Merge branch 'm_getfld2-meillo' into master
authorPhilipp Takacs <philipp@bureaucracy.de>
Fri, 22 Apr 2016 22:56:56 +0000 (00:56 +0200)
committerPhilipp Takacs <philipp@bureaucracy.de>
Fri, 22 Apr 2016 22:56:56 +0000 (00:56 +0200)
20 files changed:
1  2 
h/mh.h
h/prototypes.h
sbr/Makefile.in
sbr/readconfig.c
sbr/seq_read.c
uip/inc.c
uip/mhbuild.c
uip/mhl.c
uip/mhparse.c
uip/new.c
uip/pick.c
uip/rcvdist.c
uip/rcvstore.c
uip/repl.c
uip/scan.c
uip/scansbr.c
uip/slocal.c
uip/sortm.c
uip/spost.c
uip/whom.c

diff --combined h/mh.h
--- 1/h/mh.h
--- 2/h/mh.h
+++ b/h/mh.h
@@@ -203,14 -203,24 +203,24 @@@ struct msgs 
                             ** terminating NULL.
                             */
  
- #define LENERR   (-2)      /* Name too long error from getfld  */
- #define FMTERR   (-3)      /* Message Format error             */
- #define FLD      0         /* Field returned                   */
- #define FLDPLUS  1         /* Field returned with more to come */
- #define BODY     3         /* Body  returned with more to come */
- #define FILEEOF  5         /* Reached end of input file        */
- extern int msg_count;        /* m_getfld() indicators (That's a hack!) */
+ /* m_getfld2() returned data */
+ struct field {
+       char name[NAMESZ];
+       size_t namelen;
+       char *value;
+       size_t valuelen;
+       size_t alloclen;
+ };
+ /* m_getfld2() states */
+ enum state {
+       LENERR2 = -2,      /* Line too long */
+       FMTERR2 = -3,      /* Format error in message */
+       IOERR2 = -1,       /* Read error */
+       FLD2 = 0,          /* Header field returned */
+       BODY2,             /* Body line returned */
+       FILEEOF2,          /* Reached end of input file */
+ };
  
  #define NOUSE    0        /* draft being re-used */
  
@@@ -281,7 -291,6 +291,7 @@@ extern char *psequence
  extern char *rcvdistcomps;
  extern char *replcomps;
  extern char *replgroupcomps;
 +extern char *scanformat;
  extern char *sendmail;
  extern char *seq_all;
  extern char *seq_beyond;
diff --combined h/prototypes.h
@@@ -55,6 -55,7 +55,6 @@@ char **getans(char *, struct swit *)
  int getanswer(char *);
  char **getarguments(char *, int, char **, int);
  char *get_charset();
 -char *getcpy(char *);
  char *getcurfol(void);
  char *getdeffol(void);
  int lkclose(int, char*);
@@@ -65,7 -66,7 +65,7 @@@ int m_atoi(char *)
  char *m_backup(char *);
  int m_convert(struct msgs *, char *);
  char *m_draft(char *);
- int m_getfld(int, unsigned char *, unsigned char *, int, FILE *);
+ enum state m_getfld2(enum state, struct field *, FILE *);
  int m_gmprot(void);
  char *m_name(int);
  int m_putenv(char *, char *);
diff --combined sbr/Makefile.in
@@@ -54,10 -54,10 +54,10 @@@ SRCS = addrsbr.c ambigsw.c brkstring.
        error.c execprog.c ext_hook.c folder_addmsg.c folder_delmsgs.c  \
        folder_free.c folder_read.c  \
        folder_realloc.c gans.c getans.c getanswer.c  \
 -      getarguments.c getcpy.c \
 +      getarguments.c \
        fmt_addr.c fmt_compile.c fmt_new.c fmt_rfc2047.c  \
        fmt_scan.c lock_file.c m_atoi.c \
-       m_convert.c m_draft.c m_getfld.c m_gmprot.c  \
+       m_convert.c m_draft.c m_getfld2.c m_gmprot.c  \
        m_name.c \
        makedir.c mts.c norm_charmap.c  \
        path.c pidwait.c pidstatus.c  \
diff --combined sbr/readconfig.c
@@@ -36,9 -36,8 +36,8 @@@ static struct node **opp = NULL
  void
  readconfig(struct node **npp, FILE *ib, char *file, int ctx)
  {
-       int state;
-       char *cp;
-       char name[NAMESZ], field[BUFSIZ];
+       enum state state;
+       struct field f = {{0}};
        struct node *np;
        struct procstr *ps;
  
                return;
        }
  
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               ib)) {
-               case FLD:
-               case FLDPLUS:
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, ib)) {
+               case FLD2:
 -                      np = (struct node *) mh_xmalloc(sizeof(*np));
 +                      np = mh_xcalloc(1, sizeof(*np));
                        *npp = np;
                        *(npp = &np->n_next) = NULL;
-                       np->n_name = mh_xstrdup(name);
-                       if (state == FLDPLUS) {
-                               cp = mh_xstrdup(field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), ib);
-                                       cp = add(field, cp);
-                               }
-                               np->n_field = trimcpy(cp);
-                               mh_free0(&cp);
-                       } else {
-                               np->n_field = trimcpy(field);
-                       }
 -                      np->n_name = getcpy(f.name);
++                      np->n_name = mh_xstrdup(f.name);
+                       np->n_field = trimcpy(f.value);
                        np->n_context = ctx;
  
                        /*
                        ** Now scan the list of `procs' and link in
                        ** the field value to the global variable.
                        */
-                       for (ps = procs; ps->procname; ps++)
+                       for (ps = procs; ps->procname; ps++) {
                                if (mh_strcasecmp(np->n_name,
                                                ps->procname) == 0) {
                                        *ps->procnaddr = np->n_field;
                                        break;
                                }
+                       }
                        continue;
  
-               case BODY:
+               case BODY2:
                        adios(EX_CONFIG, NULL, "no blank lines are permitted in %s",
                                        file);
  
-               case FILEEOF:
+               case FILEEOF2:
                        break;
  
                default:
diff --combined sbr/seq_read.c
@@@ -32,7 -32,7 +32,7 @@@ seq_read(struct msgs *mp
        ** Initialize the list of sequence names.  Go ahead and
        ** add the cur sequence to the list of sequences.
        */
 -      mp->msgattrs[0] = getcpy(seq_cur);
 +      mp->msgattrs[0] = mh_xstrdup(seq_cur);
        mp->msgattrs[1] = NULL;
        make_all_public(mp);  /* initially, make all public */
  
@@@ -55,9 -55,9 +55,9 @@@
  static void
  seq_public(struct msgs *mp)
  {
-       int state;
-       char *cp, seqfile[PATH_MAX];
-       char name[NAMESZ], field[BUFSIZ];
+       enum state state;
+       struct field f = {{0}};
+       char seqfile[PATH_MAX];
        FILE *fp;
  
        /*
                return;
  
        /* Use m_getfld to scan sequence file */
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               fp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (state == FLDPLUS) {
-                               cp = mh_xstrdup(field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), fp);
-                                       cp = add(field, cp);
-                               }
-                               seq_init(mp, mh_xstrdup(name), trimcpy(cp));
-                               mh_free0(&cp);
-                       } else {
-                               seq_init(mp, mh_xstrdup(name), trimcpy(field));
-                       }
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
 -                      seq_init(mp, getcpy(f.name), trimcpy(f.value));
++                      seq_init(mp, mh_xstrdup(f.name), trimcpy(f.value));
                        continue;
  
-               case BODY:
+               case BODY2:
                        adios(EX_CONFIG, NULL, "no blank lines are permitted in %s",
                                        seqfile);
-                       /* fall */
+                       /* FALL */
  
-               case FILEEOF:
+               case FILEEOF2:
                        break;
  
                default:
                        adios(EX_CONFIG, NULL, "%s is poorly formatted", seqfile);
                }
-               break;  /* break from for loop */
+               break;
        }
  
        lkfclose(fp, seqfile);
@@@ -133,9 -120,9 +120,9 @@@ seq_private(struct msgs *mp
                                (j = strlen(np->n_name) - plen) > alen &&
                                *(np->n_name + j) == '-' &&
                                strcmp(mp->foldpath, np->n_name + j + 1)==0) {
 -                      cp = getcpy(np->n_name + alen);
 +                      cp = mh_xstrdup(np->n_name + alen);
                        *(cp + j - alen) = '\0';
 -                      if ((i = seq_init(mp, cp, getcpy(np->n_field))) != -1)
 +                      if ((i = seq_init(mp, cp, mh_xstrdup(np->n_field))) != -1)
                                make_seq_private(mp, i);
                }
        }
@@@ -181,8 -168,8 +168,8 @@@ seq_init(struct msgs *mp, char *name, c
  
        /* Return error, if too many sequences */
        if (i >= NUMATTRS) {
 -              free(name);
 -              free(field);
 +              mh_free0(&name);
 +              mh_free0(&field);
                return -1;
        }
  
        ** name string.  Else add it to the list of sequence names.
        */
        if (mp->msgattrs[i]) {
 -              free(name);
 +              mh_free0(&name);
        } else {
                mp->msgattrs[i] = name;
                mp->msgattrs[i + 1] = NULL;
                }
        }
  
 -      free(field);  /* free string containing message ranges */
 +      mh_free0(&field);  /* free string containing message ranges */
        return i;
  }
diff --combined uip/inc.c
+++ b/uip/inc.c
@@@ -162,17 -162,16 +162,16 @@@ main(int argc, char **argv
                adios(EX_OSERR, NULL, "atexit failed");
        }
  
- /*
- ** absolutely the first thing we do is save our privileges,
- ** and drop them if we can.
- */
+       /*
+       ** absolutely the first thing we do is save our privileges,
+       ** and drop them if we can.
+       */
        SAVEGROUPPRIVS();
        TRYDROPGROUPPRIVS();
  
        setlocale(LC_ALL, "");
        invo_name = mhbasename(argv[0]);
  
-       /* read user profile/context */
        context_read();
  
        arguments = getarguments(invo_name, argc, argv, 1);
                        case AUDSW:
                                if (!(cp = *argp++) || *cp == '-')
                                        adios(EX_USAGE, NULL, "missing argument to %s", argp[-2]);
 -                              audfile = getcpy(expanddir(cp));
 +                              audfile = mh_xstrdup(expanddir(cp));
                                continue;
                        case NAUDSW:
                                audfile = NULL;
                                if (!(cp = *argp++) || *cp == '-')
                                        adios(EX_USAGE, NULL, "missing argument to %s",
                                                        argp[-2]);
 -                              from = getcpy(expanddir(cp));
 +                              from = mh_xstrdup(expanddir(cp));
  
                                /*
                                ** If the truncate file is in default state,
                        if (folder)
                                adios(EX_USAGE, NULL, "only one folder at a time!");
                        else
 -                              folder = getcpy(expandfol(cp));
 +                              folder = mh_xstrdup(expandfol(cp));
                } else {
                        adios(EX_USAGE, NULL, "usage: %s [+folder] [switches]",
                                        invo_name);
        if (chdir(maildir) == NOTOK)
                adios(EX_OSERR, maildir, "unable to change directory to");
  
-       /* read folder and create message structure */
        if (!(mp = folder_read(folder)))
                adios(EX_IOERR, NULL, "unable to read folder %s", folder);
  
                         dtimenow(), from);
        }
  
 -      /* Get new format string */
 -      fmtstr = new_fs(form, FORMAT);
 +      /* Set format string */
 +      fmtstr = new_fs(form, scanformat);
  
        if (noisy) {
                printf("Incorporating new mail into %s...\n\n", folder);
                fflush(stdout);
        }
  
+       /* check if readable and nonempty */
+       if (!fgets(buf, sizeof(buf), in)) {
+               if (ferror(in)) {
+                       advise("read", "unable to");
+                       incerr = SCNFAT;
+               } else {
+                       incerr = SCNEOF;
+               }
+               goto giveup;
+       }
+       if (strncmp("From ", buf, 5)!=0) {
+               advise(NULL, "not in mbox format");
+               incerr = SCNFAT;
+               goto giveup;
+       }
        /*
        ** Get the mail from file (usually mail spool)
        */
-       thisisanmbox(in);
        hghnum = msgnum = mp->hghmsg;
        for (;;) {
                /*
                */
                break;
        }
+ giveup:;
 -      free(maildir_copy);
 +      mh_free0(&maildir_copy);
  
        if (incerr < 0) {  /* error */
                if (locked) {
                fclose(in); in = NULL;
        }
  
-       seq_setunseen(mp, 1);  /* add new msgs to unseen sequences */
-       seq_save(mp);  /* synchronize sequences   */
-       context_save();  /* save the context file   */
+       seq_setunseen(mp, 1);
+       seq_save(mp);
+       context_save();
        return 0;
  }
  
