1 |
|
|
/* $OpenBSD: send.c,v 1.24 2015/01/20 16:59:07 millert Exp $ */ |
2 |
|
|
/* $NetBSD: send.c,v 1.6 1996/06/08 19:48:39 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1980, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include "rcv.h" |
34 |
|
|
#include "extern.h" |
35 |
|
|
|
36 |
|
|
static volatile sig_atomic_t sendsignal; /* Interrupted by a signal? */ |
37 |
|
|
|
38 |
|
|
/* |
39 |
|
|
* Mail -- a mail program |
40 |
|
|
* |
41 |
|
|
* Mail to others. |
42 |
|
|
*/ |
43 |
|
|
|
44 |
|
|
/* |
45 |
|
|
* Send message described by the passed pointer to the |
46 |
|
|
* passed output buffer. Return -1 on error. |
47 |
|
|
* Adjust the status: field if need be. |
48 |
|
|
* If doign is given, suppress ignored header fields. |
49 |
|
|
* prefix is a string to prepend to each output line. |
50 |
|
|
*/ |
51 |
|
|
int |
52 |
|
|
sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign, |
53 |
|
|
char *prefix) |
54 |
|
|
{ |
55 |
|
|
int count; |
56 |
|
|
FILE *ibuf; |
57 |
|
|
char line[LINESIZE]; |
58 |
|
|
char visline[4 * LINESIZE - 3]; |
59 |
|
|
int ishead, infld, ignoring = 0, dostat, firstline; |
60 |
|
|
char *cp, *cp2; |
61 |
|
|
int c = 0; |
62 |
|
|
int length; |
63 |
|
|
int prefixlen = 0; |
64 |
|
|
int rval; |
65 |
|
|
int dovis; |
66 |
|
|
struct sigaction act, saveint; |
67 |
|
|
sigset_t oset; |
68 |
|
|
|
69 |
|
|
sendsignal = 0; |
70 |
|
|
rval = -1; |
71 |
|
|
dovis = isatty(fileno(obuf)); |
72 |
|
|
sigemptyset(&act.sa_mask); |
73 |
|
|
act.sa_flags = SA_RESTART; |
74 |
|
|
act.sa_handler = sendint; |
75 |
|
|
(void)sigaction(SIGINT, &act, &saveint); |
76 |
|
|
(void)sigprocmask(SIG_UNBLOCK, &intset, &oset); |
77 |
|
|
|
78 |
|
|
/* |
79 |
|
|
* Compute the prefix string, without trailing whitespace |
80 |
|
|
*/ |
81 |
|
|
if (prefix != NULL) { |
82 |
|
|
cp2 = 0; |
83 |
|
|
for (cp = prefix; *cp; cp++) |
84 |
|
|
if (*cp != ' ' && *cp != '\t') |
85 |
|
|
cp2 = cp; |
86 |
|
|
prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1; |
87 |
|
|
} |
88 |
|
|
ibuf = setinput(mp); |
89 |
|
|
count = mp->m_size; |
90 |
|
|
ishead = 1; |
91 |
|
|
dostat = doign == 0 || !isign("status", doign); |
92 |
|
|
infld = 0; |
93 |
|
|
firstline = 1; |
94 |
|
|
/* |
95 |
|
|
* Process headers first |
96 |
|
|
*/ |
97 |
|
|
while (count > 0 && ishead) { |
98 |
|
|
if (fgets(line, sizeof(line), ibuf) == NULL) |
99 |
|
|
break; |
100 |
|
|
count -= length = strlen(line); |
101 |
|
|
if (firstline) { |
102 |
|
|
/* |
103 |
|
|
* First line is the From line, so no headers |
104 |
|
|
* there to worry about |
105 |
|
|
*/ |
106 |
|
|
firstline = 0; |
107 |
|
|
ignoring = doign == ignoreall; |
108 |
|
|
} else if (line[0] == '\n') { |
109 |
|
|
/* |
110 |
|
|
* If line is blank, we've reached end of |
111 |
|
|
* headers, so force out status: field |
112 |
|
|
* and note that we are no longer in header |
113 |
|
|
* fields |
114 |
|
|
*/ |
115 |
|
|
if (dostat) { |
116 |
|
|
if (statusput(mp, obuf, prefix) == -1) |
117 |
|
|
goto out; |
118 |
|
|
dostat = 0; |
119 |
|
|
} |
120 |
|
|
ishead = 0; |
121 |
|
|
ignoring = doign == ignoreall; |
122 |
|
|
} else if (infld && (line[0] == ' ' || line[0] == '\t')) { |
123 |
|
|
/* |
124 |
|
|
* If this line is a continuation (via space or tab) |
125 |
|
|
* of a previous header field, just echo it |
126 |
|
|
* (unless the field should be ignored). |
127 |
|
|
* In other words, nothing to do. |
128 |
|
|
*/ |
129 |
|
|
} else { |
130 |
|
|
/* |
131 |
|
|
* Pick up the header field if we have one. |
132 |
|
|
*/ |
133 |
|
|
for (cp = line; |
134 |
|
|
(c = (unsigned char)*cp++) && c != ':' && !isspace(c); ) |
135 |
|
|
; |
136 |
|
|
cp2 = --cp; |
137 |
|
|
while (isspace((unsigned char)*cp++)) |
138 |
|
|
; |
139 |
|
|
if (cp[-1] != ':') { |
140 |
|
|
/* |
141 |
|
|
* Not a header line, force out status: |
142 |
|
|
* This happens in uucp style mail where |
143 |
|
|
* there are no headers at all. |
144 |
|
|
*/ |
145 |
|
|
if (dostat) { |
146 |
|
|
if (statusput(mp, obuf, prefix) == -1) |
147 |
|
|
goto out; |
148 |
|
|
dostat = 0; |
149 |
|
|
} |
150 |
|
|
if (doign != ignoreall) |
151 |
|
|
/* add blank line */ |
152 |
|
|
(void)putc('\n', obuf); |
153 |
|
|
ishead = 0; |
154 |
|
|
ignoring = 0; |
155 |
|
|
} else { |
156 |
|
|
/* |
157 |
|
|
* If it is an ignored field and |
158 |
|
|
* we care about such things, skip it. |
159 |
|
|
*/ |
160 |
|
|
*cp2 = 0; /* temporarily null terminate */ |
161 |
|
|
if (doign && isign(line, doign)) |
162 |
|
|
ignoring = 1; |
163 |
|
|
else if (strcasecmp(line, "status") == 0) { |
164 |
|
|
/* |
165 |
|
|
* If the field is "status," go compute |
166 |
|
|
* and print the real Status: field |
167 |
|
|
*/ |
168 |
|
|
if (dostat) { |
169 |
|
|
if (statusput(mp, obuf, prefix) == -1) |
170 |
|
|
goto out; |
171 |
|
|
dostat = 0; |
172 |
|
|
} |
173 |
|
|
ignoring = 1; |
174 |
|
|
} else { |
175 |
|
|
ignoring = 0; |
176 |
|
|
*cp2 = c; /* restore */ |
177 |
|
|
} |
178 |
|
|
infld = 1; |
179 |
|
|
} |
180 |
|
|
} |
181 |
|
|
if (!ignoring) { |
182 |
|
|
/* |
183 |
|
|
* Strip trailing whitespace from prefix |
184 |
|
|
* if line is blank. |
185 |
|
|
*/ |
186 |
|
|
if (prefix != NULL) { |
187 |
|
|
if (length > 1) |
188 |
|
|
fputs(prefix, obuf); |
189 |
|
|
else |
190 |
|
|
(void)fwrite(prefix, sizeof(*prefix), |
191 |
|
|
prefixlen, obuf); |
192 |
|
|
} |
193 |
|
|
if (dovis) { |
194 |
|
|
length = strvis(visline, line, VIS_SAFE|VIS_NOSLASH); |
195 |
|
|
(void)fwrite(visline, sizeof(*visline), length, obuf); |
196 |
|
|
} else |
197 |
|
|
(void)fwrite(line, sizeof(*line), length, obuf); |
198 |
|
|
if (ferror(obuf)) |
199 |
|
|
goto out; |
200 |
|
|
} |
201 |
|
|
if (sendsignal == SIGINT) |
202 |
|
|
goto out; |
203 |
|
|
} |
204 |
|
|
/* |
205 |
|
|
* Copy out message body |
206 |
|
|
*/ |
207 |
|
|
if (doign == ignoreall) |
208 |
|
|
count--; /* skip final blank line */ |
209 |
|
|
while (count > 0) { |
210 |
|
|
if (fgets(line, sizeof(line), ibuf) == NULL) { |
211 |
|
|
c = 0; |
212 |
|
|
break; |
213 |
|
|
} |
214 |
|
|
count -= c = strlen(line); |
215 |
|
|
if (prefix != NULL) { |
216 |
|
|
/* |
217 |
|
|
* Strip trailing whitespace from prefix |
218 |
|
|
* if line is blank. |
219 |
|
|
*/ |
220 |
|
|
if (c > 1) |
221 |
|
|
fputs(prefix, obuf); |
222 |
|
|
else |
223 |
|
|
(void)fwrite(prefix, sizeof(*prefix), |
224 |
|
|
prefixlen, obuf); |
225 |
|
|
} |
226 |
|
|
/* |
227 |
|
|
* We can't read the record file (or inbox for recipient) |
228 |
|
|
* properly with 'From ' lines in the message body (from |
229 |
|
|
* forwarded messages or sentences starting with "From "), |
230 |
|
|
* so we will prepend those lines with a '>'. |
231 |
|
|
*/ |
232 |
|
|
if (strncmp(line, "From ", 5) == 0) |
233 |
|
|
(void)fwrite(">", 1, 1, obuf); /* '>' before 'From ' */ |
234 |
|
|
if (dovis) { |
235 |
|
|
length = strvis(visline, line, VIS_SAFE|VIS_NOSLASH); |
236 |
|
|
(void)fwrite(visline, sizeof(*visline), length, obuf); |
237 |
|
|
} else |
238 |
|
|
(void)fwrite(line, sizeof(*line), c, obuf); |
239 |
|
|
if (ferror(obuf) || sendsignal == SIGINT) |
240 |
|
|
goto out; |
241 |
|
|
} |
242 |
|
|
if (doign == ignoreall && c > 0 && line[c - 1] != '\n') |
243 |
|
|
/* no final blank line */ |
244 |
|
|
if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) |
245 |
|
|
goto out; |
246 |
|
|
rval = 0; |
247 |
|
|
out: |
248 |
|
|
sendsignal = 0; |
249 |
|
|
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
250 |
|
|
(void)sigaction(SIGINT, &saveint, NULL); |
251 |
|
|
return(rval); |
252 |
|
|
} |
253 |
|
|
|
254 |
|
|
/* |
255 |
|
|
* Output a reasonable looking status field. |
256 |
|
|
*/ |
257 |
|
|
int |
258 |
|
|
statusput(struct message *mp, FILE *obuf, char *prefix) |
259 |
|
|
{ |
260 |
|
|
char statout[3]; |
261 |
|
|
char *cp = statout; |
262 |
|
|
|
263 |
|
|
if (mp->m_flag & MREAD) |
264 |
|
|
*cp++ = 'R'; |
265 |
|
|
if ((mp->m_flag & MNEW) == 0) |
266 |
|
|
*cp++ = 'O'; |
267 |
|
|
*cp = 0; |
268 |
|
|
if (statout[0]) { |
269 |
|
|
fprintf(obuf, "%sStatus: %s\n", |
270 |
|
|
prefix == NULL ? "" : prefix, statout); |
271 |
|
|
return(ferror(obuf) ? -1 : 0); |
272 |
|
|
} |
273 |
|
|
return(0); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
/* |
277 |
|
|
* Interface between the argument list and the mail1 routine |
278 |
|
|
* which does all the dirty work. |
279 |
|
|
*/ |
280 |
|
|
int |
281 |
|
|
mail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts, |
282 |
|
|
char *fromaddr, char *subject) |
283 |
|
|
{ |
284 |
|
4 |
struct header head; |
285 |
|
|
|
286 |
|
2 |
head.h_to = to; |
287 |
|
2 |
head.h_from = fromaddr; |
288 |
|
2 |
head.h_subject = subject; |
289 |
|
2 |
head.h_cc = cc; |
290 |
|
2 |
head.h_bcc = bcc; |
291 |
|
2 |
head.h_smopts = smopts; |
292 |
|
2 |
mail1(&head, 0); |
293 |
|
2 |
return(0); |
294 |
|
2 |
} |
295 |
|
|
|
296 |
|
|
/* |
297 |
|
|
* Send mail to a bunch of user names. The interface is through |
298 |
|
|
* the mail routine below. |
299 |
|
|
*/ |
300 |
|
|
int |
301 |
|
|
sendmail(void *v) |
302 |
|
|
{ |
303 |
|
|
char *str = v; |
304 |
|
|
struct header head; |
305 |
|
|
|
306 |
|
|
head.h_to = extract(str, GTO); |
307 |
|
|
head.h_from = NULL; |
308 |
|
|
head.h_subject = NULL; |
309 |
|
|
head.h_cc = NULL; |
310 |
|
|
head.h_bcc = NULL; |
311 |
|
|
head.h_smopts = NULL; |
312 |
|
|
mail1(&head, 0); |
313 |
|
|
return(0); |
314 |
|
|
} |
315 |
|
|
|
316 |
|
|
/* |
317 |
|
|
* Mail a message on standard input to the people indicated |
318 |
|
|
* in the passed header. (Internal interface). |
319 |
|
|
*/ |
320 |
|
|
void |
321 |
|
|
mail1(struct header *hp, int printheaders) |
322 |
|
|
{ |
323 |
|
|
char *cp, *envfrom = NULL; |
324 |
|
4 |
char *argv[8]; |
325 |
|
2 |
char **ap = argv; |
326 |
|
|
pid_t pid; |
327 |
|
|
struct name *to; |
328 |
|
|
FILE *mtf; |
329 |
|
|
|
330 |
|
|
/* |
331 |
|
|
* Collect user's mail from standard input. |
332 |
|
|
* Get the result as mtf. |
333 |
|
|
*/ |
334 |
✗✓ |
2 |
if ((mtf = collect(hp, printheaders)) == NULL) |
335 |
|
|
return; |
336 |
✗✓ |
2 |
if (fsize(mtf) == 0) { |
337 |
|
|
if (value("skipempty") != NULL) |
338 |
|
|
goto out; |
339 |
|
|
if (hp->h_subject == NULL || *hp->h_subject == '\0') |
340 |
|
|
puts("No message, no subject; hope that's ok"); |
341 |
|
|
else |
342 |
|
|
puts("Null message body; hope that's ok"); |
343 |
|
|
} |
344 |
|
|
/* |
345 |
|
|
* Now, take the user names from the combined |
346 |
|
|
* to and cc lists and do all the alias |
347 |
|
|
* processing. |
348 |
|
|
*/ |
349 |
|
2 |
senderr = 0; |
350 |
|
2 |
to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); |
351 |
✗✓ |
2 |
if (to == NULL) { |
352 |
|
|
puts("No recipients specified"); |
353 |
|
|
senderr++; |
354 |
|
|
} |
355 |
|
|
/* |
356 |
|
|
* Look through the recipient list for names with /'s |
357 |
|
|
* in them which we write to as files directly. |
358 |
|
|
*/ |
359 |
|
2 |
to = outof(to, mtf, hp); |
360 |
✗✓ |
2 |
if (senderr) |
361 |
|
|
savedeadletter(mtf); |
362 |
|
2 |
to = elide(to); |
363 |
✓✗ |
2 |
if (count(to) == 0) |
364 |
|
|
goto out; |
365 |
|
2 |
fixhead(hp, to); |
366 |
✗✓ |
2 |
if ((mtf = infix(hp, mtf)) == NULL) { |
367 |
|
|
fputs(". . . message lost, sorry.\n", stderr); |
368 |
|
|
return; |
369 |
|
|
} |
370 |
✗✓ |
2 |
if ((cp = value("record")) != NULL) |
371 |
|
|
(void)savemail(expand(cp), mtf); |
372 |
|
|
|
373 |
|
|
/* Setup sendmail arguments. */ |
374 |
|
2 |
*ap++ = "send-mail"; |
375 |
|
2 |
*ap++ = "-i"; |
376 |
|
2 |
*ap++ = "-t"; |
377 |
✗✓ |
6 |
cp = hp->h_from ? hp->h_from : value("from"); |
378 |
✗✓ |
2 |
if (cp != NULL) { |
379 |
|
|
envfrom = skin(cp); |
380 |
|
|
*ap++ = "-f"; |
381 |
|
|
*ap++ = envfrom; |
382 |
|
|
if (envfrom == cp) |
383 |
|
|
envfrom = NULL; |
384 |
|
|
} |
385 |
✗✓ |
2 |
if (value("metoo") != NULL) |
386 |
|
|
*ap++ = "-m"; |
387 |
✗✓ |
2 |
if (value("verbose") != NULL) |
388 |
|
|
*ap++ = "-v"; |
389 |
|
2 |
*ap = NULL; |
390 |
✗✓ |
2 |
if (debug) { |
391 |
|
|
fputs("Sendmail arguments:", stdout); |
392 |
|
|
for (ap = argv; *ap != NULL; ap++) |
393 |
|
|
printf(" \"%s\"", *ap); |
394 |
|
|
putchar('\n'); |
395 |
|
|
goto out; |
396 |
|
|
} |
397 |
|
|
/* |
398 |
|
|
* Fork, set up the temporary mail file as standard |
399 |
|
|
* input for "mail", and exec with the user list we generated |
400 |
|
|
* far above. |
401 |
|
|
*/ |
402 |
|
2 |
pid = fork(); |
403 |
✗✓ |
2 |
if (pid == -1) { |
404 |
|
|
warn("fork"); |
405 |
|
|
savedeadletter(mtf); |
406 |
|
|
goto out; |
407 |
|
|
} |
408 |
✗✓ |
2 |
if (pid == 0) { |
409 |
|
|
sigset_t nset; |
410 |
|
|
|
411 |
|
|
sigemptyset(&nset); |
412 |
|
|
sigaddset(&nset, SIGHUP); |
413 |
|
|
sigaddset(&nset, SIGINT); |
414 |
|
|
sigaddset(&nset, SIGQUIT); |
415 |
|
|
sigaddset(&nset, SIGTSTP); |
416 |
|
|
sigaddset(&nset, SIGTTIN); |
417 |
|
|
sigaddset(&nset, SIGTTOU); |
418 |
|
|
prepare_child(&nset, fileno(mtf), -1); |
419 |
|
|
if ((cp = value("sendmail")) != NULL) |
420 |
|
|
cp = expand(cp); |
421 |
|
|
else |
422 |
|
|
cp = _PATH_SENDMAIL; |
423 |
|
|
execv(cp, argv); |
424 |
|
|
warn("%s", cp); |
425 |
|
|
_exit(1); |
426 |
|
|
} |
427 |
|
2 |
free(envfrom); |
428 |
✗✓ |
2 |
if (value("verbose") != NULL) |
429 |
|
|
(void)wait_child(pid); |
430 |
|
|
else |
431 |
|
2 |
free_child(pid); |
432 |
|
|
out: |
433 |
|
2 |
(void)Fclose(mtf); |
434 |
|
4 |
} |
435 |
|
|
|
436 |
|
|
/* |
437 |
|
|
* Fix the header by glopping all of the expanded names from |
438 |
|
|
* the distribution list into the appropriate fields. |
439 |
|
|
*/ |
440 |
|
|
void |
441 |
|
|
fixhead(struct header *hp, struct name *tolist) |
442 |
|
|
{ |
443 |
|
|
struct name *np; |
444 |
|
|
|
445 |
|
4 |
hp->h_to = NULL; |
446 |
|
2 |
hp->h_cc = NULL; |
447 |
|
2 |
hp->h_bcc = NULL; |
448 |
✓✓ |
8 |
for (np = tolist; np != NULL; np = np->n_flink) |
449 |
✓✗ |
2 |
if ((np->n_type & GMASK) == GTO) |
450 |
|
2 |
hp->h_to = |
451 |
|
2 |
cat(hp->h_to, nalloc(np->n_name, np->n_type)); |
452 |
|
|
else if ((np->n_type & GMASK) == GCC) |
453 |
|
|
hp->h_cc = |
454 |
|
|
cat(hp->h_cc, nalloc(np->n_name, np->n_type)); |
455 |
|
|
else if ((np->n_type & GMASK) == GBCC) |
456 |
|
|
hp->h_bcc = |
457 |
|
|
cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); |
458 |
|
2 |
} |
459 |
|
|
|
460 |
|
|
/* |
461 |
|
|
* Prepend a header in front of the collected stuff |
462 |
|
|
* and return the new file. |
463 |
|
|
*/ |
464 |
|
|
FILE * |
465 |
|
|
infix(struct header *hp, FILE *fi) |
466 |
|
|
{ |
467 |
|
|
FILE *nfo, *nfi; |
468 |
|
|
int c, fd; |
469 |
|
4 |
char tempname[PATHSIZE]; |
470 |
|
|
|
471 |
|
4 |
(void)snprintf(tempname, sizeof(tempname), |
472 |
|
2 |
"%s/mail.RsXXXXXXXXXX", tmpdir); |
473 |
✓✗✗✓
|
4 |
if ((fd = mkstemp(tempname)) == -1 || |
474 |
|
2 |
(nfo = Fdopen(fd, "w")) == NULL) { |
475 |
|
|
warn("%s", tempname); |
476 |
|
|
return(fi); |
477 |
|
|
} |
478 |
✗✓ |
2 |
if ((nfi = Fopen(tempname, "r")) == NULL) { |
479 |
|
|
warn("%s", tempname); |
480 |
|
|
(void)Fclose(nfo); |
481 |
|
|
(void)rm(tempname); |
482 |
|
|
return(fi); |
483 |
|
|
} |
484 |
|
2 |
(void)rm(tempname); |
485 |
|
2 |
(void)puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA); |
486 |
✓✗✓✗
|
8 |
c = getc(fi); |
487 |
✓✓ |
1065784 |
while (c != EOF) { |
488 |
✓✗ |
1065780 |
(void)putc(c, nfo); |
489 |
✓✗✓✓
|
2131560 |
c = getc(fi); |
490 |
|
|
} |
491 |
✓✗✗✓ ✗✗ |
4 |
if (ferror(fi)) { |
492 |
|
|
warn("read"); |
493 |
|
|
rewind(fi); |
494 |
|
|
return(fi); |
495 |
|
|
} |
496 |
|
2 |
(void)fflush(nfo); |
497 |
✓✗✗✓ ✗✗ |
4 |
if (ferror(nfo)) { |
498 |
|
|
warn("%s", tempname); |
499 |
|
|
(void)Fclose(nfo); |
500 |
|
|
(void)Fclose(nfi); |
501 |
|
|
rewind(fi); |
502 |
|
|
return(fi); |
503 |
|
|
} |
504 |
|
2 |
(void)Fclose(nfo); |
505 |
|
2 |
(void)Fclose(fi); |
506 |
|
2 |
rewind(nfi); |
507 |
|
2 |
return(nfi); |
508 |
|
2 |
} |
509 |
|
|
|
510 |
|
|
/* |
511 |
|
|
* Dump the to, subject, cc header on the |
512 |
|
|
* passed file buffer. |
513 |
|
|
*/ |
514 |
|
|
int |
515 |
|
|
puthead(struct header *hp, FILE *fo, int w) |
516 |
|
|
{ |
517 |
|
|
int gotcha; |
518 |
|
|
char *from; |
519 |
|
|
|
520 |
|
|
gotcha = 0; |
521 |
✗✓ |
8 |
from = hp->h_from ? hp->h_from : value("from"); |
522 |
✗✓ |
2 |
if (from != NULL) |
523 |
|
|
fprintf(fo, "From: %s\n", from), gotcha++; |
524 |
✓✗✓✗
|
4 |
if (hp->h_to != NULL && w & GTO) |
525 |
|
2 |
fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; |
526 |
✓✗✓✗
|
4 |
if (hp->h_subject != NULL && w & GSUBJECT) |
527 |
|
2 |
fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; |
528 |
✗✓✗✗
|
2 |
if (hp->h_cc != NULL && w & GCC) |
529 |
|
|
fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; |
530 |
✗✓✗✗
|
2 |
if (hp->h_bcc != NULL && w & GBCC) |
531 |
|
|
fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; |
532 |
✓✗✓✗
|
4 |
if (gotcha && w & GNL) |
533 |
✓✗ |
4 |
(void)putc('\n', fo); |
534 |
|
2 |
return(0); |
535 |
|
|
} |
536 |
|
|
|
537 |
|
|
/* |
538 |
|
|
* Format the given header line to not exceed 72 characters. |
539 |
|
|
*/ |
540 |
|
|
void |
541 |
|
|
fmt(char *str, struct name *np, FILE *fo, int comma) |
542 |
|
|
{ |
543 |
|
|
int col, len; |
544 |
|
|
|
545 |
|
4 |
comma = comma ? 1 : 0; |
546 |
|
2 |
col = strlen(str); |
547 |
✓✗ |
2 |
if (col) |
548 |
|
2 |
fputs(str, fo); |
549 |
✓✓ |
6 |
for (; np != NULL; np = np->n_flink) { |
550 |
✓✗ |
2 |
if (np->n_flink == NULL) |
551 |
|
2 |
comma = 0; |
552 |
|
2 |
len = strlen(np->n_name); |
553 |
|
2 |
col++; /* for the space */ |
554 |
✗✓ |
2 |
if (col + len + comma > 72 && col > 4) { |
555 |
|
|
fputs("\n ", fo); |
556 |
|
|
col = 4; |
557 |
|
|
} else |
558 |
✓✗ |
4 |
putc(' ', fo); |
559 |
|
2 |
fputs(np->n_name, fo); |
560 |
✗✓ |
2 |
if (comma) |
561 |
|
|
putc(',', fo); |
562 |
|
2 |
col += len + comma; |
563 |
|
|
} |
564 |
✓✗ |
4 |
putc('\n', fo); |
565 |
|
2 |
} |
566 |
|
|
|
567 |
|
|
/* |
568 |
|
|
* Save the outgoing mail on the passed file. |
569 |
|
|
*/ |
570 |
|
|
/*ARGSUSED*/ |
571 |
|
|
int |
572 |
|
|
savemail(char *name, FILE *fi) |
573 |
|
|
{ |
574 |
|
|
FILE *fo; |
575 |
|
|
char buf[BUFSIZ]; |
576 |
|
|
time_t now; |
577 |
|
|
mode_t m; |
578 |
|
|
|
579 |
|
|
m = umask(077); |
580 |
|
|
fo = Fopen(name, "a"); |
581 |
|
|
(void)umask(m); |
582 |
|
|
if (fo == NULL) { |
583 |
|
|
warn("%s", name); |
584 |
|
|
return(-1); |
585 |
|
|
} |
586 |
|
|
(void)time(&now); |
587 |
|
|
fprintf(fo, "From %s %s", myname, ctime(&now)); |
588 |
|
|
while (fgets(buf, sizeof(buf), fi) == buf) { |
589 |
|
|
/* |
590 |
|
|
* We can't read the record file (or inbox for recipient) |
591 |
|
|
* in the message body (from forwarded messages or sentences |
592 |
|
|
* starting with "From "), so we will prepend those lines with |
593 |
|
|
* a '>'. |
594 |
|
|
*/ |
595 |
|
|
if (strncmp(buf, "From ", 5) == 0) |
596 |
|
|
(void)fwrite(">", 1, 1, fo); /* '>' before 'From ' */ |
597 |
|
|
(void)fwrite(buf, 1, strlen(buf), fo); |
598 |
|
|
} |
599 |
|
|
(void)putc('\n', fo); |
600 |
|
|
(void)fflush(fo); |
601 |
|
|
if (ferror(fo)) |
602 |
|
|
warn("%s", name); |
603 |
|
|
(void)Fclose(fo); |
604 |
|
|
rewind(fi); |
605 |
|
|
return(0); |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
/*ARGSUSED*/ |
609 |
|
|
void |
610 |
|
|
sendint(int s) |
611 |
|
|
{ |
612 |
|
|
|
613 |
|
|
sendsignal = s; |
614 |
|
|
} |