2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen Daode Nurpmeso.
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 static char sccsid
[] = "@(#)collect.c 2.54 (gritter) 6/16/07";
48 * Mail -- a mail program
50 * Collect input from standard input, handling
60 * Read a message from standard output and return a read file to it
65 * The following hokiness with global variables is so that on
66 * receipt of an interrupt signal, the partial message can be salted
67 * away on dead.letter.
70 static sighandler_type saveint
; /* Previous SIGINT value */
71 static sighandler_type savehup
; /* Previous SIGHUP value */
72 static sighandler_type savetstp
; /* Previous SIGTSTP value */
73 static sighandler_type savettou
; /* Previous SIGTTOU value */
74 static sighandler_type savettin
; /* Previous SIGTTIN value */
75 static FILE *collf
; /* File for saving away */
76 static int hadintr
; /* Have seen one SIGINT so far */
78 static sigjmp_buf colljmp
; /* To get back to work */
79 static int colljmp_p
; /* whether to long jump */
80 static sigjmp_buf collabort
; /* To end collection with error */
82 static sigjmp_buf pipejmp
; /* On broken pipe */
84 static void onpipe(int signo
);
85 static void insertcommand(FILE *fp
, char *cmd
);
86 static void print_collf(FILE *collf
, struct header
*hp
);
87 static int include_file(FILE *fbuf
, char *name
, int *linecount
,
88 int *charcount
, int echo
);
89 static struct attachment
*read_attachment_data(struct attachment
*ap
,
91 static struct attachment
*append_attachments(struct attachment
*attach
,
93 static int exwrite(char *name
, FILE *fp
, int f
);
94 static enum okay
makeheader(FILE *fp
, struct header
*hp
);
95 static void mesedit(int c
, struct header
*hp
);
96 static void mespipe(char *cmd
);
97 static int forward(char *ms
, FILE *fp
, int f
);
98 static void collstop(int s
);
99 static void collint(int s
);
100 static void collhup(int s
);
101 static int putesc(const char *s
, FILE *stream
);
107 siglongjmp(pipejmp
, 1);
111 * Execute cmd and insert its standard output into fp.
114 insertcommand(FILE *fp
, char *cmd
)
123 if (sigsetjmp(pipejmp
, 1))
127 if ((obuf
= Popen(cmd
, "r", cp
, 0)) == NULL
) {
131 safe_signal(SIGPIPE
, onpipe
);
132 while ((c
= getc(obuf
)) != EOF
)
135 safe_signal(SIGPIPE
, SIG_IGN
);
137 safe_signal(SIGPIPE
, dflpipe
);
144 print_collf(FILE *collf
, struct header
*hp
)
148 struct attachment
*ap
;
151 size_t linecnt
, maxlines
, linesize
= 0, linelen
, count
, count2
;
157 count
= count2
= fsize(collf
);
158 if (is_a_tty
[0] && is_a_tty
[1] && (cp
= value("crt")) != NULL
) {
160 fgetline(&lbuf
, &linesize
, &count2
, NULL
, collf
, 0);
163 maxlines
= (*cp
== '\0' ? screensize() : atoi(cp
));
175 maxlines
-= myaddrs(hp
) != NULL
|| hp
->h_from
!= NULL
;
176 maxlines
-= value("ORGANIZATION") != NULL
||
177 hp
->h_organization
!= NULL
;
178 maxlines
-= value("replyto") != NULL
|| hp
->h_replyto
!= NULL
;
179 maxlines
-= value("sender") != NULL
|| hp
->h_sender
!= NULL
;
180 if ((long)maxlines
< 0 || linecnt
> maxlines
) {
182 if (sigsetjmp(pipejmp
, 1))
184 obuf
= Popen(cp
, "w", NULL
, 1);
189 safe_signal(SIGPIPE
, onpipe
);
192 fprintf(obuf
, catgets(catd
, CATSET
, 62,
193 "-------\nMessage contains:\n"));
194 gf
= GIDENT
|GTO
|GSUBJECT
|GCC
|GBCC
|GNL
|GFILES
;
195 if (value("fullnames"))
197 puthead(hp
, obuf
, gf
, SEND_TODISP
, CONV_NONE
, NULL
, NULL
);
198 while (fgetline(&lbuf
, &linesize
, &count
, &linelen
, collf
, 1))
199 prout(lbuf
, linelen
, obuf
);
200 if (hp
->h_attach
!= NULL
) {
201 fputs(catgets(catd
, CATSET
, 63, "Attachments:"), obuf
);
202 for (ap
= hp
->h_attach
; ap
!= NULL
; ap
= ap
->a_flink
) {
204 fprintf(obuf
, " message %u", ap
->a_msgno
);
206 fprintf(obuf
, " %s", ap
->a_name
);
213 if (obuf
!= stdout
) {
214 safe_signal(SIGPIPE
, SIG_IGN
);
216 safe_signal(SIGPIPE
, dflpipe
);
223 include_file(FILE *fbuf
, char *name
, int *linecount
, int *charcount
, int echo
)
225 char *interactive
, *linebuf
= NULL
;
226 size_t linesize
= 0, linelen
, count
;
229 fbuf
= Fopen(name
, "r");
234 interactive
= value("interactive");
240 while (fgetline(&linebuf
, &linesize
, &count
, &linelen
, fbuf
, 0)
242 if (fwrite(linebuf
, sizeof *linebuf
, linelen
, collf
)
247 if (interactive
!= NULL
&& echo
)
248 fwrite(linebuf
, sizeof *linebuf
, linelen
, stdout
);
250 (*charcount
) += linelen
;
259 * Ask the user to edit file names and other data for the given
260 * attachment. NULL is returned if no file name is given.
262 static struct attachment
*
263 read_attachment_data(struct attachment
*ap
, unsigned number
)
265 char prefix
[80], *cp
;
268 ap
= csalloc(1, sizeof *ap
);
270 printf("#%u\tmessage %u\n", number
, ap
->a_msgno
);
273 snprintf(prefix
, sizeof prefix
, catgets(catd
, CATSET
, 50,
274 "#%u\tfilename: "), number
);
277 if ((ap
->a_name
= readtty(prefix
, ap
->a_name
)) == NULL
)
279 if ((exf
= expand(ap
->a_name
)) != NULL
)
281 if (access(ap
->a_name
, R_OK
) == 0)
285 if (ap
->a_name
&& (value("attachment-ask-charset") ||
286 (cp
= value("sendcharsets")) != NULL
&&
287 strchr(cp
, ',') != NULL
)) {
288 snprintf(prefix
, sizeof prefix
, "#%u\tcharset: ", number
);
289 ap
->a_charset
= readtty(prefix
, ap
->a_charset
);
292 * The "attachment-ask-content-*" variables are left undocumented
293 * since they are for RFC connoisseurs only.
295 if (ap
->a_name
&& value("attachment-ask-content-type")) {
296 if (ap
->a_content_type
== NULL
)
297 ap
->a_content_type
= mime_filecontent(ap
->a_name
);
298 snprintf(prefix
, sizeof prefix
, "#%u\tContent-Type: ", number
);
299 ap
->a_content_type
= readtty(prefix
, ap
->a_content_type
);
301 if (ap
->a_name
&& value("attachment-ask-content-disposition")) {
302 snprintf(prefix
, sizeof prefix
,
303 "#%u\tContent-Disposition: ", number
);
304 ap
->a_content_disposition
= readtty(prefix
,
305 ap
->a_content_disposition
);
307 if (ap
->a_name
&& value("attachment-ask-content-id")) {
308 snprintf(prefix
, sizeof prefix
, "#%u\tContent-ID: ", number
);
309 ap
->a_content_id
= readtty(prefix
, ap
->a_content_id
);
311 if (ap
->a_name
&& value("attachment-ask-content-description")) {
312 snprintf(prefix
, sizeof prefix
,
313 "#%u\tContent-Description: ", number
);
314 ap
->a_content_description
= readtty(prefix
,
315 ap
->a_content_description
);
317 return ap
->a_name
? ap
: NULL
;
321 * Interactively edit the attachment list.
324 edit_attachments(struct attachment
*attach
)
326 struct attachment
*ap
, *nap
;
329 for (ap
= attach
; ap
; ap
= ap
->a_flink
) {
330 if ((nap
= read_attachment_data(ap
, attno
)) == NULL
) {
332 ap
->a_blink
->a_flink
= ap
->a_flink
;
334 attach
= ap
->a_flink
;
336 ap
->a_flink
->a_blink
= ap
->a_blink
;
342 while ((nap
= read_attachment_data(NULL
, attno
)) != NULL
) {
343 for (ap
= attach
; ap
&& ap
->a_flink
; ap
= ap
->a_flink
);
356 * Put the given file to the end of the attachment list.
359 add_attachment(struct attachment
*attach
, char *file
, int expand_file
)
361 struct attachment
*ap
, *nap
;
368 file
= savestr(file
);
369 if (access(file
, R_OK
) != 0)
372 nap
= csalloc(1, sizeof *nap
);
374 if (attach
!= NULL
) {
375 for (ap
= attach
; ap
->a_flink
!= NULL
; ap
= ap
->a_flink
);
386 * Append the whitespace-separated file names to the end of
387 * the attachment list.
389 static struct attachment
*
390 append_attachments(struct attachment
*attach
, char *names
)
394 struct attachment
*ap
;
397 while (*cp
!= '\0' && blankchar(*cp
& 0377))
399 while (*cp
!= '\0') {
401 while (*cp
!= '\0' && !blankchar(*cp
& 0377))
405 if (*names
!= '\0') {
406 if ((ap
= add_attachment(attach
, names
, 1)) == NULL
)
413 while (*cp
!= '\0' && blankchar(*cp
& 0377))
420 collect(struct header
*hp
, int printheaders
, struct message
*mp
,
421 char *quotefile
, int doprefix
, int tflag
)
424 struct ignoretab
*quoteig
;
425 int lc
, cc
, escape
, eofcount
;
427 char *linebuf
= NULL
, *cp
, *quote
= NULL
;
429 char *tempMail
= NULL
;
433 enum sendaction action
;
434 sighandler_type savedtop
;
435 const char tildehelp
[] =
436 "-------------------- ~ ESCAPES ----------------------------\n\
437 ~~ Quote a single tilde\n\
438 ~@ [file ...] Edit attachment list\n\
439 ~b users Add users to \"blind\" cc list\n\
440 ~c users Add users to cc list\n\
441 ~d Read in dead.letter\n\
442 ~e Edit the message buffer\n\
443 ~f messages Read in messages without indenting lines\n\
444 ~F messages Same as ~f, but keep all header lines\n\
445 ~h Prompt for to list, subject, cc, and \"blind\" cc list\n\
446 ~r file Read a file into the message buffer\n\
447 ~p Print the message buffer\n\
448 ~q Abort message composition and save text to dead.letter\n\
449 ~m messages Read in messages with each line indented\n\
450 ~M messages Same as ~m, but keep all header lines\n\
451 ~s subject Set subject\n\
452 ~t users Add users to to list\n\
453 ~v Invoke display editor on message\n\
454 ~w file Write message onto file\n\
455 ~x Abort message composition and discard text written so far\n\
456 ~!command Invoke the shell\n\
457 ~:command Execute a regular command\n\
458 -----------------------------------------------------------\n";
469 * Start catching signals from here, but we're still die on interrupts
470 * until we're in the main loop.
473 sigaddset(&nset
, SIGINT
);
474 sigaddset(&nset
, SIGHUP
);
475 sigprocmask(SIG_BLOCK
, &nset
, &oset
);
476 handlerpush(collint
);
477 if ((saveint
= safe_signal(SIGINT
, SIG_IGN
)) != SIG_IGN
)
478 safe_signal(SIGINT
, collint
);
479 if ((savehup
= safe_signal(SIGHUP
, SIG_IGN
)) != SIG_IGN
)
480 safe_signal(SIGHUP
, collhup
);
481 savetstp
= safe_signal(SIGTSTP
, collstop
);
482 savettou
= safe_signal(SIGTTOU
, collstop
);
483 savettin
= safe_signal(SIGTTIN
, collstop
);
484 if (sigsetjmp(collabort
, 1)) {
485 if (tempMail
!= NULL
) {
491 if (sigsetjmp(colljmp
, 1)) {
492 if (tempMail
!= NULL
) {
498 sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
501 if ((collf
= Ftemp(&tempMail
, "Rs", "w+", 0600, 1)) == NULL
) {
502 perror(catgets(catd
, CATSET
, 51, "temporary mail file"));
508 if ((cp
= value("SNAIL_HEAD")) != NULL
) {
515 * If we are going to prompt for a subject,
516 * refrain from printing a newline after
517 * the headers (since some people mind).
521 t
= GTO
|GSUBJECT
|GCC
|GNL
;
522 if (value("fullnames"))
524 if (hp
->h_subject
== NULL
&& value("interactive") != NULL
&&
525 (value("ask") != NULL
|| value("asksub") != NULL
))
526 t
&= ~GNL
, getfields
|= GSUBJECT
;
527 if (hp
->h_to
== NULL
&& value("interactive") != NULL
)
528 t
&= ~GNL
, getfields
|= GTO
;
529 if (value("bsdcompat") == NULL
&& value("askatend") == NULL
&&
530 value("interactive")) {
531 if (hp
->h_bcc
== NULL
&& value("askbcc"))
532 t
&= ~GNL
, getfields
|= GBCC
;
533 if (hp
->h_cc
== NULL
&& value("askcc"))
534 t
&= ~GNL
, getfields
|= GCC
;
537 puthead(hp
, stdout
, t
, SEND_TODISP
, CONV_NONE
,
544 * Quote an original message
546 if (mp
!= NULL
&& (doprefix
|| (quote
= value("quote")) != NULL
)) {
551 if ((cp
= value("fwdheading")) == NULL
)
552 cp
= "-------- Original Message --------";
554 fprintf(collf
, "%s\n", cp
);
555 fprintf(stdout
, "%s\n", cp
);
557 } else if (strcmp(quote
, "noheading") == 0) {
559 } else if (strcmp(quote
, "headers") == 0) {
561 } else if (strcmp(quote
, "allheaders") == 0) {
563 action
= SEND_QUOTE_ALL
;
565 cp
= hfield("from", mp
);
567 mime_write(cp
, strlen(cp
),
568 collf
, CONV_FROMHDR
, TD_NONE
,
571 mime_write(cp
, strlen(cp
),
572 stdout
, CONV_FROMHDR
, TD_NONE
,
575 fwrite(catgets(catd
, CATSET
, 52,
576 " wrote:\n\n"), sizeof(char), 9, collf
);
577 fwrite(catgets(catd
, CATSET
, 52,
578 " wrote:\n\n"), sizeof(char), 9, stdout
);
581 cp
= value("indentprefix");
582 if (cp
!= NULL
&& *cp
== '\0')
584 send(mp
, collf
, quoteig
, doprefix
? NULL
: cp
, action
, NULL
);
585 send(mp
, stdout
, quoteig
, doprefix
? NULL
: cp
, action
, NULL
);
588 if ((cp
= value("escape")) != NULL
)
595 if (!sigsetjmp(colljmp
, 1)) {
597 grabh(hp
, getfields
, 1);
598 if (quotefile
!= NULL
) {
599 if (include_file(NULL
, quotefile
, &lc
, &cc
, 1) != 0)
604 * Come here for printing the after-signal message.
605 * Duplicate messages won't be printed because
606 * the write is aborted if we get a SIGTTOU.
611 fprintf(stderr
, catgets(catd
, CATSET
, 53,
612 "\n(Interrupt -- one more to kill letter)\n"));
614 printf(catgets(catd
, CATSET
, 54, "(continue)\n"));
618 if (value("interactive") == NULL
&& tildeflag
<= 0 && !is_a_tty
[0] &&
621 * No tilde escapes, interrupts not expected. Copy
622 * standard input the simple way.
624 linebuf
= srealloc(linebuf
, linesize
= BUFSIZ
);
625 while ((count
= fread(linebuf
, sizeof *linebuf
,
626 linesize
, stdin
)) > 0) {
627 if (fwrite(linebuf
, sizeof *linebuf
,
628 count
, collf
) != count
)
635 count
= readline(stdin
, &linebuf
, &linesize
);
638 if (value("interactive") != NULL
&&
639 value("ignoreeof") != NULL
&& ++eofcount
< 25) {
640 printf(catgets(catd
, CATSET
, 55,
641 "Use \".\" to terminate letter\n"));
646 if (tflag
&& count
== 0) {
648 if (makeheader(collf
, hp
) != OKAY
)
656 if (linebuf
[0] == '.' && linebuf
[1] == '\0' &&
657 value("interactive") != NULL
&&
658 (value("dot") != NULL
|| value("ignoreeof") != NULL
))
660 if (linebuf
[0] != escape
|| (value("interactive") == NULL
&&
663 if (putline(collf
, linebuf
, count
) < 0)
671 * On double escape, just send the single one.
672 * Otherwise, it's an error.
675 if (putline(collf
, &linebuf
[1], count
- 1) < 0)
680 printf(catgets(catd
, CATSET
, 56,
681 "Unknown tilde escape.\n"));
683 #ifdef DEBUG_COMMANDS
690 #endif /* DEBUG_COMMANDS */
693 * Shell escape, send the balance of the
701 * Escape to command mode, but be nice!
704 execute(&linebuf
[2], 1, count
- 2);
708 * Simulate end of file on input.
713 * Same as 'q', but no dead.letter saving.
721 * Force a quit of sending mail.
722 * Act like an interrupt happened.
730 * Grab a bunch of headers.
733 grabh(hp
, GTO
|GSUBJECT
|GCC
|GBCC
,
734 value("bsdcompat") != NULL
&&
735 value("bsdorder") != NULL
);
736 while (hp
->h_to
== NULL
);
740 * Grab extra headers.
743 grabh(hp
, GEXTRA
, 0);
744 while (check_from_and_sender(hp
->h_from
, hp
->h_sender
));
748 * Add to the To list.
750 while ((hp
->h_to
= checkaddrs(cat(hp
->h_to
,
751 sextract(&linebuf
[2], GTO
|GFULL
))))
756 * Set the Subject list.
759 while (whitechar(*cp
& 0377))
761 hp
->h_subject
= savestr(cp
);
765 * Edit the attachment list.
767 if (linebuf
[2] != '\0')
768 hp
->h_attach
= append_attachments(hp
->h_attach
,
771 hp
->h_attach
= edit_attachments(hp
->h_attach
);
775 * Add to the CC list.
777 hp
->h_cc
= checkaddrs(cat(hp
->h_cc
,
778 sextract(&linebuf
[2], GCC
|GFULL
)));
782 * Add stuff to blind carbon copies list.
784 hp
->h_bcc
= checkaddrs(cat(hp
->h_bcc
,
785 sextract(&linebuf
[2], GBCC
|GFULL
)));
788 strncpy(linebuf
+ 2, getdeadletter(), linesize
- 2);
789 linebuf
[linesize
-1]='\0';
795 * Search for the file name,
796 * then open it and copy the contents to collf.
799 while (whitechar(*cp
& 0377))
802 printf(catgets(catd
, CATSET
, 57,
803 "Interpolate what file?\n"));
807 insertcommand(collf
, cp
+ 1);
814 printf(catgets(catd
, CATSET
, 58,
815 "%s: Directory\n"), cp
);
818 if ((fbuf
= Fopen(cp
, "r")) == NULL
) {
822 printf(catgets(catd
, CATSET
, 59, "\"%s\" "), cp
);
824 if (include_file(fbuf
, cp
, &lc
, &cc
, 0) != 0)
826 printf(catgets(catd
, CATSET
, 60, "%d/%d\n"), lc
, cc
);
830 * Insert an environment variable into the file.
833 while (whitechar(*cp
& 0377))
835 if ((cp
= value(cp
)) == NULL
|| *cp
== '\0')
844 * Insert the contents of a signature variable.
846 if ((cp
= value(c
== 'a' ? "sign" : "Sign")) != NULL
&&
855 * Write the message on a file.
858 while (blankchar(*cp
& 0377))
861 fprintf(stderr
, catgets(catd
, CATSET
, 61,
862 "Write what file!?\n"));
865 if ((cp
= expand(cp
)) == NULL
)
868 exwrite(cp
, collf
, 1);
875 * Interpolate the named messages, if we
876 * are in receiving mail mode. Does the
877 * standard list processing garbage.
878 * If ~f is given, we don't shift over.
880 if (forward(linebuf
+ 2, collf
, c
) < 0)
884 fputs(tildehelp
, stdout
);
888 * Print out the current state of the
889 * message without altering anything.
891 print_collf(collf
, hp
);
895 * Pipe message through command.
896 * Collect output as new message.
899 mespipe(&linebuf
[2]);
904 * Edit the current message.
905 * 'e' means to use EDITOR
906 * 'v' means to use VISUAL
909 mesedit(c
, value("editheaders") ? hp
: NULL
);
921 if ((cp
= value("SNAIL_TAIL")) != NULL
) {
932 sigaddset(&nset
, SIGINT
);
933 sigaddset(&nset
, SIGHUP
);
935 sigprocmask(SIG_BLOCK
, &nset
, (sigset_t
*)NULL
);
937 sigprocmask(SIG_BLOCK
, &nset
, &oset
);
939 safe_signal(SIGINT
, saveint
);
940 safe_signal(SIGHUP
, savehup
);
941 safe_signal(SIGTSTP
, savetstp
);
942 safe_signal(SIGTTOU
, savettou
);
943 safe_signal(SIGTTIN
, savettin
);
944 sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
949 * Write a file, ex-like if f set.
952 exwrite(char *name
, FILE *fp
, int f
)
960 printf("\"%s\" ", name
);
963 if ((of
= Fopen(name
, "a")) == NULL
) {
969 while ((c
= getc(fp
)) != EOF
) {
981 printf(catgets(catd
, CATSET
, 65, "%d/%ld\n"), lc
, cc
);
987 makeheader(FILE *fp
, struct header
*hp
)
993 if ((nf
= Ftemp(&tempEdit
, "Re", "w+", 0600, 1)) == NULL
) {
994 perror(catgets(catd
, CATSET
, 66, "temporary mail edit file"));
1002 extract_header(fp
, hp
);
1003 while ((c
= getc(fp
)) != EOF
)
1009 if (check_from_and_sender(hp
->h_from
, hp
->h_sender
))
1015 * Edit the message being collected on fp.
1016 * On return, make the edit file the new temp file.
1019 mesedit(int c
, struct header
*hp
)
1021 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
1022 FILE *nf
= run_editor(collf
, (off_t
)-1, c
, 0, hp
, NULL
, SEND_MBOX
,
1030 fseek(nf
, 0L, SEEK_END
);
1035 safe_signal(SIGINT
, sigint
);
1039 * Pipe the message through the command.
1040 * Old message is on stdin of command;
1041 * New message collected from stdout.
1042 * Sh -c must return 0 to accept the new message.
1048 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
1052 if ((nf
= Ftemp(&tempEdit
, "Re", "w+", 0600, 1)) == NULL
) {
1053 perror(catgets(catd
, CATSET
, 66, "temporary mail edit file"));
1060 * stdin = current message.
1061 * stdout = new message.
1063 if ((shell
= value("SHELL")) == NULL
)
1065 if (run_command(shell
,
1066 0, fileno(collf
), fileno(nf
), "-c", cmd
, NULL
) < 0) {
1070 if (fsize(nf
) == 0) {
1071 fprintf(stderr
, catgets(catd
, CATSET
, 67,
1072 "No bytes from \"%s\" !?\n"), cmd
);
1079 fseek(nf
, 0L, SEEK_END
);
1083 safe_signal(SIGINT
, sigint
);
1087 * Interpolate the named messages into the current
1088 * message, preceding each line with a tab.
1089 * Return a count of the number of characters now in
1090 * the message, or -1 if an error is encountered writing
1091 * the message temporary. The flag argument is 'm' if we
1092 * should shift over and 'f' if not.
1095 forward(char *ms
, FILE *fp
, int f
)
1098 struct ignoretab
*ig
;
1100 enum sendaction action
;
1103 msgvec
= (int *)salloc((msgCount
+1) * sizeof *msgvec
);
1106 if (getmsglist(ms
, msgvec
, 0) < 0)
1109 *msgvec
= first(0, MMNORM
);
1111 printf(catgets(catd
, CATSET
, 68,
1112 "No appropriate messages\n"));
1117 if (f
== 'f' || f
== 'F')
1119 else if ((tabst
= value("indentprefix")) == NULL
)
1121 ig
= upperchar(f
) ? (struct ignoretab
*)NULL
: ignore
;
1122 action
= upperchar(f
) ? SEND_QUOTE_ALL
: SEND_QUOTE
;
1123 printf(catgets(catd
, CATSET
, 69, "Interpolating:"));
1124 for (; *msgvec
!= 0; msgvec
++) {
1125 struct message
*mp
= message
+ *msgvec
- 1;
1128 printf(" %d", *msgvec
);
1129 if (send(mp
, fp
, ig
, tabst
, action
, NULL
) < 0) {
1130 perror(catgets(catd
, CATSET
, 70,
1131 "temporary mail file"));
1140 * Print (continue) when continued after ^Z.
1146 sighandler_type old_action
= safe_signal(s
, SIG_DFL
);
1150 sigaddset(&nset
, s
);
1151 sigprocmask(SIG_UNBLOCK
, &nset
, (sigset_t
*)NULL
);
1153 sigprocmask(SIG_BLOCK
, &nset
, (sigset_t
*)NULL
);
1154 safe_signal(s
, old_action
);
1158 siglongjmp(colljmp
, 1);
1163 * On interrupt, come here to save the partial message in ~/dead.letter.
1164 * Then jump out of the collection loop.
1171 * the control flow is subtle, because we can be called from ~q.
1174 if (value("ignore") != NULL
) {
1181 siglongjmp(colljmp
, 1);
1185 if (value("save") != NULL
&& s
!= 0)
1186 savedeadletter(collf
);
1187 siglongjmp(collabort
, 1);
1195 savedeadletter(collf
);
1197 * Let's pretend nobody else wants to clean up,
1198 * a true statement at this time.
1204 savedeadletter(FILE *fp
)
1207 int c
, lines
= 0, bytes
= 0;
1212 cp
= getdeadletter();
1214 dbuf
= Fopen(cp
, "a");
1218 printf("\"%s\" ", cp
);
1219 while ((c
= getc(fp
)) != EOF
) {
1226 printf("%d/%d\n", lines
, bytes
);
1231 putesc(const char *s
, FILE *stream
)
1250 putc(s
[0]&0377, stream
);