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