]> diplodocus.org Git - nmh/blobdiff - uip/mhbuildsbr.c
Alter HasSuffixC()'s char * to be const.
[nmh] / uip / mhbuildsbr.c
index 9cc5635177b8545377c4a985174e4ff57cce9577..fc90dc0151d331531deba92376868f291668f018 100644 (file)
@@ -17,7 +17,6 @@
 
 #include <h/mh.h>
 #include <fcntl.h>
-#include <h/signals.h>
 #include <h/md5.h>
 #include <h/mts.h>
 #include <h/tws.h>
@@ -162,8 +161,7 @@ build_mime (char *infile, int autobuild, int dist, int directives,
     /*
      * Allocate space for primary (outside) content
      */
-    if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL)
-       adios (NULL, "out of memory");
+    NEW0(ct);
 
     /*
      * Allocate structure for handling decoded content
@@ -192,9 +190,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 */
@@ -245,8 +242,8 @@ build_mime (char *infile, int autobuild, int dist, int directives,
                    goto finish_field;
                }
 
-               entry = mh_xmalloc(sizeof(*entry));
-               entry->filename = getcpy(s);
+               NEW(entry);
+               entry->filename = mh_xstrdup(s);
                entry->next = NULL;
                free(vp);
 
@@ -279,12 +276,12 @@ build_mime (char *infile, int autobuild, int dist, int directives,
                         adios (NULL, "Multiple %s headers with different files"
                                " not allowed", type);
                     } else {
-                        convert->filename = getcpy (filename);
+                        convert->filename = mh_xstrdup(filename);
                     }
                 } else {
-                    convert = mh_xcalloc (sizeof *convert, 1);
-                    convert->filename = getcpy (filename);
-                    convert->type = getcpy (type);
+                    NEW0(convert);
+                    convert->filename = mh_xstrdup(filename);
+                    convert->type = mh_xstrdup(type);
 
                     if (convert_tail) {
                         convert_tail->next = convert;
@@ -319,12 +316,12 @@ build_mime (char *infile, int autobuild, int dist, int directives,
                         adios (NULL, "Multiple %s headers with different "
                                "argstrings not allowed", type);
                     } else {
-                        convert->argstring = getcpy (argstring);
+                        convert->argstring = mh_xstrdup(argstring);
                     }
                 } else {
-                    convert = mh_xcalloc (sizeof *convert, 1);
-                    convert->type = getcpy (type);
-                    convert->argstring = getcpy (argstring);
+                    NEW0(convert);
+                    convert->type = mh_xstrdup(type);
+                    convert->argstring = mh_xstrdup(argstring);
 
                     if (convert_tail) {
                         convert_tail->next = convert;
@@ -361,15 +358,17 @@ finish_field:
     }
     m_getfld_state_destroy (&gstate);
 
-    /*
-     * Iterate through the list of headers and call the function to MIME-ify
-     * them if required.
-     */
+    if (header_encoding != CE_8BIT) {
+        /*
+         * Iterate through the list of headers and call the function to MIME-ify
+         * them if required.
+         */
 
-    for (hp = ct->c_first_hf; hp != NULL; hp = hp->next) {
-       if (encode_rfc2047(hp->name, &hp->value, header_encoding, NULL)) {
-           adios(NULL, "Unable to encode header \"%s\"", hp->name);
-       }
+        for (hp = ct->c_first_hf; hp != NULL; hp = hp->next) {
+            if (encode_rfc2047(hp->name, &hp->value, header_encoding, NULL)) {
+                adios(NULL, "Unable to encode header \"%s\"", hp->name);
+            }
+        }
     }
 
     /*
@@ -393,8 +392,7 @@ finish_field:
     ct->c_type = CT_MULTIPART;
     ct->c_subtype = MULTI_MIXED;
 
-    if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
-       adios (NULL, "out of memory");
+    NEW0(m);
     ct->c_ctparams = (void *) m;
     pp = &m->mp_parts;
 
@@ -413,8 +411,7 @@ finish_field:
        if (!p)
            continue;
 
-       if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
-           adios (NULL, "out of memory");
+       NEW0(part);
        *pp = part;
        pp = &part->mp_next;
        part->mp_part = p;
@@ -434,9 +431,7 @@ finish_field:
            adios("reading", "Unable to open %s for", at_entry->filename);
        }
 
-       if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL)
-           adios(NULL, "out of memory");
-
+       NEW0(p);
        init_decoded_content(p, infile);
 
        /*
@@ -447,8 +442,7 @@ finish_field:
 
        setup_attach_content(p, at_entry->filename);
 
-       if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
-           adios (NULL, "out of memory");
+       NEW0(part);
        *pp = part;
        pp = &part->mp_next;
        part->mp_part = p;
@@ -473,9 +467,8 @@ finish_field:
         free (cts);
 
         /* Extract the type part (as a CT) from filename. */
-        if (! (cts = (CT *) mh_xcalloc ((size_t) 2, sizeof *cts))) {
-            adios (NULL, "out of memory");
-        } else if (! (cts[0] = parse_mime (convert_head->filename))) {
+        cts = mh_xcalloc(2, sizeof *cts);
+        if (! (cts[0] = parse_mime (convert_head->filename))) {
             adios (NULL, "failed to parse %s", convert_head->filename);
         }
 
@@ -502,9 +495,7 @@ finish_field:
        struct part *part;
        struct text *t;
 
-       if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL)
-           adios(NULL, "out of memory");
-
+       NEW0(p);
        init_decoded_content(p, infile);
 
        if (get_ctinfo ("text/plain", p, 0) == NOTOK)
@@ -518,18 +509,15 @@ finish_field:
         * So this seems like the best option available since we're going
         * to call scan_content() on this.
         */
-       p->c_cefile.ce_file = getcpy("/dev/null");
+       p->c_cefile.ce_file = mh_xstrdup("/dev/null");
        p->c_begin = ftell(in);
        p->c_end = ftell(in);
 
-       if ((t = (struct text *) mh_xcalloc (1, sizeof (*t))) == NULL)
-           adios (NULL, "out of memory");
-
+       NEW0(t);
        t->tx_charset = CHARSET_SPECIFIED;
        p->c_ctparams = t;
 
-       if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
-           adios (NULL, "out of memory");
+       NEW0(part);
        *pp = part;
        part->mp_part = p;
     }
@@ -571,6 +559,13 @@ finish_field:
     if ((cp = strchr(prefix, 'a')) == NULL)
        adios (NULL, "internal error(4)");
 
+    /*
+     * If using EAI, force 8-bit charset.
+     */
+    if (header_encoding == CE_8BIT) {
+        set_charset (ct, 1);
+    }
+
     /*
      * Scan the contents.  Choose a transfer encoding, and
      * check if prefix for multipart boundary clashes with
@@ -676,8 +671,7 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename)
     }
 
     /* allocate basic Content structure */
-    if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL)
-       adios (NULL, "out of memory");
+    NEW0(ct);
     *ctp = ct;
 
     /* allocate basic structure for handling decoded content */
@@ -716,9 +710,8 @@ user_content (FILE *in, char *buf, CT *ctp, const char *infilename)
            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));
