Skip to content

Commit

Permalink
oxcmail: rewrite select_parts for better multialternative selection
Browse files Browse the repository at this point in the history
Because of the MAPI message model, we do not select an alternative
like an MUA; instead, we select multiple (ouch).

Alternative selection should exclude multipart/mixed;
in contrast to MUAs, we cannot meaningfully treat them as a usable alternative.

Alternative selection should prefer the higher numbered parts;
the logic for this was missing as well.

References: GXL-526, DESK-2315
  • Loading branch information
jengelh committed Jul 28, 2024
1 parent cc958e5 commit cef3d09
Showing 1 changed file with 57 additions and 40 deletions.
97 changes: 57 additions & 40 deletions lib/mapi/oxcmail.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2511,52 +2511,69 @@ static bool smime_clearsigned(const char *head_ct, const MIME *head, char (&buf)
strcasecmp(buf, "application/x-pkcs7-signature") == 0;
}

static void select_parts(const MIME *part, MIME_ENUM_PARAM &info)
/**
* @level: how often to recurse into multiparts.
* If level==0, a top-level multipart/ will not be analyzed.
*/
static void select_parts(const MIME *part, MIME_ENUM_PARAM &info, unsigned int level)
{
for (unsigned int i = 0; i < MAXIMUM_SEARCHING_DEPTH; ++i) {
auto child = part->get_child();
if (child == nullptr)
break;
part = child;
}
auto parent = part->get_parent();
bool alt = false;
if (parent != nullptr && strcasecmp(parent->content_type,
"multipart/alternative") == 0)
alt = true;
do {
auto cttype = part->content_type;
if (strcasecmp(cttype, "text/plain") == 0 &&
info.pplain == nullptr)
/*
* At level 0, we are inspecting the root (the mail itself, only one of
* these tests will succeed)
*/
if (part->mime_type == mime_type::single) {
if (strcasecmp(part->content_type, "text/plain") == 0)
info.pplain = part;
if (strcasecmp(cttype, "text/html") == 0 &&
info.phtml == nullptr)
else if (strcasecmp(part->content_type, "text/html") == 0)
info.phtml = part;
if (strcasecmp(cttype, "text/enriched") == 0 &&
info.penriched == nullptr)
else if (strcasecmp(part->content_type, "text/enriched") == 0)
info.penriched = part;
if (strcasecmp(cttype, "text/calendar") == 0 &&
info.pcalendar == nullptr)
else if (strcasecmp(part->content_type, "text/calendar") == 0)
info.pcalendar = part;
if (!alt || part->mime_type != mime_type::multiple)
return;
}
if (level >= MAXIMUM_SEARCHING_DEPTH)
return;
++level;
bool alt = strcasecmp(part->content_type, "multipart/alternative") == 0;

for (auto child = part->get_child(); child != nullptr;
child = child->get_sibling()) {
if (child->mime_type == mime_type::multiple &&
strcasecmp(child->content_type, "multipart/alternative") != 0)
/* Having 'mixed' as an alternative is awkward. */
continue;

MIME_ENUM_PARAM cld_info{info.phash};
select_parts(child, cld_info, level);
if (alt) {
/* Parts inside a multipart/alternatives container override one another */
if (cld_info.pplain != nullptr)
info.pplain = cld_info.pplain;
if (cld_info.phtml != nullptr)
info.phtml = cld_info.phtml;
if (cld_info.penriched != nullptr)
info.penriched = cld_info.penriched;
if (cld_info.pcalendar != nullptr)
info.pcalendar = cld_info.pcalendar;
continue;
for (auto child = part->get_child(); child != nullptr;
child = child->get_sibling()) {
cttype = child->content_type;
if (strcasecmp(cttype, "text/plain") == 0 &&
info.pplain == nullptr)
info.pplain = child;
if (strcasecmp(cttype, "text/html") == 0 &&
info.phtml == nullptr)
info.phtml = child;
if (strcasecmp(cttype, "text/enriched") == 0 &&
info.penriched == nullptr)
info.penriched = child;
if (strcasecmp(cttype, "text/calendar") == 0 &&
info.pcalendar == nullptr)
info.pcalendar = child;
}
} while (alt && (part = part->get_sibling()) != nullptr);

/* /mixed and /report don't, first wins it (for us) */
if (cld_info.pplain != nullptr && info.pplain == nullptr) {
info.pplain = cld_info.pplain;
break;
} else if (cld_info.phtml != nullptr && info.phtml == nullptr) {
info.phtml = cld_info.phtml;
break;
} else if (cld_info.penriched != nullptr && info.penriched == nullptr) {
info.penriched = cld_info.penriched;
break;
} else if (cld_info.pcalendar != nullptr && info.pcalendar == nullptr) {
info.pcalendar = cld_info.pcalendar;
break;
}
}
}

static BOOL xlog_bool(const char *func, unsigned int line)
Expand Down Expand Up @@ -2717,7 +2734,7 @@ MESSAGE_CONTENT *oxcmail_import(const char *charset, const char *str_zone,
mime_enum.alloc = alloc;
mime_enum.pmsg = pmsg.get();
mime_enum.phash = phash;
select_parts(phead, mime_enum);
select_parts(phead, mime_enum, 0);

if (mime_enum.pplain != nullptr &&
!oxcmail_parse_message_body(default_charset,
Expand Down

0 comments on commit cef3d09

Please sign in to comment.