Commit | Line | Data |
---|---|---|
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 | ||
1c5ad8c6 | 14 | static char *SccsId = "@(#)send.c 1.3 %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 | ||
23 | send(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 | } | |
57 | writeit: | |
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 | ||
73 | statusput(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 | ||
96 | mail(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 | ||
130 | sendmail(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 | ||
155 | mail1(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) { | |
211 | topdog: | |
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 | ||
306 | out: | |
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 | ||
325 | fixhead(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 | ||
350 | FILE * | |
351 | infix(hp, fi) | |
352 | struct header *hp; | |
353 | FILE *fi; | |
354 | { | |
355 | extern char tempMail[]; | |
356 | register FILE *nfo, *nfi; | |
357 | register int c; | |
358 | ||
1c5ad8c6 | 359 | rewind(fi); |
3184019b KS |
360 | if ((nfo = fopen(tempMail, "w")) == NULL) { |
361 | perror(tempMail); | |
362 | return(fi); | |
363 | } | |
364 | if ((nfi = fopen(tempMail, "r")) == NULL) { | |
365 | perror(tempMail); | |
366 | fclose(nfo); | |
367 | return(fi); | |
368 | } | |
369 | remove(tempMail); | |
370 | puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL); | |
3184019b KS |
371 | c = getc(fi); |
372 | while (c != EOF) { | |
373 | putc(c, nfo); | |
374 | c = getc(fi); | |
375 | } | |
376 | if (ferror(fi)) { | |
377 | perror("read"); | |
3184019b KS |
378 | return(fi); |
379 | } | |
380 | fflush(nfo); | |
381 | if (ferror(nfo)) { | |
382 | perror(tempMail); | |
383 | fclose(nfo); | |
384 | fclose(nfi); | |
385 | return(fi); | |
386 | } | |
387 | fclose(nfo); | |
388 | fclose(fi); | |
389 | rewind(nfi); | |
390 | return(nfi); | |
391 | } | |
392 | ||
393 | /* | |
394 | * Dump the to, subject, cc header on the | |
395 | * passed file buffer. | |
396 | */ | |
397 | ||
398 | puthead(hp, fo, w) | |
399 | struct header *hp; | |
400 | FILE *fo; | |
401 | { | |
402 | register int gotcha; | |
403 | ||
404 | gotcha = 0; | |
405 | if (hp->h_to != NOSTR && w & GTO) | |
406 | fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++; | |
407 | if (hp->h_subject != NOSTR && w & GSUBJECT) | |
408 | fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; | |
409 | if (hp->h_cc != NOSTR && w & GCC) | |
410 | fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++; | |
411 | if (hp->h_bcc != NOSTR && w & GBCC) | |
412 | fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), gotcha++; | |
413 | if (gotcha && w & GNL) | |
414 | putc('\n', fo); | |
415 | return(0); | |
416 | } | |
417 | ||
418 | /* | |
419 | * Format the given text to not exceed 72 characters. | |
420 | */ | |
421 | ||
422 | fmt(str, fo) | |
423 | register char *str; | |
424 | register FILE *fo; | |
425 | { | |
426 | register int col; | |
427 | register char *cp; | |
428 | ||
429 | cp = str; | |
430 | col = 0; | |
431 | while (*cp) { | |
432 | if (*cp == ' ' && col > 65) { | |
433 | fprintf(fo, "\n "); | |
434 | col = 4; | |
435 | cp++; | |
436 | continue; | |
437 | } | |
438 | putc(*cp++, fo); | |
439 | col++; | |
440 | } | |
441 | putc('\n', fo); | |
442 | } | |
443 | ||
444 | /* | |
445 | * Save the outgoing mail on the passed file. | |
446 | */ | |
447 | ||
448 | savemail(name, hp, fi) | |
449 | char name[]; | |
450 | struct header *hp; | |
451 | FILE *fi; | |
452 | { | |
453 | register FILE *fo; | |
454 | register int c; | |
455 | long now; | |
456 | char *n; | |
457 | ||
458 | if ((fo = fopen(name, "a")) == NULL) { | |
459 | perror(name); | |
460 | return(-1); | |
461 | } | |
462 | time(&now); | |
463 | n = rflag; | |
464 | if (n == NOSTR) | |
465 | n = myname; | |
466 | fprintf(fo, "From %s %s", n, ctime(&now)); | |
467 | rewind(fi); | |
468 | for (c = getc(fi); c != EOF; c = getc(fi)) | |
469 | putc(c, fo); | |
470 | fprintf(fo, "\n"); | |
471 | fflush(fo); | |
472 | if (ferror(fo)) | |
473 | perror(name); | |
474 | fclose(fo); | |
475 | return(0); | |
476 | } |