]> diplodocus.org Git - nmh/blobdiff - uip/mhfixmsg.c
Dynamically allocate space for the output of fmt_scan(), using
[nmh] / uip / mhfixmsg.c
index df475646d993ecb771a9f8bc100e3260635f9a6b..f5488532bfa7df9f6ac05a40cf7b4852a05a9d2d 100644 (file)
@@ -53,15 +53,11 @@ int debugsw; /* Needed by mhparse.c. */
 extern int skip_mp_cte_check;                 /* flag to InitMultiPart */
 extern int suppress_bogus_mp_content_warning; /* flag to InitMultiPart */
 extern int bogus_mp_content;                  /* flag from InitMultiPart */
-CT parse_mime (char *);
 void reverse_parts (CT);
 
 /* mhoutsbr.c */
 int output_message (CT, char *);
 
-/* mhshowsbr.c */
-int show_content_aux (CT, int, int, char *, char *);
-
 /* mhmisc.c */
 void flush_errors (void);
 
@@ -85,7 +81,7 @@ int mhfixmsgsbr (CT *, const fix_transformations *, char *);
 static void reverse_alternative_parts (CT);
 static int fix_boundary (CT *, int *);
 static int get_multipart_boundary (CT, char **);
-static int replace_boundary (CT, char *, const char *);
+static int replace_boundary (CT, char *, char *);
 static int fix_multipart_cte (CT, int *);
 static int set_ce (CT, int);
 static int ensure_text_plain (CT *, CT, int *, int);
@@ -100,12 +96,12 @@ static int boundary_in_content (FILE **, char *, const char *);
 static void transfer_noncontent_headers (CT, CT);
 static int set_ct_type (CT, int type, int subtype, int encoding);
 static int decode_text_parts (CT, int, int *);
-static int content_encoding (CT);
+static int content_encoding (CT, const char **);
 static int strip_crs (CT, int *);
 static int convert_charsets (CT, char *, int *);
 static int write_content (CT, char *, char *, int, int);
 static int remove_file (char *);
-static void report (char *, char *, char *, ...);
+static void report (char *, char *, char *, char *, ...);
 static void pipeser (int);
 
 
@@ -291,11 +287,12 @@ main (int argc, char **argv) {
             }
         }
 
-        if (! (cts = (CT *) calloc ((size_t) 2, sizeof *cts)))
+        if (! (cts = (CT *) calloc ((size_t) 2, sizeof *cts))) {
             adios (NULL, "out of memory");
+        }
         ctp = cts;
 
-        if ((ct = parse_mime (file))) *ctp++ = ct;
+        if ((ct = parse_mime (file))) { *ctp++ = ct; }
     } else {
         /*
          * message(s) are coming from a folder
@@ -325,8 +322,9 @@ main (int argc, char **argv) {
                 done (1);
         seq_setprev (mp);       /* set the previous-sequence */
 
-        if (! (cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof *cts)))
+        if (! (cts = (CT *) calloc ((size_t) (mp->numsel + 1), sizeof *cts))) {
             adios (NULL, "out of memory");
+        }
         ctp = cts;
 
         for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
@@ -334,7 +332,7 @@ main (int argc, char **argv) {
                 char *msgnam;
 
                 msgnam = m_name (msgnum);
-                if ((ct = parse_mime (msgnam))) *ctp++ = ct;
+                if ((ct = parse_mime (msgnam))) { *ctp++ = ct; }
             }
         }
 
@@ -450,7 +448,7 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) {
     }
 
     if (modify_inplace) {
-        if (status != OK) (void) m_unlink (outfile);
+        if (status != OK) { (void) m_unlink (outfile); }
         free (outfile);
         outfile = NULL;
     }
