mu-message: various small tweaks

- Remove possible cache-dir
- Retain Personal flag
- Handle some corner cases
This commit is contained in:
Dirk-Jan C. Binnema
2026-07-23 13:26:27 +03:00
committed by Seth Ladygo
parent a9a57d0511
commit 31e5c7b34e

View File

@ -27,6 +27,7 @@
#include <string> #include <string>
#include <regex> #include <regex>
#include <utils/mu-utils.hh> #include <utils/mu-utils.hh>
#include <utils/mu-utils-file.hh>
#include <utils/mu-error.hh> #include <utils/mu-error.hh>
#include <utils/mu-option.hh> #include <utils/mu-option.hh>
#include <utils/mu-lang-detector.hh> #include <utils/mu-lang-detector.hh>
@ -50,6 +51,14 @@ struct Message::Private {
Private(Message::Options options, Xapian::Document&& xdoc): Private(Message::Options options, Xapian::Document&& xdoc):
opts{options}, doc{std::move(xdoc), doc_opts(opts)} {} 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; Message::Options opts;
Document doc; Document doc;
mutable Option<MimeMessage> mime_msg; mutable Option<MimeMessage> mime_msg;
@ -78,7 +87,7 @@ struct Message::Private {
private: private:
Document::Options doc_opts(Message::Options mopts) { 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::NgramsEnabled :
Document::Options::None; Document::Options::None;
} }
@ -326,6 +335,7 @@ extract_tags(const MimeMessage& mime_msg)
for (auto&& tagval : split(*hdr, item.second)) { for (auto&& tagval : split(*hdr, item.second)) {
tagval.erase(0, tagval.find_first_not_of(' ')); tagval.erase(0, tagval.find_first_not_of(' '));
tagval.erase(tagval.find_last_not_of(' ')+1); tagval.erase(tagval.find_last_not_of(' ')+1);
if (!tagval.empty())
tags.emplace_back(std::move(tagval)); tags.emplace_back(std::move(tagval));
} }
} }
@ -493,6 +503,9 @@ handle_encrypted(const MimeMultipartEncrypted& part, Message::Private& info)
} }
if (res->first.is_multipart()) { 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( MimeMultipart{res->first}.for_each(
[&](auto&& parent, auto&& child_obj) { [&](auto&& parent, auto&& child_obj) {
handle_object(parent, child_obj, info); handle_object(parent, child_obj, info);
@ -538,8 +551,7 @@ handle_object(const MimeObject& parent,
handle_encrypted(MimeMultipartEncrypted{obj}, info); handle_encrypted(MimeMultipartEncrypted{obj}, info);
else if (obj.is_part() || else if (obj.is_part() ||
obj.is_message_part() || obj.is_message_part() ||
obj.is_multipart_signed() || obj.is_multipart_signed())
obj.is_multipart_encrypted())
info.parts.emplace_back(obj); info.parts.emplace_back(obj);
if (obj.is_part()) if (obj.is_part())
@ -662,12 +674,13 @@ doc_add_list_post(Document& doc, const MimeMessage& mime_msg)
* those cases, check the List-Post address and use that instead */ * those cases, check the List-Post address and use that instead */
GMatchInfo* minfo{}; GMatchInfo* minfo{};
GRegex* rx{};
const auto list_post{mime_msg.header("List-Post")}; const auto list_post{mime_msg.header("List-Post")};
if (!list_post) if (!list_post)
return; return;
rx = g_regex_new("<?mailto:([a-z0-9!@#$%&'*+-/=?^_`{|}~]+)>?", /* compile the regex only once */
static GRegex *rx = g_regex_new(
"<?mailto:([a-z0-9!@#$%&'*+-/=?^_`{|}~]+)>?",
G_REGEX_CASELESS, (GRegexMatchFlags)0, {}); G_REGEX_CASELESS, (GRegexMatchFlags)0, {});
g_return_if_fail(rx); g_return_if_fail(rx);
@ -681,8 +694,6 @@ doc_add_list_post(Document& doc, const MimeMessage& mime_msg)
if (minfo) if (minfo)
g_match_info_free(minfo); g_match_info_free(minfo);
g_regex_unref(rx);
doc.add_extra_contacts(":list-post", contacts); doc.add_extra_contacts(":list-post", contacts);
} }
@ -732,6 +743,9 @@ fill_document(Message::Private& priv)
doc.add(field.id, mime_msg.contacts(Contact::Type::Cc)); doc.add(field.id, mime_msg.contacts(Contact::Type::Cc));
break; break;
case Field::Id::Changed: case Field::Id::Changed:
/* 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); doc.add(field.id, priv.ctime);
break; break;
case Field::Id::Date: case Field::Id::Date:
@ -745,7 +759,12 @@ fill_document(Message::Private& priv)
doc.add(field.id, part.raw_filename()); doc.add(field.id, part.raw_filename());
break; break;
case Field::Id::Flags: 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; break;
case Field::Id::From: case Field::Id::From:
doc.add(field.id, mime_msg.contacts(Contact::Type::From)); doc.add(field.id, mime_msg.contacts(Contact::Type::From));
@ -806,7 +825,9 @@ fill_document(Message::Private& priv)
Option<std::string> Option<std::string>
Message::header(const std::string& header_field) const Message::header(const std::string& header_field) const
{ {
load_mime_message(); if (!load_mime_message())
return Nothing;
return priv_->mime_msg->header(header_field); return priv_->mime_msg->header(header_field);
} }
@ -860,11 +881,11 @@ Message::cache_path(Option<size_t> index) const
} }
if (index) { if (index) {
GError *err{};
auto tpath = mu_format("{}/{}", priv_->cache_path, *index); auto tpath = mu_format("{}/{}", priv_->cache_path, *index);
if (g_mkdir(tpath.c_str(), 0700) != 0) if (g_mkdir(tpath.c_str(), 0700) != 0 && errno != EEXIST)
return Err(Error::Code::File, &err, return Err(Error::Code::File,
"failed to create cache dir '{}'; err={}", tpath, errno); "failed to create cache dir '{}': {}", tpath,
g_strerror(errno));
return Ok(std::move(tpath)); return Ok(std::move(tpath));
} else } else