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