+/*
+ * Fix various problems that aren't handled elsewhere. These
+ * are fixed unconditionally: there are no switches to disable
+ * them. (Currently, "problems" is just one: an extraneous
+ * semicolon at the end of a header parameter list.)
+ */
+static int
+fix_always (CT ct, int *message_mods) {
+ int status = OK;
+
+ switch (ct->c_type) {
+ case CT_MULTIPART: {
+ struct multipart *m = (struct multipart *) ct->c_ctparams;
+ struct part *part;
+
+ for (part = m->mp_parts; status == OK && part; part = part->mp_next) {
+ status = fix_always (part->mp_part, message_mods);
+ }
+ break;
+ }
+
+ case CT_MESSAGE:
+ if (ct->c_subtype == MESSAGE_EXTERNAL) {
+ struct exbody *e = (struct exbody *) ct->c_ctparams;
+
+ status = fix_always (e->eb_content, message_mods);
+ }
+ break;
+
+ default: {
+ HF hf;
+
+ for (hf = ct->c_first_hf; hf; hf = hf->next) {
+ size_t len = strlen (hf->value);
+
+ if (strcasecmp (hf->name, TYPE_FIELD) != 0 &&
+ strcasecmp (hf->name, DISPO_FIELD) != 0) {
+ /* Only do this for Content-Type and
+ Content-Disposition fields because those are the
+ only headers that parse_mime() warns about. */
+ continue;
+ }
+
+ /* whitespace following a trailing ';' will be nuked as well */
+ if (hf->value[len - 1] == '\n') {
+ while (isspace((unsigned char)(hf->value[len - 2]))) {
+ if (len-- == 0) { break; }
+ }
+ }
+
+ if (hf->value[len - 2] == ';') {
+ /* Remove trailing ';' from parameter value. */
+ hf->value[len - 2] = '\n';
+ hf->value[len - 1] = '\0';
+
+ /* Also, if Content-Type parameter, remove trailing ';'
+ from ct->c_ctline. This probably isn't necessary
+ but can't hurt. */
+ if (strcasecmp(hf->name, TYPE_FIELD) == 0 && ct->c_ctline) {
+ size_t l = strlen(ct->c_ctline) - 1;
+ while (isspace((unsigned char)(ct->c_ctline[l])) ||
+ ct->c_ctline[l] == ';') {
+ ct->c_ctline[l--] = '\0';
+ if (l == 0) { break; }
+ }
+ }
+
+ ++*message_mods;
+ if (verbosw) {
+ report (NULL, ct->c_partno, ct->c_file,
+ "remove trailing ; from %s parameter value",
+ hf->name);
+ }
+ }
+ }
+ }}
+
+ return status;
+}
+
+