diff options
Diffstat (limited to 'usr.bin/mail/send.c')
-rw-r--r-- | usr.bin/mail/send.c | 556 |
1 files changed, 556 insertions, 0 deletions
diff --git a/usr.bin/mail/send.c b/usr.bin/mail/send.c new file mode 100644 index 0000000..c8b8fea --- /dev/null +++ b/usr.bin/mail/send.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Mail to others. + */ + +/* + * Send message described by the passed pointer to the + * passed output buffer. Return -1 on error. + * Adjust the status: field if need be. + * If doign is given, suppress ignored header fields. + * prefix is a string to prepend to each output line. + */ +int +send(mp, obuf, doign, prefix) + register struct message *mp; + FILE *obuf; + struct ignoretab *doign; + char *prefix; +{ + long count; + register FILE *ibuf; + char line[LINESIZE]; + int ishead, infld, ignoring, dostat, firstline; + register char *cp, *cp2; + register int c; + int length; + int prefixlen; + + /* + * Compute the prefix string, without trailing whitespace + */ + if (prefix != NOSTR) { + 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; + /* + * Process headers first + */ + while (count > 0 && ishead) { + if (fgets(line, LINESIZE, ibuf) == NULL) + break; + count -= length = strlen(line); + if (firstline) { + /* + * First line is the From line, so no headers + * there to worry about + */ + firstline = 0; + ignoring = doign == ignoreall; + } else if (line[0] == '\n') { + /* + * If line is blank, we've reached end of + * headers, so force out status: field + * and note that we are no longer in header + * fields + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + ishead = 0; + ignoring = doign == ignoreall; + } else if (infld && (line[0] == ' ' || line[0] == '\t')) { + /* + * If this line is a continuation (via space or tab) + * of a previous header field, just echo it + * (unless the field should be ignored). + * In other words, nothing to do. + */ + } else { + /* + * Pick up the header field if we have one. + */ + for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) + ; + cp2 = --cp; + while (isspace(*cp++)) + ; + if (cp[-1] != ':') { + /* + * Not a header line, force out status: + * This happens in uucp style mail where + * there are no headers at all. + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + if (doign != ignoreall) + /* add blank line */ + (void) putc('\n', obuf); + ishead = 0; + ignoring = 0; + } else { + /* + * If it is an ignored field and + * we care about such things, skip it. + */ + *cp2 = 0; /* temporarily null terminate */ + if (doign && isign(line, doign)) + ignoring = 1; + else if ((line[0] == 's' || line[0] == 'S') && + strcasecmp(line, "status") == 0) { + /* + * If the field is "status," go compute + * and print the real Status: field + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + ignoring = 1; + } else { + ignoring = 0; + *cp2 = c; /* restore */ + } + infld = 1; + } + } + if (!ignoring) { + /* + * Strip trailing whitespace from prefix + * if line is blank. + */ + if (prefix != NOSTR) + if (length > 1) + fputs(prefix, obuf); + else + (void) fwrite(prefix, sizeof *prefix, + prefixlen, obuf); + (void) fwrite(line, sizeof *line, length, obuf); + if (ferror(obuf)) + return -1; + } + } + /* + * Copy out message body + */ + if (doign == ignoreall) + count--; /* skip final blank line */ + if (prefix != NOSTR) + while (count > 0) { + if (fgets(line, LINESIZE, ibuf) == NULL) { + c = 0; + break; + } + count -= c = strlen(line); + /* + * Strip trailing whitespace from prefix + * if line is blank. + */ + if (c > 1) + fputs(prefix, obuf); + else + (void) fwrite(prefix, sizeof *prefix, + prefixlen, obuf); + (void) fwrite(line, sizeof *line, c, obuf); + if (ferror(obuf)) + return -1; + } + else + while (count > 0) { + c = count < LINESIZE ? count : LINESIZE; + if ((c = fread(line, sizeof *line, c, ibuf)) <= 0) + break; + count -= c; + if (fwrite(line, sizeof *line, c, obuf) != c) + return -1; + } + if (doign == ignoreall && c > 0 && line[c - 1] != '\n') + /* no final blank line */ + if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) + return -1; + return 0; +} + +/* + * Output a reasonable looking status field. + */ +void +statusput(mp, obuf, prefix) + register struct message *mp; + FILE *obuf; + char *prefix; +{ + char statout[3]; + register 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 == NOSTR ? "" : prefix, statout); +} + +/* + * Interface between the argument list and the mail1 routine + * which does all the dirty work. + */ +int +mail(to, cc, bcc, smopts, subject) + struct name *to, *cc, *bcc, *smopts; + char *subject; +{ + struct header head; + + head.h_to = to; + head.h_subject = subject; + head.h_cc = cc; + head.h_bcc = bcc; + head.h_smopts = smopts; + mail1(&head, 0); + return(0); +} + + +/* + * Send mail to a bunch of user names. The interface is through + * the mail routine below. + */ +int +sendmail(str) + char *str; +{ + struct header head; + + head.h_to = extract(str, GTO); + head.h_subject = NOSTR; + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 0); + return(0); +} + +/* + * Mail a message on standard input to the people indicated + * in the passed header. (Internal interface). + */ +void +mail1(hp, printheaders) + struct header *hp; + int printheaders; +{ + char *cp; + int pid; + char **namelist; + struct name *to; + FILE *mtf; + + /* + * Collect user's mail from standard input. + * Get the result as mtf. + */ + if ((mtf = collect(hp, printheaders)) == NULL) + return; + if (value("interactive") != NOSTR) + if (value("askcc") != NOSTR) + grabh(hp, GCC); + else { + printf("EOT\n"); + (void) fflush(stdout); + } + if (fsize(mtf) == 0) + if (hp->h_subject == NOSTR) + printf("No message, no subject; hope that's ok\n"); + else + printf("Null message body; hope that's ok\n"); + /* + * Now, take the user names from the combined + * to and cc lists and do all the alias + * processing. + */ + senderr = 0; + to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); + if (to == NIL) { + printf("No recipients specified\n"); + senderr++; + } + /* + * Look through the recipient list for names with /'s + * in them which we write to as files directly. + */ + 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) { + fprintf(stderr, ". . . message lost, sorry.\n"); + return; + } + namelist = unpack(cat(hp->h_smopts, to)); + if (debug) { + char **t; + + printf("Sendmail arguments:"); + for (t = namelist; *t != NOSTR; t++) + printf(" \"%s\"", *t); + printf("\n"); + goto out; + } + if ((cp = value("record")) != NOSTR) + (void) savemail(expand(cp), mtf); + /* + * Fork, set up the temporary mail file as standard + * input for "mail", and exec with the user list we generated + * far above. + */ + pid = fork(); + if (pid == -1) { + perror("fork"); + savedeadletter(mtf); + goto out; + } + if (pid == 0) { + prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| + sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), + fileno(mtf), -1); + if ((cp = value("sendmail")) != NOSTR) + cp = expand(cp); + else + cp = _PATH_SENDMAIL; + execv(cp, namelist); + perror(cp); + _exit(1); + } + if (value("verbose") != NOSTR) + (void) wait_child(pid); + else + free_child(pid); +out: + (void) Fclose(mtf); +} + +/* + * Fix the header by glopping all of the expanded names from + * the distribution list into the appropriate fields. + */ +void +fixhead(hp, tolist) + struct header *hp; + struct name *tolist; +{ + register struct name *np; + + hp->h_to = NIL; + hp->h_cc = NIL; + hp->h_bcc = NIL; + for (np = tolist; np != NIL; 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)); +} + +/* + * Prepend a header in front of the collected stuff + * and return the new file. + */ +FILE * +infix(hp, fi) + struct header *hp; + FILE *fi; +{ + extern char tempMail[]; + register FILE *nfo, *nfi; + register int c; + + if ((nfo = Fopen(tempMail, "w")) == NULL) { + perror(tempMail); + return(fi); + } + if ((nfi = Fopen(tempMail, "r")) == NULL) { + perror(tempMail); + (void) Fclose(nfo); + return(fi); + } + (void) rm(tempMail); + (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)) { + perror("read"); + rewind(fi); + return(fi); + } + (void) fflush(nfo); + if (ferror(nfo)) { + perror(tempMail); + (void) Fclose(nfo); + (void) Fclose(nfi); + rewind(fi); + return(fi); + } + (void) Fclose(nfo); + (void) Fclose(fi); + rewind(nfi); + return(nfi); +} + +/* + * Dump the to, subject, cc header on the + * passed file buffer. + */ +int +puthead(hp, fo, w) + struct header *hp; + FILE *fo; + int w; +{ + register int gotcha; + + gotcha = 0; + if (hp->h_to != NIL && w & GTO) + fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; + if (hp->h_subject != NOSTR && w & GSUBJECT) + fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; + if (hp->h_cc != NIL && w & GCC) + fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; + if (hp->h_bcc != NIL && w & GBCC) + fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; + if (gotcha && w & GNL) + (void) putc('\n', fo); + return(0); +} + +/* + * Format the given header line to not exceed 72 characters. + */ +void +fmt(str, np, fo, comma) + char *str; + register struct name *np; + FILE *fo; + int comma; +{ + register col, len; + + comma = comma ? 1 : 0; + col = strlen(str); + if (col) + fputs(str, fo); + for (; np != NIL; np = np->n_flink) { + if (np->n_flink == NIL) + comma = 0; + len = strlen(np->n_name); + col++; /* for the space */ + 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); +} + +/* + * Save the outgoing mail on the passed file. + */ + +/*ARGSUSED*/ +int +savemail(name, fi) + char name[]; + register FILE *fi; +{ + register FILE *fo; + char buf[BUFSIZ]; + register i; + time_t now, time(); + char *ctime(); + + if ((fo = Fopen(name, "a")) == NULL) { + perror(name); + return (-1); + } + (void) time(&now); + fprintf(fo, "From %s %s", myname, ctime(&now)); + while ((i = fread(buf, 1, sizeof buf, fi)) > 0) + (void) fwrite(buf, 1, i, fo); + (void) putc('\n', fo); + (void) fflush(fo); + if (ferror(fo)) + perror(name); + (void) Fclose(fo); + rewind(fi); + return (0); +} |