]> diplodocus.org Git - nmh/blobdiff - uip/mhbuildsbr.c
Hacked m_Eom() to fix test-eom-align.
[nmh] / uip / mhbuildsbr.c
index c72bd8185a8a6ee01a0c3dc18965ba58d23d481c..e34dd978f7e6669479065e094b7d4db334e06396 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * mhbuildsbr.c -- routines to expand/translate MIME composition files
+/* mhbuildsbr.c -- routines to expand/translate MIME composition files
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
 #include <h/md5.h>
 #include <h/mts.h>
 #include <h/tws.h>
+#include <h/fmt_scan.h>
 #include <h/mime.h>
 #include <h/mhparse.h>
 #include <h/utils.h>
+#include "../sbr/m_mktemp.h"
+#include "../sbr/message_id.h"
+#include "../sbr/mime_type.h"
+#include "mhfree.h"
+#include "mhshowsbr.h"
 
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
@@ -36,10 +40,6 @@ extern int listsw;
 extern int rfc934sw;
 extern int contentidsw;
 
-/* cache policies */
-extern int rcachesw;   /* mhcachesbr.c */
-extern int wcachesw;   /* mhcachesbr.c */
-
 static char prefix[] = "----- =_aaaaaaaaaa";
 
 struct attach_list {
@@ -54,12 +54,6 @@ typedef struct convert_list {
     struct convert_list *next;
 } convert_list;
 
-/*
- * Maximum size of URL token in message/external-body
- */
-
-#define MAXURLTOKEN 40
-
 
 /* mhmisc.c */
 void content_error (char *, CT, char *, ...);
@@ -67,12 +61,6 @@ void content_error (char *, CT, char *, ...);
 /* mhcachesbr.c */
 int find_cache (CT, int, int *, char *, char *, int);
 
-/* mhfree.c */
-extern CT *cts;
-void freects_done (int) NORETURN;
-void free_ctinfo (CT);
-void free_encoding (CT, int);
-
 /*
  * static prototypes
  */
@@ -139,7 +127,7 @@ build_mime (char *infile, int autobuild, int dist, int directives,
            int header_encoding, size_t maxunencoded, int verbose)
 {
     int        compnum, state;
-    char buf[BUFSIZ], name[NAMESZ];
+    char buf[NMH_BUFSIZ], name[NAMESZ];
     char *cp, *np, *vp;
     struct multipart *m;
     struct part **pp;
@@ -190,9 +178,8 @@ build_mime (char *infile, int autobuild, int dist, int directives,
                    fclose(in);
                    free (ct);
                    return NULL;
-               } else {
-                   adios (NULL, "draft shouldn't contain %s: field", name);
                }
+                adios (NULL, "draft shouldn't contain %s: field", name);
            }
 
            /* ignore any Content-Type fields in the header */
@@ -205,8 +192,8 @@ build_mime (char *infile, int autobuild, int dist, int directives,
            }
 
            /* get copies of the buffers */
-           np = add (name, NULL);
-           vp = add (buf, NULL);
+           np = mh_xstrdup(name);
+           vp = mh_xstrdup(buf);
 
            /* if necessary, get rest of field */
            while (state == FLDPLUS) {
@@ -344,7 +331,7 @@ finish_field:
 
        case BODY:
            fseek (in, (long) (-strlen (buf)), SEEK_CUR);
-           /* fall through */
+           break;
        case FILEEOF:
            break;
 
@@ -378,13 +365,13 @@ finish_field:
      */
 
     if (! dist) {
-       np = add (VRSN_FIELD, NULL);
+       np = mh_xstrdup(VRSN_FIELD);
        vp = concat (" ", VRSN_VALUE, "\n", NULL);
        add_header (ct, np, vp);
     }
 
     /*
-     * We initally assume we will find multiple contents in the
+     * We initially assume we will find multiple contents in the
      * draft.  So create a multipart/mixed content to hold everything.
      * We can remove this later, if it is not needed.
      */
@@ -406,7 +393,7 @@ finish_field:
        CT p;
 
        if (user_content (in, buf, &p, infile) == DONE) {
-           admonish (NULL, "ignoring spurious #end");
+           inform("ignoring spurious #end, continuing...");
            continue;
        }
        if (!p)
@@ -613,23 +600,26 @@ static char *
 fgetstr (char *s, int n, FILE *stream)
 {
     char *cp, *ep;
-    int o_n = n;
 
+    ep = s + n;
     while(1) {
-       for (ep = (cp = s) + o_n; cp < ep; ) {
-           int i;
+       for (cp = s; cp < ep;) {
+           int len;
 
            if (!fgets (cp, n, stream))
-               return (cp != s ? s : NULL);
+                return cp == s ? NULL : s; /* "\\\nEOF" ignored. */
 
-           if (cp == s && *cp != '#')
-               return s;
+           if (! do_direct()  ||  (cp == s && *cp != '#'))
+               return s; /* Plaintext line. */
 
-           cp += (i = strlen (cp)) - 1;
-           if (i <= 1 || *cp-- != '\n' || *cp != '\\')
+           len = strlen(cp);
+           if (len <= 1)
+               break; /* Can't contain "\\\n". */
+           cp += len - 1; /* Just before NUL. */
+           if (*cp-- != '\n' || *cp != '\\')
                break;
-           *cp = '\0';
-           n -= (i - 2);
+           *cp = '\0'; /* Erase the trailing "\\\n". */
+           n -= (len - 2);
        }
 
        if (strcmp(s, "#on\n") == 0) {
@@ -639,11 +629,9 @@ fgetstr (char *s, int n, FILE *stream)
        } else if (strcmp(s, "#pop\n") == 0) {
            directive_pop();
        } else {
-           break;
+           return s;
        }
     }
-
-    return s;
 }
 
 
@@ -657,7 +645,7 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename)
 {
     int        extrnal, vrsn;
     char *cp, **ap;
-    char buffer[BUFSIZ];
+    char buffer[NMH_BUFSIZ];
     struct multipart *m;
     struct part **pp;
     struct stat st;
@@ -704,16 +692,15 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename)
        }
 
        /* use a temp file to collect the plain text lines */
-       ce->ce_file = add (cp, NULL);
+       ce->ce_file = mh_xstrdup(cp);
        ce->ce_unlink = 1;
 
        if (do_direct() && (buf[0] == '#' && buf[1] == '<')) {
            strncpy (content, buf + 2, sizeof(content));
            inlineD = 1;
            goto rock_and_roll;
-       } else {
-           inlineD = 0;
        }
+        inlineD = 0;
 
        /* the directive is implicit */
        strncpy (content, "text/plain", sizeof(content));
@@ -810,7 +797,7 @@ rock_and_roll:
                ct->c_encoding = CE_7BIT;
                goto call_init;
            }
