clang-format: update c/cc coding style

Update all cc code using .clang-format; please do so as well for future PRs
etc.; emacs has a handy 'clang-format' mode to make this automatic.

For comparing old changes with git blame, we can disregard this one using
--ignore-rev

(see https://www.moxio.com/blog/43/ignoring-bulk-change-commits-with-git-blame )
This commit is contained in:
Dirk-Jan C. Binnema
2021-10-20 12:18:15 +03:00
parent 09935cc4b3
commit 3dd721d5a3
111 changed files with 13851 additions and 14579 deletions

View File

@ -47,16 +47,16 @@ using namespace Mu;
* g_free)
*/
static gchar*
guess_last_name (const char *name)
guess_last_name(const char* name)
{
const gchar *lastsp;
const gchar* lastsp;
if (!name)
return g_strdup ("");
if (!name)
return g_strdup("");
lastsp = g_strrstr (name, " ");
lastsp = g_strrstr(name, " ");
return g_strdup (lastsp ? lastsp + 1 : "");
return g_strdup(lastsp ? lastsp + 1 : "");
}
/**
@ -69,19 +69,19 @@ guess_last_name (const char *name)
* g_free)
*/
static gchar*
guess_first_name (const char *name)
guess_first_name(const char* name)
{
const gchar *lastsp;
const gchar* lastsp;
if (!name)
return g_strdup ("");
if (!name)
return g_strdup("");
lastsp = g_strrstr (name, " ");
lastsp = g_strrstr(name, " ");
if (lastsp)
return g_strndup (name, lastsp - name);
else
return g_strdup (name);
if (lastsp)
return g_strndup(name, lastsp - name);
else
return g_strdup(name);
}
/**
@ -95,336 +95,322 @@ guess_first_name (const char *name)
* @return the guessed nick, as a newly allocated string (free with g_free)
*/
static gchar*
cleanup_str (const char* str)
cleanup_str(const char* str)
{
gchar *s;
const gchar *cur;
unsigned i;
gchar* s;
const gchar* cur;
unsigned i;
if (mu_str_is_empty(str))
return g_strdup ("");
if (mu_str_is_empty(str))
return g_strdup("");
s = g_new0 (char, strlen(str) + 1);
s = g_new0(char, strlen(str) + 1);
for (cur = str, i = 0; *cur; ++cur) {
if (ispunct(*cur) || isspace(*cur))
continue;
else
s[i++] = *cur;
}
for (cur = str, i = 0; *cur; ++cur) {
if (ispunct(*cur) || isspace(*cur))
continue;
else
s[i++] = *cur;
}
return s;
return s;
}
static char*
uniquify_nick (const char *nick, GHashTable *nicks)
uniquify_nick(const char* nick, GHashTable* nicks)
{
guint u;
guint u;
for (u = 2; u != 1000; ++u) {
char *cand;
cand = g_strdup_printf ("%s%u", nick, u);
if (!g_hash_table_contains (nicks, cand))
return cand;
}
for (u = 2; u != 1000; ++u) {
char* cand;
cand = g_strdup_printf("%s%u", nick, u);
if (!g_hash_table_contains(nicks, cand))
return cand;
}
return g_strdup (nick); /* if all else fails */
return g_strdup(nick); /* if all else fails */
}
static gchar*
guess_nick (const char* name, GHashTable *nicks)
guess_nick(const char* name, GHashTable* nicks)
{
gchar *fname, *lname, *nick;
gchar initial[7];
gchar *fname, *lname, *nick;
gchar initial[7];
fname = guess_first_name (name);
lname = guess_last_name (name);
fname = guess_first_name(name);
lname = guess_last_name(name);
/* if there's no last name, use first name as the nick */
if (mu_str_is_empty(fname) || mu_str_is_empty(lname)) {
g_free (lname);
nick = fname;
goto leave;
}
/* if there's no last name, use first name as the nick */
if (mu_str_is_empty(fname) || mu_str_is_empty(lname)) {
g_free(lname);
nick = fname;
goto leave;
}
memset (initial, 0, sizeof(initial));
/* couldn't we get an initial for the last name? */
if (g_unichar_to_utf8 (g_utf8_get_char (lname), initial) == 0) {
g_free (lname);
nick = fname;
goto leave;
}
memset(initial, 0, sizeof(initial));
/* couldn't we get an initial for the last name? */
if (g_unichar_to_utf8(g_utf8_get_char(lname), initial) == 0) {
g_free(lname);
nick = fname;
goto leave;
}
nick = g_strdup_printf ("%s%s", fname, initial);
g_free (fname);
g_free (lname);
nick = g_strdup_printf("%s%s", fname, initial);
g_free(fname);
g_free(lname);
leave:
{
gchar *tmp;
tmp = cleanup_str (nick);
g_free (nick);
nick = tmp;
}
leave : {
gchar* tmp;
tmp = cleanup_str(nick);
g_free(nick);
nick = tmp;
}
if (g_hash_table_contains (nicks, nick)) {
char *tmp;
tmp = uniquify_nick (nick, nicks);
g_free (nick);
nick = tmp;
}
if (g_hash_table_contains(nicks, nick)) {
char* tmp;
tmp = uniquify_nick(nick, nicks);
g_free(nick);
nick = tmp;
}
g_hash_table_add (nicks, g_strdup(nick));
g_hash_table_add(nicks, g_strdup(nick));
return nick;
return nick;
}
static void
print_header (const MuConfigFormat format)
print_header(const MuConfigFormat format)
{
switch (format) {
case MU_CONFIG_FORMAT_BBDB:
g_print (";; -*-coding: utf-8-emacs;-*-\n"
";;; file-version: 6\n");
break;
case MU_CONFIG_FORMAT_MUTT_AB:
g_print ("Matching addresses in the mu database:\n");
break;
default:
break;
}
switch (format) {
case MU_CONFIG_FORMAT_BBDB:
g_print(";; -*-coding: utf-8-emacs;-*-\n"
";;; file-version: 6\n");
break;
case MU_CONFIG_FORMAT_MUTT_AB: g_print("Matching addresses in the mu database:\n"); break;
default: break;
}
}
static void
each_contact_bbdb (const std::string& email, const std::string& name, time_t tstamp)
each_contact_bbdb(const std::string& email, const std::string& name, time_t tstamp)
{
char *fname, *lname, *now, *timestamp;
char *fname, *lname, *now, *timestamp;
fname = guess_first_name (name.c_str());
lname = guess_last_name (name.c_str());
now = mu_date_str ("%Y-%m-%d", time(NULL));
timestamp = mu_date_str ("%Y-%m-%d", tstamp);
fname = guess_first_name(name.c_str());
lname = guess_last_name(name.c_str());
now = mu_date_str("%Y-%m-%d", time(NULL));
timestamp = mu_date_str("%Y-%m-%d", tstamp);
g_print ("[\"%s\" \"%s\" nil nil nil nil (\"%s\") "
"((creation-date . \"%s\") (time-stamp . \"%s\")) nil]\n",
fname, lname, email.c_str(), now, timestamp);
g_print("[\"%s\" \"%s\" nil nil nil nil (\"%s\") "
"((creation-date . \"%s\") (time-stamp . \"%s\")) nil]\n",
fname,
lname,
email.c_str(),
now,
timestamp);
g_free (now);
g_free (timestamp);
g_free (fname);
g_free (lname);
}
static void
each_contact_mutt_alias (const std::string& email, const std::string& name,
GHashTable *nicks)
{
if (name.empty())
return;
char *nick = guess_nick (name.c_str(), nicks);
mu_util_print_encoded ("alias %s %s <%s>\n",
nick, name.c_str(), email.c_str());
g_free (nick);
}
static void
each_contact_wl (const std::string& email, const std::string& name, GHashTable *nicks)
{
if (name.empty())
return;
char *nick = guess_nick (name.c_str(), nicks);
mu_util_print_encoded ("%s \"%s\" \"%s\"\n", email.c_str(), nick, name.c_str());
g_free (nick);
g_free(now);
g_free(timestamp);
g_free(fname);
g_free(lname);
}
static void
print_plain (const std::string& email, const std::string& name, bool color)
each_contact_mutt_alias(const std::string& email, const std::string& name, GHashTable* nicks)
{
if (!name.empty()) {
if (color)
::fputs (MU_COLOR_MAGENTA, stdout);
mu_util_fputs_encoded (name.c_str(), stdout);
::fputs (" ", stdout);
}
if (name.empty())
return;
if (color)
::fputs (MU_COLOR_GREEN, stdout);
char* nick = guess_nick(name.c_str(), nicks);
mu_util_print_encoded("alias %s %s <%s>\n", nick, name.c_str(), email.c_str());
g_free(nick);
}
mu_util_fputs_encoded (email.c_str(), stdout);
static void
each_contact_wl(const std::string& email, const std::string& name, GHashTable* nicks)
{
if (name.empty())
return;
if (color)
fputs (MU_COLOR_DEFAULT, stdout);
char* nick = guess_nick(name.c_str(), nicks);
mu_util_print_encoded("%s \"%s\" \"%s\"\n", email.c_str(), nick, name.c_str());
g_free(nick);
}
fputs ("\n", stdout);
static void
print_plain(const std::string& email, const std::string& name, bool color)
{
if (!name.empty()) {
if (color)
::fputs(MU_COLOR_MAGENTA, stdout);
mu_util_fputs_encoded(name.c_str(), stdout);
::fputs(" ", stdout);
}
if (color)
::fputs(MU_COLOR_GREEN, stdout);
mu_util_fputs_encoded(email.c_str(), stdout);
if (color)
fputs(MU_COLOR_DEFAULT, stdout);
fputs("\n", stdout);
}
struct ECData {
MuConfigFormat format;
gboolean color, personal;
time_t after;
GRegex *rx;
GHashTable *nicks;
size_t n;
MuConfigFormat format;
gboolean color, personal;
time_t after;
GRegex* rx;
GHashTable* nicks;
size_t n;
};
static void
each_contact (const Mu::ContactInfo& ci, ECData& ecdata)
each_contact(const Mu::ContactInfo& ci, ECData& ecdata)
{
if (ecdata.personal && ci.personal)
return;
if (ecdata.personal && ci.personal)
return;
if (ci.tstamp < ecdata.after)
return;
if (ci.tstamp < ecdata.after)
return;
if (ecdata.rx &&
!g_regex_match (ecdata.rx, ci.email.c_str(), (GRegexMatchFlags)0, NULL) &&
!g_regex_match (ecdata.rx, ci.name.empty() ? "" : ci.name.c_str(), (GRegexMatchFlags)0, NULL))
return;
if (ecdata.rx && !g_regex_match(ecdata.rx, ci.email.c_str(), (GRegexMatchFlags)0, NULL) &&
!g_regex_match(ecdata.rx,
ci.name.empty() ? "" : ci.name.c_str(),
(GRegexMatchFlags)0,
NULL))
return;
++ecdata.n;
++ecdata.n;
switch (ecdata.format) {
case MU_CONFIG_FORMAT_MUTT_ALIAS:
each_contact_mutt_alias (ci.email, ci.name, ecdata.nicks);
break;
case MU_CONFIG_FORMAT_MUTT_AB:
mu_util_print_encoded ("%s\t%s\t\n",
ci.email.c_str(), ci.name.c_str());
break;
case MU_CONFIG_FORMAT_WL:
each_contact_wl (ci.email, ci.name, ecdata.nicks);
break;
case MU_CONFIG_FORMAT_ORG_CONTACT:
if (!ci.name.empty())
mu_util_print_encoded("* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n",
ci.name.c_str(), ci.email.c_str());
break;
case MU_CONFIG_FORMAT_BBDB:
each_contact_bbdb (ci.email, ci.name, ci.last_seen);
break;
case MU_CONFIG_FORMAT_CSV:
mu_util_print_encoded("%s,%s\n",
ci.name.empty() ? "" : Mu::quote(ci.name).c_str(),
Mu::quote(ci.email).c_str());
break;
case MU_CONFIG_FORMAT_DEBUG: {
char datebuf[32];
strftime(datebuf, sizeof(datebuf), "%F %T",
gmtime(&ci.last_seen));
g_print ("%s\n\tname: %s\n\t%s\n\tpersonal: %s\n\tfreq: %zu\n"
"\tlast-seen: %s\n",
ci.email.c_str(),
ci.name.empty() ? "<none>" : ci.name.c_str(),
ci.full_address.c_str(),
ci.personal ? "yes" : "no",
ci.freq,
datebuf);
} break;
default:
print_plain (ci.email, ci.name, ecdata.color);
}
switch (ecdata.format) {
case MU_CONFIG_FORMAT_MUTT_ALIAS:
each_contact_mutt_alias(ci.email, ci.name, ecdata.nicks);
break;
case MU_CONFIG_FORMAT_MUTT_AB:
mu_util_print_encoded("%s\t%s\t\n", ci.email.c_str(), ci.name.c_str());
break;
case MU_CONFIG_FORMAT_WL: each_contact_wl(ci.email, ci.name, ecdata.nicks); break;
case MU_CONFIG_FORMAT_ORG_CONTACT:
if (!ci.name.empty())
mu_util_print_encoded("* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n",
ci.name.c_str(),
ci.email.c_str());
break;
case MU_CONFIG_FORMAT_BBDB: each_contact_bbdb(ci.email, ci.name, ci.last_seen); break;
case MU_CONFIG_FORMAT_CSV:
mu_util_print_encoded("%s,%s\n",
ci.name.empty() ? "" : Mu::quote(ci.name).c_str(),
Mu::quote(ci.email).c_str());
break;
case MU_CONFIG_FORMAT_DEBUG: {
char datebuf[32];
strftime(datebuf, sizeof(datebuf), "%F %T", gmtime(&ci.last_seen));
g_print("%s\n\tname: %s\n\t%s\n\tpersonal: %s\n\tfreq: %zu\n"
"\tlast-seen: %s\n",
ci.email.c_str(),
ci.name.empty() ? "<none>" : ci.name.c_str(),
ci.full_address.c_str(),
ci.personal ? "yes" : "no",
ci.freq,
datebuf);
} break;
default: print_plain(ci.email, ci.name, ecdata.color);
}
}
static MuError
run_cmd_cfind (const Mu::Store& store,
const char* pattern,
gboolean personal,
time_t after,
const MuConfigFormat format,
gboolean color,
GError **err)
run_cmd_cfind(const Mu::Store& store,
const char* pattern,
gboolean personal,
time_t after,
const MuConfigFormat format,
gboolean color,
GError** err)
{
ECData ecdata{};
ECData ecdata{};
memset(&ecdata, 0, sizeof(ecdata));
memset(&ecdata, 0, sizeof(ecdata));
if (pattern) {
ecdata.rx = g_regex_new (pattern,
(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE),
(GRegexMatchFlags)0, err);
if (!ecdata.rx)
return MU_ERROR_CONTACTS;
}
if (pattern) {
ecdata.rx = g_regex_new(pattern,
(GRegexCompileFlags)(G_REGEX_CASELESS | G_REGEX_OPTIMIZE),
(GRegexMatchFlags)0,
err);
if (!ecdata.rx)
return MU_ERROR_CONTACTS;
}
ecdata.personal = personal;
ecdata.n = 0;
ecdata.after = after;
ecdata.format = format;
ecdata.color = color;
ecdata.nicks = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
ecdata.personal = personal;
ecdata.n = 0;
ecdata.after = after;
ecdata.format = format;
ecdata.color = color;
ecdata.nicks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
print_header (format);
print_header(format);
store.contacts().for_each([&](const auto& ci) { each_contact(ci, ecdata); });
store.contacts().for_each([&](const auto& ci) { each_contact(ci, ecdata); });
g_hash_table_unref (ecdata.nicks);
g_hash_table_unref(ecdata.nicks);
if (ecdata.rx)
g_regex_unref (ecdata.rx);
if (ecdata.rx)
g_regex_unref(ecdata.rx);
if (ecdata.n == 0) {
g_printerr ("no matching contacts found\n");
return MU_ERROR_NO_MATCHES;
}
if (ecdata.n == 0) {
g_printerr("no matching contacts found\n");
return MU_ERROR_NO_MATCHES;
}
return MU_OK;
return MU_OK;
}
static gboolean
cfind_params_valid (const MuConfig *opts)
cfind_params_valid(const MuConfig* opts)
{
switch (opts->format) {
case MU_CONFIG_FORMAT_PLAIN:
case MU_CONFIG_FORMAT_MUTT_ALIAS:
case MU_CONFIG_FORMAT_MUTT_AB:
case MU_CONFIG_FORMAT_WL:
case MU_CONFIG_FORMAT_BBDB:
case MU_CONFIG_FORMAT_CSV:
case MU_CONFIG_FORMAT_ORG_CONTACT:
case MU_CONFIG_FORMAT_DEBUG:
break;
default:
g_printerr ("invalid output format %s\n",
opts->formatstr ? opts->formatstr : "<none>");
return FALSE;
}
switch (opts->format) {
case MU_CONFIG_FORMAT_PLAIN:
case MU_CONFIG_FORMAT_MUTT_ALIAS:
case MU_CONFIG_FORMAT_MUTT_AB:
case MU_CONFIG_FORMAT_WL:
case MU_CONFIG_FORMAT_BBDB:
case MU_CONFIG_FORMAT_CSV:
case MU_CONFIG_FORMAT_ORG_CONTACT:
case MU_CONFIG_FORMAT_DEBUG: break;
default:
g_printerr("invalid output format %s\n",
opts->formatstr ? opts->formatstr : "<none>");
return FALSE;
}
/* only one pattern allowed */
if (opts->params[1] && opts->params[2]) {
g_printerr ("usage: mu cfind [options] [<ptrn>]\n");
return FALSE;
}
/* only one pattern allowed */
if (opts->params[1] && opts->params[2]) {
g_printerr("usage: mu cfind [options] [<ptrn>]\n");
return FALSE;
}
return TRUE;
return TRUE;
}
MuError
Mu::mu_cmd_cfind (const Mu::Store& store, const MuConfig *opts, GError **err)
Mu::mu_cmd_cfind(const Mu::Store& store, const MuConfig* opts, GError** err)
{
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_CFIND,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_CFIND, MU_ERROR_INTERNAL);
if (!cfind_params_valid (opts))
throw Mu::Error(Mu::Error::Code::InvalidArgument,
"invalid parameters");
if (!cfind_params_valid(opts))
throw Mu::Error(Mu::Error::Code::InvalidArgument, "invalid parameters");
auto res = run_cmd_cfind (store,
opts->params[1],
opts->personal,
opts->after,
opts->format,
!opts->nocolor,
err);
if (res != MU_OK)
throw Mu::Error(Mu::Error::Code::Internal, err/*consumes*/,
"error in cfind");
return MU_OK;
auto res = run_cmd_cfind(store,
opts->params[1],
opts->personal,
opts->after,
opts->format,
!opts->nocolor,
err);
if (res != MU_OK)
throw Mu::Error(Mu::Error::Code::Internal, err /*consumes*/, "error in cfind");
return MU_OK;
}

