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 1994 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 */ 100 void cleanup(){} 101 void systat(){} 102 void logent(){} 103 104 105 /* types of D. files */ 106 #define D_MAIL 1 107 #define D_NEWS 2 108 #define D_XFILE 3 109 #define D_DATA 4 110 #define FULLNAME(full,dir,file) (void) sprintf(full, "%s/%s", dir, file); 111 112 int _Ddays = 7; /* D. limit */ 113 int _Cdays = 7; /* C. limit */ 114 int _Xdays = 2; /* X. limit */ 115 int _Odays = 2; /* O. limit */ 116 int _Wdays = 1; /* Warning limit for C. files */ 117 char _ShortLocal[6]; /* 5 char or less version of local name */ 118 119 char *_Undeliverable[] = { 120 "Subject: Undeliverable Mail\n", 121 "This mail message is undeliverable.\n", 122 "(Probably to or from system '%s')\n", 123 "It was sent to you or by you.\n", 124 "Sorry for the inconvenience.\n", 125 "", 126 }; 127 128 #define CANT1 2 /* first line to fill in */ 129 #define CANT2 3 /* second line to fill in */ 130 char *_CantContact[] = { 131 "Subject: Job Killed By uucp\n", 132 "We can't contact machine '%s'.\n", 133 " ", /* uucleanup will fill in variable text here */ 134 " ", /* fill in jobid of killed job */ 135 "", 136 }; 137 138 #define WARN1 2 139 #define WARN2 5 140 #define WARN3 6 141 char *_Warning[] = { 142 "Subject: Warning From uucp\n", 143 "We have been unable to contact machine '%s' since you queued your job.\n", 144 " ", /* wprocess FILLS IN THIS LINE OF TEXT */ 145 "Attempts will continue for a few more days.\n", 146 "", 147 " ", /* wprocess FILLS IN THIS LINE WITH: uucp job id is JOBid. */ 148 " ", /* FILL IN THE -m STRING IF SPECIFIED */ 149 "", 150 }; 151 152 main(argc, argv, envp) 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 exit(0); 320 321 /* NOTREACHED */ 322 } 323 324 /* procdtype - select the type of processing that a D. file should receive */ 325 326 void 327 procdtype(dir, file) 328 char *dir, *file; 329 { 330 331 char fullname[MAXFULLNAME]; 332 333 FULLNAME(fullname, dir, file); 334 335 switch(dType(fullname)) { 336 case D_DATA: 337 dDprocess(fullname); 338 break; 339 case D_MAIL: 340 dMprocess(dir, file); 341 break; 342 case D_NEWS: 343 dNprocess(dir, file); 344 break; 345 case D_XFILE: 346 dXprocess(fullname); 347 break; 348 default: 349 break; 350 } 351 return; 352 } 353 354 /* xprocess - X. file processing -- just remove the X. for now */ 355 356 void 357 xprocess(fullname) 358 char *fullname; 359 { 360 char text[BUFSIZ]; 361 362 DEBUG(5, "xprocess(%s), ", fullname); 363 DEBUG(5, "unlink(%s)\n", fullname); 364 (void) sprintf(text, "xprocess: unlink(%s)", fullname); 365 errno = 0; 366 (void) unlink(fullname); 367 logit(text, errno); 368 return; 369 } 370 371 /* 372 * cprocess - Process old C. files 373 * 374 */ 375 376 #define CMFMT "\n\t%s!%s -> %s!%s (Date %2.2d/%2.2d)\n\nCan't be executed." 377 #define XFMT "\n\t%s!%s (Date %2.2d/%2.2d)\n" 378 #define XMFMT "\n\tmail %s!%s (Date %2.2d/%2.2d)\n" 379 #define WFMT "\n\t%s!%s -> %s!%s (Date %2.2d/%2.2d)\n" 380 void 381 cprocess(fullname) 382 char *fullname; 383 { 384 struct stat s; 385 register struct tm *tp; 386 char buf[BUFSIZ], user[9]; 387 char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256]; 388 char text[BUFSIZ], text1[BUFSIZ], text2[BUFSIZ]; 389 FILE *fp; 390 int ret; 391 392 DEBUG(5, "cprocess(%s)\n", fullname); 393 394 395 fp = fopen(fullname, "r"); 396 if (fp == NULL) { 397 DEBUG(5, "Can't open file (%s), ", fullname); 398 DEBUG(5, "errno=%d -- skip it!\n", errno); 399 return; 400 } 401 if (fstat(fileno(fp), &s) != 0) { 402 /* can't happen; _age() did stat of this file and file is opened */ 403 (void) fclose(fp); 404 return; 405 } 406 tp = localtime(&s.st_mtime); 407 408 if (s.st_size == 0) { /* dummy C. for polling */ 409 DEBUG(5, "dummy C. -- unlink(%s)\n", fullname); 410 (void) sprintf(text, "dDprocess: dummy C. unlinked(%s)", 411 fullname); 412 errno = 0; 413 (void) unlink(fullname); 414 logit(text, errno); 415 (void) fclose(fp); 416 return; 417 } 418 419 /* Read the C. file and process it */ 420 while (fgets(buf, BUFSIZ, fp) != NULL) { 421 buf[strlen(buf)-1] = NULLCHAR; /* remove \n */ 422 if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2, 423 user, opt, file3) <5) { 424 (void) sprintf(text, "cprocess: Bad C. %s, unlink(%s)", 425 buf, fullname); 426 break; 427 } 428 429 *text = NULLCHAR; 430 ret = 0; 431 /* fill in line 3 of text */ 432 (void) sprintf(text2, "Job (%s) killed!\n", 433 BASENAME(fullname, '/')+2); 434 _CantContact[CANT2] = text2; 435 if (*type == 'S') { 436 if (EQUALSN(file1, "D.", 2)) 437 /* generated file (mail/news) I think */ 438 /* D. processing will return it later */ 439 continue; 440 441 /* some data was requested -- tell user */ 442 443 (void) sprintf(text1, CMFMT, Myname, file1, Rmtname, file2, 444 tp->tm_mon + 1, tp->tm_mday); 445 _CantContact[CANT1] = text1; 446 ret = sendMail((char *) NULL, user, "", _CantContact); 447 } 448 else if (*type == 'R') { 449 (void) sprintf(text1, CMFMT, Rmtname, file1, Myname, file2, 450 tp->tm_mon + 1, tp->tm_mday); 451 _CantContact[CANT1] = text1; 452 ret = sendMail((char *) NULL, user, "", _CantContact); 453 } 454 } 455 456 if (!*text) { 457 (void) sprintf(text, 458 "cprocess: C. %s, mail returned (%d), unlink(%s)", 459 buf, ret, fullname); 460 } 461 DEBUG(3, "text (%s)\n", text); 462 463 errno = 0; 464 (void) unlink(fullname); 465 logit(text, errno); 466 467 (void) fclose(fp); 468 return; 469 } 470 471 /* 472 * wprocess - send warning messages for C. == Wdays 473 */ 474 475 void 476 wprocess(dir, file) 477 char *dir, *file; 478 { 479 struct stat s; 480 register struct tm *tp; 481 char fullname[BUFSIZ], xfile[BUFSIZ], xF_file[BUFSIZ]; 482 char buf[BUFSIZ], user[BUFSIZ]; 483 char file1[BUFSIZ], file2[BUFSIZ], file3[BUFSIZ], type[2], opt[256]; 484 char text[BUFSIZ], text1[BUFSIZ], text2[BUFSIZ]; 485 char *realuser, uline_m[NAMESIZE], uline_u[BUFSIZ], retaddr[BUFSIZ]; 486 FILE *fp, *xfp; 487 int ret; 488 489 FULLNAME(fullname, dir, file); 490 DEBUG(5, "wprocess(%s)\n", fullname); 491 492 fp = fopen(fullname, "r"); 493 if (fp == NULL) { 494 DEBUG(4, "Can't open file (%s), ", fullname); 495 DEBUG(4, "errno=%d -- skip it!\n", errno); 496 return; 497 } 498 499 if (fstat(fileno(fp), &s) != 0) { 500 501 /* can't happen; _age() did stat of this file and file is opened */ 502 503 (void) fclose(fp); 504 return; 505 } 506 507 tp = localtime(&s.st_mtime); 508 509 if (s.st_size == 0) { /* dummy C. for polling */ 510 DEBUG(5, "dummy C. -- skip(%s)\n", fullname); 511 (void) fclose(fp); 512 return; 513 } 514 515 /* read C. and process it */ 516 while (fgets(buf, BUFSIZ, fp) != NULL) { 517 buf[strlen(buf)-1] = NULLCHAR; /* remove \n */ 518 if (sscanf(buf,"%s%s%s%s%s%s", type, file1, file2, 519 user, opt, file3) <5) { 520 DEBUG(5, "short line (%s): ", buf); 521 DEBUG(5, "bad D. -- skip(%s)\n", fullname); 522 (void) fclose(fp); 523 return; 524 } 525 526 /* set up the 6th text line of the mail message */ 527 528 (void) sprintf(text2, 529 "\nuucp job id is %s.\n", BASENAME(fullname, '/')+2); 530 531 _Warning[WARN2] = text2; 532 533 /* if Send type then do C. file processing */ 534 535 if (*type == 'S') { 536 537 /* if this is a uux job - tell user about it */ 538 539 if (EQUALSN(file2, "X.", 2)) { 540 FULLNAME(xfile, dir, file1); 541 542 /* if X.file can't be read then skip it */ 543 544 if ((xfp = fopen(xfile, "r")) == NULL) { 545 DEBUG(3, "Can't read %s\n", xfile); 546 break; 547 } 548 *retaddr = *uline_u = *uline_m = *text = NULLCHAR; 549 while (fgets(buf, BUFSIZ, xfp) != NULL) { 550 551 /* remove \n from end of buffer */ 552 553 buf[strlen(buf)-1] = NULLCHAR; 554 switch(*buf) { 555 556 /* save the file name */ 557 558 case 'F': 559 FULLNAME(xF_file, dir, &buf[2]); 560 break; 561 562 /* save return address */ 563 564 case 'R': 565 sscanf(buf+2, "%s", retaddr); 566 DEBUG(7, "retaddr (%s)\n", retaddr); 567 break; 568 569 /* save machine, user */ 570 571 case 'U': 572 sscanf(buf+2, "%s%s", 573 uline_u, uline_m); 574 break; 575 } 576 577 if (buf[0] != 'C') 578 continue; 579 realuser = uline_u; 580 if (*retaddr != NULLCHAR) 581 realuser = retaddr; 582 if (*realuser == NULLCHAR) 583 strcpy(realuser, user); 584 if (!EQUALS(uline_m, Myname)) 585 sprintf(user, "%s!%s", 586 uline_m, realuser); 587 else 588 strcpy(user, realuser); 589 590 /* give mail special handling */ 591 if (EQUALSN(buf+2, "rmail ", 6)) 592 (void) sprintf(text1, XMFMT, 593 Rmtname, buf+8, 594 tp->tm_mon+1, tp->tm_mday); 595 else 596 (void) sprintf(text1, XFMT, 597 Rmtname, buf+2, 598 tp->tm_mon+1, tp->tm_mday); 599 600 _Warning[WARN1] = text1; 601 if (EQUALSN(&buf[2], "rmail", 5)) 602 /* 603 * this is mail; append 604 * user mail (xF_file). 605 */ 606 ret = sendMail((char *) NULL, 607 user, xF_file, _Warning); 608 else 609 ret = sendMail((char *) NULL, 610 user, "", _Warning); 611 break; 612 } 613 (void) fclose(xfp); 614 break; 615 } 616 617 /* if file1 is a D. file the it might be (mail/news) */ 618 /* if so then D. processing will take of it later */ 619 620 if (EQUALSN(file1, "D.", 2)) 621 continue; 622 623 /* some data was requested -- tell user */ 624 /* set up the 2nd text line of the mail message */ 625 626 (void) sprintf(text1, WFMT, Myname, file1, Rmtname, file2, 627 tp->tm_mon + 1, tp->tm_mday); 628 _Warning[WARN1] = text1; 629 ret = sendMail((char *) NULL, user, "", _Warning); 630 } 631 632 /* Receive C. file processing */ 633 634 else if (*type == 'R') { 635 if (EQUALSN(file1, "D.", 2) && EQUALSN(file2, "D.", 2)) 636 continue; 637 638 (void) sprintf(text1, WFMT, Rmtname, file1, Myname, file2, 639 tp->tm_mon + 1, tp->tm_mday); 640 _Warning[WARN1] = text1; 641 ret = sendMail((char *) NULL, user, "", _Warning); 642 } 643 } /* end while - read C. lines loop */ 644 645 (void) sprintf(text, 646 "wprocess: %s: %s, warning message sent to %s, returned (%d)", 647 fullname, buf, user, ret); 648 649 DEBUG(3, "text (%s)\n", text); 650 651 logit(text, errno); 652 653 (void) fclose(fp); 654 return; 655 } 656 /* 657 * oprocess - some unknown file just remove the file 658 */ 659 660 void 661 oprocess(fullname) 662 char *fullname; 663 { 664 665 char *p, text[BUFSIZ]; 666 667 p = BASENAME(fullname, '/'); 668 if (EQUALSN(p, "P.", 2) == 0) 669 if (_age(fullname) <= _Cdays) 670 return; 671 DEBUG(5, "oprocess(%s), ", fullname); 672 DEBUG(5, "unlink(%s)\n", fullname); 673 (void) sprintf(text, "oprocess: unlink(%s)", fullname); 674 errno = 0; 675 (void) unlink(fullname); 676 logit(text, errno); 677 return; 678 } 679 680 /* 681 * dDprocess - random D. file (not mail or rnews) 682 *--just delete it for now 683 */ 684 685 void 686 dDprocess(fullname) 687 char *fullname; 688 { 689 char text[BUFSIZ]; 690 691 DEBUG(5, "dDprocess(%s), ", fullname); 692 DEBUG(5, "unlink(%s)\n", fullname); 693 (void) sprintf(text, "dDprocess: unlink(%s)", fullname); 694 errno = 0; 695 (void) unlink(fullname); 696 logit(text, errno); 697 return; 698 } 699 700 /* 701 * dXprocess - process D. files that are destined for X. on remote 702 * --for now just delete it 703 */ 704 705 void 706 dXprocess(fullname) 707 char *fullname; 708 { 709 char text[BUFSIZ]; 710 711 DEBUG(5, "dXprocess(%s), ", fullname); 712 DEBUG(5, " unlink(%s)\n", fullname); 713 (void) sprintf(text, "dXprocess: unlink(%s)", fullname); 714 errno = 0; 715 (void) unlink(fullname); 716 logit(text, errno); 717 return; 718 } 719 720 /* 721 * dMprocess - process ophan D. mail files 722 * There are two types: ones generated locally and 723 * others that are from remotes. They can be identified 724 * by the system name following the D. 725 * Local ones have the local name. 726 */ 727 728 void 729 dMprocess(dir, file) 730 char *dir, *file; 731 { 732 int ret; 733 char fullname[MAXFULLNAME]; 734 char *toUser, *toSystem; 735 char text[BUFSIZ]; 736 737 (void) sprintf(fullname, "%s/%s", dir, file); 738 DEBUG(5, "dMprocess(%s)\n", fullname); 739 740 741 if (PREFIX(_ShortLocal, &file[2])) { 742 DEBUG(5, " Local file %s: ", file); 743 } 744 else { 745 DEBUG(5, " Remote file %s: ", file); 746 } 747 if (toWho(fullname, &toUser, &toSystem)) { 748 DEBUG(5, "toUser %s, ", toUser); 749 DEBUG(5, "toSystem %s ", toSystem); 750 ret = sendMail(toSystem, toUser, fullname, _Undeliverable); 751 DEBUG(5, "Mail sent, unlink(%s)\n", fullname); 752 (void) sprintf(text, 753 "dMprocess: mail %s to %s!%s, returned (%d), unlink(%s)", 754 fullname, toSystem, toUser, ret, fullname); 755 errno = 0; 756 (void) unlink(fullname); 757 logit(text, errno); 758 } 759 return; 760 } 761 762 /* 763 * dNprocess - process ophan D. netnews files 764 * There are two types: ones generated locally and 765 * others that are from remotes. They can be identified 766 * by the system name following the D. 767 * Local ones have the local name. 768 */ 769 770 void 771 dNprocess(dir, file) 772 char *dir, *file; 773 { 774 char fullname[MAXFULLNAME]; 775 char text[BUFSIZ]; 776 int ret; 777 778 (void) sprintf(fullname, "%s/%s", dir, file); 779 DEBUG(5, "dNprocess(%s)\n", fullname); 780 781 782 if (PREFIX(_ShortLocal, &file[2])) { 783 /* just delete it, the C. is gone */ 784 DEBUG(5, " Local file %s, ", file); 785 DEBUG(5, "unlink(%s)\n", fullname); 786 (void) unlink(fullname); 787 (void) sprintf(text, "dNprocess: Local news item unlink(%s)", 788 fullname); 789 errno = 0; 790 (void) unlink(fullname); 791 logit(text, errno); 792 } 793 else { 794 /* execute rnews with this file - the X. is missing */ 795 DEBUG(5, " Remote file %s, ", file); 796 DEBUG(5, "exec rnews(%s), ", fullname); 797 ret = execRnews(fullname); 798 DEBUG(5, "unlink(%s)\n", fullname); 799 (void) sprintf(text, 800 "dNprocess: Remote - exec rnews %s: returned (%d), unlink(%s)", 801 fullname, ret, fullname); 802 errno = 0; 803 (void) unlink(fullname); 804 logit(text, errno); 805 } 806 return; 807 } 808 809 810 811 static long _sec_per_day = 86400L; 812 813 /* 814 * _age - find the age of "file" in days 815 * return: 816 * age of file 817 * 0 - if stat fails 818 */ 819 820 int 821 _age(fullname) 822 char *fullname; 823 { 824 static time_t ptime = 0; 825 time_t time(); 826 struct stat stbuf; 827 int e; 828 829 if (!ptime) 830 (void) time(&ptime); 831 if (stat(fullname, &stbuf) != -1) { 832 return ((int)((ptime - stbuf.st_mtime)/_sec_per_day)); 833 } 834 e = errno; 835 DEBUG(9, "_age: stat (%s) failed", fullname); 836 DEBUG(9, ", errno %d\n", e); 837 return(0); 838 } 839 840 /* 841 * dType - return the type of D. file 842 * return: 843 * FAIL - can't read D. file 844 * D_MAIL - mail message D. file 845 * D_NEWS - netnews D. file 846 * D_DATA - other kind of D. file 847 * D_XFILE - destined for X. on destination machine 848 */ 849 850 /* NLINES - number of lines of D. file to read to determine type */ 851 #define NLINES 10 852 853 int 854 dType(fullname) 855 char *fullname; 856 { 857 char buf[BUFSIZ]; 858 FILE *fp; 859 int i, type; 860 861 fp = fopen(fullname, "r"); 862 if (fp == NULL) { 863 DEBUG(4, "Can't open file (%s), ", fullname); 864 DEBUG(4, "errno=%d -- skip it!\n", errno); 865 return(FAIL); 866 } 867 type = D_DATA; 868 869 /* read first NLINES lines to determine file type */ 870 871 for (i=0; i<NLINES; i++) { 872 if (fgets(buf, BUFSIZ, fp) == NULL) 873 break; /* no more lines */ 874 DEBUG(9, "buf: %s\n", buf); 875 if (EQUALSN(buf, "From ", 5)) { 876 type = D_MAIL; 877 break; 878 } 879 if (EQUALSN(buf, "U ", 2)) { 880 type = D_XFILE; 881 break; 882 } 883 if (EQUALSN(buf, "Newsgroups: ", 12)) { 884 type = D_NEWS; 885 break; 886 } 887 } 888 889 (void) fclose(fp); 890 return(type); 891 } 892 893 /* 894 * sendMail - send mail file and message to user (local or remote) 895 * return: 896 * the return from the pclose - mail exit status 897 */ 898 int 899 sendMail(system, user, file, mtext) 900 char *system, *user, *file; 901 char *mtext[]; 902 { 903 register FILE *fp, *fi; 904 char cmd[BUFSIZ]; 905 char *p; 906 907 DEBUG(5, "Mail %s to ", file); 908 DEBUG(5, "%s\n", user); 909 910 /* get rid of some stuff that could be dangerous */ 911 if (system != NULL && (p = strpbrk(system, Shchar)) != NULL) { 912 *p = NULLCHAR; 913 } 914 if (user != NULL && (p = strpbrk(user, Shchar)) != NULL) { 915 *p = NULLCHAR; 916 } 917 if (system != NULL && *system != '\0') 918 (void) sprintf(cmd, "%s %s '%s!%s'", PATH, MAIL, system, user); 919 else 920 (void) sprintf(cmd, "%s %s '%s'", PATH, MAIL, user); 921 922 DEBUG(7, "sendMail: %s\n", cmd); 923 if ((fp = popen(cmd, "w")) == NULL) 924 return(-errno); 925 while (*mtext[0] ) 926 (void) fprintf(fp, *mtext++, Rmtname); 927 928 (void) fprintf(fp, "\n\tSincerely,\n\t%s!uucp\n", Myname); 929 (void) fprintf(fp, 930 "\n#############################################\n"); 931 932 if (*file) { 933 /*next statement should never happen;I read once */ 934 if ((fi= fopen(file, "r")) == NULL) 935 return(pclose(fp)); 936 (void) fprintf(fp, 937 "##### Data File: ############################\n"); 938 xfappend(fi, fp); 939 (void) fclose(fi); 940 } 941 return(pclose(fp)); 942 } 943 944 /* 945 * execRnews - execute rnews command with stdin file 946 * return: 947 * the return from the pclose - rnews exit status 948 */ 949 int 950 execRnews(file) 951 char *file; 952 { 953 register FILE *fp, *fi; 954 char cmd[BUFSIZ]; 955 956 DEBUG(5, "Rnews %s\n", file); 957 958 (void) sprintf(cmd, "%s rnews ", PATH); 959 if ((fp = popen(cmd, "w")) == NULL) 960 return(-errno); 961 962 if ( (fi = fopen(file, "r")) == NULL) /* never happen - I read once */ 963 return(pclose(fp)); 964 xfappend(fi, fp); 965 (void) fclose(fi); 966 967 return(pclose(fp)); 968 } 969 970 /* 971 * toWho - figure out who to send this dead mail to 972 * It is a guess; 973 * If there is a local address, send it there. 974 * If not, send it back where it came from. 975 * return: 976 * 0 - could not find system and user information 977 * 1 - found it 978 */ 979 980 int 981 toWho(file, user, system) 982 char *file; /* the D. mail message file */ 983 char **system; /* pointer to the system name */ 984 char **user; /* pointer to the user name */ 985 { 986 char buf[BUFSIZ]; 987 FILE *fp; 988 int i; 989 static char fuser[BUFSIZ], fsystem[MAXBASENAME+1]; /* from first From */ 990 static char luser[BUFSIZ], lsystem[MAXBASENAME+1]; /* from other From */ 991 992 *fuser = NULLCHAR; 993 DEBUG(5, "toWho(%s)\n", file); 994 fp = fopen(file, "r"); 995 for (i=0; i<NLINES; i++) { 996 if (fgets(buf, BUFSIZ, fp) == NULL) 997 break; /* no more lines */ 998 DEBUG(9, "buf: %s\n", buf); 999 if (!analFrom(buf, luser, lsystem)) 1000 continue; 1001 if ( !*fuser) { 1002 (void) strcpy(fuser, luser); 1003 (void) strcpy(fsystem, lsystem); 1004 } 1005 if (EQUALS(Myname, lsystem)) { 1006 *user = luser; 1007 *system = lsystem; 1008 (void) fclose(fp); 1009 return(1); 1010 } 1011 } 1012 1013 /* could not find local user - use first line */ 1014 (void) fclose(fp); 1015 if (!*fuser) /* didn't find all information */ 1016 return(0); 1017 *user = fuser; 1018 *system = fsystem; 1019 return(1); 1020 } 1021 1022 /* analFrom - analyze From line 1023 * return: 1024 * 0 - didn't find both from and remote from info 1025 * 1 - found info. 1026 */ 1027 1028 int 1029 analFrom(line, user, system) 1030 char *line, *user, *system; 1031 { 1032 char *s; 1033 int i; 1034 1035 if (!PREFIX("From ", line) && !PREFIX(">From ", line)) 1036 return(0); 1037 1038 s = strchr(line, ' ') + 1; 1039 for (i = 0; *s && *s != ' ' && *s != '\n'; i++) 1040 user[i] = *s++; 1041 user[i] = NULLCHAR; 1042 1043 /* look for "remote from" */ 1044 while (*s && ((s = strchr(s, ' ')) != NULL)) { 1045 s++; 1046 if (PREFIX("remote from ", s)) { /* found it */ 1047 s = s + strlen("remote from "); 1048 for (i = 0; (i<MAXBASENAME) && *s && *s != ' ' && *s != '\n'; i++) 1049 system[i] = *s++; 1050 system[i] = NULLCHAR; 1051 return(1); 1052 } 1053 } 1054 return(0); 1055 } 1056 1057 1058 1059 static FILE *_Lf = NULL; 1060 1061 /* 1062 * Make log entry 1063 * text -> ptr to text string 1064 * status errno number 1065 * Returns: 1066 * none 1067 */ 1068 1069 void 1070 logit(text, status) 1071 register char *text; 1072 int status; 1073 { 1074 1075 if (Nstat.t_pid == 0) 1076 Nstat.t_pid = getpid(); 1077 1078 if (_Lf == NULL) { 1079 _Lf = fopen(Logfile, "a"); 1080 (void) chmod(Logfile, LOGFILEMODE); 1081 if (_Lf == NULL) 1082 return; 1083 setbuf(_Lf, CNULL); 1084 } 1085 (void) fseek(_Lf, 0L, 2); 1086 (void) fprintf(_Lf, "%s ", Rmtname); 1087 (void) fprintf(_Lf, "(%s,%ld,%d) ", timeStamp(), (long) Nstat.t_pid, Seqn); 1088 (void) fprintf(_Lf, "%s (%d)\n", text, status); 1089 return; 1090 } 1091 1092 cleanworkspace() 1093 { 1094 DIR *spooldir; 1095 char f[MAXFULLNAME]; 1096 1097 if (chdir(WORKSPACE) != 0) { 1098 (void) fprintf(stderr, "CAN'T CHDIR (%s): errno (%d)\n", WORKSPACE, errno); 1099 return; 1100 } 1101 if ((spooldir = opendir(WORKSPACE)) == NULL) { 1102 (void) fprintf(stderr, "CAN'T OPEN (%s): errno (%d)\n", WORKSPACE, errno); 1103 return; 1104 } 1105 1106 while (gnamef(spooldir, f) == TRUE) 1107 if (_age(f) >= 1) 1108 if (unlink(f) != 0) 1109 (void) fprintf(stderr, "CAN'T UNLINK (%s): errno (%d)\n", f, errno); 1110 1111 } 1112