@@ -516,7 +514,7 @@ fix_boundary (CT *ct, int *message_mods) {
 
                             ++*message_mods;
                             if (verbosw) {
-                                report (NULL, filename,
+                                report (NULL, NULL, filename,
                                         "fix multipart boundary");
                             }
                         }
@@ -563,10 +561,11 @@ get_multipart_boundary (CT ct, char **part_boundary) {
     while (begin >= (off_t) ct->c_begin) {
         fseeko (ct->c_fp, begin, SEEK_SET);
         while ((bytes_read = fread (buffer, 1, sizeof buffer, ct->c_fp)) > 0) {
-            char *end = buffer + bytes_read - 1;
-            char *cp;
+            char *cp = rfind_str (buffer, bytes_read, "--");
+
+            if (cp) {
+                char *end;
 
-            if ((cp = rfind_str (buffer, bytes_read, "--"))) {
                 /* Trim off trailing "--" and anything beyond. */
                 *cp-- = '\0';
                 if ((end = rfind_str (buffer, cp - buffer, "\n"))) {
@@ -622,7 +621,7 @@ get_multipart_boundary (CT ct, char **part_boundary) {
 
 /* Open and copy ct->c_file to file, replacing the multipart boundary. */
 static int
-replace_boundary (CT ct, char *file, const char *boundary) {
+replace_boundary (CT ct, char *file, char *boundary) {
     FILE *fpin, *fpout;
     int compnum, state;
     char buf[BUFSIZ], name[NAMESZ];
@@ -668,10 +667,22 @@ replace_boundary (CT ct, char *file, const char *boundary) {
             if (strcasecmp (TYPE_FIELD, np)) {
                 fprintf (fpout, "%s:%s", np, vp);
             } else {
-                char *new_boundary = update_attr (vp, "boundary=", boundary);
-
-                fprintf (fpout, "%s:%s\n", np, new_boundary);
-                free (new_boundary);
+               char *new_ctline, *new_params;
+
+               replace_param(&ct->c_ctinfo.ci_first_pm,
+                             &ct->c_ctinfo.ci_last_pm, "boundary",
+                             boundary, 0);
+
+               new_ctline = concat(" ", ct->c_ctinfo.ci_type, "/",
+                                   ct->c_ctinfo.ci_subtype, NULL);
+               new_params = output_params(strlen(TYPE_FIELD) +
+                                          strlen(new_ctline) + 1,
+                                          ct->c_ctinfo.ci_first_pm, NULL, 0);
+                fprintf (fpout, "%s:%s%s\n", np, new_ctline,
+                        new_params ? new_params : "");
+               free(new_ctline);
+               if (new_params)
+                   free(new_params);
             }
 
             free (vp);
@@ -746,7 +757,7 @@ fix_multipart_cte (CT ct, int *message_mods) {
                     ++*message_mods;
                     if (verbosw) {
                         char *encoding = cpytrim (hf->value);
-                        report (ct->c_partno, ct->c_file,
+                        report (NULL, ct->c_partno, ct->c_file,
                                 "replace Content-Transfer-Encoding of %s "
                                 "with 8 bit", encoding);
                         free (encoding);
@@ -837,7 +848,7 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) {
         int has_text_plain = 0;
 
         /* Nothing to do for text/plain. */
-        if ((*ct)->c_subtype == TEXT_PLAIN) return OK;
+        if ((*ct)->c_subtype == TEXT_PLAIN) { return OK; }
 
         if (parent  &&  parent->c_type == CT_MULTIPART  &&
             parent->c_subtype == MULTI_ALTERNATE) {
@@ -860,7 +871,7 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) {
                             prev->mp_next = part->mp_next;
                         }
                         if (verbosw) {
-                            report (parent->c_partno, parent->c_file,
+                            report (NULL, parent->c_partno, parent->c_file,
                                     "remove text/plain part %s",
                                     old_part->mp_part->c_partno);
                         }
@@ -891,7 +902,7 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) {
 
                     ++*message_mods;
                     if (verbosw) {
-                        report (parent->c_partno, parent->c_file,
+                        report (NULL, parent->c_partno, parent->c_file,
                                 "insert text/plain part");
                     }
                 } else {
@@ -918,7 +929,7 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) {
 
                         ++*message_mods;
                         if (verbosw) {
-                            report ((*ct)->c_partno, (*ct)->c_file,
+                            report (NULL, (*ct)->c_partno, (*ct)->c_file,
                                     "insert text/plain part");
                         }
                     } else {
@@ -1028,19 +1039,19 @@ divide_part (CT ct) {
 
 static void
 copy_ctinfo (CI dest, CI src) {
-    char **s_ap, **d_ap, **s_vp, **d_vp;
+    PM s_pm, d_pm;
 
     dest->ci_type = src->ci_type ? add (src->ci_type, NULL) : NULL;
     dest->ci_subtype = src->ci_subtype ? add (src->ci_subtype, NULL) : NULL;
 
-    for (s_ap = src->ci_attrs, d_ap = dest->ci_attrs,
-             s_vp = src->ci_values, d_vp = dest->ci_values;
-         *s_ap;
-         ++s_ap, ++d_ap, ++s_vp, ++d_vp) {
-        *d_ap = add (*s_ap, NULL);
-        *d_vp = *s_vp;
+    for (s_pm = src->ci_first_pm; s_pm; s_pm = s_pm->pm_next) {
+       d_pm = add_param(&dest->ci_first_pm, &dest->ci_last_pm, s_pm->pm_name,
+                        s_pm->pm_value, 0);
+       if (s_pm->pm_charset)
+           d_pm->pm_charset = getcpy(s_pm->pm_charset);
+       if (s_pm->pm_lang)
+           d_pm->pm_lang = getcpy(s_pm->pm_lang);
     }
-    *d_ap = NULL;
 
     dest->ci_comment = src->ci_comment ? add (src->ci_comment, NULL) : NULL;
     dest->ci_magic = src->ci_magic ? add (src->ci_magic, NULL) : NULL;
@@ -1082,40 +1093,25 @@ reformat_part (CT ct, char *file, char *type, char *subtype, int c_type) {
        Could show_multi() in mhshowsbr.c avoid this? */
 
     /* Check for invo_name-format-type/subtype. */
-    cp = concat (invo_name, "-format-", type, "/", subtype, NULL);
-    if ((cf = context_find (cp))  &&  *cf != '\0') {
+    if ((cf = context_find_by_type ("format", type, subtype)) == NULL) {
+        if (verbosw) {
+            advise (NULL, "Don't know how to convert %s, there is no "
+                    "%s-format-%s/%s profile entry",
+                    ct->c_file, invo_name, type, subtype);
+        }
+        return NOTOK;
+    } else {
         if (strchr (cf, '>')) {
-            free (cp);
             advise (NULL, "'>' prohibited in \"%s\",\nplease fix your "
                     "%s-format-%s/%s profile entry", cf, invo_name, type,
-                    subtype);
-            return NOTOK;
-        }
-    } else {
-        free (cp);
-
-        /* Check for invo_name-format-type. */
-        cp = concat (invo_name, "-format-", type, NULL);
-        if (! (cf = context_find (cp))  ||  *cf == '\0') {
-            free (cp);
-            if (verbosw) {
-                advise (NULL, "Don't know how to convert %s, there is no "
-                        "%s-format-%s/%s profile entry",
-                        ct->c_file, invo_name, type, subtype);
-            }
-            return NOTOK;
-        }
+                    subtype ? subtype : "");
 
-        if (strchr (cf, '>')) {
-            free (cp);
-            advise (NULL, "'>' prohibited in \"%s\"", cf);
             return NOTOK;
         }
     }
-    free (cp);
 
     cp = concat (cf, " >", file, NULL);
-    status = show_content_aux (ct, 1, 0, cp, NULL);
+    status = show_content_aux (ct, 0, cp, NULL, NULL);
     free (cp);
 
     /* Unlink decoded content tmp file and free its filename to avoid
@@ -1150,12 +1146,9 @@ reformat_part (CT ct, char *file, char *type, char *subtype, int c_type) {
 /* Identifies 7bit or 8bit content based on charset. */
 static int
 charset_encoding (CT ct) {
-    /* norm_charmap() is case sensitive. */
-    char *charset = upcase (content_charset (ct));
     int encoding =
-        strcmp (norm_charmap (charset), "US-ASCII")  ?  CE_8BIT  :  CE_7BIT;
+        strcasecmp (content_charset (ct), "US-ASCII")  ?  CE_8BIT  :  CE_7BIT;
 
-    free (charset);
     return encoding;
 }
 
@@ -1169,7 +1162,6 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) {
     CT ct;
     struct part *p;
     struct multipart *m;
-    char *cp;
     const struct str2init *ctinit;
 
     if ((ct = (CT) calloc (1, sizeof *ct)) == NULL)
@@ -1184,7 +1176,7 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) {
        c_cefile, c_encoding,
        c_digested, c_digest[16], c_ctexbody,
        c_ctinitfnx, c_ceopenfnx, c_ceclosefnx, c_cesizefnx,
-       c_umask, c_pid, c_rfc934,
+       c_umask, c_rfc934,
        c_showproc, c_termproc, c_storeproc, c_storage, c_folder
     */
 
@@ -1211,6 +1203,7 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) {
                      boundary_in_content (&new_part->c_cefile.ce_fp,
                                           new_part->c_cefile.ce_file,
                                           boundary)) == -1) {
+                    free (ct);
                     return NULL;
                 }
             }
@@ -1221,6 +1214,7 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) {
                 if ((found_boundary = boundary_in_content (&new_part->c_fp,
                                                            new_part->c_file,
                                                            boundary)) == -1) {
+                    free (ct);
                     return NULL;
                 }
             }
@@ -1241,6 +1235,7 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) {
 
         if (found_boundary) {
             advise (NULL, "giving up trying to find a unique boundary");
+            free (ct);
             return NULL;
         }
     }
@@ -1269,14 +1264,8 @@ build_multipart_alt (CT first_alt, CT new_part, int type, int subtype) {
         ct->c_ctinfo.ci_subtype = add (subtypename, NULL);
     }
 
-    name = concat (" ", typename, "/", subtypename, boundary_indicator,
-                   boundary, NULL);
-    if ((cp = strstr (name, boundary_indicator))) {
-        ct->c_ctinfo.ci_attrs[0] = name;
-        ct->c_ctinfo.ci_attrs[1] = NULL;
-        /* ci_values don't get free'd, so point into ci_attrs. */
-        ct->c_ctinfo.ci_values[0] = cp + strlen (boundary_indicator);
-    }
+    add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm,
+             "boundary", boundary, 0);
 
     p = (struct part *) mh_xmalloc (sizeof *p);
     p->mp_next = (struct part *) mh_xmalloc (sizeof *p->mp_next);
@@ -1430,16 +1419,19 @@ decode_text_parts (CT ct, int encoding, int *message_mods) {
             int ct_encoding;
 
             if (decode_part (ct) == OK  &&  ct->c_cefile.ce_file) {
-                if ((ct_encoding = content_encoding (ct)) == CE_BINARY  &&
-                    encoding != CE_BINARY) {
+                const char *reason = NULL;
+
+                if ((ct_encoding = content_encoding (ct, &reason)) == CE_BINARY
+                    &&  encoding != CE_BINARY) {
                     /* The decoding isn't acceptable so discard it.
                        Leave status as OK to allow other transformations. */
                     if (verbosw) {
-                        report (ct->c_partno, ct->c_file,
-                                "will not decode%s because it is binary",
+                        report (NULL, ct->c_partno, ct->c_file,
+                                "will not decode%s because it is binary (%s)",
                                 ct->c_partno  ?  ""
                                               :  ct->c_ctline  ?  ct->c_ctline
-                                                               :  "");
+                                                               :  "",
+                                reason);
                     }
                     (void) m_unlink (ct->c_cefile.ce_file);
                     free (ct->c_cefile.ce_file);
@@ -1449,7 +1441,7 @@ decode_text_parts (CT ct, int encoding, int *message_mods) {
                     /* The decoding isn't acceptable so discard it.
                        Leave status as OK to allow other transformations. */
                     if (verbosw) {
-                        report (ct->c_partno, ct->c_file,
+                        report (NULL, ct->c_partno, ct->c_file,
                                 "will not decode%s because it is 8bit",
                                 ct->c_partno  ?  ""
                                               :  ct->c_ctline  ?  ct->c_ctline
@@ -1469,7 +1461,7 @@ decode_text_parts (CT ct, int encoding, int *message_mods) {
                     if (set_ce (ct, enc) == OK) {
                         ++*message_mods;
                         if (verbosw) {
-                            report (ct->c_partno, ct->c_file, "decode%s",
+                            report (NULL, ct->c_partno, ct->c_file, "decode%s",
                                     ct->c_ctline ? ct->c_ctline : "");
                         }
                         strip_crs (ct, message_mods);
@@ -1523,9 +1515,10 @@ decode_text_parts (CT ct, int encoding, int *message_mods) {
 
 /* See if the decoded content is 7bit, 8bit, or binary.  It's binary
    if it has any NUL characters, a CR not followed by a LF, or lines
-   greater than 998 characters in length. */
+   greater than 998 characters in length.  If binary, reason is set
+   to a string explaining why. */
 static int
-content_encoding (CT ct) {
+content_encoding (CT ct, const char **reason) {
     CE ce = &ct->c_cefile;
     int encoding = CE_7BIT;
 
@@ -1550,6 +1543,16 @@ content_encoding (CT ct) {
                 if (*cp == '\0'  ||  ++line_len > 998  ||
                     (*cp != '\n'  &&  last_char_was_cr)) {
                     encoding = CE_BINARY;
+                    if (*cp == '\0') {
+                        *reason = "null character";
+                    } else if (line_len > 998) {
+                        *reason = "line length > 998";
+                    } else if (*cp != '\n'  &&  last_char_was_cr) {
+                        *reason = "CR not followed by LF";
+                    } else {
+                        /* Should not reach this. */
+                        *reason = "";
+                    }
                     break;
                 } else if (*cp == '\n') {
                     line_len = 0;
@@ -1571,8 +1574,7 @@ content_encoding (CT ct) {
 
 static int
 strip_crs (CT ct, int *message_mods) {
-    /* norm_charmap() is case sensitive. */
-    char *charset = upcase (content_charset (ct));
+    char *charset = content_charset (ct);
     int status = OK;
 
     /* Only strip carriage returns if content is ASCII or another
@@ -1580,10 +1582,10 @@ strip_crs (CT ct, int *message_mods) {
        LF.  We can include UTF-8 here because if the high-order bit of
        a UTF-8 byte is 0, then it must be a single-byte ASCII
        character. */
-    if (! strcmp (norm_charmap (charset), "US-ASCII")  ||
-        ! strncmp (norm_charmap (charset), "ISO-8859-", 9)  ||
-        ! strncmp (norm_charmap (charset), "UTF-8", 5)  ||
-        ! strncmp (norm_charmap (charset), "WINDOWS-12", 10)) {
+    if (! strcasecmp (charset, "US-ASCII")  ||
+        ! strcasecmp (charset, "UTF-8")  ||
+        ! strncasecmp (charset, "ISO-8859-", 9)  ||
+        ! strncasecmp (charset, "WINDOWS-12", 10)) {
         char **file = NULL;
         FILE **fp = NULL;
         size_t begin;
@@ -1630,7 +1632,7 @@ strip_crs (CT ct, int *message_mods) {
                 size_t i;
                 int last_char_was_cr = 0;
 
-                if (end > 0) bytes_to_read -= bytes_read;
+                if (end > 0) { bytes_to_read -= bytes_read; }
 
                 for (i = 0, cp = buffer; i < bytes_read; ++i, ++cp) {
                     if (*cp == '\n'  &&  last_char_was_cr) {
@@ -1665,11 +1667,19 @@ strip_crs (CT ct, int *message_mods) {
                         if (*cp == '\r') {
                             last_char_was_cr = 1;
                         } else if (last_char_was_cr) {
-                            if (*cp != '\n') write (fd, "\r", 1);
-                            write (fd, cp, 1);
+                            if (*cp != '\n') {
+                                if (write (fd, "\r", 1) < 0) {
+                                    advise (tempfile, "write of CR failed");
+                                }
+                            }
+                            if (write (fd, cp, 1) < 0) {
+                                advise (tempfile, "write failed");
+                            }
                             last_char_was_cr = 0;
                         } else {
-                            write (fd, cp, 1);
+                            if (write (fd, cp, 1) < 0) {
+                                advise (tempfile, "write failed");
+                            }
                             last_char_was_cr = 0;
                         }
                     }
@@ -1693,7 +1703,7 @@ strip_crs (CT ct, int *message_mods) {
 
                     ++*message_mods;
                     if (verbosw) {
-                        report (ct->c_partno,
+                        report (NULL, ct->c_partno,
                                 begin == 0 && end == 0  ?  ""  :  *file,
                                 "stripped CRs");
                     }
@@ -1707,7 +1717,6 @@ strip_crs (CT ct, int *message_mods) {
         }
     }
 
-    free (charset);
     return status;
 }
 
@@ -1720,9 +1729,16 @@ convert_charsets (CT ct, char *dest_charset, int *message_mods) {
     case CT_TEXT:
         if (ct->c_subtype == TEXT_PLAIN) {
             status = convert_charset (ct, dest_charset, message_mods);
-            if (verbosw  &&  status == OK) {
-               report (ct->c_partno, ct->c_file, "convert %s to %s",
-                       content_charset(ct), dest_charset);
+            if (status == OK) {
+                if (verbosw) {
+                    report (NULL, ct->c_partno, ct->c_file,
+                            "convert %s to %s",
+                            content_charset(ct), dest_charset);
+                }
+            } else {
+                report ("iconv", ct->c_partno, ct->c_file,
+                        "failed to convert %s to %s",
+                        content_charset(ct), dest_charset);
             }
         }
         break;
@@ -1791,8 +1807,8 @@ write_content (CT ct, char *input_filename, char *outfile, int modify_inplace,
                                 }
                             }
                         }
-                        if (new != -1) close (new);
-                        if (old != -1) close (old);
+                        if (new != -1) { close (new); }
+                        if (old != -1) { close (old); }
                         (void) m_unlink (outfile);
 
                         if (i < 0) {
@@ -1854,7 +1870,7 @@ remove_file (char *file) {
 
 
 static void
-report (char *partno, char *filename, char *message, ...) {
+report (char *what, char *partno, char *filename, char *message, ...) {
     va_list args;
     char *fmt;
 
@@ -1863,7 +1879,7 @@ report (char *partno, char *filename, char *message, ...) {
         fmt = concat (filename, partno ? " part " : ", ",
                       partno ? partno : "", partno ? ", " : "", message, NULL);
 
-        advertise (NULL, NULL, fmt, args);
+        advertise (what, NULL, fmt, args);
 
         free (fmt);
         va_end (args);