]> diplodocus.org Git - nmh/commitdiff
Added -[no]crlflinebreaks switches to mhfixmsg(1).
authorDavid Levine <levinedl@acm.org>
Thu, 25 Feb 2016 01:32:10 +0000 (20:32 -0500)
committerDavid Levine <levinedl@acm.org>
Thu, 25 Feb 2016 01:50:55 +0000 (20:50 -0500)
docs/pending-release-notes
h/mhparse.h
man/mhfixmsg.man
test/mhfixmsg/test-mhfixmsg
uip/mhfixmsg.c
uip/mhoutsbr.c

index 6163ec8..5e70513 100644 (file)
@@ -25,8 +25,8 @@ NEW FEATURES
 - When building from source, configure will derive ${prefix} from an existing
   nmh installation if it finds one in your $PATH.
 - Added getmymbox and getmyaddr mh-format(5) function escapes.
-- New -changecur, -nochangecur, -fixtype, and -decodetypes switches have been
-  added to mhfixmsg(1).
+- New -[no]changecur, -fixtype, -decodetypes, and -[no]crlflinebreaks switches
+  have been added to mhfixmsg(1).
 - mhfixmsg now removes an extraneous trailing semicolon from header
   parameter lists.
 - Added -convertargs switch to repl(1), to pass arguments to programs
