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	2.2	1/11/81";
   8: char Version[] = "@(#)Arpa-mailer version 2.2 of 1/11/81";
   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 (strncmp("From ", buf, 5) == 0)
 306:     {
 307:         /* strip Unix "From" line */
 308:         /* should save the date here */
 309:         fgets(buf, sizeof buf, stdin);
 310:     }
 311:     if (matchhdr(buf, "date") == NULL)
 312:         putdate(sfp);
 313:     if (!ishdr(buf))
 314:     {
 315:         putc('\n', sfp);
 316:         goto hdrdone;
 317:     }
 318: 
 319:     /*
 320: 	** At this point, we have a message with REAL headers.
 321: 	** We look at each head line and insert commas if it
 322: 	** is a To: or Cc: field.
 323: 	*/
 324: 
 325:     do
 326:     {
 327:         if (!ishdr(buf))
 328:             break;
 329:         if (!matchhdr(buf, "to") && !matchhdr(buf, "cc"))
 330:         {
 331:             fputs(buf, sfp);
 332:             continue;
 333:         }
 334:         /* gotcha! */
 335:         rewrite(buf, 1, sfp);
 336:         while (isspace(c = peekc(stdin)) && c != '\n')
 337:         {
 338:             fgets(buf, BUFSIZ, stdin);
 339:             rewrite(buf, 0, sfp);
 340:         }
 341:     } while (fgets(buf, BUFSIZ, stdin) != NULL);
 342: 
 343: hdrdone:
 344:     /* output the rest of the header & the body of the letter */
 345:     do
 346:     {
 347:         fputs(buf, sfp);
 348:         if (ferror(sfp))
 349:             goto spoolerr;
 350:     } while (fgets(buf, sizeof buf, stdin) != NULL);
 351: 
 352:     /* all done! */
 353:     fclose(sfp);
 354:     return (EX_OK);
 355: }
 356: /*
 357: **  REWRITE -- Output header line with needed commas.
 358: **
 359: **	Parameters:
 360: **		buf -- header line
 361: **		first -- true if this is not a continuation
 362: **
 363: **	Returns:
 364: **		none
 365: **
 366: **	Side effects:
 367: **		The contents of buf is copied onto the spool file with
 368: **		with the right commas interlaced
 369: **
 370: **	Called by:
 371: **		sendmail
 372: */
 373: 
 374: rewrite(buf, first, spf)
 375:     char buf[];
 376:     register FILE *spf;
 377: {
 378:     register char *cp;
 379:     register int c;
 380:     char word[BUFSIZ], word2[BUFSIZ];
 381:     char *gword();
 382:     static char wsep[] = ", ";
 383: 
 384:     cp = buf;
 385:     if (first)
 386:     {
 387:         while (*cp != ':' && *cp)
 388:             putc(*cp++, spf);
 389:         if (*cp == ':')
 390:         {
 391:             fputs(": ", spf);
 392:             cp++;
 393:         }
 394:     }
 395:     else
 396:         while (*cp && isspace(*cp))
 397:             putc(*cp++, spf);
 398:     cp = gword(word, cp);
 399:     if (strlen(word) == 0)
 400:     {
 401:         putc('\n', spf);
 402:         goto test;
 403:     }
 404:     for (;;)
 405:     {
 406:         cp = gword(word2, cp);
 407:         if (strlen(word2) == 0)
 408:         {
 409:             putaddr(word, spf);
 410:             break;
 411:         }
 412:         if (strcmp(word2, "%") == 0)
 413:             word2[0] = '@';
 414:         if (strcmp(word2, "@") && strcmp(word2, "at"))
 415:         {
 416:             putaddr(word, spf);
 417:             fputs(wsep, spf);
 418:             strcpy(word, word2);
 419:             continue;
 420:         }
 421:         fputs(word, spf);
 422:         if (word2[0] == '@')
 423:             putc('@', spf);
 424:         else
 425:             fputs(" at ", spf);
 426:         cp = gword(word, cp);
 427:         fputs(word, spf);
 428:         cp = gword(word, cp);
 429:         if (strlen(word))
 430:             fputs(wsep, spf);
 431:     }
 432: 
 433: test:
 434:     c = peekc(stdin);
 435:     if (isspace(c) && c != '\n')
 436:         fputs(",\n", spf);
 437:     else
 438:         putc('\n', spf);
 439: }
 440: /*
 441: **  PUTADDR -- output address onto file
 442: **
 443: **	Putaddr prepends the network header onto the address
 444: **	unless one already exists.
 445: **
 446: **	Parameters:
 447: **		name -- the name to output.
 448: **		fp -- the file to put it on.
 449: **
 450: **	Returns:
 451: **		none.
 452: **
 453: **	Side Effects:
 454: **		name is put onto fp.
 455: */
 456: 
 457: putaddr(name, fp)
 458:     char *name;
 459:     FILE *fp;
 460: {
 461:     register char *p;
 462: 
 463:     if (strlen(name) == 0)
 464:         return;
 465:     for (p = name; *p != '\0' && *p != ':' && *p != '.' && *p != '@' &&
 466:          *p != '!' && *p != '^'; p++)
 467:         continue;
 468:     if (*p == ':')
 469:         *p = '.';
 470:     else if (*p == '\0')
 471:         fputs(FromHost, fp);
 472:     fputs(name, fp);
 473:     if (*p != '@')
 474:         fputs("@Berkeley", fp);
 475: }
 476: /*
 477: **  PEEKC -- peek at next character in input file
 478: **
 479: **	Parameters:
 480: **		fp -- stdio file buffer
 481: **
 482: **	Returns:
 483: **		the next character in the input or EOF
 484: **
 485: **	Side effects:
 486: **		None.
 487: **
 488: **	Called by:
 489: **		sendmail
 490: **		rewrite
 491: */
 492: peekc(fp)
 493:     register FILE *fp;
 494: {
 495:     register int c;
 496: 
 497:     c = getc(fp);
 498:     ungetc(c, fp);
 499:     return(c);
 500: }
 501: 
 502: /*
 503: **  GWORD -- get the next liberal word from a string
 504: **
 505: **	Parameters:
 506: **		buf -- place to put scanned word
 507: **		p -- place to start looking for word
 508: **
 509: **	Returns:
 510: **		updated value of p or 0 if no more left after this
 511: **
 512: **	Side effects:
 513: **		buf gets the liberal word scanned.
 514: **		buf will be length 0 if there is no more input,
 515: **		or if p was passed as 0
 516: **
 517: **	Called by:
 518: **		rewrite
 519: */
 520: char *
 521: gword(buf, p)
 522:     char buf[];
 523:     register char *p;
 524: {
 525:     register char *sp, *dp;
 526: 
 527:     strcpy(buf, "");
 528:     if (p == 0)
 529:         return(0);
 530:     sp = p;
 531:     while (*sp && (isspace(*sp) || *sp == ','))
 532:         sp++;
 533:     dp = buf;
 534:     if (*sp != '%' && *sp != '@')
 535:     {
 536:         while (*sp && !isspace(*sp) && *sp != ',' && *sp != '%' && *sp != '@')
 537:             *dp++ = *sp++;
 538:     }
 539:     else
 540:         *dp++ = *sp++;
 541:     *dp = 0;
 542:     if (*sp == 0)
 543:         return(0);
 544:     return(sp);
 545: }
 546: /*
 547: **  ISHDR -- see if the passed line is a ARPA style header line
 548: **
 549: **	Parameters:
 550: **		buf -- header line
 551: **
 552: **	Returns:
 553: **		non-zero if the line is a header line, else zero
 554: **
 555: **	Side effects:
 556: **		none
 557: **
 558: **	Called by:
 559: **		sendmail
 560: */
 561: ishdr(buf)
 562:     char buf[];
 563: {
 564:     register char *p;
 565: 
 566:     p = buf;
 567:     if (isspace(*p))
 568:         p = 0;
 569:     else
 570:     {
 571:         while (*p != ':' && !isspace(*p))
 572:             p++;
 573:         while (isspace(*p))
 574:             p++;
 575:         if (*p != ':')
 576:             p = 0;
 577:     }
 578:     return(p != 0);
 579: }
 580: /*
 581: **  PUTDATE -- Put the date & from field into the message.
 582: **
 583: **	Parameters:
 584: **		fp -- file to put them onto.
 585: **
 586: **	Returns:
 587: **		none
 588: **
 589: **	Side Effects:
 590: **		output onto fp.
 591: **
 592: **	Called By:
 593: **		sendmail
 594: */
 595: 
 596: putdate(fp)
 597:     register FILE *fp;
 598: {
 599:     register char *p;
 600: 
 601:     fputs("Date: ", fp);
 602:     fputs(arpadate(), fp);
 603: 
 604:     /* output from field */
 605:     fputs("\nFrom: ", fp);
 606:     fputs(From, fp);
 607:     fputs(" at Berkeley\n", fp);
 608: }

Defined functions

finis defined in line 168; used 5 times
gword defined in line 520; used 5 times
ishdr defined in line 561; used 2 times
main defined in line 95; never used
peekc defined in line 492; used 2 times
putaddr defined in line 457; used 2 times
putdate defined in line 596; used 1 times
rewrite defined in line 374; used 2 times
rexit defined in line 190; used 2 times
sendmail defined in line 228; used 1 times

Defined variables

From defined in line 55; used 20 times
FromHost defined in line 61; used 3 times
SccsId defined in line 7; never used
State defined in line 57; used 3 times
To defined in line 56; never used
Version defined in line 8; used 1 times

Defined macros

SPOOLDIR defined in line 50; used 1 times
Last modified: 1981-02-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1211
Valid CSS Valid XHTML 1.0 Strict