|
|
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
6: * provided that this notice is preserved and that due credit is given
7: * to the University of California at Berkeley. The name of the University
8: * may not be used to endorse or promote products derived from this
9: * software without specific prior written permission. This software
10: * is provided ``as is'' without express or implied warranty.
11: */
12:
13: #ifdef notdef
14: static char sccsid[] = "@(#)send.c 5.5 (Berkeley) 2/18/88";
15: #endif /* notdef */
16:
17: #include "rcv.h"
18: #include <sys/wait.h>
19: #include <sys/stat.h>
20:
21: /*
22: * Mail -- a mail program
23: *
24: * Mail to others.
25: */
26:
27: /*
28: * Send message described by the passed pointer to the
29: * passed output buffer. Return -1 on error, but normally
30: * the number of lines written. Adjust the status: field
31: * if need be. If doign is set, suppress ignored header fields.
32: */
33: send(mp, obuf, doign)
34: register struct message *mp;
35: FILE *obuf;
36: {
37: long count;
38: register FILE *ibuf;
39: char line[LINESIZE];
40: int lc, ishead, infld, ignoring, dostat;
41: register char *cp, *cp2;
42: register int c;
43: int length;
44:
45: ibuf = setinput(mp);
46: count = mp->m_size;
47: ishead = 1;
48: dostat = !doign || !isign("status");
49: infld = 0;
50: lc = 0;
51: /*
52: * Process headers first
53: */
54: while (count > 0 && ishead) {
55: if (fgets(line, LINESIZE, ibuf) == NULL)
56: break;
57: count -= length = strlen(line);
58: if (lc == 0) {
59: /*
60: * First line is the From line, so no headers
61: * there to worry about
62: */
63: ignoring = 0;
64: } else if (line[0] == '\n') {
65: /*
66: * If line is blank, we've reached end of
67: * headers, so force out status: field
68: * and note that we are no longer in header
69: * fields
70: */
71: if (dostat) {
72: statusput(mp, obuf);
73: dostat = 0;
74: }
75: ishead = 0;
76: ignoring = 0;
77: } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
78: /*
79: * If this line is a continuation (via space or tab)
80: * of a previous header field, just echo it
81: * (unless the field should be ignored).
82: * In other words, nothing to do.
83: */
84: } else {
85: /*
86: * Pick up the header field if we have one.
87: */
88: for (cp = line; (c = *cp++) && c != ':' && !isspace(c);)
89: ;
90: cp2 = --cp;
91: while (isspace(*cp++))
92: ;
93: if (cp[-1] != ':') {
94: /*
95: * Not a header line, force out status:
96: * This happens in uucp style mail where
97: * there are no headers at all.
98: */
99: if (dostat) {
100: statusput(mp, obuf);
101: dostat = 0;
102: }
103: (void) putc('\n', obuf); /* add blank line */
104: lc++;
105: ishead = 0;
106: ignoring = 0;
107: } else {
108: /*
109: * If it is an ignored field and
110: * we care about such things, skip it.
111: */
112: *cp2 = 0; /* temporarily null terminate */
113: if (doign && isign(line))
114: ignoring = 1;
115: else if ((line[0] == 's' || line[0] == 'S') &&
116: icequal(line, "status")) {
117: /*
118: * If the field is "status," go compute
119: * and print the real Status: field
120: */
121: if (dostat) {
122: statusput(mp, obuf);
123: dostat = 0;
124: }
125: ignoring = 1;
126: } else {
127: ignoring = 0;
128: *cp2 = c; /* restore */
129: }
130: infld = 1;
131: }
132: }
133: if (!ignoring) {
134: (void) fwrite(line, sizeof *line, length, obuf);
135: if (ferror(obuf))
136: return -1;
137: lc++;
138: }
139: }
140: /*
141: * Copy out message body
142: */
143: while (count > 0) {
144: cp = line;
145: c = count < LINESIZE ? count : LINESIZE;
146: if ((c = fread(cp, sizeof *cp, c, ibuf)) <= 0)
147: break;
148: if (fwrite(cp, sizeof *cp, c, obuf) != c)
149: return -1;
150: count -= c;
151: while (--c >= 0)
152: if (*cp++ == '\n')
153: lc++;
154: }
155: if (ishead && (mp->m_flag & MSTATUS))
156: printf("failed to fix up status field\n");
157: return (lc);
158: }
159:
160: /*
161: * Output a reasonable looking status field.
162: * But if "status" is ignored and doign, forget it.
163: */
164: statusput(mp, obuf)
165: register struct message *mp;
166: FILE *obuf;
167: {
168: char statout[3];
169: register char *cp = statout;
170:
171: if (mp->m_flag & MREAD)
172: *cp++ = 'R';
173: if ((mp->m_flag & MNEW) == 0)
174: *cp++ = 'O';
175: *cp = 0;
176: if (statout[0])
177: fprintf(obuf, "Status: %s\n", statout);
178: }
179:
180: /*
181: * Interface between the argument list and the mail1 routine
182: * which does all the dirty work.
183: */
184:
185: mail(people)
186: char **people;
187: {
188: register char *cp2;
189: register int s;
190: char *buf, **ap;
191: struct header head;
192:
193: for (s = 0, ap = people; *ap != 0; ap++)
194: s += strlen(*ap) + 1;
195: buf = salloc(s+1);
196: cp2 = buf;
197: for (ap = people; *ap != 0; ap++) {
198: cp2 = copy(*ap, cp2);
199: *cp2++ = ' ';
200: }
201: if (cp2 != buf)
202: cp2--;
203: *cp2 = '\0';
204: head.h_to = buf;
205: head.h_subject = NOSTR;
206: head.h_cc = NOSTR;
207: head.h_bcc = NOSTR;
208: head.h_seq = 0;
209: (void) mail1(&head);
210: return(0);
211: }
212:
213:
214: /*
215: * Send mail to a bunch of user names. The interface is through
216: * the mail routine below.
217: */
218:
219: sendmail(str)
220: char *str;
221: {
222: struct header head;
223:
224: if (blankline(str))
225: head.h_to = NOSTR;
226: else
227: head.h_to = str;
228: head.h_subject = NOSTR;
229: head.h_cc = NOSTR;
230: head.h_bcc = NOSTR;
231: head.h_seq = 0;
232: (void) mail1(&head);
233: return(0);
234: }
235:
236: /*
237: * Mail a message on standard input to the people indicated
238: * in the passed header. (Internal interface).
239: */
240:
241: mail1(hp)
242: struct header *hp;
243: {
244: register char *cp;
245: int pid, i, p, gotcha;
246: union wait s;
247: char **namelist, *deliver;
248: struct name *to, *np;
249: struct stat sbuf;
250: FILE *mtf, *postage;
251: int remote = rflag != NOSTR || rmail;
252: char **t;
253:
254: /*
255: * Collect user's mail from standard input.
256: * Get the result as mtf.
257: */
258:
259: pid = -1;
260: if ((mtf = collect(hp)) == NULL)
261: return(-1);
262: hp->h_seq = 1;
263: if (hp->h_subject == NOSTR)
264: hp->h_subject = sflag;
265: if (intty && value("askcc") != NOSTR)
266: grabh(hp, GCC);
267: else if (intty) {
268: printf("EOT\n");
269: (void) fflush(stdout);
270: }
271:
272: /*
273: * Now, take the user names from the combined
274: * to and cc lists and do all the alias
275: * processing.
276: */
277:
278: senderr = 0;
279: to = usermap(cat(extract(hp->h_bcc, GBCC),
280: cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC))));
281: if (to == NIL) {
282: printf("No recipients specified\n");
283: goto topdog;
284: }
285:
286: /*
287: * Look through the recipient list for names with /'s
288: * in them which we write to as files directly.
289: */
290:
291: to = outof(to, mtf, hp);
292: rewind(mtf);
293: to = verify(to);
294: if (senderr && !remote) {
295: topdog:
296:
297: if (fsize(mtf) != 0) {
298: (void) remove(deadletter);
299: (void) exwrite(deadletter, mtf, 1);
300: rewind(mtf);
301: }
302: }
303: for (gotcha = 0, np = to; np != NIL; np = np->n_flink)
304: if ((np->n_type & GDEL) == 0) {
305: gotcha++;
306: break;
307: }
308: if (!gotcha)
309: goto out;
310: to = elide(to);
311: mechk(to);
312: if (count(to) > 1)
313: hp->h_seq++;
314: if (hp->h_seq > 0 && !remote) {
315: fixhead(hp, to);
316: if (fsize(mtf) == 0)
317: if (hp->h_subject == NOSTR)
318: printf("No message, no subject; hope that's ok\n");
319: else
320: printf("Null message body; hope that's ok\n");
321: if ((mtf = infix(hp, mtf)) == NULL) {
322: fprintf(stderr, ". . . message lost, sorry.\n");
323: return(-1);
324: }
325: }
326: namelist = unpack(to);
327: if (debug) {
328: printf("Recipients of message:\n");
329: for (t = namelist; *t != NOSTR; t++)
330: printf(" \"%s\"", *t);
331: printf("\n");
332: (void) fflush(stdout);
333: return 0;
334: }
335: if ((cp = value("record")) != NOSTR)
336: (void) savemail(expand(cp), mtf);
337:
338: /*
339: * Wait, to absorb a potential zombie, then
340: * fork, set up the temporary mail file as standard
341: * input for "mail" and exec with the user list we generated
342: * far above. Return the process id to caller in case he
343: * wants to await the completion of mail.
344: */
345:
346: while (wait3(&s, WNOHANG, (struct timeval *) 0) > 0)
347: ;
348: rewind(mtf);
349: pid = fork();
350: if (pid == -1) {
351: perror("fork");
352: (void) remove(deadletter);
353: (void) exwrite(deadletter, mtf, 1);
354: goto out;
355: }
356: if (pid == 0) {
357: #ifdef SIGTSTP
358: if (remote == 0) {
359: (void) signal(SIGTSTP, SIG_IGN);
360: (void) signal(SIGTTIN, SIG_IGN);
361: (void) signal(SIGTTOU, SIG_IGN);
362: }
363: #endif
364: (void) signal(SIGHUP, SIG_IGN);
365: (void) signal(SIGINT, SIG_IGN);
366: (void) signal(SIGQUIT, SIG_IGN);
367: if (!stat(POSTAGE, &sbuf))
368: if ((postage = fopen(POSTAGE, "a")) != NULL) {
369: fprintf(postage, "%s %d %ld\n", myname,
370: count(to), fsize(mtf));
371: (void) fclose(postage);
372: }
373: (void) close(0);
374: (void) dup(fileno(mtf));
375: for (i = getdtablesize(); --i > 2;)
376: (void) close(i);
377: #ifdef SENDMAIL
378: if ((deliver = value("sendmail")) == NOSTR)
379: deliver = SENDMAIL;
380: execv(deliver, namelist);
381: #endif SENDMAIL
382: execv(MAIL, namelist);
383: perror(MAIL);
384: exit(1);
385: }
386:
387: out:
388: if (remote || (value("verbose") != NOSTR)) {
389: while ((p = wait(&s)) != pid && p != -1)
390: ;
391: if (s.w_status != 0)
392: senderr++;
393: pid = 0;
394: }
395: (void) fclose(mtf);
396: return(pid);
397: }
398:
399: /*
400: * Fix the header by glopping all of the expanded names from
401: * the distribution list into the appropriate fields.
402: * If there are any ARPA net recipients in the message,
403: * we must insert commas, alas.
404: */
405:
406: fixhead(hp, tolist)
407: struct header *hp;
408: struct name *tolist;
409: {
410: register int f;
411: register struct name *np;
412:
413: for (f = 0, np = tolist; np != NIL; np = np->n_flink)
414: if (any('@', np->n_name)) {
415: f |= GCOMMA;
416: break;
417: }
418:
419: if (debug && f & GCOMMA)
420: fprintf(stderr, "Should be inserting commas in recip lists\n");
421: hp->h_to = detract(tolist, GTO|f);
422: hp->h_cc = detract(tolist, GCC|f);
423: }
424:
425: /*
426: * Prepend a header in front of the collected stuff
427: * and return the new file.
428: */
429:
430: FILE *
431: infix(hp, fi)
432: struct header *hp;
433: FILE *fi;
434: {
435: extern char tempMail[];
436: register FILE *nfo, *nfi;
437: register int c;
438:
439: rewind(fi);
440: if ((nfo = fopen(tempMail, "w")) == NULL) {
441: perror(tempMail);
442: return(fi);
443: }
444: if ((nfi = fopen(tempMail, "r")) == NULL) {
445: perror(tempMail);
446: (void) fclose(nfo);
447: return(fi);
448: }
449: (void) remove(tempMail);
450: (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL);
451: c = getc(fi);
452: while (c != EOF) {
453: (void) putc(c, nfo);
454: c = getc(fi);
455: }
456: if (ferror(fi)) {
457: perror("read");
458: return(fi);
459: }
460: (void) fflush(nfo);
461: if (ferror(nfo)) {
462: perror(tempMail);
463: (void) fclose(nfo);
464: (void) fclose(nfi);
465: return(fi);
466: }
467: (void) fclose(nfo);
468: (void) fclose(fi);
469: rewind(nfi);
470: return(nfi);
471: }
472:
473: /*
474: * Dump the to, subject, cc header on the
475: * passed file buffer.
476: */
477:
478: puthead(hp, fo, w)
479: struct header *hp;
480: FILE *fo;
481: {
482: register int gotcha;
483:
484: gotcha = 0;
485: if (hp->h_to != NOSTR && w & GTO)
486: fmt("To: ", hp->h_to, fo), gotcha++;
487: if (hp->h_subject != NOSTR && w & GSUBJECT)
488: fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
489: if (hp->h_cc != NOSTR && w & GCC)
490: fmt("Cc: ", hp->h_cc, fo), gotcha++;
491: if (hp->h_bcc != NOSTR && w & GBCC)
492: fmt("Bcc: ", hp->h_bcc, fo), gotcha++;
493: if (gotcha && w & GNL)
494: (void) putc('\n', fo);
495: return(0);
496: }
497:
498: /*
499: * Format the given text to not exceed 72 characters.
500: */
501:
502: fmt(str, txt, fo)
503: register char *str, *txt;
504: register FILE *fo;
505: {
506: register int col;
507: register char *bg, *bl, *pt, ch;
508:
509: col = strlen(str);
510: if (col)
511: fprintf(fo, "%s", str);
512: pt = bg = txt;
513: bl = 0;
514: while (*bg) {
515: pt++;
516: if (++col > 72) {
517: if (!bl) {
518: bl = bg;
519: while (*bl && !isspace(*bl))
520: bl++;
521: }
522: if (!*bl)
523: goto finish;
524: ch = *bl;
525: *bl = '\0';
526: fprintf(fo, "%s\n ", bg);
527: col = 4;
528: *bl = ch;
529: pt = bg = ++bl;
530: bl = 0;
531: }
532: if (!*pt) {
533: finish:
534: fprintf(fo, "%s\n", bg);
535: return;
536: }
537: if (isspace(*pt))
538: bl = pt;
539: }
540: }
541:
542: /*
543: * Save the outgoing mail on the passed file.
544: */
545:
546: /*ARGSUSED*/
547: savemail(name, fi)
548: char name[];
549: register FILE *fi;
550: {
551: register FILE *fo;
552: char buf[BUFSIZ];
553: register i;
554: time_t now, time();
555: char *n;
556: char *ctime();
557:
558: if ((fo = fopen(name, "a")) == NULL) {
559: perror(name);
560: return (-1);
561: }
562: (void) time(&now);
563: if ((n = rflag) == NOSTR)
564: n = myname;
565: fprintf(fo, "From %s %s", n, ctime(&now));
566: rewind(fi);
567: while ((i = fread(buf, 1, sizeof buf, fi)) > 0)
568: (void) fwrite(buf, 1, i, fo);
569: (void) putc('\n', fo);
570: (void) fflush(fo);
571: if (ferror(fo))
572: perror(name);
573: (void) fclose(fo);
574: return (0);
575: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.