]> diplodocus.org Git - nmh/commitdiff
Added -replacetextplain switch to mhfixmsg. If enabled, -reformat
authorDavid Levine <levinedl@acm.org>
Mon, 19 Aug 2013 05:42:01 +0000 (00:42 -0500)
committerDavid Levine <levinedl@acm.org>
Mon, 19 Aug 2013 05:42:01 +0000 (00:42 -0500)
will replace any existing text/plain part, such as those that are
empty or that don't match their corresponding text/html part.

man/mhfixmsg.man
test/mhfixmsg/test-mhfixmsg
uip/mhfixmsg.c

index 629014d6c68470a6c5de46e0e0689e9766a45bf4..9996d304ba0407920fb342aed3811160a3571f15 100644 (file)
@@ -17,6 +17,7 @@ mhfixmsg \- rewrite MIME messages with various transformations
 .I codeset
 .RB "| " \-notextcodeset ]
 .RB [ \-reformat " | " \-noreformat ]
 .I codeset
 .RB "| " \-notextcodeset ]
 .RB [ \-reformat " | " \-noreformat ]
+.RB [ \-replacetextplain " | " \-noreplacetextplain ]
 .RB [ \-fixboundary " | " \-nofixboundary ]
 .RB [ \-fixcte " | " \-nofixcte ]
 .RB [ \-file
 .RB [ \-fixboundary " | " \-nofixboundary ]
 .RB [ \-fixcte " | " \-nofixcte ]
 .RB [ \-file
@@ -93,6 +94,16 @@ inserts that text/plain part at the beginning of the containing
 multipart/alternative part, if present.  If not, it creates a
 multipart/alternative part.
 .PP
 multipart/alternative part, if present.  If not, it creates a
 multipart/alternative part.
 .PP
+The
+.B \-replacetextplain
+switch broadens the applicability of
+.B \-reformat
+by always replacing a corresponding text/plain part, if one exists.
+If
+.B \-verbose
+if enabled, the replacement will be shown as two steps:  a removal of
+the text/plain part followed by the usual insertion of a new part.
+.PP
 .B \-reformat
 requires a profile entry for each text part subtype to be reformatted.
 The mhfixmsg-format-text/subtype profile entries are based on external
 .B \-reformat
 requires a profile entry for each text part subtype to be reformatted.
 The mhfixmsg-format-text/subtype profile entries are based on external
@@ -300,6 +311,7 @@ is checked.
 .RB ` "\-decodetext 8bit"'
 .RB ` \-notextcodeset '
 .RB ` \-reformat '
 .RB ` "\-decodetext 8bit"'
 .RB ` \-notextcodeset '
 .RB ` \-reformat '
+.RB ` \-noreplacetextplain '
 .RB ` \-fixboundary '
 .RB ` \-fixcte '
 .RB ` \-noverbose '
 .RB ` \-fixboundary '
 .RB ` \-fixcte '
 .RB ` \-noverbose '
index 851c3c97f655918c71c3e05f9a1e84215d7048af..1a01de2fb78b8e851f85122ef1aef42234de747e 100755 (executable)
@@ -41,6 +41,7 @@ Usage: mhfixmsg [+folder] [msgs] [switches]
   -nodecodetext
   -[no]textcodeset
   -[no]reformat
   -nodecodetext
   -[no]textcodeset
   -[no]reformat
+  -[no]replacetextplain
   -[no]fixboundary
   -[no]fixcte
   -file file
   -[no]fixboundary
   -[no]fixcte
   -file file
@@ -943,6 +944,104 @@ mhfixmsg last -outfile "$actual"
 check "$expected" "$actual"
 
 
 check "$expected" "$actual"
 
 
+# check -replacetextplain
+cat >"$expected" <<EOF
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg replacement of bad text/plain part test
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="----=_Part_876302"
+
+------=_Part_876302
+Content-Type: text/plain; charset="UTF-8"
+Content-Transfer-Encoding: 8bit
+
+Yes, the text/plain part really was empty.
+
+------=_Part_876302
+Content-Type: text/html; charset="UTF-8"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline
+
+<html><head>
+<title>eticket</title>
+</head>
+<body>
+  Yes, the text/plain part really was empty.
+</body>
+</html>
+
+------=_Part_876302--
+EOF
+
+cat >`mhpath new` <<'EOF'
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg replacement of bad text/plain part test
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="----=_Part_876302"
+
+------=_Part_876302
+Content-Type: text/plain; charset="iso-8859-15"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+
+
+------=_Part_876302
+Content-Type: text/html; charset="UTF-8"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline
+
+<html><head>
+<title>eticket</title>
+</head>
+<body>
+  Yes, the text/plain part really was empty.
+</body>
+</html>
+
+------=_Part_876302--
+EOF
+
+mhfixmsg last -replacetextplain -outfile "$actual"
+check "$expected" "$actual"
+
+# check -noreplacetextplain
+cat >"$expected" <<EOF
+To: recipient@example.com
+From: sender@example.com
+Subject: mhfixmsg replacement of bad text/plain part test
+MIME-Version: 1.0
+Content-Type: multipart/alternative; boundary="----=_Part_876302"
+
+------=_Part_876302
+Content-Type: text/plain; charset="iso-8859-15"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: inline
+
+
+
+------=_Part_876302
+Content-Type: text/html; charset="UTF-8"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline
+
+<html><head>
+<title>eticket</title>
+</head>
+<body>
+  Yes, the text/plain part really was empty.
+</body>
+</html>
+
+------=_Part_876302--
+EOF
+
+mhfixmsg last -replacetextplain -noreplacetextplain -outfile "$actual"
+check "$expected" "$actual"
+
+
 # check rmmproc
 cat >"$MH_TEST_DIR/Mail/rmmproc" <<'EOF'
 mv "$1" "$1.backup"
 # check rmmproc
 cat >"$MH_TEST_DIR/Mail/rmmproc" <<'EOF'
 mv "$1" "$1.backup"
index ff189a0edfb426d9c79d312ab7f03852bce96822..0548f1b2233ba3a0bc7d0c05d9fa813ebc454e7a 100644 (file)
@@ -23,6 +23,8 @@
     X("notextcodeset", 0, NTEXTCODESETSW) \
     X("reformat", 0, REFORMATSW) \
     X("noreformat", 0, NREFORMATSW) \
     X("notextcodeset", 0, NTEXTCODESETSW) \
     X("reformat", 0, REFORMATSW) \
     X("noreformat", 0, NREFORMATSW) \
+    X("replacetextplain", 0, REPLACETEXTPLAINSW) \
+    X("noreplacetextplain", 0, NREPLACETEXTPLAINSW) \
     X("fixboundary", 0, FIXBOUNDARYSW) \
     X("nofixboundary", 0, NFIXBOUNDARYSW) \
     X("fixcte", 0, FIXCTESW) \
     X("fixboundary", 0, FIXBOUNDARYSW) \
     X("nofixboundary", 0, NFIXBOUNDARYSW) \
     X("fixcte", 0, FIXCTESW) \
@@ -78,6 +80,7 @@ typedef struct fix_transformations {
     int fixboundary;
     int fixcte;
     int reformat;
     int fixboundary;
     int fixcte;
     int reformat;
+    int replacetextplain;
     int decodetext;
     char *textcodeset;
 } fix_transformations;
     int decodetext;
     char *textcodeset;
 } fix_transformations;
@@ -90,7 +93,7 @@ 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 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 *);
+static int ensure_text_plain (CT *, CT, int *, int);
 static CT build_text_plain_part (CT);
 static CT divide_part (CT);
 static void copy_ctinfo (CI, CI);
 static CT build_text_plain_part (CT);
 static CT divide_part (CT);
 static void copy_ctinfo (CI, CI);
@@ -128,6 +131,7 @@ main (int argc, char **argv) {
     int status = OK;
     fix_transformations fx;
     fx.reformat = fx.fixcte = fx.fixboundary = 1;
     int status = OK;
     fix_transformations fx;
     fx.reformat = fx.fixcte = fx.fixboundary = 1;
+    fx.replacetextplain = 0;
     fx.decodetext = CE_8BIT;
     fx.textcodeset = NULL;
 
     fx.decodetext = CE_8BIT;
     fx.textcodeset = NULL;
 
@@ -205,6 +209,12 @@ main (int argc, char **argv) {
             case NREFORMATSW:
                 fx.reformat = 0;
                 continue;
             case NREFORMATSW:
                 fx.reformat = 0;
                 continue;
+            case REPLACETEXTPLAINSW:
+                fx.replacetextplain = 1;
+                continue;
+            case NREPLACETEXTPLAINSW:
+                fx.replacetextplain = 0;
+                continue;
 
             case FILESW:
                 if (! (cp = *argp++) || (*cp == '-' && cp[1]))
 
             case FILESW:
                 if (! (cp = *argp++) || (*cp == '-' && cp[1]))
@@ -410,7 +420,8 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) {
         status = fix_multipart_cte (*ctp, &message_mods);
     }
     if (status == OK  &&  fx->reformat) {
         status = fix_multipart_cte (*ctp, &message_mods);
     }
     if (status == OK  &&  fx->reformat) {
-        status = ensure_text_plain (ctp, NULL, &message_mods);
+        status =
+            ensure_text_plain (ctp, NULL, &message_mods, fx->replacetextplain);
     }
     if (status == OK  &&  fx->decodetext) {
         status = decode_text_parts (*ctp, fx->decodetext, &message_mods);
     }
     if (status == OK  &&  fx->decodetext) {
         status = decode_text_parts (*ctp, fx->decodetext, &message_mods);
@@ -873,7 +884,7 @@ set_ce (CT ct, int encoding) {
 
 /* Make sure each text part has a corresponding text/plain part. */
 static int
 
 /* Make sure each text part has a corresponding text/plain part. */
 static int
-ensure_text_plain (CT *ct, CT parent, int *message_mods) {
+ensure_text_plain (CT *ct, CT parent, int *message_mods, int replacetextplain) {
     int status = OK;
 
     switch ((*ct)->c_type) {
     int status = OK;
 
     switch ((*ct)->c_type) {
@@ -886,17 +897,36 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods) {
         if (parent  &&  parent->c_type == CT_MULTIPART  &&
             parent->c_subtype == MULTI_ALTERNATE) {
             struct multipart *mp = (struct multipart *) parent->c_ctparams;
         if (parent  &&  parent->c_type == CT_MULTIPART  &&
             parent->c_subtype == MULTI_ALTERNATE) {
             struct multipart *mp = (struct multipart *) parent->c_ctparams;
-            struct part *part;
+            struct part *part, *prev;
             int new_subpart_number = 1;
 
             /* See if there is a sibling text/plain. */
             int new_subpart_number = 1;
 
             /* See if there is a sibling text/plain. */
-            for (part = mp->mp_parts; part; part = part->mp_next) {
+            for (prev = part = mp->mp_parts; part; part = part->mp_next) {
                 ++new_subpart_number;
                 if (part->mp_part->c_type == CT_TEXT  &&
                     part->mp_part->c_subtype == TEXT_PLAIN) {
                 ++new_subpart_number;
                 if (part->mp_part->c_type == CT_TEXT  &&
                     part->mp_part->c_subtype == TEXT_PLAIN) {
-                    has_text_plain = 1;
+                    if (replacetextplain) {
+                        struct part *old_part;
+                        if (part == mp->mp_parts) {
+                            old_part = mp->mp_parts;
+                            mp->mp_parts = part->mp_next;
+                        } else {
+                            old_part = prev->mp_next;
+                            prev->mp_next = part->mp_next;
+                        }
+                        if (verbosw) {
+                            report (parent->c_partno, parent->c_file,
+                                    "remove text/plain part %s",
+                                    old_part->mp_part->c_partno);
+                        }
+                        free_content (old_part->mp_part);
+                        free (old_part);
+                    } else {
+                        has_text_plain = 1;
+                    }
                     break;
                 }
                     break;
                 }
+                prev = part;
             }
 
             if (! has_text_plain) {
             }
 
             if (! has_text_plain) {
@@ -967,7 +997,8 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods) {
 
         for (part = mp->mp_parts; status == OK && part; part = part->mp_next) {
             if ((*ct)->c_type == CT_MULTIPART) {
 
         for (part = mp->mp_parts; status == OK && part; part = part->mp_next) {
             if ((*ct)->c_type == CT_MULTIPART) {
-                status = ensure_text_plain (&part->mp_part, *ct, message_mods);
+                status = ensure_text_plain (&part->mp_part, *ct, message_mods,
+                                            replacetextplain);
             }
         }
         break;
             }
         }
         break;
@@ -978,7 +1009,8 @@ ensure_text_plain (CT *ct, CT parent, int *message_mods) {
             struct exbody *e;
 
             e = (struct exbody *) (*ct)->c_ctparams;
             struct exbody *e;
 
             e = (struct exbody *) (*ct)->c_ctparams;
-            status = ensure_text_plain (&e->eb_content, *ct, message_mods);
+            status = ensure_text_plain (&e->eb_content, *ct, message_mods,
+                                        replacetextplain);
         }
         break;
     }
         }
         break;
     }