diff --combined uip/mhbuild.c
@@@ -204,7 -204,7 +204,7 @@@ main(int argc, char **argv
        if ((cp = context_find(nmhstorage)) && *cp)
                tmp = concat(cp, "/", invo_name, NULL);
        else
 -              tmp = getcpy(toabsdir(invo_name));
 +              tmp = mh_xstrdup(toabsdir(invo_name));
  
        /* Check if we have a file to process */
        if (!compfile)
@@@ -312,8 -312,10 +312,10 @@@ unlink_done(
  static CT
  build_mime(char *infile)
  {
-       int compnum, state;
-       char buf[BUFSIZ], name[NAMESZ];
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
+       char buf[BUFSIZ];
        char *cp, *np, *vp;
        struct multipart *m;
        struct part **pp;
        umask(~m_gmprot());
  
        /* open the composition draft */
-       if ((in = fopen(infile, "r")) == NULL)
+       if ((in = fopen(infile, "r")) == NULL) {
                adios(EX_IOERR, infile, "unable to open for reading");
+       }
  
        /*
        ** Allocate space for primary (outside) content
        */
 -      ct = (CT) mh_xcalloc(1, sizeof(*ct));
 +      ct = mh_xcalloc(1, sizeof(*ct));
  
        /*
        ** Allocate structure for handling decoded content
        ** draft into the linked list of header fields for
        ** the new MIME message.
        */
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
+       for (compnum = 1, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        compnum++;
  
                        /* abort if draft has Mime-Version header field */
-                       if (!mh_strcasecmp(name, VRSN_FIELD))
+                       if (!mh_strcasecmp(f.name, VRSN_FIELD)) {
                                adios(EX_CONFIG, NULL, "draft shouldn't contain %s: field", VRSN_FIELD);
+                       }
  
                        /*
                        ** abort if draft has Content-Transfer-Encoding
                        ** header field
                        */
-                       if (!mh_strcasecmp(name, ENCODING_FIELD))
+                       if (!mh_strcasecmp(f.name, ENCODING_FIELD)) {
                                adios(EX_CONFIG, NULL, "draft shouldn't contain %s: field", ENCODING_FIELD);
+                       }
  
                        /* ignore any Content-Type fields in the header */
-                       if (!mh_strcasecmp(name, TYPE_FIELD)) {
-                               while (state == FLDPLUS)
-                                       state = m_getfld(state, name, buf,
-                                                       sizeof(buf), in);
+                       if (!mh_strcasecmp(f.name, TYPE_FIELD)) {
                                continue;
                        }
  
-                       /* get copies of the buffers */
-                       np = mh_xstrdup(name);
-                       vp = mh_xstrdup(buf);
-                       /* if necessary, get rest of field */
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               vp = add(buf, vp);  /* add to prev value */
-                       }
-                       /* Now add the header data to the list */
-                       add_header(ct, np, vp);
+                       /* add the header data to the list */
 -                      add_header(ct, getcpy(f.name), getcpy(f.value));
++                      add_header(ct, mh_xstrdup(f.name), mh_xstrdup(f.value));
  
                        continue;
  
-               case FILEEOF:
+               case BODY2:
+                       fseek(in, (long) (-strlen(f.value)), SEEK_CUR);
+                       break;
+               case FILEEOF2:
                        adios(EX_CONFIG, NULL, "draft has empty body -- no directives!");
                        /* NOTREACHED */
  
-               case BODY:
-                       fseek(in, (long) (-strlen(buf)), SEEK_CUR);
-                       break;
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_CONFIG, NULL, "message format error in component #%d",
                                        compnum);
  
        ** Now add the MIME-Version header field
        ** to the list of header fields.
        */
 -      np = getcpy(VRSN_FIELD);
 +      np = mh_xstrdup(VRSN_FIELD);
        vp = concat(" ", VRSN_VALUE, "\n", NULL);
        add_header(ct, np, vp);
  
        }
        ct->c_type = CT_MULTIPART;
        ct->c_subtype = MULTI_MIXED;
 -      ct->c_file = getcpy(infile);
 +      ct->c_file = mh_xstrdup(infile);
  
-       m = mh_xcalloc(1, sizeof(*m));
+       m = (struct multipart *) mh_xcalloc(1, sizeof(*m));
        ct->c_ctparams = (void *) m;
        pp = &m->mp_parts;
  
                if (!p)
                        continue;
  
 -              part = (struct part *) mh_xcalloc(1, sizeof(*part));
 +              part = mh_xcalloc(1, sizeof(*part));
                *pp = part;
                pp = &part->mp_next;
                part->mp_part = p;
@@@ -533,7 -524,7 +524,7 @@@ init_decoded_content(CT ct
  {
        CE ce;
  
 -      ce = (CE) mh_xcalloc(1, sizeof(*ce));
 +      ce = mh_xcalloc(1, sizeof(*ce));
  
        ct->c_cefile     = ce;
        ct->c_ceopenfnx  = open7Bit;  /* since unencoded */
@@@ -593,7 -584,7 +584,7 @@@ user_content(FILE *in, char *file, cha
        }
  
        /* allocate basic Content structure */
 -      ct = (CT) mh_xcalloc(1, sizeof(*ct));
 +      ct = mh_xcalloc(1, sizeof(*ct));
        *ctp = ct;
  
        /* allocate basic structure for handling decoded content */
                        adios(EX_CANTCREAT, "mhbuild", "unable to create temporary file");
  
                /* use a temp file to collect the plain text lines */
 -              ce->ce_file = getcpy(cp);
 +              ce->ce_file = mh_xstrdup(cp);
                ce->ce_unlink = 1;
  
                if (buf[0] == '#' && buf[1] == '<') {
@@@ -806,8 -797,8 +797,8 @@@ use_forw
                                        continue;
                                if (!*cp)
                                        adios(EX_DATAERR, NULL, "empty pipe command for #%s directive", ci->ci_type);
 -                              cp = getcpy(cp);
 -                              free(ci->ci_magic);
 +                              cp = mh_xstrdup(cp);
 +                              mh_free0(&(ci->ci_magic));
                                ci->ci_magic = cp;
                        } else {
                                /* record filename of decoded contents */
                                exit(EX_CONFIG);
                        }
                }
 -              ci->ci_magic = getcpy(cp);
 +              ci->ci_magic = mh_xstrdup(cp);
                return OK;
        }
  
                                if (folder)
                                        adios(EX_USAGE, NULL, "only one folder per #forw directive");
                                else
 -                                      folder = getcpy(expandfol(cp));
 +                                      folder = mh_xstrdup(expandfol(cp));
                        }
                }
  
                /* else, use the current folder */
                if (!folder)
 -                      folder = getcpy(getcurfol());
 +                      folder = mh_xstrdup(getcurfol());
  
                if (!(mp = folder_read(folder)))
                        adios(EX_IOERR, NULL, "unable to read folder %s", folder);
                                if (!m_convert(mp, cp))
                                        exit(EX_USAGE);
                }
 -              free(folder);
 +              mh_free0(&folder);
                free_ctinfo(ct);
  
                /*
                        ct->c_type = CT_MULTIPART;
                        ct->c_subtype = MULTI_DIGEST;
  
 -                      m = (struct multipart *) mh_xcalloc(1, sizeof(*m));
 +                      m = mh_xcalloc(1, sizeof(*m));
                        ct->c_ctparams = (void *) m;
                        pp = &m->mp_parts;
  
                                        CT p;
                                        CE pe;
  
 -                                      p = (CT) mh_xcalloc(1, sizeof(*p));
 +                                      p = mh_xcalloc(1, sizeof(*p));
                                        init_decoded_content(p);
                                        pe = p->c_cefile;
                                        if (get_ctinfo("message/rfc822", p, 0)
                                        snprintf(buffer, sizeof(buffer),
                                                        "%s/%d", mp->foldpath,
                                                        msgnum);
 -                                      pe->ce_file = getcpy(buffer);
 +                                      pe->ce_file = mh_xstrdup(buffer);
  
 -                                      part = (struct part *) mh_xcalloc(1, sizeof(*part));
 +                                      part = mh_xcalloc(1, sizeof(*part));
                                        *pp = part;
                                        pp = &part->mp_next;
                                        part->mp_part = p;
                        msgnum = mp->lowsel;
                        snprintf(buffer, sizeof(buffer), "%s/%d",
                                        mp->foldpath, msgnum);
 -                      ce->ce_file = getcpy(buffer);
 +                      ce->ce_file = mh_xstrdup(buffer);
                }
  
                folder_free(mp);  /* free folder/message structure */
                ct->c_type = CT_MULTIPART;
                ct->c_subtype = vrsn;
  
 -              m = (struct multipart *) mh_xcalloc(1, sizeof(*m));
 +              m = mh_xcalloc(1, sizeof(*m));
                ct->c_ctparams = (void *) m;
  
                pp = &m->mp_parts;
                        if (!p)
                                continue;
  
 -                      part = (struct part *) mh_xcalloc(1, sizeof(*part));
 +                      part = mh_xcalloc(1, sizeof(*part));
                        *pp = part;
                        pp = &part->mp_next;
                        part->mp_part = p;
@@@ -1030,10 -1021,10 +1021,10 @@@ set_id(CT ct, int top
                snprintf(msgid, sizeof(msgid), "<%d.%ld.%%d@%s>\n",
                                (int) getpid(), (long) clock, LocalName());
                partno = 0;
 -              msgfmt = getcpy(msgid);
 +              msgfmt = mh_xstrdup(msgid);
        }
        snprintf(msgid, sizeof(msgid), msgfmt, top ? 0 : ++partno);
 -      ct->c_id = getcpy(msgid);
 +      ct->c_id = mh_xstrdup(msgid);
  }
  
  
@@@ -1071,7 -1062,7 +1062,7 @@@ compose_content(CT ct
                        CT p = part->mp_part;
  
                        sprintf(pp, "%d", partnum);
 -                      p->c_partno = getcpy(partnam);
 +                      p->c_partno = mh_xstrdup(partnam);
                        if (compose_content(p) == NOTOK)
                                return NOTOK;
                }
                        if (tfile == NULL) {
                                adios(EX_CANTCREAT, "mhbuild", "unable to create temporary file");
                        }
 -                      ce->ce_file = getcpy(tfile);
 +                      ce->ce_file = mh_xstrdup(tfile);
                        ce->ce_unlink = 1;
  
                        xstdout = 0;
@@@ -1389,7 -1380,7 +1380,7 @@@ scan_content(CT ct
                                                NULL);
                        } else {
                                t->tx_charset = CHARSET_USASCII;
 -                              *ap = getcpy("charset=us-ascii");
 +                              *ap = mh_xstrdup("charset=us-ascii");
                        }
  
                        cp = strchr(*ap++, '=');
