From c28bfe04e177b1fce4aa9b1d6159c8412f1a8bdc Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Thu, 22 Aug 2024 22:34:34 +0300 Subject: [PATCH] message: detect top-level smime parts + test Fixes #2745 --- lib/message/mu-message.cc | 45 +++++++++------- lib/message/mu-mime-object.hh | 25 +++++++-- lib/tests/test-mu-msg.cc | 96 +++++++++++++++++++++++++---------- 3 files changed, 119 insertions(+), 47 deletions(-) diff --git a/lib/message/mu-message.cc b/lib/message/mu-message.cc index 46063cfe..111eef9f 100644 --- a/lib/message/mu-message.cc +++ b/lib/message/mu-message.cc @@ -484,6 +484,28 @@ handle_encrypted(const MimeMultipartEncrypted& part, Message::Private& info) handle_object(part, res->first, info); } +static void +maybe_handle_pkcs7(const MimeObject& obj, Message::Private& info) +{ + if (obj.is_mime_application_pkcs7_mime()) { + MimeApplicationPkcs7Mime smime(obj); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" + // CompressedData, CertsOnly, Unknown + switch (smime.smime_type()) { + case Mu::MimeApplicationPkcs7Mime::SecureMimeType::SignedData: + info.flags |= Flags::Signed; + break; + case Mu::MimeApplicationPkcs7Mime::SecureMimeType::EnvelopedData: + info.flags |= Flags::Encrypted; + break; + default: + break; + } +#pragma GCC diagnostic pop + } +} + static void handle_object(const MimeObject& parent, @@ -508,23 +530,8 @@ handle_object(const MimeObject& parent, /* FIXME: An encrypted part might be signed at the same time. * In that case the signed flag is lost. */ info.flags |= Flags::Encrypted; - } else if (obj.is_mime_application_pkcs7_mime()) { - MimeApplicationPkcs7Mime smime(obj); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wswitch-enum" - // CompressedData, CertsOnly, Unknown - switch (smime.smime_type()) { - case Mu::MimeApplicationPkcs7Mime::SecureMimeType::SignedData: - info.flags |= Flags::Signed; - break; - case Mu::MimeApplicationPkcs7Mime::SecureMimeType::EnvelopedData: - info.flags |= Flags::Encrypted; - break; - default: - break; - } -#pragma GCC diagnostic pop - } + } else + maybe_handle_pkcs7(obj, info); } /** @@ -548,6 +555,10 @@ process_message(const MimeMessage& mime_msg, const std::string& path, info.flags |= Flags::Unread; } + // handle top-level + if (const auto mpart = mime_msg.mime_part(); mpart) + maybe_handle_pkcs7(*mpart, info); + // parts mime_msg.for_each([&](auto&& parent, auto&& child_obj) { handle_object(parent, child_obj, info); diff --git a/lib/message/mu-mime-object.hh b/lib/message/mu-mime-object.hh index bfb2867f..20154069 100644 --- a/lib/message/mu-mime-object.hh +++ b/lib/message/mu-mime-object.hh @@ -171,9 +171,6 @@ private: }; - - - /** * Thin wrapper around a GMimeContentType @@ -200,6 +197,15 @@ struct MimeContentType: public Object { return g_mime_content_type_is_type(self(), type.c_str(), subtype.c_str()); } + + Option parameter(const std::string& name) const noexcept { + const char *param{g_mime_content_type_get_parameter(self(), name.c_str())}; + if (!param || !param[0]) + return Nothing; + else + return Some(std::string{param}); + } + private: GMimeContentType* self() const { return reinterpret_cast(object()); @@ -929,6 +935,19 @@ public: throw std::runtime_error("not a mime-message"); } + /** + * Get the top-level MIME-part or Nothing if there is none + * + * @return MIME-part of nothing + */ + Option mime_part() const noexcept { + auto obj = g_mime_message_get_mime_part(self()); + if (!obj) + return Nothing; + else + return MimeObject{obj}; + } + /** * Make a MimeMessage from a file * diff --git a/lib/tests/test-mu-msg.cc b/lib/tests/test-mu-msg.cc index 1e5d82dc..abf16fff 100644 --- a/lib/tests/test-mu-msg.cc +++ b/lib/tests/test-mu-msg.cc @@ -1,5 +1,5 @@ /* -** Copyright (C) 2008-2022 Dirk-Jan C. Binnema +** Copyright (C) 2008-2024 Dirk-Jan C. Binnema ** ** This program is free software; you can redistribute it and/or modify it ** under the terms of the GNU General Public License as published by the @@ -58,7 +58,7 @@ assert_contacts_equal(const Contacts& contacts, static void -test_mu_msg_01(void) +test_mu_msg_01() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/1220863042.12663_1.mindcrime!2,S") .value()}; @@ -84,7 +84,7 @@ test_mu_msg_01(void) } static void -test_mu_msg_02(void) +test_mu_msg_02() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/1220863087.12663_19.mindcrime!2,S") .value()}; @@ -110,7 +110,7 @@ test_mu_msg_02(void) } static void -test_mu_msg_03(void) +test_mu_msg_03() { //const GSList* params; @@ -135,7 +135,7 @@ test_mu_msg_03(void) } static void -test_mu_msg_04(void) +test_mu_msg_04() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/mail5").value()}; @@ -152,7 +152,7 @@ test_mu_msg_04(void) } static void -test_mu_msg_multimime(void) +test_mu_msg_multimime() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/multimime!2,FS").value()}; @@ -163,7 +163,7 @@ test_mu_msg_multimime(void) } static void -test_mu_msg_flags(void) +test_mu_msg_flags() { std::array, 2> tests= {{ {MU_TESTMAILDIR4 "/multimime!2,FS", @@ -181,7 +181,7 @@ test_mu_msg_flags(void) } static void -test_mu_msg_umlaut(void) +test_mu_msg_umlaut() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/1305664394.2171_402.cthulhu!2,") .value()}; @@ -196,7 +196,7 @@ test_mu_msg_umlaut(void) } static void -test_mu_msg_references(void) +test_mu_msg_references() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/1305664394.2171_402.cthulhu!2,") .value()}; @@ -213,7 +213,7 @@ test_mu_msg_references(void) } static void -test_mu_msg_references_dups(void) +test_mu_msg_references_dups() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/1252168370_3.14675.cthulhu!2,S") .value()}; @@ -232,7 +232,7 @@ test_mu_msg_references_dups(void) } static void -test_mu_msg_references_many(void) +test_mu_msg_references_many() { auto msg{Message::make_from_path(MU_TESTMAILDIR2 "/bar/cur/181736.eml") .value()}; @@ -256,7 +256,7 @@ test_mu_msg_references_many(void) } static void -test_mu_msg_tags(void) +test_mu_msg_tags() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/mail1").value()}; @@ -278,7 +278,7 @@ test_mu_msg_tags(void) } static void -test_mu_msg_comp_unix_programmer(void) +test_mu_msg_comp_unix_programmer() { auto msg{Message::make_from_path(MU_TESTMAILDIR4 "/181736.eml").value()}; @@ -309,13 +309,53 @@ test_mu_msg_comp_unix_programmer(void) } static void -test_mu_str_prio_01(void) +test_mu_str_prio_01() { g_assert_true(priority_name(Priority::Low) == "low"); g_assert_true(priority_name(Priority::Normal) == "normal"); g_assert_true(priority_name(Priority::High) == "high"); } + +static void +test_mu_smime() +{ + const auto txt = +R"(Return-Path: me@privacy.net +From: Me +To: Me +Subject: smime +Date: Mon, 19 Aug 2024 09:46:10 -0500 +Message-ID: +Content-Type: application/pkcs7-mime; + smime-type=enveloped-data; + name=smime.p7m +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename=smime.p7m +MIME-Version: 1.0 +X-TUID: 9ipTl5lnIK+/ + +MIAGCSqGSIb3DQEHA6CAMIACAQAxggGVMIIBkQIBADB5MHExCzAJBgNVBAYTAlVTMRAwDgYDVQQK +EwdFbnRydXN0MSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMSwwKgYDVQQLEyNF +bnRydXN0IE5GSSBNZWRpdW0gQXNzdXJhbmNlIFNTUCBDQQIEYdtv3DANBgkqhkiG9w0BAQEFAASC +AQB8f86oe55rCRqzwbixv4QxWQdNsP8luhGVpDv7ojDd5qMhV30MDtM64gxqagPk44ZfaAA2NutT +vPiWOxUp8FZYN4aNAQy18KMB5G+w2xFdbXrWMNvwXdoLOcMkxD2LF7jJyIT2hUQfBWffGXvlxiSE +8HsAQKggmchkVJgNSMvIenXzFGhDXg9OVkRvxV/3zfbmF/0jF3e5DbjvW3Qyclidpg/H1zM2iuYE +BMPdStvWRAkQL8sxOF0XVYjaCd0Y+crK7FwHS923vTNFxIyEaWdKD7HmuLTxVxaGAZpuRPwI/Vbj +t0k68twxZ4sCUISxAkuvPYVntEwNjqxtOs6zdzq/MIAGCSqGSIb3DQEHATAdBglghkgBZQMEASoE +EH4y0ZsEAM4pNRvjMhRTnIiggAQgnUUkL7jAwlLwDAsbqCdBTnqz2moSkhE9F/1Qqy/jXYwEEFYW +k+ZGGoQ0v8b7RwmyskMAAAAAAAAAAAAA +)"; + const auto msg{Message::make_from_text(txt, "boo/cur/msg2:2,S")}; + assert_valid_result(msg); + + assert_equal(msg->subject(), "smime"); + + assert_equal("Sxa", to_string(msg->flags())); + g_assert_true(msg->flags() == (Flags::Seen|Flags::Encrypted|Flags::HasAttachment)); +} + + G_GNUC_UNUSED static gboolean ignore_error(const char* log_domain, GLogLevelFlags log_level, const gchar* msg, gpointer user_data) { @@ -331,23 +371,25 @@ main(int argc, char* argv[]) g_test_init(&argc, &argv, NULL); /* mu_msg_str_date */ - g_test_add_func("/mu-msg/mu-msg-01", test_mu_msg_01); - g_test_add_func("/mu-msg/mu-msg-02", test_mu_msg_02); - g_test_add_func("/mu-msg/mu-msg-03", test_mu_msg_03); - g_test_add_func("/mu-msg/mu-msg-04", test_mu_msg_04); - g_test_add_func("/mu-msg/mu-msg-multimime", test_mu_msg_multimime); + g_test_add_func("/msg/mu-msg-01", test_mu_msg_01); + g_test_add_func("/msg/mu-msg-02", test_mu_msg_02); + g_test_add_func("/msg/mu-msg-03", test_mu_msg_03); + g_test_add_func("/msg/mu-msg-04", test_mu_msg_04); + g_test_add_func("/msg/mu-msg-multimime", test_mu_msg_multimime); - g_test_add_func("/mu-msg/mu-msg-flags", test_mu_msg_flags); + g_test_add_func("/msg/mu-msg-flags", test_mu_msg_flags); - g_test_add_func("/mu-msg/mu-msg-tags", test_mu_msg_tags); - g_test_add_func("/mu-msg/mu-msg-references", test_mu_msg_references); - g_test_add_func("/mu-msg/mu-msg-references_dups", test_mu_msg_references_dups); - g_test_add_func("/mu-msg/mu-msg-references_many", test_mu_msg_references_many); + g_test_add_func("/msg/mu-msg-tags", test_mu_msg_tags); + g_test_add_func("/msg/mu-msg-references", test_mu_msg_references); + g_test_add_func("/msg/mu-msg-references_dups", test_mu_msg_references_dups); + g_test_add_func("/msg/mu-msg-references_many", test_mu_msg_references_many); - g_test_add_func("/mu-msg/mu-msg-umlaut", test_mu_msg_umlaut); - g_test_add_func("/mu-msg/mu-msg-comp-unix-programmer", test_mu_msg_comp_unix_programmer); + g_test_add_func("/msg/mu-msg-umlaut", test_mu_msg_umlaut); + g_test_add_func("/msg/mu-msg-comp-unix-programmer", test_mu_msg_comp_unix_programmer); - g_test_add_func("/mu-str/mu-str-prio-01", test_mu_str_prio_01); + g_test_add_func("/msg/mu-smime", test_mu_smime); + + g_test_add_func("/str/mu-str-prio-01", test_mu_str_prio_01); rv = g_test_run();