View File

@ -32,144 +32,138 @@
using namespace Mu;
static gboolean
save_part (MuMsg *msg, const char *targetdir, guint partidx, const MuConfig *opts)
save_part(MuMsg* msg, const char* targetdir, guint partidx, const MuConfig* opts)
{
GError *err;
gchar *filepath;
gboolean rv;
GError* err;
gchar* filepath;
gboolean rv;
MuMsgOptions msgopts;
err = NULL;
rv = FALSE;
rv = FALSE;
msgopts = mu_config_get_msg_options (opts);
msgopts = mu_config_get_msg_options(opts);
filepath = mu_msg_part_get_path (msg, msgopts, targetdir, partidx, &err);
filepath = mu_msg_part_get_path(msg, msgopts, targetdir, partidx, &err);
if (!filepath)
goto exit;
if (!mu_msg_part_save (msg, msgopts, filepath, partidx, &err))
if (!mu_msg_part_save(msg, msgopts, filepath, partidx, &err))
goto exit;
if (opts->play)
rv = mu_util_play (filepath, TRUE, FALSE, &err);
rv = mu_util_play(filepath, TRUE, FALSE, &err);
else
rv = TRUE;
exit:
if (err) {
g_printerr ("error with MIME-part: %s\n", err->message);
g_clear_error (&err);
g_printerr("error with MIME-part: %s\n", err->message);
g_clear_error(&err);
}
g_free (filepath);
g_free(filepath);
return rv;
}
static gboolean
save_numbered_parts (MuMsg *msg, const MuConfig *opts)
save_numbered_parts(MuMsg* msg, const MuConfig* opts)
{
gboolean rv;
char **parts, **cur;
char ** parts, **cur;
parts = g_strsplit (opts->parts, ",", 0);
parts = g_strsplit(opts->parts, ",", 0);
for (rv = TRUE, cur = parts; cur && *cur; ++cur) {
unsigned idx;
int i;
char *endptr;
int i;
char* endptr;
idx = (unsigned)(i = strtol (*cur, &endptr, 10));
idx = (unsigned)(i = strtol(*cur, &endptr, 10));
if (i < 0 || *cur == endptr) {
g_printerr ("invalid MIME-part index '%s'\n", *cur);
g_printerr("invalid MIME-part index '%s'\n", *cur);
rv = FALSE;
break;
}
if (!save_part (msg, opts->targetdir, idx, opts)) {
g_printerr ("failed to save MIME-part %d\n", idx);
if (!save_part(msg, opts->targetdir, idx, opts)) {
g_printerr("failed to save MIME-part %d\n", idx);
rv = FALSE;
break;
}
}
g_strfreev (parts);
g_strfreev(parts);
return rv;
}
static GRegex*
anchored_regex (const char* pattern)
anchored_regex(const char* pattern)
{
GRegex *rx;
GError *err;
gchar *anchored;
GRegex* rx;
GError* err;
gchar* anchored;
anchored = g_strdup_printf
("%s%s%s",
pattern[0] == '^' ? "" : "^",
pattern,
pattern[strlen(pattern)-1] == '$' ? "" : "$");
anchored = g_strdup_printf("%s%s%s",
pattern[0] == '^' ? "" : "^",
pattern,
pattern[strlen(pattern) - 1] == '$' ? "" : "$");
err = NULL;
rx = g_regex_new (anchored,
(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE),
(GRegexMatchFlags)0, &err);
g_free (anchored);
rx = g_regex_new(anchored,
(GRegexCompileFlags)(G_REGEX_CASELESS | G_REGEX_OPTIMIZE),
(GRegexMatchFlags)0,
&err);
g_free(anchored);
if (!rx) {
g_printerr ("error in regular expression '%s': %s\n",
pattern, err->message ? err->message : "error");
g_error_free (err);
g_printerr("error in regular expression '%s': %s\n",
pattern,
err->message ? err->message : "error");
g_error_free(err);
return NULL;
}
return rx;
}
static gboolean
save_part_with_filename (MuMsg *msg, const char *pattern, const MuConfig *opts)
save_part_with_filename(MuMsg* msg, const char* pattern, const MuConfig* opts)
{
GSList *lst, *cur;
GRegex *rx;
gboolean rv;
GSList * lst, *cur;
GRegex* rx;
gboolean rv;
MuMsgOptions msgopts;
msgopts = mu_config_get_msg_options (opts);
msgopts = mu_config_get_msg_options(opts);
/* 'anchor' the pattern with '^...$' if not already */
rx = anchored_regex (pattern);
rx = anchored_regex(pattern);
if (!rx)
return FALSE;
lst = mu_msg_find_files (msg, msgopts, rx);
g_regex_unref (rx);
lst = mu_msg_find_files(msg, msgopts, rx);
g_regex_unref(rx);
if (!lst) {
g_printerr ("no matching attachments found");
g_printerr("no matching attachments found");
return FALSE;
}
for (cur = lst, rv = TRUE; cur; cur = g_slist_next (cur))
rv = rv && save_part (msg, opts->targetdir,
GPOINTER_TO_UINT(cur->data), opts);
g_slist_free (lst);
for (cur = lst, rv = TRUE; cur; cur = g_slist_next(cur))
rv = rv && save_part(msg, opts->targetdir, GPOINTER_TO_UINT(cur->data), opts);
g_slist_free(lst);
return rv;
}
struct _SaveData {
gboolean result;
guint saved_num;
const MuConfig *opts;
gboolean result;
guint saved_num;
const MuConfig* opts;
};
typedef struct _SaveData SaveData;
typedef struct _SaveData SaveData;
static gboolean
ignore_part (MuMsg *msg, MuMsgPart *part, SaveData *sd)
ignore_part(MuMsg* msg, MuMsgPart* part, SaveData* sd)
{
/* something went wrong somewhere; stop */
if (!sd->result)
@ -180,93 +174,86 @@ ignore_part (MuMsg *msg, MuMsgPart *part, SaveData *sd)
return TRUE;
/* filter out non-attachments? */
if (!sd->opts->save_all &&
!(mu_msg_part_maybe_attachment (part)))
if (!sd->opts->save_all && !(mu_msg_part_maybe_attachment(part)))
return TRUE;
return FALSE;
}
static void
save_part_if (MuMsg *msg, MuMsgPart *part, SaveData *sd)
save_part_if(MuMsg* msg, MuMsgPart* part, SaveData* sd)
{
gchar *filepath;
gboolean rv;
GError *err;
gchar* filepath;
gboolean rv;
GError* err;
MuMsgOptions msgopts;
if (ignore_part (msg, part, sd))
if (ignore_part(msg, part, sd))
return;
rv = FALSE;
rv = FALSE;
filepath = NULL;
err = NULL;
msgopts = mu_config_get_msg_options (sd->opts);
filepath = mu_msg_part_get_path (msg, msgopts,
sd->opts->targetdir,
part->index, &err);
msgopts = mu_config_get_msg_options(sd->opts);
filepath = mu_msg_part_get_path(msg, msgopts, sd->opts->targetdir, part->index, &err);
if (!filepath)
goto exit;
if (!mu_msg_part_save (msg, msgopts, filepath, part->index, &err))
if (!mu_msg_part_save(msg, msgopts, filepath, part->index, &err))
goto exit;
if (sd->opts->play)
rv = mu_util_play (filepath, TRUE, FALSE, &err);
rv = mu_util_play(filepath, TRUE, FALSE, &err);
else
rv = TRUE;
++sd->saved_num;
exit:
if (err)
g_printerr ("error saving MIME part: %s", err->message);
g_printerr("error saving MIME part: %s", err->message);
g_free (filepath);
g_clear_error (&err);
g_free(filepath);
g_clear_error(&err);
sd->result = rv;
}
static gboolean
save_certain_parts (MuMsg *msg, const MuConfig *opts)
save_certain_parts(MuMsg* msg, const MuConfig* opts)
{
SaveData sd;
SaveData sd;
MuMsgOptions msgopts;
sd.result = TRUE;
sd.saved_num = 0;
sd.opts = opts;
sd.result = TRUE;
sd.saved_num = 0;
sd.opts = opts;
msgopts = mu_config_get_msg_options (opts);
mu_msg_part_foreach (msg, msgopts,
(MuMsgPartForeachFunc)save_part_if, &sd);
msgopts = mu_config_get_msg_options(opts);
mu_msg_part_foreach(msg, msgopts, (MuMsgPartForeachFunc)save_part_if, &sd);
if (sd.saved_num == 0) {
g_printerr ("no %s extracted from this message",
opts->save_attachments ? "attachments" : "parts");
g_printerr("no %s extracted from this message",
opts->save_attachments ? "attachments" : "parts");
sd.result = FALSE;
}
return sd.result;
}
static gboolean
save_parts (const char *path, const char *filename, const MuConfig *opts)
save_parts(const char* path, const char* filename, const MuConfig* opts)
{
MuMsg* msg;
MuMsg* msg;
gboolean rv;
GError *err;
GError* err;
err = NULL;
msg = mu_msg_new_from_file (path, NULL, &err);
msg = mu_msg_new_from_file(path, NULL, &err);
if (!msg) {
if (err) {
g_printerr ("error: %s", err->message);
g_error_free (err);
g_printerr("error: %s", err->message);
g_error_free(err);
}
return FALSE;
}
@ -276,21 +263,25 @@ save_parts (const char *path, const char *filename, const MuConfig *opts)
/* should we save some explicit parts? */
if (opts->parts)
rv = save_numbered_parts (msg, opts);
rv = save_numbered_parts(msg, opts);
else if (filename)
rv = save_part_with_filename (msg, filename, opts);
rv = save_part_with_filename(msg, filename, opts);
else
rv = save_certain_parts (msg, opts);
rv = save_certain_parts(msg, opts);
mu_msg_unref (msg);
mu_msg_unref(msg);
return rv;
}
#define color_maybe(C) do{ if (color) fputs ((C),stdout);}while(0)
#define color_maybe(C) \
do { \
if (color) \
fputs((C), stdout); \
} while (0)
static const char*
disp_str (MuMsgPartType ptype)
disp_str(MuMsgPartType ptype)
{
if (ptype & MU_MSG_PART_TYPE_ATTACHMENT)
return "attach";
@ -300,94 +291,89 @@ disp_str (MuMsgPartType ptype)
}
static void
each_part_show (MuMsg *msg, MuMsgPart *part, gboolean color)
each_part_show(MuMsg* msg, MuMsgPart* part, gboolean color)
{
/* index */
g_print (" %u ", part->index);
g_print(" %u ", part->index);
/* filename */
color_maybe (MU_COLOR_GREEN); {
gchar *fname;
fname = mu_msg_part_get_filename (part, FALSE);
mu_util_fputs_encoded (fname ? fname : "<none>", stdout);
g_free (fname);
color_maybe(MU_COLOR_GREEN);
{
gchar* fname;
fname = mu_msg_part_get_filename(part, FALSE);
mu_util_fputs_encoded(fname ? fname : "<none>", stdout);
g_free(fname);
}
/* content-type */
color_maybe (MU_COLOR_BLUE);
mu_util_print_encoded (
" %s/%s ",
part->type ? part->type : "<none>",
part->subtype ? part->subtype : "<none>");
color_maybe(MU_COLOR_BLUE);
mu_util_print_encoded(" %s/%s ",
part->type ? part->type : "<none>",
part->subtype ? part->subtype : "<none>");
/* /\* disposition *\/ */
color_maybe (MU_COLOR_MAGENTA);
mu_util_print_encoded ("[%s]", disp_str(part->part_type));
color_maybe(MU_COLOR_MAGENTA);
mu_util_print_encoded("[%s]", disp_str(part->part_type));
/* size */
if (part->size > 0) {
color_maybe (MU_COLOR_CYAN);
g_print (" (%s)", mu_str_size_s (part->size));
color_maybe(MU_COLOR_CYAN);
g_print(" (%s)", mu_str_size_s(part->size));
}
color_maybe (MU_COLOR_DEFAULT);
fputs ("\n", stdout);
color_maybe(MU_COLOR_DEFAULT);
fputs("\n", stdout);
}
static gboolean
show_parts (const char* path, const MuConfig *opts, GError **err)
show_parts(const char* path, const MuConfig* opts, GError** err)
{
MuMsg *msg;
MuMsg* msg;
MuMsgOptions msgopts;
msg = mu_msg_new_from_file (path, NULL, err);
msg = mu_msg_new_from_file(path, NULL, err);
if (!msg)
return FALSE;
msgopts = mu_config_get_msg_options (opts);
msgopts = mu_config_get_msg_options(opts);
/* TODO: update this for crypto */
g_print ("MIME-parts in this message:\n");
mu_msg_part_foreach
(msg, msgopts,
(MuMsgPartForeachFunc)each_part_show,
GUINT_TO_POINTER(!opts->nocolor));
g_print("MIME-parts in this message:\n");
mu_msg_part_foreach(msg,
msgopts,
(MuMsgPartForeachFunc)each_part_show,
GUINT_TO_POINTER(!opts->nocolor));
mu_msg_unref (msg);
mu_msg_unref(msg);
return TRUE;
}
static gboolean
check_params (const MuConfig *opts, GError **err)
check_params(const MuConfig* opts, GError** err)
{
size_t param_num;
param_num = mu_config_param_num (opts);
param_num = mu_config_param_num(opts);
if (param_num < 2) {
mu_util_g_set_error
(err, MU_ERROR_IN_PARAMETERS,
"parameters missing");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "parameters missing");
return FALSE;
}
if (opts->save_attachments || opts->save_all)
if (opts->parts || param_num == 3) {
mu_util_g_set_error
(err, MU_ERROR_IN_PARAMETERS,
"--save-attachments and --save-all don't "
"accept a filename pattern or --parts");
mu_util_g_set_error(err,
MU_ERROR_IN_PARAMETERS,
"--save-attachments and --save-all don't "
"accept a filename pattern or --parts");
return FALSE;
}
if (opts->save_attachments && opts->save_all) {
mu_util_g_set_error
(err, MU_ERROR_IN_PARAMETERS,
"only one of --save-attachments and"
" --save-all is allowed");
mu_util_g_set_error(err,
MU_ERROR_IN_PARAMETERS,
"only one of --save-attachments and"
" --save-all is allowed");
return FALSE;
}
@ -395,32 +381,28 @@ check_params (const MuConfig *opts, GError **err)
}
MuError
Mu::mu_cmd_extract (const MuConfig *opts, GError **err)
Mu::mu_cmd_extract(const MuConfig* opts, GError** err)
{
int rv;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_EXTRACT,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_EXTRACT, MU_ERROR_INTERNAL);
if (!check_params (opts, err))
if (!check_params(opts, err))
return MU_ERROR_IN_PARAMETERS;
if (!opts->params[2] && !opts->parts &&
!opts->save_attachments && !opts->save_all)
if (!opts->params[2] && !opts->parts && !opts->save_attachments && !opts->save_all)
/* show, don't save */
rv = show_parts (opts->params[1], opts, err);
rv = show_parts(opts->params[1], opts, err);
else {
rv = mu_util_check_dir(opts->targetdir, FALSE, TRUE);
if (!rv)
mu_util_g_set_error
(err, MU_ERROR_FILE_CANNOT_WRITE,
"target '%s' is not a writable directory",
opts->targetdir);
mu_util_g_set_error(err,
MU_ERROR_FILE_CANNOT_WRITE,
"target '%s' is not a writable directory",
opts->targetdir);
else
rv = save_parts (opts->params[1],
opts->params[2],
opts); /* save */
rv = save_parts(opts->params[1], opts->params[2], opts); /* save */
}
return rv ? MU_OK : MU_ERROR;

File diff suppressed because it is too large Load Diff

View File

@ -42,111 +42,107 @@ using namespace Mu;
static std::atomic<bool> CaughtSignal{};
static void
install_sig_handler (void)
install_sig_handler(void)
{
struct sigaction action;
int i, sigs[] = { SIGINT, SIGHUP, SIGTERM };
int i, sigs[] = {SIGINT, SIGHUP, SIGTERM};
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESETHAND;
action.sa_handler = [](int sig) {
if (!CaughtSignal && sig == SIGINT) /* Ctrl-C */
g_print ("\nshutting down gracefully, "
"press again to kill immediately");
CaughtSignal = true;
};
action.sa_handler = [](int sig) {
if (!CaughtSignal && sig == SIGINT) /* Ctrl-C */
g_print("\nshutting down gracefully, "
"press again to kill immediately");
CaughtSignal = true;
};
for (i = 0; i != G_N_ELEMENTS(sigs); ++i)
if (sigaction (sigs[i], &action, NULL) != 0)
g_critical ("set sigaction for %d failed: %s",
sigs[i], g_strerror (errno));;
if (sigaction(sigs[i], &action, NULL) != 0)
g_critical("set sigaction for %d failed: %s", sigs[i], g_strerror(errno));
;
}
static void
print_stats (const Indexer::Progress& stats, bool color)
print_stats(const Indexer::Progress& stats, bool color)
{
const char *kars = "-\\|/";
static auto i = 0U;
const char* kars = "-\\|/";
static auto i = 0U;
MaybeAnsi col{color};
using Color = MaybeAnsi::Color;
MaybeAnsi col{color};
using Color = MaybeAnsi::Color;
std::cout << col.fg(Color::Yellow) << kars[++i % 4] << col.reset()
<< " indexing messages; "
<< "processed: " << col.fg(Color::Green) << stats.processed << col.reset()
<< "; updated/new: " << col.fg(Color::Green) << stats.updated << col.reset()
<< "; cleaned-up: " << col.fg(Color::Green) << stats.removed << col.reset();
std::cout << col.fg(Color::Yellow) << kars[++i % 4] << col.reset() << " indexing messages; "
<< "processed: " << col.fg(Color::Green) << stats.processed << col.reset()
<< "; updated/new: " << col.fg(Color::Green) << stats.updated << col.reset()
<< "; cleaned-up: " << col.fg(Color::Green) << stats.removed << col.reset();
}
MuError
Mu::mu_cmd_index (Mu::Store& store, const MuConfig *opts, GError **err)
Mu::mu_cmd_index(Mu::Store& store, const MuConfig* opts, GError** err)
{
g_return_val_if_fail (opts, MU_ERROR);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_INDEX, MU_ERROR);
g_return_val_if_fail(opts, MU_ERROR);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_INDEX, MU_ERROR);
/* param[0] == 'index' there should be no param[1] */
/* param[0] == 'index' there should be no param[1] */
if (opts->params[1]) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"unexpected parameter");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "unexpected parameter");
return MU_ERROR;
}
if (opts->max_msg_size < 0) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"the maximum message size must be >= 0");
mu_util_g_set_error(err,
MU_ERROR_IN_PARAMETERS,
"the maximum message size must be >= 0");
return MU_ERROR;
}
const auto mdir{store.metadata().root_maildir};
if (G_UNLIKELY(access (mdir.c_str(), R_OK) != 0)) {
mu_util_g_set_error(err, MU_ERROR_FILE,
"'%s' is not readable: %s", mdir.c_str(), g_strerror (errno));
return MU_ERROR;
}
const auto mdir{store.metadata().root_maildir};
if (G_UNLIKELY(access(mdir.c_str(), R_OK) != 0)) {
mu_util_g_set_error(err,
MU_ERROR_FILE,
"'%s' is not readable: %s",
mdir.c_str(),
g_strerror(errno));
return MU_ERROR;
}
MaybeAnsi col{!opts->nocolor};
using Color = MaybeAnsi::Color;
if (!opts->quiet) {
MaybeAnsi col{!opts->nocolor};
using Color = MaybeAnsi::Color;
if (!opts->quiet) {
if (opts->lazycheck)
std::cout << "lazily ";
if (opts->lazycheck)
std::cout << "lazily ";
std::cout << "indexing maildir " << col.fg(Color::Green)
<< store.metadata().root_maildir << col.reset() << " -> store "
<< col.fg(Color::Green) << store.metadata().database_path << col.reset()
<< std::endl;
}
std::cout << "indexing maildir "
<< col.fg(Color::Green) << store.metadata().root_maildir
<< col.reset()
<< " -> store "
<< col.fg(Color::Green) << store.metadata().database_path
<< col.reset()
<< std::endl;
}
Mu::Indexer::Config conf{};
conf.cleanup = !opts->nocleanup;
conf.lazy_check = opts->lazycheck;
Mu::Indexer::Config conf{};
conf.cleanup = !opts->nocleanup;
conf.lazy_check = opts->lazycheck;
install_sig_handler();
install_sig_handler ();
auto& indexer{store.indexer()};
indexer.start(conf);
while (!CaughtSignal && indexer.is_running()) {
if (!opts->quiet)
print_stats(indexer.progress(), !opts->nocolor);
auto& indexer{store.indexer()};
indexer.start(conf);
while (!CaughtSignal && indexer.is_running()) {
if (!opts->quiet)
print_stats (indexer.progress(), !opts->nocolor);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
std::this_thread::sleep_for(std::chrono::milliseconds(250));
if (!opts->quiet) {
std::cout << "\r";
std::cout.flush();
}
}
if (!opts->quiet) {
std::cout << "\r";
std::cout.flush();
}
}
store.indexer().stop();
store.indexer().stop();
if (!opts->quiet) {
print_stats(store.indexer().progress(), !opts->nocolor);
std::cout << std::endl;
}
if (!opts->quiet) {
print_stats (store.indexer().progress(), !opts->nocolor);
std::cout << std::endl;
}
return MU_OK;
return MU_OK;
}

