cleanups, add manual page
[unix-history] / usr / src / usr.bin / mail / send.c
index 431f82a..28b0c66 100644 (file)
@@ -3,20 +3,23 @@
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is given
- * to the University of California at Berkeley. The name of the University
- * may not be used to endorse or promote products derived from this
- * software without specific prior written permission. This software
- * is provided ``as is'' without express or implied warranty.
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
  */
 
-#ifdef notdef
-static char sccsid[] = "@(#)send.c     5.8 (Berkeley) %G%";
-#endif /* notdef */
+#ifndef lint
+static char sccsid[] = "@(#)send.c     5.17 (Berkeley) %G%";
+#endif /* not lint */
 
 #include "rcv.h"
 
 #include "rcv.h"
-#include <sys/wait.h>
-#include <sys/stat.h>
 
 /*
  * Mail -- a mail program
 
 /*
  * Mail -- a mail program
@@ -26,19 +29,21 @@ static char sccsid[] = "@(#)send.c  5.8 (Berkeley) %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 given, 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(mp, obuf, doign)
+send(mp, obuf, doign, prefix)
        register struct message *mp;
        FILE *obuf;
        struct ignoretab *doign;
        register struct message *mp;
        FILE *obuf;
        struct ignoretab *doign;
+       char *prefix;
 {
        long count;
        register FILE *ibuf;
        char line[LINESIZE];
 {
        long count;
        register FILE *ibuf;
        char line[LINESIZE];
-       int lc, ishead, infld, ignoring, dostat;
+       int ishead, infld, ignoring, dostat, firstline;
        register char *cp, *cp2;
        register int c;
        int length;
        register char *cp, *cp2;
        register int c;
        int length;
@@ -48,7 +53,7 @@ send(mp, obuf, doign)
        ishead = 1;
        dostat = doign == 0 || !isign("status", doign);
        infld = 0;
        ishead = 1;
        dostat = doign == 0 || !isign("status", doign);
        infld = 0;
-       lc = 0;
+       firstline = 1;
        /*
         * Process headers first
         */
        /*
         * Process headers first
         */
@@ -56,12 +61,13 @@ send(mp, obuf, doign)
                if (fgets(line, LINESIZE, ibuf) == NULL)
                        break;
                count -= length = strlen(line);
                if (fgets(line, LINESIZE, ibuf) == NULL)
                        break;
                count -= length = strlen(line);
-               if (lc == 0) {
+               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
                         */
-                       ignoring = 0;
+                       firstline = 0;
+                       ignoring = doign == ignoreall;
                } else if (line[0] == '\n') {
                        /*
                         * If line is blank, we've reached end of
                } else if (line[0] == '\n') {
                        /*
                         * If line is blank, we've reached end of
@@ -70,11 +76,11 @@ send(mp, obuf, doign)
                         * fields
                         */
                        if (dostat) {
                         * fields
                         */
                        if (dostat) {
-                               statusput(mp, obuf);
+                               statusput(mp, obuf, prefix);
                                dostat = 0;
                        }
                        ishead = 0;
                                dostat = 0;
                        }
                        ishead = 0;
-                       ignoring = 0;
+                       ignoring = doign == ignoreall;
                } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
                        /*
                         * If this line is a continuation (via space or tab)
                } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
                        /*
                         * If this line is a continuation (via space or tab)
@@ -98,11 +104,12 @@ send(mp, obuf, doign)
                                 * there are no headers at all.
                                 */
                                if (dostat) {
                                 * there are no headers at all.
                                 */
                                if (dostat) {
-                                       statusput(mp, obuf);
+                                       statusput(mp, obuf, prefix);
                                        dostat = 0;
                                }
                                        dostat = 0;
                                }
