1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32
33 /*
34 * uucleanup - This is a program based on the heuristics
35 * for cleaning up and doing something
36 * useful with old files left in the uucp queues.
37 * It also will send warning messags to users where requests are not
38 * going out due to failure to contact the remote system.
39 *
40 * This program knows a lot about the construction and
41 * contents of the C., D. and X. files. In addition, it
42 * thinks it knows what mail and netnews data files look like.
43 *
44 * At present, this is what is done:
45 * For WARNING messages:
46 * C. files of age given by -W option are read, looking for
47 * either user files to be sent or received, or
48 * mail to be sent. (Other remote execution that
49 * does not involve sending user files is not checked
50 * for now.) In either of the cases, the user is
51 * informed by mail that the request is not being
52 * processed due to lack of communications with the remote
53 * system, and the request will be deleted in the future
54 * if it the condition remains for several more days.
55 *
56 * For DELETIONS:
57 * C. files - if they reference only D. files, the C. is
58 * merely deleted, because the D. files are usually
59 * mail or news, and the later D. processing will
60 * take care of them.
61 * - if they reference files from the file system,
62 * a message is constructed that will contain a
63 * lines like
64 * We can't contact the remote.
65 *
66 * local!file -> remote!otherfile
67 *
68 * can't be executed.
69 * X. files - merely deleted at present - D.s will be taken
70 * care of later. Besides, some of the D.s are
71 * missing or else the X. wouldn't be left around.
72 * D. files - mail type data is sent to a local person if that
73 * is where it originated. If not, it is returned to the
74 * sender -- assumed to be from the first From line. If
75 * a sender can't be determing, the file is merely deleted.
76 * - rnews: if locally generated, just delete. If remote,
77 * the X. got lost, so execute rnews.
78 * other files - just delete them.
79 * .Workspace files over a day old
80 *
81 * Deletions and executions are logged in
82 * (CLEANUPLOG)--/var/uucp/.Admin/uucleanup
83 */
84
85 #include "uucp.h"
86
87 #ifdef V7
88 #define O_RDONLY 0
89 #endif
90
91 #define USAGE "[-oDAYS] [-mSTRING] [-Cdays] [-Ddays] [-Wdays] [-Xdays] [-xLEVEL] [-sSYSTEM]"
92
93 extern int _age(); /* find the age of a file */
94 extern void procdtype(), oprocess(), xprocess(), cprocess();
95 extern void dXprocess(), dNprocess(), dMprocess(), dDprocess(), wprocess();
96 extern int toWho(), sendMail(), execRnews();
97 extern void logit();
98
99 /* need these dummys to satisy some .o files */
cleanup()100 void cleanup(){}
systat()101 void systat(){}
logent()102 void logent(){}
103
104 static void cleanworkspace(void);
105
106 /* types of D. files */
107 #define D_MAIL 1
108 #define D_NEWS 2
109 #define D_XFILE 3
110 #define D_DATA 4
111 #define FULLNAME(full,dir,file) (void) sprintf(full, "%s/%s", dir, file);
112
113 int _Ddays = 7; /* D. limit */
114 int _Cdays = 7; /* C. limit */
115 int _Xdays = 2; /* X. limit */
116 int _Odays = 2; /* O. limit */
117 int _Wdays = 1; /* Warning limit for C. files */
118 char _ShortLocal[6]; /* 5 char or less version of local name */
119
120 char *_Undeliverable[] = {
121 "Subject: Undeliverable Mail\n",
122 "This mail message is undeliverable.\n",
123 "(Probably to or from system '%s')\n",
124 "It was sent to you or by you.\n",
125 "Sorry for the inconvenience.\n",
126 "",
127 };
128
129 #define CANT1 2 /* first line to fill in */
130 #define CANT2 3 /* second line to fill in */
131 char *_CantContact[] = {
132 "Subject: Job Killed By uucp\n",
133 "We can't contact machine '%s'.\n",
134 " ", /* uucleanup will fill in variable text here */
135 " ", /* fill in jobid of killed job */
136 "",
137 };
138
139 #define WARN1 2
140 #define WARN2 5
141 #define WARN3 6
142 char *_Warning[] = {
143 "Subject: Warning From uucp\n",
144 "We have been unable to contact machine '%s' since you queued your job.\n",
145 " ", /* wprocess FILLS IN THIS LINE OF TEXT */
146 "Attempts will continue for a few more days.\n",
147 "",
148 " ", /* wprocess FILLS IN THIS LINE WITH: uucp job id is JOBid. */
149 " ", /* FILL IN THE -m STRING IF SPECIFIED */
150 "",
151 };
152
153 int
main(argc,argv,envp)154 main(argc, argv, envp)
155 int argc;
156 char *argv[];
157 char **envp;
158 {
159 DIR *jcdir, *machdir, *spooldir;
160 char fullname[MAXFULLNAME], statfile[MAXFULLNAME], machname[MAXFULLNAME];
161 char file1[NAMESIZE+1], file2[NAMESIZE+1], file3[NAMESIZE+1];
162 char soptName[MAXFULLNAME], lockname[MAXFULLNAME]; /* name from -s option */
163 int i, value;
164
165 soptName[0] = NULLCHAR;
166 (void) strcpy(Logfile, CLEANUPLOGFILE);
167 uucpname(Myname);
168 (void) strncpy(_ShortLocal, Myname, 5);
169 _ShortLocal[5] = NULLCHAR;
170 (void) strcpy(Progname, "uucleanup");
171 while ((i = getopt(argc, argv, "C:D:W:X:m:o:s:x:")) != EOF) {
172 switch(i){
173 case 's': /* for debugging - choose system */
174 (void) strcpy(soptName, optarg);
175 break;
176 case 'x':
177 Debug = atoi(optarg);
178 if (Debug <= 0 || Debug >= 10) {
179 fprintf(stderr,
180 "WARNING: %s: invalid debug level %s ignored, using level 1\n",
181 Progname, optarg);
182 Debug = 1;
183 }
184 #ifdef SMALL
185 fprintf(stderr,
186 "WARNING: uucleanup built with SMALL flag defined -- no debug info available\n");
187 #endif /* SMALL */
188 break;
189 case 'm':
190 _Warning[WARN3] = optarg;
191 break;
192 default:
193 (void) fprintf(stderr, "\tusage: %s %s\n",
194 Progname, USAGE);
195 exit(1);
196
197 case 'C':
198 case 'D':
199 case 'W':
200 case 'X':
201 case 'o':
202 value = atoi(optarg);
203 if (value < 1) {
204 fprintf(stderr," Options: CDWXo require value > 0\n");
205 exit(1);
206 }
207 switch(i) {
208 case 'C':
209 _Cdays = value;
210 break;
211 case 'D':
212 _Ddays = value;
213 break;
214 case 'W':
215 _Wdays = value;
216 break;
217 case 'X':
218 _Xdays = value;
219 break;
220 case 'o':
221 _Odays = value;
222 break;
223 }
224 break;
225 }
226 }
227
228 if (argc != optind) {
229 (void) fprintf(stderr, "\tusage: %s %s\n", Progname, USAGE);
230 exit(1);
231 }
232
233 DEBUG(5, "Progname (%s): STARTED\n", Progname);
234 DEBUG(5, "Myname (%s), ", Myname);
235 DEBUG(5, "_ShortLocal (%s)\n", _ShortLocal);
236 DEBUG(5, "Days C.(%d), ", _Cdays);
237 DEBUG(5, "D.(%d), ", _Ddays);
238 DEBUG(5, "W.(%d), ", _Wdays);
239 DEBUG(5, "X.(%d), ", _Xdays);
240 DEBUG(5, "other (%d)\n", _Odays);
241
242 cleanworkspace();
243 if (chdir(SPOOL) != 0) {
244 (void) fprintf(stderr, "CAN'T CHDIR (%s): errno (%d)\n",
245 SPOOL, errno);
246 exit(1);
247 }
248 if ((spooldir = opendir(SPOOL)) == NULL) {
249 (void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n",
250 SPOOL, errno);
251 exit(1);
252 }
253
254 while (gdirf(spooldir, file1, SPOOL) == TRUE) {
255
256 if (*soptName && !EQUALS(soptName, file1))
257 continue;
258
259 (void) strcpy(Rmtname, file1);
260 (void) sprintf(machname, "%s/%s", SPOOL, file1);
261 if ((machdir = opendir(machname)) == NULL) {
262 (void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n",
263 machname, errno);
264 if (*soptName)
265 break;
266 else
267 continue;
268 }
269 DEBUG(7, "Directory: (%s) is open\n", file1);
270 while (gnamef(machdir, file2) == TRUE) {
271
272 (void) sprintf(statfile, "%s/%s", machname, file2);
273 if (DIRECTORY(statfile)) {
274 (void) sprintf(lockname, "%s.%.*s.%s",
275 LOCKPRE, SYSNSIZE, file1, file2);
276 if (cklock(lockname))
277 continue;
278 if ((jcdir = opendir(statfile)) == NULL) {
279 (void) fprintf(stderr,
280 "CAN'T OPEN (%s): errno (%d)\n",
281 statfile, errno);
282 continue;
283 }
284
285 DEBUG(7, "Directory: (%s) is open\n", file2);
286 while (gnamef(jcdir, file3)) {
287 DEBUG(9, "file: %s\n", file3);
288 FULLNAME(fullname, statfile, file3);
289 DEBUG(9,"Fullname is (%s)\n", fullname);
290 if (EQUALSN(file3, "C.", 2)) {
291 if (_age(fullname) >= _Cdays)
292 cprocess(fullname);
293 else if(_age(fullname) >= _Wdays)
294 wprocess(statfile, file3);
295 }
296 else if (EQUALSN(file3, "D.", 2)) {
297 if (_age(fullname) >= _Ddays)
298 procdtype(statfile, file3);
299 }
300 else if (_age(fullname) >= _Odays)
301 oprocess(fullname);
302 }
303 closedir(jcdir);
304 continue;
305 }
306 DEBUG(9, "file: %s\n", file2);
307 DEBUG(9, "Fullname is (%s)\n", statfile);
308 if (EQUALSN(file2, "X.", 2)) {
309 if (_age(statfile) >= _Xdays)
310 xprocess(statfile);
311 }
312 else if (EQUALSN(file2, "D.", 2)) {
313 if (_age(statfile) >= _Ddays)
314 procdtype(machname, file2);
315 }
316 else if (_age(statfile) >= _Odays)
317 oprocess(statfile);
318 }
319 closedir(machdir);
320 }
321 closedir(spooldir);
322 return (0);
323 }
324
325 /* procdtype - select the type of processing that a D. file should receive */
326
327 void
procdtype(dir,file)328 procdtype(dir, file)
329 char *dir, *file;
330 {
331
332 char fullname[MAXFULLNAME];
333
334 FULLNAME(fullname, dir, file);
335
336 switch(dType(fullname)) {
337 case D_DATA:
338 dDprocess(fullname);
339 break;
340 case D_MAIL:
341 dMprocess(dir, file);
342 break;
343 case D_NEWS:
344 dNprocess(dir, file);
345 break;
346 case D_XFILE:
347 dXprocess(fullname);
348 break;
349 default:
350 break;
351 }
352 return;
353 }
354
355 /* xprocess - X. file processing -- just remove the X. for now */
356
357 void
xprocess(fullname)358 xprocess(fullname)
359 char *fullname;
360 {
361 char text[BUFSIZ];
362
363 DEBUG(5, "xprocess(%s), ", fullname);
364 DEBUG(5, "unlink(%s)\n", fullname);
365 (void) sprintf(text, "xprocess: unlink(%s)", fullname);
366 errno = 0;
367 (void) unlink(fullname);
368 logit(text, errno);
369 return;
370 }
371
372 /*
373 * cprocess - Process old C. files
374 *
375 */
376
377 #define CMFMT "\n\t%s!%s -> %s!%s (Date %2.2d/%2.2d)\n\nCan't be executed."
378 #define XFMT "\n\t%s!%s (Date %2.2d/%2.2d)\n"
379 #define XMFMT "\n\tmail %s!%s (Date %2.2d/%2.2d)\n"
380 #define WFMT "\n\t%s!%s -> %s!%s (Date %2.2d/%2.2d)\n"
381 void
cprocess(fullname)382 cprocess(fullname)
383 char *fullname;
384 {
385 struct stat s;
386 struct tm *tp;
387 char buf[BUFSIZ], user[9];
388 char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256];
389 char text[BUFSIZ], text1[BUFSIZ], text2[BUFSIZ];
390 FILE *fp;
391 int ret;
392
393 DEBUG(5, "cprocess(%s)\n", fullname);
394
395
396 fp = fopen(fullname, "r");
397 if (fp == NULL) {
398 DEBUG(5, "Can't open file (%s), ", fullname);
399 DEBUG(5, "errno=%d -- skip it!\n", errno);
400 return;
401 }
402 if (fstat(fileno(fp), &s) != 0) {
403 /* can't happen; _age() did stat of this file and file is opened */
404 (void) fclose(fp);
405 return;
406 }
407 tp = localtime(&s.st_mtime);
408
409 if (s.st_size == 0) { /* dummy C. for polling */
410 DEBUG(5, "dummy C. -- unlink(%s)\n", fullname);
411 (void) sprintf(text, "dDprocess: dummy C. unlinked(%s)",
412 fullname);
413 errno = 0;
414 (void) unlink(fullname);
415 logit(text, errno);
416 (void) fclose(fp);
417 return;
418 }
419
420 /* Read the C. file and process it */
421 while (fgets(buf, BUFSIZ, fp) != NULL) {
422 buf[strlen(buf)-1] = NULLCHAR; /* remove \n */
423 if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2,
424 user, opt, file3) <5) {
425 (void) sprintf(text, "cprocess: Bad C. %s, unlink(%s)",
426 buf, fullname);
427 break;
428 }
429
430 *text = NULLCHAR;
431 ret = 0;
432 /* fill in line 3 of text */
433 (void) sprintf(text2, "Job (%s) killed!\n",
434 BASENAME(fullname, '/')+2);
435 _CantContact[CANT2] = text2;
436 if (*type == 'S') {
437 if (EQUALSN(file1, "D.", 2))
438 /* generated file (mail/news) I think */
439 /* D. processing will return it later */
440 continue;
441
442 /* some data was requested -- tell user */
443
444 (void) sprintf(text1, CMFMT, Myname, file1, Rmtname, file2,
445 tp->tm_mon + 1, tp->tm_mday);
446 _CantContact[CANT1] = text1;
447 ret = sendMail((char *) NULL, user, "", _CantContact);
448 }
449 else if (*type == 'R') {
450 (void) sprintf(text1, CMFMT, Rmtname, file1, Myname, file2,
451 tp->tm_mon + 1, tp->tm_mday);
452 _CantContact[CANT1] = text1;
453 ret = sendMail((char *) NULL, user, "", _CantContact);
454 }
455 }
456
457 if (!*text) {
458 (void) sprintf(text,
459 "cprocess: C. %s, mail returned (%d), unlink(%s)",
460 buf, ret, fullname);
461 }
462 DEBUG(3, "text (%s)\n", text);
463
464 errno = 0;
465 (void) unlink(fullname);
466 logit(text, errno);
467
468 (void) fclose(fp);
469 return;
470 }
471
472 /*
473 * wprocess - send warning messages for C. == Wdays
474 */
475
476 void
wprocess(dir,file)477 wprocess(dir, file)
478 char *dir, *file;
479 {
480 struct stat s;
481 struct tm *tp;
482 char fullname[BUFSIZ], xfile[BUFSIZ], xF_file[BUFSIZ];
483 char buf[BUFSIZ], user[BUFSIZ];
484 char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256];
485 char text[BUFSIZ], text1[BUFSIZ], text2[BUFSIZ];
486 char *realuser, uline_m[NAMESIZE], uline_u[BUFSIZ], retaddr[BUFSIZ];
487 FILE *fp, *xfp;
488 int ret;
489
490 FULLNAME(fullname, dir, file);
491 DEBUG(5, "wprocess(%s)\n", fullname);
492
493 fp = fopen(fullname, "r");
494 if (fp == NULL) {
495 DEBUG(4, "Can't open file (%s), ", fullname);
496 DEBUG(4, "errno=%d -- skip it!\n", errno);
497 return;
498 }
499
500 if (fstat(fileno(fp), &s) != 0) {
501
502 /* can't happen; _age() did stat of this file and file is opened */
503
504 (void) fclose(fp);
505 return;
506 }
507
508 tp = localtime(&s.st_mtime);
509
510 if (s.st_size == 0) { /* dummy C. for polling */
511 DEBUG(5, "dummy C. -- skip(%s)\n", fullname);
512 (void) fclose(fp);
513 return;
514 }
515
516 /* read C. and process it */
517 while (fgets(buf, BUFSIZ, fp) != NULL) {
518 buf[strlen(buf)-1] = NULLCHAR; /* remove \n */
519 if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2,
520 user, opt, file3) <5) {
521 DEBUG(5, "short line (%s): ", buf);
522 DEBUG(5, "bad D. -- skip(%s)\n", fullname);
523 (void) fclose(fp);
524 return;
525 }
526
527 /* set up the 6th text line of the mail message */
528
529 (void) sprintf(text2,
530 "\nuucp job id is %s.\n", BASENAME(fullname, '/')+2);
531
532 _Warning[WARN2] = text2;
533
534 /* if Send type then do C. file processing */
535
536 if (*type == 'S') {
537
538 /* if this is a uux job - tell user about it */
539
540 if (EQUALSN(file2, "X.", 2)) {
541 FULLNAME(xfile, dir, file1);
542
543 /* if X.file can't be read then skip it */
544
545 if ((xfp = fopen(xfile, "r")) == NULL) {
546 DEBUG(3, "Can't read %s\n", xfile);
547 break;
548 }
549 *retaddr = *uline_u = *uline_m = *text = NULLCHAR;
550 while (fgets(buf, BUFSIZ, xfp) != NULL) {
551
552 /* remove \n from end of buffer */
553
554 buf[strlen(buf)-1] = NULLCHAR;
555 switch(*buf) {
556
557 /* save the file name */
558
559 case 'F':
560 FULLNAME(xF_file, dir, &buf[2]);
561 break;
562
563 /* save return address */
564
565 case 'R':
566 sscanf(buf+2, "%s", retaddr);
567 DEBUG(7, "retaddr (%s)\n", retaddr);
568 break;
569
570 /* save machine, user */
571
572 case 'U':
573 sscanf(buf+2, "%s%s",
574 uline_u, uline_m);
575 break;
576 }
577
578 if (buf[0] != 'C')
579 continue;
580 realuser = uline_u;
581 if (*retaddr != NULLCHAR)
582 realuser = retaddr;
583 if (*realuser == NULLCHAR)
584 strcpy(realuser, user);
585 if (!EQUALS(uline_m, Myname))
586 sprintf(user, "%s!%s",
587 uline_m, realuser);
588 else
589 strcpy(user, realuser);
590
591 /* give mail special handling */
592 if (EQUALSN(buf+2, "rmail ", 6))
593 (void) sprintf(text1, XMFMT,
594 Rmtname, buf+8,
595 tp->tm_mon+1, tp->tm_mday);
596 else
597 (void) sprintf(text1, XFMT,
598 Rmtname, buf+2,
599 tp->tm_mon+1, tp->tm_mday);
600
601 _Warning[WARN1] = text1;
602 if (EQUALSN(&buf[2], "rmail", 5))
603 /*
604 * this is mail; append
605 * user mail (xF_file).
606 */
607 ret = sendMail((char *) NULL,
608 user, xF_file, _Warning);
609 else
610 ret = sendMail((char *) NULL,
611 user, "", _Warning);
612 break;
613 }
614 (void) fclose(xfp);
615 break;
616 }
617
618 /* if file1 is a D. file the it might be (mail/news) */
619 /* if so then D. processing will take of it later */
620
621 if (EQUALSN(file1, "D.", 2))
622 continue;
623
624 /* some data was requested -- tell user */
625 /* set up the 2nd text line of the mail message */
626
627 (void) sprintf(text1, WFMT, Myname, file1, Rmtname, file2,
628 tp->tm_mon + 1, tp->tm_mday);
629 _Warning[WARN1] = text1;
630 ret = sendMail((char *) NULL, user, "", _Warning);
631 }
632
633 /* Receive C. file processing */
634
635 else if (*type == 'R') {
636 if (EQUALSN(file1, "D.", 2) && EQUALSN(file2, "D.", 2))
637 continue;
638
639 (void) sprintf(text1, WFMT, Rmtname, file1, Myname, file2,
640 tp->tm_mon + 1, tp->tm_mday);
641 _Warning[WARN1] = text1;
642 ret = sendMail((char *) NULL, user, "", _Warning);
643 }
644 } /* end while - read C. lines loop */
645
646 (void) sprintf(text,
647 "wprocess: %s: %s, warning message sent to %s, returned (%d)",
648 fullname, buf, user, ret);
649
650 DEBUG(3, "text (%s)\n", text);
651
652 logit(text, errno);
653
654 (void) fclose(fp);
655 return;
656 }
657 /*
658 * oprocess - some unknown file just remove the file
659 */
660
661 void
oprocess(fullname)662 oprocess(fullname)
663 char *fullname;
664 {
665
666 char *p, text[BUFSIZ];
667
668 p = BASENAME(fullname, '/');
669 if (EQUALSN(p, "P.", 2) == 0)
670 if (_age(fullname) <= _Cdays)
671 return;
672 DEBUG(5, "oprocess(%s), ", fullname);
673 DEBUG(5, "unlink(%s)\n", fullname);
674 (void) sprintf(text, "oprocess: unlink(%s)", fullname);
675 errno = 0;
676 (void) unlink(fullname);
677 logit(text, errno);
678 return;
679 }
680
681 /*
682 * dDprocess - random D. file (not mail or rnews)
683 *--just delete it for now
684 */
685
686 void
dDprocess(fullname)687 dDprocess(fullname)
688 char *fullname;
689 {
690 char text[BUFSIZ];
691
692 DEBUG(5, "dDprocess(%s), ", fullname);
693 DEBUG(5, "unlink(%s)\n", fullname);
694 (void) sprintf(text, "dDprocess: unlink(%s)", fullname);
695 errno = 0;
696 (void) unlink(fullname);
697 logit(text, errno);
698 return;
699 }
700
701 /*
702 * dXprocess - process D. files that are destined for X. on remote
703 * --for now just delete it
704 */
705
706 void
dXprocess(fullname)707 dXprocess(fullname)
708 char *fullname;
709 {
710 char text[BUFSIZ];
711
712 DEBUG(5, "dXprocess(%s), ", fullname);
713 DEBUG(5, " unlink(%s)\n", fullname);
714 (void) sprintf(text, "dXprocess: unlink(%s)", fullname);
715 errno = 0;
716 (void) unlink(fullname);
717 logit(text, errno);
718 return;
719 }
720
721 /*
722 * dMprocess - process ophan D. mail files
723 * There are two types: ones generated locally and
724 * others that are from remotes. They can be identified
725 * by the system name following the D.
726 * Local ones have the local name.
727 */
728
729 void
dMprocess(dir,file)730 dMprocess(dir, file)
731 char *dir, *file;
732 {
733 int ret;
734 char fullname[MAXFULLNAME];
735 char *toUser, *toSystem;
736 char text[BUFSIZ];
737
738 (void) sprintf(fullname, "%s/%s", dir, file);
739 DEBUG(5, "dMprocess(%s)\n", fullname);
740
741
742 if (PREFIX(_ShortLocal, &file[2])) {
743 DEBUG(5, " Local file %s: ", file);
744 }
745 else {
746 DEBUG(5, " Remote file %s: ", file);
747 }
748 if (toWho(fullname, &toUser, &toSystem)) {
749 DEBUG(5, "toUser %s, ", toUser);
750 DEBUG(5, "toSystem %s ", toSystem);
751 ret = sendMail(toSystem, toUser, fullname, _Undeliverable);
752 DEBUG(5, "Mail sent, unlink(%s)\n", fullname);
753 (void) sprintf(text,
754 "dMprocess: mail %s to %s!%s, returned (%d), unlink(%s)",
755 fullname, toSystem, toUser, ret, fullname);
756 errno = 0;
757 (void) unlink(fullname);
758 logit(text, errno);
759 }
760 return;
761 }
762
763 /*
764 * dNprocess - process ophan D. netnews files
765 * There are two types: ones generated locally and
766 * others that are from remotes. They can be identified
767 * by the system name following the D.
768 * Local ones have the local name.
769 */
770
771 void
dNprocess(dir,file)772 dNprocess(dir, file)
773 char *dir, *file;
774 {
775 char fullname[MAXFULLNAME];
776 char text[BUFSIZ];
777 int ret;
778
779 (void) sprintf(fullname, "%s/%s", dir, file);
780 DEBUG(5, "dNprocess(%s)\n", fullname);
781
782
783 if (PREFIX(_ShortLocal, &file[2])) {
784 /* just delete it, the C. is gone */
785 DEBUG(5, " Local file %s, ", file);
786 DEBUG(5, "unlink(%s)\n", fullname);
787 (void) unlink(fullname);
788 (void) sprintf(text, "dNprocess: Local news item unlink(%s)",
789 fullname);
790 errno = 0;
791 (void) unlink(fullname);
792 logit(text, errno);
793 }
794 else {
795 /* execute rnews with this file - the X. is missing */
796 DEBUG(5, " Remote file %s, ", file);
797 DEBUG(5, "exec rnews(%s), ", fullname);
798 ret = execRnews(fullname);
799 DEBUG(5, "unlink(%s)\n", fullname);
800 (void) sprintf(text,
801 "dNprocess: Remote - exec rnews %s: returned (%d), unlink(%s)",
802 fullname, ret, fullname);
803 errno = 0;
804 (void) unlink(fullname);
805 logit(text, errno);
806 }
807 return;
808 }
809
810
811
812 static long _sec_per_day = 86400L;
813
814 /*
815 * _age - find the age of "file" in days
816 * return:
817 * age of file
818 * 0 - if stat fails
819 */
820
821 int
_age(fullname)822 _age(fullname)
823 char *fullname;
824 {
825 static time_t ptime = 0;
826 time_t time();
827 struct stat stbuf;
828 int e;
829
830 if (!ptime)
831 (void) time(&ptime);
832 if (stat(fullname, &stbuf) != -1) {
833 return ((int)((ptime - stbuf.st_mtime)/_sec_per_day));
834 }
835 e = errno;
836 DEBUG(9, "_age: stat (%s) failed", fullname);
837 DEBUG(9, ", errno %d\n", e);
838 return(0);
839 }
840
841 /*
842 * dType - return the type of D. file
843 * return:
844 * FAIL - can't read D. file
845 * D_MAIL - mail message D. file
846 * D_NEWS - netnews D. file
847 * D_DATA - other kind of D. file
848 * D_XFILE - destined for X. on destination machine
849 */
850
851 /* NLINES - number of lines of D. file to read to determine type */
852 #define NLINES 10
853
854 int
dType(fullname)855 dType(fullname)
856 char *fullname;
857 {
858 char buf[BUFSIZ];
859 FILE *fp;
860 int i, type;
861
862 fp = fopen(fullname, "r");
863 if (fp == NULL) {
864 DEBUG(4, "Can't open file (%s), ", fullname);
865 DEBUG(4, "errno=%d -- skip it!\n", errno);
866 return(FAIL);
867 }
868 type = D_DATA;
869
870 /* read first NLINES lines to determine file type */
871
872 for (i=0; i<NLINES; i++) {
873 if (fgets(buf, BUFSIZ, fp) == NULL)
874 break; /* no more lines */
875 DEBUG(9, "buf: %s\n", buf);
876 if (EQUALSN(buf, "From ", 5)) {
877 type = D_MAIL;
878 break;
879 }
880 if (EQUALSN(buf, "U ", 2)) {
881 type = D_XFILE;
882 break;
883 }
884 if (EQUALSN(buf, "Newsgroups: ", 12)) {
885 type = D_NEWS;
886 break;
887 }
888 }
889
890 (void) fclose(fp);
891 return(type);
892 }
893
894 /*
895 * sendMail - send mail file and message to user (local or remote)
896 * return:
897 * the return from the pclose - mail exit status
898 */
899 int
sendMail(system,user,file,mtext)900 sendMail(system, user, file, mtext)
901 char *system, *user, *file;
902 char *mtext[];
903 {
904 FILE *fp, *fi;
905 char cmd[BUFSIZ];
906 char *p;
907
908 DEBUG(5, "Mail %s to ", file);
909 DEBUG(5, "%s\n", user);
910
911 /* get rid of some stuff that could be dangerous */
912 if (system != NULL && (p = strpbrk(system, Shchar)) != NULL) {
913 *p = NULLCHAR;
914 }
915 if (user != NULL && (p = strpbrk(user, Shchar)) != NULL) {
916 *p = NULLCHAR;
917 }
918 if (system != NULL && *system != '\0')
919 (void) sprintf(cmd, "%s %s '%s!%s'", PATH, MAIL, system, user);
920 else
921 (void) sprintf(cmd, "%s %s '%s'", PATH, MAIL, user);
922
923 DEBUG(7, "sendMail: %s\n", cmd);
924 if ((fp = popen(cmd, "w")) == NULL)
925 return(-errno);
926 while (*mtext[0] )
927 (void) fprintf(fp, *mtext++, Rmtname);
928
929 (void) fprintf(fp, "\n\tSincerely,\n\t%s!uucp\n", Myname);
930 (void) fprintf(fp,
931 "\n#############################################\n");
932
933 if (*file) {
934 /*next statement should never happen;I read once */
935 if ((fi= fopen(file, "r")) == NULL)
936 return(pclose(fp));
937 (void) fprintf(fp,
938 "##### Data File: ############################\n");
939 xfappend(fi, fp);
940 (void) fclose(fi);
941 }
942 return(pclose(fp));
943 }
944
945 /*
946 * execRnews - execute rnews command with stdin file
947 * return:
948 * the return from the pclose - rnews exit status
949 */
950 int
execRnews(file)951 execRnews(file)
952 char *file;
953 {
954 FILE *fp, *fi;
955 char cmd[BUFSIZ];
956
957 DEBUG(5, "Rnews %s\n", file);
958
959 (void) sprintf(cmd, "%s rnews ", PATH);
960 if ((fp = popen(cmd, "w")) == NULL)
961 return(-errno);
962
963 if ( (fi = fopen(file, "r")) == NULL) /* never happen - I read once */
964 return(pclose(fp));
965 xfappend(fi, fp);
966 (void) fclose(fi);
967
968 return(pclose(fp));
969 }
970
971 /*
972 * toWho - figure out who to send this dead mail to
973 * It is a guess;
974 * If there is a local address, send it there.
975 * If not, send it back where it came from.
976 * return:
977 * 0 - could not find system and user information
978 * 1 - found it
979 */
980
981 int
toWho(file,user,system)982 toWho(file, user, system)
983 char *file; /* the D. mail message file */
984 char **system; /* pointer to the system name */
985 char **user; /* pointer to the user name */
986 {
987 char buf[BUFSIZ];
988 FILE *fp;
989 int i;
990 static char fuser[BUFSIZ], fsystem[MAXBASENAME+1]; /* from first From */
991 static char luser[BUFSIZ], lsystem[MAXBASENAME+1]; /* from other From */
992
993 *fuser = NULLCHAR;
994 DEBUG(5, "toWho(%s)\n", file);
995 fp = fopen(file, "r");
996 for (i=0; i<NLINES; i++) {
997 if (fgets(buf, BUFSIZ, fp) == NULL)
998 break; /* no more lines */
999 DEBUG(9, "buf: %s\n", buf);
1000 if (!analFrom(buf, luser, lsystem))
1001 continue;
1002 if ( !*fuser) {
1003 (void) strcpy(fuser, luser);
1004 (void) strcpy(fsystem, lsystem);
1005 }
1006 if (EQUALS(Myname, lsystem)) {
1007 *user = luser;
1008 *system = lsystem;
1009 (void) fclose(fp);
1010 return(1);
1011 }
1012 }
1013
1014 /* could not find local user - use first line */
1015 (void) fclose(fp);
1016 if (!*fuser) /* didn't find all information */
1017 return(0);
1018 *user = fuser;
1019 *system = fsystem;
1020 return(1);
1021 }
1022
1023 /* analFrom - analyze From line
1024 * return:
1025 * 0 - didn't find both from and remote from info
1026 * 1 - found info.
1027 */
1028
1029 int
analFrom(line,user,system)1030 analFrom(line, user, system)
1031 char *line, *user, *system;
1032 {
1033 char *s;
1034 int i;
1035
1036 if (!PREFIX("From ", line) && !PREFIX(">From ", line))
1037 return(0);
1038
1039 s = strchr(line, ' ') + 1;
1040 for (i = 0; *s && *s != ' ' && *s != '\n'; i++)
1041 user[i] = *s++;
1042 user[i] = NULLCHAR;
1043
1044 /* look for "remote from" */
1045 while (*s && ((s = strchr(s, ' ')) != NULL)) {
1046 s++;
1047 if (PREFIX("remote from ", s)) { /* found it */
1048 s = s + strlen("remote from ");
1049 for (i = 0; (i<MAXBASENAME) && *s && *s != ' ' && *s != '\n'; i++)
1050 system[i] = *s++;
1051 system[i] = NULLCHAR;
1052 return(1);
1053 }
1054 }
1055 return(0);
1056 }
1057
1058
1059
1060 static FILE *_Lf = NULL;
1061
1062 /*
1063 * Make log entry
1064 * text -> ptr to text string
1065 * status errno number
1066 * Returns:
1067 * none
1068 */
1069
1070 void
logit(text,status)1071 logit(text, status)
1072 char *text;
1073 int status;
1074 {
1075
1076 if (Nstat.t_pid == 0)
1077 Nstat.t_pid = getpid();
1078
1079 if (_Lf == NULL) {
1080 _Lf = fopen(Logfile, "a");
1081 (void) chmod(Logfile, LOGFILEMODE);
1082 if (_Lf == NULL)
1083 return;
1084 setbuf(_Lf, CNULL);
1085 }
1086 (void) fseek(_Lf, 0L, 2);
1087 (void) fprintf(_Lf, "%s ", Rmtname);
1088 (void) fprintf(_Lf, "(%s,%ld,%d) ", timeStamp(), (long) Nstat.t_pid, Seqn);
1089 (void) fprintf(_Lf, "%s (%d)\n", text, status);
1090 return;
1091 }
1092
1093 static void
cleanworkspace(void)1094 cleanworkspace(void)
1095 {
1096 DIR *spooldir;
1097 char f[MAXFULLNAME];
1098
1099 if (chdir(WORKSPACE) != 0) {
1100 (void) fprintf(stderr, "CAN'T CHDIR (%s): errno (%d)\n", WORKSPACE, errno);
1101 return;
1102 }
1103 if ((spooldir = opendir(WORKSPACE)) == NULL) {
1104 (void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n", WORKSPACE, errno);
1105 return;
1106 }
1107
1108 while (gnamef(spooldir, f) == TRUE)
1109 if (_age(f) >= 1)
1110 if (unlink(f) != 0)
1111 (void) fprintf(stderr, "CAN'T UNLINK (%s): errno (%d)\n", f, errno);
1112
1113 }
1114