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