-           /* else fall... */
+           /* FALLTHRU */
        case CT_MULTIPART:
            adios (NULL, "it doesn't make sense to define an in-line %s content",
                   ct->c_type == CT_MESSAGE ? "message" : "multipart");
@@ -932,7 +919,7 @@ use_forw:
                    continue;
                if (!*cp)
                    adios (NULL, "empty pipe command for #%s directive", ci->ci_type);
-               cp = add (cp, NULL);
+               cp = mh_xstrdup(cp);
                free (ci->ci_magic);
                ci->ci_magic = cp;
            } else {
@@ -956,7 +943,7 @@ use_forw:
            content_error (NULL, ct, "don't know how to compose content");
            done (1);
        }
-       ci->ci_magic = add (cp, NULL);
+       ci->ci_magic = mh_xstrdup(cp);
        return OK;
     }
 
@@ -994,7 +981,7 @@ use_forw:
 
        /* else, use the current folder */
        if (!folder)
-           folder = add (getfolder (1), NULL);
+           folder = mh_xstrdup(getfolder(1));
 
        if (!(mp = folder_read (folder, 0)))
            adios (NULL, "unable to read folder %s", folder);
@@ -1039,7 +1026,7 @@ use_forw:
                    p->c_subtype = MESSAGE_RFC822;
 
                    snprintf (buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum);
