|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted provided ! 7: * that: (1) source distributions retain this entire copyright notice and ! 8: * comment, and (2) distributions including binaries display the following ! 9: * acknowledgement: ``This product includes software developed by the ! 10: * University of California, Berkeley and its contributors'' in the ! 11: * documentation or other materials provided with the distribution and in ! 12: * all advertising materials mentioning features or use of this software. ! 13: * Neither the name of the University nor the names of its contributors may ! 14: * be used to endorse or promote products derived from this software without ! 15: * specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: */ ! 20: ! 21: #ifndef lint ! 22: char copyright[] = ! 23: "@(#) Copyright (c) 1988 Regents of the University of California.\n\ ! 24: All rights reserved.\n"; ! 25: #endif /* not lint */ ! 26: ! 27: #ifndef lint ! 28: static char sccsid[] = "@(#)arpa.c 5.4 (Berkeley) 6/1/90"; ! 29: #endif /* not lint */ ! 30: ! 31: # include <stdio.h> ! 32: # include <ctype.h> ! 33: # include <signal.h> ! 34: # include <sysexits.h> ! 35: # include <whoami.h> ! 36: # include <useful.h> ! 37: ! 38: char Version[] = "@(#)Arpa-mailer version 5.4 of 6/1/90"; ! 39: ! 40: # define void int ! 41: ! 42: /* ! 43: ** ARPA MAILER -- Queue ARPANET mail for eventual delivery ! 44: ** ! 45: ** The standard input is stuck away in the outgoing arpanet ! 46: ** mail queue for delivery by the true arpanet mailer. ! 47: ** ! 48: ** CUSTOMIZED FOR THE C/70 ! 49: ** ! 50: ** Usage: ! 51: ** /usr/lib/mailers/arpa from host user ! 52: ** ! 53: ** Positional Parameters: ! 54: ** from -- the person sending the mail. ! 55: ** host -- the host to send the mail to. ! 56: ** user -- the user to send the mail to. ! 57: ** ! 58: ** Flags: ! 59: ** -T -- debug flag. ! 60: ** ! 61: ** Files: ! 62: ** /usr/spool/netmail/* -- the queue file. ! 63: ** ! 64: ** Return Codes: ! 65: ** 0 -- all messages successfully mailed. ! 66: ** 2 -- user or host unknown. ! 67: ** 3 -- service unavailable, probably temporary ! 68: ** file system condition. ! 69: ** 4 -- syntax error in address. ! 70: ** ! 71: ** Compilation Flags: ! 72: ** SPOOLDIR -- the spool directory ! 73: ** ! 74: ** Compilation Instructions: ! 75: ** cc -n -O -s arpa-mailer.c -o arpa-mailer -lX ! 76: ** chmod 755 arpa-mailer ! 77: ** mv arpa-mailer /usr/lib/mailers/arpa ! 78: ** ! 79: ** Author: ! 80: ** Eric Allman, UCB/INGRES (eric@berkeley) ! 81: */ ! 82: ! 83: # ifdef C70 ! 84: # define SPOOLDIR "/usr/netmail" ! 85: # else ! 86: # define SPOOLDIR "/usr/spool/netmail" ! 87: # endif ! 88: ! 89: ! 90: ! 91: ! 92: char *From; /* person sending this mail */ ! 93: char *To; /* current "To:" person */ ! 94: int State; /* the current state (for exit codes) */ ! 95: # ifdef DEBUG ! 96: bool Tflag; /* -T given */ ! 97: # endif DEBUG ! 98: char FromHost[200]; /* string to prepend to addresses */ ! 99: /* ! 100: ** MAIN -- Main program for arpa mailer ! 101: ** ! 102: ** Processes arguments, and calls sendmail successively on ! 103: ** the To: list. ! 104: ** ! 105: ** Algorithm: ! 106: ** Scan for debug flag. ! 107: ** Catch interrupt signals. ! 108: ** Collect input file name and from person. ! 109: ** If more than one person in the to list, and ! 110: ** if the input file is not a real file, ! 111: ** collect input into a temp file. ! 112: ** For each person in the to list ! 113: ** Send to that person. ! 114: ** ! 115: ** Parameters: ! 116: ** argc ! 117: ** argv -- as usual ! 118: ** ! 119: ** Returns: ! 120: ** via exit ! 121: ** ! 122: ** Side Effects: ! 123: ** Mail gets sent. ! 124: ** ! 125: ** Author: ! 126: ** Eric Allman UCB/INGRES. ! 127: */ ! 128: ! 129: main(argc, argv) ! 130: int argc; ! 131: char **argv; ! 132: { ! 133: register int i; ! 134: register char *p; ! 135: register int ifd; ! 136: char buf[512]; ! 137: extern int done(); ! 138: extern char *locv(); ! 139: register char *q; ! 140: char *lastmark; ! 141: ! 142: State = 3; ! 143: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 144: (void) signal(SIGINT, done); ! 145: ! 146: /* process flags */ ! 147: argv[argc] = 0; ! 148: # ifdef DEBUG ! 149: if (strcmp(argv[1], "-T") == 0) ! 150: { ! 151: Tflag++; ! 152: argv++; ! 153: argc--; ! 154: printf("%s\n", Version); ! 155: } ! 156: # endif DEBUG ! 157: ! 158: if (argc != 4) ! 159: { ! 160: rexit(EX_SOFTWARE); ! 161: } ! 162: ! 163: /* decode parameters */ ! 164: From = argv[1]; ! 165: lastmark = &FromHost[-1]; ! 166: for (p = From, q = FromHost; (*q = *p) != '\0'; p++, q++) ! 167: { ! 168: if (*p == ':') ! 169: *q = *p = '.'; ! 170: if (*q == '.' || *q == '!' || *q == '@') ! 171: lastmark = q; ! 172: } ! 173: lastmark[1] = '\0'; ! 174: ! 175: /* start sending mail */ ! 176: State = sendmail(argv[2], argv[3]); ! 177: ! 178: /* all done, clean up */ ! 179: done(); ! 180: } ! 181: /* ! 182: ** DONE -- Finish up, remove temp files, etc. ! 183: ** ! 184: ** This does basic cleanup on interrupt, error, or ! 185: ** normal termination. It uses "State" to tell which ! 186: ** is happening. ! 187: ** ! 188: ** Parameters: ! 189: ** none ! 190: ** ! 191: ** Returns: ! 192: ** none ! 193: ** ! 194: ** Side Effects: ! 195: ** Exit(State). ! 196: */ ! 197: ! 198: done() ! 199: { ! 200: rexit(State); ! 201: } ! 202: ! 203: /* ! 204: ** REXIT -- exit, reporting error code if -T given ! 205: ** ! 206: ** Parameters: ! 207: ** e -- error code to exit with; see sysexits.h ! 208: ** ! 209: ** Returns: ! 210: ** none ! 211: ** ! 212: ** Side Effects: ! 213: ** Exit(e). ! 214: */ ! 215: rexit(e) ! 216: { ! 217: ! 218: # ifdef DEBUG ! 219: if (Tflag) ! 220: fprintf(stderr, "arpa-mail: return code %d\n", e); ! 221: # endif ! 222: exit(e); ! 223: } ! 224: /* ! 225: ** SENDMAIL -- Queue up mail for the arpanet mailer. ! 226: ** ! 227: ** The mail is inserted with proper headers into the ! 228: ** arpanet queue directory. ! 229: ** ! 230: ** Algorithm: ! 231: ** decode "to" address ! 232: ** if error, exit. ! 233: ** create a spool file name. ! 234: ** output the header information to spool file, ! 235: ** separate names in To:, CC: fields with commas. ! 236: ** copy the mail to the spool file. ! 237: ** ! 238: ** Parameters: ! 239: ** host -- the host to send to. ! 240: ** user -- the user to send to. ! 241: ** ! 242: ** Returns: ! 243: ** none ! 244: ** ! 245: ** Side Effects: ! 246: ** the mail is copied into a file in the network ! 247: ** queue directory (/usr/spool/netmail). ! 248: */ ! 249: ! 250: sendmail(host, user) ! 251: char *host; ! 252: char *user; ! 253: { ! 254: char spoolfile[50]; /* gets the spool file name */ ! 255: register int i; ! 256: register char *p; ! 257: static int callnum; /* for the final letter on spoolfile */ ! 258: char buf[512]; ! 259: register FILE *sfp; /* spool file */ ! 260: register int c; ! 261: extern char *matchhdr(); ! 262: ! 263: /* verify that the host exists */ ! 264: (void) strcpy(buf, "/dev/net/"); ! 265: (void) strcat(buf, host); ! 266: # ifndef C70 ! 267: #ifdef DEBUG ! 268: if (!Tflag) ! 269: #endif DEBUG ! 270: if (host[0] == '\0' || access(buf, 0) < 0) ! 271: return (EX_NOHOST); ! 272: # endif C70 ! 273: ! 274: /* ! 275: ** Create spool file name. ! 276: ** Format is "username000nnX", where username is ! 277: ** padded on the right with zeros and nn (the process ! 278: ** id) is padded on the left with zeros; X is a unique ! 279: ** sequence character. ! 280: */ ! 281: ! 282: # ifdef DEBUG ! 283: if (Tflag) ! 284: (void) strcpy(spoolfile, "arpa.out"); ! 285: else ! 286: # endif DEBUG ! 287: (void) sprintf(spoolfile, "%s/arpamail%05d%c", SPOOLDIR, getpid(), 'a' + callnum++); ! 288: ! 289: /* create spool file */ ! 290: sfp = fopen(spoolfile, "w"); ! 291: if (sfp == NULL) ! 292: { ! 293: spoolerr: ! 294: return (EX_OSERR); ! 295: } ! 296: # ifdef DEBUG ! 297: if (!Tflag) ! 298: # endif DEBUG ! 299: (void) chmod(spoolfile, 0400); ! 300: ! 301: /* ! 302: ** Output mailer control lines. ! 303: ** These lines are as follows: ! 304: ** /dev/net/<hostname> {target host} ! 305: ** user-name {at target host} ! 306: ** /mnt/eric {pathname of sender; not used} ! 307: ** eric {name of user who is sending} ! 308: ** These are different (but close) on the C/70. ! 309: */ ! 310: ! 311: # ifdef C70 ! 312: fputs(host, sfp); ! 313: fputs(":", sfp); ! 314: fputs(user, sfp); ! 315: fputs(":", sfp); ! 316: fputs(From, sfp); ! 317: fputs(":\n", sfp); ! 318: # else ! 319: fputs(buf, sfp); ! 320: fputs("\n", sfp); ! 321: fputs(user, sfp); ! 322: fputs("\n\n", sfp); ! 323: fputs(From, sfp); ! 324: fputs("\n", sfp); ! 325: # endif ! 326: ! 327: /* ! 328: ** Output the mail ! 329: ** Check the first line for the date. If not found, ! 330: ** assume the message is not in arpanet standard format ! 331: ** and output a "Date:" and "From:" header. ! 332: */ ! 333: ! 334: if (fgets(buf, sizeof buf, stdin) == NULL) ! 335: { ! 336: /* no message */ ! 337: (void) unlink(spoolfile); ! 338: return (EX_OK); ! 339: } ! 340: if (strncmp("From ", buf, 5) == 0) ! 341: { ! 342: /* strip Unix "From" line */ ! 343: /* should save the date here */ ! 344: (void) fgets(buf, sizeof buf, stdin); ! 345: } ! 346: while (matchhdr(buf, "mail-from") != NULL || ! 347: matchhdr(buf, "sender-path") != NULL || ! 348: matchhdr(buf, "received") != NULL || ! 349: matchhdr(buf, "via") != NULL) ! 350: { ! 351: fputs(buf, sfp); ! 352: (void) fgets(buf, sizeof buf, stdin); ! 353: } ! 354: if (matchhdr(buf, "date") == NULL) ! 355: putdate(sfp); ! 356: else ! 357: { ! 358: fputs(buf, sfp); ! 359: (void) fgets(buf, sizeof buf, stdin); ! 360: } ! 361: if (matchhdr(buf, "from") == NULL) ! 362: putfrom(sfp); ! 363: else ! 364: { ! 365: /* hack to support sendmail -- for a while */ ! 366: if (index(buf, '@') == NULL) ! 367: putfrom(sfp); ! 368: else ! 369: fputs(buf, sfp); ! 370: (void) fgets(buf, sizeof buf, stdin); ! 371: } ! 372: if (!ishdr(buf)) ! 373: { ! 374: if (buf[0] != '\n') ! 375: putc('\n', sfp); ! 376: goto hdrdone; ! 377: } ! 378: ! 379: /* ! 380: ** At this point, we have a message with REAL headers. ! 381: ** We look at each head line and insert commas if it ! 382: ** is a To: or Cc: field. ! 383: */ ! 384: ! 385: do ! 386: { ! 387: if (!ishdr(buf)) ! 388: break; ! 389: if (!matchhdr(buf, "to") && !matchhdr(buf, "cc")) ! 390: { ! 391: fputs(buf, sfp); ! 392: continue; ! 393: } ! 394: /* gotcha! */ ! 395: fixaddr(buf, 1, sfp); ! 396: while (isspace(c = peekc(stdin)) && c != '\n') ! 397: { ! 398: (void) fgets(buf, BUFSIZ, stdin); ! 399: fixaddr(buf, 0, sfp); ! 400: } ! 401: } while (fgets(buf, BUFSIZ, stdin) != NULL); ! 402: ! 403: hdrdone: ! 404: /* output the rest of the header & the body of the letter */ ! 405: do ! 406: { ! 407: fputs(buf, sfp); ! 408: if (ferror(sfp)) ! 409: goto spoolerr; ! 410: } while (fgets(buf, sizeof buf, stdin) != NULL); ! 411: ! 412: /* all done! */ ! 413: (void) fclose(sfp); ! 414: return (EX_OK); ! 415: } ! 416: /* ! 417: ** FIXADDR -- Output header line with needed commas. ! 418: ** ! 419: ** Parameters: ! 420: ** buf -- header line ! 421: ** first -- true if this is not a continuation ! 422: ** ! 423: ** Returns: ! 424: ** none ! 425: ** ! 426: ** Side effects: ! 427: ** The contents of buf is copied onto the spool file with ! 428: ** with the right commas interlaced ! 429: ** ! 430: ** Called by: ! 431: ** sendmail ! 432: */ ! 433: ! 434: fixaddr(buf, first, spf) ! 435: char buf[]; ! 436: register FILE *spf; ! 437: { ! 438: register char *cp; ! 439: register int c; ! 440: char word[BUFSIZ], word2[BUFSIZ]; ! 441: char *gword(); ! 442: static char wsep[] = ", "; ! 443: ! 444: cp = buf; ! 445: if (first) ! 446: { ! 447: while (*cp != ':' && *cp) ! 448: putc(*cp++, spf); ! 449: if (*cp == ':') ! 450: { ! 451: fputs(": ", spf); ! 452: cp++; ! 453: } ! 454: } ! 455: else ! 456: while (*cp && isspace(*cp)) ! 457: putc(*cp++, spf); ! 458: cp = gword(word, cp); ! 459: if (strlen(word) == 0) ! 460: { ! 461: putc('\n', spf); ! 462: goto test; ! 463: } ! 464: for (;;) ! 465: { ! 466: cp = gword(word2, cp); ! 467: if (strlen(word2) == 0) ! 468: { ! 469: putaddr(word, spf); ! 470: break; ! 471: } ! 472: if (strcmp(word2, "%") == 0) ! 473: word2[0] = '@'; ! 474: if (strcmp(word2, "@") && strcmp(word2, "at")) ! 475: { ! 476: putaddr(word, spf); ! 477: fputs(wsep, spf); ! 478: (void) strcpy(word, word2); ! 479: continue; ! 480: } ! 481: fputs(word, spf); ! 482: if (word2[0] == '@') ! 483: putc('@', spf); ! 484: else ! 485: fputs(" at ", spf); ! 486: cp = gword(word, cp); ! 487: fputs(word, spf); ! 488: cp = gword(word, cp); ! 489: if (strlen(word)) ! 490: fputs(wsep, spf); ! 491: } ! 492: ! 493: test: ! 494: c = peekc(stdin); ! 495: if (isspace(c) && c != '\n') ! 496: fputs(",\n", spf); ! 497: else ! 498: putc('\n', spf); ! 499: } ! 500: /* ! 501: ** PUTADDR -- output address onto file ! 502: ** ! 503: ** Putaddr prepends the network header onto the address ! 504: ** unless one already exists. ! 505: ** ! 506: ** Parameters: ! 507: ** name -- the name to output. ! 508: ** fp -- the file to put it on. ! 509: ** ! 510: ** Returns: ! 511: ** none. ! 512: ** ! 513: ** Side Effects: ! 514: ** name is put onto fp. ! 515: */ ! 516: ! 517: putaddr(name, fp) ! 518: char *name; ! 519: FILE *fp; ! 520: { ! 521: register char *p; ! 522: ! 523: if (strlen(name) == 0) ! 524: return; ! 525: for (p = name; *p != '\0' && *p != ':' && *p != '.' && *p != '@' && ! 526: *p != '!' && *p != '^'; p++) ! 527: continue; ! 528: if (*p == ':') ! 529: *p = '.'; ! 530: else if (*p == '\0') ! 531: fputs(FromHost, fp); ! 532: fputs(name, fp); ! 533: if (*p != '@') ! 534: fputs("@Berkeley", fp); ! 535: } ! 536: /* ! 537: ** PEEKC -- peek at next character in input file ! 538: ** ! 539: ** Parameters: ! 540: ** fp -- stdio file buffer ! 541: ** ! 542: ** Returns: ! 543: ** the next character in the input or EOF ! 544: ** ! 545: ** Side effects: ! 546: ** None. ! 547: */ ! 548: peekc(fp) ! 549: register FILE *fp; ! 550: { ! 551: register int c; ! 552: ! 553: c = getc(fp); ! 554: (void) ungetc(c, fp); ! 555: return(c); ! 556: } ! 557: ! 558: /* ! 559: ** GWORD -- get the next liberal word from a string ! 560: ** ! 561: ** Parameters: ! 562: ** buf -- place to put scanned word ! 563: ** p -- place to start looking for word ! 564: ** ! 565: ** Returns: ! 566: ** updated value of p or 0 if no more left after this ! 567: ** ! 568: ** Side effects: ! 569: ** buf gets the liberal word scanned. ! 570: ** buf will be length 0 if there is no more input, ! 571: ** or if p was passed as 0 ! 572: */ ! 573: char * ! 574: gword(buf, p) ! 575: char buf[]; ! 576: register char *p; ! 577: { ! 578: register char *sp, *dp; ! 579: int atfound = 0; /* weither or not a '@' found in the scan */ ! 580: ! 581: (void) strcpy(buf, ""); ! 582: if (p == 0) ! 583: return(0); ! 584: sp = p; ! 585: while (*sp && (isspace(*sp) || *sp == ',')) ! 586: sp++; ! 587: dp = buf; ! 588: if (*sp != '%' && *sp != '@') ! 589: { ! 590: while (*sp && !isspace(*sp) && *sp != ',' ) ! 591: { ! 592: if ( *sp == '@' || *sp == '%' ) ! 593: atfound++; ! 594: *dp++ = *sp++; ! 595: } ! 596: if ( atfound ) ! 597: { ! 598: dp--; ! 599: while ( *dp != '@' && *dp != '%' ) ! 600: dp--,sp--; ! 601: sp--; ! 602: } ! 603: ! 604: } ! 605: else ! 606: *dp++ = *sp++; ! 607: *dp = 0; ! 608: if (*sp == 0) ! 609: return(0); ! 610: return(sp); ! 611: } ! 612: /* ! 613: ** ISHDR -- see if the passed line is a ARPA style header line ! 614: ** ! 615: ** Parameters: ! 616: ** buf -- header line ! 617: ** ! 618: ** Returns: ! 619: ** non-zero if the line is a header line, else zero ! 620: ** ! 621: ** Side effects: ! 622: ** none ! 623: ** ! 624: ** Called by: ! 625: ** sendmail ! 626: */ ! 627: ishdr(buf) ! 628: char buf[]; ! 629: { ! 630: register char *p; ! 631: ! 632: p = buf; ! 633: ! 634: /* check for continuation lines */ ! 635: if (isspace(*p)) ! 636: return (1); ! 637: else ! 638: { ! 639: while (*p != ':' && !isspace(*p)) ! 640: p++; ! 641: while (isspace(*p)) ! 642: p++; ! 643: if (*p != ':') ! 644: p = 0; ! 645: } ! 646: return(p != 0); ! 647: } ! 648: /* ! 649: ** PUTDATE -- Put the date field into the message. ! 650: ** ! 651: ** Parameters: ! 652: ** fp -- file to put it onto. ! 653: ** ! 654: ** Returns: ! 655: ** none ! 656: ** ! 657: ** Side Effects: ! 658: ** output onto fp. ! 659: */ ! 660: ! 661: putdate(fp) ! 662: register FILE *fp; ! 663: { ! 664: extern char *arpadate(); ! 665: ! 666: fputs("Date: ", fp); ! 667: fputs(arpadate(NULL), fp); ! 668: fputs("\n", fp); ! 669: } ! 670: /* ! 671: ** PUTFROM -- Put the from field into the message. ! 672: ** ! 673: ** Parameters: ! 674: ** fp -- file to put it onto. ! 675: ** ! 676: ** Returns: ! 677: ** none ! 678: ** ! 679: ** Side Effects: ! 680: ** output onto fp. ! 681: */ ! 682: ! 683: putfrom(fp) ! 684: register FILE *fp; ! 685: { ! 686: ! 687: fputs("From: ", fp); ! 688: fputs(From, fp); ! 689: fputs("@Berkeley\n", fp); ! 690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.