static int should_decode(const char *, const char *, const char *);
static int content_encoding (CT, const char **);
static int strip_crs (CT, int *);
+static void update_cte (CT);
+static int least_restrictive_encoding (CT);
+static int less_restrictive (int, int);
static int convert_charsets (CT, char *, int *);
static int fix_always (CT, int *);
static int fix_filename_param (char *, char *, PM *, PM *);
fx.lf_line_endings = 0;
fx.textcharset = NULL;
- if (nmh_init(argv[0], 1)) { return 1; }
+ if (nmh_init(argv[0], 2)) { return 1; }
done = freects_done;
}
}
- if (! (cts = (CT *) mh_xcalloc ((size_t) 2, sizeof *cts))) {
- adios (NULL, "out of memory");
- }
+ cts = mh_xcalloc(2, sizeof *cts);
ctp = cts;
if ((ct = parse_mime (file))) {
}
seq_setprev (mp); /* set the previous-sequence */
- if (! (cts =
- (CT *) mh_xcalloc ((size_t) (mp->numsel + 1), sizeof *cts))) {
- adios (NULL, "out of memory");
- }
+ cts = mh_xcalloc(mp->numsel + 1, sizeof *cts);
ctp = cts;
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
if (status == OK && fx->decodetext) {
status = decode_text_parts (*ctp, fx->decodetext, fx->decodetypes,
&message_mods);
+ update_cte (*ctp);
}
if (status == OK && fx->textcharset != NULL) {
status = convert_charsets (*ctp, fx->textcharset, &message_mods);
* c_ctline
*/
/* Extract type and subtype from type/subtype. */
- ct_type = getcpy (ct_type_subtype);
+ ct_type = mh_xstrdup(ct_type_subtype);
if ((cp = strchr (ct_type, '/'))) {
*cp = '\0';
- ct_subtype = getcpy (++cp);
+ ct_subtype = mh_xstrdup(++cp);
} else {
advise (NULL, "missing / in MIME type of %s %s",
ct->c_file, ct->c_partno);
char *prefix, *new_str;
if (cp - *str) {
- prefix = getcpy (*str);
+ prefix = mh_xstrdup(*str);
*(prefix + (cp - *str)) = '\0';
new_str = concat (prefix, new, remainder, NULL);
free (prefix);
if (! strncasecmp (name, ENCODING_FIELD,
strlen (ENCODING_FIELD))) {
char *prefix = "Nmh-REPLACED-INVALID-";
- HF h = mh_xmalloc (sizeof *h);
+ HF h;
+ NEW(h);
h->name = add (hf->name, NULL);
h->hf_encoding = hf->hf_encoding;
h->next = hf->next;
ct->c_cefile.ce_file to the name of the file containing
the contents. */
+ if (ct->c_ceclosefnx) {
+ (*ct->c_ceclosefnx) (ct);
+ }
+
/* Restore the cefile. */
ct->c_cefile = decoded_content_info;
HF hf;
parent->c_subtype = MULTI_ALTERNATE;
- parent->c_ctinfo.ci_subtype = getcpy ("alternative");
+ parent->c_ctinfo.ci_subtype = mh_xstrdup("alternative");
if (! replace_substring (&parent->c_ctline, "/related",
"/alternative")) {
advise (NULL,
static int
insert_new_text_plain_part (CT ct, int new_subpart_number, CT parent) {
struct multipart *mp = (struct multipart *) parent->c_ctparams;
- struct part *new_part = mh_xmalloc (sizeof *new_part);
+ struct part *new_part;
+ NEW(new_part);
if ((new_part->mp_part = build_text_plain_part (ct))) {
char buffer[16];
snprintf (buffer, sizeof buffer, "%d", new_subpart_number);
divide_part (CT ct) {
CT new_part;
- if ((new_part = (CT) mh_xcalloc (1, sizeof *new_part)) == NULL)
- adios (NULL, "out of memory");
-
+ NEW0(new_part);
/* Just copy over what is needed for decoding. c_vrsn and
c_celine aren't necessary. */
new_part->c_file = add (ct->c_file, NULL);
d_pm = add_param(&dest->ci_first_pm, &dest->ci_last_pm, s_pm->pm_name,
s_pm->pm_value, 0);
if (s_pm->pm_charset) {
- d_pm->pm_charset = getcpy(s_pm->pm_charset);
+ d_pm->pm_charset = mh_xstrdup(s_pm->pm_charset);
}
if (s_pm->pm_lang) {
- d_pm->pm_lang = getcpy(s_pm->pm_lang);
+ d_pm->pm_lang = mh_xstrdup(s_pm->pm_lang);
}
}
struct multipart *m;
const struct str2init *ctinit;
- if ((ct = (CT) mh_xcalloc (1, sizeof *ct)) == NULL)
- adios (NULL, "out of memory");
+ NEW0(ct);
/* Set up the multipart/alternative part. These fields of *ct were
initialized to 0 by mh_xcalloc():
add_param(&ct->c_ctinfo.ci_first_pm, &ct->c_ctinfo.ci_last_pm,
"boundary", boundary, 0);
- p = (struct part *) mh_xmalloc (sizeof *p);
- p->mp_next = (struct part *) mh_xmalloc (sizeof *p->mp_next);
+ NEW(p);
+ NEW(p->mp_next);
p->mp_next->mp_next = NULL;
p->mp_next->mp_part = first_alt;
- if ((m = (struct multipart *) mh_xcalloc (1, sizeof (struct multipart))) ==
- NULL)
- adios (NULL, "out of memory");
+ NEW0(m);
m->mp_start = concat (boundary, "\n", NULL);
m->mp_stop = concat (boundary, "--\n", NULL);
m->mp_parts = p;
}
+/*
+ * Add/update, if necessary, the message C-T-E, based on the least restrictive
+ * of the part C-T-E's.
+ */
+static void
+update_cte (CT ct) {
+ const int least_restrictive_enc = least_restrictive_encoding (ct);
+
+ if (least_restrictive_enc != CE_UNKNOWN &&
+ least_restrictive_enc != CE_7BIT) {
+ char *cte = concat (" ", ce_str (least_restrictive_enc), "\n", NULL);
+ HF hf;
+ int found_cte = 0;
+
+ /* Update/add Content-Transfer-Encoding header field. */
+ for (hf = ct->c_first_hf; hf; hf = hf->next) {
+ if (! strcasecmp (ENCODING_FIELD, hf->name)) {
+ found_cte = 1;
+ free (hf->value);
+ hf->value = cte;
+ }
+ }
+ if (! found_cte) {
+ add_header (ct, add (ENCODING_FIELD, NULL), cte);
+ }
+ }
+}
+
+
+/*
+ * Find the least restrictive encoding (7bit, 8bit, binary) of the parts
+ * within a message.
+ */
+static int
+least_restrictive_encoding (CT ct) {
+ int encoding = CE_UNKNOWN;
+
+ switch (ct->c_type) {
+ case CT_MULTIPART: {
+ struct multipart *m = (struct multipart *) ct->c_ctparams;
+ struct part *part;
+
+ for (part = m->mp_parts; part; part = part->mp_next) {
+ const int part_encoding =
+ least_restrictive_encoding (part->mp_part);
+
+ if (less_restrictive (encoding, part_encoding)) {
+ encoding = part_encoding;
+ }
+ }
+ break;
+ }
+
+ case CT_MESSAGE:
+ if (ct->c_subtype == MESSAGE_EXTERNAL) {
+ struct exbody *e = (struct exbody *) ct->c_ctparams;
+ const int part_encoding =
+ least_restrictive_encoding (e->eb_content);
+
+ if (less_restrictive (encoding, part_encoding)) {
+ encoding = part_encoding;
+ }
+ }
+ break;
+
+ default: {
+ if (less_restrictive (encoding, ct->c_encoding)) {
+ encoding = ct->c_encoding;
+ }
+ }}
+
+ return encoding;
+}
+
+
+/*
+ * Return whether the second encoding is less restrictive than the first, where
+ * "less restrictive" is in the sense used by RFC 2045 Secs. 6.1 and 6.4. So,
+ * CE_BINARY is less restrictive than CE_8BIT and
+ * CE_8BIT is less restrictive than CE_7BIT.
+ */
+static int
+less_restrictive (int encoding, int second_encoding) {
+ switch (second_encoding) {
+ case CE_BINARY:
+ return encoding != CE_BINARY;
+ case CE_8BIT:
+ return encoding != CE_BINARY && encoding != CE_8BIT;
+ case CE_7BIT:
+ return encoding != CE_BINARY && encoding != CE_8BIT &&
+ encoding != CE_7BIT;
+ default :
+ return 0;
+ }
+}
+
+
/*
* Convert character set of each part.
*/
default:
if (should_decode(decodetypes, ct->c_ctinfo.ci_type, ct->c_ctinfo.ci_subtype)) {
if (ct->c_ctparams == NULL) {
- if ((ct->c_ctparams = (struct text *) mh_xcalloc (1, sizeof (struct text))) == NULL) {
- adios (NULL, "out of memory");
- }
+ ct->c_ctparams = mh_xcalloc(1, sizeof (struct text));
}
((struct text *) ct->c_ctparams)->lf_line_endings = lf_line_endings;
}