-                   pe->ce_file = add (buffer, NULL);
+                   pe->ce_file = mh_xstrdup(buffer);
                    if (listsw && stat (pe->ce_file, &st) != NOTOK)
                        p->c_end = (long) st.st_size;
 
@@ -1058,7 +1045,7 @@ use_forw:
 
            msgnum = mp->lowsel;
            snprintf (buffer, sizeof(buffer), "%s/%d", mp->foldpath, msgnum);
-           ce->ce_file = add (buffer, NULL);
+           ce->ce_file = mh_xstrdup(buffer);
            if (listsw && stat (ce->ce_file, &st) != NOTOK)
                ct->c_end = (long) st.st_size;
        }
@@ -1124,7 +1111,7 @@ use_forw:
            pp = &part->mp_next;
            part->mp_part = p;
        }
-       admonish (NULL, "premature end-of-file, missing #end");
+       inform("premature end-of-file, missing #end, continuing...");
        return OK;
     }
 
@@ -1187,7 +1174,7 @@ compose_content (CT ct, int verbose)
            CT p = part->mp_part;
 
            sprintf (pp, "%d", partnum);
-           p->c_partno = add (partnam, NULL);
+           p->c_partno = mh_xstrdup(partnam);
            if (compose_content (p, verbose) == NOTOK)
                return NOTOK;
        }
@@ -1221,7 +1208,7 @@ compose_content (CT ct, int verbose)
        if (listsw) {
            ct->c_end = (partnum = strlen (prefix) + 2) + 2;
            if (ct->c_rfc934)
-               ct->c_end += 1;
+               ct->c_end++;
 
            for (part = m->mp_parts; part; part = part->mp_next)
                ct->c_end += part->mp_part->c_end + partnum;
@@ -1253,7 +1240,7 @@ compose_content (CT ct, int verbose)
                adios("mhbuildsbr", "unable to create temporary file in %s",
                      get_temp_dir());
            }
-           ce->ce_file = add (tfile, NULL);
+           ce->ce_file = mh_xstrdup(tfile);
            ce->ce_unlink = 1;
 
            xstdout = 0;
@@ -1289,7 +1276,7 @@ compose_content (CT ct, int verbose)
                    case 'F':
                        /* %f, and stdout is not-redirected */
                        xstdout = 1;
-                       /* and fall... */
+                       /* FALLTHRU */
 
                    case 'f':
                        /*
@@ -1680,7 +1667,7 @@ build_headers (CT ct, int header_encoding)
     /*
      * output the content type and subtype
      */
-    np = add (TYPE_FIELD, NULL);
+    np = mh_xstrdup(TYPE_FIELD);
     vp = concat (" ", ci->ci_type, "/", ci->ci_subtype, NULL);
 
     /* keep track of length of line */
@@ -1726,10 +1713,12 @@ build_headers (CT ct, int header_encoding)
     add_header (ct, np, vp);
 
     /*
-     * output the Content-ID, unless disabled by -nocontentid
+     * output the Content-ID, unless disabled by -nocontentid.  Note that
+     * RFC 2045 always requires a Content-ID header for message/external-body
+     * entities.
      */
