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