View File

@ -31,97 +31,100 @@
#include "mu-script.hh"
#include "mu-runtime.hh"
#include "utils/mu-util.h"
#include "utils/mu-str.h"
#define MU_GUILE_EXT ".scm"
#define MU_GUILE_DESCR_PREFIX ";; INFO: "
#define COL(C) ((color)?C:"")
#define COL(C) ((color) ? C : "")
using namespace Mu;
static void
print_script (const char *name, const char *oneline, const char *descr,
gboolean color, gboolean verbose)
print_script(const char* name,
const char* oneline,
const char* descr,
gboolean color,
gboolean verbose)
{
g_print ("%s%s%s%s%s%s%s%s",
verbose ? "\n" : " * ",
COL(MU_COLOR_GREEN),name,COL(MU_COLOR_DEFAULT),
oneline ? ": " : "",
COL(MU_COLOR_BLUE),oneline ? oneline :"",MU_COLOR_DEFAULT);
g_print("%s%s%s%s%s%s%s%s",
verbose ? "\n" : " * ",
COL(MU_COLOR_GREEN),
name,
COL(MU_COLOR_DEFAULT),
oneline ? ": " : "",
COL(MU_COLOR_BLUE),
oneline ? oneline : "",
MU_COLOR_DEFAULT);
if (verbose && descr)
g_print ("%s%s%s",
COL(MU_COLOR_MAGENTA),descr,COL(MU_COLOR_DEFAULT));
g_print("%s%s%s", COL(MU_COLOR_MAGENTA), descr, COL(MU_COLOR_DEFAULT));
}
static gboolean
print_scripts (GSList *scripts, gboolean color,
gboolean verbose, const char *rxstr, GError **err)
print_scripts(GSList* scripts, gboolean color, gboolean verbose, const char* rxstr, GError** err)
{
GSList *cur;
const char *verb;
GSList* cur;
const char* verb;
if (!scripts) {
g_print ("No scripts available\n");
g_print("No scripts available\n");
return TRUE; /* not an error */
}
verb = verbose ? "" : " (use --verbose for details)";
if (rxstr)
g_print ("Available scripts matching '%s'%s:\n",
rxstr, verb);
g_print("Available scripts matching '%s'%s:\n", rxstr, verb);
else
g_print ("Available scripts%s:\n", verb);
g_print("Available scripts%s:\n", verb);
for (cur = scripts; cur; cur = g_slist_next (cur)) {
MuScriptInfo *msi;
const char* descr, *oneline, *name;
for (cur = scripts; cur; cur = g_slist_next(cur)) {
MuScriptInfo* msi;
const char * descr, *oneline, *name;
msi = (MuScriptInfo*)cur->data;
name = mu_script_info_name (msi);
oneline = mu_script_info_one_line (msi);
descr = mu_script_info_description (msi);
name = mu_script_info_name(msi);
oneline = mu_script_info_one_line(msi);
descr = mu_script_info_description(msi);
/* if rxstr is provide, only consider matching scriptinfos */
if (rxstr && !mu_script_info_matches_regex (msi, rxstr, err)) {
if (rxstr && !mu_script_info_matches_regex(msi, rxstr, err)) {
if (err && *err)
return FALSE;
continue;
}
print_script (name, oneline, descr, color, verbose);
print_script(name, oneline, descr, color, verbose);
}
return TRUE;
}
static char*
get_userpath (const char *muhome)
get_userpath(const char* muhome)
{
if (muhome)
return g_build_path (G_DIR_SEPARATOR_S, muhome, "scripts", NULL);
return g_build_path(G_DIR_SEPARATOR_S, muhome, "scripts", NULL);
else
return g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir(),
"mu", "scripts", NULL);
return g_build_path(G_DIR_SEPARATOR_S,
g_get_user_data_dir(),
"mu",
"scripts",
NULL);
}
static GSList*
get_script_info_list (const char *muhome, GError **err)
get_script_info_list(const char* muhome, GError** err)
{
GSList *scripts, *userscripts, *last;
char *userpath;
char* userpath;
scripts = mu_script_get_script_info_list
(MU_SCRIPTS_DIR, MU_GUILE_EXT,
MU_GUILE_DESCR_PREFIX,
err);
scripts = mu_script_get_script_info_list(MU_SCRIPTS_DIR,
MU_GUILE_EXT,
MU_GUILE_DESCR_PREFIX,
err);
if (err && *err)
return NULL;
@ -129,26 +132,25 @@ get_script_info_list (const char *muhome, GError **err)
userpath = get_userpath(muhome);
/* is there are userdir for scripts? */
if (!mu_util_check_dir (userpath, TRUE, FALSE)) {
g_free (userpath);
if (!mu_util_check_dir(userpath, TRUE, FALSE)) {
g_free(userpath);
return scripts;
}
/* append it to the list we already have */
userscripts = mu_script_get_script_info_list (userpath, MU_GUILE_EXT,
MU_GUILE_DESCR_PREFIX,
err);
g_free (userpath);
userscripts =
mu_script_get_script_info_list(userpath, MU_GUILE_EXT, MU_GUILE_DESCR_PREFIX, err);
g_free(userpath);
/* some error, return nothing */
if (err && *err) {
mu_script_info_list_destroy (userscripts);
mu_script_info_list_destroy (scripts);
mu_script_info_list_destroy(userscripts);
mu_script_info_list_destroy(scripts);
return NULL;
}
/* append the user scripts */
last = g_slist_last (scripts);
last = g_slist_last(scripts);
if (last) {
last->next = userscripts;
return scripts;
@ -156,57 +158,51 @@ get_script_info_list (const char *muhome, GError **err)
return userscripts; /* apparently, scripts was NULL */
}
static gboolean
check_params (const MuConfig *opts, GError **err)
check_params(const MuConfig* opts, GError** err)
{
if (!mu_util_supports (MU_FEATURE_GUILE)) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"the 'script' command is not available "
"in this version of mu");
if (!mu_util_supports(MU_FEATURE_GUILE)) {
mu_util_g_set_error(err,
MU_ERROR_IN_PARAMETERS,
"the 'script' command is not available "
"in this version of mu");
return FALSE;
}
return TRUE;
}
MuError
Mu::mu_cmd_script (const MuConfig *opts, GError **err)
Mu::mu_cmd_script(const MuConfig* opts, GError** err)
{
MuScriptInfo *msi;
GSList *scripts;
MuScriptInfo* msi;
GSList* scripts;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_SCRIPT,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_SCRIPT, MU_ERROR_INTERNAL);
if (!check_params (opts, err))
if (!check_params(opts, err))
return MU_ERROR;
scripts = get_script_info_list (opts->muhome, err);
scripts = get_script_info_list(opts->muhome, err);
if (err && *err)
goto leave;
if (g_strcmp0 (opts->cmdstr, "script") == 0) {
print_scripts (scripts, !opts->nocolor, opts->verbose,
opts->script_params[0], err);
if (g_strcmp0(opts->cmdstr, "script") == 0) {
print_scripts(scripts, !opts->nocolor, opts->verbose, opts->script_params[0], err);
goto leave;
}
msi = mu_script_find_script_with_name (scripts, opts->script);
msi = mu_script_find_script_with_name(scripts, opts->script);
if (!msi) {
mu_util_g_set_error (err, MU_ERROR_SCRIPT_NOT_FOUND,
"command or script not found");
mu_util_g_set_error(err, MU_ERROR_SCRIPT_NOT_FOUND, "command or script not found");
goto leave;
}
/* do it! */
mu_script_guile_run (msi, mu_runtime_path(MU_RUNTIME_PATH_CACHE),
opts->script_params, err);
mu_script_guile_run(msi, mu_runtime_path(MU_RUNTIME_PATH_CACHE), opts->script_params, err);
leave:
/* this won't be reached, unless there is some error */
mu_script_info_list_destroy (scripts);
mu_script_info_list_destroy(scripts);
return (err && *err) ? MU_ERROR : MU_OK;
}

View File

@ -30,31 +30,30 @@
#include "mu-cmd.hh"
#include "mu-server.hh"
#include "utils/mu-utils.hh"
#include "utils/mu-command-parser.hh"
#include "utils/mu-readline.hh"
using namespace Mu;
static std::atomic<bool> MuTerminate{false};
static bool tty;
static bool tty;
static void
install_sig_handler (void)
install_sig_handler(void)
{
struct sigaction action;
int i, sigs[] = { SIGINT, SIGHUP, SIGTERM, SIGPIPE };
struct sigaction action;
int i, sigs[] = {SIGINT, SIGHUP, SIGTERM, SIGPIPE};
MuTerminate = false;
MuTerminate = false;
action.sa_handler = [](int sig){ MuTerminate = true; };
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESETHAND;
action.sa_handler = [](int sig) { MuTerminate = true; };
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESETHAND;
for (i = 0; i != G_N_ELEMENTS(sigs); ++i)
if (sigaction (sigs[i], &action, NULL) != 0)
g_critical ("set sigaction for %d failed: %s",
sigs[i], g_strerror (errno));;
for (i = 0; i != G_N_ELEMENTS(sigs); ++i)
if (sigaction(sigs[i], &action, NULL) != 0)
g_critical("set sigaction for %d failed: %s", sigs[i], g_strerror(errno));
;
}
/*
@ -68,85 +67,86 @@ install_sig_handler (void)
static void
cookie(size_t n)
{
const auto num{static_cast<unsigned>(n)};
const auto num{static_cast<unsigned>(n)};
if (tty) // for testing.
::printf ("[%x]", num);
else
::printf (COOKIE_PRE "%x" COOKIE_POST, num);
if (tty) // for testing.
::printf("[%x]", num);
else
::printf(COOKIE_PRE "%x" COOKIE_POST, num);
}
static void
output_sexp_stdout (Sexp&& sexp)
output_sexp_stdout(Sexp&& sexp)
{
const auto str{sexp.to_sexp_string()};
cookie(str.size() + 1);
if (G_UNLIKELY(::puts(str.c_str()) < 0)) {
g_critical ("failed to write output '%s'", str.c_str());
::raise (SIGTERM); /* terminate ourselves */
}
const auto str{sexp.to_sexp_string()};
cookie(str.size() + 1);
if (G_UNLIKELY(::puts(str.c_str()) < 0)) {
g_critical("failed to write output '%s'", str.c_str());
::raise(SIGTERM); /* terminate ourselves */
}
}
static void
report_error(const Mu::Error& err) noexcept
{
Sexp::List e;
Sexp::List e;
e.add_prop(":error", Sexp::make_number(static_cast<size_t>(err.code())));
e.add_prop(":message", Sexp::make_string(err.what()));
e.add_prop(":error", Sexp::make_number(static_cast<size_t>(err.code())));
e.add_prop(":message", Sexp::make_string(err.what()));
output_sexp_stdout(Sexp::make_list(std::move(e)));
output_sexp_stdout(Sexp::make_list(std::move(e)));
}
MuError
Mu::mu_cmd_server (const MuConfig *opts, GError **err) try {
Mu::mu_cmd_server(const MuConfig* opts, GError** err)
try {
Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), false /*writable*/};
Server server{store, output_sexp_stdout};
Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), false/*writable*/};
Server server{store, output_sexp_stdout};
g_message("created server with store @ %s; maildir @ %s; debug-mode %s",
store.metadata().database_path.c_str(),
store.metadata().root_maildir.c_str(),
opts->debug ? "yes" : "no");
g_message ("created server with store @ %s; maildir @ %s; debug-mode %s",
store.metadata().database_path.c_str(),
store.metadata().root_maildir.c_str(),
opts->debug ? "yes" : "no");
tty = ::isatty(::fileno(stdout));
tty = ::isatty(::fileno(stdout));
const auto eval = std::string{opts->commands ? "(help :full t)"
: opts->eval ? opts->eval
: ""};
if (!eval.empty()) {
server.invoke(eval);
return MU_OK;
}
const auto eval = std::string {
opts->commands ? "(help :full t)" : opts->eval ? opts->eval : ""};
if (!eval.empty()) {
server.invoke(eval);
return MU_OK;
}
// Note, the readline stuff is inactive unless on a tty.
const auto histpath{std::string{mu_runtime_path(MU_RUNTIME_PATH_CACHE)} + "/history"};
setup_readline(histpath, 50);
// Note, the readline stuff is inactive unless on a tty.
const auto histpath{std::string{mu_runtime_path(MU_RUNTIME_PATH_CACHE)} + "/history"};
setup_readline(histpath, 50);
install_sig_handler();
std::cout << ";; Welcome to the " << PACKAGE_STRING << " command-server\n"
<< ";; Use (help) to get a list of commands, (quit) to quit.\n";
install_sig_handler();
std::cout << ";; Welcome to the " << PACKAGE_STRING << " command-server\n"
<< ";; Use (help) to get a list of commands, (quit) to quit.\n";
bool do_quit{};
while (!MuTerminate && !do_quit) {
std::fflush(stdout); // Needed for Windows, see issue #1827.
const auto line{read_line(do_quit)};
if (line.find_first_not_of(" \t") == std::string::npos)
continue; // skip whitespace-only lines
bool do_quit{};
while (!MuTerminate && !do_quit) {
std::fflush(stdout); // Needed for Windows, see issue #1827.
const auto line{read_line(do_quit)};
if (line.find_first_not_of(" \t") == std::string::npos)
continue; // skip whitespace-only lines
do_quit = server.invoke(line) ? false : true;
save_line(line);
}
shutdown_readline();
do_quit = server.invoke(line) ? false : true;
save_line(line);
}
shutdown_readline();
return MU_OK;
return MU_OK;
} catch (const Error& er) {
/* note: user-level error, "OK" for mu */
report_error(er);
g_warning ("server caught exception: %s", er.what());
return MU_OK;
/* note: user-level error, "OK" for mu */
report_error(er);
g_warning("server caught exception: %s", er.what());
return MU_OK;
} catch (...) {
g_critical ("server caught exception");
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", "caught exception");
return MU_ERROR;
g_critical("server caught exception");
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", "caught exception");
return MU_ERROR;
}

View File

