message: add cache_path per message

Generate a message-specific cache path when needed.
Update tests, too.
This commit is contained in:
Dirk-Jan C. Binnema 2022-05-05 01:24:18 +03:00
parent 85fed37870
commit c0ae7e6860
4 changed files with 62 additions and 34 deletions

View File

@ -22,6 +22,7 @@
#include "glibconfig.h" #include "glibconfig.h"
#include "mu-mime-object.hh" #include "mu-mime-object.hh"
#include "utils/mu-utils.hh" #include "utils/mu-utils.hh"
#include <string>
using namespace Mu; using namespace Mu;
@ -71,8 +72,7 @@ MessagePart::cooked_filename() const noexcept
.value_or("no-subject") + ".eml"; .value_or("no-subject") + ".eml";
} }
return Nothing; return Nothing;
} }
Option<std::string> Option<std::string>

View File

@ -39,6 +39,7 @@
#include "gmime/gmime-message.h" #include "gmime/gmime-message.h"
#include "mu-mime-object.hh" #include "mu-mime-object.hh"
#include "mu-option.hh"
using namespace Mu; using namespace Mu;
@ -98,7 +99,7 @@ Message::Message(const std::string& path, Message::Options opts):
if (!statbuf) if (!statbuf)
throw statbuf.error(); throw statbuf.error();
priv_->mtime = statbuf->st_mtime; priv_->ctime = statbuf->st_ctime;
init_gmime(); init_gmime();
if (auto msg{MimeMessage::make_from_file(path)}; !msg) 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", "'%s' is not a valid maildir for message @ %s",
maildir.c_str(), path.c_str()); maildir.c_str(), path.c_str());
priv_->doc.remove(Field::Id::Maildir);
priv_->doc.add(Field::Id::Maildir, maildir); priv_->doc.add(Field::Id::Maildir, maildir);
return Ok(); return Ok();
} }
void void
Message::set_flags(Flags flags) Message::set_flags(Flags flags)
{ {
priv_->doc.remove(Field::Id::Flags);
priv_->doc.add(flags); priv_->doc.add(flags);
} }
@ -694,13 +695,10 @@ fill_document(Message::Private& priv)
case Field::Id::To: case Field::Id::To:
doc.add(field.id, mime_msg.contacts(Contact::Type::To)); doc.add(field.id, mime_msg.contacts(Contact::Type::To));
break; break;
/* internal fields */ /* internal fields */
case Field::Id::XBodyHtml: case Field::Id::XBodyHtml:
doc.add(field.id, priv.body_html); doc.add(field.id, priv.body_html);
break; break;
case Field::Id::XCachedSexp:
break;
/* ignore */ /* ignore */
case Field::Id::_count_: case Field::Id::_count_:
break; break;
@ -759,15 +757,24 @@ Message::parts() const
return priv_->parts; return priv_->parts;
} }
::time_t Result<std::string>
Message::mtime() const Message::cache_path() const
{ {
if (!load_mime_message()) /* create tmpdir for this message, if needed */
return 0; 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<void> Result<void>
Message::update_after_move(const std::string& new_path, Message::update_after_move(const std::string& new_path,
const std::string& new_maildir, const std::string& new_maildir,

View File

@ -140,6 +140,14 @@ public:
*/ */
const Document& document() const; 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 * 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 { ::time_t changed() const {
return static_cast<::time_t>(document().integer_value(Field::Id::Modified)); 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 * @return a list with the tags for this msg. Don't modify/free
*/ */
std::vector<std::string> tags() const { std::vector<std::string> 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. * @return sexp or empty.
*/ */
std::string cached_sexp() const { 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 * Get the s-expression for this message. Stays valid as long
* processing in e.g. emacs) * 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; const Mu::Sexp::List& to_sexp_list() const;
Mu::Sexp to_sexp() 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 * Update the cached sexp for this message which is stored in the
* document.This should be done when the document is complete, * document. This should be done immediately before storing it in the
* i.e., immediately before storing it in the database. * database.
* *
*/ */
void update_cached_sexp(); void update_cached_sexp();
@ -369,13 +379,6 @@ public:
Option<std::string> header(const std::string& header_field) const; Option<std::string> 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. * Get all contacts for this message.
* *
@ -391,6 +394,16 @@ public:
using Part = MessagePart; using Part = MessagePart;
const std::vector<Part>& parts() const; const std::vector<Part>& 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<std::string> cache_path() const;
/** /**
* Load the GMime (file) message (for a database-backed message), * Load the GMime (file) message (for a database-backed message),
* if not already (but see @param reload). * if not already (but see @param reload).

View File

@ -204,6 +204,9 @@ World!
assert_equal(message->subject(), "ättächmeñts"); 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); g_assert_cmpuint(message->parts().size(),==,5);
{ {
auto&& part{message->parts().at(0)}; auto&& part{message->parts().at(0)};
@ -228,6 +231,11 @@ World!
assert_equal(part.mime_type().value(), "audio/ogg"); assert_equal(part.mime_type().value(), "audio/ogg");
// file consistso of 4 bytes 4..7 // file consistso of 4 bytes 4..7
assert_equal(part.to_string().value(), "\004\005\006\007"); 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);
} }
{ {