@@ -908,8 +901,7 @@ use_forw:
             * reference, we need to create another Content structure
             * for the message/external-body to wrap it in.
             */
-           if ((ct = (CT) mh_xcalloc (1, sizeof(*ct))) == NULL)
-               adios (NULL, "out of memory");
+           NEW0(ct);
            init_decoded_content(ct, infilename);
            *ctp = ct;
            if (get_ctinfo (buffer, ct, 0) == NOTOK)
@@ -917,8 +909,7 @@ use_forw:
            ct->c_type = CT_MESSAGE;
            ct->c_subtype = MESSAGE_EXTERNAL;
 
-           if ((e = (struct exbody *) mh_xcalloc (1, sizeof(*e))) == NULL)
-               adios (NULL, "out of memory");
+           NEW0(e);
            ct->c_ctparams = (void *) e;
 
            e->eb_parent = ct;
@@ -1027,8 +1018,7 @@ use_forw:
            ct->c_type = CT_MULTIPART;
            ct->c_subtype = MULTI_DIGEST;
 
-           if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
-               adios (NULL, "out of memory");
+           NEW0(m);
            ct->c_ctparams = (void *) m;
            pp = &m->mp_parts;
 
@@ -1038,8 +1028,7 @@ use_forw:
                    CT p;
                    CE pe;
 
