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