-                               (void) putc('\n', obuf); /* add blank line */
-                               lc++;
+                               if (doign != ignoreall)
+                                       /* add blank line */
+                                       (void) putc('\n', obuf);
                                ishead = 0;
                                ignoring = 0;
                        } else {
                                ishead = 0;
                                ignoring = 0;
                        } else {
@@ -114,13 +121,13 @@ send(mp, obuf, doign)
                                if (doign && isign(line, doign))
                                        ignoring = 1;
                                else if ((line[0] == 's' || line[0] == 'S') &&
                                if (doign && isign(line, doign))
                                        ignoring = 1;
                                else if ((line[0] == 's' || line[0] == 'S') &&
-                                        icequal(line, "status")) {
+                                        strcasecmp(line, "status") == 0) {
                                        /*
                                         * If the field is "status," go compute
                                         * and print the real Status: field
                                         */
                                        if (dostat) {
                                        /*
                                         * If the field is "status," go compute
                                         * and print the real Status: field
                                         */
                                        if (dostat) {
-                                               statusput(mp, obuf);
+                                               statusput(mp, obuf, prefix);
                                                dostat = 0;
                                        }
                                        ignoring = 1;
                                                dostat = 0;
                                        }
                                        ignoring = 1;
@@ -132,39 +139,54 @@ send(mp, obuf, doign)
                        }
                }
                if (!ignoring) {
                        }
                }
                if (!ignoring) {
+                       if (prefix != NOSTR && length > 1)
+                               fputs(prefix, obuf);
                        (void) fwrite(line, sizeof *line, length, obuf);
                        if (ferror(obuf))
                                return -1;
                        (void) fwrite(line, sizeof *line, length, obuf);
                        if (ferror(obuf))
                                return -1;
-                       lc++;
                }
        }
        /*
         * Copy out message body
         */
                }
        }
        /*
         * Copy out message body
         */
-       while (count > 0) {
-               cp = line;
-               c = count < LINESIZE ? count : LINESIZE;
-               if ((c = fread(cp, sizeof *cp, c, ibuf)) <= 0)
-                       break;
-               if (fwrite(cp, sizeof *cp, c, obuf) != c)
+       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 (c > 1)
+                               fputs(prefix, 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 -1;
-               count -= c;
-               while (--c >= 0)
-                       if (*cp++ == '\n')
-                               lc++;
-       }
-       if (ishead && (mp->m_flag & MSTATUS))
-               printf("failed to fix up status field\n");
-       return (lc);
+       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)
+statusput(mp, obuf, prefix)
        register struct message *mp;
        FILE *obuf;
        register struct message *mp;
        FILE *obuf;
