mirror of https://github.com/djcb/mu.git
server: use Mu::Store in c++ mode
I.e. Mu::Store instead of mu_store_*
This commit is contained in:
parent
a9fab4abcc
commit
0b427e5ee8
|
@ -28,6 +28,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gprintf.h>
|
#include <glib/gprintf.h>
|
||||||
|
|
||||||
|
#include "mu-msg.h"
|
||||||
#include "mu-runtime.h"
|
#include "mu-runtime.h"
|
||||||
#include "mu-cmd.hh"
|
#include "mu-cmd.hh"
|
||||||
#include "mu-maildir.h"
|
#include "mu-maildir.h"
|
||||||
|
@ -211,55 +212,59 @@ print_sexps (MuMsgIter *iter, unsigned maxnum)
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
Context(){}
|
Context(){}
|
||||||
Context (const MuConfig *opts) {
|
Context (const MuConfig *opts):
|
||||||
const auto dbpath{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB)};
|
store_{std::make_unique<Store>(mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), false/*writable*/)} {
|
||||||
|
|
||||||
|
// store = mu_store_new_writable (dbpath, NULL);
|
||||||
|
// if (!store) {
|
||||||
|
// const auto mu_init = format("mu init %s%s",
|
||||||
|
// opts->muhome ? "--muhome=" : "",
|
||||||
|
// opts->muhome ? opts->muhome : "");
|
||||||
|
|
||||||
|
// if (gerr) {
|
||||||
|
// if ((MuError)gerr->code == MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK)
|
||||||
|
// print_error(MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK,
|
||||||
|
// "mu database already locked; "
|
||||||
|
// "some other mu running?");
|
||||||
|
// else
|
||||||
|
// print_error((MuError)gerr->code,
|
||||||
|
// "cannot open database @ %s:%s; already running? "
|
||||||
|
// "if not, please try '%s", dbpath,
|
||||||
|
// gerr->message ? gerr->message : "something went wrong",
|
||||||
|
// mu_init.c_str());
|
||||||
|
// } else
|
||||||
|
// print_error(MU_ERROR,
|
||||||
|
// "cannot open database @ %s; already running? if not, please try '%s'",
|
||||||
|
// dbpath, mu_init.c_str());
|
||||||
|
|
||||||
|
// throw Mu::Error (Error::Code::Store, &gerr/*consumed*/,
|
||||||
|
// "failed to open database @ %s; already running? if not, please try '%s'",
|
||||||
|
// dbpath, mu_init.c_str());
|
||||||
|
// }
|
||||||
|
|
||||||
GError *gerr{};
|
GError *gerr{};
|
||||||
store = mu_store_new_writable (dbpath, NULL);
|
query = mu_query_new (reinterpret_cast<MuStore*>(store_.get()), &gerr);
|
||||||
if (!store) {
|
|
||||||
const auto mu_init = format("mu init %s%s",
|
|
||||||
opts->muhome ? "--muhome=" : "",
|
|
||||||
opts->muhome ? opts->muhome : "");
|
|
||||||
|
|
||||||
if (gerr) {
|
|
||||||
if ((MuError)gerr->code == MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK)
|
|
||||||
print_error(MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK,
|
|
||||||
"mu database already locked; "
|
|
||||||
"some other mu running?");
|
|
||||||
else
|
|
||||||
print_error((MuError)gerr->code,
|
|
||||||
"cannot open database @ %s:%s; already running? "
|
|
||||||
"if not, please try '%s", dbpath,
|
|
||||||
gerr->message ? gerr->message : "something went wrong",
|
|
||||||
mu_init.c_str());
|
|
||||||
} else
|
|
||||||
print_error(MU_ERROR,
|
|
||||||
"cannot open database @ %s; already running? if not, please try '%s'",
|
|
||||||
dbpath, mu_init.c_str());
|
|
||||||
|
|
||||||
throw Mu::Error (Error::Code::Store, &gerr/*consumed*/,
|
|
||||||
"failed to open database @ %s; already running? if not, please try '%s'",
|
|
||||||
dbpath, mu_init.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
query = mu_query_new (store, &gerr);
|
|
||||||
if (!query)
|
if (!query)
|
||||||
throw Error(Error::Code::Store, &gerr, "failed to create query");
|
throw Error(Error::Code::Store, &gerr/*consumes*/, "failed to create query");
|
||||||
}
|
}
|
||||||
|
|
||||||
~Context() {
|
~Context() {
|
||||||
if (query)
|
if (query)
|
||||||
mu_query_destroy(query);
|
mu_query_destroy(query);
|
||||||
if (store) {
|
|
||||||
mu_store_flush(store);
|
|
||||||
mu_store_unref(store);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Context(const Context&) = delete;
|
Context(const Context&) = delete;
|
||||||
|
|
||||||
MuStore *store{};
|
Store& store() {
|
||||||
MuQuery *query{};
|
if (!store_)
|
||||||
bool do_quit{};
|
throw Mu::Error (Error::Code::Internal, "no store");
|
||||||
|
return *store_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::unique_ptr<Mu::Store> store_;
|
||||||
|
MuQuery *query{};
|
||||||
|
bool do_quit{};
|
||||||
|
|
||||||
CommandMap command_map;
|
CommandMap command_map;
|
||||||
};
|
};
|
||||||
|
@ -291,26 +296,28 @@ message_options (const Parameters& params)
|
||||||
static void
|
static void
|
||||||
add_handler (Context& context, const Parameters& params)
|
add_handler (Context& context, const Parameters& params)
|
||||||
{
|
{
|
||||||
const auto path{get_string_or(params, "path")};
|
auto path{get_string_or(params, "path")};
|
||||||
|
const auto docid{context.store().add_message(path)};
|
||||||
|
|
||||||
GError *gerr{};
|
Node::Seq seq;
|
||||||
const auto docid{mu_store_add_path (context.store, path.c_str(), &gerr)};
|
seq.add_prop(":info", Node::make_symbol("add"));
|
||||||
if (docid == MU_STORE_INVALID_DOCID)
|
seq.add_prop(":path", path);
|
||||||
throw Error(Error::Code::Store, &gerr, "failed to add message at %s",
|
seq.add_prop(":docid", docid);
|
||||||
path.c_str());
|
|
||||||
|
|
||||||
print_expr ("(:info add :path %s :docid %u)", quote(path).c_str(), docid);
|
print_expr (std::move(seq));
|
||||||
|
|
||||||
auto msg{mu_store_get_msg(context.store, docid, &gerr)};
|
auto msg{context.store().find_message(docid)};
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error(Error::Code::Store, &gerr, "failed to get message at %s",
|
throw Error(Error::Code::Store,
|
||||||
path.c_str());
|
"failed to get message at %s (docid=%u)",
|
||||||
|
path.c_str(), docid);
|
||||||
|
|
||||||
auto sexp{mu_msg_to_sexp (msg, docid, NULL, MU_MSG_OPTION_VERIFY)};
|
Node::Seq updateseq;
|
||||||
print_expr ("(:update %s :move nil)", sexp);
|
updateseq.add_prop(":update", Mu::msg_to_sexp(msg, docid, NULL,
|
||||||
|
MU_MSG_OPTION_VERIFY));
|
||||||
|
|
||||||
|
print_expr (std::move(updateseq));
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
g_free (sexp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -367,7 +374,7 @@ compose_handler (Context& context, const Parameters& params)
|
||||||
|
|
||||||
GError *gerr{};
|
GError *gerr{};
|
||||||
const unsigned docid{(unsigned)get_int_or(params, "docid")};
|
const unsigned docid{(unsigned)get_int_or(params, "docid")};
|
||||||
auto msg{mu_store_get_msg (context.store, docid, &gerr)};
|
auto msg{context.store().find_message(docid)};
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error{Error::Code::Store, &gerr, "failed to get message %u", docid};
|
throw Error{Error::Code::Store, &gerr, "failed to get message %u", docid};
|
||||||
|
|
||||||
|
@ -390,80 +397,10 @@ compose_handler (Context& context, const Parameters& params)
|
||||||
print_expr (std::move(compose_seq));
|
print_expr (std::move(compose_seq));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct SexpData {
|
|
||||||
Sexp::Node::Seq contacts;
|
|
||||||
gboolean personal;
|
|
||||||
time_t last_seen;
|
|
||||||
gint64 tstamp;
|
|
||||||
size_t rank;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
each_contact_sexp (const char* full_address,
|
|
||||||
const char *email, const char *name, gboolean personal,
|
|
||||||
time_t last_seen, unsigned freq,
|
|
||||||
gint64 tstamp, SexpData *sdata)
|
|
||||||
{
|
|
||||||
sdata->rank++;
|
|
||||||
|
|
||||||
/* since the last time we got some contacts */
|
|
||||||
if (sdata->tstamp > tstamp)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* (maybe) only include 'personal' contacts */
|
|
||||||
if (sdata->personal && !personal)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* only include newer-than-x contacts */
|
|
||||||
if (sdata->last_seen > last_seen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* only include *real* e-mail addresses (ignore local
|
|
||||||
* addresses... there's little to complete there anyway...) */
|
|
||||||
if (!email || !strstr (email, "@"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Node::Seq contact;
|
|
||||||
contact.add_prop(":address", full_address);
|
|
||||||
contact.add_prop(":rank", sdata->rank);
|
|
||||||
|
|
||||||
sdata->contacts.add(Node::make_list(std::move(contact)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get all contacts as an s-expression
|
|
||||||
*
|
|
||||||
* @param self contacts object
|
|
||||||
* @param personal_only whether to restrict the list to 'personal' email
|
|
||||||
* addresses
|
|
||||||
*
|
|
||||||
* @return the sexp
|
|
||||||
*/
|
|
||||||
static Sexp::Node
|
|
||||||
contacts_to_sexp (const MuContacts *contacts, bool personal,
|
|
||||||
int64_t last_seen, gint64 tstamp)
|
|
||||||
{
|
|
||||||
SexpData sdata{};
|
|
||||||
sdata.personal = personal;
|
|
||||||
sdata.last_seen = last_seen;
|
|
||||||
sdata.tstamp = tstamp;
|
|
||||||
sdata.rank = 0;
|
|
||||||
|
|
||||||
const auto cutoff{g_get_monotonic_time()};
|
|
||||||
mu_contacts_foreach (contacts, (MuContactsForeachFunc)each_contact_sexp, &sdata);
|
|
||||||
Node::Seq seq;
|
|
||||||
seq.add_prop(":contacts", std::move(sdata.contacts));
|
|
||||||
seq.add_prop(":tstamp", Node::make_string(format("%" G_GINT64_FORMAT, cutoff)));
|
|
||||||
|
|
||||||
return Node::make_list(std::move(seq));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
contacts_handler (Context& context, const Parameters& params)
|
contacts_handler (Context& context, const Parameters& params)
|
||||||
{
|
{
|
||||||
const auto personal = get_bool_or(params, "personal");
|
const auto personal = get_bool_or(params, "personal");
|
||||||
const auto afterstr = get_string_or(params, "after");
|
const auto afterstr = get_string_or(params, "after");
|
||||||
const auto tstampstr = get_string_or(params, "tstamp");
|
const auto tstampstr = get_string_or(params, "tstamp");
|
||||||
|
|
||||||
|
@ -471,14 +408,39 @@ contacts_handler (Context& context, const Parameters& params)
|
||||||
g_ascii_strtoll(date_to_time_t_string(afterstr, true).c_str(), {}, 10)};
|
g_ascii_strtoll(date_to_time_t_string(afterstr, true).c_str(), {}, 10)};
|
||||||
const auto tstamp = g_ascii_strtoll (tstampstr.c_str(), NULL, 10);
|
const auto tstamp = g_ascii_strtoll (tstampstr.c_str(), NULL, 10);
|
||||||
|
|
||||||
const auto contacts{mu_store_contacts(context.store)};
|
auto rank{0};
|
||||||
if (!contacts)
|
Node::Seq contacts;
|
||||||
throw Error{Error::Code::Internal, "failed to get contacts"};
|
context.store().contacts().for_each([&](const ContactInfo& ci) {
|
||||||
|
|
||||||
|
rank++;
|
||||||
|
|
||||||
|
/* since the last time we got some contacts */
|
||||||
|
if (tstamp > ci.tstamp)
|
||||||
|
return;
|
||||||
|
/* (maybe) only include 'personal' contacts */
|
||||||
|
if (personal && !ci.personal)
|
||||||
|
return;
|
||||||
|
/* only include newer-than-x contacts */
|
||||||
|
if (after > ci.last_seen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Node::Seq contact;
|
||||||
|
contact.add_prop(":address", std::string{ci.full_address});
|
||||||
|
contact.add_prop(":rank", rank);
|
||||||
|
|
||||||
|
contacts.add(Node::make_list(std::move(contact)));
|
||||||
|
});
|
||||||
|
|
||||||
|
Node::Seq seq;
|
||||||
|
seq.add_prop(":contacts", std::move(contacts));
|
||||||
|
seq.add_prop(":tstamp", Node::make_string(format("%" G_GINT64_FORMAT,
|
||||||
|
g_get_monotonic_time())));
|
||||||
|
|
||||||
/* dump the contacts cache as a giant sexp */
|
/* dump the contacts cache as a giant sexp */
|
||||||
print_expr(contacts_to_sexp (contacts, personal, after, tstamp));
|
print_expr(std::move(seq));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
save_part (MuMsg *msg, unsigned docid, unsigned index,
|
save_part (MuMsg *msg, unsigned docid, unsigned index,
|
||||||
MuMsgOptions opts, const Parameters& params)
|
MuMsgOptions opts, const Parameters& params)
|
||||||
|
@ -572,7 +534,7 @@ extract_handler (Context& context, const Parameters& params)
|
||||||
const auto opts{message_options(params)};
|
const auto opts{message_options(params)};
|
||||||
|
|
||||||
GError *gerr{};
|
GError *gerr{};
|
||||||
auto msg{mu_store_get_msg (context.store, docid, &gerr)};
|
auto msg{context.store().find_message(docid)};
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error{Error::Code::Store, "failed to get message"};
|
throw Error{Error::Code::Store, "failed to get message"};
|
||||||
|
|
||||||
|
@ -633,12 +595,11 @@ docids_for_msgid (MuQuery *query, const std::string& msgid, size_t max=100)
|
||||||
* mu_store_get_path could be added if this turns out to be a problem
|
* mu_store_get_path could be added if this turns out to be a problem
|
||||||
*/
|
*/
|
||||||
static std::string
|
static std::string
|
||||||
path_from_docid (MuStore *store, unsigned docid)
|
path_from_docid (const Store& store, unsigned docid)
|
||||||
{
|
{
|
||||||
GError *gerr{};
|
auto msg{store.find_message(docid)};
|
||||||
auto msg{mu_store_get_msg (store, docid, &gerr)};
|
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error(Error::Code::Store, &gerr, "could not get message from store");
|
throw Error(Error::Code::Store, "could not get message from store");
|
||||||
|
|
||||||
auto p{mu_msg_get_path(msg)};
|
auto p{mu_msg_get_path(msg)};
|
||||||
if (!p) {
|
if (!p) {
|
||||||
|
@ -831,7 +792,10 @@ index_handler (Context& context, const Parameters& params)
|
||||||
GError *gerr{};
|
GError *gerr{};
|
||||||
const auto cleanup{get_bool_or(params, "cleanup")};
|
const auto cleanup{get_bool_or(params, "cleanup")};
|
||||||
const auto lazy_check{get_bool_or(params, "lazy-check")};
|
const auto lazy_check{get_bool_or(params, "lazy-check")};
|
||||||
auto index{mu_index_new (context.store, &gerr)};
|
|
||||||
|
auto store_ptr = reinterpret_cast<MuStore*>(&context.store());
|
||||||
|
|
||||||
|
auto index{mu_index_new (store_ptr, &gerr)};
|
||||||
if (!index)
|
if (!index)
|
||||||
throw Error(Error::Code::Index, &gerr, "failed to create index object");
|
throw Error(Error::Code::Index, &gerr, "failed to create index object");
|
||||||
|
|
||||||
|
@ -842,7 +806,7 @@ index_handler (Context& context, const Parameters& params)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
mu_index_destroy(index);
|
mu_index_destroy(index);
|
||||||
mu_store_flush(context.store);
|
mu_store_flush(store_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -880,14 +844,14 @@ get_flags (const std::string& path, const std::string& flagstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_move (MuStore *store, DocId docid, MuMsg *msg, const std::string& maildirarg,
|
do_move (Store& store, DocId docid, MuMsg *msg, const std::string& maildirarg,
|
||||||
MuFlags flags, bool new_name, bool no_view)
|
MuFlags flags, bool new_name, bool no_view)
|
||||||
{
|
{
|
||||||
bool different_mdir{};
|
bool different_mdir{};
|
||||||
auto maildir{maildirarg};
|
auto maildir{maildirarg};
|
||||||
if (maildir.empty()) {
|
if (maildir.empty()) {
|
||||||
maildir = mu_msg_get_maildir (msg);
|
maildir = mu_msg_get_maildir (msg);
|
||||||
different_mdir = FALSE;
|
different_mdir = false;
|
||||||
} else /* are we moving to a different mdir, or is it just flags? */
|
} else /* are we moving to a different mdir, or is it just flags? */
|
||||||
different_mdir = maildir != mu_msg_get_maildir(msg);
|
different_mdir = maildir != mu_msg_get_maildir(msg);
|
||||||
|
|
||||||
|
@ -897,37 +861,38 @@ do_move (MuStore *store, DocId docid, MuMsg *msg, const std::string& maildirarg,
|
||||||
|
|
||||||
/* after mu_msg_move_to_maildir, path will be the *new* path, and flags and maildir fields
|
/* after mu_msg_move_to_maildir, path will be the *new* path, and flags and maildir fields
|
||||||
* will be updated as wel */
|
* will be updated as wel */
|
||||||
auto rv = mu_store_update_msg (store, docid, msg, &gerr);
|
if (!store.update_message (msg, docid))
|
||||||
if (rv == MU_STORE_INVALID_DOCID)
|
throw Error{Error::Code::Store, "failed to store updated message"};
|
||||||
throw Error{Error::Code::Store, &gerr, "failed to store updated message"};
|
|
||||||
|
|
||||||
char *sexp = mu_msg_to_sexp (msg, docid, NULL, MU_MSG_OPTION_VERIFY);
|
Node::Seq seq;
|
||||||
|
seq.add_prop(":update", msg_to_sexp (msg, docid, NULL, MU_MSG_OPTION_VERIFY));
|
||||||
/* note, the :move t thing is a hint to the frontend that it
|
/* note, the :move t thing is a hint to the frontend that it
|
||||||
* could remove the particular header */
|
* could remove the particular header */
|
||||||
print_expr ("(:update %s :move %s :maybe-view %s)", sexp,
|
if (different_mdir)
|
||||||
different_mdir ? "t" : "nil",
|
seq.add_prop(":move", Node::make_symbol("t"));
|
||||||
no_view ? "nil" : "t");
|
if (!no_view)
|
||||||
g_free (sexp);
|
seq.add_prop(":maybe-view", Node::make_symbol("t"));
|
||||||
|
|
||||||
|
print_expr (std::move(seq));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
move_docid (MuStore *store, DocId docid, const std::string& flagstr,
|
move_docid (Store& store, DocId docid, const std::string& flagstr,
|
||||||
bool new_name, bool no_view)
|
bool new_name, bool no_view)
|
||||||
{
|
{
|
||||||
if (docid == MU_STORE_INVALID_DOCID)
|
if (docid == MU_STORE_INVALID_DOCID)
|
||||||
throw Error{Error::Code::InvalidArgument, "invalid docid"};
|
throw Error{Error::Code::InvalidArgument, "invalid docid"};
|
||||||
|
|
||||||
GError *gerr{};
|
auto msg{store.find_message(docid)};
|
||||||
auto msg{mu_store_get_msg (store, docid, &gerr)};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error{Error::Code::Store, &gerr, "failed to get message from store"};
|
throw Error{Error::Code::Store, "failed to get message from store"};
|
||||||
|
|
||||||
const auto flags = flagstr.empty() ? mu_msg_get_flags (msg) :
|
const auto flags = flagstr.empty() ? mu_msg_get_flags (msg) :
|
||||||
get_flags (mu_msg_get_path(msg), flagstr);
|
get_flags (mu_msg_get_path(msg), flagstr);
|
||||||
if (flags == MU_FLAG_INVALID)
|
if (flags == MU_FLAG_INVALID)
|
||||||
throw Error{Error::Code::InvalidArgument, "invalid flags '%s'", flagstr.c_str()};
|
throw Error{Error::Code::InvalidArgument, "invalid flags '%s'",
|
||||||
|
flagstr.c_str()};
|
||||||
|
|
||||||
do_move (store, docid, msg, "", flags, new_name, no_view);
|
do_move (store, docid, msg, "", flags, new_name, no_view);
|
||||||
|
|
||||||
|
@ -964,15 +929,16 @@ move_handler (Context& context, const Parameters& params)
|
||||||
"can't move multiple messages at the same time"};
|
"can't move multiple messages at the same time"};
|
||||||
// multi.
|
// multi.
|
||||||
for (auto&& docid: docids)
|
for (auto&& docid: docids)
|
||||||
move_docid(context.store, docid, flagstr, rename, no_view);
|
move_docid(context.store(), docid, flagstr, rename, no_view);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto docid{docids.at(0)};
|
auto docid{docids.at(0)};
|
||||||
|
|
||||||
GError *gerr{};
|
GError *gerr{};
|
||||||
auto msg{mu_store_get_msg(context.store, docid, &gerr)};
|
auto msg{context.store().find_message(docid)};
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error{Error::Code::InvalidArgument, &gerr, "could not create message"};
|
throw Error{Error::Code::InvalidArgument, &gerr,
|
||||||
|
"could not create message"};
|
||||||
|
|
||||||
/* if maildir was not specified, take the current one */
|
/* if maildir was not specified, take the current one */
|
||||||
if (maildir.empty())
|
if (maildir.empty())
|
||||||
|
@ -993,7 +959,8 @@ move_handler (Context& context, const Parameters& params)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
do_move (context.store, docid, msg, maildir, flags, rename, no_view);
|
do_move (context.store(), docid, msg, maildir, flags,
|
||||||
|
rename, no_view);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
mu_msg_unref(msg);
|
mu_msg_unref(msg);
|
||||||
throw;
|
throw;
|
||||||
|
@ -1005,10 +972,9 @@ move_handler (Context& context, const Parameters& params)
|
||||||
static void
|
static void
|
||||||
ping_handler (Context& context, const Parameters& params)
|
ping_handler (Context& context, const Parameters& params)
|
||||||
{
|
{
|
||||||
GError *gerr{};
|
const auto storecount{context.store().size()};
|
||||||
const auto storecount = mu_store_count(context.store, &gerr);
|
|
||||||
if (storecount == (unsigned)-1)
|
if (storecount == (unsigned)-1)
|
||||||
throw Error{Error::Code::Store, &gerr, "failed to read store"};
|
throw Error{Error::Code::Store, "failed to read store"};
|
||||||
|
|
||||||
const auto queries = get_string_vec (params, "queries");
|
const auto queries = get_string_vec (params, "queries");
|
||||||
Node::Seq qresults;
|
Node::Seq qresults;
|
||||||
|
@ -1026,13 +992,8 @@ ping_handler (Context& context, const Parameters& params)
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::Seq addrs;
|
Node::Seq addrs;
|
||||||
char **addrs_strv{mu_store_personal_addresses (context.store)};
|
for (auto&& addr: context.store().personal_addresses())
|
||||||
for (auto cur = addrs_strv; cur && *cur; ++cur)
|
addrs.add(std::string(addr));
|
||||||
addrs.add(*cur);
|
|
||||||
g_strfreev (addrs_strv);
|
|
||||||
|
|
||||||
const auto dbpath{mu_store_database_path(context.store)};
|
|
||||||
const auto root{mu_store_root_maildir(context.store)};
|
|
||||||
|
|
||||||
Node::Seq seq;
|
Node::Seq seq;
|
||||||
seq.add_prop(":pong", "mu");
|
seq.add_prop(":pong", "mu");
|
||||||
|
@ -1040,8 +1001,8 @@ ping_handler (Context& context, const Parameters& params)
|
||||||
Node::Seq propseq;
|
Node::Seq propseq;
|
||||||
propseq.add_prop(":version", VERSION);
|
propseq.add_prop(":version", VERSION);
|
||||||
propseq.add_prop(":personal-addresses", std::move(addrs));
|
propseq.add_prop(":personal-addresses", std::move(addrs));
|
||||||
propseq.add_prop(":database-path", dbpath);
|
propseq.add_prop(":database-path", context.store().database_path());
|
||||||
propseq.add_prop(":root-maildir", root);
|
propseq.add_prop(":root-maildir", context.store().root_maildir());
|
||||||
propseq.add_prop(":doccount", storecount);
|
propseq.add_prop(":doccount", storecount);
|
||||||
propseq.add_prop(":queries", std::move(qresults));
|
propseq.add_prop(":queries", std::move(qresults));
|
||||||
|
|
||||||
|
@ -1061,16 +1022,17 @@ static void
|
||||||
remove_handler (Context& context, const Parameters& params)
|
remove_handler (Context& context, const Parameters& params)
|
||||||
{
|
{
|
||||||
const auto docid{get_int_or(params, "docid")};
|
const auto docid{get_int_or(params, "docid")};
|
||||||
const auto path{path_from_docid (context.store, docid)};
|
const auto path{path_from_docid (context.store(), docid)};
|
||||||
|
|
||||||
if (::unlink (path.c_str()) != 0 && errno != ENOENT)
|
if (::unlink (path.c_str()) != 0 && errno != ENOENT)
|
||||||
throw Error(Error::Code::File, "could not delete %s: %s",
|
throw Error(Error::Code::File, "could not delete %s: %s",
|
||||||
path.c_str(), strerror (errno));
|
path.c_str(), strerror (errno));
|
||||||
|
|
||||||
if (!mu_store_remove_path (context.store, path.c_str()))
|
if (!context.store().remove_message (path))
|
||||||
throw Error(Error::Code::Store,
|
g_warning("failed to remove message @ %s (%d) from store",
|
||||||
"failed to remove message @ %s (%d) from store",
|
path.c_str(), docid);
|
||||||
path.c_str(), docid);
|
// act as if it worked.
|
||||||
|
|
||||||
Node::Seq seq;
|
Node::Seq seq;
|
||||||
seq.add_prop(":remove", docid);
|
seq.add_prop(":remove", docid);
|
||||||
|
|
||||||
|
@ -1081,11 +1043,10 @@ remove_handler (Context& context, const Parameters& params)
|
||||||
static void
|
static void
|
||||||
sent_handler (Context& context, const Parameters& params)
|
sent_handler (Context& context, const Parameters& params)
|
||||||
{
|
{
|
||||||
GError *gerr{};
|
|
||||||
const auto path{get_string_or(params, "path")};
|
const auto path{get_string_or(params, "path")};
|
||||||
const auto docid{mu_store_add_path(context.store, path.c_str(), &gerr)};
|
const auto docid{context.store().add_message(path)};
|
||||||
if (docid == MU_STORE_INVALID_DOCID)
|
if (docid == MU_STORE_INVALID_DOCID)
|
||||||
throw Error{Error::Code::Store, &gerr, "failed to add path"};
|
throw Error{Error::Code::Store, "failed to add path"};
|
||||||
|
|
||||||
Node::Seq seq;
|
Node::Seq seq;
|
||||||
seq.add_prop (":sent", Node::make_symbol("t"));
|
seq.add_prop (":sent", Node::make_symbol("t"));
|
||||||
|
@ -1095,12 +1056,40 @@ sent_handler (Context& context, const Parameters& params)
|
||||||
print_expr (std::move(seq));
|
print_expr (std::move(seq));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
maybe_mark_as_unread (MuMsg *msg, DocId docid)
|
||||||
|
{
|
||||||
|
g_debug ("%s", __func__);
|
||||||
|
|
||||||
|
if (!msg)
|
||||||
|
throw Error{Error::Code::Store, "missing message"};
|
||||||
|
if (docid == MU_STORE_INVALID_DOCID)
|
||||||
|
throw Error{Error::Code::Store, "invalid docid"};
|
||||||
|
|
||||||
|
const auto oldflags{mu_msg_get_flags (msg)};
|
||||||
|
const auto newflags{get_flags (mu_msg_get_path(msg), "+S-u-N")};
|
||||||
|
if (oldflags == newflags)
|
||||||
|
return; // nothing to do.
|
||||||
|
|
||||||
|
GError* gerr{};
|
||||||
|
if (!mu_msg_move_to_maildir (msg,
|
||||||
|
mu_msg_get_maildir (msg),
|
||||||
|
newflags,
|
||||||
|
TRUE,
|
||||||
|
FALSE,/*new_name,*/
|
||||||
|
&gerr))
|
||||||
|
throw Error{Error::Code::File, &gerr, "failed to move message"};
|
||||||
|
|
||||||
|
g_debug ("marked message %d as read => %s", docid, mu_msg_get_path(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
view_handler (Context& context, const Parameters& params)
|
view_handler (Context& context, const Parameters& params)
|
||||||
{
|
{
|
||||||
DocId docid{};
|
DocId docid{MU_STORE_INVALID_DOCID};
|
||||||
const auto path{get_string_or(params, "path")};
|
const auto path{get_string_or(params, "path")};
|
||||||
|
const auto mark_unread{get_bool_or(params, "mark-unread")};
|
||||||
|
|
||||||
GError *gerr{};
|
GError *gerr{};
|
||||||
MuMsg *msg{};
|
MuMsg *msg{};
|
||||||
|
@ -1109,11 +1098,14 @@ view_handler (Context& context, const Parameters& params)
|
||||||
msg = mu_msg_new_from_file (path.c_str(), NULL, &gerr);
|
msg = mu_msg_new_from_file (path.c_str(), NULL, &gerr);
|
||||||
else {
|
else {
|
||||||
docid = determine_docids(context.query, params).at(0);
|
docid = determine_docids(context.query, params).at(0);
|
||||||
msg = mu_store_get_msg (context.store, docid, &gerr);
|
msg = context.store().find_message(docid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!msg)
|
if (!msg)
|
||||||
throw Error{Error::Code::Store, &gerr, "failed to find message for view"};
|
throw Error{Error::Code::Store, &gerr,
|
||||||
|
"failed to find message for view"};
|
||||||
|
//if (mark_unread)
|
||||||
|
maybe_mark_as_unread (msg, docid);
|
||||||
|
|
||||||
Node::Seq seq;
|
Node::Seq seq;
|
||||||
seq.add_prop(":view", msg_to_sexp(msg, docid, {}, message_options(params)));
|
seq.add_prop(":view", msg_to_sexp(msg, docid, {}, message_options(params)));
|
||||||
|
@ -1141,7 +1133,8 @@ make_command_map (Context& context)
|
||||||
ArgMap{{"type", ArgInfo{Type::Symbol, true,
|
ArgMap{{"type", ArgInfo{Type::Symbol, true,
|
||||||
"type of composition: reply/forward/edit/resend/new"}},
|
"type of composition: reply/forward/edit/resend/new"}},
|
||||||
{"docid", ArgInfo{Type::Number, false,"document id of parent-message, if any"}},
|
{"docid", ArgInfo{Type::Number, false,"document id of parent-message, if any"}},
|
||||||
{"decrypt", ArgInfo{Type::Symbol, false, "whether to decrypt encrypted parts (if any)" }}},
|
{"decrypt", ArgInfo{Type::Symbol, false,
|
||||||
|
"whether to decrypt encrypted parts (if any)" }}},
|
||||||
"get contact information",
|
"get contact information",
|
||||||
[&](const auto& params){compose_handler(context, params);}});
|
[&](const auto& params){compose_handler(context, params);}});
|
||||||
|
|
||||||
|
@ -1214,6 +1207,7 @@ make_command_map (Context& context)
|
||||||
{"no-view", ArgInfo{Type::Symbol, false,
|
{"no-view", ArgInfo{Type::Symbol, false,
|
||||||
"if set, do not hint at updating the view"}},},
|
"if set, do not hint at updating the view"}},},
|
||||||
"move messages and/or change their flags",
|
"move messages and/or change their flags",
|
||||||
|
|
||||||
[&](const auto& params){move_handler(context, params);}});
|
[&](const auto& params){move_handler(context, params);}});
|
||||||
|
|
||||||
cmap.emplace("mkdir",
|
cmap.emplace("mkdir",
|
||||||
|
@ -1253,10 +1247,10 @@ make_command_map (Context& context)
|
||||||
|
|
||||||
cmap.emplace("view",
|
cmap.emplace("view",
|
||||||
CommandInfo{
|
CommandInfo{
|
||||||
ArgMap{{"docid", ArgInfo{Type::Number, false, "document-id"}},
|
ArgMap{{"docid", ArgInfo{Type::Number, false, "document-id"}},
|
||||||
{"msgid", ArgInfo{Type::String, false, "message-id"}},
|
{"msgid", ArgInfo{Type::String, false, "message-id"}},
|
||||||
{"path", ArgInfo{Type::String, false, "message filesystem path"}},
|
{"path", ArgInfo{Type::String, false, "message filesystem path"}},
|
||||||
|
{"mark-unread", ArgInfo{Type::String, false, "mark message as unread"}},
|
||||||
{"extract-images", ArgInfo{Type::Symbol, false,
|
{"extract-images", ArgInfo{Type::Symbol, false,
|
||||||
"whether to extract images for this messages (if any)"}},
|
"whether to extract images for this messages (if any)"}},
|
||||||
{"decrypt", ArgInfo{Type::Symbol, false,
|
{"decrypt", ArgInfo{Type::Symbol, false,
|
||||||
|
@ -1311,6 +1305,7 @@ mu_cmd_server (const MuConfig *opts, GError **err) try
|
||||||
|
|
||||||
} catch (const Error& er) {
|
} catch (const Error& er) {
|
||||||
std::cerr << ";; error: " << er.what() << "\n";
|
std::cerr << ";; error: " << er.what() << "\n";
|
||||||
|
g_warning ("error in server: %s", er.what());
|
||||||
print_error ((MuError)er.code(), "%s (line was:'%s')",
|
print_error ((MuError)er.code(), "%s (line was:'%s')",
|
||||||
er.what(), line.c_str());
|
er.what(), line.c_str());
|
||||||
}
|
}
|
||||||
|
@ -1320,9 +1315,11 @@ mu_cmd_server (const MuConfig *opts, GError **err) try
|
||||||
return MU_OK;
|
return MU_OK;
|
||||||
|
|
||||||
} catch (const Error& er) {
|
} catch (const Error& er) {
|
||||||
|
g_critical ("server caught exception: %s", er.what());
|
||||||
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", er.what());
|
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", er.what());
|
||||||
return MU_ERROR;
|
return MU_ERROR;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
g_critical ("server caught exception");
|
||||||
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", "caught exception");
|
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", "caught exception");
|
||||||
return MU_ERROR;
|
return MU_ERROR;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue