summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--guile/meson.build2
-rw-r--r--guile/mu-guile-message.cc182
-rw-r--r--guile/mu-guile.cc40
-rw-r--r--guile/mu-guile.hh2
-rw-r--r--guile/tests/meson.build3
-rw-r--r--guile/tests/test-mu-guile.cc77
-rw-r--r--lib/mu-script.cc2
-rw-r--r--meson.build7
8 files changed, 168 insertions, 147 deletions
diff --git a/guile/meson.build b/guile/meson.build
index b66a4ec..394ce15 100644
--- a/guile/meson.build
+++ b/guile/meson.build
@@ -28,7 +28,7 @@ compile_scm=configure_file(
run_command('chmod', '+x', compile_scm, check: true)
scm_compiler=join_paths(meson.current_build_dir(), 'compile-scm')
-snarf = find_program('guile-snarf')
+snarf = find_program('guile-snarf3.0','guile-snarf')
# there must be a better way of feeding the include paths to snarf...
snarf_args=['-o', '@OUTPUT@', '@INPUT@', '-I' + meson.current_source_dir() + '/..',
'-I' + meson.current_source_dir() + '/../lib',
diff --git a/guile/mu-guile-message.cc b/guile/mu-guile-message.cc
index 6ebcc34..e27fd78 100644
--- a/guile/mu-guile-message.cc
+++ b/guile/mu-guile-message.cc
@@ -17,11 +17,18 @@
**
*/
#include "mu-guile-message.hh"
+
+extern "C" {
#include "libguile/scm.h"
+#include "libguile/strings.h"
+}
+
#include "message/mu-message.hh"
+#include "utils/mu-utils.hh"
#include <config.h>
#include <glib-object.h>
+#include <memory>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
#include <libguile.h>
@@ -44,24 +51,51 @@ static std::array<SCM, AllMessageFlagInfos.size()> SYMB_FLAGS;
static SCM SYMB_CONTACT_TO, SYMB_CONTACT_CC, SYMB_CONTACT_BCC, SYMB_CONTACT_FROM;
static long MSG_TAG;
+
+using MessageSPtr = std::unique_ptr<Message>;
+
static gboolean
mu_guile_scm_is_msg(SCM scm)
{
return SCM_NIMP(scm) && (long)SCM_CAR(scm) == MSG_TAG;
}
-SCM
-mu_guile_msg_to_scm(Message&& msg)
+static SCM
+message_scm_create(Xapian::Document&& doc)
+{
+ /* placement-new */
+
+ void *scm_mem{scm_gc_malloc(sizeof(Message), "msg")};
+ Message* msgp = new(scm_mem)Message(std::move(doc));
+
+ SCM_RETURN_NEWSMOB(MSG_TAG, msgp);
+}
+
+static const Message*
+message_from_scm(SCM msg_smob)
{
- void *data{scm_gc_malloc(sizeof(Message), "msg")};
- auto msgptr = reinterpret_cast<MuMsgWrapper*>(
- scm_gc_malloc(sizeof(MuMsgWrapper), "msg"));
- msgwrap->_msg = std::move(msg);
- msgwrap->_unrefme = false;
+ return reinterpret_cast<Message*>(SCM_CDR(msg_smob));
+}
- SCM_RETURN_NEWSMOB(MSG_TAG,
+static size_t
+message_scm_free(SCM msg_smob)
+{
+ if (auto msg = message_from_scm(msg_smob); msg)
+ msg->~Message();
- msgwrap);
+ return sizeof(Message);
+}
+
+static int
+message_scm_print(SCM msg_smob, SCM port, scm_print_state* pstate)
+{
+ scm_puts("#<msg ", port);
+
+ if (auto msg = message_from_scm(msg_smob); msg)
+ scm_puts(msg->path().c_str(), port);
+
+ scm_puts(">", port);
+ return 1;
}
struct FlagData {
@@ -122,6 +156,13 @@ msg_string_list_field(const Message& msg, Field::Id field_id)
}
static SCM
+msg_contact_list_field(const Message& msg, Field::Id field_id)
+{
+ return scm_from_utf8_string(
+ to_string(msg.document().contacts_value(field_id)).c_str());
+}
+
+static SCM
get_body(const Message& msg, bool html)
{
if (const auto body = html ? msg.body_html() : msg.body_text(); body)
@@ -139,46 +180,37 @@ SCM_DEFINE(get_field,
"Get the field FIELD from message MSG.\n")
#define FUNC_NAME s_get_field
{
- MuMsgWrapper* msgwrap;
- size_t field_id;
- msgwrap = (MuMsgWrapper*)SCM_CDR(MSG);
- const auto& msg{msgwrap->_msg};
-
- MU_GUILE_INITIALIZED_OR_ERROR;
-
SCM_ASSERT(mu_guile_scm_is_msg(MSG), MSG, SCM_ARG1, FUNC_NAME);
- SCM_ASSERT(scm_integer_p(FIELD), FIELD, SCM_ARG2, FUNC_NAME);
+ auto msg{message_from_scm(MSG)};
+ SCM_ASSERT(msg, MSG, SCM_ARG1, FUNC_NAME);
- field_id = scm_to_int(FIELD);
- if (field_id == MU_GUILE_MSG_FIELD_ID_TIMESTAMP)
- return scm_from_uint((unsigned)msgwrap->_msg.date());
-
- const auto field_opt{field_from_number(static_cast<size_t>(field_id))};
+ SCM_ASSERT(scm_integer_p(FIELD), FIELD, SCM_ARG2, FUNC_NAME);
+ const auto field_opt{field_from_number(static_cast<size_t>(scm_to_int(FIELD)))};
SCM_ASSERT(!!field_opt, FIELD, SCM_ARG2, FUNC_NAME);
switch (field_opt->id) {
case Field::Id::Priority:
- return get_prio_scm(msg);
+ return get_prio_scm(*msg);
case Field::Id::Flags:
- return get_flags_scm(msg);
- case Field::Id::BodyHtml:
- return get_body(msg, true);
+ return get_flags_scm(*msg);
case Field::Id::BodyText:
- return get_body(msg, false);
-
+ return get_body(*msg, false);
default: break;
}
switch (field_opt->type) {
case Field::Type::String:
- return mu_guile_scm_from_string(msg.document().string_value(field_opt->id));
+ return mu_guile_scm_from_string(msg->document().string_value(field_opt->id));
case Field::Type::ByteSize:
case Field::Type::TimeT:
case Field::Type::Integer:
- return scm_from_uint(msg.document().integer_value(field_opt->id));
+ return scm_from_uint(msg->document().integer_value(field_opt->id));
case Field::Type::StringList:
- return msg_string_list_field(msg, field_opt->id);
- default: SCM_ASSERT(0, FIELD, SCM_ARG2, FUNC_NAME);
+ return msg_string_list_field(*msg, field_opt->id);
+ case Field::Type::ContactList:
+ return msg_contact_list_field(*msg, field_opt->id);
+ default:
+ SCM_ASSERT(0, FIELD, SCM_ARG2, FUNC_NAME);
}
}
#undef FUNC_NAME
@@ -211,13 +243,14 @@ SCM_DEFINE(get_contacts,
"Get a list of contact information pairs.\n")
#define FUNC_NAME s_get_contacts
{
- MuMsgWrapper* msgwrap;
- SCM list;
-
+ SCM list;
MU_GUILE_INITIALIZED_OR_ERROR;
SCM_ASSERT(mu_guile_scm_is_msg(MSG), MSG, SCM_ARG1, FUNC_NAME);
+ auto msg{message_from_scm(MSG)};
+ SCM_ASSERT(msg, MSG, SCM_ARG1, FUNC_NAME);
+
SCM_ASSERT(scm_symbol_p(CONTACT_TYPE) || scm_is_bool(CONTACT_TYPE),
CONTACT_TYPE,
SCM_ARG2,
@@ -244,11 +277,9 @@ SCM_DEFINE(get_contacts,
}
}
- msgwrap = (MuMsgWrapper*)SCM_CDR(MSG);
-
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
- list = contacts_to_list(msgwrap->_msg, field_id);
+ list = contacts_to_list(*msg, field_id);
#pragma GCC diagnostic pop
/* explicitly close the file backend, so we won't run out of fds */
@@ -269,19 +300,18 @@ SCM_DEFINE(get_parts,
"elements which are list of the form (index name mime-type size).\n")
#define FUNC_NAME s_get_parts
{
- MuMsgWrapper* msgwrap;
-
MU_GUILE_INITIALIZED_OR_ERROR;
SCM_ASSERT(mu_guile_scm_is_msg(MSG), MSG, SCM_ARG1, FUNC_NAME);
+ auto msg{message_from_scm(MSG)};
+ SCM_ASSERT(msg, MSG, SCM_ARG1, FUNC_NAME);
SCM_ASSERT(scm_is_bool(ATTS_ONLY), ATTS_ONLY, SCM_ARG2, FUNC_NAME);
SCM attlist = SCM_EOL; /* empty list */
bool attachments_only = ATTS_ONLY == SCM_BOOL_T ? TRUE : FALSE;
- const Message& msg{reinterpret_cast<MuMsgWrapper*>(SCM_CDR(MSG))->_msg};
size_t n{};
- for (auto&& part: msg.parts()) {
+ for (auto&& part: msg->parts()) {
if (attachments_only && !part.is_attachment())
continue;
@@ -291,7 +321,7 @@ SCM_DEFINE(get_parts,
SCM elm = scm_list_5(
/* msg */
- mu_guile_scm_from_string(msgwrap->_msg.path()),
+ mu_guile_scm_from_string(msg->path().c_str()),
/* index */
scm_from_uint(n++),
/* filename or #f */
@@ -305,7 +335,7 @@ SCM_DEFINE(get_parts,
}
/* explicitly close the file backend, so we won't run of fds */
- msg.unload_mime_message();
+ msg->unload_mime_message();
return attlist;
}
@@ -323,27 +353,21 @@ SCM_DEFINE(get_header,
MU_GUILE_INITIALIZED_OR_ERROR;
SCM_ASSERT(mu_guile_scm_is_msg(MSG), MSG, SCM_ARG1, FUNC_NAME);
- SCM_ASSERT(scm_is_string(HEADER) || HEADER == SCM_UNDEFINED, HEADER, SCM_ARG2, FUNC_NAME);
+ auto msg{message_from_scm(MSG)};
+ SCM_ASSERT(msg, MSG, SCM_ARG1, FUNC_NAME);
- const Message& msg{reinterpret_cast<MuMsgWrapper*>(SCM_CDR(MSG))->_msg};
+ SCM_ASSERT(scm_is_string(HEADER) || HEADER == SCM_UNDEFINED, HEADER, SCM_ARG2, FUNC_NAME);
char *header = scm_to_utf8_string(HEADER);
- SCM val = mu_guile_scm_from_string(msg.header(header).value_or(""));
+ SCM val = mu_guile_scm_from_string(msg->header(header).value_or(""));
free(header);
/* explicitly close the file backend, so we won't run of fds */
- msg.unload_mime_message();
+ msg->unload_mime_message();
return val;
}
#undef FUNC_NAME
-
-static Mu::Option<Mu::QueryResults>
-get_query_results(Mu::Store& store, const char* expr, int maxnum)
-{
- return store.run_query(expr, {}, Mu::QueryFlags::None, maxnum);
-}
-
SCM_DEFINE(for_each_message,
"mu:c:for-each-message",
3,
@@ -369,19 +393,18 @@ SCM_DEFINE(for_each_message,
return SCM_UNSPECIFIED; /* nothing to do */
if (EXPR == SCM_BOOL_T)
- expr = strdup(""); /* note, "" matches *all* messages */
+ expr = strdup("\"\""); /* note, "" matches *all* messages */
else
expr = scm_to_utf8_string(EXPR);
- const auto res{get_query_results(mu_guile_store(), expr, scm_to_int(MAXNUM))};
+ const auto res = mu_guile_store().run_query(expr,{}, {}, scm_to_int(MAXNUM));
free(expr);
if (!res)
return SCM_UNSPECIFIED;
for (auto&& mi : *res) {
- if (auto msg{mi.message()}; msg) {
- auto msgsmob{mu_guile_msg_to_scm(std::move(msg.value()))};
- scm_call_1(FUNC, msgsmob);
+ if (auto xdoc{mi.document()}; xdoc) {
+ scm_call_1(FUNC, message_scm_create(std::move(xdoc.value())));
}
}
@@ -423,7 +446,8 @@ static void
define_vars(void)
{
field_for_each([](auto&& field){
- const auto name{"mu:field:" + std::string{field.name}};
+ const auto name{"mu:field:" +
+ std::string{field.alias.empty() ? field.name : field.alias}};
scm_c_define(name.c_str(), scm_from_uint(field.value_no()));
scm_c_export(name.c_str(), NULL);
});
@@ -435,43 +459,13 @@ define_vars(void)
}
-static size_t
-msg_free(SCM msg_smob)
-{
- MuMsgWrapper* msgwrap;
- msgwrap = (MuMsgWrapper*)SCM_CDR(msg_smob);
-
- if (msgwrap->_unrefme)
- mu_msg_unref(msgwrap->_msg);
-
- return sizeof(MuMsgWrapper);
-}
-
-static int
-msg_print(SCM msg_smob, SCM port, scm_print_state* pstate)
-{
- MuMsgWrapper* msgwrap;
- msgwrap = (MuMsgWrapper*)SCM_CDR(msg_smob);
-
- scm_puts("#<msg ", port);
-
- if (msg_smob == SCM_BOOL_F)
- scm_puts("#f", port);
- else
- scm_puts(mu_msg_get_path(msgwrap->_msg), port);
-
- scm_puts(">", port);
-
- return 1;
-}
-
void*
mu_guile_message_init(void* data)
{
- MSG_TAG = scm_make_smob_type("msg", sizeof(MuMsgWrapper));
+ MSG_TAG = scm_make_smob_type("message", sizeof(Message));
- scm_set_smob_free(MSG_TAG, msg_free);
- scm_set_smob_print(MSG_TAG, msg_print);
+ scm_set_smob_free(MSG_TAG, message_scm_free);
+ scm_set_smob_print(MSG_TAG, message_scm_print);
define_vars();
define_symbols();
diff --git a/guile/mu-guile.cc b/guile/mu-guile.cc
index 2927b6d..3da8eb3 100644
--- a/guile/mu-guile.cc
+++ b/guile/mu-guile.cc
@@ -23,9 +23,12 @@
#include <locale.h>
#include <glib-object.h>
+
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
+extern "C" {
#include <libguile.h>
+}
#pragma GCC diagnostic pop
#include <mu-runtime.hh>
@@ -71,26 +74,42 @@ mu_guile_g_error(const char* func_name, GError* err)
/* there can be only one */
-static std::unique_ptr<Mu::Store> StoreSingleton;
+static Option<Mu::Store> StoreSingleton = Nothing;
-static gboolean
+static bool
mu_guile_init_instance(const char* muhome)
try {
setlocale(LC_ALL, "");
if (!mu_runtime_init(muhome, "guile", true) || StoreSingleton)
return FALSE;
- StoreSingleton = std::make_unique<Mu::Store>(mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB));
+ const auto path{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB)};
+ auto store = Store::make(path);
+ if (!store) {
+ g_critical("error creating store @ %s: %s", path, store.error().what());
+ throw store.error();
+ } else
+ StoreSingleton.emplace(std::move(store.value()));
g_debug("mu-guile: opened store @ %s (n=%zu); maildir: %s",
StoreSingleton->properties().database_path.c_str(),
StoreSingleton->size(),
StoreSingleton->properties().root_maildir.c_str());
- return TRUE;
-
+ return true;
+
+} catch (const Xapian::Error& xerr) {
+ g_critical("%s: xapian error '%s'", __func__, xerr.get_msg().c_str());
+ return false;
+} catch (const std::runtime_error& re) {
+ g_critical("%s: error: %s", __func__, re.what());
+ return false;
+} catch (const std::exception& e) {
+ g_critical("%s: caught exception: %s", __func__, e.what());
+ return false;
} catch (...) {
- return FALSE;
+ g_critical("%s: caught exception", __func__);
+ return false;
}
static void
@@ -107,7 +126,7 @@ mu_guile_store()
if (!StoreSingleton)
g_error("mu guile not initialized");
- return *StoreSingleton.get();
+ return StoreSingleton.value();
}
gboolean
@@ -131,7 +150,6 @@ SCM_DEFINE_PUBLIC(mu_initialize,
#define FUNC_NAME s_mu_initialize
{
char* muhome;
- gboolean rv;
SCM_ASSERT(scm_is_string(MUHOME) || MUHOME == SCM_BOOL_F || SCM_UNBNDP(MUHOME),
MUHOME,
@@ -146,14 +164,12 @@ SCM_DEFINE_PUBLIC(mu_initialize,
else
muhome = scm_to_utf8_string(MUHOME);
- rv = mu_guile_init_instance(muhome);
- if (!rv) {
+ if (!mu_guile_init_instance(muhome)) {
free(muhome);
mu_guile_error(FUNC_NAME, 0, "Failed to initialize mu", SCM_UNSPECIFIED);
}
- g_debug("mu-guile: initialized @ %s (%p)",
- muhome ? muhome : "<default>", StoreSingleton.get());
+ g_debug("mu-guile: initialized @ %s", muhome ? muhome : "<default>");
free(muhome);
/* cleanup when we're exiting */
diff --git a/guile/mu-guile.hh b/guile/mu-guile.hh
index 6265995..ea886a2 100644
--- a/guile/mu-guile.hh
+++ b/guile/mu-guile.hh
@@ -21,7 +21,9 @@
#define __MU_GUILE_H__
#include <glib.h>
+extern "C" {
#include <libguile.h>
+}
#include <mu-query.hh>
/**
diff --git a/guile/tests/meson.build b/guile/tests/meson.build
index 1242638..7cb61f5 100644
--- a/guile/tests/meson.build
+++ b/guile/tests/meson.build
@@ -25,6 +25,7 @@ test('test-mu-guile',
install: false,
cpp_args: [
'-DABS_SRCDIR="' + meson.current_source_dir() + '"',
- '-DGUILE_LOAD_PATH="' + guile_load_path + '"'
+ '-DGUILE_LOAD_PATH="' + guile_load_path + '"',
+ '-DGUILE_EXTENSIONS_PATH="' + guile_load_path + '"'
],
dependencies: [glib_dep, lib_mu_dep, lib_test_mu_common_dep]))
diff --git a/guile/tests/test-mu-guile.cc b/guile/tests/test-mu-guile.cc
index c0e145b..b7172bf 100644
--- a/guile/tests/test-mu-guile.cc
+++ b/guile/tests/test-mu-guile.cc
@@ -29,64 +29,66 @@
#include "test-mu-common.hh"
#include <lib/mu-store.hh>
+#include <utils/mu-utils.hh>
-/* Tests For The command line interface, uses testdir2 */
+using namespace Mu;
-static gchar*
+static std::string test_dir;
+
+static std::string
fill_database(void)
{
- gchar * cmdline, *tmpdir;
- GError* err;
-
- tmpdir = test_mu_common_get_random_tmpdir();
- cmdline = g_strdup_printf("/bin/sh -c '"
- "%s init --muhome=%s --maildir=%s --quiet; "
- "%s index --muhome=%s --quiet'",
- MU_PROGRAM,
- tmpdir,
- MU_TESTMAILDIR2,
- MU_PROGRAM,
- tmpdir);
+ const auto cmdline = format(
+ "/bin/sh -c '"
+ "%s init --muhome=%s --maildir=%s --quiet; "
+ "%s index --muhome=%s --quiet'",
+ MU_PROGRAM,
+ test_dir.c_str(),
+ MU_TESTMAILDIR2,
+ MU_PROGRAM,
+ test_dir.c_str());
if (g_test_verbose())
- g_print("%s\n", cmdline);
+ g_print("%s\n", cmdline.c_str());
- err = NULL;
- if (!g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, &err)) {
+ GError *err{};
+ if (!g_spawn_command_line_sync(cmdline.c_str(), NULL, NULL, NULL, &err)) {
g_printerr("Error: %s\n", err ? err->message : "?");
+ g_clear_error(&err);
g_assert(0);
}
- g_free(cmdline);
- return tmpdir;
+ return test_dir;
}
static void
test_something(const char* what)
{
- char *dir, *cmdline;
- gint result;
-
-
g_setenv("GUILE_AUTO_COMPILE", "0", TRUE);
g_setenv("GUILE_LOAD_PATH", GUILE_LOAD_PATH, TRUE);
-
- dir = fill_database();
- cmdline = g_strdup_printf("%s -q -e main %s/test-mu-guile.scm "
- "--muhome=%s --test=%s",
- GUILE_BINARY,
- ABS_SRCDIR,
- dir,
- what);
+ g_setenv("GUILE_EXTENSIONS_PATH",GUILE_EXTENSIONS_PATH, TRUE);
if (g_test_verbose())
- g_print("cmdline: %s\n", cmdline);
+ g_print("GUILE_LOAD_PATH: %s\n", GUILE_LOAD_PATH);
- result = system(cmdline);
- g_assert(result == 0);
+ const auto dir = fill_database();
+ const auto cmdline = format("%s -q -e main %s/test-mu-guile.scm "
+ "--muhome=%s --test=%s",
+ GUILE_BINARY,
+ ABS_SRCDIR,
+ dir.c_str(), what);
- g_free(dir);
- g_free(cmdline);
+ if (g_test_verbose())
+ g_print("cmdline: %s\n", cmdline.c_str());
+
+ GError *err{};
+ int status{};
+ if (!g_spawn_command_line_sync(cmdline.c_str(), NULL, NULL, &status, &err) ||
+ status != 0) {
+ g_printerr("Error: %s\n", err ? err->message : "something went wrong");
+ g_clear_error(&err);
+ g_assert(0);
+ }
}
static void
@@ -111,6 +113,9 @@ int
main(int argc, char* argv[])
{
int rv;
+ TempDir tempdir;
+ test_dir = tempdir.path();
+
g_test_init(&argc, &argv, NULL);
if (!set_en_us_utf8_locale())
diff --git a/lib/mu-script.cc b/lib/mu-script.cc
index 02e3830..ccecf17 100644
--- a/lib/mu-script.cc
+++ b/lib/mu-script.cc
@@ -23,7 +23,9 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wredundant-decls"
+extern "C" {
#include <libguile.h>
+}
#pragma GCC diagnostic pop
#endif /*BUILD_GUILE*/
diff --git a/meson.build b/meson.build
index 43d7701..48d382d 100644
--- a/meson.build
+++ b/meson.build
@@ -179,9 +179,10 @@ endif
if not get_option('guile').disabled() and guile_dep.found()
config_h_data.set('BUILD_GUILE', 1)
- config_h_data.set_quoted('GUILE_BINARY', 'guile')
- message('guile is disabled for now')
- #subdir('guile')
+ config_h_data.set_quoted('GUILE_BINARY',
+ guile_dep.get_pkgconfig_variable('guile'))
+ #message('guile is disabled for now')
+ subdir('guile')
endif
config_h_data.set_quoted('MU_PROGRAM', mu.full_path())