-                   if ((p = (CT) mh_xcalloc (1, sizeof(*p))) == NULL)
-                       adios (NULL, "out of memory");
+                   NEW0(p);
                    init_decoded_content (p, infilename);
                    pe = &p->c_cefile;
                    if (get_ctinfo ("message/rfc822", p, 0) == NOTOK)
@@ -1052,8 +1041,7 @@ use_forw:
                    if (listsw && stat (pe->ce_file, &st) != NOTOK)
                        p->c_end = (long) st.st_size;
 
-                   if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
-                       adios (NULL, "out of memory");
+                   NEW0(part);
                    *pp = part;
                    pp = &part->mp_next;
                    part->mp_part = p;
@@ -1113,8 +1101,7 @@ use_forw:
        ct->c_type = CT_MULTIPART;
        ct->c_subtype = vrsn;
 
-       if ((m = (struct multipart *) mh_xcalloc (1, sizeof(*m))) == NULL)
-           adios (NULL, "out of memory");
+       NEW0(m);
        ct->c_ctparams = (void *) m;
 
        pp = &m->mp_parts;
@@ -1130,8 +1117,7 @@ use_forw:
            if (!p)
                continue;
 
-           if ((part = (struct part *) mh_xcalloc (1, sizeof(*part))) == NULL)
-               adios (NULL, "out of memory");
+           NEW0(part);
            *pp = part;
            pp = &part->mp_next;
            part->mp_part = p;
@@ -1160,10 +1146,10 @@ set_id (CT ct, int top)
        time (&clock);
        snprintf (contentid, sizeof(contentid), "%s\n", message_id (clock, 1));
        partno = 0;
-       msgfmt = getcpy(contentid);
+       msgfmt = mh_xstrdup(contentid);
     }
     snprintf (contentid, sizeof(contentid), msgfmt, top ? 0 : ++partno);
-    ct->c_id = getcpy (contentid);
+    ct->c_id = mh_xstrdup(contentid);
 }
 
 
@@ -1452,15 +1438,17 @@ scan_content (CT ct, size_t maxunencoded)
      * Decide what to check while scanning this content.  Note that
      * for text content we always check for 8bit characters if the
      * charset is unspecified, because that controls whether or not the
-     * character set is us-ascii or retrieved from the locale.
+     * character set is us-ascii or retrieved from the locale.  And
+     * we check even if the charset is specified, to allow setting
+     * the proper Content-Transfer-Encoding.
      */
 
     if (ct->c_type == CT_TEXT) {
        t = (struct text *) ct->c_ctparams;
        if (t->tx_charset == CHARSET_UNSPECIFIED) {
-           check8bit = 1;
            checknul = 1;
        }
+       check8bit = 1;
     }
 
     switch (ct->c_reqencoding) {
@@ -1749,8 +1737,11 @@ build_headers (CT ct, int header_encoding)
     if (ct->c_descr) {
        np = add (DESCR_FIELD, NULL);
        vp = concat (" ", ct->c_descr, NULL);
-       if (encode_rfc2047(DESCR_FIELD, &vp, header_encoding, NULL))
-           adios(NULL, "Unable to encode %s header", DESCR_FIELD);
+       if (header_encoding != CE_8BIT) {
+           if (encode_rfc2047(DESCR_FIELD, &vp, header_encoding, NULL)) {
+               adios(NULL, "Unable to encode %s header", DESCR_FIELD);
+           }
+       }
        add_header (ct, np, vp);
     }
 
@@ -1768,9 +1759,8 @@ 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);
-       add_header (ct, getcpy(DISPO_FIELD), vp);
+        mh_xfree(np);
+       add_header (ct, mh_xstrdup(DISPO_FIELD), vp);
     }
 
 skip_headers:
