|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Eric P. Allman
3: * Copyright (c) 1988 Regents of the University of California.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms are permitted provided
7: * that: (1) source distributions retain this entire copyright notice and
8: * comment, and (2) distributions including binaries display the following
9: * acknowledgement: ``This product includes software developed by the
10: * University of California, Berkeley and its contributors'' in the
11: * documentation or other materials provided with the distribution and in
12: * all advertising materials mentioning features or use of this software.
13: * Neither the name of the University nor the names of its contributors may
14: * be used to endorse or promote products derived from this software without
15: * specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: */
20:
21: #ifndef lint
22: char copyright[] =
23: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
24: All rights reserved.\n";
25: #endif /* not lint */
26:
27: #ifndef lint
28: static char sccsid[] = "@(#)arpa.c 5.4 (Berkeley) 6/1/90";
29: #endif /* not lint */
30:
31: # include <stdio.h>
32: # include <ctype.h>
33: # include <signal.h>
34: # include <sysexits.h>
35: # include <whoami.h>
36: # include <useful.h>
37:
38: char Version[] = "@(#)Arpa-mailer version 5.4 of 6/1/90";
39:
40: # define void int
41:
42: /*
43: ** ARPA MAILER -- Queue ARPANET mail for eventual delivery
44: **
45: ** The standard input is stuck away in the outgoing arpanet
46: ** mail queue for delivery by the true arpanet mailer.
47: **
48: ** CUSTOMIZED FOR THE C/70
49: **
50: ** Usage:
51: ** /usr/lib/mailers/arpa from host user
52: **
53: ** Positional Parameters:
54: ** from -- the person sending the mail.
55: ** host -- the host to send the mail to.
56: ** user -- the user to send the mail to.
57: **
58: ** Flags:
59: ** -T -- debug flag.
60: **
61: ** Files:
62: ** /usr/spool/netmail/* -- the queue file.
63: **
64: ** Return Codes:
65: ** 0 -- all messages successfully mailed.
66: ** 2 -- user or host unknown.
67: ** 3 -- service unavailable, probably temporary
68: ** file system condition.
69: ** 4 -- syntax error in address.
70: **
71: ** Compilation Flags:
72: ** SPOOLDIR -- the spool directory
73: **
74: ** Compilation Instructions:
75: ** cc -n -O -s arpa-mailer.c -o arpa-mailer -lX
76: ** chmod 755 arpa-mailer
77: ** mv arpa-mailer /usr/lib/mailers/arpa
78: **
79: ** Author:
80: ** Eric Allman, UCB/INGRES (eric@berkeley)
81: */
82:
83: # ifdef C70
84: # define SPOOLDIR "/usr/netmail"
85: # else
86: # define SPOOLDIR "/usr/spool/netmail"
87: # endif
88:
89:
90:
91:
92: char *From; /* person sending this mail */
93: char *To; /* current "To:" person */
94: int State; /* the current state (for exit codes) */
95: # ifdef DEBUG
96: bool Tflag; /* -T given */
97: # endif DEBUG
98: char FromHost[200]; /* string to prepend to addresses */
99: /*
100: ** MAIN -- Main program for arpa mailer
101: **
102: ** Processes arguments, and calls sendmail successively on
103: ** the To: list.
104: **
105: ** Algorithm:
106: ** Scan for debug flag.
107: ** Catch interrupt signals.
108: ** Collect input file name and from person.
109: ** If more than one person in the to list, and
110: ** if the input file is not a real file,
111: ** collect input into a temp file.
112: ** For each person in the to list
113: ** Send to that person.
114: **
115: ** Parameters:
116: ** argc
117: ** argv -- as usual
118: **
119: ** Returns:
120: ** via exit
121: **
122: ** Side Effects:
123: ** Mail gets sent.
124: **
125: ** Author:
126: ** Eric Allman UCB/INGRES.
127: */
128:
129: main(argc, argv)
130: int argc;
131: char **argv;
132: {
133: register int i;
134: register char *p;
135: register int ifd;
136: char buf[512];
137: extern int done();
138: extern char *locv();
139: register char *q;
140: char *lastmark;
141:
142: State = 3;
143: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
144: (void) signal(SIGINT, done);
145:
146: /* process flags */
147: argv[argc] = 0;
148: # ifdef DEBUG
149: if (strcmp(argv[1], "-T") == 0)
150: {
151: Tflag++;
152: argv++;
153: argc--;
154: printf("%s\n", Version);
155: }
156: # endif DEBUG
157:
158: if (argc != 4)
159: {
160: rexit(EX_SOFTWARE);
161: }
162:
163: /* decode parameters */
164: From = argv[1];
165: lastmark = &FromHost[-1];
166: for (p = From, q = FromHost; (*q = *p) != '\0'; p++, q++)
167: {
168: if (*p == ':')
169: *q = *p = '.';
170: if (*q == '.' || *q == '!' || *q == '@')
171: lastmark = q;
172: }
173: lastmark[1] = '\0';
174:
175: /* start sending mail */
176: State = sendmail(argv[2], argv[3]);
177:
178: /* all done, clean up */
179: done();
180: }
181: /*
182: ** DONE -- Finish up, remove temp files, etc.
183: **
184: ** This does basic cleanup on interrupt, error, or
185: ** normal termination. It uses "State" to tell which
186: ** is happening.
187: **
188: ** Parameters:
189: ** none
190: **
191: ** Returns:
192: ** none
193: **
194: ** Side Effects:
195: ** Exit(State).
196: */
197:
198: done()
199: {
200: rexit(State);
201: }
202:
203: /*
204: ** REXIT -- exit, reporting error code if -T given
205: **
206: ** Parameters:
207: ** e -- error code to exit with; see sysexits.h
208: **
209: ** Returns:
210: ** none
211: **
212: ** Side Effects:
213: ** Exit(e).
214: */
215: rexit(e)
216: {
217:
218: # ifdef DEBUG
219: if (Tflag)
220: fprintf(stderr, "arpa-mail: return code %d\n", e);
221: # endif
222: exit(e);
223: }
224: /*
225: ** SENDMAIL -- Queue up mail for the arpanet mailer.
226: **
227: ** The mail is inserted with proper headers into the
228: ** arpanet queue directory.
229: **
230: ** Algorithm:
231: ** decode "to" address
232: ** if error, exit.
233: ** create a spool file name.
234: ** output the header information to spool file,
235: ** separate names in To:, CC: fields with commas.
236: ** copy the mail to the spool file.
237: **
238: ** Parameters:
239: ** host -- the host to send to.
240: ** user -- the user to send to.
241: **
242: ** Returns:
243: ** none
244: **
245: ** Side Effects:
246: ** the mail is copied into a file in the network
247: ** queue directory (/usr/spool/netmail).
248: */
249:
250: sendmail(host, user)
251: char *host;
252: char *user;
253: {
254: char spoolfile[50]; /* gets the spool file name */
255: register int i;
256: register char *p;
257: static int callnum; /* for the final letter on spoolfile */
258: char buf[512];
259: register FILE *sfp; /* spool file */
260: register int c;
261: extern char *matchhdr();
262:
263: /* verify that the host exists */
264: (void) strcpy(buf, "/dev/net/");
265: (void) strcat(buf, host);
266: # ifndef C70
267: #ifdef DEBUG
268: if (!Tflag)
269: #endif DEBUG
270: if (host[0] == '\0' || access(buf, 0) < 0)
271: return (EX_NOHOST);
272: # endif C70
273:
274: /*
275: ** Create spool file name.
276: ** Format is "username000nnX", where username is
277: ** padded on the right with zeros and nn (the process
278: ** id) is padded on the left with zeros; X is a unique
279: ** sequence character.
280: */
281:
282: # ifdef DEBUG
283: if (Tflag)
284: (void) strcpy(spoolfile, "arpa.out");
285: else
286: # endif DEBUG
287: (void) sprintf(spoolfile, "%s/arpamail%05d%c", SPOOLDIR, getpid(), 'a' + callnum++);
288:
289: /* create spool file */
290: sfp = fopen(spoolfile, "w");
291: if (sfp == NULL)
292: {
293: spoolerr:
294: return (EX_OSERR);
295: }
296: # ifdef DEBUG
297: if (!Tflag)
298: # endif DEBUG
299: (void) chmod(spoolfile, 0400);
300:
301: /*
302: ** Output mailer control lines.
303: ** These lines are as follows:
304: ** /dev/net/<hostname> {target host}
305: ** user-name {at target host}
306: ** /mnt/eric {pathname of sender; not used}
307: ** eric {name of user who is sending}
308: ** These are different (but close) on the C/70.
309: */
310:
311: # ifdef C70
312: fputs(host, sfp);
313: fputs(":", sfp);
314: fputs(user, sfp);
315: fputs(":", sfp);
316: fputs(From, sfp);
317: fputs(":\n", sfp);
318: # else
319: fputs(buf, sfp);
320: fputs("\n", sfp);
321: fputs(user, sfp);
322: fputs("\n\n", sfp);
323: fputs(From, sfp);
324: fputs("\n", sfp);
325: # endif
326:
327: /*
328: ** Output the mail
329: ** Check the first line for the date. If not found,
330: ** assume the message is not in arpanet standard format
331: ** and output a "Date:" and "From:" header.
332: */
333:
334: if (fgets(buf, sizeof buf, stdin) == NULL)
335: {
336: /* no message */
337: (void) unlink(spoolfile);
338: return (EX_OK);
339: }
340: if (strncmp("From ", buf, 5) == 0)
341: {
342: /* strip Unix "From" line */
343: /* should save the date here */
344: (void) fgets(buf, sizeof buf, stdin);
345: }
346: while (matchhdr(buf, "mail-from") != NULL ||
347: matchhdr(buf, "sender-path") != NULL ||
348: matchhdr(buf, "received") != NULL ||
349: matchhdr(buf, "via") != NULL)
350: {
351: fputs(buf, sfp);
352: (void) fgets(buf, sizeof buf, stdin);
353: }
354: if (matchhdr(buf, "date") == NULL)
355: putdate(sfp);
356: else
357: {
358: fputs(buf, sfp);
359: (void) fgets(buf, sizeof buf, stdin);
360: }
361: if (matchhdr(buf, "from") == NULL)
362: putfrom(sfp);
363: else
364: {
365: /* hack to support sendmail -- for a while */
366: if (index(buf, '@') == NULL)
367: putfrom(sfp);
368: else
369: fputs(buf, sfp);
370: (void) fgets(buf, sizeof buf, stdin);
371: }
372: if (!ishdr(buf))
373: {
374: if (buf[0] != '\n')
375: putc('\n', sfp);
376: goto hdrdone;
377: }
378:
379: /*
380: ** At this point, we have a message with REAL headers.
381: ** We look at each head line and insert commas if it
382: ** is a To: or Cc: field.
383: */
384:
385: do
386: {
387: if (!ishdr(buf))
388: break;
389: if (!matchhdr(buf, "to") && !matchhdr(buf, "cc"))
390: {
391: fputs(buf, sfp);
392: continue;
393: }
394: /* gotcha! */
395: fixaddr(buf, 1, sfp);
396: while (isspace(c = peekc(stdin)) && c != '\n')
397: {
398: (void) fgets(buf, BUFSIZ, stdin);
399: fixaddr(buf, 0, sfp);
400: }
401: } while (fgets(buf, BUFSIZ, stdin) != NULL);
402:
403: hdrdone:
404: /* output the rest of the header & the body of the letter */
405: do
406: {
407: fputs(buf, sfp);
408: if (ferror(sfp))
409: goto spoolerr;
410: } while (fgets(buf, sizeof buf, stdin) != NULL);
411:
412: /* all done! */
413: (void) fclose(sfp);
414: return (EX_OK);
415: }
416: /*
417: ** FIXADDR -- Output header line with needed commas.
418: **
419: ** Parameters:
420: ** buf -- header line
421: ** first -- true if this is not a continuation
422: **
423: ** Returns:
424: ** none
425: **
426: ** Side effects:
427: ** The contents of buf is copied onto the spool file with
428: ** with the right commas interlaced
429: **
430: ** Called by:
431: ** sendmail
432: */
433:
434: fixaddr(buf, first, spf)
435: char buf[];
436: register FILE *spf;
437: {
438: register char *cp;
439: register int c;
440: char word[BUFSIZ], word2[BUFSIZ];
441: char *gword();
442: static char wsep[] = ", ";
443:
444: cp = buf;
445: if (first)
446: {
447: while (*cp != ':' && *cp)
448: putc(*cp++, spf);
449: if (*cp == ':')
450: {
451: fputs(": ", spf);
452: cp++;
453: }
454: }
455: else
456: while (*cp && isspace(*cp))
457: putc(*cp++, spf);
458: cp = gword(word, cp);
459: if (strlen(word) == 0)
460: {
461: putc('\n', spf);
462: goto test;
463: }
464: for (;;)
465: {
466: cp = gword(word2, cp);
467: if (strlen(word2) == 0)
468: {
469: putaddr(word, spf);
470: break;
471: }
472: if (strcmp(word2, "%") == 0)
473: word2[0] = '@';
474: if (strcmp(word2, "@") && strcmp(word2, "at"))
475: {
476: putaddr(word, spf);
477: fputs(wsep, spf);
478: (void) strcpy(word, word2);
479: continue;
480: }
481: fputs(word, spf);
482: if (word2[0] == '@')
483: putc('@', spf);
484: else
485: fputs(" at ", spf);
486: cp = gword(word, cp);
487: fputs(word, spf);
488: cp = gword(word, cp);
489: if (strlen(word))
490: fputs(wsep, spf);
491: }
492:
493: test:
494: c = peekc(stdin);
495: if (isspace(c) && c != '\n')
496: fputs(",\n", spf);
497: else
498: putc('\n', spf);
499: }
500: /*
501: ** PUTADDR -- output address onto file
502: **
503: ** Putaddr prepends the network header onto the address
504: ** unless one already exists.
505: **
506: ** Parameters:
507: ** name -- the name to output.
508: ** fp -- the file to put it on.
509: **
510: ** Returns:
511: ** none.
512: **
513: ** Side Effects:
514: ** name is put onto fp.
515: */
516:
517: putaddr(name, fp)
518: char *name;
519: FILE *fp;
520: {
521: register char *p;
522:
523: if (strlen(name) == 0)
524: return;
525: for (p = name; *p != '\0' && *p != ':' && *p != '.' && *p != '@' &&
526: *p != '!' && *p != '^'; p++)
527: continue;
528: if (*p == ':')
529: *p = '.';
530: else if (*p == '\0')
531: fputs(FromHost, fp);
532: fputs(name, fp);
533: if (*p != '@')
534: fputs("@Berkeley", fp);
535: }
536: /*
537: ** PEEKC -- peek at next character in input file
538: **
539: ** Parameters:
540: ** fp -- stdio file buffer
541: **
542: ** Returns:
543: ** the next character in the input or EOF
544: **
545: ** Side effects:
546: ** None.
547: */
548: peekc(fp)
549: register FILE *fp;
550: {
551: register int c;
552:
553: c = getc(fp);
554: (void) ungetc(c, fp);
555: return(c);
556: }
557:
558: /*
559: ** GWORD -- get the next liberal word from a string
560: **
561: ** Parameters:
562: ** buf -- place to put scanned word
563: ** p -- place to start looking for word
564: **
565: ** Returns:
566: ** updated value of p or 0 if no more left after this
567: **
568: ** Side effects:
569: ** buf gets the liberal word scanned.
570: ** buf will be length 0 if there is no more input,
571: ** or if p was passed as 0
572: */
573: char *
574: gword(buf, p)
575: char buf[];
576: register char *p;
577: {
578: register char *sp, *dp;
579: int atfound = 0; /* weither or not a '@' found in the scan */
580:
581: (void) strcpy(buf, "");
582: if (p == 0)
583: return(0);
584: sp = p;
585: while (*sp && (isspace(*sp) || *sp == ','))
586: sp++;
587: dp = buf;
588: if (*sp != '%' && *sp != '@')
589: {
590: while (*sp && !isspace(*sp) && *sp != ',' )
591: {
592: if ( *sp == '@' || *sp == '%' )
593: atfound++;
594: *dp++ = *sp++;
595: }
596: if ( atfound )
597: {
598: dp--;
599: while ( *dp != '@' && *dp != '%' )
600: dp--,sp--;
601: sp--;
602: }
603:
604: }
605: else
606: *dp++ = *sp++;
607: *dp = 0;
608: if (*sp == 0)
609: return(0);
610: return(sp);
611: }
612: /*
613: ** ISHDR -- see if the passed line is a ARPA style header line
614: **
615: ** Parameters:
616: ** buf -- header line
617: **
618: ** Returns:
619: ** non-zero if the line is a header line, else zero
620: **
621: ** Side effects:
622: ** none
623: **
624: ** Called by:
625: ** sendmail
626: */
627: ishdr(buf)
628: char buf[];
629: {
630: register char *p;
631:
632: p = buf;
633:
634: /* check for continuation lines */
635: if (isspace(*p))
636: return (1);
637: else
638: {
639: while (*p != ':' && !isspace(*p))
640: p++;
641: while (isspace(*p))
642: p++;
643: if (*p != ':')
644: p = 0;
645: }
646: return(p != 0);
647: }
648: /*
649: ** PUTDATE -- Put the date field into the message.
650: **
651: ** Parameters:
652: ** fp -- file to put it onto.
653: **
654: ** Returns:
655: ** none
656: **
657: ** Side Effects:
658: ** output onto fp.
659: */
660:
661: putdate(fp)
662: register FILE *fp;
663: {
664: extern char *arpadate();
665:
666: fputs("Date: ", fp);
667: fputs(arpadate(NULL), fp);
668: fputs("\n", fp);
669: }
670: /*
671: ** PUTFROM -- Put the from field into the message.
672: **
673: ** Parameters:
674: ** fp -- file to put it onto.
675: **
676: ** Returns:
677: ** none
678: **
679: ** Side Effects:
680: ** output onto fp.
681: */
682:
683: putfrom(fp)
684: register FILE *fp;
685: {
686:
687: fputs("From: ", fp);
688: fputs(From, fp);
689: fputs("@Berkeley\n", fp);
690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.