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: }

Defined functions

done defined in line 170; used 3 times
fixaddr defined in line 406; used 2 times
gword defined in line 545; used 5 times
ishdr defined in line 599; used 2 times
main defined in line 101; never used
peekc defined in line 520; used 2 times
putaddr defined in line 489; used 2 times
putdate defined in line 633; used 1 times
putfrom defined in line 655; used 2 times
rexit defined in line 187; used 2 times
sendmail defined in line 222; used 1 times

Defined variables

From defined in line 64; used 5 times
FromHost defined in line 70; used 3 times
SccsId defined in line 8; never used
State defined in line 66; used 3 times
To defined in line 65; never used
Version defined in line 10; used 1 times

Defined macros

SPOOLDIR defined in line 58; used 1 times
void defined in line 12; never used
Last modified: 1983-12-09
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1377
Valid CSS Valid XHTML 1.0 Strict