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