]> diplodocus.org Git - nmh/commitdiff
Moved upcase(), update_attr(), content_charset(), and
authorDavid Levine <levinedl@acm.org>
Sat, 8 Feb 2014 17:11:25 +0000 (11:11 -0600)
committerDavid Levine <levinedl@acm.org>
Sat, 8 Feb 2014 17:11:25 +0000 (11:11 -0600)
convert_charset() out of mhfixmsg.c so that other programs can
use them.

Makefile.am
h/mhparse.h
h/prototypes.h
sbr/utils.c
uip/mhfixmsg.c
uip/mhparse.c
uip/mhshowsbr.c

index bdcca08926929a7935f7c1d9853dead7724cf104..5bc612c85a2e71f4ecda274785d911bfc30dee28 100644 (file)
@@ -334,7 +334,7 @@ uip_mhlist_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
 uip_mhn_SOURCES = uip/mhn.c uip/mhparse.c uip/mhcachesbr.c uip/mhshowsbr.c \
                  uip/mhlistsbr.c uip/mhstoresbr.c uip/mhmisc.c uip/mhfree.c \
                  uip/md5.c
 uip_mhn_SOURCES = uip/mhn.c uip/mhparse.c uip/mhcachesbr.c uip/mhshowsbr.c \
                  uip/mhlistsbr.c uip/mhstoresbr.c uip/mhmisc.c uip/mhfree.c \
                  uip/md5.c
-uip_mhn_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhn_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_mhparam_SOURCES = uip/mhparam.c
 uip_mhparam_LDADD = $(LDADD) $(POSTLINK)
 
 uip_mhparam_SOURCES = uip/mhparam.c
 uip_mhparam_LDADD = $(LDADD) $(POSTLINK)
@@ -345,12 +345,12 @@ uip_mhpath_LDADD = $(LDADD) $(POSTLINK)
 uip_mhshow_SOURCES = uip/mhshow.c uip/mhparse.c uip/mhcachesbr.c \
                     uip/mhshowsbr.c uip/mhlistsbr.c uip/mhmisc.c \
                     uip/mhfree.c uip/md5.c
 uip_mhshow_SOURCES = uip/mhshow.c uip/mhparse.c uip/mhcachesbr.c \
                     uip/mhshowsbr.c uip/mhlistsbr.c uip/mhmisc.c \
                     uip/mhfree.c uip/md5.c
-uip_mhshow_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhshow_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_mhstore_SOURCES = uip/mhstore.c uip/mhparse.c uip/mhcachesbr.c \
                      uip/mhshowsbr.c uip/mhlistsbr.c uip/mhstoresbr.c \
                      uip/mhmisc.c uip/mhfree.c uip/md5.c
 
 uip_mhstore_SOURCES = uip/mhstore.c uip/mhparse.c uip/mhcachesbr.c \
                      uip/mhshowsbr.c uip/mhlistsbr.c uip/mhstoresbr.c \
                      uip/mhmisc.c uip/mhfree.c uip/md5.c
-uip_mhstore_LDADD = $(LDADD) $(TERMLIB) $(POSTLINK)
+uip_mhstore_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 
 uip_msgchk_SOURCES = uip/msgchk.c uip/popsbr.c
 uip_msgchk_LDADD = $(LDADD) $(SASLLIB) $(POSTLINK)
 
 uip_msgchk_SOURCES = uip/msgchk.c uip/popsbr.c
 uip_msgchk_LDADD = $(LDADD) $(SASLLIB) $(POSTLINK)
index bb55153feb5ca39ea66418fd11ed19261aaf1f6f..72188c6d42d903d2f040bacde1022a7d71807c7a 100644 (file)
@@ -327,5 +327,8 @@ const struct str2init *get_ct_init (int);
 const char *ce_str (int);
 const struct str2init *get_ce_method (const char *);
 int parse_header_attrs (const char *, int, char **, CI, int *);
 const char *ce_str (int);
 const struct str2init *get_ce_method (const char *);
 int parse_header_attrs (const char *, int, char **, CI, int *);
+char *update_attr (char *, const char *, const char *e);
+char *content_charset (CT);
+int convert_charset (CT, char *, int *);
 
 extern int checksw;    /* Add Content-MD5 field */
 
 extern int checksw;    /* Add Content-MD5 field */
