|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.