+       char *prefix;
 {
        char statout[3];
        register char *cp = statout;
 {
        char statout[3];
        register char *cp = statout;
@@ -175,26 +197,26 @@ statusput(mp, obuf)
                *cp++ = 'O';
        *cp = 0;
        if (statout[0])
                *cp++ = 'O';
        *cp = 0;
        if (statout[0])
-               fprintf(obuf, "Status: %s\n", statout);
+               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(to, cc, bcc, smopts)
+mail(to, cc, bcc, smopts, subject)
        struct name *to, *cc, *bcc, *smopts;
        struct name *to, *cc, *bcc, *smopts;
+       char *subject;
 {
        struct header head;
 
 {
        struct header head;
 
-       head.h_to = detract(to, 0);
-       head.h_subject = NOSTR;
-       head.h_cc = detract(cc, 0);
-       head.h_bcc = detract(bcc, 0);
-       head.h_smopts = detract(smopts, 0);
-       head.h_seq = 0;
-       (void) 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);
 }
 
@@ -203,22 +225,17 @@ mail(to, cc, bcc, smopts)
  * 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;
 {
        struct header head;
 
 sendmail(str)
        char *str;
 {
        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_smopts = NOSTR;
-       head.h_seq = 0;
-       (void) mail1(&head);
+       head.h_cc = NIL;
+       head.h_bcc = NIL;
+       head.h_smopts = NIL;
+       mail1(&head, 0);
        return(0);
 }
 
        return(0);
 }
 
@@ -226,193 +243,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, p, gotcha;
-       union wait s;
-       char **namelist, *deliver;
-       struct name *to, *np;
-       struct stat sbuf;
-       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 (hp->h_subject == NOSTR)
-               hp->h_subject = sflag;
-       if ((mtf = collect(hp)) == NULL)
-               return(-1);
-       hp->h_seq = 1;
-       if (intty && value("askcc") != NOSTR)
-               grabh(hp, GCC);
-       else if (intty) {
-               printf("EOT\n");
-               (void) fflush(stdout);
-       }
-
+       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);
-       if (senderr && !remote) {
-topdog:
-
-               if (fsize(mtf) != 0) {
-                       (void) remove(deadletter);
-                       (void) 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)
-                   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");
-               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(cat(extract(hp->h_smopts, 0), 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");
-               (void) fflush(stdout);
-               return 0;
+               goto out;
        }
        if ((cp = value("record")) != NOSTR)
                (void) savemail(expand(cp), mtf);
        }
        if ((cp = value("record")) != NOSTR)
                (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.
         */
         */
-
-       while (wait3(&s, WNOHANG, (struct timeval *) 0) > 0)
-               ;
-       rewind(mtf);
        pid = fork();
        if (pid == -1) {
                perror("fork");
        pid = fork();
        if (pid == -1) {
                perror("fork");
-               (void) remove(deadletter);
-               (void) exwrite(deadletter, mtf, 1);
+               savedeadletter(mtf);
                goto out;
        }
        if (pid == 0) {
                goto out;
        }
        if (pid == 0) {
-#ifdef SIGTSTP
-               if (remote == 0) {
-                       (void) signal(SIGTSTP, SIG_IGN);
-                       (void) signal(SIGTTIN, SIG_IGN);
-                       (void) signal(SIGTTOU, SIG_IGN);
-               }
-#endif
-               (void) signal(SIGHUP, SIG_IGN);
-               (void) signal(SIGINT, SIG_IGN);
-               (void) signal(SIGQUIT, SIG_IGN);
-               if (!stat(POSTAGE, &sbuf))
+               if (access(POSTAGE, 0) == 0) {
+                       FILE *postage;
+
                        if ((postage = fopen(POSTAGE, "a")) != NULL) {
                                fprintf(postage, "%s %d %ld\n", myname,
                                    count(to), fsize(mtf));
                                (void) fclose(postage);
                        }
                        if ((postage = fopen(POSTAGE, "a")) != NULL) {
                                fprintf(postage, "%s %d %ld\n", myname,
                                    count(to), fsize(mtf));
                                (void) fclose(postage);
                        }
-               (void) close(0);
-               (void) dup(fileno(mtf));
-               for (i = getdtablesize(); --i > 2;)
-                       (void) close(i);
-               if ((deliver = value("sendmail")) == NOSTR)
-                       deliver = SENDMAIL;
-               execv(deliver, namelist);
-               perror(deliver);
-               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 = SENDMAIL;
+               execv(cp, namelist);
+               perror(cp);
+               _exit(1);
        }
        }
-
+       if (value("verbose") != NOSTR)
+               (void) wait_child(pid);
+       else
+               free_child(pid);
 out:
 out:
-       if (remote || (value("verbose") != NOSTR)) {
-               while ((p = wait(&s)) != pid && p != -1)
-                       ;
-               if (s.w_status != 0)
-                       senderr++;
-               pid = 0;
-       }
        (void) fclose(mtf);
        (void) fclose(mtf);
-       return(pid);
 }
 
 /*
  * 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 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_bcc = detract(tolist, GBCC|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;
@@ -422,7 +386,6 @@ 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) {
                perror(tempMail);
                return(fi);
        if ((nfo = fopen(tempMail, "w")) == NULL) {
                perror(tempMail);
                return(fi);
@@ -433,7 +396,7 @@ infix(hp, fi)
                return(fi);
        }
        (void) remove(tempMail);
                return(fi);
        }
        (void) remove(tempMail);
-       (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL);
+       (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
        c = getc(fi);
        while (c != EOF) {
                (void) putc(c, nfo);
        c = getc(fi);
        while (c != EOF) {
                (void) putc(c, nfo);
@@ -441,6 +404,7 @@ infix(hp, fi)
        }
        if (ferror(fi)) {
                perror("read");
        }
        if (ferror(fi)) {
                perror("read");
+               rewind(fi);
                return(fi);
        }
        (void) fflush(nfo);
                return(fi);
        }
        (void) fflush(nfo);
@@ -448,6 +412,7 @@ infix(hp, fi)
                perror(tempMail);
                (void) fclose(nfo);
                (void) fclose(nfi);
                perror(tempMail);
                (void) fclose(nfo);
                (void) fclose(nfi);
+               rewind(fi);
                return(fi);
        }
        (void) fclose(nfo);
                return(fi);
        }
        (void) fclose(nfo);
@@ -460,7 +425,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;
@@ -468,61 +432,50 @@ puthead(hp, fo, w)
        register int gotcha;
 
        gotcha = 0;
        register int gotcha;
 
        gotcha = 0;
-       if (hp->h_to != NOSTR && w & GTO)
-               fmt("To: ", 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)
-               fmt("Cc: ", hp->h_cc, fo), gotcha++;
-       if (hp->h_bcc != NOSTR && w & GBCC)
-               fmt("Bcc: ", 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)
                (void) putc('\n', fo);
        return(0);
 }
 
 /*
        if (gotcha && w & GNL)
                (void) putc('\n', fo);
        return(0);
 }
 
 /*
- * Format the given text to not exceed 72 characters.
+ * Format the given header line to not exceed 72 characters.
  */
  */
-
-fmt(str, txt, fo)
-       register char *str, *txt;
-       register FILE *fo;
+fmt(str, np, fo, comma)
+       char *str;
+       register struct name *np;
+       FILE *fo;
+       int comma;
 {
 {
-       register int col;
-       register char *bg, *bl, *pt, ch;
+       register col, len;
 
 
+       comma = comma ? 1 : 0;
        col = strlen(str);
        if (col)
        col = strlen(str);
        if (col)
-               fprintf(fo, "%s", str);
-       pt = bg = txt;
-       bl = 0;
-       while (*bg) {
-               pt++;
-               if (++col > 72) {
-                       if (!bl) {
-                               bl = bg;
-                               while (*bl && !isspace(*bl))
-                                       bl++;
-                       }
-                       if (!*bl)
-                               goto finish;
-                       ch = *bl;
-                       *bl = '\0';
-                       fprintf(fo, "%s\n    ", bg);
+               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;
-                       *bl = ch;
-                       pt = bg = ++bl;
-                       bl = 0;
-               }
-               if (!*pt) {
-finish:
-                       fprintf(fo, "%s\n", bg);
-                       return;
-               }
-               if (isspace(*pt))
-                       bl = pt;
+               } else
+                       putc(' ', fo);
+               fputs(np->n_name, fo);
+               if (comma)
+                       putc(',', fo);
+               col += len + comma;
        }
        }
+       putc('\n', fo);
 }
 
 /*
 }
 
 /*
@@ -538,7 +491,6 @@ savemail(name, fi)
        char buf[BUFSIZ];
        register i;
        time_t now, time();
        char buf[BUFSIZ];
        register i;
        time_t now, time();
-       char *n;
        char *ctime();
 
        if ((fo = fopen(name, "a")) == NULL) {
        char *ctime();
 
        if ((fo = fopen(name, "a")) == NULL) {
@@ -546,10 +498,7 @@ savemail(name, fi)
                return (-1);
        }
        (void) time(&now);
                return (-1);
        }
        (void) time(&now);
-       if ((n = rflag) == NOSTR)
-               n = myname;
-       fprintf(fo, "From %s %s", n, ctime(&now));
-       rewind(fi);
+       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);
        while ((i = fread(buf, 1, sizeof buf, fi)) > 0)
                (void) fwrite(buf, 1, i, fo);
        (void) putc('\n', fo);
@@ -557,5 +506,6 @@ savemail(name, fi)
        if (ferror(fo))
                perror(name);
        (void) fclose(fo);
        if (ferror(fo))
                perror(name);
        (void) fclose(fo);
+       rewind(fi);
        return (0);
 }
        return (0);
 }