index 1ff92f64c5cf0c3c33e832ab5b3de6ad62caf34c..621146c3f401850dd2540fcacc211cff9202d4f1 100644 (file)
@@ -46,6 +46,7 @@ void cpydgst (int, int, char *, char *);
 char *cpytrim (const char *);
 int decode_rfc2047 (char *, char *, size_t);
 void discard (FILE *);
 char *cpytrim (const char *);
 int decode_rfc2047 (char *, char *, size_t);
 void discard (FILE *);
+char *upcase (const char *);
 int default_done (int);
 
 /*
 int default_done (int);
 
 /*
index d8b060fb13ce5f7a87a949166fe01e6d566c73d6..59ab7c72754bf6c0bcd3bb85e2393ae22de5d517 100644 (file)
@@ -352,3 +352,16 @@ nmh_init(const char *argv0, int read_context) {
         return status;
     }
 }
         return status;
     }
 }
+
+
+/* Returns copy of argument str with all characters converted to upper
+   case, and trimmed whitespace (see cpytrim()) . */
+char *
+upcase (const char *str) {
+    char *up = cpytrim (str);
+    char *cp;
+
+    for (cp = up; *cp; ++cp) { *cp = toupper ((unsigned char) *cp); }
+
+    return up;
+}
index 201625087d44427126a6117ebf7860948768fbe9..4c0a3ef53f6e1135427cc3989f246c17718f571d 100644 (file)
@@ -12,9 +12,6 @@
 #include <h/utils.h>
 #include <h/signals.h>
 #include <fcntl.h>
 #include <h/utils.h>
 #include <h/signals.h>
 #include <fcntl.h>
-#ifdef HAVE_ICONV
-#   include <iconv.h>
-#endif
 
 #define MHFIXMSG_SWITCHES \
     X("decodetext 8bit|7bit", 0, DECODETEXTSW) \
 
 #define MHFIXMSG_SWITCHES \
     X("decodetext 8bit|7bit", 0, DECODETEXTSW) \
@@ -89,7 +86,6 @@ 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 fix_boundary (CT *, int *);
 static int get_multipart_boundary (CT, char **);
 static int replace_boundary (CT, char *, const char *);
-static char *update_attr (char *, const char *, const char *e);
 static int fix_multipart_cte (CT, int *);
 static int set_ce (CT, int);
 static int ensure_text_plain (CT *, CT, int *, int);
 static int fix_multipart_cte (CT, int *);
 static int set_ce (CT, int);
 static int ensure_text_plain (CT *, CT, int *, int);
@@ -107,12 +103,9 @@ static int decode_text_parts (CT, int, int *);
 static int content_encoding (CT);
 static int strip_crs (CT, int *);
 static int convert_codesets (CT, char *, int *);
 static int content_encoding (CT);
 static int strip_crs (CT, int *);
 static int convert_codesets (CT, char *, int *);
-static int convert_codeset (CT, char *, int *);
-static char *content_codeset (CT);
 static int write_content (CT, char *, char *, int, int);
 static int remove_file (char *);
 static void report (char *, char *, char *, ...);
 static int write_content (CT, char *, char *, int, int);
 static int remove_file (char *);
 static void report (char *, char *, char *, ...);
-static char *upcase (char *);
 static void pipeser (int);
 
 
 static void pipeser (int);
 
 
@@ -718,44 +711,6 @@ replace_boundary (CT ct, char *file, const char *boundary) {
 }
 
 
 }
 
 
