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 */ 100 void cleanup(){} 101 void systat(){} 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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