xref: /original-bsd/usr.bin/mail/send.c (revision ba72ef4c)
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 
14 static char *SccsId = "@(#)send.c	1.1 10/08/80";
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 
22 send(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 
51 mail(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 
85 sendmail(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 
110 mail1(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) {
166 topdog:
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 
261 out:
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 
280 fixhead(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 
305 FILE *
306 infix(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 
354 puthead(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 
378 fmt(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 
404 savemail(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 }
433