Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

1258 lines
24 KiB
C

#ifndef lint
static char *sccsid = "@(#)collect.c 1.1 92/07/30 SMI"; /* from S5R2 1.3 */
#endif
/*
* mailx -- a modified version of a University of California at Berkeley
* mail program
*
* Collect input from standard input, handling
* ~ escapes.
*/
#include "rcv.h"
#include <ctype.h>
#include <sys/stat.h>
/*
* Read a message from standard output and return a read file to it
* or NULL on error.
*/
/*
* The following hokiness with global variables is so that on
* receipt of an interrupt signal, the partial message can be salted
* away on dead.letter. The output file must be available to flush,
* and the input to read. Several open files could be saved all through
* mailx if stdio allowed simultaneous read/write access.
*/
static void (*savesig)(); /* Previous SIGINT value */
static void (*savehup)(); /* Previous SIGHUP value */
# ifdef VMUNIX
static void (*savecont)(); /* Previous SIGCONT value */
# endif VMUNIX
static FILE *newi; /* File for saving away */
static FILE *newo; /* Output side of same */
static int ignintr; /* Ignore interrupts */
static int hadintr; /* Have seen one SIGINT so far */
static jmp_buf coljmp; /* To get back to work */
extern char tempMail[], tempEdit[];
FILE *
collect(hp)
struct header *hp;
{
FILE *ibuf, *fbuf, *obuf;
int lc, cc, escape, eof;
void collrub(), intack();
# ifdef VMUNIX
void collcont();
# endif
register int c, t;
char *cp, *cp2, **fldp, **curr_hdr;
char linebuf[LINESIZE], field[LINESIZE];
int getsub, inhead;
extern char tempMail[];
extern void collintsig(), collhupsig();
noreset++;
ibuf = obuf = NULL;
if (value("ignore") != NOSTR)
ignintr = 1;
else
ignintr = 0;
hadintr = 0;
inhead = 1;
fldp = curr_hdr = (char **)NULL;
# ifdef VMUNIX
if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
sigset(SIGINT, ignintr ? intack : collrub), sigblock(sigmask(SIGINT));
if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
savecont = sigset(SIGCONT, collcont);
# else VMUNIX
savesig = sigset(SIGINT, SIG_IGN);
savehup = sigset(SIGHUP, SIG_IGN);
# endif VMUNIX
newi = NULL;
newo = NULL;
if ((obuf = fopen(tempMail, "w")) == NULL) {
perror(tempMail);
goto err;
}
newo = obuf;
if ((ibuf = fopen(tempMail, "r")) == NULL) {
perror(tempMail);
newo = NULL;
fclose(obuf);
goto err;
}
newi = ibuf;
remove(tempMail);
/*
* If we are going to prompt for a subject,
* refrain from printing a newline after
* the headers (since some people mind).
*/
t = GTO|GSUBJECT|GCC|GNL;
getsub = 0;
if (hp->h_subject == NOSTR) {
hp->h_subject = sflag;
sflag = NOSTR;
}
if (intty && !tflag && hp->h_subject == NOSTR && value("asksub"))
t &= ~GNL, getsub++;
if (hp->h_seq != 0) {
puthead(hp, stdout, t);
fflush(stdout);
}
escape = ESCAPE;
if ((cp = value("escape")) != NOSTR)
escape = *cp;
eof = 0;
for (;;) {
# ifdef VMUNIX
int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
# endif
setjmp(coljmp);
# ifdef VMUNIX
sigset(SIGCONT, collcont);
sigsetmask(omask);
# else VMUNIX
if (savesig != SIG_IGN)
signal(SIGINT, ignintr ? intack : collintsig);
if (savehup != SIG_IGN)
signal(SIGHUP, collhupsig);
# endif VMUNIX
fflush(stdout);
if (getsub) {
grabh(hp, GSUBJECT);
getsub = 0;
continue;
}
if (readline(stdin, linebuf) <= 0) {
if (intty && value("ignoreeof") != NOSTR) {
if (++eof > 35)
break;
printf("Use \".\" to terminate letter\n",
escape);
continue;
}
break;
}
eof = 0;
hadintr = 0;
if (intty && equal(".", linebuf) &&
(value("dot") != NOSTR || value("ignoreeof") != NOSTR))
break;
/*
* If -t, scan text for headers.
*/
if (tflag) {
if (!inhead)
goto writeit;
if (linebuf[0] == 0) {
inhead = 0;
goto writeit;
}
if (isspace(linebuf[0])) {
if (fldp) {
*fldp = addto(*fldp, linebuf);
continue;
} else if (curr_hdr) {
/*
* Tack on to end of current header,
* which is pointed to by "curr_hdr".
*/
char *new_hdr, *salloc();
if ((new_hdr =
salloc(strlen(*curr_hdr) +
strlen(linebuf) + 2)) == NULL) {
fprintf(stderr,
"Mail: Out of memory in collect\n");
goto err;
}
strcpy(new_hdr, *curr_hdr);
strcat(new_hdr, "\n");
strcat(new_hdr, linebuf);
*curr_hdr = new_hdr;
continue;
}
inhead = 0;
goto writeit;
}
if (!headerp(linebuf)) {
putline(obuf, "");
inhead = 0;
goto writeit;
}
cp = linebuf;
cp2 = field;
fldp = curr_hdr = (char **)NULL;
while (*cp && *cp != ':' && !isspace(*cp))
*cp2++ = *cp++;
*cp2 = 0;
cp = index(linebuf, ':') + 1;
if (icequal(field, "to")) {
hp->h_to = addto(hp->h_to, cp);
fldp = &hp->h_to;
hp->h_seq++;
} else if (icequal(field, "subject")) {
while (any(*cp, " \t"))
cp++;
hp->h_subject = savestr(cp);
fldp = &hp->h_subject;
hp->h_seq++;
} else if (icequal(field, "cc")) {
hp->h_cc = addto(hp->h_cc, cp);
fldp = &hp->h_cc;
hp->h_seq++;
} else if (icequal(field, "bcc")) {
hp->h_bcc = addto(hp->h_bcc, cp);
fldp = &hp->h_bcc;
hp->h_seq++;
} else {
writeit:
if (putline(obuf, linebuf) < 0)
goto err;
}
continue;
}
if (linebuf[0] != escape || rflag != NOSTR) {
if ((t = putline(obuf, linebuf)) < 0)
goto err;
continue;
}
c = linebuf[1];
switch (c) {
default:
/*
* On double escape, just send the single one.
* Otherwise, it's an error.
*/
if (c == escape) {
if (putline(obuf, &linebuf[1]) < 0)
goto err;
else
break;
}
printf("Unknown tilde escape.\n");
break;
case 'a':
case 'A':
/*
* autograph; sign the letter.
*/
if (cp = value(c=='a' ? "sign":"Sign")) {
cpout(cp, obuf);
if (isatty(fileno(stdin)))
cpout(cp, stdout);
}
break;
case 'i':
/*
* insert string
*/
for (cp = &linebuf[2]; any(*cp, " \t"); cp++)
;
if (*cp)
cp = value(cp);
if (cp != NOSTR) {
cpout(cp, obuf);
if (isatty(fileno(stdout)))
cpout(cp, stdout);
}
break;
case '!':
/*
* Shell escape, send the balance of the
* line to sh -c.
*/
shell(&linebuf[2]);
break;
case ':':
case '_':
/*
* Escape to command mode, but be nice!
*/
execute(&linebuf[2], 1);
printf("(continue)\n");
break;
case '.':
/*
* Simulate end of file on input.
*/
goto eofl;
case 'q':
case 'Q':
/*
* Force a quit of sending mail.
* Act like an interrupt happened.
*/
hadintr++;
collrub(SIGINT);
exit(1);
case 'x':
xhalt();
break; /* not reached */
case 'h':
/*
* Grab a bunch of headers.
*/
if (!intty || !outtty) {
printf("~h: no can do!?\n");
break;
}
grabh(hp, GTO|GSUBJECT|GCC|GBCC);
printf("(continue)\n");
break;
case 't':
/*
* Add to the To list.
*/
hp->h_to = addto(hp->h_to, &linebuf[2]);
hp->h_seq++;
break;
case 's':
/*
* Set the Subject list.
*/
cp = &linebuf[2];
while (any(*cp, " \t"))
cp++;
hp->h_subject = savestr(cp);
hp->h_seq++;
break;
case 'c':
/*
* Add to the CC list.
*/
hp->h_cc = addto(hp->h_cc, &linebuf[2]);
hp->h_seq++;
break;
case 'b':
/*
* Add stuff to blind carbon copies list.
*/
hp->h_bcc = addto(hp->h_bcc, &linebuf[2]);
hp->h_seq++;
break;
case 'd':
copy(Getf("DEAD"), &linebuf[2]);
/* fall into . . . */
case '<':
case 'r': {
int ispip;
/*
* Invoke a file:
* Search for the file name,
* then open it and copy the contents to obuf.
*
* if name begins with '!', read from a command
*/
cp = &linebuf[2];
while (any(*cp, " \t"))
cp++;
if (*cp == '\0') {
printf("Interpolate what file?\n");
break;
}
if (*cp=='!') {
/* take input from a command */
ispip = 1;
if ((fbuf = popen(++cp, "r"))==NULL) {
perror("");
break;
}
} else {
ispip = 0;
cp = expand(cp);
if (cp == NOSTR)
break;
if (isdir(cp)) {
printf("%s: directory\n", cp);
break;
}
if ((fbuf = fopen(cp, "r")) == NULL) {
perror(cp);
break;
}
}
printf("\"%s\" ", cp);
fflush(stdout);
lc = 0;
cc = 0;
while (readline(fbuf, linebuf) > 0) {
lc++;
if ((t = putline(obuf, linebuf)) < 0) {
if (ispip)
pclose(fbuf);
else
fclose(fbuf);
goto err;
}
cc += t;
}
if (ispip)
pclose(fbuf);
else
fclose(fbuf);
printf("%d/%d\n", lc, cc);
break;
}
case 'w':
/*
* Write the message on a file.
*/
cp = &linebuf[2];
while (any(*cp, " \t"))
cp++;
if (*cp == '\0') {
fprintf(stderr, "Write what file!?\n");
break;
}
if ((cp = expand(cp)) == NOSTR)
break;
fflush(obuf);
rewind(ibuf);
exwrite(cp, ibuf, 1);
break;
case 'm':
case 'f':
/*
* Interpolate the named messages, if we
* are in receiving mail mode. Does the
* standard list processing garbage.
* If ~f is given, we don't shift over.
*/
if (!rcvmode) {
printf("No messages to send from!?!\n");
break;
}
cp = &linebuf[2];
while (any(*cp, " \t"))
cp++;
if (forward(cp, obuf, c) < 0)
goto err;
printf("(continue)\n");
break;
case '?':
if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
printf("No help just now.\n");
break;
}
t = getc(fbuf);
while (t != -1) {
putchar(t);
t = getc(fbuf);
}
fclose(fbuf);
break;
case 'p': {
/*
* Print out the current state of the
* message without altering anything.
*/
FILE *pbuf;
int nlines;
void (*saveint)();
extern jmp_buf pipestop;
extern void brokpipe();
fflush(obuf);
rewind(ibuf);
saveint = signal(SIGINT, SIG_IGN);
pbuf = stdout;
if (setjmp(pipestop))
goto ret0;
if (intty && outtty && (cp = value("crt")) != NOSTR) {
nlines = atoi(cp) - 7; /* 7 for hdr lines */
while ((t = getc(ibuf)) != EOF) {
if (t == '\n')
if (--nlines <= 0)
break;
}
rewind(ibuf);
if (nlines <= 0) {
pbuf = popen(MORE, "w");
if (pbuf == NULL) {
perror(MORE);
pbuf = stdout;
} else {
pipef = pbuf;
sigset(SIGPIPE, brokpipe);
}
} else
signal(SIGINT, saveint);
} else
signal(SIGINT, saveint);
fprintf(pbuf, "-------\nMessage contains:\n");
puthead(hp, pbuf, GTO|GSUBJECT|GCC|GBCC|GNL);
while ((t = getc(ibuf))!=EOF)
putc(t, pbuf);
ret0:
if (pbuf != stdout) {
pipef = NULL;
pclose(pbuf);
}
sigset(SIGPIPE, SIG_DFL);
signal(SIGINT, saveint);
printf("(continue)\n");
break;
}
case '^':
case '|':
/*
* Pipe message through command.
* Collect output as new message.
*/
obuf = mespipe(ibuf, obuf, &linebuf[2]);
newo = obuf;
ibuf = newi;
newi = ibuf;
printf("(continue)\n");
break;
case 'v':
case 'e':
/*
* Edit the current message.
* 'e' means to use EDITOR
* 'v' means to use VISUAL
* 'E' and 'V' mean edit the whole message, including
* headers.
*/
if ((obuf = mesedit(ibuf, obuf, c, hp)) == NULL)
goto err;
newo = obuf;
ibuf = newi;
printf("(continue)\n");
break;
}
}
eofl:
fclose(obuf);
rewind(ibuf);
if (intty && value("askcc") != NOSTR) {
setjmp(coljmp);
grabh(hp, GCC);
} else if (intty) {
printf("EOT\n");
fflush(stdout);
}
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
# ifdef VMUNIX
sigset(SIGCONT, savecont);
sigsetmask(0);
# endif VMUNIX
noreset = 0;
return(ibuf);
err:
if (ibuf != NULL)
fclose(ibuf);
if (obuf != NULL)
fclose(obuf);
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
# ifdef VMUNIX
sigset(SIGCONT, savecont);
sigsetmask(0);
# endif VMUNIX
noreset = 0;
return(NULL);
}
/*
* Write a file, ex-like if f set.
*/
exwrite(name, ibuf, f)
char name[];
FILE *ibuf;
{
register FILE *of;
register int c;
long cc;
int lc;
struct stat junk;
if (f) {
printf("\"%s\" ", name);
fflush(stdout);
}
if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
if (!f)
fprintf(stderr, "%s: ", name);
fprintf(stderr, "File exists\n", name);
return;
}
if ((of = fopen(name, "w")) == NULL) {
perror("");
return;
}
lc = 0;
cc = 0;
while ((c = getc(ibuf)) != EOF) {
cc++;
if (c == '\n')
lc++;
putc(c, of);
if (ferror(of)) {
perror(name);
fclose(of);
return;
}
}
fclose(of);
printf("%d/%ld\n", lc, cc);
fflush(stdout);
}
/*
* Edit the message being collected on ibuf and obuf.
* Write the message out onto some poorly-named temp file
* and point an editor at it.
*
* On return, make the edit file the new temp file.
*/
FILE *
mesedit(ibuf, obuf, c, hp)
FILE *ibuf, *obuf;
struct header *hp;
{
FILE *fbuf;
register int t;
void (*sig)();
# ifdef VMUNIX
void (*scont)(), foonly();
# endif VMUNIX
struct stat sbuf;
register char *editor;
int edit_header;
char ecmd[BUFSIZ];
sig = sigset(SIGINT, SIG_IGN);
# ifdef VMUNIX
scont = sigset(SIGCONT, foonly);
# endif VMUNIX
if (stat(tempEdit, &sbuf) >= 0) {
printf("%s: file exists\n", tempEdit);
goto out;
}
close(creat(tempEdit, 0600));
if ((fbuf = fopen(tempEdit, "w")) == NULL) {
perror(tempEdit);
goto out;
}
fflush(obuf);
rewind(ibuf);
/*
* Optionally add the headers to the file to be edited.
*/
edit_header = (int)value("editheaders");
if (edit_header)
puthead(hp, fbuf, GTO|GSUBJECT|GCC|GBCC|GNL);
while ((t = getc(ibuf)) != EOF)
putc(t, fbuf);
fflush(fbuf);
if (ferror(fbuf)) {
perror(tempEdit);
remove(tempEdit);
goto fix;
}
fclose(fbuf);
if ((editor = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
editor = c == 'e' ? EDITOR : VISUAL;
sprintf(ecmd, "exec %s %s", editor, tempEdit);
if (system(ecmd) & 0377) {
printf("Fatal error in \"%s\"\n", editor);
remove(tempEdit);
goto out;
}
/*
* Now switch to new file.
*/
if ((fbuf = fopen(tempEdit, "a")) == NULL) {
perror(tempEdit);
remove(tempEdit);
goto out;
}
if ((ibuf = fopen(tempEdit, "r")) == NULL) {
perror(tempEdit);
fclose(fbuf);
remove(tempEdit);
goto out;
}
remove(tempEdit);
/*
* Re-parse the header. we must arrange to leave
* only the text of the article in ibuf/fbuf, so
* parse_header also has to copy those files to new ones,
* without the header.
*/
if (edit_header)
parse_header(&ibuf, &fbuf, hp);
fclose(obuf);
fclose(newi);
obuf = fbuf;
goto out;
fix:
perror(tempEdit);
out:
# ifdef VMUNIX
sigset(SIGCONT, scont);
# endif VMUNIX
sigset(SIGINT, sig);
newi = ibuf;
return(obuf);
}
#ifdef VMUNIX
/*
* Currently, Berkeley virtual VAX/UNIX will not let you change the
* disposition of SIGCONT, except to trap it somewhere new.
* Hence, sigset(SIGCONT, foonly) is used to ignore continue signals.
*/
void
foonly() {}
#endif
/*
* Pipe the message through the command.
* Old message is on stdin of command;
* New message collected from stdout.
* Sh -c must return 0 to accept the new message.
*/
FILE *
mespipe(ibuf, obuf, cmd)
FILE *ibuf, *obuf;
char cmd[];
{
register FILE *ni, *no;
int pid, s;
void (*saveint)();
char *Shell;
newi = ibuf;
if ((no = fopen(tempEdit, "w")) == NULL) {
perror(tempEdit);
return(obuf);
}
if ((ni = fopen(tempEdit, "r")) == NULL) {
perror(tempEdit);
fclose(no);
remove(tempEdit);
return(obuf);
}
remove(tempEdit);
saveint = sigset(SIGINT, SIG_IGN);
fflush(obuf);
rewind(ibuf);
if ((Shell = value("SHELL")) == NULL || *Shell=='\0')
Shell = "/bin/sh";
if ((pid = vfork()) == -1) {
perror("fork");
goto err;
}
if (pid == 0) {
/*
* stdin = current message.
* stdout = new message.
*/
sigchild();
close(0);
dup(fileno(ibuf));
close(1);
dup(fileno(no));
for (s = 4; s < 15; s++)
close(s);
execlp(Shell, Shell, "-c", cmd, (char *)0);
perror(Shell);
_exit(1);
}
while (wait(&s) != pid)
;
if (s != 0 || pid == -1) {
fprintf(stderr, "\"%s\" failed!?\n", cmd);
goto err;
}
if (fsize(ni) == 0) {
fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
goto err;
}
/*
* Take new files.
*/
newi = ni;
fclose(ibuf);
fclose(obuf);
sigset(SIGINT, saveint);
return(no);
err:
fclose(no);
fclose(ni);
sigset(SIGINT, saveint);
return(obuf);
}
static char *indentprefix; /* used instead of tab by tabputs */
/*
* Interpolate the named messages into the current
* message, preceding each line with a tab.
* Return a count of the number of characters now in
* the message, or -1 if an error is encountered writing
* the message temporary. The flag argument is 'm' if we
* should shift over and 'f' if not.
*/
forward(ms, obuf, f)
char ms[];
FILE *obuf;
{
register int *msgvec, *ip;
extern char tempMail[];
int tabputs();
msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
if (msgvec == (int *) NOSTR)
return(0);
if (getmsglist(ms, msgvec, 0) < 0)
return(0);
if (*msgvec == NULL) {
*msgvec = first(0, MMNORM);
if (*msgvec == NULL) {
printf("No appropriate messages\n");
return(0);
}
msgvec[1] = NULL;
}
if (f == 'm')
indentprefix = value("indentprefix");
printf("Interpolating:");
for (ip = msgvec; *ip != NULL; ip++) {
touch(*ip);
printf(" %d", *ip);
if (msend(&message[*ip-1], obuf, (int)value("alwaysignore"),
f == 'm' ? tabputs : fputs) < 0) {
perror(tempMail);
return(-1);
}
}
printf("\n");
return(0);
}
tabputs(line, obuf)
char *line;
FILE *obuf;
{
if (indentprefix)
fputs(indentprefix, obuf);
/* Don't create lines with only a tab on them */
else if (line[0] != '\n')
fputc('\t', obuf);
fputs(line, obuf);
}
# ifdef VMUNIX
/*
* Print (continue) when continued after ^Z.
*/
/*ARGSUSED*/
void
collcont(s)
{
printf("(continue)\n");
fflush(stdout);
}
# endif VMUNIX
/*
* On interrupt, go here to save the partial
* message on ~/dead.letter.
* Then restore signals and execute the normal
* signal routine. We only come here if signals
* were previously set anyway.
*/
# ifndef VMUNIX
void
collintsig()
{
signal(SIGINT, SIG_IGN);
collrub(SIGINT);
}
void
collhupsig()
{
signal(SIGHUP, SIG_IGN);
collrub(SIGHUP);
}
# endif VMUNIX
void
collrub(s)
{
register FILE *dbuf;
register int c;
register char *deadletter = Getf("DEAD");
extern void hangup(), stop();
if (s == SIGINT && hadintr == 0) {
hadintr++;
fflush(stdout);
fprintf(stderr, "\n(Interrupt -- one more to kill letter)\n");
longjmp(coljmp, 1);
}
fclose(newo);
rewind(newi);
if (s == SIGINT && value("save")==NOSTR || fsize(newi) == 0)
goto done;
if ((dbuf = fopen(deadletter, "w")) == NULL)
goto done;
chmod(deadletter, 0600);
while ((c = getc(newi)) != EOF)
putc(c, dbuf);
fclose(dbuf);
done:
fclose(newi);
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
# ifdef VMUNIX
sigset(SIGCONT, savecont);
# endif VMUNIX
if (rcvmode) {
if (s == SIGHUP)
hangup(SIGHUP);
else
stop(s);
}
else
exit(1);
}
/*
* Acknowledge an interrupt signal from the tty by typing an @
*/
/*ARGSUSED*/
void
intack(s)
{
puts("@");
fflush(stdout);
clearerr(stdin);
longjmp(coljmp,1);
}
/*
* Add a string to the end of a header entry field.
*/
char *
addto(hf, news)
char hf[], news[];
{
register char *cp, *cp2, *linebuf;
if (hf == NOSTR)
hf = "";
if (*news == '\0')
return(hf);
linebuf = salloc(strlen(hf) + strlen(news) + 2);
for (cp = hf; any(*cp, " \t"); cp++)
;
for (cp2 = linebuf; *cp;)
*cp2++ = *cp++;
if (cp2 != linebuf)
*cp2++ = ' ';
for (cp = news; any(*cp, " \t"); cp++)
;
while (*cp != '\0')
*cp2++ = *cp++;
*cp2 = '\0';
return(linebuf);
}
/*
* Re-read the header stuff from the newly edited file;
* take pointers to the file open for reading and appending and
* use/replace them with a new temp file with the header read/stripped off
* (since the rest of Mail expects that the temp file contains only the text).
*/
parse_header(pibuf, pfbuf, hp)
FILE **pibuf; /* Ptr to file currently open for reading. */
FILE **pfbuf; /* Return file opened for writing at end */
register struct header *hp;
{
register char *cp, *cp2;
register int c;
int fd;
char **curr_hdr, **fldp, **add_header();
char *osubject, *oto, *occ, *obcc, **oheaders;
int gothdr;
char linebuf[LINESIZE], field[LINESIZE];
char new_tempfile[14];
strcpy(new_tempfile, "/tmp/RnXXXXXX");
if ((fd = mkstemp(new_tempfile)) < 0) {
perror(new_tempfile);
/* Nothing changes. Message has header in it, though. */
return;
}
fclose(*pfbuf);
*pfbuf = fdopen(fd, "a");
/* save the old headers, in case they are accidentally deleted */
osubject = hp->h_subject;
oto = hp->h_to;
occ = hp->h_cc;
obcc = hp->h_bcc;
oheaders = hp->h_headers;
hp->h_subject = hp->h_to = hp->h_cc = hp->h_bcc = NOSTR;
hp->h_headers = (char **)NULL;
gothdr = 0;
fldp = curr_hdr = (char **)NULL;
while (readline(*pibuf, linebuf) > 0) {
if (linebuf[0] == '\0')
break; /* Blank line, end of header. */
/*
* Is it a continuation of the previous header?
*/
if (isspace(linebuf[0])) {
if (debug)
fprintf(stderr, "Continuation: %s\n", linebuf);
if (fldp) {
*fldp = addto(*fldp, linebuf);
} else if (curr_hdr) {
/*
* Tack on to end of current header,
* which is pointed to by "curr_hdr".
*/
char *new_hdr, *salloc();
if ((new_hdr = salloc(strlen(*curr_hdr) +
strlen(linebuf) + 2)) == NULL) {
fprintf(stderr,
"Mail: Out of memory in parse_header\n");
} else {
strcpy(new_hdr, *curr_hdr);
strcat(new_hdr, "\n");
strcat(new_hdr, linebuf);
*curr_hdr = new_hdr;
}
} else {
/*
* Looks like a continuation, but no
* previous header. Assume this is
* part of the text - somehow the
* user deleted the header.
*/
putline(*pfbuf, linebuf);
break;
}
} else if (!headerp(linebuf)) {
/*
* Not a header. Get out of this loop.
*/
putline(*pfbuf, linebuf);
break; /* Non-header text line found */
} else {
/*
* Is a header line. Figure out which one
* it is, and save it in the appropriate spot.
*/
fldp = curr_hdr = (char **)NULL;
gothdr = 1;
cp = linebuf;
cp2 = field;
while (*cp && *cp != ':' && !isspace(*cp))
*cp2++ = *cp++;
*cp2 = 0;
cp = index(linebuf, ':') + 1;
if (icequal(field, "to")) {
hp->h_to = addto(hp->h_to, cp);
fldp = &hp->h_to;
hp->h_seq++;
} else if (icequal(field, "subject")) {
while (any(*cp, " \t"))
cp++;
hp->h_subject = savestr(cp);
fldp = &hp->h_subject;
hp->h_seq++;
} else if (icequal(field, "cc")) {
hp->h_cc = addto(hp->h_cc, cp);
fldp = &hp->h_cc;
hp->h_seq++;
} else if (icequal(field, "bcc")) {
hp->h_bcc = addto(hp->h_bcc, cp);
fldp = &hp->h_bcc;
hp->h_seq++;
} else {
/*
* User supplied header.
* add the line to hp->h_headers
*/
curr_hdr = add_header(hp, linebuf);
}
}
}
while ((c = getc(*pibuf)) != EOF)
putc(c, *pfbuf);
fclose(*pibuf);
if (!gothdr) {
/* if we didn't see any headers, restore the original headers */
hp->h_subject = osubject;
hp->h_to = oto;
hp->h_cc = occ;
hp->h_bcc = obcc;
hp->h_headers = oheaders;
}
/*
* this isn't too robust if it fails
*/
if ((*pibuf = fopen(new_tempfile, "r")) == NULL) {
perror(new_tempfile);
return;
}
remove(new_tempfile);
rewind(*pibuf);
}
/*
* Add a new header line to the h_headers part of the header.
* "line" should be the entire "Header: we want to add".
* We return a pointer to the (stored) header that we just added.
*/
char **
add_header(hp, line)
register struct header *hp;
char *line;
{
register char **p, **np;
register int nheaders = 0;
p = hp->h_headers;
if (p != (char **)NULL)
while (*p++)
nheaders++;
np = (char **)salloc((nheaders + 2) * sizeof(char *));
p = hp->h_headers;
hp->h_headers = np;
while (nheaders--)
*np++ = *p++;
*np = savestr(line);
np[1] = NOSTR;
return(np);
}
cpout(str, ofd)
char *str;
FILE *ofd;
{
register char *cp = str;
while (*cp) {
if (*cp == '\\') {
switch (*(cp+1)) {
case 'n':
putc('\n', ofd);
cp++;
break;
case 't':
putc('\t', ofd);
cp++;
break;
default:
putc('\\', ofd);
}
} else {
putc(*cp, ofd);
}
cp++;
}
putc('\n', ofd);
}
xhalt()
{
fclose(newo);
fclose(newi);
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
if (rcvmode)
stop(0);
exit(1);
}