@ -28,7 +28,6 @@
#include <unistd.h>
#include <errno.h>
#include "mu-msg.hh"
#include "mu-msg-part.hh"
#include "mu-cmd.hh"
@ -48,223 +47,205 @@
using namespace Mu;
static gboolean
view_msg_sexp (MuMsg *msg, const MuConfig *opts)
view_msg_sexp(MuMsg* msg, const MuConfig* opts)
{
::fputs(msg_to_sexp(msg,0, mu_config_get_msg_options(opts))
.to_sexp_string(). c_str(), stdout);
::fputs(msg_to_sexp(msg, 0, mu_config_get_msg_options(opts)).to_sexp_string().c_str(),
stdout);
return TRUE;
}
static void
each_part (MuMsg *msg, MuMsgPart *part, gchar **attach)
each_part(MuMsg* msg, MuMsgPart* part, gchar** attach)
{
char *fname, *tmp;
if (!mu_msg_part_maybe_attachment (part))
if (!mu_msg_part_maybe_attachment(part))
return;
fname = mu_msg_part_get_filename (part, FALSE);
fname = mu_msg_part_get_filename(part, FALSE);
if (!fname)
return;
tmp = *attach;
*attach = g_strdup_printf ("%s%s'%s'",
*attach ? *attach : "",
*attach ? ", " : "",
fname);
g_free (tmp);
tmp = *attach;
*attach = g_strdup_printf("%s%s'%s'", *attach ? *attach : "", *attach ? ", " : "", fname);
g_free(tmp);
}
/* return comma-sep'd list of attachments */
static gchar *
get_attach_str (MuMsg *msg, const MuConfig *opts)
static gchar*
get_attach_str(MuMsg* msg, const MuConfig* opts)
{
gchar *attach;
gchar* attach;
const auto msgopts = (MuMsgOptions)
(mu_config_get_msg_options(opts) | MU_MSG_OPTION_CONSOLE_PASSWORD);
const auto msgopts =
(MuMsgOptions)(mu_config_get_msg_options(opts) | MU_MSG_OPTION_CONSOLE_PASSWORD);
attach = NULL;
mu_msg_part_foreach (msg, msgopts,
(MuMsgPartForeachFunc)each_part, &attach);
mu_msg_part_foreach(msg, msgopts, (MuMsgPartForeachFunc)each_part, &attach);
return attach;
}
#define color_maybe(C) do { if(color) fputs ((C),stdout);} while(0)
#define color_maybe(C) \
do { \
if (color) \
fputs((C), stdout); \
} while (0)
static void
print_field (const char* field, const char *val, gboolean color)
print_field(const char* field, const char* val, gboolean color)
{
if (!val)
return;
color_maybe (MU_COLOR_MAGENTA);
mu_util_fputs_encoded (field, stdout);
color_maybe (MU_COLOR_DEFAULT);
fputs (": ", stdout);
color_maybe(MU_COLOR_MAGENTA);
mu_util_fputs_encoded(field, stdout);
color_maybe(MU_COLOR_DEFAULT);
fputs(": ", stdout);
if (val) {
color_maybe (MU_COLOR_GREEN);
mu_util_fputs_encoded (val, stdout);
color_maybe(MU_COLOR_GREEN);
mu_util_fputs_encoded(val, stdout);
}
color_maybe (MU_COLOR_DEFAULT);
fputs ("\n", stdout);
color_maybe(MU_COLOR_DEFAULT);
fputs("\n", stdout);
}
/* a summary_len of 0 mean 'don't show summary, show body */
static void
body_or_summary (MuMsg *msg, const MuConfig *opts)
body_or_summary(MuMsg* msg, const MuConfig* opts)
{
const char *body;
const char* body;
gboolean color;
int my_opts = mu_config_get_msg_options(opts) |
MU_MSG_OPTION_CONSOLE_PASSWORD;
int my_opts = mu_config_get_msg_options(opts) | MU_MSG_OPTION_CONSOLE_PASSWORD;
color = !opts->nocolor;
body = mu_msg_get_body_text (msg, (MuMsgOptions)my_opts);
body = mu_msg_get_body_text(msg, (MuMsgOptions)my_opts);
if (!body) {
if (mu_msg_get_flags (msg) & MU_FLAG_ENCRYPTED) {
color_maybe (MU_COLOR_CYAN);
g_print ("[No body found; "
"message has encrypted parts]\n");
if (mu_msg_get_flags(msg) & MU_FLAG_ENCRYPTED) {
color_maybe(MU_COLOR_CYAN);
g_print("[No body found; "
"message has encrypted parts]\n");
} else {
color_maybe (MU_COLOR_MAGENTA);
g_print ("[No body found]\n");
color_maybe(MU_COLOR_MAGENTA);
g_print("[No body found]\n");
}
color_maybe (MU_COLOR_DEFAULT);
color_maybe(MU_COLOR_DEFAULT);
return;
}
if (opts->summary_len != 0) {
gchar *summ;
summ = mu_str_summarize (body, opts->summary_len);
print_field ("Summary", summ, color);
g_free (summ);
gchar* summ;
summ = mu_str_summarize(body, opts->summary_len);
print_field("Summary", summ, color);
g_free(summ);
} else {
mu_util_print_encoded ("%s", body);
if (!g_str_has_suffix (body, "\n"))
g_print ("\n");
mu_util_print_encoded("%s", body);
if (!g_str_has_suffix(body, "\n"))
g_print("\n");
}
}
/* we ignore fields for now */
/* summary_len == 0 means "no summary */
static gboolean
view_msg_plain (MuMsg *msg, const MuConfig *opts)
view_msg_plain(MuMsg* msg, const MuConfig* opts)
{
gchar *attachs;
time_t date;
const GSList *lst;
gboolean color;
gchar* attachs;
time_t date;
const GSList* lst;
gboolean color;
color = !opts->nocolor;
print_field ("From", mu_msg_get_from (msg), color);
print_field ("To", mu_msg_get_to (msg), color);
print_field ("Cc", mu_msg_get_cc (msg), color);
print_field ("Bcc", mu_msg_get_bcc (msg), color);
print_field ("Subject", mu_msg_get_subject (msg), color);
print_field("From", mu_msg_get_from(msg), color);
print_field("To", mu_msg_get_to(msg), color);
print_field("Cc", mu_msg_get_cc(msg), color);
print_field("Bcc", mu_msg_get_bcc(msg), color);
print_field("Subject", mu_msg_get_subject(msg), color);
if ((date = mu_msg_get_date (msg)))
print_field ("Date", mu_date_str_s ("%c", date),
color);
if ((date = mu_msg_get_date(msg)))
print_field("Date", mu_date_str_s("%c", date), color);
if ((lst = mu_msg_get_tags (msg))) {
gchar *tags;
tags = mu_str_from_list (lst,',');
print_field ("Tags", tags, color);
g_free (tags);
if ((lst = mu_msg_get_tags(msg))) {
gchar* tags;
tags = mu_str_from_list(lst, ',');
print_field("Tags", tags, color);
g_free(tags);
}
if ((attachs = get_attach_str (msg, opts))) {
print_field ("Attachments", attachs, color);
g_free (attachs);
if ((attachs = get_attach_str(msg, opts))) {
print_field("Attachments", attachs, color);
g_free(attachs);
}
body_or_summary (msg, opts);
body_or_summary(msg, opts);
return TRUE;
}
static gboolean
handle_msg (const char *fname, const MuConfig *opts, GError **err)
handle_msg(const char* fname, const MuConfig* opts, GError** err)
{
MuMsg *msg;
MuMsg* msg;
gboolean rv;
msg = mu_msg_new_from_file (fname, NULL, err);
msg = mu_msg_new_from_file(fname, NULL, err);
if (!msg)
return FALSE;
switch (opts->format) {
case MU_CONFIG_FORMAT_PLAIN:
rv = view_msg_plain (msg, opts);
break;
case MU_CONFIG_FORMAT_SEXP:
rv = view_msg_sexp (msg, opts);
break;
default:
g_critical ("bug: should not be reached");
rv = FALSE;
case MU_CONFIG_FORMAT_PLAIN: rv = view_msg_plain(msg, opts); break;
case MU_CONFIG_FORMAT_SEXP: rv = view_msg_sexp(msg, opts); break;
default: g_critical("bug: should not be reached"); rv = FALSE;
}
mu_msg_unref (msg);
mu_msg_unref(msg);
return rv;
}
static gboolean
view_params_valid (const MuConfig *opts, GError **err)
view_params_valid(const MuConfig* opts, GError** err)
{
/* note: params[0] will be 'view' */
if (!opts->params[0] || !opts->params[1]) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"error in parameters");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "error in parameters");
return FALSE;
}
switch (opts->format) {
case MU_CONFIG_FORMAT_PLAIN:
case MU_CONFIG_FORMAT_SEXP:
break;
case MU_CONFIG_FORMAT_SEXP: break;
default:
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"invalid output format");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "invalid output format");
return FALSE;
}
return TRUE;
}
static MuError
cmd_view (const MuConfig *opts, GError **err)
cmd_view(const MuConfig* opts, GError** err)
{
int i;
int i;
gboolean rv;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_VIEW,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_VIEW, MU_ERROR_INTERNAL);
rv = view_params_valid (opts, err);
rv = view_params_valid(opts, err);
if (!rv)
goto leave;
for (i = 1; opts->params[i]; ++i) {
rv = handle_msg (opts->params[i], opts, err);
rv = handle_msg(opts->params[i], opts, err);
if (!rv)
break;
/* add a separator between two messages? */
if (opts->terminator)
g_print ("%c", VIEW_TERMINATOR);
g_print("%c", VIEW_TERMINATOR);
}
leave:
@ -275,189 +256,173 @@ leave:
}
static MuError
cmd_mkdir (const MuConfig *opts, GError **err)
cmd_mkdir(const MuConfig* opts, GError** err)
{
int i;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_MKDIR,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_MKDIR, MU_ERROR_INTERNAL);
if (!opts->params[1]) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"missing directory parameter");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "missing directory parameter");
return MU_ERROR_IN_PARAMETERS;
}
for (i = 1; opts->params[i]; ++i)
if (!mu_maildir_mkdir (opts->params[i], opts->dirmode,
FALSE, err))
return err && *err ? (MuError)(*err)->code :
MU_ERROR_FILE_CANNOT_MKDIR;
if (!mu_maildir_mkdir(opts->params[i], opts->dirmode, FALSE, err))
return err && *err ? (MuError)(*err)->code : MU_ERROR_FILE_CANNOT_MKDIR;
return MU_OK;
}
static gboolean
check_file_okay (const char *path, gboolean cmd_add)
check_file_okay(const char* path, gboolean cmd_add)
{
if (!g_path_is_absolute (path)) {
g_printerr ("path is not absolute: %s\n", path);
if (!g_path_is_absolute(path)) {
g_printerr("path is not absolute: %s\n", path);
return FALSE;
}
if (cmd_add && access(path, R_OK) != 0) {
g_printerr ("path is not readable: %s: %s\n",
path, g_strerror (errno));
g_printerr("path is not readable: %s: %s\n", path, g_strerror(errno));
return FALSE;
}
return TRUE;
}
typedef bool (*ForeachMsgFunc) (Mu::Store& store, const char *path, GError **err);
typedef bool (*ForeachMsgFunc)(Mu::Store& store, const char* path, GError** err);
static MuError
foreach_msg_file (Mu::Store& store, const MuConfig *opts,
ForeachMsgFunc foreach_func, GError **err)
foreach_msg_file(Mu::Store& store, const MuConfig* opts, ForeachMsgFunc foreach_func, GError** err)
{
unsigned u;
gboolean all_ok;
unsigned u;
gboolean all_ok;
/* note: params[0] will be 'add' */
if (!opts->params[0] || !opts->params[1]) {
g_print ("usage: mu %s <file> [<files>]\n",
opts->params[0] ? opts->params[0] : "<cmd>");
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"missing parameters");
g_print("usage: mu %s <file> [<files>]\n",
opts->params[0] ? opts->params[0] : "<cmd>");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "missing parameters");
return MU_ERROR_IN_PARAMETERS;
}
for (u = 1, all_ok = TRUE; opts->params[u]; ++u) {
const char* path;
path = opts->params[u];
if (!check_file_okay (path, TRUE)) {
if (!check_file_okay(path, TRUE)) {
all_ok = FALSE;
g_printerr ("not a valid message file: %s\n", path);
g_printerr("not a valid message file: %s\n", path);
continue;
}
if (!foreach_func (store, path, err)) {
if (!foreach_func(store, path, err)) {
all_ok = FALSE;
g_printerr ("error with %s: %s\n", path,
(err&&*err) ? (*err)->message :
"something went wrong");
g_clear_error (err);
g_printerr("error with %s: %s\n",
path,
(err && *err) ? (*err)->message : "something went wrong");
g_clear_error(err);
continue;
}
}
if (!all_ok) {
mu_util_g_set_error (err, MU_ERROR_XAPIAN_STORE_FAILED,
"%s failed for some message(s)",
opts->params[0]);
mu_util_g_set_error(err,
MU_ERROR_XAPIAN_STORE_FAILED,
"%s failed for some message(s)",
opts->params[0]);
return MU_ERROR_XAPIAN_STORE_FAILED;
}
return MU_OK;
}
static bool
add_path_func (Mu::Store& store, const char *path, GError **err)
add_path_func(Mu::Store& store, const char* path, GError** err)
{
const auto docid = store.add_message (path);
g_debug ("added message @ %s, docid=%u", path, docid);
const auto docid = store.add_message(path);
g_debug("added message @ %s, docid=%u", path, docid);
return true;
}
static MuError
cmd_add (Mu::Store& store, const MuConfig *opts, GError **err)
{
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_ADD,
MU_ERROR_INTERNAL);
return foreach_msg_file (store, opts, add_path_func, err);
}
static bool
remove_path_func (Mu::Store& store, const char *path, GError **err)
{
const auto res = store.remove_message (path);
g_debug ("removed %s (%s)", path, res ? "yes" : "no");
return true;
return true;
}
static MuError
cmd_remove (Mu::Store& store, const MuConfig *opts, GError **err)
cmd_add(Mu::Store& store, const MuConfig* opts, GError** err)
{
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_REMOVE,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_ADD, MU_ERROR_INTERNAL);
return foreach_msg_file (store, opts, remove_path_func, err);
return foreach_msg_file(store, opts, add_path_func, err);
}
static bool
tickle_func (Mu::Store& store, const char *path, GError **err)
remove_path_func(Mu::Store& store, const char* path, GError** err)
{
MuMsg *msg{mu_msg_new_from_file (path, NULL, err)};
const auto res = store.remove_message(path);
g_debug("removed %s (%s)", path, res ? "yes" : "no");
return true;
}
static MuError
cmd_remove(Mu::Store& store, const MuConfig* opts, GError** err)
{
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_REMOVE, MU_ERROR_INTERNAL);
return foreach_msg_file(store, opts, remove_path_func, err);
}
static bool
tickle_func(Mu::Store& store, const char* path, GError** err)
{
MuMsg* msg{mu_msg_new_from_file(path, NULL, err)};
if (!msg)
return false;
const auto res = mu_msg_tickle (msg, err);
g_debug ("tickled %s (%s)", path, res ? "ok" : "failed");
mu_msg_unref (msg);
const auto res = mu_msg_tickle(msg, err);
g_debug("tickled %s (%s)", path, res ? "ok" : "failed");
mu_msg_unref(msg);
return res == TRUE;
}
static MuError
cmd_tickle (Mu::Store& store, const MuConfig *opts, GError **err)
cmd_tickle(Mu::Store& store, const MuConfig* opts, GError** err)
{
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_TICKLE,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_TICKLE, MU_ERROR_INTERNAL);
return foreach_msg_file (store, opts, tickle_func, err);
return foreach_msg_file(store, opts, tickle_func, err);
}
struct _VData {
MuMsgPartSigStatus combined_status;
char *report;
gboolean oneline;
char* report;
gboolean oneline;
};
typedef struct _VData VData;
static void
each_sig (MuMsg *msg, MuMsgPart *part, VData *vdata)
each_sig(MuMsg* msg, MuMsgPart* part, VData* vdata)
{
MuMsgPartSigStatusReport *report;
MuMsgPartSigStatusReport* report;
report = part->sig_status_report;
if (!report)
return;
if (vdata->oneline)
vdata->report = g_strdup_printf
("%s%s%s",
vdata->report ? vdata->report : "",
vdata->report ? "; " : "",
report->report);
vdata->report = g_strdup_printf("%s%s%s",
vdata->report ? vdata->report : "",
vdata->report ? "; " : "",
report->report);
else
vdata->report = g_strdup_printf
("%s%s\t%s",
vdata->report ? vdata->report : "",
vdata->report ? "\n" : "",
report->report);
vdata->report = g_strdup_printf("%s%s\t%s",
vdata->report ? vdata->report : "",
vdata->report ? "\n" : "",
report->report);
if (vdata->combined_status == MU_MSG_PART_SIG_STATUS_BAD ||
vdata->combined_status == MU_MSG_PART_SIG_STATUS_ERROR)
@ -466,170 +431,157 @@ each_sig (MuMsg *msg, MuMsgPart *part, VData *vdata)
vdata->combined_status = report->verdict;
}
static void
print_verdict (VData *vdata, gboolean color, gboolean verbose)
print_verdict(VData* vdata, gboolean color, gboolean verbose)
{
g_print ("verdict: ");
g_print("verdict: ");
switch (vdata->combined_status) {
case MU_MSG_PART_SIG_STATUS_UNSIGNED:
g_print ("no signature found");
break;
case MU_MSG_PART_SIG_STATUS_UNSIGNED: g_print("no signature found"); break;
case MU_MSG_PART_SIG_STATUS_GOOD:
color_maybe (MU_COLOR_GREEN);
g_print ("signature(s) verified");
color_maybe(MU_COLOR_GREEN);
g_print("signature(s) verified");
break;
case MU_MSG_PART_SIG_STATUS_BAD:
color_maybe (MU_COLOR_RED);
g_print ("bad signature");
color_maybe(MU_COLOR_RED);
g_print("bad signature");
break;
case MU_MSG_PART_SIG_STATUS_ERROR:
color_maybe (MU_COLOR_RED);
g_print ("verification failed");
color_maybe(MU_COLOR_RED);
g_print("verification failed");
break;
case MU_MSG_PART_SIG_STATUS_FAIL:
color_maybe(MU_COLOR_RED);
g_print ("error in verification process");
g_print("error in verification process");
break;
default: g_return_if_reached ();
default: g_return_if_reached();
}
color_maybe (MU_COLOR_DEFAULT);
color_maybe(MU_COLOR_DEFAULT);
if (vdata->report && verbose)
g_print ("%s%s\n",
(vdata->oneline) ? ";" : "\n",
vdata->report);
g_print("%s%s\n", (vdata->oneline) ? ";" : "\n", vdata->report);
else
g_print ("\n");
g_print("\n");
}
static MuError
cmd_verify (const MuConfig *opts, GError **err)
cmd_verify(const MuConfig* opts, GError** err)
{
MuMsg *msg;
MuMsg* msg;
int msgopts;
VData vdata;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_VERIFY,
MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts->cmd == MU_CONFIG_CMD_VERIFY, MU_ERROR_INTERNAL);
if (!opts->params[1]) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"missing message-file parameter");
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "missing message-file parameter");
return MU_ERROR_IN_PARAMETERS;
}
msg = mu_msg_new_from_file (opts->params[1], NULL, err);
msg = mu_msg_new_from_file(opts->params[1], NULL, err);
if (!msg)
return MU_ERROR;
msgopts = mu_config_get_msg_options (opts)
| MU_MSG_OPTION_VERIFY
| MU_MSG_OPTION_CONSOLE_PASSWORD;
msgopts =
mu_config_get_msg_options(opts) | MU_MSG_OPTION_VERIFY | MU_MSG_OPTION_CONSOLE_PASSWORD;
vdata.report = NULL;
vdata.report = NULL;
vdata.combined_status = MU_MSG_PART_SIG_STATUS_UNSIGNED;
vdata.oneline = FALSE;
vdata.oneline = FALSE;
mu_msg_part_foreach (msg, (MuMsgOptions)msgopts,
(MuMsgPartForeachFunc)each_sig, &vdata);
mu_msg_part_foreach(msg, (MuMsgOptions)msgopts, (MuMsgPartForeachFunc)each_sig, &vdata);
if (!opts->quiet)
print_verdict (&vdata, !opts->nocolor, opts->verbose);
print_verdict(&vdata, !opts->nocolor, opts->verbose);
mu_msg_unref (msg);
g_free (vdata.report);
mu_msg_unref(msg);
g_free(vdata.report);
return vdata.combined_status == MU_MSG_PART_SIG_STATUS_GOOD ?
MU_OK : MU_ERROR;
return vdata.combined_status == MU_MSG_PART_SIG_STATUS_GOOD ? MU_OK : MU_ERROR;
}
template <typename T>
static void key_val(const Mu::MaybeAnsi& col, const std::string& key, T val)
static void
key_val(const Mu::MaybeAnsi& col, const std::string& key, T val)
{
using Color = Mu::MaybeAnsi::Color;
using Color = Mu::MaybeAnsi::Color;
std::cout << col.fg(Color::BrightBlue)
<< std::left << std::setw(18) << key
<< col.reset() << ": ";
std::cout << col.fg(Color::BrightBlue) << std::left << std::setw(18) << key << col.reset()
<< ": ";
std::cout << col.fg(Color::Green)
<< val << col.reset() << "\n";
std::cout << col.fg(Color::Green) << val << col.reset() << "\n";
}
static MuError
cmd_info (const Mu::Store& store, const MuConfig *opts, GError **err)
cmd_info(const Mu::Store& store, const MuConfig* opts, GError** err)
{
Mu::MaybeAnsi col{!opts->nocolor};
Mu::MaybeAnsi col{!opts->nocolor};
key_val(col, "maildir", store.metadata().root_maildir);
key_val(col, "database-path", store.metadata().database_path);
key_val(col, "schema-version", store.metadata().schema_version);
key_val(col, "max-message-size", store.metadata().max_message_size);
key_val(col, "batch-size", store.metadata().batch_size);
key_val(col, "messages in store", store.size());
key_val(col, "maildir", store.metadata().root_maildir);
key_val(col, "database-path", store.metadata().database_path);
key_val(col, "schema-version", store.metadata().schema_version);
key_val(col, "max-message-size", store.metadata().max_message_size);
key_val(col, "batch-size", store.metadata().batch_size);
key_val(col, "messages in store", store.size());
const auto created{store.metadata().created};
const auto tstamp{::localtime (&created)};
const auto tstamp{::localtime(&created)};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-y2k"
char tbuf[64];
strftime (tbuf, sizeof(tbuf), "%c", tstamp);
char tbuf[64];
strftime(tbuf, sizeof(tbuf), "%c", tstamp);
#pragma GCC diagnostic pop
key_val(col, "created", tbuf);
key_val(col, "created", tbuf);
const auto addrs{store.metadata().personal_addresses};
if (addrs.empty())
key_val(col, "personal-address", "<none>");
else
for (auto&& c: addrs)
key_val(col, "personal-address", c);
if (addrs.empty())
key_val(col, "personal-address", "<none>");
else
for (auto&& c : addrs)
key_val(col, "personal-address", c);
return MU_OK;
return MU_OK;
}
static MuError
cmd_init (const MuConfig *opts, GError **err)
cmd_init(const MuConfig* opts, GError** err)
{
/* not provided, nor could we find a good default */
if (!opts->maildir) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"missing --maildir parameter and could "
"not determine default");
/* not provided, nor could we find a good default */
if (!opts->maildir) {
mu_util_g_set_error(err,
MU_ERROR_IN_PARAMETERS,
"missing --maildir parameter and could "
"not determine default");
return MU_ERROR_IN_PARAMETERS;
}
}
if (opts->max_msg_size < 0) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"invalid value for max-message-size");
if (opts->max_msg_size < 0) {
mu_util_g_set_error(err,
MU_ERROR_IN_PARAMETERS,
"invalid value for max-message-size");
return MU_ERROR_IN_PARAMETERS;
} else if (opts->batch_size < 0) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"invalid value for batch-size");
} else if (opts->batch_size < 0) {
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "invalid value for batch-size");
return MU_ERROR_IN_PARAMETERS;
}
}
Mu::Store::Config conf{};
conf.max_message_size = opts->max_msg_size;
conf.batch_size = opts->batch_size;
Mu::Store::Config conf{};
conf.max_message_size = opts->max_msg_size;
conf.batch_size = opts->batch_size;
Mu::StringVec my_addrs;
auto addrs = opts->my_addresses;
while (addrs && *addrs) {
my_addrs.emplace_back (*addrs);
++addrs;
}
Mu::StringVec my_addrs;
auto addrs = opts->my_addresses;
while (addrs && *addrs) {
my_addrs.emplace_back(*addrs);
++addrs;
}
Mu::Store store(mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB),
opts->maildir, my_addrs, conf);
Mu::Store store(mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), opts->maildir, my_addrs, conf);
if (!opts->quiet) {
cmd_info (store, opts, NULL);
cmd_info(store, opts, NULL);
std::cout << "\nstore created; use the 'index' command to fill/update it.\n";
}
@ -637,49 +589,46 @@ cmd_init (const MuConfig *opts, GError **err)
}
static MuError
cmd_find (const MuConfig *opts, GError **err)
cmd_find(const MuConfig* opts, GError** err)
{
Mu::Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), true/*readonly*/};
Mu::Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), true /*readonly*/};
return mu_cmd_find(store, opts, err);
return mu_cmd_find(store, opts, err);
}
static void
show_usage (void)
show_usage(void)
{
g_print ("usage: mu command [options] [parameters]\n");
g_print ("where command is one of index, find, cfind, view, mkdir, "
"extract, add, remove, script, verify or server\n");
g_print ("see the mu, mu-<command> or mu-easy manpages for "
"more information\n");
g_print("usage: mu command [options] [parameters]\n");
g_print("where command is one of index, find, cfind, view, mkdir, "
"extract, add, remove, script, verify or server\n");
g_print("see the mu, mu-<command> or mu-easy manpages for "
"more information\n");
}
typedef MuError (*readonly_store_func) (const Mu::Store&, const MuConfig *, GError **err);
typedef MuError (*writable_store_func) (Mu::Store&, const MuConfig *, GError **err);
typedef MuError (*readonly_store_func)(const Mu::Store&, const MuConfig*, GError** err);
typedef MuError (*writable_store_func)(Mu::Store&, const MuConfig*, GError** err);
static MuError
with_readonly_store (readonly_store_func func, const MuConfig *opts, GError **err)
with_readonly_store(readonly_store_func func, const MuConfig* opts, GError** err)
{
const Mu::Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), true/*readonly*/};
return func (store, opts, err);
const Mu::Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), true /*readonly*/};
return func(store, opts, err);
}
static MuError
with_writable_store (writable_store_func func, const MuConfig *opts, GError **err)
with_writable_store(writable_store_func func, const MuConfig* opts, GError** err)
{
Mu::Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), false/*!readonly*/};
return func (store, opts, err);
Mu::Store store{mu_runtime_path(MU_RUNTIME_PATH_XAPIANDB), false /*!readonly*/};
return func(store, opts, err);
}
static gboolean
check_params (const MuConfig *opts, GError **err)
check_params(const MuConfig* opts, GError** err)
{
if (!opts->params||!opts->params[0]) {/* no command? */
show_usage ();
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"error in parameters");
if (!opts->params || !opts->params[0]) { /* no command? */
show_usage();
mu_util_g_set_error(err, MU_ERROR_IN_PARAMETERS, "error in parameters");
return FALSE;
}
@ -687,64 +636,58 @@ check_params (const MuConfig *opts, GError **err)
}
MuError
Mu::mu_cmd_execute (const MuConfig *opts, GError **err) try
{
Mu::mu_cmd_execute(const MuConfig* opts, GError** err)
try {
MuError merr;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail(opts, MU_ERROR_INTERNAL);
if (!check_params(opts, err))
return MU_G_ERROR_CODE(err);
switch (opts->cmd) {
/* already handled in mu-config.c */
case MU_CONFIG_CMD_HELP: return MU_OK;
case MU_CONFIG_CMD_HELP:
return MU_OK;
/* no store needed */
/* no store needed */
case MU_CONFIG_CMD_MKDIR: merr = cmd_mkdir (opts, err); break;
case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script (opts, err); break;
case MU_CONFIG_CMD_VIEW: merr = cmd_view (opts, err); break;
case MU_CONFIG_CMD_VERIFY: merr = cmd_verify (opts, err); break;
case MU_CONFIG_CMD_EXTRACT: merr = mu_cmd_extract (opts, err); break;
case MU_CONFIG_CMD_MKDIR: merr = cmd_mkdir(opts, err); break;
case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script(opts, err); break;
case MU_CONFIG_CMD_VIEW: merr = cmd_view(opts, err); break;
case MU_CONFIG_CMD_VERIFY: merr = cmd_verify(opts, err); break;
case MU_CONFIG_CMD_EXTRACT:
merr = mu_cmd_extract(opts, err);
break;
/* read-only store */
/* read-only store */
case MU_CONFIG_CMD_CFIND:
merr = with_readonly_store (mu_cmd_cfind, opts, err); break;
case MU_CONFIG_CMD_FIND:
merr = cmd_find(opts, err); break;
case MU_CONFIG_CMD_CFIND: merr = with_readonly_store(mu_cmd_cfind, opts, err); break;
case MU_CONFIG_CMD_FIND: merr = cmd_find(opts, err); break;
case MU_CONFIG_CMD_INFO:
merr = with_readonly_store (cmd_info, opts, err); break;
merr = with_readonly_store(cmd_info, opts, err);
break;
/* writable store */
/* writable store */
case MU_CONFIG_CMD_ADD:
merr = with_writable_store (cmd_add, opts, err); break;
case MU_CONFIG_CMD_REMOVE:
merr = with_writable_store (cmd_remove, opts, err); break;
case MU_CONFIG_CMD_TICKLE:
merr = with_writable_store (cmd_tickle, opts, err); break;
case MU_CONFIG_CMD_INDEX:
merr = with_writable_store (mu_cmd_index, opts, err); break;
case MU_CONFIG_CMD_ADD: merr = with_writable_store(cmd_add, opts, err); break;
case MU_CONFIG_CMD_REMOVE: merr = with_writable_store(cmd_remove, opts, err); break;
case MU_CONFIG_CMD_TICKLE: merr = with_writable_store(cmd_tickle, opts, err); break;
case MU_CONFIG_CMD_INDEX: merr = with_writable_store(mu_cmd_index, opts, err); break;
/* commands instantiate store themselves */
case MU_CONFIG_CMD_INIT:
merr = cmd_init (opts,err); break;
case MU_CONFIG_CMD_SERVER:
merr = mu_cmd_server (opts, err); break;
case MU_CONFIG_CMD_INIT: merr = cmd_init(opts, err); break;
case MU_CONFIG_CMD_SERVER: merr = mu_cmd_server(opts, err); break;
default:
merr = MU_ERROR_IN_PARAMETERS; break;
default: merr = MU_ERROR_IN_PARAMETERS; break;
}
return merr;
} catch (const Mu::Error& er) {
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", er.what());
return MU_ERROR;
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", er.what());
return MU_ERROR;
} catch (...) {
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", "caught exception");
return MU_ERROR;
g_set_error(err, MU_ERROR_DOMAIN, MU_ERROR, "%s", "caught exception");
return MU_ERROR;
}

View File

@ -36,8 +36,7 @@ namespace Mu {
* >MU_OK (0) results, MU_EXITCODE_NO_MATCHES if the command
* succeeds but there no matches, some error code for all other errors
*/
MuError mu_cmd_find (const Mu::Store& store, const MuConfig *opts,
GError **err);
MuError mu_cmd_find(const Mu::Store& store, const MuConfig* opts, GError** err);
/**
* execute the 'extract' command
@ -48,8 +47,7 @@ MuError mu_cmd_find (const Mu::Store& store, const MuConfig *opts,
* @return MU_OK (0) if the command succeeds,
* some error code otherwise
*/
MuError mu_cmd_extract (const MuConfig *opts, GError **err);
MuError mu_cmd_extract(const MuConfig* opts, GError** err);
/**
* execute the 'script' command
@ -60,7 +58,7 @@ MuError mu_cmd_extract (const MuConfig *opts, GError **err);
* @return MU_OK (0) if the command succeeds,
* some error code otherwise
*/
MuError mu_cmd_script (const MuConfig *opts, GError **err);
MuError mu_cmd_script(const MuConfig* opts, GError** err);
/**
* execute the cfind command
@ -72,8 +70,7 @@ MuError mu_cmd_script (const MuConfig *opts, GError **err);
* @return MU_OK (0) if the command succeeds,
* some error code otherwise
*/
MuError mu_cmd_cfind (const Mu::Store& store, const MuConfig *opts,
GError **err);
MuError mu_cmd_cfind(const Mu::Store& store, const MuConfig* opts, GError** err);
/**
* execute some mu command, based on 'opts'
@ -83,7 +80,7 @@ MuError mu_cmd_cfind (const Mu::Store& store, const MuConfig *opts,
*
* @return MU_OK if all went wall, some error code otherwise
*/
MuError mu_cmd_execute (const MuConfig *opts, GError **err);
MuError mu_cmd_execute(const MuConfig* opts, GError** err);
/**
* execute the 'index' command
@ -95,7 +92,7 @@ MuError mu_cmd_execute (const MuConfig *opts, GError **err);
* @return MU_OK (0) if the command succeeded,
* some error code otherwise
*/
MuError mu_cmd_index (Mu::Store& store, const MuConfig *opt, GError **err);
MuError mu_cmd_index(Mu::Store& store, const MuConfig* opt, GError** err);
/**
* execute the server command
@ -104,8 +101,7 @@ MuError mu_cmd_index (Mu::Store& store, const MuConfig *opt, GError **err);
*
* @return MU_OK (0) if the command succeeds, some error code otherwise
*/
MuError mu_cmd_server (const MuConfig *opts, GError **err);
MuError mu_cmd_server(const MuConfig* opts, GError** err);
} // namespace Mu

File diff suppressed because it is too large Load Diff

View File

@ -35,28 +35,28 @@ typedef enum {
MU_CONFIG_FORMAT_UNKNOWN = 0,
/* for cfind, find, view */
MU_CONFIG_FORMAT_PLAIN, /* plain output */
MU_CONFIG_FORMAT_PLAIN, /* plain output */
/* for cfind */
MU_CONFIG_FORMAT_MUTT_ALIAS, /* mutt alias style */
MU_CONFIG_FORMAT_MUTT_AB, /* mutt ext abook */
MU_CONFIG_FORMAT_WL, /* Wanderlust abook */
MU_CONFIG_FORMAT_CSV, /* comma-sep'd values */
MU_CONFIG_FORMAT_ORG_CONTACT, /* org-contact */
MU_CONFIG_FORMAT_BBDB, /* BBDB */
MU_CONFIG_FORMAT_MUTT_ALIAS, /* mutt alias style */
MU_CONFIG_FORMAT_MUTT_AB, /* mutt ext abook */
MU_CONFIG_FORMAT_WL, /* Wanderlust abook */
MU_CONFIG_FORMAT_CSV, /* comma-sep'd values */
MU_CONFIG_FORMAT_ORG_CONTACT, /* org-contact */
MU_CONFIG_FORMAT_BBDB, /* BBDB */
MU_CONFIG_FORMAT_DEBUG,
/* for find, view */
MU_CONFIG_FORMAT_SEXP, /* output sexps (emacs) */
MU_CONFIG_FORMAT_JSON, /* output JSON */
MU_CONFIG_FORMAT_SEXP, /* output sexps (emacs) */
MU_CONFIG_FORMAT_JSON, /* output JSON */
/* for find */
MU_CONFIG_FORMAT_LINKS, /* output as symlinks */
MU_CONFIG_FORMAT_XML, /* output xml */
MU_CONFIG_FORMAT_XQUERY, /* output the xapian query */
MU_CONFIG_FORMAT_MQUERY, /* output the mux query */
MU_CONFIG_FORMAT_LINKS, /* output as symlinks */
MU_CONFIG_FORMAT_XML, /* output xml */
MU_CONFIG_FORMAT_XQUERY, /* output the xapian query */
MU_CONFIG_FORMAT_MQUERY, /* output the mux query */
MU_CONFIG_FORMAT_EXEC /* execute some command */
MU_CONFIG_FORMAT_EXEC /* execute some command */
} MuConfigFormat;
typedef enum {
@ -68,8 +68,8 @@ typedef enum {
MU_CONFIG_CMD_FIND,
MU_CONFIG_CMD_HELP,
MU_CONFIG_CMD_INDEX,
MU_CONFIG_CMD_INFO,
MU_CONFIG_CMD_INIT,
MU_CONFIG_CMD_INFO,
MU_CONFIG_CMD_INIT,
MU_CONFIG_CMD_MKDIR,
MU_CONFIG_CMD_REMOVE,
MU_CONFIG_CMD_SCRIPT,
@ -81,115 +81,110 @@ typedef enum {
MU_CONFIG_CMD_NONE
} MuConfigCmd;
#define mu_config_cmd_is_valid(C) \
((C) > MU_CONFIG_CMD_UNKNOWN && (C) < MU_CONFIG_CMD_NONE)
#define mu_config_cmd_is_valid(C) ((C) > MU_CONFIG_CMD_UNKNOWN && (C) < MU_CONFIG_CMD_NONE)
/* struct with all configuration options for mu; it will be filled
* from the config file, and/or command line arguments */
struct _MuConfig {
MuConfigCmd cmd; /* the command, or
* MU_CONFIG_CMD_NONE */
char *cmdstr; /* cmd string, for user
* info */
MuConfigCmd cmd; /* the command, or
* MU_CONFIG_CMD_NONE */
char* cmdstr; /* cmd string, for user
* info */
/* general options */
gboolean quiet; /* don't give any output */
gboolean debug; /* log debug-level info */
gchar *muhome; /* the House of Mu */
gboolean version; /* request mu version */
gboolean log_stderr; /* log to stderr (not logfile) */
gchar** params; /* parameters (for querying) */
gboolean nocolor; /* don't use use ansi-colors
* in some output */
gboolean verbose; /* verbose output */
gboolean quiet; /* don't give any output */
gboolean debug; /* log debug-level info */
gchar* muhome; /* the House of Mu */
gboolean version; /* request mu version */
gboolean log_stderr; /* log to stderr (not logfile) */
gchar** params; /* parameters (for querying) */
gboolean nocolor; /* don't use use ansi-colors
* in some output */
gboolean verbose; /* verbose output */
/* options for init */
gchar *maildir; /* where the mails are */
char** my_addresses; /* 'my e-mail address', for mu cfind;
* can be use multiple times */
int max_msg_size; /* maximum size for message files */
int batch_size; /* database transaction batch size */
/* options for init */
gchar* maildir; /* where the mails are */
char** my_addresses; /* 'my e-mail address', for mu cfind;
* can be use multiple times */
int max_msg_size; /* maximum size for message files */
int batch_size; /* database transaction batch size */
/* options for indexing */
gboolean nocleanup; /* don't cleanup del'd mails from db */
gboolean rebuild; /* empty the database before indexing */
gboolean lazycheck; /* don't check dirs with up-to-date
* timestamps */
gboolean nocleanup; /* don't cleanup del'd mails from db */
gboolean rebuild; /* empty the database before indexing */
gboolean lazycheck; /* don't check dirs with up-to-date
* timestamps */
/* options for querying 'find' (and view-> 'summary') */
gchar *fields; /* fields to show in output */
gchar *sortfield; /* field to sort by (string) */
int maxnum; /* max # of entries to print */
gboolean reverse; /* sort in revers order (z->a) */
gboolean threads; /* show message threads */
gchar* fields; /* fields to show in output */
gchar* sortfield; /* field to sort by (string) */
int maxnum; /* max # of entries to print */
gboolean reverse; /* sort in revers order (z->a) */
gboolean threads; /* show message threads */
gboolean summary; /* OBSOLETE: use summary_len */
int summary_len; /* max # of lines for summary */
gboolean summary; /* OBSOLETE: use summary_len */
int summary_len; /* max # of lines for summary */
gchar *bookmark; /* use bookmark */
gchar *formatstr; /* output type for find
* (plain,links,xml,json,sexp)
* and view (plain, sexp) and cfind
*/
MuConfigFormat format; /* the decoded formatstr */
gchar *exec; /* command to execute on the
* files for the matched
* messages */
gboolean skip_dups; /* if there are multiple
* messages with the same
* msgid, show only the first
* one */
gboolean include_related; /* included related messages
* in results */
gchar* bookmark; /* use bookmark */
gchar* formatstr; /* output type for find
* (plain,links,xml,json,sexp)
* and view (plain, sexp) and cfind
*/
MuConfigFormat format; /* the decoded formatstr */
gchar* exec; /* command to execute on the
* files for the matched
* messages */
gboolean skip_dups; /* if there are multiple
* messages with the same
* msgid, show only the first
* one */
gboolean include_related; /* included related messages
* in results */
/* for find and cind */
time_t after; /* only show messages or
* addresses last seen after
* T */
time_t after; /* only show messages or
* addresses last seen after
* T */
/* options for crypto
* ie, 'view', 'extract' */
gboolean auto_retrieve; /* assume we're online */
gboolean use_agent; /* attempt to use the gpg-agent */
gboolean decrypt; /* try to decrypt the
* message body, if any */
gboolean verify; /* try to crypto-verify the
* message */
gboolean auto_retrieve; /* assume we're online */
gboolean use_agent; /* attempt to use the gpg-agent */
gboolean decrypt; /* try to decrypt the
* message body, if any */
gboolean verify; /* try to crypto-verify the
* message */
/* options for view */
gboolean terminator; /* add separator \f between
* multiple messages in mu
* view */
gboolean terminator; /* add separator \f between
* multiple messages in mu
* view */
/* options for cfind (and 'find' --> "after") */
gboolean personal; /* only show 'personal' addresses */
gboolean personal; /* only show 'personal' addresses */
/* also 'after' --> see above */
/* output to a maildir with symlinks */
gchar *linksdir; /* maildir to output symlinks */
gboolean clearlinks; /* clear a linksdir before filling */
mode_t dirmode; /* mode for the created maildir */
gchar* linksdir; /* maildir to output symlinks */
gboolean clearlinks; /* clear a linksdir before filling */
mode_t dirmode; /* mode for the created maildir */
/* options for extracting parts */
gboolean save_all; /* extract all parts */
gboolean save_attachments; /* extract all attachment parts */
gchar *parts; /* comma-sep'd list of parts
* to save / open */
gchar *targetdir; /* where to save the attachments */
gboolean overwrite; /* should we overwrite same-named files */
gboolean play; /* after saving, try to 'play'
* (open) the attmnt using xdgopen */
gboolean save_all; /* extract all parts */
gboolean save_attachments; /* extract all attachment parts */
gchar* parts; /* comma-sep'd list of parts
* to save / open */
gchar* targetdir; /* where to save the attachments */
gboolean overwrite; /* should we overwrite same-named files */
gboolean play; /* after saving, try to 'play'
* (open) the attmnt using xdgopen */
/* for server */
gboolean commands; /* dump documentations for server
* commands */
gchar *eval; /* command to evaluate */
gboolean commands; /* dump documentations for server
* commands */
gchar* eval; /* command to evaluate */
/* options for mu-script */
gchar *script; /* script to run */
const char **script_params; /* parameters for scripts */
/* options for mu-script */
gchar* script; /* script to run */
const char** script_params; /* parameters for scripts */
};
typedef struct _MuConfig MuConfig;
@ -207,15 +202,13 @@ typedef struct _MuConfig MuConfig;
* @param argvp: pointer to argv
* @param err: receives error information
*/
MuConfig *mu_config_init (int *argcp, char ***argvp, GError **err)
G_GNUC_WARN_UNUSED_RESULT;
MuConfig* mu_config_init(int* argcp, char*** argvp, GError** err) G_GNUC_WARN_UNUSED_RESULT;
/**
* free the MuConfig structure
*
* @param opts a MuConfig struct, or NULL
*/
void mu_config_uninit (MuConfig *conf);
void mu_config_uninit(MuConfig* conf);
/**
* execute the command / options in this config
@ -227,7 +220,7 @@ void mu_config_uninit (MuConfig *conf);
* the exit code of the process
*
*/
MuError mu_config_execute (const MuConfig *conf);
MuError mu_config_execute(const MuConfig* conf);
/**
* count the number of non-option parameters
@ -236,8 +229,7 @@ MuError mu_config_execute (const MuConfig *conf);
*
* @return the number of non-option parameters, or 0 in case of error
*/
size_t mu_config_param_num (const MuConfig *conf);
size_t mu_config_param_num(const MuConfig* conf);
/**
* determine MuMsgOptions for command line args
@ -246,15 +238,14 @@ size_t mu_config_param_num (const MuConfig *conf);
*
* @return the corresponding MuMsgOptions
*/
MuMsgOptions mu_config_get_msg_options (const MuConfig *opts);
MuMsgOptions mu_config_get_msg_options(const MuConfig* opts);
/**
* print help text for the current command
*
* @param cmd the command to show help for
*/
void mu_config_show_help (const MuConfigCmd cmd);
void mu_config_show_help(const MuConfigCmd cmd);
} // namespace Mu.

155
mu/mu.cc
View File

@ -31,110 +31,105 @@
using namespace Mu;
static void
show_version (void)
show_version(void)
{
const char* blurb =
"mu (mail indexer/searcher) version " VERSION "\n"
"Copyright (C) 2008-2021 Dirk-Jan C. Binnema\n"
"License GPLv3+: GNU GPL version 3 or later "
"<http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change "
"and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.";
const char* blurb = "mu (mail indexer/searcher) version " VERSION "\n"
"Copyright (C) 2008-2021 Dirk-Jan C. Binnema\n"
"License GPLv3+: GNU GPL version 3 or later "
"<http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change "
"and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.";
g_print ("%s\n", blurb);
g_print("%s\n", blurb);
}
static void
handle_error (MuConfig *conf, MuError merr, GError **err)
handle_error(MuConfig* conf, MuError merr, GError** err)
{
if (!(err && *err))
return;
if (!(err && *err))
return;
using Color = MaybeAnsi::Color;
MaybeAnsi col{conf ? !conf->nocolor : false};
using Color = MaybeAnsi::Color;
MaybeAnsi col{conf ? !conf->nocolor : false};
if (*err)
std::cerr << col.fg(Color::Red) << "error" << col.reset() << ": "
<< col.fg(Color::BrightYellow)
<< ((*err) ? (*err)->message : "something when wrong")
<< "\n";
if (*err)
std::cerr << col.fg(Color::Red) << "error" << col.reset() << ": "
<< col.fg(Color::BrightYellow)
<< ((*err) ? (*err)->message : "something when wrong") << "\n";
std::cerr << col.fg(Color::Green);
std::cerr << col.fg(Color::Green);
switch ((*err)->code) {
case MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK:
std::cerr << "Maybe mu is already running?\n";
break;
switch ((*err)->code) {
case MU_ERROR_XAPIAN_CANNOT_GET_WRITELOCK:
std::cerr << "Maybe mu is already running?\n";
break;
case MU_ERROR_XAPIAN_NEEDS_REINDEX:
std::cerr << "Database needs (re)indexing.\n"
<< "try 'mu index' "
<< "(see mu-index(1) for details)\n";
return;
case MU_ERROR_IN_PARAMETERS:
if (conf && mu_config_cmd_is_valid(conf->cmd))
mu_config_show_help (conf->cmd);
break;
case MU_ERROR_SCRIPT_NOT_FOUND:
std::cerr << "See the mu manpage for commands, or "
<< "'mu script' for the scripts\n";
break;
case MU_ERROR_XAPIAN_CANNOT_OPEN:
std::cerr << "Please (re)initialize mu with 'mu init' "
<< "see mu-init(1) for details\n";
return;
case MU_ERROR_XAPIAN_SCHEMA_MISMATCH:
std::cerr << "Please (re)initialize mu with 'mu init' "
<< "see mu-init(1) for details\n";
return;
default:
break; /* nothing to do */
}
case MU_ERROR_XAPIAN_NEEDS_REINDEX:
std::cerr << "Database needs (re)indexing.\n"
<< "try 'mu index' "
<< "(see mu-index(1) for details)\n";
return;
case MU_ERROR_IN_PARAMETERS:
if (conf && mu_config_cmd_is_valid(conf->cmd))
mu_config_show_help(conf->cmd);
break;
case MU_ERROR_SCRIPT_NOT_FOUND:
std::cerr << "See the mu manpage for commands, or "
<< "'mu script' for the scripts\n";
break;
case MU_ERROR_XAPIAN_CANNOT_OPEN:
std::cerr << "Please (re)initialize mu with 'mu init' "
<< "see mu-init(1) for details\n";
return;
case MU_ERROR_XAPIAN_SCHEMA_MISMATCH:
std::cerr << "Please (re)initialize mu with 'mu init' "
<< "see mu-init(1) for details\n";
return;
default: break; /* nothing to do */
}
std::cerr << col.reset();
std::cerr << col.reset();
}
int
main (int argc, char *argv[])
main(int argc, char* argv[])
{
GError *err;
MuError rv;
MuConfig *conf;
GError* err;
MuError rv;
MuConfig* conf;
setlocale (LC_ALL, "");
setlocale(LC_ALL, "");
err = NULL;
rv = MU_OK;
err = NULL;
rv = MU_OK;
conf = mu_config_init (&argc, &argv, &err);
if (!conf) {
rv = err ? (MuError)err->code : MU_ERROR;
goto cleanup;
} else if (conf->version) {
show_version ();
goto cleanup;
}
conf = mu_config_init(&argc, &argv, &err);
if (!conf) {
rv = err ? (MuError)err->code : MU_ERROR;
goto cleanup;
} else if (conf->version) {
show_version();
goto cleanup;
}
/* nothing to do */
if (conf->cmd == MU_CONFIG_CMD_NONE)
return 0;
/* nothing to do */
if (conf->cmd == MU_CONFIG_CMD_NONE)
return 0;
if (!mu_runtime_init (conf->muhome, PACKAGE_NAME, conf->debug)) {
mu_config_uninit (conf);
return 1;
}
if (!mu_runtime_init(conf->muhome, PACKAGE_NAME, conf->debug)) {
mu_config_uninit(conf);
return 1;
}
rv = mu_cmd_execute (conf, &err);
rv = mu_cmd_execute(conf, &err);
cleanup:
handle_error (conf, rv, &err);
g_clear_error (&err);
handle_error(conf, rv, &err);
g_clear_error(&err);
mu_config_uninit (conf);
mu_runtime_uninit ();
mu_config_uninit(conf);
mu_runtime_uninit();
return rv;
return rv;
}

View File

@ -31,338 +31,327 @@
#include "mu-store.hh"
#include "mu-query.hh"
static gchar *CONTACTS_CACHE = NULL;
static gchar* CONTACTS_CACHE = NULL;
static gchar*
fill_contacts_cache (void)
fill_contacts_cache(void)
{
gchar *cmdline, *tmpdir;
GError *err;
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_TESTMAILDIR,
MU_PROGRAM, tmpdir);
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_TESTMAILDIR,
MU_PROGRAM,
tmpdir);
if (g_test_verbose())
g_print ("%s\n", cmdline);
g_print("%s\n", cmdline);
err = NULL;
if (!g_spawn_command_line_sync (cmdline, NULL, NULL,
NULL, &err)) {
g_printerr ("Error: %s\n", err ? err->message : "?");
g_assert (0);
err = NULL;
if (!g_spawn_command_line_sync(cmdline, NULL, NULL, NULL, &err)) {
g_printerr("Error: %s\n", err ? err->message : "?");
g_assert(0);
}
g_free (cmdline);
g_free(cmdline);
return tmpdir;
}
static void
test_mu_cfind_plain (void)
test_mu_cfind_plain(void)
{
gchar *cmdline, *output, *erroutput;
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=plain "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=plain "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
if (g_test_verbose())
g_print ("%s\n", cmdline);
g_print("%s\n", cmdline);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
/* note, output order is unspecified */
g_assert (output);
g_assert(output);
if (output[0] == 'H')
g_assert_cmpstr (output,
==,
"Helmut Kröger hk@testmu.xxx\n"
"Mü testmu@testmu.xx\n");
g_assert_cmpstr(output,
==,
"Helmut Kröger hk@testmu.xxx\n"
"Mü testmu@testmu.xx\n");
else
g_assert_cmpstr (output,
==,
"Mü testmu@testmu.xx\n"
"Helmut Kröger hk@testmu.xxx\n");
g_free (cmdline);
g_free (output);
g_free (erroutput);
g_assert_cmpstr(output,
==,
"Mü testmu@testmu.xx\n"
"Helmut Kröger hk@testmu.xxx\n");
g_free(cmdline);
g_free(output);
g_free(erroutput);
}
static void
test_mu_cfind_bbdb (void)
test_mu_cfind_bbdb(void)
{
gchar *cmdline, *output, *erroutput, *expected;
gchar today[12];
struct tm *tmtoday;
time_t now;
const char *old_tz;
gchar * cmdline, *output, *erroutput, *expected;
gchar today[12];
struct tm* tmtoday;
time_t now;
const char* old_tz;
old_tz = set_tz ("Europe/Helsinki");
old_tz = set_tz("Europe/Helsinki");
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=bbdb "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=bbdb "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
#define frm1 ";; -*-coding: utf-8-emacs;-*-\n" \
";;; file-version: 6\n" \
"[\"Helmut\" \"Kröger\" nil nil nil nil (\"hk@testmu.xxx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n" \
"[\"Mü\" \"\" nil nil nil nil (\"testmu@testmu.xx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n"
#define frm1 \
";; -*-coding: utf-8-emacs;-*-\n" \
";;; file-version: 6\n" \
"[\"Helmut\" \"Kröger\" nil nil nil nil (\"hk@testmu.xxx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n" \
"[\"Mü\" \"\" nil nil nil nil (\"testmu@testmu.xx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n"
#define frm2 \
";; -*-coding: utf-8-emacs;-*-\n" \
";;; file-version: 6\n" \
"[\"Mü\" \"\" nil nil nil nil (\"testmu@testmu.xx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n" \
"[\"Helmut\" \"Kröger\" nil nil nil nil (\"hk@testmu.xxx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n"
#define frm2 ";; -*-coding: utf-8-emacs;-*-\n" \
";;; file-version: 6\n" \
"[\"Mü\" \"\" nil nil nil nil (\"testmu@testmu.xx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n" \
"[\"Helmut\" \"Kröger\" nil nil nil nil (\"hk@testmu.xxx\") " \
"((creation-date . \"%s\") " \
"(time-stamp . \"1970-01-01\")) nil]\n"
g_assert(output);
g_assert (output);
now = time(NULL);
now = time(NULL);
tmtoday = localtime(&now);
strftime(today,sizeof(today),"%Y-%m-%d", tmtoday);
strftime(today, sizeof(today), "%Y-%m-%d", tmtoday);
expected = g_strdup_printf (output[52] == 'H' ? frm1 : frm2,
today, today);
expected = g_strdup_printf(output[52] == 'H' ? frm1 : frm2, today, today);
/* g_print ("\n%s\n", output); */
g_assert_cmpstr (output, ==, expected);
g_assert_cmpstr(output, ==, expected);
g_free (cmdline);
g_free (output);
g_free (erroutput);
g_free (expected);
g_free(cmdline);
g_free(output);
g_free(erroutput);
g_free(expected);
set_tz (old_tz);
set_tz(old_tz);
}
static void
test_mu_cfind_wl (void)
test_mu_cfind_wl(void)
{
gchar *cmdline, *output, *erroutput;
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=wl "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=wl "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
g_assert (output);
g_assert(output);
if (output[0] == 'h')
g_assert_cmpstr (output,
==,
"hk@testmu.xxx \"HelmutK\" \"Helmut Kröger\"\n"
"testmu@testmu.xx \"\" \"\"\n");
g_assert_cmpstr(output,
==,
"hk@testmu.xxx \"HelmutK\" \"Helmut Kröger\"\n"
"testmu@testmu.xx \"\" \"\"\n");
else
g_assert_cmpstr (output,
==,
"testmu@testmu.xx \"\" \"\"\n"
"hk@testmu.xxx \"HelmutK\" \"Helmut Kröger\"\n");
g_assert_cmpstr(output,
==,
"testmu@testmu.xx \"\" \"\"\n"
"hk@testmu.xxx \"HelmutK\" \"Helmut Kröger\"\n");
g_free (cmdline);
g_free (output);
g_free (erroutput);
g_free(cmdline);
g_free(output);
g_free(erroutput);
}
static void
test_mu_cfind_mutt_alias (void)
test_mu_cfind_mutt_alias(void)
{
gchar *cmdline, *output, *erroutput;
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=mutt-alias "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=mutt-alias "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
/* both orders are possible... */
g_assert (output);
g_assert(output);
if (output[6] == 'H')
g_assert_cmpstr (output,
==,
"alias HelmutK Helmut Kröger <hk@testmu.xxx>\n"
"alias Mü Mü <testmu@testmu.xx>\n");
g_assert_cmpstr(output,
==,
"alias HelmutK Helmut Kröger <hk@testmu.xxx>\n"
"alias Mü Mü <testmu@testmu.xx>\n");
else
g_assert_cmpstr (output,
==,
"alias Mü Mü <testmu@testmu.xx>\n"
"alias HelmutK Helmut Kröger <hk@testmu.xxx>\n");
g_assert_cmpstr(output,
==,
"alias Mü Mü <testmu@testmu.xx>\n"
"alias HelmutK Helmut Kröger <hk@testmu.xxx>\n");
g_free (cmdline);
g_free (output);
g_free (erroutput);
g_free(cmdline);
g_free(output);
g_free(erroutput);
}
static void
test_mu_cfind_mutt_ab (void)
test_mu_cfind_mutt_ab(void)
{
gchar *cmdline, *output, *erroutput;
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=mutt-ab "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=mutt-ab "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
if (g_test_verbose())
g_print("%s\n", cmdline);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert (output);
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
g_assert(output);
if (output[39] == 'h')
g_assert_cmpstr (output,
==,
"Matching addresses in the mu database:\n"
"hk@testmu.xxx\tHelmut Kröger\t\n"
"testmu@testmu.xx\t\t\n");
g_assert_cmpstr(output,
==,
"Matching addresses in the mu database:\n"
"hk@testmu.xxx\tHelmut Kröger\t\n"
"testmu@testmu.xx\t\t\n");
else
g_assert_cmpstr (output,
==,
"Matching addresses in the mu database:\n"
"testmu@testmu.xx\t\t\n"
"hk@testmu.xxx\tHelmut Kröger\t\n");
g_assert_cmpstr(output,
==,
"Matching addresses in the mu database:\n"
"testmu@testmu.xx\t\t\n"
"hk@testmu.xxx\tHelmut Kröger\t\n");
g_free (cmdline);
g_free (output);
g_free (erroutput);
g_free(cmdline);
g_free(output);
g_free(erroutput);
}
static void
test_mu_cfind_org_contact (void)
{
gchar*cmdline, *output, *erroutput;
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=org-contact "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert (output);
if (output[2] == 'H')
g_assert_cmpstr (output,
==,
"* Helmut Kröger\n"
":PROPERTIES:\n"
":EMAIL: hk@testmu.xxx\n"
":END:\n\n"
"* Mü\n"
":PROPERTIES:\n"
":EMAIL: testmu@testmu.xx\n"
":END:\n\n");
else
g_assert_cmpstr (output,
==,
"* Mü\n"
":PROPERTIES:\n"
":EMAIL: testmu@testmu.xx\n"
":END:\n\n"
"* Helmut Kröger\n"
":PROPERTIES:\n"
":EMAIL: hk@testmu.xxx\n"
":END:\n\n");
g_free (cmdline);
g_free (output);
g_free (erroutput);
}
static void
test_mu_cfind_csv (void)
test_mu_cfind_org_contact(void)
{
gchar *cmdline, *output, *erroutput;
cmdline = g_strdup_printf ("%s cfind --muhome=%s --format=csv "
"'testmu\\.xxx?'",
MU_PROGRAM, CONTACTS_CACHE);
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=org-contact "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
output = erroutput = NULL;
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
g_assert(output);
if (output[2] == 'H')
g_assert_cmpstr(output,
==,
"* Helmut Kröger\n"
":PROPERTIES:\n"
":EMAIL: hk@testmu.xxx\n"
":END:\n\n"
"* Mü\n"
":PROPERTIES:\n"
":EMAIL: testmu@testmu.xx\n"
":END:\n\n");
else
g_assert_cmpstr(output,
==,
"* Mü\n"
":PROPERTIES:\n"
":EMAIL: testmu@testmu.xx\n"
":END:\n\n"
"* Helmut Kröger\n"
":PROPERTIES:\n"
":EMAIL: hk@testmu.xxx\n"
":END:\n\n");
g_free(cmdline);
g_free(output);
g_free(erroutput);
}
static void
test_mu_cfind_csv(void)
{
gchar *cmdline, *output, *erroutput;
cmdline = g_strdup_printf("%s cfind --muhome=%s --format=csv "
"'testmu\\.xxx?'",
MU_PROGRAM,
CONTACTS_CACHE);
if (g_test_verbose())
g_print("%s\n", cmdline);
output = erroutput = NULL;
g_assert (g_spawn_command_line_sync (cmdline, &output, &erroutput,
NULL, NULL));
g_assert (output);
g_assert(g_spawn_command_line_sync(cmdline, &output, &erroutput, NULL, NULL));
g_assert(output);
if (output[1] == 'H')
g_assert_cmpstr (output,
==,
"\"Helmut Kröger\",\"hk@testmu.xxx\"\n"
"\"\",\"testmu@testmu.xx\"\n");
g_assert_cmpstr(output,
==,
"\"Helmut Kröger\",\"hk@testmu.xxx\"\n"
"\"\",\"testmu@testmu.xx\"\n");
else
g_assert_cmpstr (output,
==,
"\"\",\"testmu@testmu.xx\"\n"
"\"Helmut Kröger\",\"hk@testmu.xxx\"\n");
g_free (cmdline);
g_free (output);
g_free (erroutput);
g_assert_cmpstr(output,
==,
"\"\",\"testmu@testmu.xx\"\n"
"\"Helmut Kröger\",\"hk@testmu.xxx\"\n");
g_free(cmdline);
g_free(output);
g_free(erroutput);
}
int
main (int argc, char *argv[])
main(int argc, char* argv[])
{
int rv;
g_test_init (&argc, &argv, NULL);
g_test_init(&argc, &argv, NULL);
if (!set_en_us_utf8_locale())
return 0; /* don't error out... */
CONTACTS_CACHE = fill_contacts_cache ();
CONTACTS_CACHE = fill_contacts_cache();
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-plain", test_mu_cfind_plain);
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-bbdb", test_mu_cfind_bbdb);
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-wl", test_mu_cfind_wl);
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-mutt-alias",
test_mu_cfind_mutt_alias);
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-mutt-ab",
test_mu_cfind_mutt_ab);
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-org-contact",
test_mu_cfind_org_contact);
g_test_add_func ("/mu-cmd-cfind/test-mu-cfind-csv",
test_mu_cfind_csv);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-plain", test_mu_cfind_plain);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-bbdb", test_mu_cfind_bbdb);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-wl", test_mu_cfind_wl);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-mutt-alias", test_mu_cfind_mutt_alias);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-mutt-ab", test_mu_cfind_mutt_ab);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-org-contact", test_mu_cfind_org_contact);
g_test_add_func("/mu-cmd-cfind/test-mu-cfind-csv", test_mu_cfind_csv);
g_log_set_handler (NULL,
(GLogLevelFlags)(
G_LOG_LEVEL_MASK | G_LOG_LEVEL_WARNING|
G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION),
(GLogFunc)black_hole, NULL);
g_log_set_handler(NULL,
(GLogLevelFlags)(G_LOG_LEVEL_MASK | G_LOG_LEVEL_WARNING |
G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION),
(GLogFunc)black_hole,
NULL);
rv = g_test_run ();
rv = g_test_run();
g_free (CONTACTS_CACHE);
g_free(CONTACTS_CACHE);
CONTACTS_CACHE = NULL;
return rv;