index 3efec9c..5d7668f 100644 (file)
@@ -193,6 +193,10 @@ struct Content {
 /* Structure for text content */
 struct text {
     int        tx_charset;             /* flag for character set */
+    int lf_line_endings;        /* Whether to use CR LF (0) or LF (1) line
+                                   endings.  The meaning of 0 was selected so
+                                   that CR LF is the default, in accordance
+                                   with RFC 2046, Sec. 4.1.1, Par. 1. */
 };
 
 /*
index 17fca71..dd97fe8 100644 (file)
@@ -1,4 +1,4 @@
-.TH MHFIXMSG %manext1% "February 20, 2016" "%nmhversion%"
+.TH MHFIXMSG %manext1% "February 24, 2016" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -18,6 +18,7 @@ mhfixmsg \- rewrite MIME messages with various transformations
 .BR \-nodecodetext ]
 .RB [ \-decodetypes
 .IR "type/[subtype][,...]" ]
+.RB [ \-crlflinebreaks " | " \-nocrlflinebreaks ]
 .RB [ \-textcharset
 .I charset
 .RB "| " \-notextcharset ]
@@ -91,6 +92,16 @@ to restrict
 .B \-decodetext
 to just text/plain parts.
 .PP
+By default, carriage return characters are preserved or inserted at
+the end of each line of text content.  The
+.B \-crlflinebreaks
+switch selects this behavior and is enabled by default.  The
+.B \-nocrlflinebreaks
+switch causes carriage return characters to be stripped from, and not
+inserted in, text content when it is decoded and encoded.  Note that
+its use can cause the generation of MIME messages that do not conform
+with RFC 2046, §4.1.1, paragraph 1.
+.PP
 The
 .B \-textcharset
 switch specifies that all text/plain parts of the message(s)
@@ -175,7 +186,7 @@ The
 switch enables a transformation to change the
 Content-Transfer-Encoding from an invalid value to 8bit in message
 parts with a Content-Type of multipart, as required by RFC 2045,
-Section 6.4.  That condition is indicated by a \*(lqmust be encoded in
+§6.4.  That condition is indicated by a \*(lqmust be encoded in
 7bit, 8bit, or binary\*(rq error message from
 .B mhlist
 and other
@@ -275,14 +286,15 @@ content type and/or encoding as follows:
 .PP
 .RS 5
 .nf
-.ta \w'\-fixboundary 'u
-\-decodetext   base64 and quoted-printable encoded text parts
-\-decodetypes  limits parts to which -decodetext applies
-\-textcharset  text/plain parts
-\-reformat     text parts that are not text/plain
-\-fixboundary  outermost multipart part
-\-fixcte       multipart part
-\-fixtype      all except multipart and message parts
+.ta \w'\-crlflinebreaks 'u
+\-decodetext         base64 and quoted-printable encoded text parts
+\-decodetypes        limits parts to which -decodetext applies
+\-crlflinebreaks text parts
+\-textcharset        text/plain parts
+\-reformat           text parts that are not text/plain
+\-fixboundary        outermost multipart part
+\-fixcte             multipart part
+\-fixtype            all except multipart and message parts
 .fi
 .RE
 .PP
@@ -409,6 +421,7 @@ is checked.
 .RB ` msgs "' defaults to cur"
 .RB ` "\-decodetext 8bit"'
 .RB ` "\-decodetypes text"'
+.RB ` \-crlflinebreaks '
 .RB ` \-notextcharset '
 .RB ` \-reformat '
 .RB ` \-noreplacetextplain '
index 323fb72..77de37d 100755 (executable)
@@ -52,6 +52,7 @@ Usage: mhfixmsg [+folder] [msgs] [switches]
   -decodetext 8bit|7bit
   -nodecodetext
   -decodetypes
+  -[no]crlflinebreaks
   -[no]textcharset
   -[no]reformat
   -[no]replacetextplain
@@ -1053,7 +1054,7 @@ run_test 'mhfixmsg last -outfile '"$actual" ''
 check "$expected" "$actual"
 
 
-# check stripping of CRs from ASCII text context
+# check not stripping of CRs from ASCII text context (default)
 cat >"$expected" <<EOF
 MIME-Version: 1.0
 From: sender@example.com
@@ -1061,8 +1062,8 @@ To: recipient@example.com
 Subject: message with CR's
 Date: Mon, 29 Apr 2013 11:51:45 -0400
 
-There are two CR-LF pairs at the end of this sentence.
-
+There are two CR-LF pairs at the end of this sentence.\r
+\r
 EOF
 
 cat >`mhpath new` <<'EOF'
@@ -1080,6 +1081,33 @@ run_prog mhfixmsg last -outfile "$actual"
 check "$expected" "$actual"
 
 
+# check stripping of CRs from ASCII text context
+cat >"$expected" <<EOF
+MIME-Version: 1.0
+From: sender@example.com
+To: recipient@example.com
+Subject: message with CR's
+Date: Mon, 29 Apr 2013 11:51:45 -0400
+
+There were two CR-LF pairs at the end of this sentence.
+
+EOF
+
+cat >`mhpath new` <<'EOF'
+MIME-Version: 1.0
+From: sender@example.com
+To: recipient@example.com
+Subject: message with CR's
+Date: Mon, 29 Apr 2013 11:51:45 -0400
+
+There were two CR-LF pairs at the end of this sentence.\r
+\r
+EOF
+
+run_prog mhfixmsg last -outfile "$actual" -nocrlflinebreaks
+check "$expected" "$actual"
+
+
 # check -replacetextplain
 prepare_space >"$expected" <<EOF
 To: recipient@example.com
index a5a24b9..2dd3ef2 100644 (file)
@@ -17,6 +17,8 @@
     X("decodetext 8bit|7bit", 0, DECODETEXTSW) \
     X("nodecodetext", 0, NDECODETEXTSW) \
     X("decodetypes", 0, DECODETYPESW) \
+    X("crlflinebreaks", 0, CRLFLINEBREAKSSW) \
+    X("nocrlflinebreaks", 0, NCRLFLINEBREAKSSW) \
     X("textcharset", 0, TEXTCHARSETSW) \
     X("notextcharset", 0, NTEXTCHARSETSW) \
     X("reformat", 0, REFORMATSW) \
@@ -82,6 +84,8 @@ typedef struct fix_transformations {
     int replacetextplain;
     int decodetext;
     char *decodetypes;
+    /* Whether to use CRLF linebreaks, per RFC 2046 Sec. 4.1.1, par.1. */
+    int lf_line_endings;
     char *textcharset;
 } fix_transformations;
 