@@ -1793,7 +1783,12 @@ skip_headers:
 
     /*
      * output the Content-Transfer-Encoding
+     * If using EAI and message body is 7-bit, force 8-bit C-T-E.
      */
+    if (header_encoding == CE_8BIT  &&  ct->c_encoding == CE_7BIT) {
+        ct->c_encoding = CE_8BIT;
+    }
+
     switch (ct->c_encoding) {
     case CE_7BIT:
        /* Nothing to output */
@@ -2037,9 +2032,8 @@ 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);
-           pm->pm_value = getcpy(simplename);
+            mh_xfree(pm->pm_value);
+           pm->pm_value = mh_xstrdup(simplename);
            break;
        }
     }
@@ -2048,9 +2042,9 @@ setup_attach_content(CT ct, char *filename)
        add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm,
                  "name", simplename, 0);
 
-    ct->c_descr = getcpy(simplename);
+    ct->c_descr = mh_xstrdup(simplename);
     ct->c_descr = add("\n", ct->c_descr);
-    ct->c_cefile.ce_file = getcpy(filename);
+    ct->c_cefile.ce_file = mh_xstrdup(filename);
 
     set_disposition (ct);
 
@@ -2081,7 +2075,9 @@ set_disposition (CT ct) {
                       cp);
         }
 
-        ct->c_dispo_type = cp  ?  getcpy (cp)  :  getcpy ("attachment");
+        if (!cp)
+            cp = "attachment";
+        ct->c_dispo_type = mh_xstrdup(cp);
     }
 }
 
