mirror of https://github.com/djcb/mu.git
message: add cache_path per message
Generate a message-specific cache path when needed. Update tests, too.
This commit is contained in:
parent
85fed37870
commit
c0ae7e6860
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue