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

Defined functions

done defined in line 188; used 7 times
fixaddr defined in line 424; used 2 times
gword defined in line 563; used 5 times
ishdr defined in line 617; used 2 times
main defined in line 119; never used
putaddr defined in line 507; used 2 times
putdate defined in line 651; used 2 times
putfrom defined in line 673; used 2 times
rexit defined in line 205; used 2 times
sendmail defined in line 240; used 1 times

Defined variables

From defined in line 82; used 5 times
FromHost defined in line 88; used 3 times
SccsId defined in line 18; never used
State defined in line 84; used 3 times
To defined in line 83; never used
Version defined in line 28; used 1 times
copyright defined in line 12; never used

Defined macros

SPOOLDIR defined in line 76; used 1 times
void defined in line 30; never used
Last modified: 1985-06-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2042
Valid CSS Valid XHTML 1.0 Strict