|
|
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.