]> diplodocus.org Git - nmh/blobdiff - uip/mhparse.c
Commit ddf3a8574f65 is a fix to commit af586ebe59b7.
[nmh] / uip / mhparse.c
index efa8848058f5317912e7e623f40ed61fa1725857..cb9d2799e781949cc2ca6ce91fd93b0af3a67fee 100644 (file)
@@ -5,16 +5,28 @@
  * complete copyright information.
  */
 
-#include <h/mh.h>
+#include "h/mh.h"
+#include "sbr/m_gmprot.h"
+#include "sbr/m_getfld.h"
+#include "sbr/read_yes_or_no_if_tty.h"
+#include "sbr/concat.h"
+#include "sbr/r1bindex.h"
+#include "sbr/ruserpass.h"
+#include "sbr/fmt_rfc2047.h"
+#include "sbr/uprf.h"
+#include "sbr/check_charset.h"
+#include "sbr/getcpy.h"
+#include "sbr/context_find.h"
+#include "sbr/pidstatus.h"
+#include "sbr/arglist.h"
+#include "sbr/error.h"
 #include <fcntl.h>
-#include <h/md5.h>
-#include <h/mts.h>
-#include <h/tws.h>
-#include <h/mime.h>
-#include <h/mhparse.h>
-#include <h/utils.h>
+#include "h/mts.h"
+#include "h/tws.h"
+#include "h/mime.h"
+#include "h/mhparse.h"
+#include "h/utils.h"
 #include "mhmisc.h"
-#include <h/mhcachesbr.h>
 #include "sbr/m_mktemp.h"
 #include "mhfree.h"
 #ifdef HAVE_ICONV
@@ -25,8 +37,6 @@
 
 extern int debugsw;
 
-int checksw = 0;       /* check Content-MD5 field */
-
 /*
  * These are for mhfixmsg to:
  * 1) Instruct parser not to detect invalid Content-Transfer-Encoding
@@ -79,7 +89,6 @@ struct k2v SubMultiPart[] = {
  */
 struct k2v SubMessage[] = {
     { "rfc822",        MESSAGE_RFC822 },
-    { "partial",       MESSAGE_PARTIAL },
     { "external-body", MESSAGE_EXTERNAL },
     { NULL,            MESSAGE_UNKNOWN }       /* this one must be last! */
 };
@@ -127,14 +136,13 @@ static int openBase64 (CT, char **);
 static int InitQuoted (CT);
 static int openQuoted (CT, char **);
 static int Init7Bit (CT);
-static int openExternal (CT, CT, CE, char **, int *);
+static int openExternal (CT, CE, char **, int *);
 static int InitFile (CT);
 static int openFile (CT, char **);
 static int InitFTP (CT);
 static int openFTP (CT, char **);
 static int InitMail (CT);
 static int openMail (CT, char **);
-static int readDigest (CT, char *);
 static int get_leftover_mp_content (CT, int);
 static int InitURL (CT);
 static int openURL (CT, char **);
@@ -361,10 +369,10 @@ get_content (FILE *in, char *file, int toplevel)
 
        case LENERR:
        case FMTERR:
-           adios (NULL, "message format error in component #%d", compnum);
+           die("message format error in component #%d", compnum);
 
        default:
-           adios (NULL, "getfld() returned %d", state);
+           die("getfld() returned %d", state);
        }
 
        /* break out of the loop */
@@ -495,46 +503,6 @@ get_content (FILE *in, char *file, int toplevel)
            if (s2i->si_init && (*s2i->si_init) (ct) == NOTOK)
                goto out;
        }
-       else if (!strcasecmp (hp->name, MD5_FIELD)) {
-       /* Get Content-MD5 field */
-           char *cp, *dp, *ep;
-
-           if (!checksw)
-               goto next_header;
-
-           if (ct->c_digested) {
-               inform("message %s has multiple %s: fields",
-                       ct->c_file, MD5_FIELD);
-               goto next_header;
-           }
-
-           ep = cp = mh_xstrdup(FENDNULL(hp->value)); /* get a copy */
-
-           while (isspace ((unsigned char) *cp))
-               cp++;
-           for (dp = strchr(cp, '\n'); dp; dp = strchr(dp, '\n'))
-               *dp++ = ' ';
-           for (dp = cp + strlen (cp) - 1; dp >= cp; dp--)
-               if (!isspace ((unsigned char) *dp))
-                   break;
-           *++dp = '\0';
-           if (debugsw)
-               fprintf (stderr, "%s: %s\n", MD5_FIELD, cp);
-
-           if (*cp == '('  &&
-                get_comment (ct->c_file, MD5_FIELD, &cp, NULL) == NOTOK) {
-               free (ep);
-               goto out;
-           }
-
-           for (dp = cp; *dp && !isspace ((unsigned char) *dp); dp++)
-               continue;
-           *dp = '\0';
-
-           readDigest (ct, cp);
-           free (ep);
-           ct->c_digested++;
-       }
        else if (!strcasecmp (hp->name, ID_FIELD)) {
        /* Get Content-ID field */
            ct->c_id = add (hp->value, ct->c_id);
@@ -657,7 +625,7 @@ get_ctinfo (char *cp, CT ct, int magic)
        fprintf (stderr, "%s: %s\n", TYPE_FIELD, cp);
 
     if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
-                                  &ci->ci_comment) == NOTOK)
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     for (dp = cp; istoken (*dp); dp++)
@@ -679,7 +647,7 @@ get_ctinfo (char *cp, CT ct, int magic)
        cp++;
 
     if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
