|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: static char sccsid[] = "@(#)send.c 5.21 (Berkeley) 6/25/90";
22: #endif /* not lint */
23:
24: #include "rcv.h"
25:
26: /*
27: * Mail -- a mail program
28: *
29: * Mail to others.
30: */
31:
32: /*
33: * Send message described by the passed pointer to the
34: * passed output buffer. Return -1 on error.
35: * Adjust the status: field if need be.
36: * If doign is given, suppress ignored header fields.
37: * prefix is a string to prepend to each output line.
38: */
39: send(mp, obuf, doign, prefix)
40: register struct message *mp;
41: FILE *obuf;
42: struct ignoretab *doign;
43: char *prefix;
44: {
45: long count;
46: register FILE *ibuf;
47: char line[LINESIZE];
48: int ishead, infld, ignoring, dostat, firstline;
49: register char *cp, *cp2;
50: register int c;
51: int length;
52: int prefixlen;
53:
54: /*
55: * Compute the prefix string, without trailing whitespace
56: */
57: cp2 = 0;
58: for (cp = prefix; *cp; cp++)
59: if (*cp != ' ' && *cp != '\t')
60: cp2 = cp;
61: prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1;
62: ibuf = setinput(mp);
63: count = mp->m_size;
64: ishead = 1;
65: dostat = doign == 0 || !isign("status", doign);
66: infld = 0;
67: firstline = 1;
68: /*
69: * Process headers first
70: */
71: while (count > 0 && ishead) {
72: if (fgets(line, LINESIZE, ibuf) == NULL)
73: break;
74: count -= length = strlen(line);
75: if (firstline) {
76: /*
77: * First line is the From line, so no headers
78: * there to worry about
79: */
80: firstline = 0;
81: ignoring = doign == ignoreall;
82: } else if (line[0] == '\n') {
83: /*
84: * If line is blank, we've reached end of
85: * headers, so force out status: field
86: * and note that we are no longer in header
87: * fields
88: */
89: if (dostat) {
90: statusput(mp, obuf, prefix);
91: dostat = 0;
92: }
93: ishead = 0;
94: ignoring = doign == ignoreall;
95: } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
96: /*
97: * If this line is a continuation (via space or tab)
98: * of a previous header field, just echo it
99: * (unless the field should be ignored).
100: * In other words, nothing to do.
101: */
102: } else {
103: /*
104: * Pick up the header field if we have one.
105: */
106: for (cp = line; (c = *cp++) && c != ':' && !isspace(c);)
107: ;
108: cp2 = --cp;
109: while (isspace(*cp++))
110: ;
111: if (cp[-1] != ':') {
112: /*
113: * Not a header line, force out status:
114: * This happens in uucp style mail where
115: * there are no headers at all.
116: */
117: if (dostat) {
118: statusput(mp, obuf, prefix);
119: dostat = 0;
120: }
121: if (doign != ignoreall)
122: /* add blank line */
123: (void) putc('\n', obuf);
124: ishead = 0;
125: ignoring = 0;
126: } else {
127: /*
128: * If it is an ignored field and
129: * we care about such things, skip it.
130: */
131: *cp2 = 0; /* temporarily null terminate */
132: if (doign && isign(line, doign))
133: ignoring = 1;
134: else if ((line[0] == 's' || line[0] == 'S') &&
135: strcasecmp(line, "status") == 0) {
136: /*
137: * If the field is "status," go compute
138: * and print the real Status: field
139: */
140: if (dostat) {
141: statusput(mp, obuf, prefix);
142: dostat = 0;
143: }
144: ignoring = 1;
145: } else {
146: ignoring = 0;
147: *cp2 = c; /* restore */
148: }
149: infld = 1;
150: }
151: }
152: if (!ignoring) {
153: /*
154: * Strip trailing whitespace from prefix
155: * if line is blank.
156: */
157: if (prefix != NOSTR)
158: if (length > 1)
159: fputs(prefix, obuf);
160: else
161: (void) fwrite(prefix, sizeof *prefix,
162: prefixlen, obuf);
163: (void) fwrite(line, sizeof *line, length, obuf);
164: if (ferror(obuf))
165: return -1;
166: }
167: }
168: /*
169: * Copy out message body
170: */
171: if (doign == ignoreall)
172: count--; /* skip final blank line */
173: if (prefix != NOSTR)
174: while (count > 0) {
175: if (fgets(line, LINESIZE, ibuf) == NULL) {
176: c = 0;
177: break;
178: }
179: count -= c = strlen(line);
180: /*
181: * Strip trailing whitespace from prefix
182: * if line is blank.
183: */
184: if (c > 1)
185: fputs(prefix, obuf);
186: else
187: (void) fwrite(prefix, sizeof *prefix,
188: prefixlen, obuf);
189: (void) fwrite(line, sizeof *line, c, obuf);
190: if (ferror(obuf))
191: return -1;
192: }
193: else
194: while (count > 0) {
195: c = count < LINESIZE ? count : LINESIZE;
196: if ((c = fread(line, sizeof *line, c, ibuf)) <= 0)
197: break;
198: count -= c;
199: if (fwrite(line, sizeof *line, c, obuf) != c)
200: return -1;
201: }
202: if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
203: /* no final blank line */
204: if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
205: return -1;
206: return 0;
207: }
208:
209: /*
210: * Output a reasonable looking status field.
211: */
212: statusput(mp, obuf, prefix)
213: register struct message *mp;
214: FILE *obuf;
215: char *prefix;
216: {
217: char statout[3];
218: register char *cp = statout;
219:
220: if (mp->m_flag & MREAD)
221: *cp++ = 'R';
222: if ((mp->m_flag & MNEW) == 0)
223: *cp++ = 'O';
224: *cp = 0;
225: if (statout[0])
226: fprintf(obuf, "%sStatus: %s\n",
227: prefix == NOSTR ? "" : prefix, statout);
228: }
229:
230: /*
231: * Interface between the argument list and the mail1 routine
232: * which does all the dirty work.
233: */
234: mail(to, cc, bcc, smopts, subject)
235: struct name *to, *cc, *bcc, *smopts;
236: char *subject;
237: {
238: struct header head;
239:
240: head.h_to = to;
241: head.h_subject = subject;
242: head.h_cc = cc;
243: head.h_bcc = bcc;
244: head.h_smopts = smopts;
245: mail1(&head, 0);
246: return(0);
247: }
248:
249:
250: /*
251: * Send mail to a bunch of user names. The interface is through
252: * the mail routine below.
253: */
254: sendmail(str)
255: char *str;
256: {
257: struct header head;
258:
259: head.h_to = extract(str, GTO);
260: head.h_subject = NOSTR;
261: head.h_cc = NIL;
262: head.h_bcc = NIL;
263: head.h_smopts = NIL;
264: mail1(&head, 0);
265: return(0);
266: }
267:
268: /*
269: * Mail a message on standard input to the people indicated
270: * in the passed header. (Internal interface).
271: */
272: mail1(hp, printheaders)
273: struct header *hp;
274: {
275: char *cp;
276: int pid;
277: char **namelist;
278: struct name *to;
279: FILE *mtf;
280:
281: /*
282: * Collect user's mail from standard input.
283: * Get the result as mtf.
284: */
285: if ((mtf = collect(hp, printheaders)) == NULL)
286: return;
287: if (value("interactive") != NOSTR)
288: if (value("askcc") != NOSTR)
289: grabh(hp, GCC);
290: else {
291: printf("EOT\n");
292: (void) fflush(stdout);
293: }
294: if (fsize(mtf) == 0)
295: if (hp->h_subject == NOSTR)
296: printf("No message, no subject; hope that's ok\n");
297: else
298: printf("Null message body; hope that's ok\n");
299: /*
300: * Now, take the user names from the combined
301: * to and cc lists and do all the alias
302: * processing.
303: */
304: senderr = 0;
305: to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
306: if (to == NIL) {
307: printf("No recipients specified\n");
308: senderr++;
309: }
310: /*
311: * Look through the recipient list for names with /'s
312: * in them which we write to as files directly.
313: */
314: to = outof(to, mtf, hp);
315: if (senderr)
316: savedeadletter(mtf);
317: to = elide(to);
318: if (count(to) == 0)
319: goto out;
320: fixhead(hp, to);
321: if ((mtf = infix(hp, mtf)) == NULL) {
322: fprintf(stderr, ". . . message lost, sorry.\n");
323: return;
324: }
325: namelist = unpack(cat(hp->h_smopts, to));
326: if (debug) {
327: char **t;
328:
329: printf("Sendmail arguments:");
330: for (t = namelist; *t != NOSTR; t++)
331: printf(" \"%s\"", *t);
332: printf("\n");
333: goto out;
334: }
335: if ((cp = value("record")) != NOSTR)
336: (void) savemail(expand(cp), mtf);
337: /*
338: * Fork, set up the temporary mail file as standard
339: * input for "mail", and exec with the user list we generated
340: * far above.
341: */
342: pid = fork();
343: if (pid == -1) {
344: perror("fork");
345: savedeadletter(mtf);
346: goto out;
347: }
348: if (pid == 0) {
349: if (access(_PATH_MAIL_LOG, 0) == 0) {
350: FILE *postage;
351:
352: if ((postage = Fopen(_PATH_MAIL_LOG, "a")) != NULL) {
353: fprintf(postage, "%s %d %ld\n", myname,
354: count(to), fsize(mtf));
355: (void) Fclose(postage);
356: }
357: }
358: prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)|
359: sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU),
360: fileno(mtf), -1);
361: if ((cp = value("sendmail")) != NOSTR)
362: cp = expand(cp);
363: else
364: cp = _PATH_SENDMAIL;
365: execv(cp, namelist);
366: perror(cp);
367: _exit(1);
368: }
369: if (value("verbose") != NOSTR)
370: (void) wait_child(pid);
371: else
372: free_child(pid);
373: out:
374: (void) Fclose(mtf);
375: }
376:
377: /*
378: * Fix the header by glopping all of the expanded names from
379: * the distribution list into the appropriate fields.
380: */
381: fixhead(hp, tolist)
382: struct header *hp;
383: struct name *tolist;
384: {
385: register struct name *np;
386:
387: hp->h_to = NIL;
388: hp->h_cc = NIL;
389: hp->h_bcc = NIL;
390: for (np = tolist; np != NIL; np = np->n_flink)
391: if ((np->n_type & GMASK) == GTO)
392: hp->h_to =
393: cat(hp->h_to, nalloc(np->n_name, np->n_type));
394: else if ((np->n_type & GMASK) == GCC)
395: hp->h_cc =
396: cat(hp->h_cc, nalloc(np->n_name, np->n_type));
397: else if ((np->n_type & GMASK) == GBCC)
398: hp->h_bcc =
399: cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
400: }
401:
402: /*
403: * Prepend a header in front of the collected stuff
404: * and return the new file.
405: */
406: FILE *
407: infix(hp, fi)
408: struct header *hp;
409: FILE *fi;
410: {
411: extern char tempMail[];
412: register FILE *nfo, *nfi;
413: register int c;
414:
415: if ((nfo = Fopen(tempMail, "w")) == NULL) {
416: perror(tempMail);
417: return(fi);
418: }
419: if ((nfi = Fopen(tempMail, "r")) == NULL) {
420: perror(tempMail);
421: (void) Fclose(nfo);
422: return(fi);
423: }
424: (void) remove(tempMail);
425: (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
426: c = getc(fi);
427: while (c != EOF) {
428: (void) putc(c, nfo);
429: c = getc(fi);
430: }
431: if (ferror(fi)) {
432: perror("read");
433: rewind(fi);
434: return(fi);
435: }
436: (void) fflush(nfo);
437: if (ferror(nfo)) {
438: perror(tempMail);
439: (void) Fclose(nfo);
440: (void) Fclose(nfi);
441: rewind(fi);
442: return(fi);
443: }
444: (void) Fclose(nfo);
445: (void) Fclose(fi);
446: rewind(nfi);
447: return(nfi);
448: }
449:
450: /*
451: * Dump the to, subject, cc header on the
452: * passed file buffer.
453: */
454: puthead(hp, fo, w)
455: struct header *hp;
456: FILE *fo;
457: {
458: register int gotcha;
459:
460: gotcha = 0;
461: if (hp->h_to != NIL && w & GTO)
462: fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
463: if (hp->h_subject != NOSTR && w & GSUBJECT)
464: fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
465: if (hp->h_cc != NIL && w & GCC)
466: fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
467: if (hp->h_bcc != NIL && w & GBCC)
468: fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
469: if (gotcha && w & GNL)
470: (void) putc('\n', fo);
471: return(0);
472: }
473:
474: /*
475: * Format the given header line to not exceed 72 characters.
476: */
477: fmt(str, np, fo, comma)
478: char *str;
479: register struct name *np;
480: FILE *fo;
481: int comma;
482: {
483: register col, len;
484:
485: comma = comma ? 1 : 0;
486: col = strlen(str);
487: if (col)
488: fputs(str, fo);
489: for (; np != NIL; np = np->n_flink) {
490: if (np->n_flink == NIL)
491: comma = 0;
492: len = strlen(np->n_name);
493: col++; /* for the space */
494: if (col + len + comma > 72 && col > 4) {
495: fputs("\n ", fo);
496: col = 4;
497: } else
498: putc(' ', fo);
499: fputs(np->n_name, fo);
500: if (comma)
501: putc(',', fo);
502: col += len + comma;
503: }
504: putc('\n', fo);
505: }
506:
507: /*
508: * Save the outgoing mail on the passed file.
509: */
510:
511: /*ARGSUSED*/
512: savemail(name, fi)
513: char name[];
514: register FILE *fi;
515: {
516: register FILE *fo;
517: char buf[BUFSIZ];
518: register i;
519: time_t now, time();
520: char *ctime();
521:
522: if ((fo = Fopen(name, "a")) == NULL) {
523: perror(name);
524: return (-1);
525: }
526: (void) time(&now);
527: fprintf(fo, "From %s %s", myname, ctime(&now));
528: while ((i = fread(buf, 1, sizeof buf, fi)) > 0)
529: (void) fwrite(buf, 1, i, fo);
530: (void) putc('\n', fo);
531: (void) fflush(fo);
532: if (ferror(fo))
533: perror(name);
534: (void) Fclose(fo);
535: rewind(fi);
536: return (0);
537: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.