-    if (contentidsw && ct->c_id) {
-       np = add (ID_FIELD, NULL);
+    if ((contentidsw || ct->c_ctexbody) && ct->c_id) {
+       np = mh_xstrdup(ID_FIELD);
        vp = concat (" ", ct->c_id, NULL);
        add_header (ct, np, vp);
     }
@@ -1737,7 +1726,7 @@ build_headers (CT ct, int header_encoding)
      * output the Content-Description
      */
     if (ct->c_descr) {
-       np = add (DESCR_FIELD, NULL);
+       np = mh_xstrdup(DESCR_FIELD);
        vp = concat (" ", ct->c_descr, NULL);
        if (header_encoding != CE_8BIT) {
            if (encode_rfc2047(DESCR_FIELD, &vp, header_encoding, NULL)) {
@@ -1752,7 +1741,7 @@ build_headers (CT ct, int header_encoding)
      * set, then we need to build it.
      */
     if (ct->c_dispo) {
-       np = add (DISPO_FIELD, NULL);
+       np = mh_xstrdup(DISPO_FIELD);
        vp = concat (" ", ct->c_dispo, NULL);
        add_header (ct, np, vp);
     } else if (ct->c_dispo_type) {
@@ -1761,8 +1750,7 @@ build_headers (CT ct, int header_encoding)
        np = output_params(len, ct->c_dispo_first, NULL, 0);
        vp = add(np, vp);
        vp = add("\n", vp);
-       if (np)
-           free(np);
+        mh_xfree(np);
        add_header (ct, mh_xstrdup(DISPO_FIELD), vp);
     }
 
@@ -1779,8 +1767,8 @@ skip_headers:
      * output the Content-MD5
      */
     if (checksw) {
-       np = add (MD5_FIELD, NULL);
-       vp = calculate_digest (ct, (ct->c_encoding == CE_QUOTED) ? 1 : 0);
+       np = mh_xstrdup(MD5_FIELD);
+        vp = calculate_digest (ct, ct->c_encoding == CE_QUOTED);
        add_header (ct, np, vp);
     }
 
@@ -1798,7 +1786,7 @@ skip_headers:
        break;
 
     case CE_8BIT:
-       np = add (ENCODING_FIELD, NULL);
+       np = mh_xstrdup(ENCODING_FIELD);
        vp = concat (" ", "8bit", "\n", NULL);
        add_header (ct, np, vp);
        break;
@@ -1807,7 +1795,7 @@ skip_headers:
        if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART)
            adios (NULL, "internal error, invalid encoding");
 
-       np = add (ENCODING_FIELD, NULL);
+       np = mh_xstrdup(ENCODING_FIELD);
        vp = concat (" ", "quoted-printable", "\n", NULL);
        add_header (ct, np, vp);
        break;
@@ -1816,7 +1804,7 @@ skip_headers:
        if (ct->c_type == CT_MESSAGE || ct->c_type == CT_MULTIPART)
            adios (NULL, "internal error, invalid encoding");
 
-       np = add (ENCODING_FIELD, NULL);
+       np = mh_xstrdup(ENCODING_FIELD);
        vp = concat (" ", "base64", "\n", NULL);
        add_header (ct, np, vp);
        break;
@@ -1825,7 +1813,7 @@ skip_headers:
        if (ct->c_type == CT_MESSAGE)
            adios (NULL, "internal error, invalid encoding");
 
-       np = add (ENCODING_FIELD, NULL);
+       np = mh_xstrdup(ENCODING_FIELD);
        vp = concat (" ", "binary", "\n", NULL);
        add_header (ct, np, vp);
        break;
@@ -1930,7 +1918,7 @@ calculate_digest (CT ct, int asciiP)
        unsigned char *ep;
 
        fprintf (stderr, "MD5 digest=");
-       for (ep = (dp = digest) + sizeof(digest) / sizeof(digest[0]);
+       for (ep = (dp = digest) + sizeof digest;
                 dp < ep; dp++)
            fprintf (stderr, "%02x", *dp & 0xff);
        fprintf (stderr, "\n");
@@ -1938,7 +1926,7 @@ calculate_digest (CT ct, int asciiP)
 
     /* encode the digest using base64 */
     for (dp = digest, op = (char *) outbuf,
-                               cc = sizeof(digest) / sizeof(digest[0]);
+                               cc = sizeof digest;
                cc > 0; cc -= 3, op += 4) {
        unsigned long bits;
        char *bp;
@@ -1985,7 +1973,7 @@ setup_attach_content(CT ct, char *filename)
 
     /*
      * Parse the Content-Type.  get_ctinfo() parses MIME parameters, but
-     * since we're just feeding it a MIME type we have to add those ourself.
+     * since we're just feeding it a MIME type we have to add those ourselves.
      * Map that to a valid content-type label and call any initialization
      * function.
      */
@@ -2017,7 +2005,7 @@ setup_attach_content(CT ct, char *filename)
        if (strcasecmp(ct->c_ctinfo.ci_subtype, "external-body") == 0)
            adios(NULL, "external-body messages must be specified "
                "by mhbuild directives");
-       /* Fall through */
+       /* FALLTHRU */
 
     default:
        /*
@@ -2035,8 +2023,7 @@ setup_attach_content(CT ct, char *filename)
 
     for (pm = ct->c_ctinfo.ci_first_pm; pm; pm = pm->pm_next) {
        if (strcasecmp(pm->pm_name, "name") == 0) {
-           if (pm->pm_value)
-               free(pm->pm_value);
+            mh_xfree(pm->pm_value);
            pm->pm_value = mh_xstrdup(simplename);
            break;
        }
@@ -2070,13 +2057,13 @@ set_disposition (CT ct) {
 
         if (cp  &&  strcasecmp (cp, "attachment")  &&
             strcasecmp (cp, "inline")) {
-            admonish (NULL, "configuration problem: %s-disposition-%s%s%s "
-                      "specifies '%s' but only 'attachment' and 'inline' are "
-                      "allowed", invo_name,
-                      ct->c_ctinfo.ci_type,
-                      ct->c_ctinfo.ci_subtype ? "/" : "",
-                      ct->c_ctinfo.ci_subtype ? ct->c_ctinfo.ci_subtype : "",
-                      cp);
+            inform("configuration problem: %s-disposition-%s%s%s specifies "
+               "'%s' but only 'attachment' and 'inline' are allowed, "
+               "continuing...", invo_name,
+               ct->c_ctinfo.ci_type,
+               ct->c_ctinfo.ci_subtype ? "/" : "",
+               FENDNULL(ct->c_ctinfo.ci_subtype),
+               cp);
         }
 
         if (!cp)
@@ -2087,7 +2074,7 @@ set_disposition (CT ct) {
 
 /*
  * Set text content charset if it was unspecified.  contains8bit
- * selctions:
+ * selections:
  * 0: content does not contain 8-bit characters
  * 1: content contains 8-bit characters
  * -1: ignore content and use user's locale to determine charset
@@ -2218,7 +2205,6 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
     struct str2init *s2i;
     CT reply_ct;
     struct part *part;
-    int eightbit = 0;
     int status;
 
     type_p = getcpy (type);
@@ -2233,15 +2219,13 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
     free (type_p);
 
     if (! (convert)) {
-        /* No mhbuild-convert- entry in mhn.defaults or profile
-           for type. */
+        /* No mhbuild-convert- entry in mhn.defaults or profile for type. */
         return;
     }
     /* reply_file is used to pass the output of the convert. */
     reply_file = getcpy (m_mktemp2 (NULL, invo_name, NULL, NULL));
     convert_command =
-        concat (convert, " ", argstring ? argstring : "", " >", reply_file,
-                NULL);
+        concat (convert, " ", FENDNULL(argstring), " >", reply_file, NULL);
 
     /* Convert here . . . */
     ct->c_storeproc = mh_xstrdup(convert_command);
@@ -2249,7 +2233,7 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
 
     if ((status = show_content_aux (ct, 0, convert_command, NULL, NULL)) !=
         OK) {
-        admonish (NULL, "store of %s content failed", type);
+        inform("store of %s content failed, continuing...", type);
     }
     free (convert_command);
 
@@ -2259,26 +2243,11 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
 
     if (extract_headers (reply_ct, reply_file, &reply_fp) == NOTOK) {
         free (reply_file);
-        admonish (NULL,
-                  "failed to extract headers from convert output in %s",
-                  reply_file);
+        inform("failed to extract headers from convert output in %s, "
+           "continuing...", reply_file);
         return;
     }
 
-    /* For text content only, see if it is 8-bit text. */
-    if (reply_ct->c_type == CT_TEXT) {
-        int fd;
-
-        if ((fd = open (reply_file, O_RDONLY)) == NOTOK  ||
-            scan_input (fd, &eightbit) == NOTOK) {
-            free (reply_file);
-            admonish (NULL, "failed to read %s", reply_file);
-            return;
-        } else {
-            (void) close (fd);
-        }
-    }
-
     /* This sets reply_ct->c_ctparams, and reply_ct->c_termproc if the
        charset can't be handled natively. */
     for (s2i = str2cts; s2i->si_key; s2i++) {
@@ -2291,45 +2260,22 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
         (*reply_ct->c_ctinitfnx)(reply_ct);
     }
 
-    if ((cp =
-         get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1))) {
+    if ((cp = get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1))) {
         /* The reply Content-Type had the charset. */
         charset = cp;
     } else {
         set_charset (reply_ct, -1);
         charset = get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1);
-        if (reply_ct->c_reqencoding == CE_UNKNOWN  &&
-            reply_ct->c_type == CT_TEXT) {
-            /* Assume that 8bit is sufficient (for text).  In other words,
-               don't allow it to be encoded as quoted printable if lines
-               are too long.  This also sidesteps the check for whether
-               it needs to be encoded as binary; instead, it relies on
-               the applicable mhbuild-convert-text directive to ensure
-               that the resultant text is not binary. */
-            reply_ct->c_reqencoding = eightbit  ?  CE_8BIT  :  CE_7BIT;
-        }
     }
 
     /* Concatenate text/plain parts. */
-    if (reply_ct->c_type == CT_TEXT  &&
-        reply_ct->c_subtype == TEXT_PLAIN) {
+    if (reply_ct->c_type == CT_TEXT  &&  reply_ct->c_subtype == TEXT_PLAIN) {
         if (! *text_plain_ct  &&  m->mp_parts  &&  m->mp_parts->mp_part  &&
             m->mp_parts->mp_part->c_type == CT_TEXT  &&
             m->mp_parts->mp_part->c_subtype == TEXT_PLAIN) {
             *text_plain_ct = m->mp_parts->mp_part;
-            /* Make sure that the charset is set in the text/plain
-               part. */
+            /* Make sure that the charset is set in the text/plain part. */
             set_charset (*text_plain_ct, -1);
-            if ((*text_plain_ct)->c_reqencoding == CE_UNKNOWN) {
-                /* Assume that 8bit is sufficient (for text).  In other words,
-                   don't allow it to be encoded as quoted printable if lines
-                   are too long.  This also sidesteps the check for whether
-                   it needs to be encoded as binary; instead, it relies on
-                   the applicable mhbuild-convert-text directive to ensure
-                   that the resultant text is not binary. */
-                (*text_plain_ct)->c_reqencoding =
-                    eightbit  ?  CE_8BIT  :  CE_7BIT;
-            }
         }
 
         if (*text_plain_ct) {
@@ -2442,7 +2388,7 @@ extract_headers (CT ct, char *reply_file, FILE **reply_fp) {
         n = strlen (buffer);
 
         if (get_ctinfo (buffer + 14, ct, 0) != OK) {
-            admonish (NULL, "unable to get content info for reply");
+            inform("unable to get content info for reply, continuing...");
             goto failed_to_extract_ct;
         }