File diff suppressed because it is too large Load Diff

View File

@ -42,24 +42,24 @@ static std::string DB_PATH1;
static std::string DB_PATH2;
static std::string
make_database (const std::string& testdir)
make_database(const std::string& testdir)
{
char *tmpdir{test_mu_common_get_random_tmpdir()};
const auto cmdline{
format("/bin/sh -c '"
"%s init --muhome=%s --maildir=%s --quiet ; "
"%s index --muhome=%s --quiet'",
MU_PROGRAM, tmpdir, testdir.c_str(),
MU_PROGRAM, tmpdir)};
char* tmpdir{test_mu_common_get_random_tmpdir()};
const auto cmdline{format("/bin/sh -c '"
"%s init --muhome=%s --maildir=%s --quiet ; "
"%s index --muhome=%s --quiet'",
MU_PROGRAM,
tmpdir,
testdir.c_str(),
MU_PROGRAM,
tmpdir)};
if (g_test_verbose())
g_printerr ("\n%s\n", cmdline.c_str());
g_printerr("\n%s\n", cmdline.c_str());
g_assert (g_spawn_command_line_sync (cmdline.c_str(), NULL, NULL,
NULL, NULL));
auto xpath= g_strdup_printf ("%s%c%s", tmpdir, G_DIR_SEPARATOR, "xapian");
g_free (tmpdir);
g_assert(g_spawn_command_line_sync(cmdline.c_str(), NULL, NULL, NULL, NULL));
auto xpath = g_strdup_printf("%s%c%s", tmpdir, G_DIR_SEPARATOR, "xapian");
g_free(tmpdir);
std::string dbpath{xpath};
g_free(xpath);
@ -67,518 +67,476 @@ make_database (const std::string& testdir)
return dbpath;
}
static void
assert_no_dups (const QueryResults& qres)
assert_no_dups(const QueryResults& qres)
{
std::unordered_set<std::string> msgid_set, path_set;
std::unordered_set<std::string> msgid_set, path_set;
for (auto&& mi: qres) {
g_assert_true(msgid_set.find(mi.message_id().value()) == msgid_set.end());
g_assert_true(path_set.find(mi.path().value()) == path_set.end());
for (auto&& mi : qres) {
g_assert_true(msgid_set.find(mi.message_id().value()) == msgid_set.end());
g_assert_true(path_set.find(mi.path().value()) == path_set.end());
path_set.emplace(*mi.path());
msgid_set.emplace(*mi.message_id());
path_set.emplace(*mi.path());
msgid_set.emplace(*mi.message_id());
g_assert_false(msgid_set.find(mi.message_id().value()) == msgid_set.end());
g_assert_false(path_set.find(mi.path().value()) == path_set.end());
}
g_assert_false(msgid_set.find(mi.message_id().value()) == msgid_set.end());
g_assert_false(path_set.find(mi.path().value()) == path_set.end());
}
}
/* note: this also *moves the iter* */
static size_t
run_and_count_matches (const std::string& xpath, const std::string& expr,
Mu::QueryFlags flags = Mu::QueryFlags::None)
run_and_count_matches(const std::string& xpath,
const std::string& expr,
Mu::QueryFlags flags = Mu::QueryFlags::None)
{
Mu::Store store{xpath};
Mu::Query query{store};
if (g_test_verbose()) {
std::cout << "==> mquery: " << query.parse (expr, false) << "\n";
std::cout << "==> xquery: " << query.parse (expr, true) << "\n";
std::cout << "==> mquery: " << query.parse(expr, false) << "\n";
std::cout << "==> xquery: " << query.parse(expr, true) << "\n";
}
Mu::allow_warnings();
auto qres{query.run (expr, MU_MSG_FIELD_ID_NONE, flags)};
g_assert_true (!!qres);
assert_no_dups (*qres);
auto qres{query.run(expr, MU_MSG_FIELD_ID_NONE, flags)};
g_assert_true(!!qres);
assert_no_dups(*qres);
return qres->size();
}
typedef struct {
const char *query;
size_t count; /* expected number of matches */
typedef struct {
const char* query;
size_t count; /* expected number of matches */
} QResults;
static void
test_mu_query_01 (void)
test_mu_query_01(void)
{
int i;
int i;
QResults queries[] = {
{ "basic", 3 },
{ "question", 5 },
{ "thanks", 2 },
{ "html", 4 },
{ "subject:exception", 1 },
{ "exception", 1 },
{ "subject:A&B", 1 },
{ "A&B", 1 },
{ "subject:elisp", 1 },
{ "html AND contains", 1 },
{ "html and contains", 1 },
{ "from:pepernoot", 0 },
{ "foo:pepernoot", 0 },
{ "funky", 1 },
{ "fünkÿ", 1 },
// { "", 18 },
{ "msgid:abcd$efgh@example.com", 1},
{ "i:abcd$efgh@example.com", 1},
{"basic", 3},
{"question", 5},
{"thanks", 2},
{"html", 4},
{"subject:exception", 1},
{"exception", 1},
{"subject:A&B", 1},
{"A&B", 1},
{"subject:elisp", 1},
{"html AND contains", 1},
{"html and contains", 1},
{"from:pepernoot", 0},
{"foo:pepernoot", 0},
{"funky", 1},
{"fünkÿ", 1},
// { "", 18 },
{"msgid:abcd$efgh@example.com", 1},
{"i:abcd$efgh@example.com", 1},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_02 (void)
test_mu_query_02(void)
{
const char* q;
q = "i:f7ccd24b0808061357t453f5962w8b61f9a453b684d0@mail.gmail.com";
g_assert_cmpuint (run_and_count_matches (DB_PATH1, q), ==, 1);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, q), ==, 1);
}
static void
test_mu_query_03 (void)
test_mu_query_03(void)
{
int i;
QResults queries[] = {
{ "ploughed", 1},
{ "i:3BE9E6535E3029448670913581E7A1A20D852173@"
"emss35m06.us.lmco.com", 1},
{ "i:!&!AAAAAAAAAYAAAAAAAAAOH1+8mkk+lLn7Gg5fke7"
"FbCgAAAEAAAAJ7eBDgcactKhXL6r8cEnJ8BAAAAAA==@"
"example.com", 1},
int i;
QResults queries[] = {{"ploughed", 1},
{"i:3BE9E6535E3029448670913581E7A1A20D852173@"
"emss35m06.us.lmco.com",
1},
{"i:!&!AAAAAAAAAYAAAAAAAAAOH1+8mkk+lLn7Gg5fke7"
"FbCgAAAEAAAAJ7eBDgcactKhXL6r8cEnJ8BAAAAAA==@"
"example.com",
1},
/* subsets of the words in the subject should match */
{ "s:gcc include search order" , 1},
{ "s:gcc include search" , 1},
{ "s:search order" , 1},
{ "s:include" , 1},
/* subsets of the words in the subject should match */
{"s:gcc include search order", 1},
{"s:gcc include search", 1},
{"s:search order", 1},
{"s:include", 1},
{ "s:lisp", 1},
{ "s:LISP", 1},
{"s:lisp", 1},
{"s:LISP", 1},
/* { "s:\"Re: Learning LISP; Scheme vs elisp.\"", 1}, */
/* { "subject:Re: Learning LISP; Scheme vs elisp.", 1}, */
/* { "subject:\"Re: Learning LISP; Scheme vs elisp.\"", 1}, */
{ "to:help-gnu-emacs@gnu.org", 4},
{ "t:help-gnu-emacs", 4},
{ "flag:flagged", 1}
};
/* { "s:\"Re: Learning LISP; Scheme vs elisp.\"", 1}, */
/* { "subject:Re: Learning LISP; Scheme vs elisp.", 1}, */
/* { "subject:\"Re: Learning LISP; Scheme vs elisp.\"", 1}, */
{"to:help-gnu-emacs@gnu.org", 4},
{"t:help-gnu-emacs", 4},
{"flag:flagged", 1}};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_04 (void)
test_mu_query_04(void)
{
int i;
QResults queries[] = {
{ "frodo@example.com", 1},
{ "f:frodo@example.com", 1},
{ "f:Frodo Baggins", 1},
{ "bilbo@anotherexample.com", 1},
{ "t:bilbo@anotherexample.com", 1},
{ "t:bilbo", 1},
{ "f:bilbo", 0},
{ "baggins", 1},
{ "prio:h", 1},
{ "prio:high", 1},
{ "prio:normal", 11},
{ "prio:l", 7},
{ "not prio:l", 12},
{"frodo@example.com", 1},
{"f:frodo@example.com", 1},
{"f:Frodo Baggins", 1},
{"bilbo@anotherexample.com", 1},
{"t:bilbo@anotherexample.com", 1},
{"t:bilbo", 1},
{"f:bilbo", 0},
{"baggins", 1},
{"prio:h", 1},
{"prio:high", 1},
{"prio:normal", 11},
{"prio:l", 7},
{"not prio:l", 12},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_logic (void)
test_mu_query_logic(void)
{
int i;
QResults queries[] = {
{ "subject:gcc" , 1},
{ "subject:lisp" , 1},
{ "subject:gcc OR subject:lisp" , 2},
{ "subject:gcc or subject:lisp" , 2},
{ "subject:gcc AND subject:lisp" , 0},
int i;
QResults queries[] = {{"subject:gcc", 1},
{"subject:lisp", 1},
{"subject:gcc OR subject:lisp", 2},
{"subject:gcc or subject:lisp", 2},
{"subject:gcc AND subject:lisp", 0},
{ "subject:gcc OR (subject:scheme AND subject:elisp)" , 2},
{ "(subject:gcc OR subject:scheme) AND subject:elisp" , 1}
};
{"subject:gcc OR (subject:scheme AND subject:elisp)", 2},
{"(subject:gcc OR subject:scheme) AND subject:elisp", 1}};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_accented_chars_01 (void)
test_mu_query_accented_chars_01(void)
{
Store store{DB_PATH1};
Query q{store};
auto qres{q.run("fünkÿ")};
g_assert_true(!!qres);
g_assert_false(qres->empty());
auto qres{q.run("fünkÿ")};
g_assert_true(!!qres);
g_assert_false(qres->empty());
auto begin{qres->begin()};
auto msg{begin.floating_msg()};
auto begin{qres->begin()};
auto msg{begin.floating_msg()};
if (!msg) {
g_warning ("error getting message");
g_assert_not_reached ();
g_warning("error getting message");
g_assert_not_reached();
}
g_assert_cmpstr (mu_msg_get_subject(msg),==,
"Greetings from Lothlórien");
g_assert_cmpstr(mu_msg_get_subject(msg), ==, "Greetings from Lothlórien");
/* TODO: fix this again */
auto summ = mu_str_summarize (mu_msg_get_body_text
(msg, MU_MSG_OPTION_NONE), 5);
g_assert_cmpstr (summ,==,
"Let's write some fünkÿ text using umlauts. Foo.");
g_free (summ);
auto summ = mu_str_summarize(mu_msg_get_body_text(msg, MU_MSG_OPTION_NONE), 5);
g_assert_cmpstr(summ, ==, "Let's write some fünkÿ text using umlauts. Foo.");
g_free(summ);
}
static void
test_mu_query_accented_chars_02 (void)
test_mu_query_accented_chars_02(void)
{
int i;
QResults queries[] = {
{ "f:mü", 1},
{ "s:motörhead", 1},
{ "t:Helmut", 1},
{ "t:Kröger", 1},
{ "s:MotorHeäD", 1},
{ "queensryche", 1},
{ "Queensrÿche", 1}
};
QResults queries[] = {{"f:mü", 1},
{"s:motörhead", 1},
{"t:Helmut", 1},
{"t:Kröger", 1},
{"s:MotorHeäD", 1},
{"queensryche", 1},
{"Queensrÿche", 1}};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_accented_chars_fraiche (void)
test_mu_query_accented_chars_fraiche(void)
{
int i;
QResults queries[] = {
{ "crème fraîche", 1},
{ "creme fraiche", 1},
{ "fraîche crème", 1},
{ "будланула", 1},
{ "БУДЛАНУЛА", 1},
{ "CRÈME FRAÎCHE", 1},
{ "CREME FRAICHE", 1}
};
QResults queries[] = {{"crème fraîche", 1},
{"creme fraiche", 1},
{"fraîche crème", 1},
{"будланула", 1},
{"БУДЛАНУЛА", 1},
{"CRÈME FRAÎCHE", 1},
{"CREME FRAICHE", 1}};
for (i = 0; i != G_N_ELEMENTS(queries); ++i) {
if (g_test_verbose())
g_print("'%s'\n", queries[i].query);
if (g_test_verbose ())
g_print ("'%s'\n", queries[i].query);
g_assert_cmpuint (run_and_count_matches (DB_PATH2,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH2, queries[i].query),
==,
queries[i].count);
}
}
static void
test_mu_query_wildcards (void)
test_mu_query_wildcards(void)
{
int i;
QResults queries[] = {
{ "f:mü", 1},
{ "s:mo*", 1},
{ "t:Helm*", 1},
{ "queensryche", 1},
{ "Queen*", 1},
{"f:mü", 1},
{"s:mo*", 1},
{"t:Helm*", 1},
{"queensryche", 1},
{"Queen*", 1},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
}
static void
test_mu_query_dates_helsinki (void)
{
int i;
const char *old_tz;
QResults queries[] = {
{ "date:20080731..20080804", 5},
{ "date:20080731..20080804 s:gcc", 1},
{ "date:200808110803..now", 7},
{ "date:200808110803..today",7},
{ "date:200808110801..now", 7}
};
old_tz = set_tz ("Europe/Helsinki");
const auto xpath{make_database (MU_TESTMAILDIR)};
g_assert_false (xpath.empty());
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches
(xpath, queries[i].query),
==, queries[i].count);
set_tz (old_tz);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_dates_sydney (void)
test_mu_query_dates_helsinki(void)
{
int i;
const char *old_tz;
QResults queries[] = {
{ "date:20080731..20080804", 5},
{ "date:20080731..20080804 s:gcc", 1},
{ "date:200808110803..now", 7},
{ "date:200808110803..today", 7},
{ "date:200808110801..now", 7}
};
int i;
const char* old_tz;
old_tz = set_tz ("Australia/Sydney");
QResults queries[] = {{"date:20080731..20080804", 5},
{"date:20080731..20080804 s:gcc", 1},
{"date:200808110803..now", 7},
{"date:200808110803..today", 7},
{"date:200808110801..now", 7}};
old_tz = set_tz("Europe/Helsinki");
const auto xpath{make_database(MU_TESTMAILDIR)};
g_assert_false (xpath.empty());
g_assert_false(xpath.empty());
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches
(xpath, queries[i].query),
==, queries[i].count);
set_tz (old_tz);
g_assert_cmpuint(run_and_count_matches(xpath, queries[i].query),
==,
queries[i].count);
set_tz(old_tz);
}
static void
test_mu_query_dates_la (void)
test_mu_query_dates_sydney(void)
{
int i;
const char *old_tz;
int i;
const char* old_tz;
QResults queries[] = {{"date:20080731..20080804", 5},
{"date:20080731..20080804 s:gcc", 1},
{"date:200808110803..now", 7},
{"date:200808110803..today", 7},
{"date:200808110801..now", 7}};
QResults queries[] = {
{ "date:20080731..20080804", 5},
{ "date:2008-07-31..2008-08-04", 5},
{ "date:20080804..20080731", 5},
{ "date:20080731..20080804 s:gcc", 1},
{ "date:200808110803..now", 6},
{ "date:200808110803..today", 6},
{ "date:200808110801..now", 6}
};
old_tz = set_tz("Australia/Sydney");
old_tz = set_tz ("America/Los_Angeles");
const auto xpath{make_database(MU_TESTMAILDIR)};
g_assert_false(xpath.empty());
const auto xpath = make_database (MU_TESTMAILDIR);
g_assert_false (xpath.empty());
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint(run_and_count_matches(xpath, queries[i].query),
==,
queries[i].count);
set_tz(old_tz);
}
static void
test_mu_query_dates_la(void)
{
int i;
const char* old_tz;
QResults queries[] = {{"date:20080731..20080804", 5},
{"date:2008-07-31..2008-08-04", 5},
{"date:20080804..20080731", 5},
{"date:20080731..20080804 s:gcc", 1},
{"date:200808110803..now", 6},
{"date:200808110803..today", 6},
{"date:200808110801..now", 6}};
old_tz = set_tz("America/Los_Angeles");
const auto xpath = make_database(MU_TESTMAILDIR);
g_assert_false(xpath.empty());
for (i = 0; i != G_N_ELEMENTS(queries); ++i) {
/* g_print ("%s\n", queries[i].query); */
g_assert_cmpuint (run_and_count_matches
(xpath, queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(xpath, queries[i].query),
==,
queries[i].count);
}
set_tz (old_tz);
set_tz(old_tz);
}
static void
test_mu_query_sizes (void)
test_mu_query_sizes(void)
{
int i;
int i;
QResults queries[] = {
{ "size:0b..2m", 19},
{ "size:3b..2m", 19},
{ "size:2k..4k", 4},
{"size:0b..2m", 19},
{"size:3b..2m", 19},
{"size:2k..4k", 4},
{ "size:0b..2m", 19},
{ "size:2m..0b", 19},
{"size:0b..2m", 19},
{"size:2m..0b", 19},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_attach (void)
test_mu_query_attach(void)
{
int i;
QResults queries[] = {
{ "j:sittingbull.jpg", 1},
{ "file:custer", 0},
{ "file:custer.jpg", 1}
};
int i;
QResults queries[] = {{"j:sittingbull.jpg", 1}, {"file:custer", 0}, {"file:custer.jpg", 1}};
for (i = 0; i != G_N_ELEMENTS(queries); ++i) {
if (g_test_verbose())
g_print ("query: %s\n", queries[i].query);
g_assert_cmpuint (run_and_count_matches (DB_PATH2,
queries[i].query),
==, queries[i].count);
g_print("query: %s\n", queries[i].query);
g_assert_cmpuint(run_and_count_matches(DB_PATH2, queries[i].query),
==,
queries[i].count);
}
}
static void
test_mu_query_msgid (void)
test_mu_query_msgid(void)
{
int i;
int i;
QResults queries[] = {
{ "i:CAHSaMxZ9rk5ASjqsbXizjTQuSk583=M6TORHz"
"=bfogtmbGGs5A@mail.gmail.com", 1},
{ "msgid:CAHSaMxZ9rk5ASjqsbXizjTQuSk583=M6TORHz="
"bfogtmbGGs5A@mail.gmail.com", 1},
{"i:CAHSaMxZ9rk5ASjqsbXizjTQuSk583=M6TORHz"
"=bfogtmbGGs5A@mail.gmail.com",
1},
{"msgid:CAHSaMxZ9rk5ASjqsbXizjTQuSk583=M6TORHz="
"bfogtmbGGs5A@mail.gmail.com",
1},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i) {
if (g_test_verbose())
g_print ("query: %s\n", queries[i].query);
g_assert_cmpuint (run_and_count_matches (DB_PATH2,
queries[i].query),
==, queries[i].count);
g_print("query: %s\n", queries[i].query);
g_assert_cmpuint(run_and_count_matches(DB_PATH2, queries[i].query),
==,
queries[i].count);
}
}
static void
test_mu_query_tags (void)
test_mu_query_tags(void)
{
int i;
int i;
QResults queries[] = {
{ "x:paradise", 1},
{ "tag:lost", 1},
{ "tag:lost tag:paradise", 1},
{ "tag:lost tag:horizon", 0},
{ "tag:lost OR tag:horizon", 1},
{ "x:paradise,lost", 0},
{ "x:paradise AND x:lost", 1},
{ "x:\\\\backslash", 1},
{"x:paradise", 1},
{"tag:lost", 1},
{"tag:lost tag:paradise", 1},
{"tag:lost tag:horizon", 0},
{"tag:lost OR tag:horizon", 1},
{"x:paradise,lost", 0},
{"x:paradise AND x:lost", 1},
{"x:\\\\backslash", 1},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH2,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH2, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_wom_bat (void)
test_mu_query_wom_bat(void)
{
int i;
int i;
QResults queries[] = {
{ "maildir:/wom_bat", 3},
//{ "\"maildir:/wom bat\"", 3},
// as expected, no longer works with new parser
{"maildir:/wom_bat", 3},
//{ "\"maildir:/wom bat\"", 3},
// as expected, no longer works with new parser
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH2,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH2, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_signed_encrypted (void)
test_mu_query_signed_encrypted(void)
{
int i;
int i;
QResults queries[] = {
{ "flag:encrypted", 2},
{ "flag:signed", 2},
{"flag:encrypted", 2},
{"flag:signed", 2},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_multi_to_cc (void)
test_mu_query_multi_to_cc(void)
{
int i;
int i;
QResults queries[] = {
{ "to:a@example.com", 1},
{ "cc:d@example.com", 1},
{ "to:b@example.com", 1},
{ "cc:e@example.com", 1},
{ "cc:e@example.com AND cc:d@example.com", 1},
{"to:a@example.com", 1},
{"cc:d@example.com", 1},
{"to:b@example.com", 1},
{"cc:e@example.com", 1},
{"cc:e@example.com AND cc:d@example.com", 1},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i)
g_assert_cmpuint (run_and_count_matches (DB_PATH1,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH1, queries[i].query),
==,
queries[i].count);
}
static void
test_mu_query_tags_02 (void)
test_mu_query_tags_02(void)
{
int i;
int i;
QResults queries[] = {
{ "x:paradise", 1},
{ "tag:@NextActions", 1},
{ "x:queensrÿche", 1},
{ "tag:lost OR tag:operation*", 2},
{"x:paradise", 1},
{"tag:@NextActions", 1},
{"x:queensrÿche", 1},
{"tag:lost OR tag:operation*", 2},
};
for (i = 0; i != G_N_ELEMENTS(queries); ++i) {
g_assert_cmpuint (run_and_count_matches (DB_PATH2,
queries[i].query),
==, queries[i].count);
g_assert_cmpuint(run_and_count_matches(DB_PATH2, queries[i].query),
==,
queries[i].count);
}
}
@ -588,87 +546,75 @@ test_mu_query_tags_02 (void)
--related option doesn't work.
*/
static void
test_mu_query_threads_compilation_error (void)
test_mu_query_threads_compilation_error(void)
{
const auto xpath = make_database (MU_TESTMAILDIR);
const auto xpath = make_database(MU_TESTMAILDIR);
g_assert_cmpuint (run_and_count_matches
(xpath, "msgid:uwsireh25.fsf@one.dot.net"),
==, 1);
g_assert_cmpuint(run_and_count_matches(xpath, "msgid:uwsireh25.fsf@one.dot.net"), ==, 1);
g_assert_cmpuint (run_and_count_matches
(xpath, "msgid:uwsireh25.fsf@one.dot.net",
QueryFlags::IncludeRelated),
==, 3);
g_assert_cmpuint(run_and_count_matches(xpath,
"msgid:uwsireh25.fsf@one.dot.net",
QueryFlags::IncludeRelated),
==,
3);
}
int
main (int argc, char *argv[])
main(int argc, char* argv[])
{
int rv;
setlocale (LC_ALL, "");
setlocale(LC_ALL, "");
g_test_init (&argc, &argv, NULL);
g_test_init(&argc, &argv, NULL);
DB_PATH1 = make_database (MU_TESTMAILDIR);
g_assert_false (DB_PATH1.empty());
DB_PATH1 = make_database(MU_TESTMAILDIR);
g_assert_false(DB_PATH1.empty());
DB_PATH2 = make_database (MU_TESTMAILDIR2);
g_assert_false (DB_PATH2.empty());
DB_PATH2 = make_database(MU_TESTMAILDIR2);
g_assert_false(DB_PATH2.empty());
g_test_add_func ("/mu-query/test-mu-query-01", test_mu_query_01);
g_test_add_func ("/mu-query/test-mu-query-02", test_mu_query_02);
g_test_add_func ("/mu-query/test-mu-query-03", test_mu_query_03);
g_test_add_func ("/mu-query/test-mu-query-04", test_mu_query_04);
g_test_add_func("/mu-query/test-mu-query-01", test_mu_query_01);
g_test_add_func("/mu-query/test-mu-query-02", test_mu_query_02);
g_test_add_func("/mu-query/test-mu-query-03", test_mu_query_03);
g_test_add_func("/mu-query/test-mu-query-04", test_mu_query_04);
g_test_add_func ("/mu-query/test-mu-query-signed-encrypted",
test_mu_query_signed_encrypted);
g_test_add_func ("/mu-query/test-mu-query-multi-to-cc",
test_mu_query_multi_to_cc);
g_test_add_func ("/mu-query/test-mu-query-logic", test_mu_query_logic);
g_test_add_func("/mu-query/test-mu-query-signed-encrypted", test_mu_query_signed_encrypted);
g_test_add_func("/mu-query/test-mu-query-multi-to-cc", test_mu_query_multi_to_cc);
g_test_add_func("/mu-query/test-mu-query-logic", test_mu_query_logic);
g_test_add_func ("/mu-query/test-mu-query-accented-chars-1",
test_mu_query_accented_chars_01);
g_test_add_func ("/mu-query/test-mu-query-accented-chars-2",
test_mu_query_accented_chars_02);
g_test_add_func ("/mu-query/test-mu-query-accented-chars-fraiche",
test_mu_query_accented_chars_fraiche);
g_test_add_func("/mu-query/test-mu-query-accented-chars-1",
test_mu_query_accented_chars_01);
g_test_add_func("/mu-query/test-mu-query-accented-chars-2",
test_mu_query_accented_chars_02);
g_test_add_func("/mu-query/test-mu-query-accented-chars-fraiche",
test_mu_query_accented_chars_fraiche);
g_test_add_func ("/mu-query/test-mu-query-msgid",
test_mu_query_msgid);
g_test_add_func("/mu-query/test-mu-query-msgid", test_mu_query_msgid);
g_test_add_func ("/mu-query/test-mu-query-wom-bat",
test_mu_query_wom_bat);
g_test_add_func("/mu-query/test-mu-query-wom-bat", test_mu_query_wom_bat);
g_test_add_func ("/mu-query/test-mu-query-wildcards",
test_mu_query_wildcards);
g_test_add_func ("/mu-query/test-mu-query-sizes",
test_mu_query_sizes);
g_test_add_func("/mu-query/test-mu-query-wildcards", test_mu_query_wildcards);
g_test_add_func("/mu-query/test-mu-query-sizes", test_mu_query_sizes);
g_test_add_func ("/mu-query/test-mu-query-dates-helsinki",
test_mu_query_dates_helsinki);
g_test_add_func ("/mu-query/test-mu-query-dates-sydney",
test_mu_query_dates_sydney);
g_test_add_func ("/mu-query/test-mu-query-dates-la",
test_mu_query_dates_la);
g_test_add_func("/mu-query/test-mu-query-dates-helsinki", test_mu_query_dates_helsinki);
g_test_add_func("/mu-query/test-mu-query-dates-sydney", test_mu_query_dates_sydney);
g_test_add_func("/mu-query/test-mu-query-dates-la", test_mu_query_dates_la);
g_test_add_func ("/mu-query/test-mu-query-attach",
test_mu_query_attach);
g_test_add_func ("/mu-query/test-mu-query-tags",
test_mu_query_tags);
g_test_add_func ("/mu-query/test-mu-query-tags_02",
test_mu_query_tags_02);
g_test_add_func("/mu-query/test-mu-query-attach", test_mu_query_attach);
g_test_add_func("/mu-query/test-mu-query-tags", test_mu_query_tags);
g_test_add_func("/mu-query/test-mu-query-tags_02", test_mu_query_tags_02);
g_test_add_func ("/mu-query/test-mu-query-threads-compilation-error",
test_mu_query_threads_compilation_error);
g_test_add_func("/mu-query/test-mu-query-threads-compilation-error",
test_mu_query_threads_compilation_error);
if (!g_test_verbose())
g_log_set_handler (NULL,
(GLogLevelFlags)(G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL|
G_LOG_LEVEL_WARNING|G_LOG_FLAG_RECURSION),
(GLogFunc)black_hole, NULL);
rv = g_test_run ();
g_log_set_handler(NULL,
(GLogLevelFlags)(G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
G_LOG_LEVEL_WARNING | G_LOG_FLAG_RECURSION),
(GLogFunc)black_hole,
NULL);
rv = g_test_run();
return rv;
}