386BSD 0.1 development
[unix-history] / usr / src / usr.bin / mail / send.c
index 1864888..06588b5 100644 (file)
@@ -1,10 +1,41 @@
-#
+/*
+ * Copyright (c) 1980 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     5.23 (Berkeley) 2/9/91";
+#endif /* not lint */
 
 #include "rcv.h"
 
 #include "rcv.h"
-#ifdef VMUNIX
-#include <wait.h>
-#endif
-#include <ctype.h>
 
 /*
  * Mail -- a mail program
 
 /*
  * Mail -- a mail program
  * Mail to others.
  */
 
  * Mail to others.
  */
 
-static char *SccsId = "@(#)send.c      2.7 %G%";
-
 /*
  * Send message described by the passed pointer to the
 /*
  * Send message described by the passed pointer to the
- * passed output buffer.  Return -1 on error, but normally
- * the number of lines written.  Adjust the status: field
- * if need be.  If doign is set, suppress ignored header fields.
+ * 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.
  */
  */
-send(mailp, obuf, doign)
-       struct message *mailp;
+send(mp, obuf, doign, prefix)
+       register struct message *mp;
        FILE *obuf;
        FILE *obuf;
+       struct ignoretab *doign;
+       char *prefix;
 {
 {
-       register struct message *mp;
-       register int t;
-       long c;
-       FILE *ibuf;
-       char line[LINESIZE], field[BUFSIZ];
-       int lc, ishead, infld, fline, dostat;
-       char *cp, *cp2;
+       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;
 
 
-       mp = mailp;
+       /*
+        * 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);
        ibuf = setinput(mp);
-       c = mp->m_size;
+       count = mp->m_size;
        ishead = 1;
        ishead = 1;
-       dostat = 1;
+       dostat = doign == 0 || !isign("status", doign);
        infld = 0;
        infld = 0;
-       fline = 1;
-       lc = 0;
-       while (c > 0L) {
-               fgets(line, LINESIZE, ibuf);
-               c -= (long) strlen(line);
-               lc++;
-               if (ishead) {
+       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
                         */
                        /* 
                         * First line is the From line, so no headers
                         * there to worry about
                         */
-                       if (fline) {
-                               fline = 0;
-                               goto writeit;
-                       }
+                       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 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 (line[0] == '\n') {
-                               if (dostat) {
-                                       statusput(mailp, obuf, doign);
-                                       dostat = 0;
-                               }
-                               ishead = 0;
-                               goto writeit;
+                       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).
                        /*
                         * 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.
                         */
                         */
-                       if (infld && (isspace(line[0]) || line[0] == '\t')) {
-                               if (doign && isign(field)) continue;
-                               goto writeit;
-                       }
-                       infld = 0;
+               } else {
                        /*
                        /*
-                        * If we are no longer looking at real
-                        * header lines, force out status:
-                        * This happens in uucp style mail where
-                        * there are no headers at all.
+                        * Pick up the header field if we have one.
                         */
                         */
-                       if (!headerp(line)) {
+                       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) {
                                if (dostat) {
-                                       statusput(mailp, obuf, doign);
+                                       statusput(mp, obuf, prefix);
                                        dostat = 0;
                                }
                                        dostat = 0;
                                }
-                               putc('\n', obuf);
+                               if (doign != ignoreall)
+                                       /* add blank line */
+                                       (void) putc('\n', obuf);
                                ishead = 0;
                                ishead = 0;
-                               goto writeit;
+                               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;
                        }
                        }
-                       infld++;
+               }
+               if (!ignoring) {
                        /*
                        /*
-                        * Pick up the header field.
-                        * If it is an ignored field and
-                        * we care about such things, skip it.
+                        * Strip trailing whitespace from prefix
+                        * if line is blank.
                         */
                         */
-                       cp = line;
-                       cp2 = field;
-                       while (*cp && *cp != ':' && !isspace(*cp))
-                               *cp2++ = *cp++;
-                       *cp2 = 0;
-                       if (doign && isign(field))
-                               continue;
+                       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);
                        /*
                        /*
-                        * If the field is "status," go compute and print the
-                        * real Status: field
+                        * Strip trailing whitespace from prefix
+                        * if line is blank.
                         */
                         */
-                       if (icequal(field, "status")) {
-                               if (dostat) {
-                                       statusput(mailp, obuf, doign);
-                                       dostat = 0;
-                               }
-                               continue;
-                       }
+                       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;
                }
                }
