1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Collect input from standard input, handling ~ escapes.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * The following hokiness with global variables is so that on
49 * receipt of an interrupt signal, the partial message can be salted
50 * away on dead.letter.
53 static sighandler_type saveint
; /* Previous SIGINT value */
54 static sighandler_type savehup
; /* Previous SIGHUP value */
55 static sighandler_type savetstp
; /* Previous SIGTSTP value */
56 static sighandler_type savettou
; /* Previous SIGTTOU value */
57 static sighandler_type savettin
; /* Previous SIGTTIN value */
58 static FILE *collf
; /* File for saving away */
59 static int hadintr
; /* Have seen one SIGINT so far */
61 static sigjmp_buf colljmp
; /* To get back to work */
62 static int colljmp_p
; /* whether to long jump */
63 static sigjmp_buf collabort
; /* To end collection with error */
65 static sigjmp_buf pipejmp
; /* On broken pipe */
67 /* If *interactive* is set and *echo* is, too, also dump to *stdout* */
68 static int _include_file(FILE *fbuf
, char const *name
, int *linecount
,
69 int *charcount
, int echo
);
71 static void onpipe(int signo
);
72 static void insertcommand(FILE *fp
, char const *cmd
);
73 static void print_collf(FILE *collf
, struct header
*hp
);
74 static int exwrite(char const *name
, FILE *fp
, int f
);
75 static enum okay
makeheader(FILE *fp
, struct header
*hp
);
76 static void mesedit(int c
, struct header
*hp
);
77 static void mespipe(char *cmd
);
78 static int forward(char *ms
, FILE *fp
, int f
);
79 static void collstop(int s
);
80 static void collint(int s
);
81 static void collhup(int s
);
82 static int putesc(const char *s
, FILE *stream
);
85 _include_file(FILE *fbuf
, char const *name
, int *linecount
, int *charcount
,
90 size_t linesize
= 0, linelen
, count
;
93 if ((fbuf
= Fopen(name
, "r")) == NULL
) {
100 *linecount
= *charcount
= 0;
102 while (fgetline(&linebuf
, &linesize
, &count
, &linelen
, fbuf
, 0)
104 if (fwrite(linebuf
, sizeof *linebuf
, linelen
, collf
)
107 if ((options
& OPT_INTERACTIVE
) && echo
)
108 fwrite(linebuf
, sizeof *linebuf
, linelen
, stdout
);
110 (*charcount
) += linelen
;
129 siglongjmp(pipejmp
, 1);
133 * Execute cmd and insert its standard output into fp.
136 insertcommand(FILE *fp
, char const *cmd
)
145 if ((ibuf
= Popen(cmd
, "r", cp
, 0)) != NULL
) {
146 while ((c
= getc(ibuf
)) != EOF
) /* XXX bytewise, yuck! */
157 print_collf(FILE *collf
, struct header
*hp
)
160 FILE *volatile obuf
= stdout
;
161 struct attachment
*ap
;
164 size_t linecnt
, maxlines
, linesize
= 0, linelen
, count
, count2
;
168 count
= count2
= fsize(collf
);
170 if (IS_TTY_SESSION() && (cp
= voption("crt")) != NULL
) {
172 fgetline(&lbuf
, &linesize
, &count2
, NULL
, collf
, 0);
175 maxlines
= (*cp
== '\0' ? screensize() : atoi(cp
));
187 maxlines
-= myaddrs(hp
) != NULL
|| hp
->h_from
!= NULL
;
188 maxlines
-= value("ORGANIZATION") != NULL
||
189 hp
->h_organization
!= NULL
;
190 maxlines
-= value("replyto") != NULL
|| hp
->h_replyto
!= NULL
;
191 maxlines
-= value("sender") != NULL
|| hp
->h_sender
!= NULL
;
192 if ((long)maxlines
< 0 || linecnt
> maxlines
) {
194 if (sigsetjmp(pipejmp
, 1))
196 obuf
= Popen(cp
, "w", NULL
, 1);
201 safe_signal(SIGPIPE
, onpipe
);
205 fprintf(obuf
, tr(62, "-------\nMessage contains:\n"));
206 gf
= GIDENT
|GTO
|GSUBJECT
|GCC
|GBCC
|GNL
|GFILES
;
207 if (value("fullnames"))
209 puthead(hp
, obuf
, gf
, SEND_TODISP
, CONV_NONE
, NULL
, NULL
);
210 while (fgetline(&lbuf
, &linesize
, &count
, &linelen
, collf
, 1))
211 prout(lbuf
, linelen
, obuf
);
212 if (hp
->h_attach
!= NULL
) {
213 fputs(tr(63, "-------\nAttachments:\n"), obuf
);
214 for (ap
= hp
->h_attach
; ap
!= NULL
; ap
= ap
->a_flink
) {
216 fprintf(obuf
, " - message %u\n", ap
->a_msgno
);
218 /* TODO after MIME/send layer rewrite we *know*
219 * TODO the details of the attachment here,
220 * TODO so adjust this again, then */
221 char const *cs
, *csi
= "-> ";
223 if ((cs
= ap
->a_charset
) == NULL
&&
225 cs
= ap
->a_input_charset
)
227 cs
= charset_get_lc();
228 if ((cp
= ap
->a_content_type
) == NULL
)
230 else if (ascncasecmp(cp
, "text/", 5) != 0)
233 fprintf(obuf
, " - [%s, %s%s] %s\n",
234 cp
, csi
, cs
, ap
->a_name
);
239 if (obuf
!= stdout
) {
240 safe_signal(SIGPIPE
, SIG_IGN
);
242 safe_signal(SIGPIPE
, dflpipe
);
249 collect(struct header
*hp
, int printheaders
, struct message
*mp
,
250 char *quotefile
, int doprefix
)
253 struct ignoretab
*quoteig
;
254 int lc
, cc
, eofcount
, c
, t
;
255 int volatile escape
, getfields
;
256 char *linebuf
= NULL
, *quote
= NULL
, *tempMail
= NULL
;
260 enum sendaction action
;
262 sighandler_type savedtop
;
266 * Start catching signals from here, but we're still die on interrupts
267 * until we're in the main loop.
270 sigaddset(&nset
, SIGINT
);
271 sigaddset(&nset
, SIGHUP
);
272 sigprocmask(SIG_BLOCK
, &nset
, &oset
);
273 handlerpush(collint
);
274 if ((saveint
= safe_signal(SIGINT
, SIG_IGN
)) != SIG_IGN
)
275 safe_signal(SIGINT
, collint
);
276 if ((savehup
= safe_signal(SIGHUP
, SIG_IGN
)) != SIG_IGN
)
277 safe_signal(SIGHUP
, collhup
);
278 /* TODO We do a lot of redundant signal handling, especially
279 * TODO with the line editor(s); try to merge this */
280 savetstp
= safe_signal(SIGTSTP
, collstop
);
281 savettou
= safe_signal(SIGTTOU
, collstop
);
282 savettin
= safe_signal(SIGTTIN
, collstop
);
283 if (sigsetjmp(collabort
, 1))
285 if (sigsetjmp(colljmp
, 1))
287 sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
290 if ((collf
= Ftemp(&tempMail
, "Rs", "w+", 0600, 1)) == NULL
) {
291 perror(tr(51, "temporary mail file"));
297 if ((cp
= value("NAIL_HEAD")) != NULL
&& putesc(cp
, collf
) < 0)
301 * If we are going to prompt for a subject,
302 * refrain from printing a newline after
303 * the headers (since some people mind).
306 if (! (options
& OPT_t_FLAG
)) {
307 t
= GTO
|GSUBJECT
|GCC
|GNL
;
308 if (value("fullnames"))
310 if (hp
->h_subject
== NULL
&& (options
& OPT_INTERACTIVE
) &&
311 (value("ask") != NULL
|| value("asksub") != NULL
))
312 t
&= ~GNL
, getfields
|= GSUBJECT
;
313 if (hp
->h_to
== NULL
&& (options
& OPT_INTERACTIVE
))
314 t
&= ~GNL
, getfields
|= GTO
;
315 if (value("bsdcompat") == NULL
&& value("askatend") == NULL
&&
316 (options
& OPT_INTERACTIVE
)) {
317 if (hp
->h_bcc
== NULL
&& value("askbcc"))
318 t
&= ~GNL
, getfields
|= GBCC
;
319 if (hp
->h_cc
== NULL
&& value("askcc"))
320 t
&= ~GNL
, getfields
|= GCC
;
323 (void)puthead(hp
, stdout
, t
, SEND_TODISP
, CONV_NONE
,
325 (void)fflush(stdout
);
330 * Quote an original message
332 if (mp
!= NULL
&& (doprefix
|| (quote
= value("quote")) != NULL
)) {
337 if ((cp
= value("fwdheading")) == NULL
)
338 cp
= "-------- Original Message --------";
339 if (*cp
&& fprintf(collf
, "%s\n", cp
) < 0)
341 } else if (strcmp(quote
, "noheading") == 0) {
343 } else if (strcmp(quote
, "headers") == 0) {
345 } else if (strcmp(quote
, "allheaders") == 0) {
347 action
= SEND_QUOTE_ALL
;
349 cp
= hfield1("from", mp
);
350 if (cp
!= NULL
&& (count
= (long)strlen(cp
)) > 0) {
351 if (xmime_write(cp
, count
,
352 collf
, CONV_FROMHDR
, TD_NONE
,
355 if (fprintf(collf
, tr(52, " wrote:\n\n")) < 0)
361 cp
= value("indentprefix");
362 if (cp
!= NULL
&& *cp
== '\0')
364 if (send(mp
, collf
, quoteig
, (doprefix
? NULL
: cp
), action
,
369 /* Print what we have sofar also on the terminal */
371 while ((c
= getc(collf
)) != EOF
) /* XXX bytewise, yuck! */
372 (void)putc(c
, stdout
);
373 if (fseek(collf
, 0, SEEK_END
))
376 escape
= ((cp
= value("escape")) != NULL
) ? *cp
: ESCAPE
;
380 if (! sigsetjmp(colljmp
, 1)) {
382 grab_headers(hp
, getfields
, 1);
383 if (quotefile
!= NULL
) {
384 if (_include_file(NULL
, quotefile
, &lc
, &cc
, 1) != 0)
387 if ((options
& OPT_INTERACTIVE
) && value("editalong")) {
394 * Come here for printing the after-signal message.
395 * Duplicate messages won't be printed because
396 * the write is aborted if we get a SIGTTOU.
400 (void)fprintf(stderr
, tr(53,
401 "\n(Interrupt -- one more to kill letter)\n"));
403 printf(tr(54, "(continue)\n"));
404 (void)fflush(stdout
);
409 * No tilde escapes, interrupts not expected. Simply copy STDIN
411 if (! (options
& (OPT_INTERACTIVE
| OPT_t_FLAG
|OPT_TILDE_FLAG
))) {
412 linebuf
= srealloc(linebuf
, linesize
= LINESIZE
);
413 while ((count
= fread(linebuf
, sizeof *linebuf
,
414 linesize
, stdin
)) > 0) {
415 if ((size_t)count
!= fwrite(linebuf
, sizeof *linebuf
,
425 * The interactive collect loop
429 count
= readline_input(LNED_NONE
, "", &linebuf
, &linesize
);
433 if ((options
& OPT_INTERACTIVE
) &&
434 value("ignoreeof") != NULL
&& ++eofcount
< 25) {
436 "Use \".\" to terminate letter\n"));
441 if ((options
& OPT_t_FLAG
) && count
== 0) {
443 if (makeheader(collf
, hp
) != OKAY
)
446 options
&= ~OPT_t_FLAG
;
452 if (linebuf
[0] == '.' && linebuf
[1] == '\0' &&
453 (options
& (OPT_INTERACTIVE
|OPT_TILDE_FLAG
)) &&
454 (boption("dot") || boption("ignoreeof")))
456 if (count
== 0 || linebuf
[0] != escape
|| ! (options
&
457 (OPT_INTERACTIVE
| OPT_TILDE_FLAG
))) {
458 /* TODO calls putline(), which *always* appends LF;
459 * TODO thus, STDIN with -t will ALWAYS end with LF,
460 * TODO even if no trailing LF and QP CTE */
461 if (putline(collf
, linebuf
, count
) < 0)
470 * On double escape, just send the single one.
471 * Otherwise, it's an error.
474 if (putline(collf
, &linebuf
[1], count
- 1) < 0)
479 printf(tr(56, "Unknown tilde escape.\n"));
488 /* Shell escape, send the balance of line to sh -c */
493 /* Escape to command mode, but be nice! */
495 execute(&linebuf
[2], 1, count
- 2);
498 /* Simulate end of file on input */
501 /* Same as 'q', but no dead.letter saving */
508 * Force a quit of sending mail.
509 * Act like an interrupt happened.
516 /* Grab a bunch of headers */
518 grab_headers(hp
, GTO
|GSUBJECT
|GCC
|GBCC
,
519 (value("bsdcompat") != NULL
&&
520 value("bsdorder") != NULL
));
521 while (hp
->h_to
== NULL
);
524 /* Grab extra headers */
526 grab_headers(hp
, GEXTRA
, 0);
527 while (check_from_and_sender(hp
->h_from
, hp
->h_sender
));
530 /* Add to the To list */
531 while ((hp
->h_to
= cat(hp
->h_to
, checkaddrs(
532 lextract(&linebuf
[2], GTO
|GFULL
))))
537 /* Set the Subject list */
539 while (whitechar(*cp
))
541 hp
->h_subject
= savestr(cp
);
549 /* Edit the attachment list */
550 if (linebuf
[2] != '\0')
551 hp
->h_attach
= append_attachments(hp
->h_attach
,
554 hp
->h_attach
= edit_attachments(hp
->h_attach
);
557 /* Add to the CC list */
558 hp
->h_cc
= cat(hp
->h_cc
, checkaddrs(
559 lextract(&linebuf
[2], GCC
|GFULL
)));
562 /* Add stuff to blind carbon copies list */
563 hp
->h_bcc
= cat(hp
->h_bcc
, checkaddrs(
564 lextract(&linebuf
[2], GBCC
|GFULL
)));
567 strncpy(linebuf
+ 2, getdeadletter(), linesize
- 2);
568 linebuf
[linesize
-1]='\0';
574 * Search for the file name,
575 * then open it and copy the contents to collf.
578 while (whitechar(*cp
))
581 fprintf(stderr
, tr(57,
582 "Interpolate what file?\n"));
586 insertcommand(collf
, cp
+ 1);
589 if ((cp
= file_expand(cp
)) == NULL
)
592 fprintf(stderr
, tr(58, "%s: Directory\n"), cp
);
595 if ((fbuf
= Fopen(cp
, "r")) == NULL
) {
599 printf(tr(59, "\"%s\" "), cp
);
601 if (_include_file(fbuf
, cp
, &lc
, &cc
, 0) != 0)
603 printf(tr(60, "%d/%d\n"), lc
, cc
);
606 /* Insert an environment variable into the file */
608 while (whitechar(*cp
))
610 if ((cp
= value(cp
)) == NULL
|| *cp
== '\0')
612 if (putesc(cp
, collf
) < 0)
614 if ((options
& OPT_INTERACTIVE
) &&
615 putesc(cp
, stdout
) < 0)
620 /* Insert the contents of a signature variable */
621 if ((cp
= value(c
== 'a' ? "sign" : "Sign")) != NULL
&&
623 if (putesc(cp
, collf
) < 0)
625 if ((options
& OPT_INTERACTIVE
) &&
626 putesc(cp
, stdout
) < 0)
631 /* Write the message on a file */
633 while (blankchar(*cp
))
635 if (*cp
== '\0' || (cp
= file_expand(cp
)) == NULL
) {
636 fprintf(stderr
, tr(61, "Write what file!?\n"));
640 if (exwrite(cp
, collf
, 1) < 0)
648 * Interpolate the named messages, if we
649 * are in receiving mail mode. Does the
650 * standard list processing garbage.
651 * If ~f is given, we don't shift over.
653 if (forward(linebuf
+ 2, collf
, c
) < 0)
658 * Print out the current state of the
659 * message without altering anything.
661 print_collf(collf
, hp
);
665 * Pipe message through command.
666 * Collect output as new message.
669 mespipe(&linebuf
[2]);
674 * Edit the current message.
675 * 'e' means to use EDITOR
676 * 'v' means to use VISUAL
679 mesedit(c
, value("editheaders") ? hp
: NULL
);
683 * Last the lengthy help string.
684 * (Very ugly, but take care for compiler supported
688 "-------------------- ~ ESCAPES ----------------------------\n"
689 "~~ Quote a single tilde\n"
690 "~@ [file ...] Edit attachment list\n"
691 "~b users Add users to \"blind\" cc list\n"
692 "~c users Add users to cc list\n"
693 "~d Read in dead.letter\n"
694 "~e Edit the message buffer\n"
695 "~f messages Read in messages without indenting lines\n"
696 "~F messages Same as ~f, but keep all header lines\n"
697 "~h Prompt for to list, subject, cc, and \"blind\" cc list\n"));
699 "~r file Read a file into the message buffer\n"
700 "~p Print the message buffer\n"
701 "~q Abort message composition and save text to dead.letter\n"
702 "~m messages Read in messages with each line indented\n"
703 "~M messages Same as ~m, but keep all header lines\n"
704 "~s subject Set subject\n"
705 "~t users Add users to to list\n"
706 "~v Invoke display editor on message\n"
707 "~w file Write message onto file\n"
708 "~x Abort message composition and discard text written so far\n"));
710 "~!command Invoke the shell\n"
711 "~:command Execute a regular command\n"
712 "-----------------------------------------------------------\n"));
719 if ((cp
= value("NAIL_TAIL")) != NULL
) {
720 if (putesc(cp
, collf
) < 0)
722 if ((options
& OPT_INTERACTIVE
) &&
723 putesc(cp
, stdout
) < 0)
733 sigaddset(&nset
, SIGINT
);
734 sigaddset(&nset
, SIGHUP
);
735 sigprocmask(SIG_BLOCK
, &nset
, (sigset_t
*)NULL
);
736 safe_signal(SIGINT
, saveint
);
737 safe_signal(SIGHUP
, savehup
);
738 safe_signal(SIGTSTP
, savetstp
);
739 safe_signal(SIGTTOU
, savettou
);
740 safe_signal(SIGTTIN
, savettin
);
741 sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
745 if (tempMail
!= NULL
) {
757 * Write a file, ex-like if f set.
760 exwrite(char const *name
, FILE *fp
, int f
)
768 printf("\"%s\" ", name
);
771 if ((of
= Fopen(name
, "a")) == NULL
) {
777 while ((c
= getc(fp
)) != EOF
) {
789 printf(catgets(catd
, CATSET
, 65, "%d/%ld\n"), lc
, cc
);
795 makeheader(FILE *fp
, struct header
*hp
)
801 if ((nf
= Ftemp(&tempEdit
, "Re", "w+", 0600, 1)) == NULL
) {
802 perror(tr(66, "temporary mail edit file"));
808 extract_header(fp
, hp
);
809 while ((c
= getc(fp
)) != EOF
) /* XXX bytewise, yuck! */
815 if (check_from_and_sender(hp
->h_from
, hp
->h_sender
))
821 * Edit the message being collected on fp.
822 * On return, make the edit file the new temp file.
825 mesedit(int c
, struct header
*hp
)
827 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
828 char *saved
= value("add-file-recipients");
831 assign("add-file-recipients", "");
832 nf
= run_editor(collf
, (off_t
)-1, c
, 0, hp
, NULL
, SEND_MBOX
, sigint
);
839 fseek(nf
, 0L, SEEK_END
);
845 assign("add-file-recipients", saved
);
846 safe_signal(SIGINT
, sigint
);
850 * Pipe the message through the command.
851 * Old message is on stdin of command;
852 * New message collected from stdout.
853 * Sh -c must return 0 to accept the new message.
859 sighandler_type sigint
= safe_signal(SIGINT
, SIG_IGN
);
863 if ((nf
= Ftemp(&tempEdit
, "Re", "w+", 0600, 1)) == NULL
) {
864 perror(catgets(catd
, CATSET
, 66, "temporary mail edit file"));
871 * stdin = current message.
872 * stdout = new message.
874 if ((shell
= value("SHELL")) == NULL
)
876 if (run_command(shell
,
877 0, fileno(collf
), fileno(nf
), "-c", cmd
, NULL
) < 0) {
881 if (fsize(nf
) == 0) {
882 fprintf(stderr
, catgets(catd
, CATSET
, 67,
883 "No bytes from \"%s\" !?\n"), cmd
);
890 fseek(nf
, 0L, SEEK_END
);
894 safe_signal(SIGINT
, sigint
);
898 * Interpolate the named messages into the current
899 * message, preceding each line with a tab.
900 * Return a count of the number of characters now in
901 * the message, or -1 if an error is encountered writing
902 * the message temporary. The flag argument is 'm' if we
903 * should shift over and 'f' if not.
906 forward(char *ms
, FILE *fp
, int f
)
909 struct ignoretab
*ig
;
911 enum sendaction action
;
914 msgvec
= (int *)salloc((msgCount
+1) * sizeof *msgvec
);
917 if (getmsglist(ms
, msgvec
, 0) < 0)
920 *msgvec
= first(0, MMNORM
);
922 printf(catgets(catd
, CATSET
, 68,
923 "No appropriate messages\n"));
928 if (f
== 'f' || f
== 'F')
930 else if ((tabst
= value("indentprefix")) == NULL
)
932 ig
= upperchar(f
) ? (struct ignoretab
*)NULL
: ignore
;
933 action
= upperchar(f
) ? SEND_QUOTE_ALL
: SEND_QUOTE
;
934 printf(catgets(catd
, CATSET
, 69, "Interpolating:"));
935 for (; *msgvec
!= 0; msgvec
++) {
936 struct message
*mp
= message
+ *msgvec
- 1;
939 printf(" %d", *msgvec
);
940 if (send(mp
, fp
, ig
, tabst
, action
, NULL
) < 0) {
941 perror(catgets(catd
, CATSET
, 70,
942 "temporary mail file"));
951 * Print (continue) when continued after ^Z.
957 sighandler_type old_action
= safe_signal(s
, SIG_DFL
);
962 sigprocmask(SIG_UNBLOCK
, &nset
, (sigset_t
*)NULL
);
964 sigprocmask(SIG_BLOCK
, &nset
, (sigset_t
*)NULL
);
965 safe_signal(s
, old_action
);
969 siglongjmp(colljmp
, 1);
974 * On interrupt, come here to save the partial message in ~/dead.letter.
975 * Then jump out of the collection loop.
982 * the control flow is subtle, because we can be called from ~q.
985 if (value("ignore") != NULL
) {
992 siglongjmp(colljmp
, 1);
995 if (value("save") != NULL
&& s
!= 0)
996 savedeadletter(collf
, 1);
997 /* Aborting message, no need to fflush() .. */
998 siglongjmp(collabort
, 1);
1006 savedeadletter(collf
, 1);
1008 * Let's pretend nobody else wants to clean up,
1009 * a true statement at this time.
1015 savedeadletter(FILE *fp
, int fflush_rewind_first
)
1022 if (fflush_rewind_first
) {
1029 cp
= getdeadletter();
1031 dbuf
= Fopen(cp
, "a");
1037 * There are problems with dup()ing of file-descriptors for child
1038 * processes. As long as those are not fixed in equal spirit to
1039 * (outof(): FIX and recode.., 2012-10-04), and to avoid reviving of
1040 * bugs like (If *record* is set, avoid writing dead content twice..,
1041 * 2012-09-14), we have to somehow accomplish that the FILE* fp
1042 * makes itself comfortable with the *real* offset of the underlaying
1043 * file descriptor. Unfortunately Standard I/O and POSIX don't
1044 * describe a way for that -- fflush();rewind(); won't do it.
1045 * This fseek(END),rewind() pair works around the problem on *BSD.
1047 (void)fseek(fp
, 0, SEEK_END
);
1050 printf("\"%s\" ", cp
);
1051 for (lines
= bytes
= 0; (c
= getc(fp
)) != EOF
; ++bytes
) {
1056 printf("%lu/%lu\n", lines
, bytes
);
1064 putesc(const char *s
, FILE *stream
)
1071 if (putc('\t', stream
) == EOF
)
1078 if (putc('\n', stream
) == EOF
)
1085 if (putc(s
[0], stream
) == EOF
)
1090 if (putc('\n', stream
) == EOF
)