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