changed file stacking to save and restore cond flag;
[unix-history] / usr / src / usr.bin / mail / send.c
CommitLineData
3184019b
KS
1#
2
3#include "rcv.h"
4#ifdef VMUNIX
5#include <wait.h>
6#endif
7
8/*
9 * Mail -- a mail program
10 *
11 * Mail to others.
12 */
13
57079810 14static char *SccsId = "@(#)send.c 1.2 %G%";
3184019b
KS
15
16/*
17 * Send message described by the passed pointer to the
18 * passed output buffer. Return -1 on error, but normally
57079810
KS
19 * the number of lines written. Adjust the status: field
20 * if need be.
3184019b
KS
21 */
22
23send(mailp, obuf)
24 struct message *mailp;
25 FILE *obuf;
26{
27 register struct message *mp;
28 register int t;
29 unsigned int c;
30 FILE *ibuf;
57079810
KS
31 char line[LINESIZE];
32 int lc, ishead;
3184019b
KS
33
34 mp = mailp;
35 ibuf = setinput(mp);
36 c = msize(mp);
57079810 37 ishead = (mailp->m_flag & MSTATUS) != 0;
3184019b 38 lc = 0;
57079810
KS
39 while (c > 0) {
40 fgets(line, LINESIZE, ibuf);
41 c -= strlen(line);
42 lc++;
43 if (ishead) {
44 if (line[0] == '\n') {
45 statusput(mailp, obuf);
46 ishead = 0;
47 goto writeit;
48 }
49 if (index(line, ':') == 0)
50 goto writeit;
51 if (icisname(line, "status", 6)) {
52 statusput(mailp, obuf);
53 ishead = 0;
54 continue;
55 }
56 }
57writeit:
58 fputs(line, obuf);
3184019b
KS
59 if (ferror(obuf))
60 return(-1);
61 }
57079810
KS
62 if (ferror(obuf))
63 return(-1);
64 if (ishead && (mailp->m_flag & MSTATUS))
65 printf("failed to fix up status field\n");
3184019b
KS
66 return(lc);
67}
68
57079810
KS
69/*
70 * Output a reasonable looking status field.
71 */
72
73statusput(mp, obuf)
74 register struct message *mp;
75 register FILE *obuf;
76{
77 char statout[3];
78
79 if ((mp->m_flag & (MNEW|MREAD)) == MNEW)
80 return;
81 if (mp->m_flag & MREAD)
82 strcpy(statout, "R");
83 else
84 strcpy(statout, "");
85 if ((mp->m_flag & MNEW) == 0)
86 strcat(statout, "O");
87 fprintf(obuf, "Status: %s\n", statout);
88}
89
90
3184019b
KS
91/*
92 * Interface between the argument list and the mail1 routine
93 * which does all the dirty work.
94 */
95
96mail(people)
97 char **people;
98{
99 register char *cp2;
100 register int s;
101 char *buf, **ap;
102 struct header head;
103
104 for (s = 0, ap = people; *ap != (char *) -1; ap++)
105 s += strlen(*ap) + 1;
106 buf = salloc(s+1);
107 cp2 = buf;
108 for (ap = people; *ap != (char *) -1; ap++) {
109 cp2 = copy(*ap, cp2);
110 *cp2++ = ' ';
111 }
112 if (cp2 != buf)
113 cp2--;
114 *cp2 = '\0';
115 head.h_to = buf;
116 head.h_subject = NOSTR;
117 head.h_cc = NOSTR;
118 head.h_bcc = NOSTR;
119 head.h_seq = 0;
120 mail1(&head);
121 return(0);
122}
123
124
125/*
126 * Send mail to a bunch of user names. The interface is through
127 * the mail routine below.
128 */
129
130sendmail(str)
131 char *str;
132{
133 register char **ap;
134 char *bufp;
135 register int t;
136 struct header head;
137
138 if (blankline(str))
139 head.h_to = NOSTR;
140 else
141 head.h_to = str;
142 head.h_subject = NOSTR;
143 head.h_cc = NOSTR;
144 head.h_bcc = NOSTR;
145 head.h_seq = 0;
146 mail1(&head);
147 return(0);
148}
149
150/*
151 * Mail a message on standard input to the people indicated
152 * in the passed header. (Internal interface).
153 */
154
155mail1(hp)
156 struct header *hp;
157{
158 register char *cp;
159 int pid, i, s, p, gotcha;
160 char **namelist;
161 struct name *to, *np;
162 FILE *mtf, *postage;
163 int remote = rflag != NOSTR || rmail;
164 char **t;
165
166 /*
167 * Collect user's mail from standard input.
168 * Get the result as mtf.
169 */
170
171 pid = -1;
172 if ((mtf = collect(hp)) == NULL)
173 return(-1);
174 hp->h_seq = 1;
175 if (hp->h_subject == NOSTR)
176 hp->h_subject = sflag;
177 if (fsize(mtf) == 0 && hp->h_subject == NOSTR) {
178 printf("No message !?!\n");
179 goto out;
180 }
181 if (intty && value("askcc") != NOSTR)
182 grabh(hp, GCC);
183 else if (intty) {
184 printf("EOT\n");
185 flush();
186 }
187
188 /*
189 * Now, take the user names from the combined
190 * to and cc lists and do all the alias
191 * processing.
192 */
193
194 senderr = 0;
195 to = usermap(cat(extract(hp->h_bcc, GBCC),
196 cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC))));
197 if (to == NIL) {
198 printf("No recipients specified\n");
199 goto topdog;
200 }
201
202 /*
203 * Look through the recipient list for names with /'s
204 * in them which we write to as files directly.
205 */
206
207 to = outof(to, mtf, hp);
208 rewind(mtf);
209 to = verify(to);
210 if (senderr && !remote) {
211topdog:
212
213 if (fsize(mtf) != 0) {
214 remove(deadletter);
215 exwrite(deadletter, mtf, 1);
216 rewind(mtf);
217 }
218 }
219 for (gotcha = 0, np = to; np != NIL; np = np->n_flink)
220 if ((np->n_type & GDEL) == 0) {
221 gotcha++;
222 break;
223 }
224 if (!gotcha)
225 goto out;
226 to = elide(to);
227 mechk(to);
228 if (count(to) > 1)
229 hp->h_seq++;
230 if (hp->h_seq > 0 && !remote) {
231 fixhead(hp, to);
232 if (fsize(mtf) == 0)
233 printf("Null message body; hope that's ok\n");
234 if ((mtf = infix(hp, mtf)) == NULL) {
235 fprintf(stderr, ". . . message lost, sorry.\n");
236 return(-1);
237 }
238 }
239 namelist = unpack(to);
240 if (debug) {
241 printf("Recipients of message:\n");
242 for (t = namelist; *t != NOSTR; t++)
243 printf(" \"%s\"", *t);
244 printf("\n");
245 fflush(stdout);
246 return;
247 }
248 if ((cp = value("record")) != NOSTR)
249 savemail(expand(cp), hp, mtf);
250
251 /*
252 * Wait, to absorb a potential zombie, then
253 * fork, set up the temporary mail file as standard
254 * input for "mail" and exec with the user list we generated
255 * far above. Return the process id to caller in case he
256 * wants to await the completion of mail.
257 */
258
259#ifdef VMUNIX
260 while (wait3(&s, WNOHANG, 0) > 0)
261 ;
262#else
263 wait(&s);
264#endif
265 rewind(mtf);
266 pid = fork();
267 if (pid == -1) {
268 perror("fork");
269 remove(deadletter);
270 exwrite(deadletter, mtf, 1);
271 goto out;
272 }
273 if (pid == 0) {
274#ifdef SIGTSTP
275 if (remote == 0) {
276 signal(SIGTSTP, SIG_IGN);
277 signal(SIGTTIN, SIG_IGN);
278 signal(SIGTTOU, SIG_IGN);
279 }
280#endif
281 for (i = SIGHUP; i <= SIGQUIT; i++)
282 signal(i, SIG_IGN);
283 if ((postage = fopen("/crp/kurt/postage", "a")) != NULL) {
284 fprintf(postage, "%s %d %d\n", myname,
285 count(to), fsize(mtf));
286 fclose(postage);
287 }
288 s = fileno(mtf);
289 for (i = 3; i < 15; i++)
290 if (i != s)
291 close(i);
292 close(0);
293 dup(s);
294 close(s);
295#ifdef CC
296 submit(getpid());
297#endif CC
298#ifdef DELIVERMAIL
299 execv(DELIVERMAIL, namelist);
300#endif DELIVERMAIL
301 execv(MAIL, namelist);
302 perror(MAIL);
303 exit(1);
304 }
305
306out:
307 if (remote) {
308 while ((p = wait(&s)) != pid && p != -1)
309 ;
310 if (s != 0)
311 senderr++;
312 pid = 0;
313 }
314 fclose(mtf);
315 return(pid);
316}
317
318/*
319 * Fix the header by glopping all of the expanded names from
320 * the distribution list into the appropriate fields.
321 * If there are any ARPA net recipients in the message,
322 * we must insert commas, alas.
323 */
324
325fixhead(hp, tolist)
326 struct header *hp;
327 struct name *tolist;
328{
329 register struct name *nlist;
330 register int f;
331 register struct name *np;
332
333 for (f = 0, np = tolist; np != NIL; np = np->n_flink)
334 if (any('@', np->n_name)) {
335 f |= GCOMMA;
336 break;
337 }
338
339 if (debug && f & GCOMMA)
340 fprintf(stderr, "Should be inserting commas in recip lists\n");
341 hp->h_to = detract(tolist, GTO|f);
342 hp->h_cc = detract(tolist, GCC|f);
343}
344
345/*
346 * Prepend a header in front of the collected stuff
347 * and return the new file.
348 */
349
350FILE *
351infix(hp, fi)
352 struct header *hp;
353 FILE *fi;
354{
355 extern char tempMail[];
356 register FILE *nfo, *nfi;
357 register int c;
358
359 if ((nfo = fopen(tempMail, "w")) == NULL) {
360 perror(tempMail);
361 return(fi);
362 }
363 if ((nfi = fopen(tempMail, "r")) == NULL) {
364 perror(tempMail);
365 fclose(nfo);
366 return(fi);
367 }
368 remove(tempMail);
369 puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL);
370 rewind(fi);
371 c = getc(fi);
372 while (c != EOF) {
373 putc(c, nfo);
374 c = getc(fi);
375 }
376 if (ferror(fi)) {
377 perror("read");
378 fprintf(stderr, "Please notify Kurt Shoens\n");
379 return(fi);
380 }
381 fflush(nfo);
382 if (ferror(nfo)) {
383 perror(tempMail);
384 fclose(nfo);
385 fclose(nfi);
386 return(fi);
387 }
388 fclose(nfo);
389 fclose(fi);
390 rewind(nfi);
391 return(nfi);
392}
393
394/*
395 * Dump the to, subject, cc header on the
396 * passed file buffer.
397 */
398
399puthead(hp, fo, w)
400 struct header *hp;
401 FILE *fo;
402{
403 register int gotcha;
404
405 gotcha = 0;
406 if (hp->h_to != NOSTR && w & GTO)
407 fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++;
408 if (hp->h_subject != NOSTR && w & GSUBJECT)
409 fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
410 if (hp->h_cc != NOSTR && w & GCC)
411 fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++;
412 if (hp->h_bcc != NOSTR && w & GBCC)
413 fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++;
414 if (gotcha && w & GNL)
415 putc('\n', fo);
416 return(0);
417}
418
419/*
420 * Format the given text to not exceed 72 characters.
421 */
422
423fmt(str, fo)
424 register char *str;
425 register FILE *fo;
426{
427 register int col;
428 register char *cp;
429
430 cp = str;
431 col = 0;
432 while (*cp) {
433 if (*cp == ' ' && col > 65) {
434 fprintf(fo, "\n ");
435 col = 4;
436 cp++;
437 continue;
438 }
439 putc(*cp++, fo);
440 col++;
441 }
442 putc('\n', fo);
443}
444
445/*
446 * Save the outgoing mail on the passed file.
447 */
448
449savemail(name, hp, fi)
450 char name[];
451 struct header *hp;
452 FILE *fi;
453{
454 register FILE *fo;
455 register int c;
456 long now;
457 char *n;
458
459 if ((fo = fopen(name, "a")) == NULL) {
460 perror(name);
461 return(-1);
462 }
463 time(&now);
464 n = rflag;
465 if (n == NOSTR)
466 n = myname;
467 fprintf(fo, "From %s %s", n, ctime(&now));
468 rewind(fi);
469 for (c = getc(fi); c != EOF; c = getc(fi))
470 putc(c, fo);
471 fprintf(fo, "\n");
472 fflush(fo);
473 if (ferror(fo))
474 perror(name);
475 fclose(fo);
476 return(0);
477}