@@ -139,6 +143,7 @@ main (int argc, char **argv) {
     fx.replacetextplain = 0;
     fx.decodetext = CE_8BIT;
     fx.decodetypes = "text";  /* Default to all text content. */
+    fx.lf_line_endings = 0;
     fx.textcharset = NULL;
 
     if (nmh_init(argv[0], 1)) { return 1; }
@@ -188,6 +193,12 @@ main (int argc, char **argv) {
                     adios (NULL, "missing argument to %s", argp[-2]);
                 fx.decodetypes = cp;
                 continue;
+            case CRLFLINEBREAKSSW:
+                fx.lf_line_endings = 0;
+                continue;
+            case NCRLFLINEBREAKSSW:
+                fx.lf_line_endings = 1;
+                continue;
             case TEXTCHARSETSW:
                 if (! (cp = *argp++) || (*cp == '-' && cp[1]))
                     adios (NULL, "missing argument to %s", argp[-2]);
@@ -334,7 +345,18 @@ main (int argc, char **argv) {
         }
         ctp = cts;
 
-        if ((ct = parse_mime (file))) { *ctp++ = ct; }
+        if ((ct = parse_mime (file))) {
+            if (ct->c_type == CT_TEXT) {
+                /* parse_mime() does not set lf_line_endings in struct text, so set it here. */
+                if (ct->c_ctparams == NULL) {
+                    if ((ct->c_ctparams = (struct text *) mh_xcalloc (1, sizeof (struct text))) == NULL) {
+                        adios (NULL, "out of memory");
+                    }
+                }
+                ((struct text *) ct->c_ctparams)->lf_line_endings = fx.lf_line_endings;
+            }
+            *ctp++ = ct;
+        }
     } else {
         /*
          * message(s) are coming from a folder
@@ -375,7 +397,19 @@ main (int argc, char **argv) {
                 char *msgnam;
 
                 msgnam = m_name (msgnum);
-                if ((ct = parse_mime (msgnam))) { *ctp++ = ct; }
+                if ((ct = parse_mime (msgnam))) {
+                    if (ct->c_type == CT_TEXT) {
+                        /* parse_mime() does not set lf_line_endings in struct text, so set it here. */
+                        if (ct->c_ctparams == NULL) {
+                            if ((ct->c_ctparams = (struct text *) mh_xcalloc (1, sizeof (struct text))) ==
+                                NULL) {
+                                adios (NULL, "out of memory");
+                            }
+                        }
+                        ((struct text *) ct->c_ctparams)->lf_line_endings = fx.lf_line_endings;
+                    }
+                    *ctp++ = ct;
+                }
             }
         }
 
@@ -1327,8 +1361,7 @@ insert_into_new_mp_alt (CT *ct, int *message_mods) {
         CT mp_alt = build_multipart_alt (*ct, tp_part, CT_MULTIPART,
                                          MULTI_ALTERNATE);
         if (mp_alt) {
-            struct multipart *mp =
-                (struct multipart *) mp_alt->c_ctparams;
+            struct multipart *mp = (struct multipart *) mp_alt->c_ctparams;
 
             if (mp  &&  mp->mp_parts) {
                 mp->mp_parts->mp_part = tp_part;
@@ -1761,7 +1794,9 @@ decode_text_parts (CT ct, int encoding, const char *decodetypes, int *message_mo
     int status = OK;
 
     switch (ct->c_type) {
-    case CT_TEXT:
+    case CT_TEXT: {
+        struct text *const text_content_info = (struct text *) ct->c_ctparams;
+
         if (! should_decode(decodetypes, ct->c_ctinfo.ci_type, ct->c_ctinfo.ci_subtype)) {
             break;
         }
@@ -1817,7 +1852,9 @@ decode_text_parts (CT ct, int encoding, const char *decodetypes, int *message_mo
                             report (NULL, ct->c_partno, ct->c_file, "decode%s",
                                     ct->c_ctline ? ct->c_ctline : "");
                         }
-                        strip_crs (ct, message_mods);
+                        if (text_content_info  &&  text_content_info->lf_line_endings) {
+                            strip_crs (ct, message_mods);
+                        }
                     } else {
                         status = NOTOK;
                     }
@@ -1829,13 +1866,16 @@ decode_text_parts (CT ct, int encoding, const char *decodetypes, int *message_mo
         }
         case CE_8BIT:
         case CE_7BIT:
-            strip_crs (ct, message_mods);
+            if (text_content_info  &&  text_content_info->lf_line_endings) {
+                strip_crs (ct, message_mods);
+            }
             break;
         default:
             break;
         }
 
         break;
+    }
 
     case CT_MULTIPART: {
         struct multipart *m = (struct multipart *) ct->c_ctparams;
index 066a4b9..456a2e2 100644 (file)
@@ -426,7 +426,10 @@ writeBase64ct (CT ct, FILE *out)
     if ((fd = (*ct->c_ceopenfnx) (ct, &file)) == NOTOK)
        return NOTOK;
 
-    result = writeBase64aux (ce->ce_fp, out, (ct->c_type == CT_TEXT));
+    result = writeBase64aux (ce->ce_fp, out,
+                             ct->c_type == CT_TEXT  &&  ct->c_ctparams
+                             ?  ((struct text *) ct->c_ctparams)->lf_line_endings == 0
+                             :  0);
     (*ct->c_ceclosefnx) (ct);
     return result;
 }