@@ -2098,11 +2094,8 @@ set_charset (CT ct, int contains8bit) {
         struct text *t;
 
         if (ct->c_ctparams == NULL) {
-            if ((t = ct->c_ctparams =
-                 (struct text *) mh_xcalloc (1, sizeof (struct text))) ==
-                NULL) {
-                adios (NULL, "out of memory");
-            }
+            NEW0(t);
+            ct->c_ctparams = t;
             t->tx_charset = CHARSET_UNSPECIFIED;
         } else {
             t = (struct text *) ct->c_ctparams;
@@ -2160,7 +2153,7 @@ expand_pseudoheaders (CT ct, struct multipart *m, const char *infile,
                             part->mp_part->c_ctinfo.ci_subtype, NULL);
 
                 if (part->mp_part->c_type == CT_MULTIPART) {
-                    expand_pseudoheaders (part->mp_part, mp, infile,
+                    expand_pseudoheaders (part->mp_part, m, infile,
                                           convert_head);
                 } else {
                     const convert_list *c;
@@ -2221,6 +2214,8 @@ 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);
     if ((subtype_p = strchr (type_p, '/'))) {
@@ -2245,15 +2240,17 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
                 NULL);
 
     /* Convert here . . . */
-    ct->c_storeproc = getcpy (convert_command);
+    ct->c_storeproc = mh_xstrdup(convert_command);
     ct->c_umask = ~m_gmprot ();
-    if (show_content_aux (ct, 0, convert_command, NULL, NULL) == NOTOK) {
+
+    if ((status = show_content_aux (ct, 0, convert_command, NULL, NULL)) !=
+        OK) {
         admonish (NULL, "store of %s content failed", type);
     }
     free (convert_command);
 
     /* Fill out the the new ct, reply_ct. */
-    reply_ct = (CT) mh_xcalloc (1, sizeof *reply_ct);
+    NEW0(reply_ct);
     init_decoded_content (reply_ct, infile);
 
     if (extract_headers (reply_ct, reply_file, &reply_fp) == NOTOK) {
@@ -2264,6 +2261,19 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
         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;
+        } 
+        (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++) {
@@ -2284,25 +2294,36 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
         set_charset (reply_ct, -1);
         charset = get_param (reply_ct->c_ctinfo.ci_first_pm, "charset", '?', 1);
         if (reply_ct->c_reqencoding == CE_UNKNOWN  &&
-            strcasecmp (charset, "US-ASCII")) {
-            /* Assume that 8bit is sufficient (for text). */
-            reply_ct->c_reqencoding = CE_8BIT;
+            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 (m->mp_parts  &&  ! *text_plain_ct) {
+        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. */
             set_charset (*text_plain_ct, -1);
-            if ((*text_plain_ct)->c_reqencoding == CE_UNKNOWN  &&
-                strcasecmp (charset, "US-ASCII")) {
-                /* Assume that 8bit is sufficient (for text). */
-                (*text_plain_ct)->c_reqencoding = CE_8BIT;
+            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;
             }
         }
 
@@ -2323,6 +2344,7 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
 
                 if (text_plain_reply != NOTOK  &&  addl_reply != NOTOK) {
                     /* Insert blank line before each addl part. */
+                    /* It would be nice not to do this for the first one. */
                     if (write (text_plain_reply, "\n", 1) == 1) {
                         /* Copy the text from the new reply and
                            then free its Content struct. */
@@ -2331,6 +2353,13 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
                                  reply_file);
                         if (close (text_plain_reply) == OK  &&
                             close (addl_reply) == OK) {
+                            /* If appended text needed 8-bit but first text didn't,
+                               propagate the 8-bit indication. */
+                            if ((*text_plain_ct)->c_reqencoding == CE_7BIT  &&
+                                reply_ct->c_reqencoding == CE_8BIT) {
+                                (*text_plain_ct)->c_reqencoding = CE_8BIT;
+                            }
+
                             if (reply_fp) { fclose (reply_fp); }
                             free (reply_file);
                             free_content (reply_ct);
@@ -2348,8 +2377,8 @@ expand_pseudoheader (CT ct, CT *text_plain_ct, struct multipart *m,
     reply_ct->c_cefile.ce_fp = reply_fp;
     reply_ct->c_cefile.ce_unlink = 1;
 
-    /* Attach the new part to the parent mulitpart/mixed, "m". */
-    part = (struct part *) mh_xcalloc (1, sizeof *part);
+    /* Attach the new part to the parent multipart/mixed, "m". */
+    NEW0(part);
     part->mp_part = reply_ct;
     if (m->mp_parts) {
         struct part *p;
@@ -2386,12 +2415,15 @@ extract_headers (CT ct, char *reply_file, FILE **reply_fp) {
     buffer[statbuf.st_size] = '\0';
 
     /* Look for a header in the convert reply. */
-    if ((end_of_header = strstr (buffer, "\r\n\r\n"))) {
-        end_of_header += 2;
-        found_header = 1;
-    } else if ((end_of_header = strstr (buffer, "\n\n"))) {
-        ++end_of_header;
-        found_header = 1;
+    if (strncasecmp (buffer, TYPE_FIELD, strlen (TYPE_FIELD)) == 0  &&
+        buffer[strlen (TYPE_FIELD)] == ':') {
+        if ((end_of_header = strstr (buffer, "\r\n\r\n"))) {
+            end_of_header += 2;
+            found_header = 1;
+        } else if ((end_of_header = strstr (buffer, "\n\n"))) {
+            ++end_of_header;
+            found_header = 1;
+        }
     }
 
     if (found_header) {