1 |
|
|
/* $OpenBSD: collect.c,v 1.34 2014/01/17 18:42:30 okan Exp $ */ |
2 |
|
|
/* $NetBSD: collect.c,v 1.9 1997/07/09 05:25:45 mikel 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 |
|
|
/* |
34 |
|
|
* Mail -- a mail program |
35 |
|
|
* |
36 |
|
|
* Collect input from standard input, handling |
37 |
|
|
* ~ escapes. |
38 |
|
|
*/ |
39 |
|
|
|
40 |
|
|
#include "rcv.h" |
41 |
|
|
#include "extern.h" |
42 |
|
|
|
43 |
|
|
/* |
44 |
|
|
* Read a message from standard output and return a read file to it |
45 |
|
|
* or NULL on error. |
46 |
|
|
*/ |
47 |
|
|
|
48 |
|
|
/* |
49 |
|
|
* The following hokiness with global variables is so that on |
50 |
|
|
* receipt of an interrupt signal, the partial message can be salted |
51 |
|
|
* away on dead.letter. |
52 |
|
|
*/ |
53 |
|
|
static FILE *collf; /* File for saving away */ |
54 |
|
|
static int hadintr; /* Have seen one SIGINT so far */ |
55 |
|
|
|
56 |
|
|
FILE * |
57 |
|
|
collect(struct header *hp, int printheaders) |
58 |
|
|
{ |
59 |
|
|
FILE *fbuf; |
60 |
|
4 |
int lc, cc, fd, c, t, lastlong, rc, sig; |
61 |
|
|
int escape, eofcount, longline; |
62 |
|
|
char getsub; |
63 |
|
2 |
char linebuf[LINESIZE], tempname[PATHSIZE], *cp; |
64 |
|
|
|
65 |
|
2 |
collf = NULL; |
66 |
|
|
eofcount = 0; |
67 |
|
2 |
hadintr = 0; |
68 |
|
|
lastlong = 0; |
69 |
|
|
longline = 0; |
70 |
✗✓ |
2 |
if ((cp = value("escape")) != NULL) |
71 |
|
|
escape = *cp; |
72 |
|
|
else |
73 |
|
|
escape = ESCAPE; |
74 |
|
2 |
noreset++; |
75 |
|
|
|
76 |
|
4 |
(void)snprintf(tempname, sizeof(tempname), |
77 |
|
2 |
"%s/mail.RsXXXXXXXXXX", tmpdir); |
78 |
✓✗✗✓
|
4 |
if ((fd = mkstemp(tempname)) == -1 || |
79 |
|
2 |
(collf = Fdopen(fd, "w+")) == NULL) { |
80 |
|
|
warn("%s", tempname); |
81 |
|
|
goto err; |
82 |
|
|
} |
83 |
|
2 |
(void)rm(tempname); |
84 |
|
|
|
85 |
|
|
/* |
86 |
|
|
* If we are going to prompt for a subject, |
87 |
|
|
* refrain from printing a newline after |
88 |
|
|
* the headers (since some people mind). |
89 |
|
|
*/ |
90 |
|
|
t = GTO|GSUBJECT|GCC|GNL; |
91 |
|
|
getsub = 0; |
92 |
✗✓✗✗ ✗✗ |
2 |
if (hp->h_subject == NULL && value("interactive") != NULL && |
93 |
|
|
(value("ask") != NULL || value("asksub") != NULL)) |
94 |
|
|
t &= ~GNL, getsub++; |
95 |
✗✓ |
2 |
if (printheaders) { |
96 |
|
|
puthead(hp, stdout, t); |
97 |
|
|
fflush(stdout); |
98 |
|
|
} |
99 |
✗✓✗✗
|
2 |
if (getsub && gethfromtty(hp, GSUBJECT) == -1) |
100 |
|
|
goto err; |
101 |
|
|
|
102 |
|
|
if (0) { |
103 |
|
|
cont: |
104 |
|
|
/* Come here for printing the after-suspend message. */ |
105 |
|
|
if (isatty(0)) { |
106 |
|
|
puts("(continue)"); |
107 |
|
|
fflush(stdout); |
108 |
|
|
} |
109 |
|
|
} |
110 |
|
2 |
for (;;) { |
111 |
|
13049 |
c = readline(stdin, linebuf, LINESIZE, &sig); |
112 |
|
|
|
113 |
|
|
/* Act on any signal caught during readline() ignoring 'c' */ |
114 |
✗✗✗✓
|
13049 |
switch (sig) { |
115 |
|
|
case 0: |
116 |
|
|
break; |
117 |
|
|
case SIGINT: |
118 |
|
|
if (collabort()) |
119 |
|
|
goto err; |
120 |
|
|
continue; |
121 |
|
|
case SIGHUP: |
122 |
|
|
rewind(collf); |
123 |
|
|
savedeadletter(collf); |
124 |
|
|
/* |
125 |
|
|
* Let's pretend nobody else wants to clean up, |
126 |
|
|
* a true statement at this time. |
127 |
|
|
*/ |
128 |
|
|
exit(1); |
129 |
|
|
default: |
130 |
|
|
/* Stopped due to job control */ |
131 |
|
|
(void)kill(0, sig); |
132 |
|
|
goto cont; |
133 |
|
|
} |
134 |
|
|
|
135 |
|
|
/* No signal, check for error */ |
136 |
✓✓ |
13049 |
if (c < 0) { |
137 |
✗✓✗✗
|
2 |
if (value("interactive") != NULL && |
138 |
|
|
value("ignoreeof") != NULL && ++eofcount < 25) { |
139 |
|
|
puts("Use \".\" to terminate letter"); |
140 |
|
|
continue; |
141 |
|
|
} |
142 |
|
|
break; |
143 |
|
|
} |
144 |
|
|
lastlong = longline; |
145 |
|
13047 |
longline = (c == LINESIZE - 1); |
146 |
|
|
eofcount = 0; |
147 |
|
13047 |
hadintr = 0; |
148 |
✗✓✗✗ ✗✗ |
13047 |
if (linebuf[0] == '.' && linebuf[1] == '\0' && |
149 |
|
|
value("interactive") != NULL && !lastlong && |
150 |
|
|
(value("dot") != NULL || value("ignoreeof") != NULL)) |
151 |
|
|
break; |
152 |
✗✓✗✗
|
13047 |
if (linebuf[0] != escape || value("interactive") == NULL || |
153 |
|
|
lastlong) { |
154 |
✓✗ |
13047 |
if (putline(collf, linebuf, !longline) < 0) |
155 |
|
|
goto err; |
156 |
|
|
continue; |
157 |
|
|
} |
158 |
|
|
c = (unsigned char)linebuf[1]; |
159 |
|
|
switch (c) { |
160 |
|
|
default: |
161 |
|
|
/* |
162 |
|
|
* On double escape, just send the single one. |
163 |
|
|
* Otherwise, it's an error. |
164 |
|
|
*/ |
165 |
|
|
if (c == escape) { |
166 |
|
|
if (putline(collf, &linebuf[1], !longline) < 0) |
167 |
|
|
goto err; |
168 |
|
|
else |
169 |
|
|
break; |
170 |
|
|
} |
171 |
|
|
puts("Unknown tilde escape."); |
172 |
|
|
break; |
173 |
|
|
case '!': |
174 |
|
|
/* |
175 |
|
|
* Shell escape, send the balance of the |
176 |
|
|
* line to sh -c. |
177 |
|
|
*/ |
178 |
|
|
shell(&linebuf[2]); |
179 |
|
|
break; |
180 |
|
|
case ':': |
181 |
|
|
case '_': |
182 |
|
|
/* |
183 |
|
|
* Escape to command mode, but be nice! |
184 |
|
|
*/ |
185 |
|
|
execute(&linebuf[2], 1); |
186 |
|
|
goto cont; |
187 |
|
|
case '.': |
188 |
|
|
/* |
189 |
|
|
* Simulate end of file on input. |
190 |
|
|
*/ |
191 |
|
|
goto out; |
192 |
|
|
case 'q': |
193 |
|
|
/* |
194 |
|
|
* Force a quit of sending mail. |
195 |
|
|
* Act like an interrupt happened. |
196 |
|
|
*/ |
197 |
|
|
hadintr++; |
198 |
|
|
collabort(); |
199 |
|
|
fputs("Interrupt\n", stderr); |
200 |
|
|
goto err; |
201 |
|
|
case 'x': |
202 |
|
|
/* |
203 |
|
|
* Force a quit of sending mail. |
204 |
|
|
* Do not save the message. |
205 |
|
|
*/ |
206 |
|
|
goto err; |
207 |
|
|
case 'h': |
208 |
|
|
/* |
209 |
|
|
* Grab a bunch of headers. |
210 |
|
|
*/ |
211 |
|
|
grabh(hp, GTO|GSUBJECT|GCC|GBCC); |
212 |
|
|
goto cont; |
213 |
|
|
case 't': |
214 |
|
|
/* |
215 |
|
|
* Add to the To list. |
216 |
|
|
*/ |
217 |
|
|
hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); |
218 |
|
|
break; |
219 |
|
|
case 's': |
220 |
|
|
/* |
221 |
|
|
* Set the Subject list. |
222 |
|
|
*/ |
223 |
|
|
cp = &linebuf[2]; |
224 |
|
|
while (isspace((unsigned char)*cp)) |
225 |
|
|
cp++; |
226 |
|
|
hp->h_subject = savestr(cp); |
227 |
|
|
break; |
228 |
|
|
case 'c': |
229 |
|
|
/* |
230 |
|
|
* Add to the CC list. |
231 |
|
|
*/ |
232 |
|
|
hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); |
233 |
|
|
break; |
234 |
|
|
case 'b': |
235 |
|
|
/* |
236 |
|
|
* Add stuff to blind carbon copies list. |
237 |
|
|
*/ |
238 |
|
|
hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); |
239 |
|
|
break; |
240 |
|
|
case 'd': |
241 |
|
|
linebuf[2] = '\0'; |
242 |
|
|
strlcat(linebuf, getdeadletter(), sizeof(linebuf)); |
243 |
|
|
/* fall into . . . */ |
244 |
|
|
case 'r': |
245 |
|
|
case '<': |
246 |
|
|
/* |
247 |
|
|
* Invoke a file: |
248 |
|
|
* Search for the file name, |
249 |
|
|
* then open it and copy the contents to collf. |
250 |
|
|
*/ |
251 |
|
|
cp = &linebuf[2]; |
252 |
|
|
while (isspace((unsigned char)*cp)) |
253 |
|
|
cp++; |
254 |
|
|
if (*cp == '\0') { |
255 |
|
|
puts("Interpolate what file?"); |
256 |
|
|
break; |
257 |
|
|
} |
258 |
|
|
cp = expand(cp); |
259 |
|
|
if (cp == NULL) |
260 |
|
|
break; |
261 |
|
|
if (isdir(cp)) { |
262 |
|
|
printf("%s: Directory\n", cp); |
263 |
|
|
break; |
264 |
|
|
} |
265 |
|
|
if ((fbuf = Fopen(cp, "r")) == NULL) { |
266 |
|
|
warn("%s", cp); |
267 |
|
|
break; |
268 |
|
|
} |
269 |
|
|
printf("\"%s\" ", cp); |
270 |
|
|
fflush(stdout); |
271 |
|
|
lc = 0; |
272 |
|
|
cc = 0; |
273 |
|
|
while ((rc = readline(fbuf, linebuf, LINESIZE, NULL)) >= 0) { |
274 |
|
|
if (rc != LINESIZE - 1) |
275 |
|
|
lc++; |
276 |
|
|
if ((t = putline(collf, linebuf, |
277 |
|
|
rc != LINESIZE-1)) < 0) { |
278 |
|
|
(void)Fclose(fbuf); |
279 |
|
|
goto err; |
280 |
|
|
} |
281 |
|
|
cc += t; |
282 |
|
|
} |
283 |
|
|
(void)Fclose(fbuf); |
284 |
|
|
printf("%d/%d\n", lc, cc); |
285 |
|
|
break; |
286 |
|
|
case 'w': |
287 |
|
|
/* |
288 |
|
|
* Write the message on a file. |
289 |
|
|
*/ |
290 |
|
|
cp = &linebuf[2]; |
291 |
|
|
while (*cp == ' ' || *cp == '\t') |
292 |
|
|
cp++; |
293 |
|
|
if (*cp == '\0') { |
294 |
|
|
fputs("Write what file!?\n", stderr); |
295 |
|
|
break; |
296 |
|
|
} |
297 |
|
|
if ((cp = expand(cp)) == NULL) |
298 |
|
|
break; |
299 |
|
|
rewind(collf); |
300 |
|
|
exwrite(cp, collf, 1); |
301 |
|
|
break; |
302 |
|
|
case 'm': |
303 |
|
|
case 'M': |
304 |
|
|
case 'f': |
305 |
|
|
case 'F': |
306 |
|
|
/* |
307 |
|
|
* Interpolate the named messages, if we |
308 |
|
|
* are in receiving mail mode. Does the |
309 |
|
|
* standard list processing garbage. |
310 |
|
|
* If ~f is given, we don't shift over. |
311 |
|
|
*/ |
312 |
|
|
if (forward(linebuf + 2, collf, tempname, c) < 0) |
313 |
|
|
goto err; |
314 |
|
|
goto cont; |
315 |
|
|
case '?': |
316 |
|
|
if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { |
317 |
|
|
warn(_PATH_TILDE); |
318 |
|
|
break; |
319 |
|
|
} |
320 |
|
|
while ((t = getc(fbuf)) != EOF) |
321 |
|
|
(void)putchar(t); |
322 |
|
|
(void)Fclose(fbuf); |
323 |
|
|
break; |
324 |
|
|
case 'p': |
325 |
|
|
/* |
326 |
|
|
* Print out the current state of the |
327 |
|
|
* message without altering anything. |
328 |
|
|
*/ |
329 |
|
|
rewind(collf); |
330 |
|
|
puts("-------\nMessage contains:"); |
331 |
|
|
puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); |
332 |
|
|
while ((t = getc(collf)) != EOF) |
333 |
|
|
(void)putchar(t); |
334 |
|
|
goto cont; |
335 |
|
|
case '|': |
336 |
|
|
/* |
337 |
|
|
* Pipe message through command. |
338 |
|
|
* Collect output as new message. |
339 |
|
|
*/ |
340 |
|
|
rewind(collf); |
341 |
|
|
mespipe(collf, &linebuf[2]); |
342 |
|
|
goto cont; |
343 |
|
|
case 'v': |
344 |
|
|
case 'e': |
345 |
|
|
/* |
346 |
|
|
* Edit the current message. |
347 |
|
|
* 'e' means to use EDITOR |
348 |
|
|
* 'v' means to use VISUAL |
349 |
|
|
*/ |
350 |
|
|
rewind(collf); |
351 |
|
|
mesedit(collf, c); |
352 |
|
|
goto cont; |
353 |
|
|
} |
354 |
|
|
} |
355 |
|
|
|
356 |
✗✓ |
2 |
if (value("interactive") != NULL) { |
357 |
|
|
if (value("askcc") != NULL || value("askbcc") != NULL) { |
358 |
|
|
if (value("askcc") != NULL) { |
359 |
|
|
if (gethfromtty(hp, GCC) == -1) |
360 |
|
|
goto err; |
361 |
|
|
} |
362 |
|
|
if (value("askbcc") != NULL) { |
363 |
|
|
if (gethfromtty(hp, GBCC) == -1) |
364 |
|
|
goto err; |
365 |
|
|
} |
366 |
|
|
} else { |
367 |
|
|
puts("EOT"); |
368 |
|
|
(void)fflush(stdout); |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
goto out; |
372 |
|
|
err: |
373 |
|
|
if (collf != NULL) { |
374 |
|
|
(void)Fclose(collf); |
375 |
|
|
collf = NULL; |
376 |
|
|
} |
377 |
|
|
out: |
378 |
✓✗ |
2 |
if (collf != NULL) |
379 |
|
2 |
rewind(collf); |
380 |
|
2 |
noreset--; |
381 |
|
4 |
return(collf); |
382 |
|
2 |
} |
383 |
|
|
|
384 |
|
|
/* |
385 |
|
|
* Write a file, ex-like if f set. |
386 |
|
|
*/ |
387 |
|
|
int |
388 |
|
|
exwrite(char *name, FILE *fp, int f) |
389 |
|
|
{ |
390 |
|
|
FILE *of; |
391 |
|
|
int c; |
392 |
|
|
ssize_t cc, lc; |
393 |
|
|
struct stat junk; |
394 |
|
|
|
395 |
|
|
if (f) { |
396 |
|
|
printf("\"%s\" ", name); |
397 |
|
|
fflush(stdout); |
398 |
|
|
} |
399 |
|
|
if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { |
400 |
|
|
if (!f) |
401 |
|
|
fprintf(stderr, "%s: ", name); |
402 |
|
|
fputs("File exists\n", stderr); |
403 |
|
|
return(-1); |
404 |
|
|
} |
405 |
|
|
if ((of = Fopen(name, "w")) == NULL) { |
406 |
|
|
warn(NULL); |
407 |
|
|
return(-1); |
408 |
|
|
} |
409 |
|
|
lc = 0; |
410 |
|
|
cc = 0; |
411 |
|
|
while ((c = getc(fp)) != EOF) { |
412 |
|
|
cc++; |
413 |
|
|
if (c == '\n') |
414 |
|
|
lc++; |
415 |
|
|
(void)putc(c, of); |
416 |
|
|
if (ferror(of)) { |
417 |
|
|
warn("%s", name); |
418 |
|
|
(void)Fclose(of); |
419 |
|
|
return(-1); |
420 |
|
|
} |
421 |
|
|
} |
422 |
|
|
(void)Fclose(of); |
423 |
|
|
printf("%lld/%lld\n", (long long)lc, (long long)cc); |
424 |
|
|
fflush(stdout); |
425 |
|
|
return(0); |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
/* |
429 |
|
|
* Edit the message being collected on fp. |
430 |
|
|
* On return, make the edit file the new temp file. |
431 |
|
|
*/ |
432 |
|
|
void |
433 |
|
|
mesedit(FILE *fp, int c) |
434 |
|
|
{ |
435 |
|
|
FILE *nf; |
436 |
|
|
struct sigaction oact; |
437 |
|
|
sigset_t oset; |
438 |
|
|
|
439 |
|
|
(void)ignoresig(SIGINT, &oact, &oset); |
440 |
|
|
nf = run_editor(fp, (off_t)-1, c, 0); |
441 |
|
|
if (nf != NULL) { |
442 |
|
|
fseek(nf, 0L, SEEK_END); |
443 |
|
|
collf = nf; |
444 |
|
|
(void)Fclose(fp); |
445 |
|
|
} |
446 |
|
|
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
447 |
|
|
(void)sigaction(SIGINT, &oact, NULL); |
448 |
|
|
} |
449 |
|
|
|
450 |
|
|
/* |
451 |
|
|
* Pipe the message through the command. |
452 |
|
|
* Old message is on stdin of command; |
453 |
|
|
* New message collected from stdout. |
454 |
|
|
* Sh -c must return 0 to accept the new message. |
455 |
|
|
*/ |
456 |
|
|
void |
457 |
|
|
mespipe(FILE *fp, char *cmd) |
458 |
|
|
{ |
459 |
|
|
FILE *nf; |
460 |
|
|
int fd; |
461 |
|
|
char *shell, tempname[PATHSIZE]; |
462 |
|
|
struct sigaction oact; |
463 |
|
|
sigset_t oset; |
464 |
|
|
|
465 |
|
|
(void)ignoresig(SIGINT, &oact, &oset); |
466 |
|
|
(void)snprintf(tempname, sizeof(tempname), |
467 |
|
|
"%s/mail.ReXXXXXXXXXX", tmpdir); |
468 |
|
|
if ((fd = mkstemp(tempname)) == -1 || |
469 |
|
|
(nf = Fdopen(fd, "w+")) == NULL) { |
470 |
|
|
warn("%s", tempname); |
471 |
|
|
goto out; |
472 |
|
|
} |
473 |
|
|
(void)rm(tempname); |
474 |
|
|
/* |
475 |
|
|
* stdin = current message. |
476 |
|
|
* stdout = new message. |
477 |
|
|
*/ |
478 |
|
|
shell = value("SHELL"); |
479 |
|
|
if (run_command(shell, |
480 |
|
|
0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { |
481 |
|
|
(void)Fclose(nf); |
482 |
|
|
goto out; |
483 |
|
|
} |
484 |
|
|
if (fsize(nf) == 0) { |
485 |
|
|
fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); |
486 |
|
|
(void)Fclose(nf); |
487 |
|
|
goto out; |
488 |
|
|
} |
489 |
|
|
/* |
490 |
|
|
* Take new files. |
491 |
|
|
*/ |
492 |
|
|
(void)fseek(nf, 0L, SEEK_END); |
493 |
|
|
collf = nf; |
494 |
|
|
(void)Fclose(fp); |
495 |
|
|
out: |
496 |
|
|
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
497 |
|
|
(void)sigaction(SIGINT, &oact, NULL); |
498 |
|
|
} |
499 |
|
|
|
500 |
|
|
/* |
501 |
|
|
* Interpolate the named messages into the current |
502 |
|
|
* message, preceding each line with a tab. |
503 |
|
|
* Return a count of the number of characters now in |
504 |
|
|
* the message, or -1 if an error is encountered writing |
505 |
|
|
* the message temporary. The flag argument is 'm' if we |
506 |
|
|
* should shift over and 'f' if not. |
507 |
|
|
*/ |
508 |
|
|
int |
509 |
|
|
forward(char *ms, FILE *fp, char *fn, int f) |
510 |
|
|
{ |
511 |
|
|
int *msgvec; |
512 |
|
|
struct ignoretab *ig; |
513 |
|
|
char *tabst; |
514 |
|
|
|
515 |
|
|
msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); |
516 |
|
|
if (msgvec == NULL) |
517 |
|
|
return(0); |
518 |
|
|
if (getmsglist(ms, msgvec, 0) < 0) |
519 |
|
|
return(0); |
520 |
|
|
if (*msgvec == 0) { |
521 |
|
|
*msgvec = first(0, MMNORM); |
522 |
|
|
if (*msgvec == 0) { |
523 |
|
|
puts("No appropriate messages"); |
524 |
|
|
return(0); |
525 |
|
|
} |
526 |
|
|
msgvec[1] = 0; |
527 |
|
|
} |
528 |
|
|
if (tolower(f) == 'f') |
529 |
|
|
tabst = NULL; |
530 |
|
|
else if ((tabst = value("indentprefix")) == NULL) |
531 |
|
|
tabst = "\t"; |
532 |
|
|
ig = isupper(f) ? NULL : ignore; |
533 |
|
|
fputs("Interpolating:", stdout); |
534 |
|
|
for (; *msgvec != 0; msgvec++) { |
535 |
|
|
struct message *mp = message + *msgvec - 1; |
536 |
|
|
|
537 |
|
|
touch(mp); |
538 |
|
|
printf(" %d", *msgvec); |
539 |
|
|
if (sendmessage(mp, fp, ig, tabst) < 0) { |
540 |
|
|
warn("%s", fn); |
541 |
|
|
return(-1); |
542 |
|
|
} |
543 |
|
|
} |
544 |
|
|
putchar('\n'); |
545 |
|
|
return(0); |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
/* |
549 |
|
|
* User aborted during message composition. |
550 |
|
|
* Save the partial message in ~/dead.letter. |
551 |
|
|
*/ |
552 |
|
|
int |
553 |
|
|
collabort(void) |
554 |
|
|
{ |
555 |
|
|
/* |
556 |
|
|
* the control flow is subtle, because we can be called from ~q. |
557 |
|
|
*/ |
558 |
|
|
if (hadintr == 0 && isatty(0)) { |
559 |
|
|
if (value("ignore") != NULL) { |
560 |
|
|
puts("@"); |
561 |
|
|
fflush(stdout); |
562 |
|
|
clearerr(stdin); |
563 |
|
|
} else { |
564 |
|
|
fflush(stdout); |
565 |
|
|
fputs("\n(Interrupt -- one more to kill letter)\n", |
566 |
|
|
stderr); |
567 |
|
|
hadintr++; |
568 |
|
|
} |
569 |
|
|
return(0); |
570 |
|
|
} |
571 |
|
|
fflush(stdout); |
572 |
|
|
rewind(collf); |
573 |
|
|
if (value("nosave") == NULL) |
574 |
|
|
savedeadletter(collf); |
575 |
|
|
return(1); |
576 |
|
|
} |
577 |
|
|
|
578 |
|
|
void |
579 |
|
|
savedeadletter(FILE *fp) |
580 |
|
|
{ |
581 |
|
|
FILE *dbuf; |
582 |
|
|
int c; |
583 |
|
|
char *cp; |
584 |
|
|
|
585 |
|
|
if (fsize(fp) == 0) |
586 |
|
|
return; |
587 |
|
|
cp = getdeadletter(); |
588 |
|
|
c = umask(077); |
589 |
|
|
dbuf = Fopen(cp, "a"); |
590 |
|
|
(void)umask(c); |
591 |
|
|
if (dbuf == NULL) |
592 |
|
|
return; |
593 |
|
|
while ((c = getc(fp)) != EOF) |
594 |
|
|
(void)putc(c, dbuf); |
595 |
|
|
(void)Fclose(dbuf); |
596 |
|
|
rewind(fp); |
597 |
|
|
} |
598 |
|
|
|
599 |
|
|
int |
600 |
|
|
gethfromtty(struct header *hp, int gflags) |
601 |
|
|
{ |
602 |
|
|
|
603 |
|
|
hadintr = 0; |
604 |
|
|
while (grabh(hp, gflags) != 0) { |
605 |
|
|
if (collabort()) |
606 |
|
|
return(-1); |
607 |
|
|
} |
608 |
|
|
return(0); |
609 |
|
|
} |