@@@ -1451,7 -1442,7 +1442,7 @@@ build_headers(CT ct
                ep = ci->ci_values;
                snprintf(buffer, sizeof(buffer), "boundary=%s%d",
                                prefix, level++);
 -              cp = strchr(*ap++ = getcpy(buffer), '=');
 +              cp = strchr(*ap++ = mh_xstrdup(buffer), '=');
                *ap = NULL;
                *cp++ = '\0';
                *ep = cp;
        /*
        ** output the content type and subtype
        */
 -      np = getcpy(TYPE_FIELD);
 +      np = mh_xstrdup(TYPE_FIELD);
        vp = concat(" ", ci->ci_type, "/", ci->ci_subtype, NULL);
  
        /* keep track of length of line */
        ** output the Content-ID
        */
        if (ct->c_id) {
 -              np = getcpy(ID_FIELD);
 +              np = mh_xstrdup(ID_FIELD);
                vp = concat(" ", ct->c_id, NULL);
                add_header(ct, np, vp);
        }
        ** output the Content-Description
        */
        if (ct->c_descr) {
 -              np = getcpy(DESCR_FIELD);
 +              np = mh_xstrdup(DESCR_FIELD);
                vp = concat(" ", ct->c_descr, NULL);
                if (encode_rfc2047(DESCR_FIELD, &vp, NULL)) {
                        adios(EX_DATAERR, NULL, "Unable to encode %s header", DESCR_FIELD);
        ** output the Content-Disposition
        */
        if (ct->c_dispo) {
 -              np = getcpy(DISPO_FIELD);
 +              np = mh_xstrdup(DISPO_FIELD);
                vp = concat(" ", ct->c_dispo, NULL);
                add_header(ct, np, vp);
        }
                if (ct->c_type == CT_MESSAGE)
                        adios(EX_DATAERR, NULL, "internal error, invalid encoding");
  
 -              np = getcpy(ENCODING_FIELD);
 +              np = mh_xstrdup(ENCODING_FIELD);
                vp = concat(" ", "8bit", "\n", NULL);
                add_header(ct, np, vp);
                break;
                if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART)
                        adios(EX_DATAERR, NULL, "internal error, invalid encoding");
  
 -              np = getcpy(ENCODING_FIELD);
 +              np = mh_xstrdup(ENCODING_FIELD);
                vp = concat(" ", "quoted-printable", "\n", NULL);
                add_header(ct, np, vp);
                break;
                if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART)
                        adios(EX_DATAERR, NULL, "internal error, invalid encoding");
  
 -              np = getcpy(ENCODING_FIELD);
 +              np = mh_xstrdup(ENCODING_FIELD);
                vp = concat(" ", "base64", "\n", NULL);
                add_header(ct, np, vp);
                break;
                if (ct->c_type == CT_MESSAGE)
                        adios(EX_DATAERR, NULL, "internal error, invalid encoding");
  
 -              np = getcpy(ENCODING_FIELD);
 +              np = mh_xstrdup(ENCODING_FIELD);
                vp = concat(" ", "binary", "\n", NULL);
                add_header(ct, np, vp);
                break;
diff --combined uip/mhl.c
+++ b/uip/mhl.c
@@@ -369,7 -369,7 +369,7 @@@ mhl_format(char *file, int width
                                int n = 0;
  
                                /* split the fields */
 -                              tmparray = brkstring(getcpy(++parptr), ",",
 +                              tmparray = brkstring(mh_xstrdup(++parptr), ",",
                                                NULL);
                                /*
                                ** copy pointers to split fields
                        if (!c1->c_fstr && global.c_fstr) {
                                if ((c1->c_flags & DATEFMT) &&
                                                (global.c_flags & DATEFMT)) {
 -                                      c1->c_fstr = getcpy(global.c_fstr);
 +                                      c1->c_fstr = mh_xstrdup(global.c_fstr);
                                } else if ((c1->c_flags & ADDRFMT) &&
                                                (global.c_flags & ADDRFMT)) {
 -                                      c1->c_fstr = getcpy(global.c_fstr);
 +                                      c1->c_fstr = mh_xstrdup(global.c_fstr);
                                }
                        }
                        continue;
@@@ -458,8 -458,8 +458,8 @@@ evalvar(struct mcomp *c1
                        return 1;
                cp = concat("=", cp, NULL);
                fmtstr = new_fs(cp, NULL);
 -              free(cp);
 -              c1->c_fstr = getcpy(fmtstr);
 +              mh_free0(&cp);
 +              c1->c_fstr = mh_xstrdup(fmtstr);
                c1->c_flags |= FORMAT;
                return 0;
        }
                char *fmtstr;
  
                fmtstr = new_fs("=%(decode{text})", NULL);
 -              c1->c_fstr = getcpy(fmtstr);
 +              c1->c_fstr = mh_xstrdup(fmtstr);
                c1->c_flags |= FORMAT;
                return 0;
        }
@@@ -530,7 -530,7 +530,7 @@@ ptos(char *name, char **s
        }
        c = *parptr;
        *parptr = 0;
 -      *s = getcpy(cp);
 +      *s = mh_xstrdup(cp);
        if ((*parptr = c) == '"')
                parptr++;
        return 0;
@@@ -586,7 -586,8 +586,7 @@@ process(char *fname, int ofilen, int of
        if (fp != stdin)
                fclose(fp);
        if (holder.c_text) {
 -              free(holder.c_text);
 -              holder.c_text = NULL;
 +              mh_free0(&(holder.c_text));
        }
        free_queue(&msghd, &msgtl);
        for (c1 = fmthd; c1; c1 = c1->c_next)
  static void
  mhlfile(FILE *fp, char *mname, int ofilen, int ofilec)
  {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        struct mcomp *c1, *c2, *c3;
-       char **ip, name[NAMESZ], buf[BUFSIZ];
+       char **ip;
  
        if (forwall) {
                printf("\n-------");
-               if (ofilen == 1)
+               if (ofilen == 1) {
                        printf(" Forwarded Message%s", ofilec > 1 ? "s" : "");
-               else
+               } else {
                        printf(" Message %d", ofilen);
+               }
                printf("\n\n");
        } else if (ofilec > 1) {
                if (ofilen > 1) {
                printf(">>> %s\n\n", mname);
        }
  
-       for (state = FLD;!eflag;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), fp)) {
-               case FLD:
-               case FLDPLUS:
+       for (state = FLD2; !eflag; ) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
                        for (ip = ignores; *ip; ip++)
-                               if (!mh_strcasecmp(name, *ip)) {
-                                       while (state == FLDPLUS)
-                                               state = m_getfld(state, name, buf, sizeof(buf), fp);
+                               if (mh_strcasecmp(f.name, *ip)==0) {
                                        break;
                                }
-                       if (*ip)
+                       if (*ip) {
                                continue;
+                       }
  
                        for (c2 = fmthd; c2; c2 = c2->c_next)
-                               if (!mh_strcasecmp(c2->c_name, name))
+                               if (mh_strcasecmp(c2->c_name, f.name)==0) {
                                        break;
+                               }
                        c1 = NULL;
                        if (!((c3 = c2 ? c2 : &global)->c_flags & SPLIT))
                                for (c1 = msghd; c1; c1 = c1->c_next)
-                                       if (!mh_strcasecmp(c1->c_name,
-                                                       c3->c_name)) {
-                                               c1->c_text = mcomp_add(c1->c_flags, buf, c1->c_text);
+                                       if (mh_strcasecmp(c1->c_name,
+                                                       c3->c_name)==0) {
+                                               c1->c_text = mcomp_add(c1->c_flags, f.value, c1->c_text);
                                                break;
                                        }
-                       if (c1 == NULL)
-                               c1 = add_queue(&msghd, &msgtl, name, buf, 0);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), fp);
-                               c1->c_text = add(buf, c1->c_text);
+                       if (c1 == NULL) {
+                               c1 = add_queue(&msghd, &msgtl, f.name, f.value, 0);
                        }
-                       if (c2 == NULL)
+                       if (c2 == NULL) {
                                c1->c_flags |= EXTRA;
+                       }
                        continue;
  
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        column = 0;
                        for (c1 = fmthd; c1; c1 = c1->c_next) {
                                if (c1->c_flags & CLEARTEXT) {
                                        putcomp(c1, c1, ONECOMP);
                                        continue;
                                }
-                               if (!mh_strcasecmp(c1->c_name, "messagename")) {
+                               if (mh_strcasecmp(c1->c_name, "messagename")==0) {
                                        holder.c_text = concat("(Message ",
                                                        mname, ")\n", NULL);
                                        putcomp(c1, &holder, ONECOMP);
 -                                      free(holder.c_text);
 -                                      holder.c_text = NULL;
 +                                      mh_free0(&(holder.c_text));
                                        continue;
                                }
-                               if (!mh_strcasecmp(c1->c_name, "extras")) {
-                                       for (c2 = msghd; c2; c2 = c2->c_next)
-                                               if (c2->c_flags & EXTRA)
+                               if (mh_strcasecmp(c1->c_name, "extras")==0) {
+                                       for (c2 = msghd; c2; c2 = c2->c_next) {
+                                               if (c2->c_flags & EXTRA) {
                                                        putcomp(c1, c2, TWOCOMP);
+                                               }
+                                       }
                                        continue;
                                }
-                               if (dobody && !mh_strcasecmp(c1->c_name, "body")) {
-                                       holder.c_text = mh_xcalloc(sizeof(buf), sizeof(char));
-                                       strncpy(holder.c_text, buf, sizeof(buf));
-                                       while (state == BODY) {
+                               if (dobody && mh_strcasecmp(c1->c_name, "body")==0) {
 -                                      holder.c_text = getcpy(f.value);
++                                      holder.c_text = mh_xstrdup(f.value);
+                                       while (state == BODY2) {
                                                putcomp(c1, &holder, BODYCOMP);
-                                               state = m_getfld(state, name, holder.c_text, sizeof(buf), fp);
+                                               state = m_getfld2(state, &f, fp);
+                                               free(holder.c_text);
 -                                              holder.c_text = getcpy(f.value);
++                                              holder.c_text = mh_xstrdup(f.value);
                                        }
 -                                      free(holder.c_text);
 -                                      holder.c_text = NULL;
 +                                      mh_free0(&(holder.c_text));
                                        continue;
                                }
-                               for (c2 = msghd; c2; c2 = c2->c_next)
-                                       if (!mh_strcasecmp(c2->c_name,
-                                                       c1->c_name)) {
+                               for (c2 = msghd; c2; c2 = c2->c_next) {
+                                       if (mh_strcasecmp(c2->c_name,
+                                                       c1->c_name)==0) {
                                                putcomp(c1, c2, ONECOMP);
-                                               if (!(c1->c_flags & SPLIT))
+                                               if (!(c1->c_flags & SPLIT)) {
                                                        break;
+                                               }
                                        }
+                               }
                        }
                        return;
  
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        advise(NULL, "format error in message %s", mname);
                        exitstat++;
                        return;
@@@ -769,21 -776,21 +773,21 @@@ mcomp_format(struct mcomp *c1, struct m
  
                fmt_scan(c1->c_fmt, buffer, sizeof(buffer) - 1, dat);
                /* Don't need to append a newline, dctime() already did */
 -              c2->c_text = getcpy(buffer);
 +              c2->c_text = mh_xstrdup(buffer);
  
 -              free(ap);
 +              mh_free0(&ap);
                return;
        }
  
        (q = &pq)->pq_next = NULL;
        while ((cp = getname(ap))) {
 -              p = (struct pqpair *) mh_xcalloc((size_t) 1, sizeof(*p));
 +              p = mh_xcalloc(1, sizeof(*p));
  
                if ((mp = getm(cp, NULL, 0, AD_NAME, error)) == NULL) {
 -                      p->pq_text = getcpy(cp);
 -                      p->pq_error = getcpy(error);
 +                      p->pq_text = mh_xstrdup(cp);
 +                      p->pq_error = mh_xstrdup(error);
                } else {
 -                      p->pq_text = getcpy(mp->m_text);
 +                      p->pq_text = mh_xstrdup(mp->m_text);
                        mnfree(mp);
                }
                q = (q->pq_next = p);
                        c2->c_text = add(buffer, c2->c_text);
                }
  
 -              free(p->pq_text);
 +              mh_free0(&(p->pq_text));
                if (p->pq_error)
 -                      free(p->pq_error);
 +                      mh_free0(&(p->pq_error));
                q = p->pq_next;
 -              free((char *) p);
 +              mh_free0(&p);
        }
  
        c2->c_text = add("\n", c2->c_text);
@@@ -824,15 -831,15 +828,15 @@@ add_queue(struct mcomp **head, struct m
  {
        struct mcomp *c1;
  
 -      c1 = (struct mcomp *) mh_xcalloc((size_t) 1, sizeof(*c1));
 +      c1 = mh_xcalloc(1, sizeof(*c1));
  
        c1->c_flags = flags & ~INIT;
 -      if ((c1->c_name = name ? getcpy(name) : NULL))
 +      if ((c1->c_name = name ? mh_xstrdup(name) : NULL))
                c1->c_flags |= mcomp_flags(c1->c_name);
 -      c1->c_text = text ? getcpy(text) : NULL;
 +      c1->c_text = text ? mh_xstrdup(text) : NULL;
        if (flags & INIT) {
                if (global.c_ovtxt)
 -                      c1->c_ovtxt = getcpy(global.c_ovtxt);
 +                      c1->c_ovtxt = mh_xstrdup(global.c_ovtxt);
                c1->c_offset = global.c_offset;
                c1->c_ovoff = global. c_ovoff;
                c1->c_width = 0;
@@@ -857,16 -864,16 +861,16 @@@ free_queue(struct mcomp **head, struct 
        for (c1 = *head; c1; c1 = c2) {
                c2 = c1->c_next;
                if (c1->c_name)
 -                      free(c1->c_name);
 +                      mh_free0(&(c1->c_name));
                if (c1->c_text)
 -                      free(c1->c_text);
 +                      mh_free0(&(c1->c_text));
                if (c1->c_ovtxt)
 -                      free(c1->c_ovtxt);
 +                      mh_free0(&(c1->c_ovtxt));
                if (c1->c_fstr)
 -                      free(c1->c_fstr);
 +                      mh_free0(&(c1->c_fstr));
                if (c1->c_fmt)
 -                      free((char *) c1->c_fmt);
 -              free((char *) c1);
 +                      mh_free0(&(c1->c_fmt));
 +              mh_free0(&c1);
        }
  
        *head = *tail = NULL;
diff --combined uip/mhparse.c
@@@ -166,7 -166,7 +166,7 @@@ parse_mime(char *file
                        advise("mhparse", "unable to create temporary file");
                        return NULL;
                }
 -              file = getcpy(tfile);
 +              file = mh_xstrdup(tfile);
                chmod(file, 0600);
  
                while (fgets(buffer, sizeof(buffer), stdin))
  static CT
  get_content(FILE *in, char *file, int toplevel)
  {
-       int compnum, state;
-       char buf[BUFSIZ], name[NAMESZ];
-       char *np, *vp;
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
        CT ct;
        HF hp;
  
        /* allocate the content structure */
 -      ct = (CT) mh_xcalloc(1, sizeof(*ct));
 +      ct = mh_xcalloc(1, sizeof(*ct));
  
        ct->c_fp = in;
 -      ct->c_file = getcpy(file);
 +      ct->c_file = mh_xstrdup(file);
        ct->c_begin = ftell(ct->c_fp) + 1;
  
        /*
        ** Parse the header fields for this
        ** content into a linked list.
        */
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
+       for (compnum = 1, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        compnum++;
  
-                       /* get copies of the buffers */
-                       np = mh_xstrdup(name);
-                       vp = mh_xstrdup(buf);
-                       /* if necessary, get rest of field */
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               vp = add(buf, vp);  /* add to previous value */
-                       }
-                       /* Now add the header data to the list */
-                       add_header(ct, np, vp);
+                       /* add the header data to the list */
 -                      add_header(ct, getcpy(f.name), getcpy(f.value));
++                      add_header(ct, mh_xstrdup(f.name), mh_xstrdup(f.value));
  
                        ct->c_begin = ftell(in) + 1;
                        continue;
  
-               case BODY:
-                       ct->c_begin = ftell(in) - strlen(buf);
+               case BODY2:
+                       ct->c_begin = ftell(in) - strlen(f.value);
                        break;
  
-               case FILEEOF:
+               case FILEEOF2:
                        ct->c_begin = ftell(in);
                        break;
  
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);
  
                default:
                        adios(EX_SOFTWARE, NULL, "getfld() returned %d", state);
                }
-               /* break out of the loop */
                break;
        }
  
                                advise(NULL, "message %s has multiple %s: fields", ct->c_file, VRSN_FIELD);
                                goto next_header;
                        }
 -                      ct->c_vrsn = getcpy(hp->value);
 +                      ct->c_vrsn = mh_xstrdup(hp->value);
  
                        /* Now, cleanup this field */
                        cp = ct->c_vrsn;
                        }
  
                        /* get copy of this field */
 -                      ct->c_celine = cp = getcpy(hp->value);
 +                      ct->c_celine = cp = mh_xstrdup(hp->value);
  
                        while (isspace(*cp))
                                cp++;
@@@ -475,7 -462,7 +462,7 @@@ add_header(CT ct, char *name, char *val
        HF hp;
  
        /* allocate header field structure */
 -      hp = mh_xmalloc(sizeof(*hp));
 +      hp = mh_xcalloc(1, sizeof(*hp));
  
        /* link data into header structure */
        hp->name = name;
@@@ -530,24 -517,24 +517,24 @@@ incl_name_value(unsigned char *buf, cha
                        ** Insert at first semicolon, if any.
                        ** If none, append to end.
                        */
 -                      prefix = getcpy(buf);
 +                      prefix = mh_xstrdup(buf);
                        if ((cp = strchr(prefix, ';'))) {
                                suffix = concat(cp, NULL);
                                *cp = '\0';
                                newbuf = concat(prefix, insertion, suffix,
                                                "\n", NULL);
 -                              free(suffix);
 +                              mh_free0(&suffix);
                        } else {
                                /* Append to end. */
                                newbuf = concat(buf, insertion, "\n", NULL);
                        }
  
 -                      free(prefix);
 -                      free(insertion);
 -                      free(buf);
 +                      mh_free0(&prefix);
 +                      mh_free0(&insertion);
 +                      mh_free0(&buf);
                }
  
 -              free(name_plus_equal);
 +              mh_free0(&name_plus_equal);
        }
  
        return newbuf;
@@@ -565,7 -552,7 +552,7 @@@ extract_name_value(char *name_suffix, c
        char *name_suffix_equals = strstr(value, name_suffix_plus_quote);
        char *cp;
  
 -      free(name_suffix_plus_quote);
 +      mh_free0(&name_suffix_plus_quote);
        if (name_suffix_equals) {
                char *name_suffix_begin;
  
                for (; *cp != '"'; ++cp)
                        ;
  
 -              extracted_name_value = mh_xmalloc(cp - name_suffix_begin + 1);
 +              extracted_name_value = mh_xcalloc(cp - name_suffix_begin + 1, sizeof(char));
                memcpy(extracted_name_value, name_suffix_begin,
                                cp - name_suffix_begin);
                extracted_name_value[cp - name_suffix_begin] = '\0';
@@@ -603,7 -590,7 +590,7 @@@ get_ctinfo(unsigned char *cp, CT ct, in
        i = strlen(invo_name) + 2;
  
        /* store copy of Content-Type line */
 -      cp = ct->c_ctline = getcpy(cp);
 +      cp = ct->c_ctline = mh_xstrdup(cp);
  
        while (isspace(*cp))  /* trim leading spaces */
                cp++;
        for (dp = cp; istoken(*dp); dp++)
                continue;
        c = *dp, *dp = '\0';
 -      ci->ci_type = getcpy(cp);  /* store content type */
 +      ci->ci_type = mh_xstrdup(cp);  /* store content type */
        *dp = c, cp = dp;
  
        if (!*ci->ci_type) {
  
        if (*cp != '/') {
                if (!magic)
 -                      ci->ci_subtype = getcpy("");
 +                      ci->ci_subtype = mh_xstrdup("");
                goto magic_skip;
        }
  
        for (dp = cp; istoken(*dp); dp++)
                continue;
        c = *dp, *dp = '\0';
 -      ci->ci_subtype = getcpy(cp);  /* store the content subtype */
 +      ci->ci_subtype = mh_xstrdup(cp);  /* store the content subtype */
        *dp = c, cp = dp;
  
        if (!*ci->ci_subtype) {
@@@ -720,7 -707,7 +707,7 @@@ magic_skip
                        return NOTOK;
                }
  
 -              vp = (*ap = getcpy(cp)) + (up - cp);
 +              vp = (*ap = mh_xstrdup(cp)) + (up - cp);
                *vp = '\0';
                for (dp++; isspace(*dp);)
                        dp++;
@@@ -777,7 -764,8 +764,7 @@@ bad_quote
        */
        if (magic && *cp == '<') {
                if (ct->c_id) {
 -                      free(ct->c_id);
 -                      ct->c_id = NULL;
 +                      mh_free0(&(ct->c_id));
                }
                if (!(dp = strchr(ct->c_id = ++cp, '>'))) {
                        advise(NULL, "invalid ID in message %s", ct->c_file);
        */
        if (*cp) {
                if (magic) {
 -                      ci->ci_magic = getcpy(cp);
 +                      ci->ci_magic = mh_xstrdup(cp);
  
                        /*
                        ** If there is a Content-Disposition header and
@@@ -924,9 -912,9 +911,9 @@@ invalid
        if (istype) {
                if ((dp = ci->ci_comment)) {
                        ci->ci_comment = concat(dp, " ", buffer, NULL);
 -                      free(dp);
 +                      mh_free0(&dp);
                } else {
 -                      ci->ci_comment = getcpy(buffer);
 +                      ci->ci_comment = mh_xstrdup(buffer);
                }
        }
  
@@@ -975,7 -963,7 +962,7 @@@ InitText(CT ct
        ct->c_subtype = kv->kv_value;
  
        /* allocate text character set structure */
 -      t = (struct text *) mh_xcalloc(1, sizeof(*t));
 +      t = mh_xcalloc(1, sizeof(*t));
        ct->c_ctparams = (void *) t;
  
        /* scan for charset parameter */
        /* check if content specified a character set */
        if (*ap) {
                /* store its name */
 -              ct->c_charset = getcpy(norm_charmap(*ep));
 +              ct->c_charset = mh_xstrdup(norm_charmap(*ep));
                /* match character set or set to CHARSET_UNKNOWN */
                for (kv = Charset; kv->kv_key; kv++) {
                        if (!mh_strcasecmp(*ep, kv->kv_key)) {
@@@ -1056,7 -1044,7 +1043,7 @@@ InitMultiPart(CT ct
        }
  
        /* allocate primary structure for multipart info */
 -      m = (struct multipart *) mh_xcalloc(1, sizeof(*m));
 +      m = mh_xcalloc(1, sizeof(*m));
        ct->c_ctparams = (void *) m;
  
        /* check if boundary parameter contains only whitespace characters */
                        if (strcmp(buffer + 2, m->mp_start)!=0)
                                continue;
  next_part:
 -                      part = (struct part *) mh_xcalloc(1, sizeof(*part));
 +                      part = mh_xcalloc(1, sizeof(*part));
                        *next = part;
                        next = &part->mp_next;
  
@@@ -1142,7 -1130,7 +1129,7 @@@ end_part
                                continue;
                        *next = NULL;
                        free_content(p);
 -                      free((char *) part);
 +                      mh_free0(&part);
                }
        }
  
@@@ -1173,7 -1161,7 +1160,7 @@@ last_part
                        p = part->mp_part;
  
                        sprintf(pp, "%d", partnum);
 -                      p->c_partno = getcpy(partnam);
 +                      p->c_partno = mh_xstrdup(partnam);
  
                        /* initialize the content of the subparts */
                        if (p->c_ctinitfnx && (*p->c_ctinitfnx) (p) == NOTOK) {
@@@ -1213,7 -1201,7 +1200,7 @@@ reverse_parts(CT ct
                i++;
  
        /* allocate array of pointers to the parts */
 -      base = (struct part **) mh_xcalloc((size_t) (i + 1), sizeof(*base));
 +      base = mh_xcalloc(i + 1, sizeof(*base));
        bmp = base;
  
        /* point at all the parts */
        *next = NULL;
  
        /* free array of pointers */
 -      free((char *) base);
 +      mh_free0(&base);
  }
  
  
@@@ -1269,7 -1257,7 +1256,7 @@@ InitMessage(CT ct
                char **ap, **ep;
                struct partial *p;
  
 -              p = (struct partial *) mh_xcalloc(1, sizeof(*p));
 +              p = mh_xcalloc(1, sizeof(*p));
                ct->c_ctparams = (void *) p;
  
                /*
                */
                for (ap = ci->ci_attrs, ep = ci->ci_values; *ap; ap++, ep++) {
                        if (!mh_strcasecmp(*ap, "id")) {
 -                              p->pm_partid = getcpy(*ep);
 +                              p->pm_partid = mh_xstrdup(*ep);
                                continue;
                        }
                        if (!mh_strcasecmp(*ap, "number")) {
@@@ -1381,7 -1369,7 +1368,7 @@@ init_encoding(CT ct, OpenCEFunc openfnx
  {
        CE ce;
  
 -      ce = (CE) mh_xcalloc(1, sizeof(*ce));
 +      ce = mh_xcalloc(1, sizeof(*ce));
  
        ct->c_cefile     = ce;
        ct->c_ceopenfnx  = openfnx;
@@@ -1511,10 -1499,10 +1498,10 @@@ openBase64(CT ct, char **file
        }
  
        if (*file == NULL) {
 -              ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL));
 +              ce->ce_file = mh_xstrdup(m_mktemp(tmp, NULL, NULL));
                ce->ce_unlink = 1;
        } else {
 -              ce->ce_file = getcpy(*file);
 +              ce->ce_file = mh_xstrdup(*file);
                ce->ce_unlink = 0;
        }
  
                        ** Temporary file already exists, so we rename to
                        ** version with extension.
                        */
 -                      char *file_org = strdup(ce->ce_file);
 +                      char *file_org = mh_xstrdup(ce->ce_file);
                        ce->ce_file = add(cp, ce->ce_file);
                        if (rename(file_org, ce->ce_file)) {
                                adios(EX_IOERR, ce->ce_file, "unable to rename %s to ",
                                                file_org);
                        }
 -                      free(file_org);
 +                      mh_free0(&file_org);
  
                } else {
                        ce->ce_file = add(cp, ce->ce_file);
@@@ -1722,10 -1710,10 +1709,10 @@@ openQuoted(CT ct, char **file
        }
  
        if (*file == NULL) {
 -              ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL));
 +              ce->ce_file = mh_xstrdup(m_mktemp(tmp, NULL, NULL));
                ce->ce_unlink = 1;
        } else {
 -              ce->ce_file = getcpy(*file);
 +              ce->ce_file = mh_xstrdup(*file);
                ce->ce_unlink = 0;
        }
  
                        ** Temporary file already exists, so we rename to
                        ** version with extension.
                        */
 -                      char *file_org = strdup(ce->ce_file);
 +                      char *file_org = mh_xstrdup(ce->ce_file);
                        ce->ce_file = add(cp, ce->ce_file);
                        if (rename(file_org, ce->ce_file)) {
                                adios(EX_IOERR, ce->ce_file, "unable to rename %s to ",
                                                file_org);
                        }
 -                      free(file_org);
 +                      mh_free0(&file_org);
  
                } else {
                        ce->ce_file = add(cp, ce->ce_file);
@@@ -1939,10 -1927,10 +1926,10 @@@ open7Bit(CT ct, char **file
        }
  
        if (*file == NULL) {
 -              ce->ce_file = getcpy(m_mktemp(tmp, NULL, NULL));
 +              ce->ce_file = mh_xstrdup(m_mktemp(tmp, NULL, NULL));
                ce->ce_unlink = 1;
        } else {
 -              ce->ce_file = getcpy(*file);
 +              ce->ce_file = mh_xstrdup(*file);
                ce->ce_unlink = 0;
        }
  
                        ** Temporary file already exists, so we rename to
                        ** version with extension.
                        */
 -                      char *file_org = strdup(ce->ce_file);
 +                      char *file_org = mh_xstrdup(ce->ce_file);
                        ce->ce_file = add(cp, ce->ce_file);
                        if (rename(file_org, ce->ce_file)) {
                                adios(EX_IOERR, ce->ce_file, "unable to rename %s to ",
                                                file_org);
                        }
 -                      free(file_org);
 +                      mh_free0(&file_org);
  
                } else {
                        ce->ce_file = add(cp, ce->ce_file);
diff --combined uip/new.c
+++ b/uip/new.c
@@@ -55,7 -55,7 +55,7 @@@ count_messages(char *field
        int j, k;
        char *cp, **ap;
  
 -      field = getcpy(field);
 +      field = mh_xstrdup(field);
  
        /* copied from seq_read.c:seq_init */
        for (ap = brkstring(field, " ", "\n"); *ap; ap++) {
@@@ -68,7 -68,7 +68,7 @@@
                }
        }
  
 -      free(field);
 +      mh_free0(&field);
  
        return total;
  }
@@@ -95,11 -95,10 +95,10 @@@ seq_in_list(char *name, char *sequences
  static char *
  get_msgnums(char *folder, char *sequences[])
  {
+       enum state state;
+       struct field f = {{0}};
        char *seqfile = concat(toabsdir(folder), "/", mh_seq, (void *)NULL);
        FILE *fp = fopen(seqfile, "r");
-       int state;
-       char name[NAMESZ], field[BUFSIZ];
-       char *cp;
        char *msgnums = NULL, *this_msgnums, *old_msgnums;
  
        /* no sequences file -> no messages */
                return NULL;
        }
  
-       /* copied from seq_read.c:seq_public */
-       for (state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               fp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (state == FLDPLUS) {
-                               cp = mh_xstrdup(field);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, name, field,
-                                                       sizeof(field), fp);
-                                       cp = add(field, cp);
-                               }
-                               /*
-                               ** Here's where we differ from
-                               ** seq_public: if it's in a
-                               ** sequence we want, save the list
-                               ** of messages.
-                               */
-                               if (seq_in_list(name, sequences)) {
-                                       this_msgnums = trimcpy(cp);
-                                       if (msgnums == NULL) {
-                                               msgnums = this_msgnums;
-                                       } else {
-                                               old_msgnums = msgnums;
-                                               msgnums = concat(old_msgnums, " ", this_msgnums, (void *)NULL);
-                                               mh_free0(&old_msgnums);
-                                               mh_free0(&this_msgnums);
-                                       }
-                               }
-                               mh_free0(&cp);
-                       } else {
-                               /* and here */
-                               if (seq_in_list(name, sequences)) {
-                                       this_msgnums = trimcpy(field);
-                                       if (msgnums == NULL) {
-                                               msgnums = this_msgnums;
-                                       } else {
-                                               old_msgnums = msgnums;
-                                               msgnums = concat(old_msgnums, " ", this_msgnums, (void *)NULL);
-                                               mh_free0(&old_msgnums);
-                                               mh_free0(&this_msgnums);
-                                       }
+       for (state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
+                       /*
+                       ** if it's in a sequence we want,
+                       ** save the list of messages.
+                       */
+                       if (seq_in_list(f.name, sequences)) {
+                               this_msgnums = trimcpy(f.value);
+                               if (msgnums == NULL) {
+                                       msgnums = this_msgnums;
+                               } else {
+                                       old_msgnums = msgnums;
+                                       msgnums = concat(old_msgnums, " ",
+                                                       this_msgnums,
 -                                                      (void *)NULL);
 -                                      free(old_msgnums);
 -                                      free(this_msgnums);
++                                                      NULL);
++                                      mh_free0(&old_msgnums);
++                                      mh_free0(&this_msgnums);
                                }
                        }
                        continue;
  
-               case BODY:
-                       adios(EX_DATAERR, NULL, "no blank lines are permitted in %s",
-                                       seqfile);
-                       /* fall */
+               case BODY2:
+                       adios(EX_DATAERR, NULL, "no blank lines are permitted in %s", seqfile);
+                       /* FALL */
  
-               case FILEEOF:
+               case FILEEOF2:
                        break;
  
                default:
                        adios(EX_SOFTWARE, NULL, "%s is poorly formatted", seqfile);
                }
-               break;  /* break from for loop */
+               break;
        }
  
        fclose(fp);
@@@ -187,9 -158,9 +158,9 @@@ check_folder(char *folder, size_t len, 
  
        if (is_cur || msgnums != NULL) {
                if (*b->first == NULL) {
 -                      *b->first = b->node = mh_xmalloc(sizeof(*b->node));
 +                      *b->first = b->node = mh_xcalloc(1, sizeof(*b->node));
                } else {
 -                      b->node->n_next = mh_xmalloc(sizeof(*b->node));
 +                      b->node->n_next = mh_xcalloc(1, sizeof(*b->node));
                        b->node = b->node->n_next;
                }
                b->node->n_name = folder;
@@@ -258,7 -229,7 +229,7 @@@ check_folders(struct node **first, stru
                while (vfgets(fp, &line) == OK) {
                        len = strlen(line) - 1;
                        line[len] = '\0';
 -                      check_folder(getcpy(line), len, &b);
 +                      check_folder(mh_xstrdup(line), len, &b);
                }
                fclose(fp);
        }
@@@ -280,7 -251,7 +251,7 @@@ join_sequences(char *sequences[]
        for (i = 0; sequences[i] != NULL; i++) {
                len += strlen(sequences[i]) + 1;
        }
 -      result = mh_xmalloc(len + 1);
 +      result = mh_xcalloc(len + 1, sizeof(char));
  
        for (i = 0, cp = result; sequences[i] != NULL; i++, cp += len + 1) {
                len = strlen(sequences[i]);
@@@ -514,7 -485,7 +485,7 @@@ main(int argc, char **argv
                } else {
                        unseen = seq_unseen;  /* use default */
                }
 -              dp = getcpy(unseen);
 +              dp = mh_xstrdup(unseen);
                for (ap = brkstring(dp, " ", "\n"); *ap; ap++) {
                        sequences[i++] = *ap;
                }
diff --combined uip/pick.c
@@@ -197,7 -197,7 +197,7 @@@ main(int argc, char **argv
                        if (folder)
                                adios(EX_USAGE, NULL, "only one folder at a time!");
                        else
 -                              folder = getcpy(expandfol(cp));
 +                              folder = mh_xstrdup(expandfol(cp));
                } else
                        app_msgarg(&msgs, cp);
        }
@@@ -731,7 -731,7 +731,7 @@@ pattern: 
                        padvise(NULL, "pattern error in %s %s", argp[-2], cp);
                        return NULL;
                }
 -              n->n_patbuf = getcpy(dp);
 +              n->n_patbuf = mh_xstrdup(dp);
                return n;
  
        case PROTHR:
@@@ -768,7 -768,7 +768,7 @@@ newnexus(int (*action)()
  {
        struct nexus *p;
  
 -      p = (struct nexus *) mh_xcalloc((size_t) 1, sizeof *p);
 +      p = mh_xcalloc(1, sizeof *p);
  
        p->n_action = action;
        return p;
@@@ -1241,37 -1241,36 +1241,33 @@@ static in
  TWSaction(params)
  plist
  {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        char *bp;
        struct tws *tw;
  
        fseek(fp, start, SEEK_SET);
-       for (state = FLD, bp = NULL;;) {
-               switch (state = m_getfld(state, name, buf, sizeof buf, fp)) {
-               case FLD:
-               case FLDPLUS:
-                       if (bp != NULL) {
+       for (state = FLD2, bp = NULL;;) {
+               switch (state = m_getfld2(state, &f, fp)) {
+               case FLD2:
+                       if (bp) {
 -                              free(bp);
 -                              bp = NULL;
 +                              mh_free0(&bp);
                        }
-                       bp = mh_xstrdup(buf);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof buf, fp);
-                               bp = add(buf, bp);
-                       }
-                       if (!mh_strcasecmp(name, n->n_datef))
 -                      bp = getcpy(f.value);
++                      bp = mh_xstrdup(f.value);
+                       if (mh_strcasecmp(f.name, n->n_datef)==0) {
                                break;
+                       }
                        continue;
  
-               case BODY:
-               case FILEEOF:
-               case LENERR:
-               case FMTERR:
-                       if (state == LENERR || state == FMTERR)
-                               advise(NULL, "format error in message %d", msgnum);
-                       if (bp != NULL)
-                               mh_free0(&bp);
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+                       advise(NULL, "format error in message %d", msgnum);
+                       /* FALL */
+               case BODY2:
+               case FILEEOF2:
 -                      if (bp) {
 -                              free(bp);
 -                      }
++                      mh_free0(&bp);
                        return 0;
  
                default:
                        : (twsort(tw, &n->n_tws) < 0);
  
        if (bp != NULL)
 -              free(bp);
 +              mh_free0(&bp);
        return state;
  }
diff --combined uip/rcvdist.c
@@@ -85,7 -85,7 +85,7 @@@ main(int argc, char **argv
                                continue;
                        }
                }
 -              addrs = addrs ? add(cp, add(", ", addrs)) : getcpy(cp);
 +              addrs = addrs ? add(cp, add(", ", addrs)) : mh_xstrdup(cp);
        }
  
        if (!addrs) {
  
  /* very similar to routine in replsbr.c */
  
  static struct format *fmt;
  
  static int ncomps = 0;
- static char **compbuffers = 0;
- static struct comp **used_buf = 0;
  
  static int dat[5];
  
@@@ -156,10 -152,12 +152,12 @@@ static char *addrcomps[] = 
  static void
  rcvdistout(FILE *inb, char *form, char *addrs)
  {
-       int char_read = 0, format_len, i, state;
-       char *tmpbuf, **nxtbuf, **ap;
-       char *cp, *scanl, name[NAMESZ];
-       struct comp *cptr, **savecomp;
+       int char_read = 0, format_len, i;
+       enum state state;
+       struct field f = {{0}};
+       char **ap;
+       char *cp, *scanl;
+       struct comp *cptr;
        FILE *out;
  
        if (!(out = fopen(drft, "w"))) {
        cp = new_fs(form ? form : rcvdistcomps, NULL);
        format_len = strlen(cp);
        ncomps = fmt_compile(cp, &fmt) + 1;
-       nxtbuf = compbuffers = mh_xcalloc(ncomps, sizeof(char *));
-       savecomp = used_buf = mh_xcalloc(ncomps + 1, sizeof(struct comp *));
-       savecomp += ncomps + 1;
-       *--savecomp = 0;
-       for (i = ncomps; i--;) {
-               *nxtbuf++ = mh_xcalloc(SBUFSIZ, sizeof(char));
-       }
-       nxtbuf = compbuffers;
-       tmpbuf = *nxtbuf++;
  
        for (ap = addrcomps; *ap; ap++) {
                FINDCOMP(cptr, *ap);
        if (cptr) {
                cptr->c_text = addrs;
        }
-       state = FLD;
+       state = FLD2;
        while (1) {
-               state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
+               state = m_getfld2(state, &f, inb);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
-                       if ((cptr = wantcomp[CHASH(name)])) {
+               case FLD2:
+                       if ((cptr = wantcomp[CHASH(f.name)])) {
                                do {
-                                       if (mh_strcasecmp(name, cptr->c_name)!=0) {
+                                       if (mh_strcasecmp(f.name, cptr->c_name)!=0) {
                                                continue;
                                        }
-                                       char_read += msg_count;
+                                       char_read += strlen(f.value);
                                        if (!cptr->c_text) {
-                                               cptr->c_text = tmpbuf;
-                                               *--savecomp = cptr;
-                                               tmpbuf = *nxtbuf++;
 -                                              cptr->c_text = getcpy(f.value);
++                                              cptr->c_text = mh_xstrdup(f.value);
                                        } else {
                                                cp = cptr->c_text;
                                                i = strlen(cp) - 1;
                                                                cp = add("\t", cp);
                                                        }
                                                }
-                                               cptr->c_text = add(tmpbuf, cp);
-                                       }
-                                       while (state == FLDPLUS) {
-                                               state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
-                                               cptr->c_text = add(tmpbuf, cptr->c_text);
-                                               char_read += msg_count;
+                                               cptr->c_text = add(f.value, cp);
                                        }
                                        break;
                                } while ((cptr = cptr->c_next));
                        }
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, tmpbuf,
-                                               SBUFSIZ, inb);
-                       }
                        break;
  
-               case LENERR:
-               case FMTERR:
-               case BODY:
-               case FILEEOF:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+               case BODY2:
+               case FILEEOF2:
                        goto finished;
  
                default:
  finished: ;
  
        i = format_len + char_read + 256;
 -      scanl = mh_xmalloc((size_t) i + 2);
 +      scanl = mh_xcalloc(i + 2, sizeof(char));
        dat[0] = dat[1] = dat[2] = dat[4] = 0;
        dat[3] = OUTPUTLINELEN;
        fmt_scan(fmt, scanl, i, dat);
        }
        fclose(out);
  
 -      free(scanl);
 +      mh_free0(&scanl);
-       for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++);
-                       nxtbuf++, i--) {
-               mh_free0(&(cptr->c_text));
-       }
-       while (i-- > 0) {
-               mh_free0(nxtbuf++);
-       }
-       mh_free0(&compbuffers);
-       mh_free0(&used_buf);
  }
  
  
diff --combined uip/rcvstore.c
@@@ -7,7 -7,6 +7,7 @@@
  */
  
  #include <h/mh.h>
 +#include <h/utils.h>
  #include <fcntl.h>
  #include <h/signals.h>
  #include <errno.h>
@@@ -50,6 -49,7 +50,7 @@@ static struct swit switches[] = 
  static char *tmpfilenam = NULL;
  
  void unlink_done();
+ static void fix_mbox(int out, char *ofile);
  
  int
  main(int argc, char **argv)
                        if (folder)
                                adios(EX_USAGE, NULL, "only one folder at a time!");
                        else
 -                              folder = getcpy(expandfol(cp));
 +                              folder = mh_xstrdup(expandfol(cp));
                } else {
                        adios(EX_USAGE, NULL, "usage: %s [+folder] [switches]",
                                        invo_name);
        }
        chmod(tmpfilenam, m_gmprot());
  
+       /* check if incoming mail is in mbox-format */
+       fix_mbox(fd, tmpfilenam);
        /* copy the message from stdin into temp file */
        cpydata(fileno(stdin), fd, "standard input", tmpfilenam);
  
        return EX_OK;
  }
  
+ static void
+ fix_mbox(int out, char *outfile)
+ {
+       char mbox[5];
+       int ret;
+       if ((ret = read(fileno(stdin), mbox, sizeof(mbox))) != sizeof(mbox)) {
+               if (ret == -1) {
+                       adios(EX_IOERR, "standard input", "error reading");
+               }
+               return;
+       }
+       if (strncmp(mbox, "From ", sizeof(mbox))==0) {
+               do {
+                       if ((ret = read(fileno(stdin), mbox, 1)) != 1) {
+                               if (ret == -1) {
+                                       adios(EX_IOERR, "standard input", "error reading");
+                               }
+                               return;
+                       }
+               } while (*mbox != '\n');
+       } else {
+               if (write(out, mbox, sizeof(mbox)) != sizeof(mbox)) {
+                       adios(EX_IOERR, outfile, "error writing");
+               }
+       }
+ }
  /*
  ** Clean up and exit
  */
diff --combined uip/repl.c
@@@ -72,15 -72,6 +72,6 @@@ static struct swit ccswitches[] = 
        { NULL, 0 }
  };
  
- /*
- ** Buffer size for content part of header fields.
- ** We want this to be large enough so that we don't
- ** do a lot of extra FLDPLUS calls on m_getfld but
- ** small enough so that we don't snarf the entire
- ** message body when we're not going to use any of it.
- */
- #define SBUFSIZ 256
  static short ccto = -1;
  static short cccc = -1;
  static short ccme = -1;
@@@ -102,8 -93,6 +93,6 @@@ static struct mailname mq
  static struct format *fmt;
  
  static int ncomps = 0;  /* # of interesting components */
- static char **compbuffers = NULL;  /* buffers for component text */
- static struct comp **used_buf = NULL;  /* stack for comp that use buffers */
  
  static int dat[5];  /* aux. data for format routine */
  
@@@ -145,14 -134,14 +134,14 @@@ main(int argc, char **argv
        FILE *in;
        int buildsw = 0;
  
 -      filter = getcpy(etcpath(mhlreply));
 -
        setlocale(LC_ALL, "");
        invo_name = mhbasename(argv[0]);
  
        /* read user profile/context */
        context_read();
  
 +      filter = mh_xstrdup(etcpath(mhlreply));
 +
        arguments = getarguments(invo_name, argc, argv, 1);
        argp = arguments;
  
                                if (!(cp = *argp++) || *cp == '-')
                                        adios(EX_USAGE, NULL, "missing argument to %s",
                                                        argp[-2]);
 -                              file = getcpy(expanddir(cp));
 +                              file = mh_xstrdup(expanddir(cp));
                                continue;
                        case FORMSW:
                                if (!(form = *argp++) || *form == '-')
                                if (!(cp = *argp++) || *cp == '-')
                                        adios(EX_USAGE, NULL, "missing argument to %s",
                                                        argp[-2]);
 -                              filter = getcpy(etcpath(cp));
 +                              filter = mh_xstrdup(etcpath(cp));
                                continue;
                        case NFILTSW:
                                filter = NULL;
                        if (folder)
                                adios(EX_USAGE, NULL, "only one folder at a time!");
                        else
 -                              folder = getcpy(expandfol(cp));
 +                              folder = mh_xstrdup(expandfol(cp));
                } else {
                        if (msg)
                                adios(EX_USAGE, NULL, "only one message at a time!");
        if (ccme == -1)
                ccme = groupreply;
  
 -      cwd = getcpy(pwd());
 +      cwd = mh_xstrdup(pwd());
  
        if (file && (msg || folder))
                adios(EX_USAGE, NULL, "can't mix files and folders/msgs");
                context_save();  /* save the context file   */
        }
  
 -      msg = file ? file : getcpy(m_name(mp->lowsel));
 +      msg = file ? file : mh_xstrdup(m_name(mp->lowsel));
  
        if ((in = fopen(msg, "r")) == NULL)
                adios(EX_IOERR, msg, "unable to open");
@@@ -388,14 -377,13 +377,13 @@@ static voi
  replout(FILE *inb, char *drft, struct msgs *mp,
        int mime, char *form, char *filter)
  {
-       int state, i;
+       enum state state;
+       struct field f = {{0}};
+       int i;
        struct comp *cptr;
-       char *tmpbuf;
-       char **nxtbuf;
        char **ap;
-       struct comp **savecomp;
        int char_read = 0, format_len, mask;
-       char name[NAMESZ], *scanl;
+       char *scanl;
        unsigned char *cp;
        FILE *out;
  
        /* compile format string */
        ncomps = fmt_compile(cp, &fmt) + 1;
  
-       nxtbuf = compbuffers = mh_xcalloc(ncomps, sizeof(char *));
-       savecomp = used_buf = mh_xcalloc(ncomps+1, sizeof(struct comp *));
-       savecomp += ncomps + 1;
-       *--savecomp = NULL;  /* point at zero'd end minus 1 */
-       for (i = ncomps; i--; )
-               *nxtbuf++ = mh_xcalloc(SBUFSIZ, sizeof(char));
-       nxtbuf = compbuffers;  /* point at start */
-       tmpbuf = *nxtbuf++;
        for (ap = addrcomps; *ap; ap++) {
                FINDCOMP(cptr, *ap);
                if (cptr)
        if ((cp = getenv("USER"))) {
                FINDCOMP(cptr, "user");
                if (cptr)
 -                      cptr->c_text = getcpy(cp);
 +                      cptr->c_text = mh_xstrdup(cp);
        }
        if (!ccme)
                ismymbox(NULL);
        /*
        ** pick any interesting stuff out of msg "inb"
        */
-       for (state = FLD;;) {
-               state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb);
+       for (state = FLD2;;) {
+               state = m_getfld2(state, &f, inb);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
+               case FLD2:
                        /*
                        ** if we're interested in this component, save
                        ** a pointer to the component text, then start
                        ** temp buffer (buffer switching saves an extra
                        ** copy of the component text).
                        */
-                       if ((cptr = wantcomp[CHASH(name)]))
+                       if ((cptr = wantcomp[CHASH(f.name)])) {
                                do {
-                                       if (!mh_strcasecmp(name, cptr->c_name)) {
-                                               char_read += msg_count;
-                                               if (! cptr->c_text) {
-                                                       i = strlen(cptr->c_text = tmpbuf) - 1;
-                                                       if (tmpbuf[i] == '\n')
-                                                               tmpbuf[i] = '\0';
-                                                       *--savecomp = cptr;
-                                                       tmpbuf = *nxtbuf++;
-                                               } else {
-                                                       i = strlen(cp = cptr->c_text) - 1;
-                                                       if (cp[i] == '\n') {
-                                                               if (cptr->c_type & CT_ADDR) {
-                                                                       cp[i] = '\0';
-                                                                       cp = add(",\n\t", cp);
-                                                               } else {
-                                                                       cp = add("\t", cp);
-                                                               }
-                                                       }
-                                                       cptr->c_text = add(tmpbuf, cp);
+                                       if (mh_strcasecmp(f.name, cptr->c_name)!=0) {
+                                               continue;
+                                       }
+                                       char_read += strlen(f.value);
+                                       if (!cptr->c_text) {
 -                                              cptr->c_text = getcpy(f.value);
++                                              cptr->c_text = mh_xstrdup(f.value);
+                                               i = strlen(cptr->c_text) - 1;
+                                               if (cptr->c_text[i] == '\n') {
+                                                       cptr->c_text[i] = '\0';
                                                }
-                                               while (state == FLDPLUS) {
-                                                       state = m_getfld(state, name, tmpbuf,
-                                                                                         SBUFSIZ, inb);
-                                                       cptr->c_text = add(tmpbuf, cptr->c_text);
-                                                       char_read += msg_count;
+                                       } else {
+                                               cp = cptr->c_text;
+                                               i = strlen(cp) - 1;
+                                               if (cp[i] == '\n') {
+                                                       if (cptr->c_type & CT_ADDR) {
+                                                               cp[i] = '\0';
+                                                               cp = add(",\n\t", cp);
+                                                       } else {
+                                                               cp = add("\t", cp);
+                                                       }
                                                }
-                                               break;
+                                               cptr->c_text = add(f.value, cp);
                                        }
+                                       break;
                                } while ((cptr = cptr->c_next));
-                       while (state == FLDPLUS)
-                               state = m_getfld(state, name, tmpbuf,
-                                               SBUFSIZ, inb);
+                       }
                        break;
  
-               case LENERR:
-               case FMTERR:
-               case BODY:
-               case FILEEOF:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+               case BODY2:
+               case FILEEOF2:
                        goto finished;
  
                default:
@@@ -536,12 -506,12 +506,12 @@@ finished
                }
                if (sp != cptr->c_text) {
                        cp = cptr->c_text;
 -                      cptr->c_text = getcpy(sp);
 -                      free(cp);
 +                      cptr->c_text = mh_xstrdup(sp);
 +                      mh_free0(&cp);
                }
        }
        i = format_len + char_read + 256;
 -      scanl = mh_xmalloc((size_t) i + 2);
 +      scanl = mh_xcalloc(i + 2, sizeof(char));
        dat[0] = 0;
        dat[1] = 0;
        dat[2] = 0;
        }
  
        /* return dynamically allocated buffers */
 -      free(scanl);
 +      mh_free0(&scanl);
-       for (nxtbuf = compbuffers, i = ncomps; (cptr = *savecomp++);
-                       nxtbuf++, i--)
-               mh_free0(&(cptr->c_text));  /* if not nxtbuf, nxtbuf already freed */
-       while ( i-- > 0)
-               mh_free0(nxtbuf++);  /* free unused nxtbufs */
-       mh_free0(&compbuffers);
-       mh_free0(&used_buf);
  }
  
  static char *buf;  /* our current working buffer */
@@@ -625,7 -588,7 +588,7 @@@ static unsigned int bufsiz=0;  /* curre
  ** returns a pointer to the concatenated address string.
  **
  ** We try to not do a lot of malloc/copy/free's (which is why we
 -** don't call "getcpy") but still place no upper limit on the
 +** don't call "mh_xstrdup") but still place no upper limit on the
  ** length of the result string.
  **
  ** This routine is an override for the equally named one in sbr/fmt_addr.c.
@@@ -644,7 -607,7 +607,7 @@@ formataddr(char *orig, char *str
  
        /* if we don't have a buffer yet, get one */
        if (bufsiz == 0) {
 -              buf = mh_xmalloc(BUFINCR);
 +              buf = mh_xcalloc(BUFINCR, sizeof(char));
                last_dst = buf;  /* XXX */
                bufsiz = BUFINCR - 6;  /* leave some slop */
                bufend = buf + bufsiz;
@@@ -738,8 -701,7 +701,8 @@@ insert(struct mailname *np
  static void
  replfilter(FILE *in, FILE *out, char *filter)
  {
 -      int pid, n;
 +      int pid, pid_show, n;
 +      int mailpipe[2];
        char *errstr;
  
        if (filter == NULL)
        rewind(in);
        lseek(fileno(in), (off_t) 0, SEEK_SET);
  
 -      switch (pid = fork()) {
 +      if (pipe(mailpipe) == -1) {
 +              adios(EX_OSERR, "pipe", "can't create pipe");
 +      }
 +
 +      switch (pid_show = fork()) {
        case NOTOK:
                adios(EX_OSERR, "fork", "unable to");
  
        case OK:
                dup2(fileno(in), fileno(stdin));
 +              dup2(mailpipe[1], fileno(stdout));
 +              for (n=3; n<OPEN_MAX; n++) {
 +                      close(n);
 +              }
 +
 +              execlp("show", "show", "-file", "-", NULL);
 +
 +              adios(EX_OSERR, "exec", "unable to");
 +      }
 +
 +      switch (pid = fork()) {
 +      case NOTOK:
 +              adios(EX_OSERR, "fork", "unable to");
 +
 +      case OK:
 +              dup2(mailpipe[0], fileno(stdin));
                dup2(fileno(out), fileno(stdout));
                for (n=3; n<OPEN_MAX; n++) {
                        close(n);
                _exit(EX_OSERR);
  
        default:
 -              if (pidXwait(pid, "mhl"))
 +              if (pidXwait(-1, "show | mhl"))
                        exit(EX_SOFTWARE);
                fseek(out, 0L, SEEK_END);
                break;
        }
 +
 +      close(mailpipe[0]);
 +      close(mailpipe[1]);
  }
diff --combined uip/scan.c
@@@ -91,7 -91,7 +91,7 @@@ main(int argc, char **argv
                                        adios(EX_USAGE, NULL, "missing argument to %s",
                                                        argp[-2]);
                                if (strcmp(file = cp, "-")!=0)
 -                                      file = getcpy(expanddir(cp));
 +                                      file = mh_xstrdup(expanddir(cp));
                                continue;
                        }
                }
                        if (folder)
                                adios(EX_USAGE, NULL, "only one folder at a time!");
                        else
 -                              folder = getcpy(expandfol(cp));
 +                              folder = mh_xstrdup(expandfol(cp));
                } else
                        app_msgarg(&msgs, cp);
        }
  
 -      /*
 -      ** Get new format string.  Must be before chdir().
 -      */
 -      fmtstr = new_fs(form, FORMAT);
 +      /* Set format string.  Must be before chdir(). */
 +      fmtstr = new_fs(form, scanformat);
  
        /*
        ** We are scanning a maildrop file
                        adios(EX_IOERR, file, "unable to open");
                }
  
-               thisisanmbox(in);
                for (msgnum = 1; ; ++msgnum) {
                        state = scan(in, msgnum, SCN_MBOX, fmtstr, width, 0, 0);
                        if (state != SCNMSG)
        if (chdir(maildir) == NOTOK)
                adios(EX_OSERR, maildir, "unable to change directory to");
  
-       /* read folder and create message structure */
        if (!(mp = folder_read(folder)))
                adios(EX_IOERR, NULL, "unable to read folder %s", folder);
  
        for (msgnum = 0; msgnum < msgs.size; msgnum++)
                if (!m_convert(mp, msgs.msgs[msgnum]))
                        exit(EX_USAGE);
-       seq_setprev(mp);  /* set the Previous-Sequence */
+       seq_setprev(mp);
  
-       context_replace(curfolder, folder);  /* update current folder */
-       seq_save(mp);  /* synchronize message sequences */
-       context_save();  /* save the context file */
+       context_replace(curfolder, folder);
+       seq_save(mp);
+       context_save();
  
        /*
        ** Get the sequence number for each `unseen' sequence
        if (*cp) {
                char **ap, *dp;
  
 -              dp = getcpy(cp);
 +              dp = mh_xstrdup(cp);
                ap = brkstring(dp, " ", "\n");
                for (i = 0; ap && *ap; i++, ap++) {
                        seqnum[i] = seq_getnum(mp, *ap);
                }
                num_unseen_seq = i;
                if (dp) {
 -                      free(dp);
 +                      mh_free0(&dp);
                }
        }
  
        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
-               if (is_selected(mp, msgnum)) {
-                       if ((in = fopen(cp = m_name(msgnum), "r")) == NULL) {
-                               admonish(cp, "unable to open message");
-                               continue;
-                       }
+               if (!is_selected(mp, msgnum)) {
+                       continue;
+               }
  
-                       /*
-                       ** Check if message is in any sequence given
-                       ** by Unseen-Sequence profile entry.
-                       */
-                       unseen = 0;
-                       for (i = 0; i < num_unseen_seq; i++) {
-                               if (in_sequence(mp, seqnum[i], msgnum)) {
-                                       unseen = 1;
-                                       break;
-                               }
-                       }
+               if ((in = fopen(cp = m_name(msgnum), "r")) == NULL) {
+                       admonish(cp, "unable to open message");
+                       continue;
+               }
  
-                       switch (state = scan(in, msgnum, SCN_FOLD, fmtstr,
-                                       width, msgnum==mp->curmsg, unseen)) {
-                       case SCNMSG:
-                       case SCNERR:
+               /*
+               ** Check if message is in any sequence given
+               ** by Unseen-Sequence profile entry.
+               */
+               unseen = 0;
+               for (i = 0; i < num_unseen_seq; i++) {
+                       if (in_sequence(mp, seqnum[i], msgnum)) {
+                               unseen = 1;
                                break;
+                       }
+               }
  
-                       default:
-                               adios(EX_SOFTWARE, NULL, "scan() botch(%d)", state);
+               switch (state = scan(in, msgnum, SCN_FOLD, fmtstr,
+                               width, msgnum==mp->curmsg, unseen)) {
+               case SCNMSG:
+               case SCNERR:
+                       break;
  
-                       case SCNEOF:
-                               advise(NULL, "message %d: empty", msgnum);
-                               break;
-                       }
-                       fclose(in);
+               default:
+                       adios(EX_SOFTWARE, NULL, "scan() botch(%d)", state);
+               case SCNEOF:
+                       advise(NULL, "message %d: empty", msgnum);
+                       break;
                }
+               fclose(in);
        }
-       folder_free(mp);  /* free folder/message structure */
+       folder_free(mp);
  
        return 0;
  }
diff --combined uip/scansbr.c
  #include <sys/stat.h>
  #include <sysexits.h>
  
- #ifdef _FSTDIO
- # define _ptr _p  /* Gag */
- # define _cnt _w  /* Wretch */
- #endif
  #define MAXSCANL 256  /* longest possible scan line */
  
- /*
- ** Buffer size for content part of header fields.  We want this
- ** to be large enough so that we don't do a lot of extra FLDPLUS
- ** calls on m_getfld.
- */
- #define SBUFSIZ 512
  static struct format *fmt;
  
  static struct comp *datecomp;  /* pntr to "date" comp */
  static int ncomps = 0;  /* # of interesting components */
- static char **compbuffers = NULL;  /* buffers for component text */
- static struct comp **used_buf = NULL;  /* stack for comp that use buffers */
  
  static int dat[5];  /* aux. data for format routine */
  
@@@ -62,18 -48,18 +48,18 @@@ scan(FILE *inb, int innum, int outnum, 
        int unseen)
  {
        static int slwidth;
-       int i, compnum, state;
-       unsigned char *cp, *tmpbuf;
-       char **nxtbuf;
+       int compnum, i;
+       enum state state;
+       struct field f = {{0}};
+       char *cp;
        struct comp *cptr;
-       struct comp **savecomp;
        char *scnmsg = NULL;
        FILE *scnout = NULL;
-       char name[NAMESZ];
        int incing = (outnum != SCN_MBOX && outnum != SCN_FOLD);
        int scanfolder = (outnum == SCN_FOLD);
        long fpos;
        struct stat st;
+       int blankline;
  
        /* first-time only initialization */
        if (!scanl) {
@@@ -88,7 -74,8 +74,7 @@@
                                        width = MAXSCANL;
                        }
                        dat[3] = slwidth = width;
 -                      scanl = (char *) mh_xmalloc((size_t) SCAN_CHARWIDTH *
 -                                      (slwidth + 2));  /* probably for \n and \0 */
 +                      scanl = mh_xcalloc(slwidth + 2, SCAN_CHARWIDTH);  /* probably for \n and \0 */
                        /* Compile format string */
                        ncomps = fmt_compile(fmtstr, &fmt) + 1;
                        FINDCOMP(datecomp, "date");
                        ncomps = 1;
                        datecomp = NULL;
                }
+       }
  
-               nxtbuf = compbuffers = mh_xcalloc(ncomps, sizeof(char *));
-               used_buf = mh_xcalloc(ncomps+1, sizeof(struct comp *));
-               /* NULL-terminate array */
-               used_buf += ncomps;
-               *used_buf = NULL;
-               /* allocate space for the items */
-               for (i = ncomps; i--; )
-                       *nxtbuf++ = mh_xcalloc(SBUFSIZ, sizeof(char));
+       if (feof(inb)) {
+               return SCNEOF;
        }
  
        /*
        ** each-message initialization
        */
-       nxtbuf = compbuffers;
-       savecomp = used_buf;
-       tmpbuf = *nxtbuf++;
        dat[0] = innum ? innum : outnum;
        dat[1] = curflg;
        dat[4] = unseen;
        fpos = ftell(inb);
  
-       /*
-       ** Get the first field.  If the message is non-empty
-       ** and we're doing an "inc", open the output file.
-       */
-       if ((state = m_getfld(FLD, name, tmpbuf, SBUFSIZ, inb)) == FILEEOF) {
-               if (ferror(inb)) {
-                       advise("read", "unable to"); /* "read error" */
-                       return SCNFAT;
-               } else {
-                       return SCNEOF;
-               }
-       }
        if (incing) {
                scnmsg = m_name(outnum);
                if (*scnmsg == '?')  /* msg num out of range */
                if (!(scnout = fopen(scnmsg, "w")))
                        adios(EX_IOERR, scnmsg, "unable to write");
        }
        /* scan - main loop */
-       for (compnum = 1; ;
-                       state = m_getfld(state, name, tmpbuf, SBUFSIZ, inb)) {
+       for (compnum = 1, state = FLD2; ; ) {
+               state = m_getfld2(state, &f, inb);
                switch (state) {
-               case FLD:
-               case FLDPLUS:
+               case FLD2:
                        compnum++;
                        if (incing) {
-                               FPUTS(name);
+                               FPUTS(f.name);
                                FPUTS(":");
-                               FPUTS(tmpbuf);
+                               FPUTS(f.value);
                        }
-                       /*
-                       ** if we're interested in this component, save
-                       ** a pointer to the component text, then start
-                       ** using our next free buffer as the component
-                       ** temp buffer (buffer switching saves an extra
-                       ** copy of the component text).
-                       */
-                       if (fmtstr && (cptr = wantcomp[CHASH(name)])) {
+                       if (fmtstr && (cptr = wantcomp[CHASH(f.name)])) {
+                               /*
+                               ** we're interested in this component,
+                               ** but find the right one in the hash
+                               ** collision chain ...
+                               */
                                do {
-                                       if (mh_strcasecmp(name, cptr->c_name)!=0) {
+                                       if (mh_strcasecmp(f.name, cptr->c_name)!=0) {
                                                continue;
                                        }
-                                       if (!cptr->c_text) {
-                                               cptr->c_text = tmpbuf;
-                                               cp = tmpbuf+strlen(tmpbuf)-1;
-                                               for (; cp >= tmpbuf; cp--) {
-                                                       if (isspace(*cp))
-                                                               *cp = '\0';
-                                                       else
-                                                               break;
+                                       if (cptr->c_text) {
+                                               free(cptr->c_text);
+                                               cptr->c_text = NULL;
+                                       }
 -                                      cptr->c_text = getcpy(f.value);
++                                      cptr->c_text = mh_xstrdup(f.value);
+                                       cp = cptr->c_text + strlen(cptr->c_text) - 1;
+                                       for (; cp >= cptr->c_text; cp--) {
+                                               if (isspace(*cp)) {
+                                                       *cp = '\0';
+                                               } else {
+                                                       break;
                                                }
-                                               *--savecomp = cptr;
-                                               tmpbuf = *nxtbuf++;
                                        }
                                        break;
                                } while ((cptr = cptr->c_next));
                        }
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, tmpbuf, SBUFSIZ,
-                                               inb);
-                               if (incing)
-                                       FPUTS(tmpbuf);
-                       }
                        break;
  
-               case BODY:
+               case BODY2:
                        compnum = -1;
                        if (scanfolder) {
                                /* stop here if we scan a msg in a folder */
-                               state = FILEEOF;
+                               state = FILEEOF2;
                                goto finished;
                        }
                        /* otherwise (mbox): snarf the body */
+                       if (strncmp("From ", f.value, 5)==0) {
+                               state = FILEEOF2;
+                               goto finished;
+                       }
                        if (incing) {
                                FPUTS("\n");
-                               FPUTS(tmpbuf);
+                               FPUTS(f.value);
                        }
  body:;
-                       while (state == BODY) {
-                               state = m_getfld(state, name, tmpbuf, SBUFSIZ,
-                                               inb);
+                       blankline = 0;
+                       while ((state = m_getfld2(state, &f, inb)) == BODY2) {
+                               /*
+                               ** recognize From lines without blank lines
+                               ** before them as well.
+                               */
+                               if (strncmp("From ", f.value, 5)==0) {
+                                       state = FILEEOF2;
+                                       goto finished;
+                               }
+                               /*
+                               ** delay the printing of blank lines
+                               ** because if it's the end of the message,
+                               ** then we must omit the blank line,
+                               ** as it is not part of the message but
+                               ** part of the mbox format
+                               */
+                               if (blankline) {
+                                       /* print the delayed blank line */
+                                       FPUTS("\n");
+                                       blankline = 0;
+                               }
+                               if (strcmp(f.value, "\n")==0) {
+                                       blankline = 1;
+                                       continue;
+                               }
                                if (incing) {
-                                       FPUTS(tmpbuf);
+                                       FPUTS(f.value);
                                }
                        }
                        goto finished;
  
-               case LENERR:
-               case FMTERR:
-                       fprintf(stderr, innum ? "??Format error (message %d) in " : "??Format error in ", outnum ? outnum : innum);
+               case LENERR2:
+                       advise(NULL, "line \"%s\" too long", trim(f.value));
+                       goto handleerror;
+               case FMTERR2:
+                       if (strncmp("From ", f.value, 5)==0) {
+                               state = FILEEOF2;
+                               goto finished;
+                       }
+                       /* FALL */
+               case IOERR2:
+ handleerror:;
+                       fprintf(stderr, innum ?
+                                       "??Format error (message %d) in " :
+                                       "??Format error in ",
+                                       outnum ? outnum : innum);
                        fprintf(stderr, "component %d\n", compnum);
  
                        if (incing) {
                                FPUTS("\n\nBAD MSG:\n");
-                               FPUTS(name);
+                               FPUTS(f.name);  /* XXX use f.field? */
                                FPUTS("\n");
-                               state = BODY;
+                               state = BODY2;
                                goto body;
                        }
                        /* fall through if we scan only */
  
-               case FILEEOF:
+               case FILEEOF2:
                        goto finished;
  
                default:
        }
  
  finished:
        /* Format and output the scan line. */
        if (ferror(inb)) {
                advise("read", "unable to");
                if (datecomp && !datecomp->c_text) {
                        if (!datecomp->c_text) {
                                if (!datecomp->c_tws)
 -                                      datecomp->c_tws = (struct tws *) mh_xcalloc((size_t) 1, sizeof(*datecomp->c_tws));
 +                                      datecomp->c_tws = mh_xcalloc(1, sizeof(*datecomp->c_tws));
                                if (!datecomp->c_tws)
                                        adios(EX_OSERR, NULL, "unable to allocate tws buffer");
                                *datecomp->c_tws = *dlocaltime((time_t *) &st.st_mtime);
                fputs(scanl, stdout);
        }
  
-       /* return dynamically allocated buffers to pool */
-       while ((cptr = *savecomp++)) {
-               *--nxtbuf = cptr->c_text;
-               cptr->c_text = NULL;
+       /* clean up old values */
+         for (i=0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) {
+               for (cptr=wantcomp[i]; cptr; cptr=cptr->c_next) {
+                       if (cptr->c_text) {
+                               free(cptr->c_text);
+                               cptr->c_text = NULL;
+                       }
+               }
        }
-       *--nxtbuf = tmpbuf;
  
        if (incing && (ferror(scnout) || fclose(scnout) == EOF))
                adios(EX_IOERR, scnmsg, "write error on");
  
-       return (state != FILEEOF ? SCNERR : SCNMSG);
+       return (state == FILEEOF2 ? SCNMSG : SCNERR);
  }
diff --combined uip/slocal.c
@@@ -724,10 -724,10 +724,10 @@@ split(char *cp, char **vec
  static int
  parse(int fd)
  {
-       int i, state;
-       int fd1;
+       enum state state;
+       struct field f = {{0}};
+       int i, fd1;
        char *cp, *dp, *lp;
-       char name[NAMESZ], field[BUFSIZ];
        struct pair *p, *q;
        FILE  *in;
  
  
        /* add special entries to lookup table */
        if ((p = lookup(hdrs, "source"))) {
 -              p->p_value = getcpy(sender);
 +              p->p_value = mh_xstrdup(sender);
        }
        if ((p = lookup(hdrs, "addr"))) {
 -              p->p_value = getcpy(addr);
 +              p->p_value = mh_xstrdup(addr);
        }
  
        /*
        ** Scan the headers of the message and build a lookup table.
        */
-       for (i = 0, state = FLD;;) {
-               switch (state = m_getfld(state, name, field, sizeof(field),
-                               in)) {
-               case FLD:
-               case FLDPLUS:
-                       lp = mh_xstrdup(field);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, field,
-                                               sizeof(field), in);
-                               lp = add(field, lp);
-                       }
+       for (i = 0, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
 -                      lp = getcpy(f.value);
++                      lp = mh_xstrdup(f.value);
                        for (p = hdrs; p->p_name; p++) {
-                               if (mh_strcasecmp(p->p_name, name)!=0) {
+                               if (mh_strcasecmp(p->p_name, f.name)!=0) {
                                        if (!(p->p_flags & P_HID)) {
                                                if ((cp = p->p_value)) {
                                                        if (p->p_flags & P_ADR) {
                                                }
                                                p->p_value = add(lp, cp);
                                        }
 -                                      free(lp);
 +                                      mh_free0(&lp);
                                        break;
                                }
                        }
                        if (!p->p_name && i < NVEC) {
-                               p->p_name = mh_xstrdup(name);
 -                              p->p_name = getcpy(f.name);
++                              p->p_name = mh_xstrdup(f.name);
                                p->p_value = lp;
                                p->p_flags = P_NIL;
                                p++, i++;
                        }
                        continue;
  
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        break;
  
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        advise(NULL, "format error in message");
                        break;
  
                if (!(q = lookup(hdrs, "reply-to")) || !q->p_value) {
                        q = lookup(hdrs, "from");
                }
 -              p->p_value = getcpy(q ? q->p_value : "");
 +              p->p_value = mh_xstrdup(q ? q->p_value : "");
                p->p_flags &= ~P_CHK;
                if (debug) {
                        debug_printf("vars[%d]: name=\"%s\" value=\"%s\"\n",
@@@ -891,18 -885,18 +885,18 @@@ glob(int fd
                return;
        }
        if ((p = lookup(vars, "sender"))) {
 -              p->p_value = getcpy(sender);
 +              p->p_value = mh_xstrdup(sender);
        }
        if ((p = lookup(vars, "address"))) {
 -              p->p_value = getcpy(addr);
 +              p->p_value = mh_xstrdup(addr);
        }
        if ((p = lookup(vars, "size"))) {
                snprintf(buffer, sizeof(buffer), "%d",
                                fstat(fd, &st) != -1 ? (int) st.st_size : 0);
 -              p->p_value = getcpy(buffer);
 +              p->p_value = mh_xstrdup(buffer);
        }
        if ((p = lookup(vars, "info"))) {
 -              p->p_value = getcpy(info);
 +              p->p_value = mh_xstrdup(info);
        }
        if (debug) {
                for (p = vars; p->p_name; p++) {
@@@ -1090,7 -1084,7 +1084,7 @@@ get_sender(char *envelope, char **sende
        unsigned char buffer[BUFSIZ];
  
        if (!envelope) {
 -              *sender = getcpy("");
 +              *sender = mh_xstrdup("");
                return;
        }
  
                } else {
                        break;
                }
 -      *sender = getcpy(buffer);
 +      *sender = mh_xstrdup(buffer);
  }
  
  
@@@ -1194,7 -1188,7 +1188,7 @@@ you_lose
                                ** get copy of envelope information
                                ** ("From " line)
                                */
 -                              envelope = getcpy(buffer);
 +                              envelope = mh_xstrdup(buffer);
  
                                /* Put the delivery date in message */
                                fputs(ddate, ffp);
@@@ -1264,7 -1258,7 +1258,7 @@@ trimstr(char *cp
                        *sp = ' ';
                }
        }
 -      return getcpy(bp);
 +      return mh_xstrdup(bp);
  }
  
  /*
diff --combined uip/sortm.c
@@@ -161,7 -161,7 +161,7 @@@ main(int argc, char **argv
                        if (folder)
                                adios(EX_USAGE, NULL, "only one folder at a time!");
                        else
 -                              folder = getcpy(expandfol(cp));
 +                              folder = mh_xstrdup(expandfol(cp));
                } else
                        app_msgarg(&msgs, cp);
        }
        /*
        ** sort a list of pointers to our "messages to be sorted".
        */
 -      dlist = (struct smsg **) mh_xcalloc((size_t) (nmsgs+1), sizeof(*dlist));
 +      dlist = mh_xcalloc(nmsgs+1, sizeof(*dlist));
        for (i = 0; i < nmsgs; i++)
                dlist[i] = &smsgs[i];
        dlist[nmsgs] = 0;
                struct smsg **slist, **flist;
                struct smsg ***il, **fp, **dp;
  
 -              slist = (struct smsg **)
 -                              mh_xmalloc((nmsgs+1) * sizeof(*slist));
 +              slist = mh_xcalloc(nmsgs+1, sizeof(*slist));
                memcpy((char *)slist, (char *)dlist, (nmsgs+1)*sizeof(*slist));
                qsort((char *)slist, nmsgs, sizeof(*slist),
                                (qsort_comp) subsort);
                ** the collection of messages with the same subj
                ** given a message number.
                */
 -              il = (struct smsg ***) mh_xcalloc(mp->hghsel+1, sizeof(*il));
 +              il = mh_xcalloc(mp->hghsel+1, sizeof(*il));
                if (! il)
                        adios(EX_OSERR, NULL, "couldn't allocate msg list");
                for (i = 0; i < nmsgs; i++)
                ** make up the final list, chronological but with
                ** all the same subjects grouped together.
                */
 -              flist = (struct smsg **)
 -                              mh_xmalloc((nmsgs+1) * sizeof(*flist));
 +              flist = mh_xcalloc(nmsgs+1, sizeof(*flist));
                fp = flist;
                for (dp = dlist; *dp;) {
                        struct smsg **s = il[(*dp++)->s_msg];
                        }
                }
                *fp = 0;
 -              free(slist);
 -              free(dlist);
 +              mh_free0(&slist);
 +              mh_free0(&dlist);
                dlist = flist;
        }
  
@@@ -293,7 -295,8 +293,7 @@@ read_hdrs(struct msgs *mp, char *datesw
  
        twscopy(&tb, dlocaltimenow());
  
 -      smsgs = (struct smsg *) mh_xcalloc((size_t) (mp->hghsel - mp->lowsel + 2),
 -                      sizeof(*smsgs));
 +      smsgs = mh_xcalloc(mp->hghsel - mp->lowsel + 2, sizeof(*smsgs));
  
        s = smsgs;
        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
  static int
  get_fields(char *datesw, int msg, struct smsg *smsg)
  {
-       int state;
+       enum state state;
+       struct field f = {{0}};
        int compnum;
-       char *msgnam, buf[BUFSIZ], nam[NAMESZ];
+       char *msgnam;
        struct tws *tw;
        char *datecomp = NULL, *subjcomp = NULL;
        FILE *in;
                admonish(msgnam, "unable to read message");
                return (0);
        }
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, nam, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
-                       compnum++;
-                       if (!mh_strcasecmp(nam, datesw)) {
-                               datecomp = add(buf, datecomp);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, nam, buf,
-                                                       sizeof(buf), in);
-                                       datecomp = add(buf, datecomp);
-                               }
-                               if (!subjsort || subjcomp)
+       for (compnum = 1, state = FLD2;; compnum++) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
+                       if (mh_strcasecmp(f.name, datesw)==0) {
 -                              datecomp = getcpy(f.value);
++                              datecomp = mh_xstrdup(f.value);
+                               if (!subjsort || subjcomp) {
                                        break;
-                       } else if (subjsort && !mh_strcasecmp(nam, subjsort)) {
-                               subjcomp = add(buf, subjcomp);
-                               while (state == FLDPLUS) {
-                                       state = m_getfld(state, nam, buf,
-                                                       sizeof(buf), in);
-                                       subjcomp = add(buf, subjcomp);
                                }
-                               if (datecomp)
+                       } else if (subjsort && mh_strcasecmp(f.name,
+                                       subjsort)==0) {
 -                              subjcomp = getcpy(f.value);
++                              subjcomp = mh_xstrdup(f.value);
+                               if (datecomp) {
                                        break;
-                       } else {
-                               /* just flush this guy */
-                               while (state == FLDPLUS)
-                                       state = m_getfld(state, nam, buf,
-                                                       sizeof(buf), in);
+                               }
                        }
                        continue;
  
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        break;
  
-               case LENERR:
-               case FMTERR:
-                       if (state == LENERR || state == FMTERR)
-                               admonish(NULL, "format error in message %d (header #%d)", msg, compnum);
-                       if (datecomp)
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
+                       admonish(NULL, "format error in message %d (header #%d)", msg, compnum);
+                       if (datecomp) {
 -                              free(datecomp);
 +                              mh_free0(&datecomp);
-                       if (subjcomp)
+                       }
+                       if (subjcomp) {
 -                              free(subjcomp);
 +                              mh_free0(&subjcomp);
+                       }
                        fclose(in);
                        return (0);
  
        }
        fclose(in);
        if (datecomp)
 -              free(datecomp);
 +              mh_free0(&datecomp);
  
        return (1);
  }
diff --combined uip/spost.c
@@@ -117,7 -117,6 +117,7 @@@ static enum 
  static char *tmpfil;
  
  static char *subject = NULL;  /* the subject field for BCC'ing */
 +static struct mailname *from = NULL;  /* the from field for BCC'ing */
  static char fccs[BUFSIZ] = "";
  struct mailname *bccs = NULL;  /* list of the bcc recipients */
  struct mailname *recipients = NULL;  /* list of the recipients */
@@@ -144,9 -143,11 +144,11 @@@ static size_t do_aliasing(struct mailna
  int
  main(int argc, char **argv)
  {
-       int state, compnum;
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
        char *cp, *msg = NULL, **argp, **arguments;
-       char **sargv, buf[BUFSIZ], name[NAMESZ];
+       char **sargv, buf[BUFSIZ];
        FILE *in;
  
        setlocale(LC_ALL, "");
                verbose++;
                out = stdout;
        } else {
 -              tmpfil = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out));
 +              tmpfil = mh_xstrdup(m_mktemp2("/tmp/", invo_name, NULL, &out));
        }
  
        /* check for "Aliasfile:" profile entry */
                char *dp, **ap; 
  
                aliasflg = 1;
 -              for (ap=brkstring(dp=getcpy(cp), " ", "\n"); ap && *ap;
 +              for (ap=brkstring(dp=mh_xstrdup(cp), " ", "\n"); ap && *ap;
                                ap++) {
                        if ((state = alias(etcpath(*ap))) != AK_OK) {
                                adios(EX_IOERR, NULL, "aliasing error in file %s: %s",
  
        hdrtab = (msgstate == normal) ? NHeaders : RHeaders;
  
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-               case FLDPLUS:
+       for (compnum = 1, state = FLD2;;) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
                        compnum++;
-                       cp = mh_xstrdup(buf);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               cp = add(buf, cp);
-                       }
-                       putfmt(name, cp, out);
-                       mh_free0(&cp);
+                       putfmt(f.name, f.value, out);
                        continue;
  
-               case BODY:
+               case BODY2:
                        finish_headers(out);
-                       fprintf(out, "\n%s", buf);
-                       while (state == BODY) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               fputs(buf, out);
+                       fprintf(out, "\n%s", f.value);
+                       while ((state = m_getfld2(state, &f, in)) == BODY2) {
+                               fputs(f.value, out);
                        }
                        break;
  
-               case FILEEOF:
+               case FILEEOF2:
                        finish_headers(out);
                        break;
  
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);
  
                adios(EX_DATAERR, NULL, "message has no recipients");
        }
  
 -      sargv = mh_xmalloc(sizeof(char **) * (recipientsc + 4));
 +      sargv = mh_xcalloc(recipientsc + 4, sizeof(char **));
  
        argp = sargv;
        *argp++ = "send-mail";
        }
  
        while (recipients != NULL) {
 -              cp = getcpy(recipients->m_mbox);
 +              cp = mh_xstrdup(recipients->m_mbox);
                if (recipients->m_host) {
                        cp = add("@", cp);
                        cp = add(recipients->m_host, cp);
@@@ -405,7 -397,7 +398,7 @@@ putfmt(char *name, char *str, FILE *out
        }
  
        if (hdr->flags & HSUB) {
 -              subject = getcpy(str);
 +              subject = mh_xstrdup(str);
        }
  
        if (!(hdr->flags & HADR)) {
                /* needed because the address parser holds global state */
                ismymbox(NULL);
  
 -              for ( mp = addr_start.m_next; mp; mp = mp->m_next) {
 +              for (mp = addr_start.m_next; mp; mp = mp->m_next) {
                        if (ismymbox(mp)) {
                                msgflags |= MFMM;
                                if (my == NULL) {
 -                                      my = mp;
 +                                      from = my = mp;
                                }
                        }
                }
@@@ -551,10 -543,10 +544,10 @@@ putadr(char *name, struct mailname *nl
                }
                if (mp->m_ingrp) {
                        if (mp->m_gname != NULL) {
 -                              cp = getcpy(mp->m_gname);
 +                              cp = mh_xstrdup(mp->m_gname);
                                cp = add(";", cp);
                                linepos = putone(cp, linepos, namelen);
 -                              free(cp);
 +                              mh_free0(&cp);
                                cp = NULL;
                        }
                } else {
@@@ -650,7 -642,7 +643,7 @@@ fcc(char *file, char *folders
                fprintf(stderr, "Skipped %sFcc %s: unable to system().\n",
                                msgstate == resent ? "Resent-" : "", folders);
        } else if (status != 0) {
 -              fprintf(stderr, "%sFcc %s: Problems occured.\n",
 +              fprintf(stderr, "%sFcc %s: Problems occurred.\n",
                                msgstate == resent ? "Resent-" : "", folders);
        }
  }
@@@ -666,11 -658,8 +659,11 @@@ process_bccs(char *origmsg
        FILE *out = NULL;
  
        for (mp=bccs; mp; mp=mp->m_next) {
 -              bccdraft = getcpy(m_mktemp2("/tmp/", invo_name, NULL, &out));
 +              bccdraft = mh_xstrdup(m_mktemp2("/tmp/", invo_name, NULL, &out));
                fprintf(out, "To: %s\n", mp->m_text);
 +              if (from) {
 +                      fprintf(out, "From: %s\n", from->m_text);
 +              }
                fprintf(out, "Subject: [BCC] %s", subject ? subject : "");
                fprintf(out, "%s: %s\n", attach_hdr, origmsg);
                fprintf(out, "------------\n");
diff --combined uip/whom.c
@@@ -167,7 -167,7 +167,7 @@@ main(int argc, char **argv
                }
                pclose(in);
        }
 -      free(cmd);
 +      mh_free0(&cmd);
        naddrs += n;
  
        cmd = add("ali -list", NULL);
                }
                pclose(in);
        }
 -      free(cmd);
 +      mh_free0(&cmd);
        naddrs += n;
  
        cmd = add("ali -list", NULL);
                }
                pclose(in);
        }
 -      free(cmd);
 +      mh_free0(&cmd);
        naddrs += n;
  
        return naddrs ? 0 : 1;
  static int
  process(char *file)
  {
-         int state, compnum;
-       char *cp = NULL;
-       char buf[BUFSIZ], name[NAMESZ];
+       enum state state;
+       struct field f = {{0}};
+       int compnum;
        FILE *in;
  
  
                adios(EX_IOERR, file, "unable to open");
        }
  
-       for (compnum = 1, state = FLD;;) {
-               switch (state = m_getfld(state, name, buf, sizeof(buf), in)) {
-               case FLD:
-                       compnum++;
-                       proc_hdr(name, buf);
+       for (compnum=1, state=FLD2;; compnum++) {
+               switch (state = m_getfld2(state, &f, in)) {
+               case FLD2:
+                       proc_hdr(f.name, f.value);
                        continue;
  
-               case FLDPLUS:
-                       compnum++;
-                       cp = mh_xstrdup(buf);
-                       while (state == FLDPLUS) {
-                               state = m_getfld(state, name, buf,
-                                               sizeof(buf), in);
-                               cp = add(buf, cp);
-                       }
-                       proc_hdr(name, cp);
-                       mh_free0(&cp);
-                       continue;
-               case BODY:
-               case FILEEOF:
+               case BODY2:
+               case FILEEOF2:
                        break;
  
-               case LENERR:
-               case FMTERR:
+               case LENERR2:
+               case FMTERR2:
+               case IOERR2:
                        adios(EX_DATAERR, NULL, "message format error in component #%d",
                                        compnum);