version 1.21.2.1, 2002/04/13 19:09:48 |
version 1.22, 2001/11/20 20:50:00 |
|
|
* away on dead.letter. |
* away on dead.letter. |
*/ |
*/ |
|
|
static sig_t saveint; /* Previous SIGINT value */ |
|
static sig_t savehup; /* Previous SIGHUP value */ |
|
static sig_t savetstp; /* Previous SIGTSTP value */ |
|
static sig_t savettou; /* Previous SIGTTOU value */ |
|
static sig_t savettin; /* Previous SIGTTIN value */ |
|
static FILE *collf; /* File for saving away */ |
static FILE *collf; /* File for saving away */ |
static int hadintr; /* Have seen one SIGINT so far */ |
static int hadintr; /* Have seen one SIGINT so far */ |
|
|
static sigjmp_buf colljmp; /* To get back to work */ |
|
static int colljmp_p; /* whether to long jump */ |
|
static sigjmp_buf collabort; /* To end collection with error */ |
|
|
|
FILE * |
FILE * |
collect(hp, printheaders) |
collect(hp, printheaders) |
struct header *hp; |
struct header *hp; |
int printheaders; |
int printheaders; |
{ |
{ |
FILE *fbuf; |
FILE *fbuf; |
int lc, cc, fd, c, t, lastlong, rc; |
int lc, cc, fd, c, t, lastlong, rc, sig; |
volatile int escape, eofcount, longline; |
int escape, eofcount, longline; |
volatile char getsub; |
char getsub; |
char linebuf[LINESIZE], tempname[PATHSIZE], *cp; |
char linebuf[LINESIZE], tempname[PATHSIZE], *cp; |
sigset_t oset, nset; |
|
|
|
collf = NULL; |
collf = NULL; |
/* |
eofcount = 0; |
* Start catching signals from here, but we're still die on interrupts |
hadintr = 0; |
* until we're in the main loop. |
lastlong = 0; |
*/ |
longline = 0; |
sigemptyset(&nset); |
if ((cp = value("escape")) != NULL) |
sigaddset(&nset, SIGINT); |
escape = *cp; |
sigaddset(&nset, SIGHUP); |
else |
sigprocmask(SIG_BLOCK, &nset, &oset); |
escape = ESCAPE; |
if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) |
|
(void)signal(SIGINT, collint); |
|
if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) |
|
(void)signal(SIGHUP, collhup); |
|
savetstp = signal(SIGTSTP, collstop); |
|
savettou = signal(SIGTTOU, collstop); |
|
savettin = signal(SIGTTIN, collstop); |
|
if (sigsetjmp(collabort, 1) || sigsetjmp(colljmp, 1)) { |
|
(void)rm(tempname); |
|
goto err; |
|
} |
|
sigdelset(&oset, SIGINT); |
|
sigdelset(&oset, SIGHUP); |
|
sigprocmask(SIG_SETMASK, &oset, NULL); |
|
|
|
noreset++; |
noreset++; |
|
|
(void)snprintf(tempname, sizeof(tempname), |
(void)snprintf(tempname, sizeof(tempname), |
"%s/mail.RsXXXXXXXXXX", tmpdir); |
"%s/mail.RsXXXXXXXXXX", tmpdir); |
if ((fd = mkstemp(tempname)) == -1 || |
if ((fd = mkstemp(tempname)) == -1 || |
|
|
puthead(hp, stdout, t); |
puthead(hp, stdout, t); |
fflush(stdout); |
fflush(stdout); |
} |
} |
if ((cp = value("escape")) != NULL) |
if (getsub && gethfromtty(hp, GSUBJECT) == -1) |
escape = *cp; |
goto err; |
else |
|
escape = ESCAPE; |
|
eofcount = 0; |
|
hadintr = 0; |
|
lastlong = 0; |
|
longline = 0; |
|
|
|
if (!sigsetjmp(colljmp, 1)) { |
if (0) { |
if (getsub) |
|
gethfromtty(hp, GSUBJECT); |
|
} else { |
|
/* |
|
* Come here for printing the after-signal message. |
|
* Duplicate messages won't be printed because |
|
* the write is aborted if we get a SIGTTOU. |
|
*/ |
|
cont: |
cont: |
if (hadintr) { |
/* Come here for printing the after-suspend message. */ |
|
if (isatty(0)) { |
|
puts("(continue)"); |
fflush(stdout); |
fflush(stdout); |
fputs("\n(Interrupt -- one more to kill letter)\n", |
|
stderr); |
|
} else { |
|
if (isatty(0)) { |
|
puts("(continue)"); |
|
fflush(stdout); |
|
} |
|
} |
} |
} |
} |
for (;;) { |
for (;;) { |
colljmp_p = 1; |
c = readline(stdin, linebuf, LINESIZE, &sig); |
c = readline(stdin, linebuf, LINESIZE); |
|
colljmp_p = 0; |
/* Act on any signal caught during readline() ignoring 'c' */ |
|
switch (sig) { |
|
case 0: |
|
break; |
|
case SIGINT: |
|
if (collabort()) |
|
goto err; |
|
continue; |
|
case SIGHUP: |
|
rewind(collf); |
|
savedeadletter(collf); |
|
/* |
|
* Let's pretend nobody else wants to clean up, |
|
* a true statement at this time. |
|
*/ |
|
exit(1); |
|
default: |
|
/* Stopped due to job control */ |
|
(void)kill(0, sig); |
|
goto cont; |
|
} |
|
|
|
/* No signal, check for error */ |
if (c < 0) { |
if (c < 0) { |
if (value("interactive") != NULL && |
if (value("interactive") != NULL && |
value("ignoreeof") != NULL && ++eofcount < 25) { |
value("ignoreeof") != NULL && ++eofcount < 25) { |
|
|
value("interactive") != NULL && !lastlong && |
value("interactive") != NULL && !lastlong && |
(value("dot") != NULL || value("ignoreeof") != NULL)) |
(value("dot") != NULL || value("ignoreeof") != NULL)) |
break; |
break; |
if (linebuf[0] != escape || value("interactive") == NULL || |
if (linebuf[0] != escape || lastlong) { |
lastlong) { |
|
if (putline(collf, linebuf, !longline) < 0) |
if (putline(collf, linebuf, !longline) < 0) |
goto err; |
goto err; |
continue; |
continue; |
|
|
* Act like an interrupt happened. |
* Act like an interrupt happened. |
*/ |
*/ |
hadintr++; |
hadintr++; |
collint(SIGINT); |
collabort(); |
exit(1); |
fputs("Interrupt\n", stderr); |
|
goto err; |
case 'h': |
case 'h': |
/* |
/* |
* Grab a bunch of headers. |
* Grab a bunch of headers. |
|
|
fflush(stdout); |
fflush(stdout); |
lc = 0; |
lc = 0; |
cc = 0; |
cc = 0; |
while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) { |
while ((rc = readline(fbuf, linebuf, LINESIZE, NULL)) >= 0) { |
if (rc != LINESIZE - 1) |
if (rc != LINESIZE - 1) |
lc++; |
lc++; |
if ((t = putline(collf, linebuf, |
if ((t = putline(collf, linebuf, |
|
|
|
|
if (value("interactive") != NULL) { |
if (value("interactive") != NULL) { |
if (value("askcc") != NULL || value("askbcc") != NULL) { |
if (value("askcc") != NULL || value("askbcc") != NULL) { |
if (value("askcc") != NULL) |
if (value("askcc") != NULL) { |
gethfromtty(hp, GCC); |
if (gethfromtty(hp, GCC) == -1) |
if (value("askbcc") != NULL) |
goto err; |
gethfromtty(hp, GBCC); |
} |
|
if (value("askbcc") != NULL) { |
|
if (gethfromtty(hp, GBCC) == -1) |
|
goto err; |
|
} |
} else { |
} else { |
puts("EOT"); |
puts("EOT"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
if (collf != NULL) |
if (collf != NULL) |
rewind(collf); |
rewind(collf); |
noreset--; |
noreset--; |
(void)sigemptyset(&nset); |
|
(void)sigaddset(&nset, SIGINT); |
|
(void)sigaddset(&nset, SIGHUP); |
|
(void)sigprocmask(SIG_BLOCK, &nset, &oset); |
|
(void)signal(SIGINT, saveint); |
|
(void)signal(SIGHUP, savehup); |
|
(void)signal(SIGTSTP, savetstp); |
|
(void)signal(SIGTTOU, savettou); |
|
(void)signal(SIGTTIN, savettin); |
|
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
|
return(collf); |
return(collf); |
} |
} |
|
|
|
|
FILE *fp; |
FILE *fp; |
int c; |
int c; |
{ |
{ |
sig_t sigint = signal(SIGINT, SIG_IGN); |
FILE *nf; |
FILE *nf = run_editor(fp, (off_t)-1, c, 0); |
struct sigaction oact; |
|
sigset_t oset; |
|
|
|
(void)ignoresig(SIGINT, &oact, &oset); |
|
nf = run_editor(fp, (off_t)-1, c, 0); |
if (nf != NULL) { |
if (nf != NULL) { |
fseek(nf, 0L, 2); |
fseek(nf, 0L, 2); |
collf = nf; |
collf = nf; |
(void)Fclose(fp); |
(void)Fclose(fp); |
} |
} |
(void)signal(SIGINT, sigint); |
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
|
(void)sigaction(SIGINT, &oact, NULL); |
} |
} |
|
|
/* |
/* |
|
|
{ |
{ |
FILE *nf; |
FILE *nf; |
int fd; |
int fd; |
sig_t sigint = signal(SIGINT, SIG_IGN); |
|
char *shell, tempname[PATHSIZE]; |
char *shell, tempname[PATHSIZE]; |
|
struct sigaction oact; |
|
sigset_t oset; |
|
|
|
(void)ignoresig(SIGINT, &oact, &oset); |
(void)snprintf(tempname, sizeof(tempname), |
(void)snprintf(tempname, sizeof(tempname), |
"%s/mail.ReXXXXXXXXXX", tmpdir); |
"%s/mail.ReXXXXXXXXXX", tmpdir); |
if ((fd = mkstemp(tempname)) == -1 || |
if ((fd = mkstemp(tempname)) == -1 || |
|
|
collf = nf; |
collf = nf; |
(void)Fclose(fp); |
(void)Fclose(fp); |
out: |
out: |
(void)signal(SIGINT, sigint); |
(void)sigprocmask(SIG_SETMASK, &oset, NULL); |
|
(void)sigaction(SIGINT, &oact, NULL); |
} |
} |
|
|
/* |
/* |
|
|
} |
} |
|
|
/* |
/* |
* Print (continue) when continued after ^Z. |
* User aborted during message composition. |
|
* Save the partial message in ~/dead.letter. |
*/ |
*/ |
/*ARGSUSED*/ |
int |
void |
collabort() |
collstop(s) |
|
int s; |
|
{ |
{ |
sig_t old_action = signal(s, SIG_DFL); |
|
sigset_t nset; |
|
|
|
(void)sigemptyset(&nset); |
|
(void)sigaddset(&nset, s); |
|
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL); |
|
(void)kill(0, s); |
|
(void)sigprocmask(SIG_BLOCK, &nset, NULL); |
|
(void)signal(s, old_action); |
|
if (colljmp_p) { |
|
colljmp_p = 0; |
|
hadintr = 0; |
|
siglongjmp(colljmp, 1); |
|
} |
|
} |
|
|
|
/* |
|
* On interrupt, come here to save the partial message in ~/dead.letter. |
|
* Then jump out of the collection loop. |
|
*/ |
|
/*ARGSUSED*/ |
|
void |
|
collint(s) |
|
int s; |
|
{ |
|
/* |
/* |
* the control flow is subtle, because we can be called from ~q. |
* the control flow is subtle, because we can be called from ~q. |
*/ |
*/ |
|
|
puts("@"); |
puts("@"); |
fflush(stdout); |
fflush(stdout); |
clearerr(stdin); |
clearerr(stdin); |
return; |
} else { |
|
fflush(stdout); |
|
fputs("\n(Interrupt -- one more to kill letter)\n", |
|
stderr); |
|
hadintr++; |
} |
} |
hadintr = 1; |
return(0); |
siglongjmp(colljmp, 1); |
|
} |
} |
|
fflush(stdout); |
rewind(collf); |
rewind(collf); |
if (value("nosave") == NULL) |
if (value("nosave") == NULL) |
savedeadletter(collf); |
savedeadletter(collf); |
siglongjmp(collabort, 1); |
return(1); |
} |
} |
|
|
/*ARGSUSED*/ |
|
void |
void |
collhup(s) |
|
int s; |
|
{ |
|
rewind(collf); |
|
savedeadletter(collf); |
|
/* |
|
* Let's pretend nobody else wants to clean up, |
|
* a true statement at this time. |
|
*/ |
|
exit(1); |
|
} |
|
|
|
void |
|
savedeadletter(fp) |
savedeadletter(fp) |
FILE *fp; |
FILE *fp; |
{ |
{ |
|
|
rewind(fp); |
rewind(fp); |
} |
} |
|
|
void |
int |
gethfromtty(hp, gflags) |
gethfromtty(hp, gflags) |
struct header *hp; |
struct header *hp; |
int gflags; |
int gflags; |
{ |
{ |
if (grabh(hp, gflags) == SIGINT) { |
|
fflush(stdout); |
hadintr = 0; |
fputs("\n(Interrupt -- one more to kill letter)\n", |
while (grabh(hp, gflags) != 0) { |
stderr); |
if (collabort()) |
if (grabh(hp, gflags) == SIGINT) { |
return(-1); |
hadintr++; |
|
collint(SIGINT); |
|
exit(1); |
|
} |
|
} |
} |
|
return(0); |
} |
} |