-                                  &ci->ci_comment) == NOTOK)
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     if (*cp != '/') {
@@ -693,7 +661,7 @@ get_ctinfo (char *cp, CT ct, int magic)
        cp++;
 
     if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
-                                  &ci->ci_comment) == NOTOK)
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     for (dp = cp; istoken (*dp); dp++)
@@ -716,11 +684,11 @@ magic_skip:
        cp++;
 
     if (*cp == '(' && get_comment (ct->c_file, TYPE_FIELD, &cp,
-                                  &ci->ci_comment) == NOTOK)
+                                  &ci->ci_comment) == NOTOK)
        return NOTOK;
 
     if ((status = parse_header_attrs (ct->c_file, TYPE_FIELD, &cp,
-                                     &ci->ci_first_pm, &ci->ci_last_pm,
+                                     &ci->ci_first_pm, &ci->ci_last_pm,
                                      &ci->ci_comment)) != OK) {
        return status == NOTOK ? NOTOK : OK;
     }
@@ -808,7 +776,7 @@ magic_skip:
      */
 
     if (magic && *cp == '*') {
-       /*
+       /*
         * See if it's a CTE we match on
         */
        struct k2v *kv;
@@ -906,7 +874,7 @@ get_dispo (char *cp, CT ct, int buildflag)
        fprintf (stderr, "%s: %s\n", DISPO_FIELD, cp);
 
     if (*cp == '(' && get_comment (ct->c_file, DISPO_FIELD, &cp, NULL) ==
-                                                       NOTOK) {
+                                                       NOTOK) {
        free(dispoheader);
        return NOTOK;
     }
@@ -923,7 +891,7 @@ get_dispo (char *cp, CT ct, int buildflag)
        return NOTOK;
 
     if ((status = parse_header_attrs (ct->c_file, DISPO_FIELD, &cp,
-                                     &ct->c_dispo_first, &ct->c_dispo_last,
+                                     &ct->c_dispo_first, &ct->c_dispo_last,
                                      NULL)) != OK) {
        if (status == NOTOK) {
            free(dispoheader);
@@ -935,7 +903,7 @@ get_dispo (char *cp, CT ct, int buildflag)
     }
 
     if (buildflag)
-       free(dispoheader);
+       free(dispoheader);
     else
        ct->c_dispo = dispoheader;
 
@@ -1082,7 +1050,7 @@ InitText (CT ct)
 static int
 InitMultiPart (CT ct)
 {
-    int        inout;
+    bool inout;
     long last, pos;
     char *cp, *dp;
     PM pm;
@@ -1175,7 +1143,7 @@ InitMultiPart (CT ct)
     last = ct->c_end;
     next = &m->mp_parts;
     part = NULL;
-    inout = 1;
+    inout = true;
 
     while ((gotlen = getline(&bufp, &buflen, fp)) != -1) {
        if (pos > last)
@@ -1184,6 +1152,23 @@ InitMultiPart (CT ct)
        pos += gotlen;
        if (bufp[0] != '-' || bufp[1] != '-')
            continue;
+
+       /*
+        * A bit of a lame hack; if this line ends in \r\n then replace
+        * the \r\n with just a \n so that the boundary markers will match
+        * up properly in case this uses "MS-DOS" line endings.
+        */
+
+       if (gotlen > 2 && bufp[gotlen - 1] == '\n' &&
+           bufp[gotlen - 2] == '\r') {
+               /*
+                * Note we don't change getpos here, because it is used to
+                * calculate multipart offsets.
+                */
+               bufp[gotlen - 2] = '\n';
+               bufp[gotlen - 1] = '\0';
+       }
+
        if (inout) {
            if (strcmp (bufp + 2, m->mp_start))
                continue;
@@ -1202,10 +1187,10 @@ next_part:
            part->mp_part = p;
            pos = p->c_begin;
            fseek (fp, pos, SEEK_SET);
-           inout = 0;
+           inout = false;
        } else {
            if (strcmp (bufp + 2, m->mp_start) == 0) {
-               inout = 1;
+               inout = true;
 end_part:
                p = part->mp_part;
                p->c_end = ftell(fp) - (gotlen + 1);
@@ -1377,7 +1362,8 @@ prefer_parts(CT ct)
    example, a text/plain part before a text/html part in a
    multipart/alternative part, for example, where it belongs. */
 void
-reverse_alternative_parts (CT ct) {
+reverse_alternative_parts (CT ct)
+{
     if (ct->c_type == CT_MULTIPART) {
         struct multipart *m = (struct multipart *) ct->c_ctparams;
         struct part *part;
@@ -1421,49 +1407,6 @@ InitMessage (CT ct)
        case MESSAGE_RFC822:
            break;
 
-       case MESSAGE_PARTIAL:
-           {
-               PM pm;
-               struct partial *p;
-
-               NEW0(p);
-               ct->c_ctparams = (void *) p;
-
-               /* scan for parameters "id", "number", and "total" */
-               for (pm = ci->ci_first_pm; pm; pm = pm->pm_next) {
-                   if (!strcasecmp (pm->pm_name, "id")) {
-                       p->pm_partid = mh_xstrdup(FENDNULL(pm->pm_value));
-                       continue;
-                   }
-                   if (!strcasecmp (pm->pm_name, "number")) {
-                       if (sscanf (pm->pm_value, "%d", &p->pm_partno) != 1
-                               || p->pm_partno < 1) {
-invalid_param:
-                           inform("invalid %s parameter for \"%s/%s\" type in message %s's %s field",
-                                pm->pm_name, ci->ci_type, ci->ci_subtype,
-                                ct->c_file, TYPE_FIELD);
-                           return NOTOK;
-                       }
-                       continue;
-                   }
-                   if (!strcasecmp (pm->pm_name, "total")) {
-                       if (sscanf (pm->pm_value, "%d", &p->pm_maxno) != 1
-                               || p->pm_maxno < 1)
-                           goto invalid_param;
-                       continue;
-                   }
-               }
-
-               if (!p->pm_partid
-                       || !p->pm_partno
-                       || (p->pm_maxno && p->pm_partno > p->pm_maxno)) {
-                   inform("invalid parameters for \"%s/%s\" type in message %s's %s field",
-                        ci->ci_type, ci->ci_subtype, ct->c_file, TYPE_FIELD);
-                   return NOTOK;
-               }
-           }
-           break;
-
        case MESSAGE_EXTERNAL:
            {
                int exresult;
@@ -1511,7 +1454,7 @@ invalid_param:
                                adios ("failed", "fread");
 
                            case OK:
-                               adios (NULL, "unexpected EOF from fread");
+                               die("unexpected EOF from fread");
 
                            default:
                                bp += cc, size -= cc;
@@ -1629,7 +1572,7 @@ params_external (CT ct, int composing)
            e->eb_url = u = mh_xmalloc(strlen(pm->pm_value) + 1);
 
            for (; *p != '\0'; p++) {
-               if (! isspace((unsigned char) *p))
+               if (! isspace((unsigned char) *p))
                    *u++ = *p;
            }
 
@@ -1745,14 +1688,14 @@ static int
 openBase64 (CT ct, char **file)
 {
     ssize_t cc, len;
-    int fd, own_ct_fp = 0;
+    int fd;
+    bool own_ct_fp = false;
     char *cp, *buffer = NULL;
     /* sbeck -- handle suffixes */
     CI ci;
     CE ce = &ct->c_cefile;
     unsigned char *decoded;
     size_t decoded_len;
-    unsigned char digest[16];
 
     if (ce->ce_fp) {
        fseek (ce->ce_fp, 0L, SEEK_SET);
@@ -1780,7 +1723,7 @@ openBase64 (CT ct, char **file)
        if (ce->ce_unlink) {
            /* Create temporary file with filename extension. */
            if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) {
-               adios(NULL, "unable to create temporary file in %s",
+               die("unable to create temporary file in %s",
                      get_temp_dir());
            }
        } else {
@@ -1789,7 +1732,7 @@ openBase64 (CT ct, char **file)
     } else if (*file == NULL) {
        char *tempfile;
        if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
+           die("unable to create temporary file in %s",
                  get_temp_dir());
        }
        ce->ce_file = mh_xstrdup(tempfile);
@@ -1801,7 +1744,7 @@ openBase64 (CT ct, char **file)
     }
 
     if ((len = ct->c_end - ct->c_begin) < 0)
-       adios (NULL, "internal error(1)");
+       die("internal error(1)");
 
     buffer = mh_xmalloc (len + 1);
 
@@ -1810,7 +1753,7 @@ openBase64 (CT ct, char **file)
            content_error (ct->c_file, ct, "unable to open for reading");
            return NOTOK;
        }
-       own_ct_fp = 1;
+       own_ct_fp = true;
     }
 
     lseek (fd = fileno (ct->c_fp), (off_t) ct->c_begin, SEEK_SET);
@@ -1836,8 +1779,8 @@ openBase64 (CT ct, char **file)
     /* decodeBase64() requires null-terminated input. */
     *cp = '\0';
 
-    if (decodeBase64 (buffer, &decoded, &decoded_len, ct->c_type == CT_TEXT,
-                      ct->c_digested ? digest : NULL) != OK)
+    if (decodeBase64 (buffer, &decoded, &decoded_len,
+                     ct->c_type == CT_TEXT) != OK)
         goto clean_up;
 
     {
@@ -1851,18 +1794,6 @@ openBase64 (CT ct, char **file)
             content_error (ce->ce_file, ct, "error writing to");
             goto clean_up;
         }
-
-        if (ct->c_digested) {
-            if (memcmp(digest, ct->c_digest,
-                       sizeof digest)) {
-                content_error (NULL, ct,
-                               "content integrity suspect (digest mismatch) -- continuing");
-            } else {
-                if (debugsw) {
-                    fprintf (stderr, "content integrity confirmed\n");
-                }
-            }
-        }
     }
 
     fseek (ct->c_fp, 0L, SEEK_SET);
@@ -1928,7 +1859,8 @@ InitQuoted (CT ct)
 static int
 openQuoted (CT ct, char **file)
 {
-    int        cc, digested, len, quoted, own_ct_fp = 0;
+    int        cc, len, quoted;
+    bool own_ct_fp = false;
     char *cp, *ep;
     char *bufp = NULL;
     size_t buflen;
@@ -1937,7 +1869,6 @@ openQuoted (CT ct, char **file)
     CE ce = &ct->c_cefile;
     /* sbeck -- handle suffixes */
     CI ci;
-    MD5_CTX mdContext;
 
     if (ce->ce_fp) {
        fseek (ce->ce_fp, 0L, SEEK_SET);
@@ -1965,7 +1896,7 @@ openQuoted (CT ct, char **file)
        if (ce->ce_unlink) {
            /* Create temporary file with filename extension. */
            if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) {
-               adios(NULL, "unable to create temporary file in %s",
+               die("unable to create temporary file in %s",
                      get_temp_dir());
            }
        } else {
@@ -1974,7 +1905,7 @@ openQuoted (CT ct, char **file)
     } else if (*file == NULL) {
        char *tempfile;
        if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
+           die("unable to create temporary file in %s",
                  get_temp_dir());
        }
        ce->ce_file = mh_xstrdup(tempfile);
@@ -1986,19 +1917,16 @@ openQuoted (CT ct, char **file)
     }
 
     if ((len = ct->c_end - ct->c_begin) < 0)
-       adios (NULL, "internal error(2)");
+       die("internal error(2)");
 
     if (! ct->c_fp) {
        if ((ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
            content_error (ct->c_file, ct, "unable to open for reading");
            return NOTOK;
        }
-       own_ct_fp = 1;
+       own_ct_fp = true;
     }
 
-    if ((digested = ct->c_digested))
-       MD5Init (&mdContext);
-
     quoted = 0;
 
     fseek (ct->c_fp, ct->c_begin, SEEK_SET);
@@ -2031,8 +1959,6 @@ openQuoted (CT ct, char **file)
                    mask <<= 4;
                    mask |= hex2nib[((unsigned char) *cp) & 0x7f];
                    putc (mask, ce->ce_fp);
-                   if (digested)
-                       MD5Update (&mdContext, &mask, 1);
                    if (ferror (ce->ce_fp)) {
                        content_error (ce->ce_file, ct, "error writing to");
                        goto clean_up;
@@ -2070,13 +1996,6 @@ openQuoted (CT ct, char **file)
 
            /* Just show the raw byte. */
            putc (*cp, ce->ce_fp);
-           if (digested) {
-               if (*cp == '\n') {
-                   MD5Update (&mdContext, (unsigned char *) "\r\n",2);
-               } else {
-                   MD5Update (&mdContext, (unsigned char *) cp, 1);
-               }
-           }
            if (ferror (ce->ce_fp)) {
                content_error (ce->ce_file, ct, "error writing to");
                goto clean_up;
@@ -2096,18 +2015,6 @@ openQuoted (CT ct, char **file)
        goto clean_up;
     }
 
-    if (digested) {
-       unsigned char digest[16];
-
-       MD5Final (digest, &mdContext);
-       if (memcmp((char *) digest, (char *) ct->c_digest,
-                  sizeof digest))
-           content_error (NULL, ct,
-                          "content integrity suspect (digest mismatch) -- continuing");
-       else if (debugsw)
-            fprintf (stderr, "content integrity confirmed\n");
-    }
-
     fseek (ce->ce_fp, 0L, SEEK_SET);
 
 ready_to_go:
@@ -2148,7 +2055,8 @@ Init7Bit (CT ct)
 int
 open7Bit (CT ct, char **file)
 {
-    int        cc, fd, len, own_ct_fp = 0;
+    int        cc, fd, len;
+    bool own_ct_fp = false;
     char buffer[BUFSIZ];
     /* sbeck -- handle suffixes */
     char *cp;
@@ -2181,7 +2089,7 @@ open7Bit (CT ct, char **file)
        if (ce->ce_unlink) {
            /* Create temporary file with filename extension. */
            if ((ce->ce_file = m_mktemps(invo_name, cp, NULL, NULL)) == NULL) {
-               adios(NULL, "unable to create temporary file in %s",
+               die("unable to create temporary file in %s",
                      get_temp_dir());
            }
        } else {
@@ -2190,7 +2098,7 @@ open7Bit (CT ct, char **file)
     } else if (*file == NULL) {
        char *tempfile;
        if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
+           die("unable to create temporary file in %s",
                  get_temp_dir());
        }
        ce->ce_file = mh_xstrdup(tempfile);
@@ -2239,14 +2147,14 @@ open7Bit (CT ct, char **file)
     }
 
     if ((len = ct->c_end - ct->c_begin) < 0)
-       adios (NULL, "internal error(3)");
+       die("internal error(3)");
 
     if (! ct->c_fp) {
        if ((ct->c_fp = fopen (ct->c_file, "r")) == NULL) {
            content_error (ct->c_file, ct, "unable to open for reading");
            return NOTOK;
        }
-       own_ct_fp = 1;
+       own_ct_fp = true;
     }
 
     lseek (fd = fileno (ct->c_fp), (off_t) ct->c_begin, SEEK_SET);
@@ -2306,10 +2214,8 @@ clean_up:
  */
 
 static int
-openExternal (CT ct, CT cb, CE ce, char **file, int *fd)
+openExternal (CT ct, CE ce, char **file, int *fd)
 {
-    char cachefile[BUFSIZ];
-
     if (ce->ce_fp) {
        fseek (ce->ce_fp, 0L, SEEK_SET);
        goto ready_already;
@@ -2323,16 +2229,6 @@ openExternal (CT ct, CT cb, CE ce, char **file, int *fd)
        goto ready_already;
     }
 
-    if (find_cache(ct, rcachesw, NULL, cb->c_id,
-               cachefile, sizeof(cachefile)) != NOTOK) {
-       if ((ce->ce_fp = fopen (cachefile, "r"))) {
-           ce->ce_file = mh_xstrdup(cachefile);
-           ce->ce_unlink = 0;
-           goto ready_already;
-       }
-        admonish (cachefile, "unable to fopen for reading");
-    }
-
     *fd = ce->ce_fp ? fileno (ce->ce_fp) : -1;
     return OK;
 
@@ -2356,12 +2252,11 @@ InitFile (CT ct)
 static int
 openFile (CT ct, char **file)
 {
-    int        fd, cachetype;
-    char cachefile[BUFSIZ];
+    int        fd;
     struct exbody *e = ct->c_ctexbody;
     CE ce = &ct->c_cefile;
 
-    switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) {
+    switch (openExternal (e->eb_parent, ce, file, &fd)) {
        case NOTOK:
            return NOTOK;
 
@@ -2385,39 +2280,6 @@ openFile (CT ct, char **file)
        return NOTOK;
     }
 
-    if ((!e->eb_permission || strcasecmp (e->eb_permission, "read-write"))
-           && find_cache (NULL, wcachesw, &cachetype, e->eb_content->c_id,
-               cachefile, sizeof(cachefile)) != NOTOK) {
-       int mask;
-       FILE *fp;
-
-       mask = umask (cachetype ? ~m_gmprot () : 0222);
-       if ((fp = fopen (cachefile, "w"))) {
-           int cc;
-           char buffer[BUFSIZ];
-           FILE *gp = ce->ce_fp;
-
-           fseek (gp, 0L, SEEK_SET);
-
-           while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp))
-                      > 0)
-               if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) {
-                   advise ("openFile", "fwrite");
-               }
-           fflush (fp);
-
-           if (ferror (gp)) {
-               admonish (ce->ce_file, "error reading");
-               (void) m_unlink (cachefile);
-           } else if (ferror (fp)) {
-                admonish (cachefile, "error writing");
-                (void) m_unlink (cachefile);
-            }
-           fclose (fp);
-       }
-       umask (mask);
-    }
-
     fseek (ce->ce_fp, 0L, SEEK_SET);
     *file = ce->ce_file;
     return fileno (ce->ce_fp);
@@ -2437,10 +2299,10 @@ InitFTP (CT ct)
 static int
 openFTP (CT ct, char **file)
 {
-    int        cachetype, caching, fd;
+    int fd;
     int len, buflen;
     char *bp, *ftp, *user, *pass;
-    char buffer[BUFSIZ], cachefile[BUFSIZ];
+    char buffer[BUFSIZ];
     struct exbody *e;
     CE ce = &ct->c_cefile;
     static char *username = NULL;
@@ -2454,7 +2316,7 @@ openFTP (CT ct, char **file)
     if (!ftp)
        return NOTOK;
 
-    switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) {
+    switch (openExternal (e->eb_parent, ce, file, &fd)) {
        case NOTOK:
            return NOTOK;
 
@@ -2512,7 +2374,7 @@ openFTP (CT ct, char **file)
 
     if (e->eb_flags) {
        user = "anonymous";
-       snprintf (buffer, sizeof(buffer), "%s@%s", getusername (),
+       snprintf (buffer, sizeof(buffer), "%s@%s", getusername (1),
                  LocalName (1));
        pass = buffer;
     } else {
@@ -2522,25 +2384,13 @@ openFTP (CT ct, char **file)
     }
 
     ce->ce_unlink = (*file == NULL);
-    caching = 0;
-    cachefile[0] = '\0';
-    if ((!e->eb_permission || strcasecmp (e->eb_permission, "read-write"))
-           && find_cache (NULL, wcachesw, &cachetype, e->eb_content->c_id,
-               cachefile, sizeof(cachefile)) != NOTOK) {
-       if (*file == NULL) {
-           ce->ce_unlink = 0;
-           caching = 1;
-       }
-    }
 
     if (*file)
        ce->ce_file = mh_xstrdup(*file);
-    else if (caching)
-       ce->ce_file = mh_xstrdup(cachefile);
     else {
        char *tempfile;
        if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
+           die("unable to create temporary file in %s",
                  get_temp_dir());
        }
        ce->ce_file = mh_xstrdup(tempfile);
@@ -2564,7 +2414,7 @@ openFTP (CT ct, char **file)
        vec[vecp++] = e->eb_name;
        vec[vecp++] = ce->ce_file,
        vec[vecp++] = e->eb_mode && !strcasecmp (e->eb_mode, "ascii")
-                       ? "ascii" : "binary";
+                       ? "ascii" : "binary";
        vec[vecp] = NULL;
 
        fflush (stdout);
@@ -2593,40 +2443,6 @@ openFTP (CT ct, char **file)
        }
     }
 
-    if (cachefile[0]) {
-       if (caching)
-           chmod (cachefile, cachetype ? m_gmprot () : 0444);
-       else {
-           int mask;
-           FILE *fp;
-
-           mask = umask (cachetype ? ~m_gmprot () : 0222);
-           if ((fp = fopen (cachefile, "w"))) {
-               int cc;
-               FILE *gp = ce->ce_fp;
-
-               fseek (gp, 0L, SEEK_SET);
-
-               while ((cc= fread (buffer, sizeof(*buffer), sizeof(buffer), gp))
-                          > 0)
-                   if ((int) fwrite (buffer, sizeof(*buffer), cc, fp) < cc) {
-                       advise ("openFTP", "fwrite");
-                   }
-               fflush (fp);
-
-               if (ferror (gp)) {
-                   admonish (ce->ce_file, "error reading");
-                   (void) m_unlink (cachefile);
-               } else if (ferror (fp)) {
-                    admonish (cachefile, "error writing");
-                    (void) m_unlink (cachefile);
-                }
-               fclose (fp);
-           }
-           umask (mask);
-       }
-    }
-
     fseek (ce->ce_fp, 0L, SEEK_SET);
     *file = ce->ce_file;
     return fileno (ce->ce_fp);
@@ -2653,7 +2469,7 @@ openMail (CT ct, char **file)
     struct exbody *e = ct->c_ctexbody;
     CE ce = &ct->c_cefile;
 
-    switch (openExternal (e->eb_parent, e->eb_content, ce, file, &fd)) {
+    switch (openExternal (e->eb_parent, ce, file, &fd)) {
        case NOTOK:
            return NOTOK;
 
@@ -2725,7 +2541,7 @@ openMail (CT ct, char **file)
     if (*file == NULL) {
        char *tempfile;
        if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
+           die("unable to create temporary file in %s",
                  get_temp_dir());
        }
        ce->ce_file = mh_xstrdup(tempfile);
@@ -2768,21 +2584,20 @@ openURL (CT ct, char **file)
     struct exbody *e = ct->c_ctexbody;
     CE ce = &ct->c_cefile;
     char *urlprog, *program;
-    char buffer[BUFSIZ], cachefile[BUFSIZ];
-    int fd, caching, cachetype;
+    int fd;
     struct msgs_array args = { 0, 0, NULL};
     pid_t child_id;
 
     if ((urlprog = context_find(nmhaccessurl)) && *urlprog == '\0')
-       urlprog = NULL;
+       urlprog = NULL;
 
     if (! urlprog) {
-       content_error(NULL, ct, "No entry for nmh-access-url in profile");
-       return NOTOK;
+       content_error(NULL, ct, "No entry for nmh-access-url in profile");
+       return NOTOK;
     }
 
-    switch (openExternal(e->eb_parent, e->eb_content, ce, file, &fd)) {
-       case NOTOK:
+    switch (openExternal(e->eb_parent, ce, file, &fd)) {
+       case NOTOK:
            return NOTOK;
 
        case OK:
@@ -2793,47 +2608,35 @@ openURL (CT ct, char **file)
     }
 
     if (!e->eb_url) {
-       content_error(NULL, ct, "missing url parameter");
+       content_error(NULL, ct, "missing url parameter");
        return NOTOK;
     }
 
     ce->ce_unlink = (*file == NULL);
-    caching = 0;
-    cachefile[0] = '\0';
-
-    if (find_cache(NULL, wcachesw, &cachetype, e->eb_content->c_id,
-                  cachefile, sizeof(cachefile)) != NOTOK) {
-       if (*file == NULL) {
-           ce->ce_unlink = 0;
-           caching = 1;
-       }
-    }
 
     if (*file)
         ce->ce_file = mh_xstrdup(*file);
-    else if (caching)
-        ce->ce_file = mh_xstrdup(cachefile);
     else {
        char *tempfile;
        if ((tempfile = m_mktemp2(NULL, invo_name, NULL, NULL)) == NULL) {
-           adios(NULL, "unable to create temporary file in %s",
+           die("unable to create temporary file in %s",
                  get_temp_dir());
        }
        ce->ce_file = mh_xstrdup(tempfile);
     }
 
     if ((ce->ce_fp = fopen(ce->ce_file, "w+")) == NULL) {
-       content_error(ce->ce_file, ct, "unable to fopen for read/writing");
+       content_error(ce->ce_file, ct, "unable to fopen for read/writing");
        return NOTOK;
     }
 
     switch (child_id = fork()) {
     case NOTOK:
-       adios ("fork", "unable to");
+       adios ("fork", "unable to");
        /* NOTREACHED */
 
     case OK:
-       argsplit_msgarg(&args, urlprog, &program);
+       argsplit_msgarg(&args, urlprog, &program);
        app_msgarg(&args, e->eb_url);
        app_msgarg(&args, NULL);
        dup2(fileno(ce->ce_fp), 1);
@@ -2845,89 +2648,18 @@ openURL (CT ct, char **file)
        /* NOTREACHED */
 
     default:
-       if (pidXwait(child_id, NULL)) {
+       if (pidXwait(child_id, NULL)) {
            ce->ce_unlink = 1;
            return NOTOK;
        }
     }
 
-    if (cachefile[0]) {
-       if (caching)
-           chmod(cachefile, cachetype ? m_gmprot() : 0444);
-       else {
-           int mask;
-           FILE *fp;
-
-           mask = umask (cachetype ? ~m_gmprot() : 0222);
-           if ((fp = fopen(cachefile, "w"))) {
-               int cc;
-               FILE *gp = ce->ce_fp;
-
-               fseeko(gp, 0, SEEK_SET);
-
-               while ((cc = fread(buffer, sizeof(*buffer),
-                                  sizeof(buffer), gp)) > 0)
-                   if ((int) fwrite(buffer, sizeof(*buffer), cc, fp) < cc) {
-                       advise ("openURL", "fwrite");
-                   }
-
-               fflush(fp);
-
-               if (ferror(gp)) {
-                   admonish(ce->ce_file, "error reading");
-                   (void) m_unlink (cachefile);
-               }
-           }
-           umask(mask);
-       }
-    }
-
     fseeko(ce->ce_fp, 0, SEEK_SET);
     *file = ce->ce_file;
     return fileno(ce->ce_fp);
 }
 
 
-/*
- * Stores MD5 digest (in cp, from Content-MD5 header) in ct->c_digest.  It
- * has to be base64 decoded.
- */
-static int
-readDigest (CT ct, char *cp)
-{
-    unsigned char *digest;
-
-    size_t len;
-    if (decodeBase64 (cp, &digest, &len, 0, NULL) == OK) {
-        const size_t maxlen = sizeof ct->c_digest;
-
-        if (strlen ((char *) digest) <= maxlen) {
-            memcpy (ct->c_digest, digest, maxlen);
-
-            if (debugsw) {
-                size_t i;
-
-                fprintf (stderr, "MD5 digest=");
-                for (i = 0; i < maxlen; ++i) {
-                    fprintf (stderr, "%02x", ct->c_digest[i] & 0xff);
-                }
-                fprintf (stderr, "\n");
-            }
-
-            return OK;
-        }
-        if (debugsw) {
-            fprintf (stderr, "invalid MD5 digest (got %d octets)\n",
-                     (int) strlen ((char *) digest));
-        }
-
-        return NOTOK;
-    }
-
-    return NOTOK;
-}
-
-
 /* Multipart parts might have content before the first subpart and/or
    after the last subpart that hasn't been stored anywhere else, so do
    that. */
@@ -2936,7 +2668,7 @@ get_leftover_mp_content (CT ct, int before /* or after */)
 {
     struct multipart *m = (struct multipart *) ct->c_ctparams;
     char *boundary;
-    int found_boundary = 0;
+    bool found_boundary = false;
     int max = BUFSIZ;
     char *bufp = NULL;
     size_t buflen;
@@ -2981,11 +2713,11 @@ get_leftover_mp_content (CT ct, int before /* or after */)
 
         if (before) {
             if (! strcmp (bufp, boundary)) {
-                found_boundary = 1;
+                found_boundary = true;
             }
         } else {
             if (! found_boundary  &&  ! strcmp (bufp, boundary)) {
-                found_boundary = 1;
+                found_boundary = true;
                 continue;
             }
         }
@@ -3039,7 +2771,8 @@ get_leftover_mp_content (CT ct, int before /* or after */)
 
 
 char *
-ct_type_str (int type) {
+ct_type_str (int type)
+{
     switch (type) {
     case CT_APPLICATION:
         return "application";
@@ -3064,7 +2797,8 @@ ct_type_str (int type) {
 
 
 char *
-ct_subtype_str (int type, int subtype) {
+ct_subtype_str (int type, int subtype)
+{
     switch (type) {
     case CT_APPLICATION:
         switch (subtype) {
@@ -3079,8 +2813,6 @@ ct_subtype_str (int type, int subtype) {
         switch (subtype) {
         case MESSAGE_RFC822:
             return "rfc822";
-        case MESSAGE_PARTIAL:
-            return "partial";
         case MESSAGE_EXTERNAL:
             return "external";
         default:
@@ -3119,7 +2851,8 @@ ct_subtype_str (int type, int subtype) {
 
 
 int
-ct_str_type (const char *type) {
+ct_str_type (const char *type)
+{
     struct str2init *s2i;
 
     for (s2i = str2cts; s2i->si_key; ++s2i) {
@@ -3136,7 +2869,8 @@ ct_str_type (const char *type) {
 
 
 int
-ct_str_subtype (int type, const char *subtype) {
+ct_str_subtype (int type, const char *subtype)
+{
     struct k2v *kv;
 
     switch (type) {
@@ -3176,7 +2910,8 @@ ct_str_subtype (int type, const char *subtype) {
 
 /* Find the content type and InitFunc for the CT. */
 const struct str2init *
-get_ct_init (int type) {
+get_ct_init (int type)
+{
     const struct str2init *sp;
 
     for (sp = str2cts; sp->si_key; ++sp) {
@@ -3189,7 +2924,8 @@ get_ct_init (int type) {
 }
 
 const char *
-ce_str (int encoding) {
+ce_str (int encoding)
+{
     switch (encoding) {
     case CE_BASE64:
         return "base64";
@@ -3212,7 +2948,8 @@ ce_str (int encoding) {
 
 /* Find the content type and InitFunc for the content encoding method. */
 const struct str2init *
-get_ce_method (const char *method) {
+get_ce_method (const char *method)
+{
     struct str2init *sp;
 
     for (sp = str2ces; sp->si_key; ++sp) {
@@ -3266,7 +3003,9 @@ parse_header_attrs (const char *filename, const char *fieldname,
 
     while (*cp == ';') {
        char *dp, *vp, *up, *nameptr, *valptr, *charset = NULL, *lang = NULL;
-       int encoded = 0, partial = 0, len = 0, index = 0;
+       bool encoded = false;
+        bool partial = false;
+        int len = 0, index = 0;
 
        cp++;
        while (isspace ((unsigned char) *cp))
@@ -3316,11 +3055,11 @@ parse_header_attrs (const char *filename, const char *fieldname,
 
        for (vp = cp; vp < up; vp++) {
            if (*vp == '*' && vp < up - 1) {
-               partial = 1;
+               partial = true;
                continue;
            }
             if (*vp == '*' && vp == up - 1) {
-               encoded = 1;
+               encoded = true;
            } else if (partial) {
                if (isdigit((unsigned char) *vp))
                    index = *vp - '0' + index * 10;
@@ -3353,7 +3092,7 @@ parse_header_attrs (const char *filename, const char *fieldname,
             * parameter).
             */
            if (index == 0) {
-               vp = dp;
+               vp = dp;
                while (*vp != '\'' && !isspace((unsigned char) *vp) &&
                                                        *vp != '\0')
                    vp++;
@@ -3483,7 +3222,7 @@ bad_quote:
            valptr = mh_xmalloc(len + 1);
 
            if (*dp == '"') {
-               int i;
+               int i;
                for (cp = dp + 1, vp = valptr, i = 0; i < len; i++) {
                    if (*cp == '\\') {
                        cp++;
@@ -3492,7 +3231,7 @@ bad_quote:
                }
                cp++;
            } else {
-               strncpy(valptr, cp = dp, len);
+               strncpy(valptr, cp = dp, len);
                cp += len;
            }
 
@@ -3566,7 +3305,7 @@ bad_quote:
 
            if (index == 0 && encoded) {
                 free(pp->charset);
-               pp->charset = charset;
+               pp->charset = charset;
                 free(pp->lang);
                pp->lang = lang;
            }
@@ -3590,7 +3329,7 @@ bad_quote:
      */
 
     for (pp = phead; pp != NULL; ) {
-       char *p, *q;
+       char *p, *q;
        size_t tlen = 0;
        int pindex = 0;
        for (sp = pp->sechead; sp != NULL; sp = sp->next) {
@@ -3632,7 +3371,8 @@ bad_quote:
  */
 
 char *
-content_charset (CT ct) {
+content_charset (CT ct)
+{
     char *ret_charset = NULL;
 
     ret_charset = get_param(ct->c_ctinfo.ci_first_pm, "charset", '?', 0);
@@ -3752,7 +3492,7 @@ output_params(size_t initialwidth, PM params, int *offsetout, int external)
 
        if (index > 0) {
            q += snprintf(q, sizeof(line) - (q - line), "%s*%d",
-                         params->pm_name, index);
+                         params->pm_name, index);
        } else {
            strncpy(q, params->pm_name, sizeof(line) - (q - line));
            q += strlen(q);
@@ -3760,10 +3500,10 @@ output_params(size_t initialwidth, PM params, int *offsetout, int external)
 
        if (encode)
            i = encode_param(params, q, sizeof(line) - (q - line),
-                            strlen(params->pm_value + valoff), valoff, index);
+                            strlen(params->pm_value + valoff), valoff, index);
        else
            i = normal_param(params, q, sizeof(line) - (q - line),
-                            strlen(params->pm_value + valoff), valoff);
+                            strlen(params->pm_value + valoff), valoff);
 
        if (i == 0) {
             free(paramout);
@@ -3867,7 +3607,7 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont,
        if (! pm->pm_charset) {
            pm->pm_charset = mh_xstrdup(write_charset_8bit());
            if (strcasecmp(pm->pm_charset, "US-ASCII") == 0)
-               adios(NULL, "8-bit characters in parameter \"%s\", but "
+               die("8-bit characters in parameter \"%s\", but "
                      "local character set is US-ASCII", pm->pm_name);
        }
        if (! pm->pm_lang)
@@ -3891,7 +3631,7 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont,
                len += 3;
                maxfit -= 3;
            } else {
-               len++;
+               len++;
                maxfit--;
            }
            /*
@@ -3904,7 +3644,7 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont,
                fitlimit++;
        }
     } else {
-       /*
+       /*
         * Calculate the string length, but add room for quoting \
         * and " if necessary.  Also account for quotes at beginning
         * and end.
@@ -3913,7 +3653,7 @@ param_len(PM pm, int index, size_t valueoff, int *encode, int *cont,
            switch (*p) {
            case '"':
            case '\\':
-               len++;
+               len++;
                maxfit--;
            /* FALLTHRU */
            default:
@@ -4062,7 +3802,7 @@ add_param(PM *first, PM *last, char *name, char *value, int nocopy)
        (*last)->pm_next = pm;
        *last = pm;
     } else {
-       *first = pm;
+       *first = pm;
        *last = pm;
     }
 
@@ -4107,7 +3847,7 @@ get_param(PM first, const char *name, char replace, int fetchonly)
     while (first != NULL) {
        if (strcasecmp(name, first->pm_name) == 0) {
            if (fetchonly)
-               return first->pm_value;
+               return first->pm_value;
             return getcpy(get_param_value(first, replace));
        }
        first = first->pm_next;
@@ -4121,7 +3861,8 @@ get_param(PM first, const char *name, char replace, int fetchonly)
  * necessary
  */
 
-char *get_param_value(PM pm, char replace)
+char *
+get_param_value(PM pm, char replace)
 {
     static char buffer[4096];          /* I hope no parameters are larger */
     size_t bufsize = sizeof(buffer);
@@ -4143,7 +3884,7 @@ char *get_param_value(PM pm, char replace)
      */
 
     if (!pm->pm_charset || check_charset(pm->pm_charset,
-                                        strlen(pm->pm_charset))) {
+                                        strlen(pm->pm_charset))) {
        return pm->pm_value;
     }