- 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
/* 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. */
};
/*
-.TH MHFIXMSG %manext1% "February 20, 2016" "%nmhversion%"
+.TH MHFIXMSG %manext1% "February 24, 2016" "%nmhversion%"
.\"
.\" %nmhwarning%
.\"
.BR \-nodecodetext ]
.RB [ \-decodetypes
.IR "type/[subtype][,...]" ]
+.RB [ \-crlflinebreaks " | " \-nocrlflinebreaks ]
.RB [ \-textcharset
.I charset
.RB "| " \-notextcharset ]
.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)
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
.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
.RB ` msgs "' defaults to cur"
.RB ` "\-decodetext 8bit"'
.RB ` "\-decodetypes text"'
+.RB ` \-crlflinebreaks '
.RB ` \-notextcharset '
.RB ` \-reformat '
.RB ` \-noreplacetextplain '
-decodetext 8bit|7bit
-nodecodetext
-decodetypes
+ -[no]crlflinebreaks
-[no]textcharset
-[no]reformat
-[no]replacetextplain
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
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'
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
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) \
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;
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; }
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]);
}
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
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;
+ }
}
}
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;
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;
}
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;
}
}
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;
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;
}