-writeit:
-               fputs(line, obuf);
-               if (ferror(obuf))
-                       return(-1);
-       }
-       if (ferror(obuf))
-               return(-1);
-       if (ishead && (mailp->m_flag & MSTATUS))
-               printf("failed to fix up status field\n");
-       return(lc);
-}
-
-/*
- * Test if the passed line is a header line, RFC 733 style.
- */
-headerp(line)
-       register char *line;
-{
-       register char *cp = line;
-
-       while (*cp && !isspace(*cp) && *cp != ':')
-               cp++;
-       while (*cp && isspace(*cp))
-               cp++;
-       return(*cp == ':');
+       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.
 }
 
 /*
  * Output a reasonable looking status field.
- * But if "status" is ignored and doign, forget it.
  */
  */
-statusput(mp, obuf, doign)
+statusput(mp, obuf, prefix)
        register struct message *mp;
        register struct message *mp;
-       register FILE *obuf;
+       FILE *obuf;
+       char *prefix;
 {
        char statout[3];
 {
        char statout[3];
+       register char *cp = statout;
 
 
-       if (doign && isign("status"))
-               return;
-       if ((mp->m_flag & (MNEW|MREAD)) == MNEW)
-               return;
        if (mp->m_flag & MREAD)
        if (mp->m_flag & MREAD)
-               strcpy(statout, "R");
-       else
-               strcpy(statout, "");
+               *cp++ = 'R';
        if ((mp->m_flag & MNEW) == 0)
        if ((mp->m_flag & MNEW) == 0)
-               strcat(statout, "O");
-       fprintf(obuf, "Status: %s\n", statout);
+               *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.
  */
 /*
  * Interface between the argument list and the mail1 routine
  * which does all the dirty work.
  */
-
-mail(people)
-       char **people;
+mail(to, cc, bcc, smopts, subject)
+       struct name *to, *cc, *bcc, *smopts;
+       char *subject;
 {
 {
-       register char *cp2;
-       register int s;
-       char *buf, **ap;
        struct header head;
 
        struct header head;
 
-       for (s = 0, ap = people; *ap != (char *) -1; ap++)
-               s += strlen(*ap) + 1;
-       buf = salloc(s+1);
-       cp2 = buf;
-       for (ap = people; *ap != (char *) -1; ap++) {
-               cp2 = copy(*ap, cp2);
-               *cp2++ = ' ';
-       }
-       if (cp2 != buf)
-               cp2--;
-       *cp2 = '\0';
-       head.h_to = buf;
-       head.h_subject = NOSTR;
-       head.h_cc = NOSTR;
-       head.h_bcc = NOSTR;
-       head.h_seq = 0;
-       mail1(&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);
 }
 
        return(0);
 }
 
@@ -206,24 +267,17 @@ mail(people)
  * Send mail to a bunch of user names.  The interface is through
  * the mail routine below.
  */
  * Send mail to a bunch of user names.  The interface is through
  * the mail routine below.
  */
-
 sendmail(str)
        char *str;
 {
 sendmail(str)
        char *str;
 {
-       register char **ap;
-       char *bufp;
-       register int t;
        struct header head;
 
        struct header head;
 
-       if (blankline(str))
-               head.h_to = NOSTR;
-       else
-               head.h_to = str;
+       head.h_to = extract(str, GTO);
        head.h_subject = NOSTR;
        head.h_subject = NOSTR;
-       head.h_cc = NOSTR;
-       head.h_bcc = NOSTR;
-       head.h_seq = 0;
-       mail1(&head);
+       head.h_cc = NIL;
+       head.h_bcc = NIL;
+       head.h_smopts = NIL;
+       mail1(&head, 0);
        return(0);
 }
 
        return(0);
 }
 
@@ -231,210 +285,140 @@ sendmail(str)
  * Mail a message on standard input to the people indicated
  * in the passed header.  (Internal interface).
  */
  * Mail a message on standard input to the people indicated
  * in the passed header.  (Internal interface).
  */
-
-mail1(hp)
+mail1(hp, printheaders)
        struct header *hp;
 {
        struct header *hp;
 {
-       register char *cp;
-       int pid, i, s, p, gotcha;
-       char **namelist, *deliver;
-       struct name *to, *np;
-       FILE *mtf, *postage;
-       int remote = rflag != NOSTR || rmail;
-       char **t;
+       char *cp;
+       int pid;
+       char **namelist;
+       struct name *to;
+       FILE *mtf;
 
        /*
         * Collect user's mail from standard input.
         * Get the result as mtf.
         */
 
        /*
         * Collect user's mail from standard input.
         * Get the result as mtf.
         */
-
-       pid = -1;
-       if ((mtf = collect(hp)) == NULL)
-               return(-1);
-       hp->h_seq = 1;
-       if (hp->h_subject == NOSTR)
-               hp->h_subject = sflag;
-       if (fsize(mtf) == 0 && hp->h_subject == NOSTR) {
-               printf("No message !?!\n");
-               goto out;
-       }
-       if (intty && value("askcc") != NOSTR)
-               grabh(hp, GCC);
-       else if (intty) {
-               printf("EOT\n");
-               flush();
-       }
-
+       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.
         */
        /*
         * Now, take the user names from the combined
         * to and cc lists and do all the alias
         * processing.
         */
-
        senderr = 0;
        senderr = 0;
-       to = usermap(cat(extract(hp->h_bcc, GBCC),
-           cat(extract(hp->h_to, GTO), extract(hp->h_cc, GCC))));
+       to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
        if (to == NIL) {
                printf("No recipients specified\n");
        if (to == NIL) {
                printf("No recipients specified\n");
-               goto topdog;
+               senderr++;
        }
        }
-
        /*
         * Look through the recipient list for names with /'s
         * in them which we write to as files directly.
         */
        /*
         * Look through the recipient list for names with /'s
         * in them which we write to as files directly.
         */
-
        to = outof(to, mtf, hp);
        to = outof(to, mtf, hp);
-       rewind(mtf);
-       to = verify(to);
-       if (senderr && !remote) {
-topdog:
-
-               if (fsize(mtf) != 0) {
-                       remove(deadletter);
-                       exwrite(deadletter, mtf, 1);
-                       rewind(mtf);
-               }
-       }
-       for (gotcha = 0, np = to; np != NIL; np = np->n_flink)
-               if ((np->n_type & GDEL) == 0) {
-                       gotcha++;
-                       break;
-               }
-       if (!gotcha)
-               goto out;
+       if (senderr)
+               savedeadletter(mtf);
        to = elide(to);
        to = elide(to);
-       mechk(to);
-       if (count(to) > 1)
-               hp->h_seq++;
-       if (hp->h_seq > 0 && !remote) {
-               fixhead(hp, to);
-               if (fsize(mtf) == 0)
-                       printf("Null message body; hope that's ok\n");
-               if ((mtf = infix(hp, mtf)) == NULL) {
-                       fprintf(stderr, ". . . message lost, sorry.\n");
-                       return(-1);
-               }
+       if (count(to) == 0)
+               goto out;
+       fixhead(hp, to);
+       if ((mtf = infix(hp, mtf)) == NULL) {
+               fprintf(stderr, ". . . message lost, sorry.\n");
+               return;
        }
        }
-       namelist = unpack(to);
+       namelist = unpack(cat(hp->h_smopts, to));
        if (debug) {
        if (debug) {
-               printf("Recipients of message:\n");
+               char **t;
+
+               printf("Sendmail arguments:");
                for (t = namelist; *t != NOSTR; t++)
                        printf(" \"%s\"", *t);
                printf("\n");
                for (t = namelist; *t != NOSTR; t++)
                        printf(" \"%s\"", *t);
                printf("\n");
-               fflush(stdout);
-               return;
+               goto out;
        }
        if ((cp = value("record")) != NOSTR)
        }
        if ((cp = value("record")) != NOSTR)
-               savemail(expand(cp), hp, mtf);
-
+               (void) savemail(expand(cp), mtf);
        /*
        /*
-        * Wait, to absorb a potential zombie, then
-        * fork, set up the temporary mail file as standard
-        * input for "mail" and exec with the user list we generated
-        * far above. Return the process id to caller in case he
-        * wants to await the completion of mail.
+        * Fork, set up the temporary mail file as standard
+        * input for "mail", and exec with the user list we generated
+        * far above.
         */
         */
-
-#ifdef VMUNIX
-#ifdef pdp11
-       while (wait2(&s, WNOHANG) > 0)
-#endif
-#ifdef vax
-       while (wait3(&s, WNOHANG, 0) > 0)
-#endif
-               ;
-#else
-       wait(&s);
-#endif
-       rewind(mtf);
        pid = fork();
        if (pid == -1) {
                perror("fork");
        pid = fork();
        if (pid == -1) {
                perror("fork");
-               remove(deadletter);
-               exwrite(deadletter, mtf, 1);
+               savedeadletter(mtf);
                goto out;
        }
        if (pid == 0) {
                goto out;
        }
        if (pid == 0) {
-               sigchild();
-#ifdef SIGTSTP
-               if (remote == 0) {
-                       sigset(SIGTSTP, SIG_IGN);
-                       sigset(SIGTTIN, SIG_IGN);
-                       sigset(SIGTTOU, SIG_IGN);
-               }
-#endif
-               for (i = SIGHUP; i <= SIGQUIT; i++)
-                       sigset(i, SIG_IGN);
-               if ((postage = fopen(POSTAGE, "a")) != NULL) {
-                       fprintf(postage, "%s %d %d\n", myname,
-                           count(to), fsize(mtf));
-                       fclose(postage);
+               if (access(_PATH_MAIL_LOG, 0) == 0) {
+                       FILE *postage;
+
+                       if ((postage = Fopen(_PATH_MAIL_LOG, "a")) != NULL) {
+                               fprintf(postage, "%s %d %ld\n", myname,
+                                   count(to), fsize(mtf));
+                               (void) Fclose(postage);
+                       }
                }
                }
-               s = fileno(mtf);
-               for (i = 3; i < 15; i++)
-                       if (i != s)
-                               close(i);
-               close(0);
-               dup(s);
-               close(s);
-#ifdef CC
-               submit(getpid());
-#endif CC
-#ifdef DELIVERMAIL
-               if ((deliver = value("sendmail")) == NOSTR)
-                       deliver = DELIVERMAIL;
-               execv(deliver, namelist);
-#endif DELIVERMAIL
-               execv(MAIL, namelist);
-               perror(MAIL);
-               exit(1);
+               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:
 out:
-       if (remote) {
-               while ((p = wait(&s)) != pid && p != -1)
-                       ;
-               if (s != 0)
-                       senderr++;
-               pid = 0;
-       }
-       fclose(mtf);
-       return(pid);
+       (void) Fclose(mtf);
 }
 
 /*
  * Fix the header by glopping all of the expanded names from
  * the distribution list into the appropriate fields.
 }
 
 /*
  * Fix the header by glopping all of the expanded names from
  * the distribution list into the appropriate fields.
- * If there are any ARPA net recipients in the message,
- * we must insert commas, alas.
  */
  */
-
 fixhead(hp, tolist)
        struct header *hp;
        struct name *tolist;
 {
 fixhead(hp, tolist)
        struct header *hp;
        struct name *tolist;
 {
-       register struct name *nlist;
-       register int f;
        register struct name *np;
 
        register struct name *np;
 
-       for (f = 0, np = tolist; np != NIL; np = np->n_flink)
-               if (any('@', np->n_name)) {
-                       f |= GCOMMA;
-                       break;
-               }
-
-       if (debug && f & GCOMMA)
-               fprintf(stderr, "Should be inserting commas in recip lists\n");
-       hp->h_to = detract(tolist, GTO|f);
-       hp->h_cc = detract(tolist, GCC|f);
+       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.
  */
 }
 
 /*
  * Prepend a header in front of the collected stuff
  * and return the new file.
  */
-
 FILE *
 infix(hp, fi)
        struct header *hp;
 FILE *
 infix(hp, fi)
        struct header *hp;
@@ -444,36 +428,37 @@ infix(hp, fi)
        register FILE *nfo, *nfi;
        register int c;
 
        register FILE *nfo, *nfi;
        register int c;
 
-       rewind(fi);
-       if ((nfo = fopen(tempMail, "w")) == NULL) {
+       if ((nfo = Fopen(tempMail, "w")) == NULL) {
                perror(tempMail);
                return(fi);
        }
                perror(tempMail);
                return(fi);
        }
-       if ((nfi = fopen(tempMail, "r")) == NULL) {
+       if ((nfi = Fopen(tempMail, "r")) == NULL) {
                perror(tempMail);
                perror(tempMail);
-               fclose(nfo);
+               (void) Fclose(nfo);
                return(fi);
        }
                return(fi);
        }
-       remove(tempMail);
-       puthead(hp, nfo, GTO|GSUBJECT|GCC|GNL);
+       (void) rm(tempMail);
+       (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
        c = getc(fi);
        while (c != EOF) {
        c = getc(fi);
        while (c != EOF) {
-               putc(c, nfo);
+               (void) putc(c, nfo);
                c = getc(fi);
        }
        if (ferror(fi)) {
                perror("read");
                c = getc(fi);
        }
        if (ferror(fi)) {
                perror("read");
+               rewind(fi);
                return(fi);
        }
                return(fi);
        }
-       fflush(nfo);
+       (void) fflush(nfo);
        if (ferror(nfo)) {
                perror(tempMail);
        if (ferror(nfo)) {
                perror(tempMail);
-               fclose(nfo);
-               fclose(nfi);
+               (void) Fclose(nfo);
+               (void) Fclose(nfi);
+               rewind(fi);
                return(fi);
        }
                return(fi);
        }
-       fclose(nfo);
-       fclose(fi);
+       (void) Fclose(nfo);
+       (void) Fclose(fi);
        rewind(nfi);
        return(nfi);
 }
        rewind(nfi);
        return(nfi);
 }
@@ -482,7 +467,6 @@ infix(hp, fi)
  * Dump the to, subject, cc header on the
  * passed file buffer.
  */
  * Dump the to, subject, cc header on the
  * passed file buffer.
  */
-
 puthead(hp, fo, w)
        struct header *hp;
        FILE *fo;
 puthead(hp, fo, w)
        struct header *hp;
        FILE *fo;
@@ -490,41 +474,48 @@ puthead(hp, fo, w)
        register int gotcha;
 
        gotcha = 0;
        register int gotcha;
 
        gotcha = 0;
-       if (hp->h_to != NOSTR && w & GTO)
-               fprintf(fo, "To: "), fmt(hp->h_to, fo), gotcha++;
+       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_subject != NOSTR && w & GSUBJECT)
                fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
-       if (hp->h_cc != NOSTR && w & GCC)
-               fprintf(fo, "Cc: "), fmt(hp->h_cc, fo), gotcha++;
-       if (hp->h_bcc != NOSTR && w & GBCC)
-               fprintf(fo, "Bcc: "), fmt(hp->h_bcc, fo), 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)
        if (gotcha && w & GNL)
-               putc('\n', fo);
+               (void) putc('\n', fo);
        return(0);
 }
 
 /*
        return(0);
 }
 
 /*
- * Format the given text to not exceed 72 characters.
+ * Format the given header line to not exceed 72 characters.
  */
  */
-
-fmt(str, fo)
-       register char *str;
-       register FILE *fo;
+fmt(str, np, fo, comma)
+       char *str;
+       register struct name *np;
+       FILE *fo;
+       int comma;
 {
 {
-       register int col;
-       register char *cp;
-
-       cp = str;
-       col = 0;
-       while (*cp) {
-               if (*cp == ' ' && col > 65) {
-                       fprintf(fo, "\n    ");
+       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;
                        col = 4;
-                       cp++;
-                       continue;
-               }
-               putc(*cp++, fo);
-               col++;
+               } else
+                       putc(' ', fo);
+               fputs(np->n_name, fo);
+               if (comma)
+                       putc(',', fo);
+               col += len + comma;
        }
        putc('\n', fo);
 }
        }
        putc('\n', fo);
 }
