From 31e5c7b34e8312f4bda2cffeee77d243eb8d2df8 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Thu, 23 Jul 2026 13:26:27 +0300 Subject: [PATCH] mu-message: various small tweaks - Remove possible cache-dir - Retain Personal flag - Handle some corner cases --- lib/message/mu-message.cc | 53 +++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/lib/message/mu-message.cc b/lib/message/mu-message.cc index b2581b07..41b737d3 100644 --- a/lib/message/mu-message.cc +++ b/lib/message/mu-message.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,14 @@ struct Message::Private { Private(Message::Options options, Xapian::Document&& xdoc): opts{options}, doc{std::move(xdoc), doc_opts(opts)} {} + ~Private() { /* clean up the cache dir, if any */ + if (cache_path.empty()) + return; + if (auto&& res{remove_directory(cache_path)}; !res) + mu_warning("failed to remove cache dir '{}': {}", + cache_path, res.error().what()); + } + Message::Options opts; Document doc; mutable Option mime_msg; @@ -78,7 +87,7 @@ struct Message::Private { private: Document::Options doc_opts(Message::Options mopts) { - return any_of(opts & Message::Options::NgramsEnabled) ? + return any_of(mopts & Message::Options::NgramsEnabled) ? Document::Options::NgramsEnabled : Document::Options::None; } @@ -326,7 +335,8 @@ extract_tags(const MimeMessage& mime_msg) for (auto&& tagval : split(*hdr, item.second)) { tagval.erase(0, tagval.find_first_not_of(' ')); tagval.erase(tagval.find_last_not_of(' ')+1); - tags.emplace_back(std::move(tagval)); + if (!tagval.empty()) + tags.emplace_back(std::move(tagval)); } } }); @@ -493,6 +503,9 @@ handle_encrypted(const MimeMultipartEncrypted& part, Message::Private& info) } if (res->first.is_multipart()) { + /* handle the multipart itself too, so e.g. a decrypted + * multipart/signed sets the Signed flag */ + handle_object(part, res->first, info); MimeMultipart{res->first}.for_each( [&](auto&& parent, auto&& child_obj) { handle_object(parent, child_obj, info); @@ -538,8 +551,7 @@ handle_object(const MimeObject& parent, handle_encrypted(MimeMultipartEncrypted{obj}, info); else if (obj.is_part() || obj.is_message_part() || - obj.is_multipart_signed() || - obj.is_multipart_encrypted()) + obj.is_multipart_signed()) info.parts.emplace_back(obj); if (obj.is_part()) @@ -662,13 +674,14 @@ doc_add_list_post(Document& doc, const MimeMessage& mime_msg) * those cases, check the List-Post address and use that instead */ GMatchInfo* minfo{}; - GRegex* rx{}; const auto list_post{mime_msg.header("List-Post")}; if (!list_post) return; - rx = g_regex_new("?", - G_REGEX_CASELESS, (GRegexMatchFlags)0, {}); + /* compile the regex only once */ + static GRegex *rx = g_regex_new( + "?", + G_REGEX_CASELESS, (GRegexMatchFlags)0, {}); g_return_if_fail(rx); Contacts contacts; @@ -681,8 +694,6 @@ doc_add_list_post(Document& doc, const MimeMessage& mime_msg) if (minfo) g_match_info_free(minfo); - g_regex_unref(rx); - doc.add_extra_contacts(":list-post", contacts); } @@ -732,7 +743,10 @@ fill_document(Message::Private& priv) doc.add(field.id, mime_msg.contacts(Contact::Type::Cc)); break; case Field::Id::Changed: - doc.add(field.id, priv.ctime); + /* when lazily re-filling a store-backed message, we + * never stat'ed the file; keep the stored value */ + if (priv.ctime != 0) + doc.add(field.id, priv.ctime); break; case Field::Id::Date: doc.add(field.id, mime_msg.date()); @@ -745,7 +759,12 @@ fill_document(Message::Private& priv) doc.add(field.id, part.raw_filename()); break; case Field::Id::Flags: - doc.add(priv.flags); + /* the stored flags may include Flags::Personal, which + * is determined with the contacts-cache (mu-store.cc) + * and cannot be recomputed here; don't lose it when + * lazily re-filling a store-backed message */ + doc.add(flags_keep_unmutable(doc.flags_value(), priv.flags, + Flags::Personal)); break; case Field::Id::From: doc.add(field.id, mime_msg.contacts(Contact::Type::From)); @@ -806,7 +825,9 @@ fill_document(Message::Private& priv) Option Message::header(const std::string& header_field) const { - load_mime_message(); + if (!load_mime_message()) + return Nothing; + return priv_->mime_msg->header(header_field); } @@ -860,11 +881,11 @@ Message::cache_path(Option index) const } if (index) { - GError *err{}; auto tpath = mu_format("{}/{}", priv_->cache_path, *index); - if (g_mkdir(tpath.c_str(), 0700) != 0) - return Err(Error::Code::File, &err, - "failed to create cache dir '{}'; err={}", tpath, errno); + if (g_mkdir(tpath.c_str(), 0700) != 0 && errno != EEXIST) + return Err(Error::Code::File, + "failed to create cache dir '{}': {}", tpath, + g_strerror(errno)); return Ok(std::move(tpath)); } else