X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/3f609815e33ab5474e631eac097d515d982ff0f5..00cfba08b276c3566cdc7d268965a6fc80c441df:/uip/mhfixmsg.c diff --git a/uip/mhfixmsg.c b/uip/mhfixmsg.c index 8d67e827..8a586182 100644 --- a/uip/mhfixmsg.c +++ b/uip/mhfixmsg.c @@ -16,6 +16,9 @@ #define MHFIXMSG_SWITCHES \ 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) \ @@ -80,6 +83,9 @@ typedef struct fix_transformations { int reformat; 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; @@ -106,7 +112,8 @@ static CT build_multipart_alt (CT, CT, int, int); 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 decode_text_parts (CT, int, const char *, int *); +static int should_decode(const char *, const char *, const char *); static int content_encoding (CT, const char **); static int strip_crs (CT, int *); static int convert_charsets (CT, char *, int *); @@ -135,6 +142,8 @@ main (int argc, char **argv) { fx.fixtypes = NULL; fx.replacetextplain = 0; fx.decodetext = CE_8BIT; + fx.decodetypes = "text,application/ics"; /* Default, per man page. */ + fx.lf_line_endings = 0; fx.textcharset = NULL; if (nmh_init(argv[0], 1)) { return 1; } @@ -179,6 +188,17 @@ main (int argc, char **argv) { case NDECODETEXTSW: fx.decodetext = 0; continue; + case DECODETYPESW: + if (! (cp = *argp++) || *cp == '-') + 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]); @@ -325,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 @@ -366,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; + } } } @@ -445,7 +488,7 @@ mhfixmsgsbr (CT *ctp, const fix_transformations *fx, char *outfile) { ensure_text_plain (ctp, NULL, &message_mods, fx->replacetextplain); } if (status == OK && fx->decodetext) { - status = decode_text_parts (*ctp, fx->decodetext, &message_mods); + status = decode_text_parts (*ctp, fx->decodetext, fx->decodetypes, &message_mods); } if (status == OK && fx->textcharset != NULL) { status = convert_charsets (*ctp, fx->textcharset, &message_mods); @@ -1318,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; @@ -1340,7 +1382,7 @@ insert_into_new_mp_alt (CT *ct, int *message_mods) { status = NOTOK; } } else { - status = NOTOK; + /* Not an error if text/plain couldn't be built. */ } return status; @@ -1748,11 +1790,40 @@ set_ct_type (CT ct, int type, int subtype, int encoding) { static int -decode_text_parts (CT ct, int encoding, int *message_mods) { +decode_text_parts (CT ct, int encoding, const char *decodetypes, int *message_mods) { int status = OK; + int lf_line_endings = 0; switch (ct->c_type) { - case CT_TEXT: + case CT_MULTIPART: { + struct multipart *m = (struct multipart *) ct->c_ctparams; + struct part *part; + + /* Should check to see if the body for this part is encoded? + For now, it gets passed along as-is by InitMultiPart(). */ + for (part = m->mp_parts; status == OK && part; part = part->mp_next) { + status = decode_text_parts (part->mp_part, encoding, decodetypes, message_mods); + } + break; + } + + case CT_MESSAGE: + if (ct->c_subtype == MESSAGE_EXTERNAL) { + struct exbody *e = (struct exbody *) ct->c_ctparams; + + status = decode_text_parts (e->eb_content, encoding, decodetypes, message_mods); + } + break; + + default: + if (! should_decode(decodetypes, ct->c_ctinfo.ci_type, ct->c_ctinfo.ci_subtype)) { + break; + } + + lf_line_endings = + ct->c_type == CT_TEXT && ct->c_ctparams && + ((struct text *) ct->c_ctparams)->lf_line_endings; + switch (ct->c_encoding) { case CE_BASE64: case CE_QUOTED: { @@ -1804,7 +1875,9 @@ decode_text_parts (CT ct, int encoding, int *message_mods) { report (NULL, ct->c_partno, ct->c_file, "decode%s", ct->c_ctline ? ct->c_ctline : ""); } - strip_crs (ct, message_mods); + if (lf_line_endings) { + strip_crs (ct, message_mods); + } } else { status = NOTOK; } @@ -1816,39 +1889,49 @@ decode_text_parts (CT ct, int encoding, int *message_mods) { } case CE_8BIT: case CE_7BIT: - strip_crs (ct, message_mods); + if (lf_line_endings) { + strip_crs (ct, message_mods); + } break; default: break; } break; - - case CT_MULTIPART: { - struct multipart *m = (struct multipart *) ct->c_ctparams; - struct part *part; - - /* Should check to see if the body for this part is encoded? - For now, it gets passed along as-is by InitMultiPart(). */ - for (part = m->mp_parts; status == OK && part; part = part->mp_next) { - status = decode_text_parts (part->mp_part, encoding, message_mods); - } - break; } - case CT_MESSAGE: - if (ct->c_subtype == MESSAGE_EXTERNAL) { - struct exbody *e = (struct exbody *) ct->c_ctparams; + return status; +} - status = decode_text_parts (e->eb_content, encoding, message_mods); - } - break; - default: - break; +/* Determine if the part with type[/subtype] should be decoded, according to + decodetypes (which came from the -decodetypes switch). */ +static int +should_decode(const char *decodetypes, const char *type, const char *subtype) { + /* Quick search for matching type[/subtype] in decodetypes: bracket + decodetypes with commas, then search for ,type, and ,type/subtype, in + it. */ + + int found_match = 0; + char *delimited_decodetypes = concat(",", decodetypes, ",", NULL); + char *delimited_type = concat(",", type, ",", NULL); + + if (nmh_strcasestr(delimited_decodetypes, delimited_type)) { + found_match = 1; + } else if (subtype != NULL) { + char *delimited_type_subtype = + concat(",", type, "/", subtype, ",", NULL); + + if (nmh_strcasestr(delimited_decodetypes, delimited_type_subtype)) { + found_match = 1; + } + free(delimited_type_subtype); } - return status; + free(delimited_type); + free(delimited_decodetypes); + + return found_match; }