diff --git a/lib/message/mu-message-part.cc b/lib/message/mu-message-part.cc index 735b27c4..dde57702 100644 --- a/lib/message/mu-message-part.cc +++ b/lib/message/mu-message-part.cc @@ -22,6 +22,7 @@ #include "glibconfig.h" #include "mu-mime-object.hh" #include "utils/mu-utils.hh" +#include using namespace Mu; @@ -71,8 +72,7 @@ MessagePart::cooked_filename() const noexcept .value_or("no-subject") + ".eml"; } -return Nothing; - + return Nothing; } Option diff --git a/lib/message/mu-message.cc b/lib/message/mu-message.cc index 74904031..3c39710e 100644 --- a/lib/message/mu-message.cc +++ b/lib/message/mu-message.cc @@ -39,6 +39,7 @@ #include "gmime/gmime-message.h" #include "mu-mime-object.hh" +#include "mu-option.hh" using namespace Mu; @@ -98,7 +99,7 @@ Message::Message(const std::string& path, Message::Options opts): if (!statbuf) throw statbuf.error(); - priv_->mtime = statbuf->st_mtime; + priv_->ctime = statbuf->st_ctime; init_gmime(); if (auto msg{MimeMessage::make_from_file(path)}; !msg) @@ -204,16 +205,16 @@ Message::set_maildir(const std::string& maildir) "'%s' is not a valid maildir for message @ %s", maildir.c_str(), path.c_str()); + priv_->doc.remove(Field::Id::Maildir); priv_->doc.add(Field::Id::Maildir, maildir); return Ok(); } - - void Message::set_flags(Flags flags) { + priv_->doc.remove(Field::Id::Flags); priv_->doc.add(flags); } @@ -694,13 +695,10 @@ fill_document(Message::Private& priv) case Field::Id::To: doc.add(field.id, mime_msg.contacts(Contact::Type::To)); break; - /* internal fields */ case Field::Id::XBodyHtml: doc.add(field.id, priv.body_html); break; - case Field::Id::XCachedSexp: - break; /* ignore */ case Field::Id::_count_: break; @@ -759,15 +757,24 @@ Message::parts() const return priv_->parts; } -::time_t -Message::mtime() const +Result +Message::cache_path() const { - if (!load_mime_message()) - return 0; + /* create tmpdir for this message, if needed */ + if (priv_->cache_path.empty()) { + GError *err{}; + auto tpath{to_string_opt_gchar( + g_dir_make_tmp("mu-message-part-XXXXXX", &err))}; + if (!tpath) + return Err(Error::Code::File, &err, + "failed to create temp dir"); + priv_->cache_path = std::move(tpath.value()); + } - return priv_->mtime; + return Ok(std::string{priv_->cache_path}); } + Result Message::update_after_move(const std::string& new_path, const std::string& new_maildir, diff --git a/lib/message/mu-message.hh b/lib/message/mu-message.hh index 8b3e003c..9b60c61c 100644 --- a/lib/message/mu-message.hh +++ b/lib/message/mu-message.hh @@ -140,6 +140,14 @@ public: */ const Document& document() const; + + /** + * Get the document-id, or 0 if non-existent. + * + * @return document id + */ + unsigned docid() const; + /** * Get the file system path of this message * @@ -236,12 +244,12 @@ public: } /** - * get the last modification or creation time for this message + * get the last change-time (ctime) for this message * - * @return message date/time or 0 if unknown + * @return chnage time or 0 if unknown */ - ::time_t modified() const { - return static_cast<::time_t>(document().integer_value(Field::Id::Modified)); + ::time_t changed() const { + return static_cast<::time_t>(document().integer_value(Field::Id::Changed)); } /** @@ -297,7 +305,8 @@ public: * @return a list with the tags for this msg. Don't modify/free */ std::vector tags() const { - return document().string_vec_value(Field::Id::Tags); + return document() + .string_vec_value(Field::Id::Tags); } /** @@ -306,7 +315,7 @@ public: * @return sexp or empty. */ std::string cached_sexp() const { - return document().string_value(Field::Id::XCachedSexp); + return document().cached_sexp(); } /* @@ -314,19 +323,20 @@ public: */ /** - * convert the message to a Lisp symbolic expression (for further - * processing in e.g. emacs) + * Get the s-expression for this message. Stays valid as long + * as this message is. * - * @return a Mu::Sexp or a Mu::Sexp::List representing the message. + * @return a Mu::Sexp::List representing the message. */ - Mu::Sexp::List to_sexp_list() const; - Mu::Sexp to_sexp() const; - + const Mu::Sexp::List& to_sexp_list() const; + Mu::Sexp to_sexp() const { + return Sexp::make_list(Sexp::List(to_sexp_list())); + } /** * Update the cached sexp for this message which is stored in the - * document.This should be done when the document is complete, - * i.e., immediately before storing it in the database. + * document. This should be done immediately before storing it in the + * database. * */ void update_cached_sexp(); @@ -369,13 +379,6 @@ public: Option header(const std::string& header_field) const; - /** - * Get the mtime for the message file. - * - * @return the mtime - */ - ::time_t mtime() const; - /** * Get all contacts for this message. * @@ -391,6 +394,16 @@ public: using Part = MessagePart; const std::vector& parts() const; + + /** + * Get the path to a cche directory for this message, which + * is useful for temporarily saving attachments + * + * @return path to a (created) cache directory, or an error. + */ + Result cache_path() const; + + /** * Load the GMime (file) message (for a database-backed message), * if not already (but see @param reload). diff --git a/lib/message/test-mu-message.cc b/lib/message/test-mu-message.cc index 823a067d..cfbdc660 100644 --- a/lib/message/test-mu-message.cc +++ b/lib/message/test-mu-message.cc @@ -204,6 +204,9 @@ World! assert_equal(message->subject(), "ättächmeñts"); + const auto cache_path{message->cache_path()}; + g_assert_true(!!cache_path); + g_assert_cmpuint(message->parts().size(),==,5); { auto&& part{message->parts().at(0)}; @@ -228,6 +231,11 @@ World! assert_equal(part.mime_type().value(), "audio/ogg"); // file consistso of 4 bytes 4..7 assert_equal(part.to_string().value(), "\004\005\006\007"); + const auto fpath{*cache_path + part.cooked_filename().value()}; + const auto res = part.to_file(fpath, true); + + g_assert_cmpuint(*res,==,4); + g_assert_cmpuint(::access(fpath.c_str(), R_OK), ==, 0); } {