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