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