|
|
1.1 root 1: #ident "@(#)send.c 1.6 'attmail mail(1) command'"
2: #ident "@(#)mailx:send.c 1.11.1.2"
3: /* Copyright (c) 1984 AT&T */
4: /* All Rights Reserved */
5:
6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
7: /* The copyright notice above does not evidence any */
8: /* actual or intended publication of such source code. */
9:
10: #ident "@(#)mailx:send.c 1.11.1.1"
11:
12: #include "rcv.h"
13:
14: /*
15: * mailx -- a modified version of a University of California at Berkeley
16: * mail program
17: *
18: * Mail to others.
19: */
20:
21: static void fmt();
22: static FILE *infix();
23: static void statusput();
24: static int savemail();
25: static int sendmail();
26: static int Sendmail();
27:
28: static off_t textpos;
29:
30: /*
31: * Send message described by the passed pointer to the
32: * passed output buffer. Return -1 on error, but normally
33: * the number of lines written. Adjust the status: field
34: * if need be. If doign is set, suppress ignored header fields.
35: */
36: long
37: send(mailp, obuf, doign)
38: struct message *mailp;
39: FILE *obuf;
40: {
41: register struct message *mp;
42: long clen, n, c;
43: FILE *ibuf;
44: char line[LINESIZE+1], field[BUFSIZ];
45: int ishead, infld, fline, dostat, nread, unused;
46: char *cp, *cp2;
47: int oldign = 0; /* previous line was ignored */
48: long lc;
49:
50: mp = mailp;
51: ibuf = setinput(mp);
52: c = mp->m_size;
53: ishead = 1;
54: dostat = 1;
55: infld = 0;
56: fline = 1;
57: lc = 0;
58: clearerr(obuf);
59: while (c > 0L) {
60: nread = getline(line, LINESIZE, ibuf, &unused);
61: c -= nread;
62: lc++;
63: if (ishead) {
64: /*
65: * First line is the From line, so no headers
66: * there to worry about
67: */
68: if (fline) {
69: fline = 0;
70: goto writeit;
71: }
72: /*
73: * If line is blank, we've reached end of
74: * headers, so force out status: field
75: * and note that we are no longer in header
76: * fields
77: */
78: if (line[0] == '\n') {
79: if (dostat) {
80: statusput(mailp, obuf, doign);
81: dostat = 0;
82: }
83: ishead = 0;
84: putc('\n', obuf);
85: continue;
86: }
87: /*
88: * If this line is a continuation
89: * of a previous header field, just echo it.
90: */
91: if (isspace(line[0]) && infld)
92: if (oldign)
93: continue;
94: else
95: goto writeit;
96: infld = 0;
97: /*
98: * If we are no longer looking at real
99: * header lines, force out status:
100: * This happens in uucp style mail where
101: * there are no headers at all.
102: */
103: if (!headerp(line)) {
104: if (dostat) {
105: statusput(mailp, obuf, doign);
106: dostat = 0;
107: }
108: putc('\n', obuf);
109: ishead = 0;
110: goto writeit;
111: }
112: infld++;
113: /*
114: * Pick up the header field.
115: * If it is an ignored field and
116: * we care about such things, skip it.
117: */
118: cp = line;
119: cp2 = field;
120: while (*cp && *cp != ':' && !isspace(*cp))
121: *cp2++ = *cp++;
122: *cp2 = 0;
123: oldign = doign && isign(field);
124: if (oldign)
125: continue;
126: /*
127: * If the field is "status," go compute and print the
128: * real Status: field
129: */
130: if (icequal(field, "status")) {
131: if (dostat) {
132: statusput(mailp, obuf, doign);
133: dostat = 0;
134: }
135: continue;
136: }
137: }
138: writeit:
139: if ((!ishead) && (!(mp->m_text))) {
140: fwrite(line, 1, nread, obuf); /* output first non-hdr */
141: if (ferror(obuf))
142: return(-1);
143: clen = mp->m_clen - nread;
144: n = clen < sizeof line ? clen : sizeof line;
145: for (;n > 0;) {
146: if ((n = fread(line, 1, n, ibuf)) <= 0) {
147: fprintf(stderr, "\t(Unexpected end-of-file).\n");
148: clen = 0;
149: } else {
150: if (fwrite(line, 1, n, obuf) != n) {
151: fprintf(stderr, "\t Error writing to the new file.\n");
152: fflush(obuf);
153: if (ferror(obuf))
154: return (-1);
155: }
156: }
157: clen -= n;
158: if (clen <= 0) {
159: break;
160: }
161: }
162: c = 0L;
163: } else {
164: fwrite(line, 1, nread, obuf);
165: if (ferror(obuf))
166: return(-1);
167: }
168: }
169: fflush(obuf);
170: if (ferror(obuf))
171: return(-1);
172: if (ishead && (mailp->m_flag & MSTATUS))
173: printf("failed to fix up status field\n");
174: return(lc);
175: }
176:
177: /*
178: * Test if the passed line is a header line, RFC 733 style.
179: */
180: headerp(line)
181: register char *line;
182: {
183: register char *cp = line;
184:
185: if (*cp=='>' && strncmp(cp+1, "From", 4)==0)
186: return(1);
187: while (*cp && !isspace(*cp) && *cp != ':')
188: cp++;
189: while (*cp && isspace(*cp))
190: cp++;
191: return(*cp == ':');
192: }
193:
194: /*
195: * Output a reasonable looking status field.
196: * But if "status" is ignored and doign, forget it.
197: */
198: static void
199: statusput(mp, obuf, doign)
200: register struct message *mp;
201: register FILE *obuf;
202: {
203: char statout[3];
204:
205: if (doign && isign("status"))
206: return;
207: if ((mp->m_flag & (MNEW|MREAD)) == MNEW)
208: return;
209: if (mp->m_flag & MREAD)
210: strcpy(statout, "R");
211: else
212: strcpy(statout, "");
213: if ((mp->m_flag & MNEW) == 0)
214: strcat(statout, "O");
215: fprintf(obuf, "Status: %s\n", statout);
216: }
217:
218: /*
219: * Interface between the argument list and the mail1 routine
220: * which does all the dirty work.
221: */
222:
223: mail(people)
224: char **people;
225: {
226: register char *cp2;
227: register int s;
228: char *buf, **ap;
229: struct header head;
230: char recfile[128];
231:
232: for (s = 0, ap = people; *ap; ap++)
233: s += strlen(*ap) + 2;
234: buf = salloc((unsigned)(s+1));
235: cp2 = buf;
236: for (ap = people; *ap; ap++) {
237: cp2 = copy(*ap, cp2);
238: /* *cp2++ = ','; adb: not in our mail */
239: *cp2++ = ' ';
240: }
241: *cp2 = '\0';
242: head.h_to = buf;
243: strncpy(recfile, buf, sizeof recfile);
244: head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR;
245: head.h_others = NOSTRPTR;
246: head.h_seq = 0;
247: mail1(&head, Fflag ? recfile : 0);
248: return(0);
249: }
250:
251: sendm(str)
252: char *str;
253: {
254: if (value("flipm") != NOSTR)
255: return(Sendmail(str));
256: else return(sendmail(str));
257: }
258:
259: Sendm(str)
260: char *str;
261: {
262: if (value("flipm") != NOSTR)
263: return(sendmail(str));
264: else return(Sendmail(str));
265: }
266:
267: /*
268: * Send mail to a bunch of user names. The interface is through
269: * the mail routine below.
270: */
271: static int
272: sendmail(str)
273: char *str;
274: {
275: struct header head;
276:
277: if (blankline(str))
278: head.h_to = NOSTR;
279: else
280: head.h_to = addto(NOSTR, str);
281: head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR;
282: head.h_others = NOSTRPTR;
283: head.h_seq = 0;
284: mail1(&head, (char *) 0);
285: return(0);
286: }
287:
288: /*
289: * Send mail to a bunch of user names. The interface is through
290: * the mail routine below.
291: * save a copy of the letter
292: */
293: static int
294: Sendmail(str)
295: char *str;
296: {
297: char recfile[128];
298: struct header head;
299:
300: if (blankline(str))
301: head.h_to = NOSTR;
302: else
303: head.h_to = addto(NOSTR, str);
304: strncpy(recfile, head.h_to, sizeof recfile);
305: head.h_subject = head.h_cc = head.h_bcc = head.h_defopt = NOSTR;
306: head.h_others = NOSTRPTR;
307: head.h_seq = 0;
308: mail1(&head, recfile);
309: return(0);
310: }
311:
312: /*
313: * Mail a message on standard input to the people indicated
314: * in the passed header. (Internal interface).
315: */
316: void
317: mail1(hp, rec)
318: struct header *hp;
319: char *rec;
320: {
321: pid_t p, pid;
322: int i, s, gotcha;
323: char **namelist, *deliver;
324: struct name *to, *np;
325: FILE *mtf, *fp;
326: int remote = rflag != NOSTR || rmail;
327: char **t;
328: char *deadletter;
329: char recfile[128];
330:
331: /*
332: * Collect user's mail from standard input.
333: * Get the result as mtf.
334: */
335:
336: pid = (pid_t)-1;
337: if ((mtf = collect(hp)) == NULL)
338: return;
339: hp->h_seq = 1;
340: if (hp->h_subject == NOSTR)
341: hp->h_subject = sflag;
342: if (fsize(mtf) == 0 && hp->h_subject == NOSTR) {
343: printf("No message !?!\n");
344: goto out;
345: }
346: if (intty) {
347: printf("EOT\n");
348: flush();
349: }
350:
351: /*
352: * Now, take the user names from the combined
353: * to and cc lists and do all the alias
354: * processing.
355: */
356:
357: senderr = 0;
358: to = cat(extract(hp->h_bcc, GBCC),
359: cat(extract(hp->h_to, GTO),
360: extract(hp->h_cc, GCC)));
361: /* to = translate(outpre(elide(usermap(to)))); I can't imagine why outpre is used--adb */
362: to = translate(elide(usermap(to)));
363: if (!senderr)
364: mapf(to, myname);
365: mechk(to);
366: for (gotcha = 0, np = to; np != NIL; np = np->n_flink)
367: if ((np->n_type & GDEL) == 0)
368: gotcha++;
369: hp->h_to = detract(to, GTO);
370: hp->h_cc = detract(to, GCC);
371: hp->h_bcc = detract(to, GBCC);
372: if ((mtf = infix(hp, mtf)) == NULL) {
373: fprintf(stderr, ". . . message lost, sorry.\n");
374: return;
375: }
376: rewind(mtf);
377: if (askme && isatty(0)) {
378: char ans[64];
379: puthead(hp, stdout, GTO|GCC|GBCC);
380: printf("Send? [yes] ");
381: if (fgets(ans, sizeof(ans), stdin) && ans[0] && tolower(ans[0]) != 'y')
382: goto dead;
383: }
384: if (senderr)
385: goto dead;
386: /*
387: * Look through the recipient list for names with /'s
388: * in them which we write to as files directly.
389: */
390: i = outof(to, mtf);
391: rewind(mtf);
392: if (!gotcha && !i) {
393: printf("No recipients specified\n");
394: goto dead;
395: }
396: if (senderr)
397: goto dead;
398: if ((gotcha - i) == 0)
399: return;
400:
401: getrecf(rec, recfile, !!rec);
402: if (recfile != NOSTR && *recfile)
403: savemail(expand(recfile), hp, mtf);
404: if (!gotcha)
405: goto out;
406: namelist = unpack(to);
407: if (debug) {
408: fprintf(stderr, "Recipients of message:\n");
409: for (t = namelist; *t != NOSTR; t++)
410: fprintf(stderr, " \"%s\"", *t);
411: fprintf(stderr, "\n");
412: return;
413: }
414:
415: /*
416: * Wait, to absorb a potential zombie, then
417: * fork, set up the temporary mail file as standard
418: * input for "mail" and exec with the user list we generated
419: * far above. Return the process id to caller in case he
420: * wants to await the completion of mail.
421: */
422:
423: wait(&s);
424: rewind(mtf);
425: pid = fork();
426: if (pid == (pid_t)-1) {
427: perror("fork");
428: dead:
429: deadletter = Getf("DEAD");
430: removefile(deadletter); /* adb -- old style */
431: if (fp = fopen(deadletter, "w")) { /* adb */
432: puthead(hp, fp, GMASK);
433: fseek(mtf, textpos, 0);
434: lcwrite(deadletter, mtf, fp);
435: fclose(fp);
436: chmod(deadletter, DEADPERM);
437: } else
438: perror(deadletter);
439: goto out;
440: }
441: if (pid == 0) {
442: sigchild();
443: #ifdef SIGTSTP
444: if (remote == 0) {
445: sigset(SIGTSTP, SIG_IGN);
446: sigset(SIGTTIN, SIG_IGN);
447: sigset(SIGTTOU, SIG_IGN);
448: }
449: #endif
450: sigignore(SIGHUP);
451: sigignore(SIGINT);
452: sigignore(SIGQUIT);
453: s = fileno(mtf);
454: for (i = 3; i < 32; i++)
455: if (i != s)
456: close(i);
457: close(0);
458: dup(s);
459: close(s);
460: #ifdef CC
461: submit(getpid());
462: #endif /* CC */
463: if ((deliver = value("sendmail")) == NOSTR)
464: deliver = MAIL;
465: execvp(expand(deliver), namelist);
466: perror(deliver);
467: exit(1);
468: }
469:
470: if (value("sendwait")!=NOSTR)
471: remote++;
472: out:
473: if (remote) {
474: while ((p = wait(&s)) != pid && p != (pid_t)-1)
475: ;
476: if (s != 0)
477: senderr++;
478: pid = 0;
479: }
480: fclose(mtf);
481: return;
482: }
483:
484: /*
485: * Prepend a header in front of the collected stuff
486: * and return the new file.
487: */
488:
489: static FILE *
490: infix(hp, fi)
491: struct header *hp;
492: FILE *fi;
493: {
494: register FILE *nfo, *nfi;
495: register int c;
496: char *from, *postmark;
497:
498: rewind(fi);
499: if ((nfo = fopen(tempMail, "w")) == NULL) {
500: perror(tempMail);
501: return(fi);
502: }
503: if ((nfi = fopen(tempMail, "r")) == NULL) {
504: perror(tempMail);
505: fclose(nfo);
506: return(fi);
507: }
508: removefile(tempMail);
509: postmark = value("postmark");
510: from = value("from");
511: if ((from != 0) || (postmark != 0)) {
512: fprintf(nfo, "From: ");
513: if (from)
514: fprintf(nfo, "%s@%s%s", myname, host, maildomain());
515: else
516: fprintf(nfo, "%s!%s", host, myname);
517: if (postmark && *postmark)
518: fprintf(nfo, " (%s)", postmark);
519: putc('\n', nfo);
520: }
521: puthead(hp, nfo, GMASK & ~GBCC);
522: textpos = ftell(nfo);
523: while ((c = getc(fi)) != EOF)
524: putc(c, nfo);
525: if (ferror(fi)) {
526: perror("read");
527: return(fi);
528: }
529: fflush(nfo);
530: if (ferror(nfo)) {
531: perror(tempMail);
532: fclose(nfo);
533: fclose(nfi);
534: return(fi);
535: }
536: fclose(nfo);
537: fclose(fi);
538: rewind(nfi);
539: return(nfi);
540: }
541:
542: /*
543: * Dump the message header on the
544: * passed file buffer.
545: */
546:
547: puthead(hp, fo, w)
548: struct header *hp;
549: FILE *fo;
550: {
551: register int gotcha;
552:
553: gotcha = 0;
554: if (hp->h_to != NOSTR && (w & GTO))
555: fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++;
556: if (hp->h_cc != NOSTR && (w & GCC))
557: fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++;
558: if (hp->h_bcc != NOSTR && (w & GBCC))
559: fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++;
560: if (hp->h_defopt != NOSTR && (w & GDEFOPT))
561: fprintf(fo, "Default-Options: %s\n", hp->h_defopt), gotcha++;
562: if (w & GSUBJECT)
563: if (hp->h_subject != NOSTR && *hp->h_subject)
564: fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
565: else
566: if (sflag && *sflag)
567: fprintf(fo, "Subject: %s\n", sflag), gotcha++;
568: if (hp->h_others != NOSTRPTR && (w & GOTHER)) {
569: char **p;
570: for (p = hp->h_others; *p; p++)
571: fprintf(fo, "%s\n", *p);
572: gotcha++;
573: }
574: if (gotcha && (w & GNL))
575: putc('\n', fo);
576: return(0);
577: }
578:
579: /*
580: * Format the given text to not exceed 78 characters.
581: */
582: static void
583: fmt(str, fo)
584: register char *str;
585: register FILE *fo;
586: {
587: register int col = 4;
588: char name[256];
589: int len;
590:
591: str = strcpy(salloc(strlen(str)+1), str);
592: while (str = yankword(str, name, 1)) {
593: len = strlen(name);
594: if (col > 4) {
595: if (col + len > 76) {
596: fputs(",\n ", fo);
597: col = 4;
598: } else {
599: fputs(", ", fo);
600: col += 2;
601: }
602: }
603: fputs(name, fo);
604: col += len;
605: }
606: putc('\n', fo);
607: }
608:
609: /*
610: * Save the outgoing mail on the passed file.
611: */
612: static int
613: savemail(name, hp, fi)
614: char name[];
615: struct header *hp;
616: FILE *fi;
617: {
618: register FILE *fo;
619: char line[BUFSIZ];
620: long now;
621: char *n;
622:
623: if (debug)
624: fprintf(stderr, "save in '%s'\n", name);
625: if ((fo = fopen(name, "a")) == NULL) {
626: perror(name);
627: return(-1);
628: }
629: time(&now);
630: n = rflag;
631: if (n == NOSTR)
632: n = myname;
633: fprintf(fo, "From %s %s", n, ctime(&now));
634: puthead(hp, fo, GMASK);
635: fseek(fi, textpos, 0);
636: while (fgets(line, sizeof line, fi)) {
637: if (!strncmp(line, "From ", 5))
638: putc('>', fo);
639: fputs(line, fo);
640: }
641: putc('\n', fo);
642: fflush(fo);
643: if (ferror(fo))
644: perror(name);
645: fclose(fo);
646: return(0);
647: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.