#include "rcv.h"
#include "extern.h"
static volatile sig_atomic_t sendsignal;
int
sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign,
char *prefix)
{
int count;
FILE *ibuf;
char line[LINESIZE];
char visline[4 * LINESIZE - 3];
int ishead, infld, ignoring = 0, dostat, firstline;
char *cp, *cp2;
int c = 0;
int length;
int prefixlen = 0;
int rval;
int dovis;
struct sigaction act, saveint;
sigset_t oset;
sendsignal = 0;
rval = -1;
dovis = isatty(fileno(obuf));
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
act.sa_handler = sendint;
(void)sigaction(SIGINT, &act, &saveint);
(void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
if (prefix != NULL) {
cp2 = 0;
for (cp = prefix; *cp; cp++)
if (*cp != ' ' && *cp != '\t')
cp2 = cp;
prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1;
}
ibuf = setinput(mp);
count = mp->m_size;
ishead = 1;
dostat = doign == 0 || !isign("status", doign);
infld = 0;
firstline = 1;
while (count > 0 && ishead) {
if (fgets(line, sizeof(line), ibuf) == NULL)
break;
count -= length = strlen(line);
if (firstline) {
firstline = 0;
ignoring = doign == ignoreall;
} else if (line[0] == '\n') {
if (dostat) {
if (statusput(mp, obuf, prefix) == -1)
goto out;
dostat = 0;
}
ishead = 0;
ignoring = doign == ignoreall;
} else if (infld && (line[0] == ' ' || line[0] == '\t')) {
} else {
for (cp = line;
(c = (unsigned char)*cp++) && c != ':' && !isspace(c); )
;
cp2 = --cp;
while (isspace((unsigned char)*cp++))
;
if (cp[-1] != ':') {
if (dostat) {
if (statusput(mp, obuf, prefix) == -1)
goto out;
dostat = 0;
}
if (doign != ignoreall)
(void)putc('\n', obuf);
ishead = 0;
ignoring = 0;
} else {
*cp2 = 0;
if (doign && isign(line, doign))
ignoring = 1;
else if (strcasecmp(line, "status") == 0) {
if (dostat) {
if (statusput(mp, obuf, prefix) == -1)
goto out;
dostat = 0;
}
ignoring = 1;
} else {
ignoring = 0;
*cp2 = c;
}
infld = 1;
}
}
if (!ignoring) {
if (prefix != NULL) {
if (length > 1)
fputs(prefix, obuf);
else
(void)fwrite(prefix, sizeof(*prefix),
prefixlen, obuf);
}
if (dovis) {
length = strvis(visline, line, VIS_SAFE|VIS_NOSLASH);
(void)fwrite(visline, sizeof(*visline), length, obuf);
} else
(void)fwrite(line, sizeof(*line), length, obuf);
if (ferror(obuf))
goto out;
}
if (sendsignal == SIGINT)
goto out;
}
if (doign == ignoreall)
count--;
while (count > 0) {
if (fgets(line, sizeof(line), ibuf) == NULL) {
c = 0;
break;
}
count -= c = strlen(line);
if (prefix != NULL) {
if (c > 1)
fputs(prefix, obuf);
else
(void)fwrite(prefix, sizeof(*prefix),
prefixlen, obuf);
}
if (strncmp(line, "From ", 5) == 0)
(void)fwrite(">", 1, 1, obuf);
if (dovis) {
length = strvis(visline, line, VIS_SAFE|VIS_NOSLASH);
(void)fwrite(visline, sizeof(*visline), length, obuf);
} else
(void)fwrite(line, sizeof(*line), c, obuf);
if (ferror(obuf) || sendsignal == SIGINT)
goto out;
}
if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
goto out;
rval = 0;
out:
sendsignal = 0;
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
(void)sigaction(SIGINT, &saveint, NULL);
return(rval);
}
int
statusput(struct message *mp, FILE *obuf, char *prefix)
{
char statout[3];
char *cp = statout;
if (mp->m_flag & MREAD)
*cp++ = 'R';
if ((mp->m_flag & MNEW) == 0)
*cp++ = 'O';
*cp = 0;
if (statout[0]) {
fprintf(obuf, "%sStatus: %s\n",
prefix == NULL ? "" : prefix, statout);
return(ferror(obuf) ? -1 : 0);
}
return(0);
}
int
mail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts,
char *fromaddr, char *subject)
{
struct header head;
head.h_to = to;
head.h_from = fromaddr;
head.h_subject = subject;
head.h_cc = cc;
head.h_bcc = bcc;
head.h_smopts = smopts;
mail1(&head, 0);
return(0);
}
int
sendmail(void *v)
{
char *str = v;
struct header head;
head.h_to = extract(str, GTO);
head.h_from = NULL;
head.h_subject = NULL;
head.h_cc = NULL;
head.h_bcc = NULL;
head.h_smopts = NULL;
mail1(&head, 0);
return(0);
}
void
mail1(struct header *hp, int printheaders)
{
char *cp, *envfrom = NULL;
char *argv[8];
char **ap = argv;
pid_t pid;
struct name *to;
FILE *mtf;
if ((mtf = collect(hp, printheaders)) == NULL)
return;
if (fsize(mtf) == 0) {
if (value("skipempty") != NULL)
goto out;
if (hp->h_subject == NULL || *hp->h_subject == '\0')
puts("No message, no subject; hope that's ok");
else
puts("Null message body; hope that's ok");
}
senderr = 0;
to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
if (to == NULL) {
puts("No recipients specified");
senderr++;
}
to = outof(to, mtf, hp);
if (senderr)
savedeadletter(mtf);
to = elide(to);
if (count(to) == 0)
goto out;
fixhead(hp, to);
if ((mtf = infix(hp, mtf)) == NULL) {
fputs(". . . message lost, sorry.\n", stderr);
return;
}
if ((cp = value("record")) != NULL)
(void)savemail(expand(cp), mtf);
*ap++ = "sendmail";
*ap++ = "-i";
*ap++ = "-t";
cp = hp->h_from ? hp->h_from : value("from");
if (cp != NULL) {
envfrom = skin(cp);
*ap++ = "-f";
*ap++ = envfrom;
if (envfrom == cp)
envfrom = NULL;
}
if (value("metoo") != NULL)
*ap++ = "-m";
if (value("verbose") != NULL)
*ap++ = "-v";
*ap = NULL;
if (debug) {
fputs("Sendmail arguments:", stdout);
for (ap = argv; *ap != NULL; ap++)
printf(" \"%s\"", *ap);
putchar('\n');
goto out;
}
pid = fork();
if (pid == -1) {
warn("fork");
savedeadletter(mtf);
goto out;
}
if (pid == 0) {
sigset_t nset;
sigemptyset(&nset);
sigaddset(&nset, SIGHUP);
sigaddset(&nset, SIGINT);
sigaddset(&nset, SIGQUIT);
sigaddset(&nset, SIGTSTP);
sigaddset(&nset, SIGTTIN);
sigaddset(&nset, SIGTTOU);
prepare_child(&nset, fileno(mtf), -1);
if ((cp = value("sendmail")) != NULL)
cp = expand(cp);
else
cp = _PATH_SENDMAIL;
execv(cp, argv);
warn("%s", cp);
_exit(1);
}
free(envfrom);
if (value("verbose") != NULL)
(void)wait_child(pid);
else
free_child(pid);
out:
(void)Fclose(mtf);
}
void
fixhead(struct header *hp, struct name *tolist)
{
struct name *np;
hp->h_to = NULL;
hp->h_cc = NULL;
hp->h_bcc = NULL;
for (np = tolist; np != NULL; np = np->n_flink)
if ((np->n_type & GMASK) == GTO)
hp->h_to =
cat(hp->h_to, nalloc(np->n_name, np->n_type));
else if ((np->n_type & GMASK) == GCC)
hp->h_cc =
cat(hp->h_cc, nalloc(np->n_name, np->n_type));
else if ((np->n_type & GMASK) == GBCC)
hp->h_bcc =
cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
}
FILE *
infix(struct header *hp, FILE *fi)
{
FILE *nfo, *nfi;
int c, fd;
char tempname[PATHSIZE];
(void)snprintf(tempname, sizeof(tempname),
"%s/mail.RsXXXXXXXXXX", tmpdir);
if ((fd = mkstemp(tempname)) == -1 ||
(nfo = Fdopen(fd, "w")) == NULL) {
warn("%s", tempname);
return(fi);
}
if ((nfi = Fopen(tempname, "r")) == NULL) {
warn("%s", tempname);
(void)Fclose(nfo);
(void)rm(tempname);
return(fi);
}
(void)rm(tempname);
(void)puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
c = getc(fi);
while (c != EOF) {
(void)putc(c, nfo);
c = getc(fi);
}
if (ferror(fi)) {
warn("read");
rewind(fi);
return(fi);
}
(void)fflush(nfo);
if (ferror(nfo)) {
warn("%s", tempname);
(void)Fclose(nfo);
(void)Fclose(nfi);
rewind(fi);
return(fi);
}
(void)Fclose(nfo);
(void)Fclose(fi);
rewind(nfi);
return(nfi);
}
int
puthead(struct header *hp, FILE *fo, int w)
{
int gotcha;
char *from;
gotcha = 0;
from = hp->h_from ? hp->h_from : value("from");
if (from != NULL)
fprintf(fo, "From: %s\n", from), gotcha++;
if (hp->h_to != NULL && w & GTO)
fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
if (hp->h_subject != NULL && w & GSUBJECT)
fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
if (hp->h_cc != NULL && w & GCC)
fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
if (hp->h_bcc != NULL && w & GBCC)
fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
if (gotcha && w & GNL)
(void)putc('\n', fo);
return(0);
}
void
fmt(char *str, struct name *np, FILE *fo, int comma)
{
int col, len;
comma = comma ? 1 : 0;
col = strlen(str);
if (col)
fputs(str, fo);
for (; np != NULL; np = np->n_flink) {
if (np->n_flink == NULL)
comma = 0;
len = strlen(np->n_name);
col++;
if (col + len + comma > 72 && col > 4) {
fputs("\n ", fo);
col = 4;
} else
putc(' ', fo);
fputs(np->n_name, fo);
if (comma)
putc(',', fo);
col += len + comma;
}
putc('\n', fo);
}
int
savemail(char *name, FILE *fi)
{
FILE *fo;
char buf[BUFSIZ];
time_t now;
mode_t m;
m = umask(077);
fo = Fopen(name, "a");
(void)umask(m);
if (fo == NULL) {
warn("%s", name);
return(-1);
}
(void)time(&now);
fprintf(fo, "From %s %s", myname, ctime(&now));
while (fgets(buf, sizeof(buf), fi) == buf) {
if (strncmp(buf, "From ", 5) == 0)
(void)fwrite(">", 1, 1, fo);
(void)fwrite(buf, 1, strlen(buf), fo);
}
(void)putc('\n', fo);
(void)fflush(fo);
if (ferror(fo))
warn("%s", name);
(void)Fclose(fo);
rewind(fi);
return(0);
}
void
sendint(int s)
{
sendsignal = s;
}