-/* Change the value of a name=value pair in a header field body.
-   If the name isn't there, append them.  In any case, a new
-   string will be allocated and must be free'd by the caller.
-   Trims any trailing newlines. */
-static char *
-update_attr (char *body, const char *name, const char *value) {
-    char *bp = nmh_strcasestr (body, name);
-    char *new_body;
-
-    if (bp) {
-        char *other_attrs = strchr (bp, ';');
-
-        *(bp + strlen (name)) = '\0';
-        new_body = concat (body, "\"", value, "\"", NULL);
-
-        if (other_attrs) {
-            char *cp;
-
-            /* Trim any trailing newlines. */
-            for (cp = &other_attrs[strlen (other_attrs) - 1];
-                 cp > other_attrs  &&  *cp == '\n';
-                 *cp-- = '\0') continue;
-            new_body = add (other_attrs, new_body);
-        }
-    } else {
-        char *cp;
-
-        /* Append name/value pair, after first removing a final newline
-           and (extraneous) semicolon. */
-        if (*(cp = &body[strlen (body) - 1]) == '\n') *cp = '\0';
-        if (*(cp = &body[strlen (body) - 1]) == ';') *cp = '\0';
-        new_body = concat (body, "; ", name, "\"", value, "\"", NULL);
-    }
-
-    return new_body;
-}
-
-
 static int
 fix_multipart_cte (CT ct, int *message_mods) {
     int status = OK;
 static int
 fix_multipart_cte (CT ct, int *message_mods) {
     int status = OK;
@@ -1196,7 +1151,7 @@ reformat_part (CT ct, char *file, char *type, char *subtype, int c_type) {
 static int
 charset_encoding (CT ct) {
     /* norm_charmap() is case sensitive. */
 static int
 charset_encoding (CT ct) {
     /* norm_charmap() is case sensitive. */
-    char *codeset = upcase (content_codeset (ct));
+    char *codeset = upcase (content_charset (ct));
     int encoding =
         strcmp (norm_charmap (codeset), "US-ASCII")  ?  CE_8BIT  :  CE_7BIT;
 
     int encoding =
         strcmp (norm_charmap (codeset), "US-ASCII")  ?  CE_8BIT  :  CE_7BIT;
 
@@ -1617,7 +1572,7 @@ content_encoding (CT ct) {
 static int
 strip_crs (CT ct, int *message_mods) {
     /* norm_charmap() is case sensitive. */
 static int
 strip_crs (CT ct, int *message_mods) {
     /* norm_charmap() is case sensitive. */
-    char *codeset = upcase (content_codeset (ct));
+    char *codeset = upcase (content_charset (ct));
     int status = OK;
 
     /* Only strip carriage returns if content is ASCII or another
     int status = OK;
 
     /* Only strip carriage returns if content is ASCII or another
@@ -1757,29 +1712,6 @@ strip_crs (CT ct, int *message_mods) {
 }
 
 
 }
 
 
-char *
-content_codeset (CT ct) {
-    const char *const charset = "charset";
-    char *default_codeset = NULL;
-    CI ctinfo = &ct->c_ctinfo;
-    char **ap, **vp;
-    char **src_codeset = NULL;
-
-    for (ap = ctinfo->ci_attrs, vp = ctinfo->ci_values; *ap; ++ap, ++vp) {
-        if (! strcasecmp (*ap, charset)) {
-            src_codeset = vp;
-            break;
-        }
-    }
-
-    /* RFC 2045, Sec. 5.2:  default to us-ascii. */
-    if (src_codeset == NULL) src_codeset = &default_codeset;
-    if (*src_codeset == NULL) *src_codeset = "US-ASCII";
-
-    return *src_codeset;
-}
-
-
 static int
 convert_codesets (CT ct, char *dest_codeset, int *message_mods) {
     int status = OK;
 static int
 convert_codesets (CT ct, char *dest_codeset, int *message_mods) {
     int status = OK;
@@ -1787,7 +1719,11 @@ convert_codesets (CT ct, char *dest_codeset, int *message_mods) {
     switch (ct->c_type) {
     case CT_TEXT:
         if (ct->c_subtype == TEXT_PLAIN) {
     switch (ct->c_type) {
     case CT_TEXT:
         if (ct->c_subtype == TEXT_PLAIN) {
-            status = convert_codeset (ct, dest_codeset, message_mods);
+            status = convert_charset (ct, dest_codeset, message_mods);
+            if (verbosw  &&  status == OK) {
+               report (ct->c_partno, ct->c_file, "convert %s to %s",
+                       content_charset(ct), dest_codeset);
+            }
         }
         break;
 
         }
         break;
 
@@ -1822,161 +1758,6 @@ convert_codesets (CT ct, char *dest_codeset, int *message_mods) {
 }
 
 
 }
 
 
-static int
-convert_codeset (CT ct, char *dest_codeset, int *message_mods) {
-    char *src_codeset = content_codeset (ct);
-    int status = OK;
-
-    /* norm_charmap() is case sensitive. */
-    char *src_codeset_u = upcase (src_codeset);
-    char *dest_codeset_u = upcase (dest_codeset);
-    int different_codesets =
-        strcmp (norm_charmap (src_codeset), norm_charmap (dest_codeset));
-
-    free (dest_codeset_u);
-    free (src_codeset_u);
-
-    if (different_codesets) {
-#ifdef HAVE_ICONV
-        iconv_t conv_desc = NULL;
-        char *dest;
-        int fd = -1;
-        char **file = NULL;
-        FILE **fp = NULL;
-        size_t begin;
-        size_t end;
-        int opened_input_file = 0;
-        char src_buffer[BUFSIZ];
-        HF hf;
-        char *tempfile;
-
-        if ((conv_desc = iconv_open (dest_codeset, src_codeset)) ==
-            (iconv_t) -1) {
-            advise (NULL, "Can't convert %s to %s", src_codeset, dest_codeset);
-            return -1;
-        }
-
-        if ((tempfile = m_mktemp2 (NULL, invo_name, &fd, NULL)) == NULL) {
-            adios (NULL, "unable to create temporary file in %s",
-                   get_temp_dir());
-        }
-        dest = add (tempfile, NULL);
-
-        if (ct->c_cefile.ce_file) {
-            file = &ct->c_cefile.ce_file;
-            fp = &ct->c_cefile.ce_fp;
-            begin = end = 0;
-        } else if (ct->c_file) {
-            file = &ct->c_file;
-            fp = &ct->c_fp;
-            begin = (size_t) ct->c_begin;
-            end = (size_t) ct->c_end;
-        } /* else no input file: shouldn't happen */
-
-        if (file  &&  *file  &&  fp) {
-            if (! *fp) {
-                if ((*fp = fopen (*file, "r")) == NULL) {
-                    advise (*file, "unable to open for reading");
-                    status = NOTOK;
-                } else {
-                    opened_input_file = 1;
-                }
-            }
-        }
-
-        if (fp  &&  *fp) {
-            size_t inbytes;
-            size_t bytes_to_read =
-                end > 0 && end > begin  ?  end - begin  :  sizeof src_buffer;
-
-            fseeko (*fp, begin, SEEK_SET);
-            while ((inbytes = fread (src_buffer, 1,
-                                     min (bytes_to_read, sizeof src_buffer),
-                                     *fp)) > 0) {
-                char dest_buffer[BUFSIZ];
-                ICONV_CONST char *ib = src_buffer;
-                char *ob = dest_buffer;
-                size_t outbytes = sizeof dest_buffer;
-                size_t outbytes_before = outbytes;
-
-                if (end > 0) bytes_to_read -= inbytes;
-
-                if (iconv (conv_desc, &ib, &inbytes, &ob, &outbytes) ==
-                    (size_t) -1) {
-                    status = NOTOK;
-                    break;
-                } else {
-                    write (fd, dest_buffer, outbytes_before - outbytes);
-                }
-            }
-
-            if (opened_input_file) {
-                fclose (*fp);
-                *fp = NULL;
-            }
-        }
-
-        iconv_close (conv_desc);
-        close (fd);
-
-        if (status == OK) {
-            /* Replace the decoded file with the converted one. */
-            if (ct->c_cefile.ce_file) {
-                if (ct->c_cefile.ce_unlink) {
-                    (void) m_unlink (ct->c_cefile.ce_file);
-                }
-                free (ct->c_cefile.ce_file);
-            }
-            ct->c_cefile.ce_file = dest;
-            ct->c_cefile.ce_unlink = 1;
-
-            ++*message_mods;
-            if (verbosw) {
-                report (ct->c_partno, ct->c_file, "convert %s to %s",
-                        src_codeset, dest_codeset);
-            }
-
-            /* Update ci_attrs. */
-            src_codeset = dest_codeset;
-
-            /* Update ct->c_ctline. */
-            if (ct->c_ctline) {
-                char *ctline =
-                    update_attr (ct->c_ctline, "charset=", dest_codeset);
-
-                free (ct->c_ctline);
-                ct->c_ctline = ctline;
-            } /* else no CT line, which is odd */
-
-            /* Update Content-Type header field. */
-            for (hf = ct->c_first_hf; hf; hf = hf->next) {
-                if (! strcasecmp (TYPE_FIELD, hf->name)) {
-                    char *ctline_less_newline =
-                        update_attr (hf->value, "charset=", dest_codeset);
-                    char *ctline = concat (ctline_less_newline, "\n", NULL);
-                    free (ctline_less_newline);
-
-                    free (hf->value);
-                    hf->value = ctline;
-                    break;
-                }
-            }
-        } else {
-            (void) m_unlink (dest);
-        }
-#else  /* ! HAVE_ICONV */
-        NMH_UNUSED (message_mods);
-
-        advise (NULL, "Can't convert %s to %s without iconv", src_codeset,
-                dest_codeset);
-        status = NOTOK;
-#endif /* ! HAVE_ICONV */
-    }
-
-    return status;
-}
-
-
 static int
 write_content (CT ct, char *input_filename, char *outfile, int modify_inplace,
                int message_mods) {
 static int
 write_content (CT ct, char *input_filename, char *outfile, int modify_inplace,
                int message_mods) {
@@ -2090,17 +1871,6 @@ report (char *partno, char *filename, char *message, ...) {
 }
 
 
 }
 
 
-static char *
-upcase (char *str) {
-    char *up = cpytrim (str);
-    char *cp;
-
-    for (cp = up; *cp; ++cp) *cp = toupper ((unsigned char) *cp);
-
-    return up;
-}
-
-
 static void
 pipeser (int i)
 {
 static void
 pipeser (int i)
 {
index 8af26906fe9edfbb38fe2bea9fdd5f4a948e236c..9873e0b184d679f420283f28d1b924939d2b5684 100644 (file)
@@ -3351,3 +3351,64 @@ bad_quote:
     *header_attrp = cp;
     return OK;
 }
     *header_attrp = cp;
     return OK;
 }
+
+
+char *
+content_charset (CT ct) {
+    const char *const charset = "charset";
+    char *default_charset = NULL;
+    CI ctinfo = &ct->c_ctinfo;
+    char **ap, **vp;
+    char **src_charset = NULL;
+
+    for (ap = ctinfo->ci_attrs, vp = ctinfo->ci_values; *ap; ++ap, ++vp) {
+        if (! strcasecmp (*ap, charset)) {
+            src_charset = vp;
+            break;
+        }
+    }
+
+    /* RFC 2045, Sec. 5.2:  default to us-ascii. */
+    if (src_charset == NULL) src_charset = &default_charset;
+    if (*src_charset == NULL) *src_charset = "US-ASCII";
+
+    return *src_charset;
+}
+
+
+/* Change the value of a name=value pair in a header field body.
+   If the name isn't there, append them.  In any case, a new
+   string will be allocated and must be free'd by the caller.
+   Trims any trailing newlines. */
+char *
+update_attr (char *body, const char *name, const char *value) {
+    char *bp = nmh_strcasestr (body, name);
+    char *new_body;
+
+    if (bp) {
+        char *other_attrs = strchr (bp, ';');
+
+        *(bp + strlen (name)) = '\0';
+        new_body = concat (body, "\"", value, "\"", NULL);
+
+        if (other_attrs) {
+            char *cp;
+
+            /* Trim any trailing newlines. */
+            for (cp = &other_attrs[strlen (other_attrs) - 1];
+                 cp > other_attrs  &&  *cp == '\n';
+                 *cp-- = '\0') continue;
+            new_body = add (other_attrs, new_body);
+        }
+    } else {
+        char *cp;
+
+        /* Append name/value pair, after first removing a final newline
+           and (extraneous) semicolon. */
+        if (*(cp = &body[strlen (body) - 1]) == '\n') *cp = '\0';
+        if (*(cp = &body[strlen (body) - 1]) == ';') *cp = '\0';
+        new_body = concat (body, "; ", name, "\"", value, "\"", NULL);
+    }
+
+    return new_body;
+}
index fe0e33041ba2fa9e7dbdc6547a5aa4058b5eac2e..6f7f1ee66900956ecd7e9e0b1b968a8a568e1c7c 100644 (file)
@@ -17,6 +17,9 @@
 #include <h/mime.h>
 #include <h/mhparse.h>
 #include <h/utils.h>
 #include <h/mime.h>
 #include <h/mhparse.h>
 #include <h/utils.h>
+#ifdef HAVE_ICONV
+#   include <iconv.h>
+#endif
 
 extern int debugsw;
 
 
 extern int debugsw;
 
@@ -1063,6 +1066,157 @@ show_external (CT ct, int serial, int alternate)
 }
 
 
 }
 
 
+int
+convert_charset (CT ct, char *dest_charset, int *message_mods) {
+    char *src_charset = content_charset (ct);
+    int status = OK;
+
+    /* norm_charmap() is case sensitive. */
+    char *src_charset_u = upcase (src_charset);
+    char *dest_charset_u = upcase (dest_charset);
+    int different_charsets =
+        strcmp (norm_charmap (src_charset), norm_charmap (dest_charset));
+
+    free (dest_charset_u);
+    free (src_charset_u);
+
+    if (different_charsets) {
+#ifdef HAVE_ICONV
+        iconv_t conv_desc = NULL;
+        char *dest;
+        int fd = -1;
+        char **file = NULL;
+        FILE **fp = NULL;
+        size_t begin;
+        size_t end;
+        int opened_input_file = 0;
+        char src_buffer[BUFSIZ];
+        HF hf;
+        char *tempfile;
+
+        if ((conv_desc = iconv_open (dest_charset, src_charset)) ==
+            (iconv_t) -1) {
+            advise (NULL, "Can't convert %s to %s", src_charset, dest_charset);
+            return NOTOK;
+        }
+
+        if ((tempfile = m_mktemp2 (NULL, invo_name, &fd, NULL)) == NULL) {
+            adios (NULL, "unable to create temporary file in %s",
+                   get_temp_dir());
+        }
+        dest = add (tempfile, NULL);
+
+        if (ct->c_cefile.ce_file) {
+            file = &ct->c_cefile.ce_file;
+            fp = &ct->c_cefile.ce_fp;
+            begin = end = 0;
+        } else if (ct->c_file) {
+            file = &ct->c_file;
+            fp = &ct->c_fp;
+            begin = (size_t) ct->c_begin;
+            end = (size_t) ct->c_end;
+        } /* else no input file: shouldn't happen */
+
+        if (file  &&  *file  &&  fp) {
+            if (! *fp) {
+                if ((*fp = fopen (*file, "r")) == NULL) {
+                    advise (*file, "unable to open for reading");
+                    status = NOTOK;
+                } else {
+                    opened_input_file = 1;
+                }
+            }
+        }
+
+        if (fp  &&  *fp) {
+            size_t inbytes;
+            size_t bytes_to_read =
+                end > 0 && end > begin  ?  end - begin  :  sizeof src_buffer;
+
+            fseeko (*fp, begin, SEEK_SET);
+            while ((inbytes = fread (src_buffer, 1,
+                                     min (bytes_to_read, sizeof src_buffer),
+                                     *fp)) > 0) {
+                char dest_buffer[BUFSIZ];
+                ICONV_CONST char *ib = src_buffer;
+                char *ob = dest_buffer;
+                size_t outbytes = sizeof dest_buffer;
+                size_t outbytes_before = outbytes;
+
+                if (end > 0) bytes_to_read -= inbytes;
+
+                if (iconv (conv_desc, &ib, &inbytes, &ob, &outbytes) ==
+                    (size_t) -1) {
+                    status = NOTOK;
+                    break;
+                } else {
+                    write (fd, dest_buffer, outbytes_before - outbytes);
+                }
+            }
+
+            if (opened_input_file) {
+                fclose (*fp);
+                *fp = NULL;
+            }
+        }
+
+        iconv_close (conv_desc);
+        close (fd);
+
+        if (status == OK) {
+            /* Replace the decoded file with the converted one. */
+            if (ct->c_cefile.ce_file) {
+                if (ct->c_cefile.ce_unlink) {
+                    (void) m_unlink (ct->c_cefile.ce_file);
+                }
+                free (ct->c_cefile.ce_file);
+            }
+            ct->c_cefile.ce_file = dest;
+            ct->c_cefile.ce_unlink = 1;
+
+            ++*message_mods;
+
+            /* Update ci_attrs. */
+            src_charset = dest_charset;
+
+            /* Update ct->c_ctline. */
+            if (ct->c_ctline) {
+                char *ctline =
+                    update_attr (ct->c_ctline, "charset=", dest_charset);
+
+                free (ct->c_ctline);
+                ct->c_ctline = ctline;
+            } /* else no CT line, which is odd */
+
+            /* Update Content-Type header field. */
+            for (hf = ct->c_first_hf; hf; hf = hf->next) {
+                if (! strcasecmp (TYPE_FIELD, hf->name)) {
+                    char *ctline_less_newline =
+                        update_attr (hf->value, "charset=", dest_charset);
+                    char *ctline = concat (ctline_less_newline, "\n", NULL);
+                    free (ctline_less_newline);
+
+                    free (hf->value);
+                    hf->value = ctline;
+                    break;
+                }
+            }
+        } else {
+            (void) m_unlink (dest);
+        }
+#else  /* ! HAVE_ICONV */
+        NMH_UNUSED (message_mods);
+
+        advise (NULL, "Can't convert %s to %s without iconv", src_charset,
+                dest_charset);
+        status = NOTOK;
+#endif /* ! HAVE_ICONV */
+    }
+
+    return status;
+}
+
+
 static void
 intrser (int i)
 {
 static void
 intrser (int i)
 {