@@ -533,32 +524,30 @@ fmt(str, fo)
  * Save the outgoing mail on the passed file.
  */
 
  * Save the outgoing mail on the passed file.
  */
 
-savemail(name, hp, fi)
+/*ARGSUSED*/
+savemail(name, fi)
        char name[];
        char name[];
-       struct header *hp;
-       FILE *fi;
+       register FILE *fi;
 {
        register FILE *fo;
 {
        register FILE *fo;
-       register int c;
-       long now;
-       char *n;
+       char buf[BUFSIZ];
+       register i;
+       time_t now, time();
+       char *ctime();
 
 
-       if ((fo = fopen(name, "a")) == NULL) {
+       if ((fo = Fopen(name, "a")) == NULL) {
                perror(name);
                perror(name);
-               return(-1);
+               return (-1);
        }
        }
-       time(&now);
-       n = rflag;
-       if (n == NOSTR)
-               n = myname;
-       fprintf(fo, "From %s %s", n, ctime(&now));
-       rewind(fi);
-       for (c = getc(fi); c != EOF; c = getc(fi))
-               putc(c, fo);
-       fprintf(fo, "\n");
-       fflush(fo);
+       (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);
        if (ferror(fo))
                perror(name);
-       fclose(fo);
-       return(0);
+       (void) Fclose(fo);
+       rewind(fi);
+       return (0);
 }
 }