From e9a0939f8fe672af59794bc7365127c4ed46f1fb Mon Sep 17 00:00:00 2001 From: djcb Date: Sun, 28 Apr 2019 13:58:34 +0300 Subject: [PATCH] update cfind, server for new contacts-cache Use the new APIs. --- man/mu-cfind.1 | 45 +- mu/mu-cmd-cfind.c | 528 ++++++------ mu/mu-cmd-server.c | 1945 ++++++++++++++++++++++---------------------- mu/mu-cmd.c | 3 +- mu/mu-cmd.h | 3 +- mu/mu-config.c | 3 +- mu/mu-config.h | 1 + 7 files changed, 1266 insertions(+), 1262 deletions(-) diff --git a/man/mu-cfind.1 b/man/mu-cfind.1 index a02f41b4..a3618e1c 100644 --- a/man/mu-cfind.1 +++ b/man/mu-cfind.1 @@ -1,4 +1,4 @@ -.TH MU CFIND 1 "May 2013" "User Manuals" +.TH MU CFIND 1 "April 2019" "User Manuals" .SH NAME @@ -38,10 +38,9 @@ would find all contacts with a gmail-address, while lists all contacts with Mary in either name or e-mail address. -If you do not specify a search expression, \fBmu cfind\fR returns the full -list of contacts. Note, \fBmu cfind\fR does not use the -database, but uses a cache file with e-mail addresses, which is populated -during the indexing process. +If you do not specify a search expression, \fBmu cfind\fR returns the full list +of contacts. Note, \fBmu cfind\fR uses a cache with the e-mail information, +which is populated during the indexing process. The regular expressions are Perl-compatible (as per the PCRE-library used by GRegex). @@ -65,25 +64,24 @@ sets the output format to the given value. The following are available: .fi -(*) CSV is not really standardized, but \fBmu cfind\fR follows some common -practices: any double-quote is replaced by a double-double quote (thus, -"hello" become ""hello"", and fields with commas are put in -double-quotes. Normally, this should only apply to name fields. +(*) CSV is not fully standardized, but \fBmu cfind\fR follows some common +practices: any double-quote is replaced by a double-double quote (thus, "hello" +become ""hello"", and fields with commas are put in double-quotes. Normally, +this should only apply to name fields. .TP -\fB\-\-personal\fR only show addresses seen in messages where one of 'my' -e-mail addresses was seen in one of the address fields; this is to exclude -addresses only seen in mailing-list messages. See the \fB\-\-my-address\fR -parameter in \fBmu index\fR. +\fB\-\-personal\fR only show addresses seen in messages where one of 'my' e-mail +addresses was seen in one of the address fields; this is to exclude addresses +only seen in mailing-list messages. See the \fB\-\-my-address\fR parameter in +\fBmu index\fR. .TP \fB\-\-after=\fR\fI\fR only show addresses last seen after -\fI\fR. \fI\fR is a UNIX \fBtime_t\fR value, the number -of seconds since 1970-01-01 (in UTC). +\fI\fR. \fI\fR is a UNIX \fBtime_t\fR value, the number of +seconds since 1970-01-01 (in UTC). -From the command line, you can use the \fBdate\fR command to get this -value. For example, only consider addresses last seen after 2009-06-01, you -could specify +From the command line, you can use the \fBdate\fR command to get this value. For +example, only consider addresses last seen after 2009-06-01, you could specify .nf --after=`date +%s --date='2009-06-01'` .fi @@ -103,15 +101,15 @@ contact was found. Anything else leads to a non-zero return value: .SH INTEGRATION WITH MUTT -You can use \fBmu cfind\fR as an external address book server for -\fBmutt\fR. For this to work, add the following to your \fImuttrc\fR: +You can use \fBmu cfind\fR as an external address book server for \fBmutt\fR. +For this to work, add the following to your \fImuttrc\fR: .nf set query_command = "mu cfind --format=mutt-ab '%s'" .fi -Now, in mutt, you can easily search for e-mail addresses using the -\fBquery\fR-command, which is (by default) accessible by pressing \fBQ\fR. +Now, in mutt, you can search for e-mail addresses using the \fBquery\fR-command, +which is (by default) accessible by pressing \fBQ\fR. .SH ENCODING @@ -121,8 +119,7 @@ output-file, so emacs/bbdb can handle things correctly, without guessing. .SH BUGS -Please report bugs if you find them at -\fBhttps://github.com/djcb/mu/issues\fR. +Please report bugs if you find them at \fBhttps://github.com/djcb/mu/issues\fR. .SH AUTHOR diff --git a/mu/mu-cmd-cfind.c b/mu/mu-cmd-cfind.c index 3597c26d..4bc2524d 100644 --- a/mu/mu-cmd-cfind.c +++ b/mu/mu-cmd-cfind.c @@ -1,25 +1,22 @@ /* -** Copyright (C) 2011-2016 Dirk-Jan C. Binnema +** Copyright (C) 2011-2019 Dirk-Jan C. Binnema ** -** This program is free software; you can redistribute it and/or modify it -** under the terms of the GNU General Public License as published by the -** Free Software Foundation; either version 3, or (at your option) any -** later version. +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; either version 3, or (at your option) any later version. ** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. +** This program is distributed in the hope that it will be useful, but WITHOUT +** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +** details. ** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software Foundation, -** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** You should have received a copy of the GNU General Public License along with +** this program; if not, write to the Free Software Foundation, Inc., 51 +** Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** */ -#if HAVE_CONFIG_H #include "config.h" -#endif /*HAVE_CONFIG_H*/ #include #include @@ -45,14 +42,14 @@ static gchar* 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 : ""); } /** @@ -67,17 +64,17 @@ guess_last_name (const char *name) static gchar* 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); } /** @@ -93,87 +90,87 @@ guess_first_name (const char *name) static gchar* 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) { - 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) { - 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; - } + { + 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; } @@ -181,53 +178,54 @@ leave: static void print_header (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 char *email, const char *name, time_t tstamp) { - char *fname, *lname, *now, *timestamp; + char *fname, *lname, *now, *timestamp; - fname = guess_first_name (name); - lname = guess_last_name (name); - now = mu_date_str ("%Y-%m-%d", time(NULL)); - timestamp = mu_date_str ("%Y-%m-%d", tstamp); + fname = guess_first_name (name); + lname = guess_last_name (name); + 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, now, timestamp); + g_print ("[\"%s\" \"%s\" nil nil nil nil (\"%s\") " + "((creation-date . \"%s\") (time-stamp . \"%s\")) nil]\n", + fname, lname, email, now, timestamp); - g_free (now); - g_free (timestamp); - g_free (fname); - g_free (lname); + g_free (now); + g_free (timestamp); + g_free (fname); + g_free (lname); } static void each_contact_mutt_alias (const char *email, const char *name, - GHashTable *nicks) + GHashTable *nicks) { - gchar *nick; - if (!name) - return; + gchar *nick; - nick = guess_nick (name, nicks); - mu_util_print_encoded ("alias %s %s <%s>\n", - nick, name, email); - g_free (nick); + if (!name) + return; + + nick = guess_nick (name, nicks); + mu_util_print_encoded ("alias %s %s <%s>\n", + nick, name, email); + g_free (nick); } @@ -235,52 +233,52 @@ each_contact_mutt_alias (const char *email, const char *name, static void each_contact_wl (const char *email, const char *name, GHashTable *nicks) { - gchar *nick; + gchar *nick; - if (!name) - return; + if (!name) + return; - nick = guess_nick (name, nicks); - mu_util_print_encoded ("%s \"%s\" \"%s\"\n", - email, nick, name); - g_free (nick); + nick = guess_nick (name, nicks); + mu_util_print_encoded ("%s \"%s\" \"%s\"\n", + email, nick, name); + g_free (nick); } static void each_contact_org_contact (const char *email, const char *name) { - if (name) - mu_util_print_encoded ( - "* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n", - name, email); + if (name) + mu_util_print_encoded ( + "* %s\n:PROPERTIES:\n:EMAIL: %s\n:END:\n\n", + name, email); } static void print_csv_field (const char *str) { - char *s; + char *s; - if (!str) - return; + if (!str) + return; - s = mu_str_replace (str, "\"", "\"\""); - if (strchr (s, ',')) - mu_util_print_encoded ("\"%s\"", s); - else - mu_util_print_encoded ("%s", s); + s = mu_str_replace (str, "\"", "\"\""); + if (strchr (s, ',')) + mu_util_print_encoded ("\"%s\"", s); + else + mu_util_print_encoded ("%s", s); - g_free (s); + g_free (s); } static void each_contact_csv (const char *email, const char *name) { - print_csv_field (name); - mu_util_print_encoded (","); - print_csv_field (email); - mu_util_print_encoded ("\n"); + print_csv_field (name); + mu_util_print_encoded (","); + print_csv_field (email); + mu_util_print_encoded ("\n"); } @@ -288,155 +286,185 @@ each_contact_csv (const char *email, const char *name) static void print_plain (const char *email, const char *name, gboolean color) { - if (name) { - if (color) fputs (MU_COLOR_MAGENTA, stdout); - mu_util_fputs_encoded (name, stdout); - fputs (" ", stdout); - } + if (name) { + if (color) fputs (MU_COLOR_MAGENTA, stdout); + mu_util_fputs_encoded (name, stdout); + fputs (" ", stdout); + } - if (color) - fputs (MU_COLOR_GREEN, stdout); + if (color) + fputs (MU_COLOR_GREEN, stdout); - mu_util_fputs_encoded (email, stdout); + mu_util_fputs_encoded (email, stdout); - if (color) - fputs (MU_COLOR_DEFAULT, stdout); + if (color) + fputs (MU_COLOR_DEFAULT, stdout); - fputs ("\n", stdout); + fputs ("\n", stdout); } typedef struct { - MuConfigFormat format; - gboolean color, personal; - time_t after; - GHashTable *nicks; + MuConfigFormat format; + gboolean color, personal; + time_t after; + GRegex *rx; + GHashTable *nicks; + size_t n; } ECData; static void -each_contact (const char *email, const char *name, gboolean personal, - time_t tstamp, unsigned freq, ECData *ecdata) +each_contact (const char *full_address, + const char *email, const char *name, gboolean personal, + time_t last_seen, size_t freq, gint64 tstamp, + ECData *ecdata) { - if (ecdata->personal && !personal) - return; + if (ecdata->personal && !personal) + return; - if (tstamp < ecdata->after) - return; + if (tstamp < ecdata->after) + return; - switch (ecdata->format) { - case MU_CONFIG_FORMAT_MUTT_ALIAS: - each_contact_mutt_alias (email, name, ecdata->nicks); - break; - case MU_CONFIG_FORMAT_MUTT_AB: - mu_util_print_encoded ("%s\t%s\t\n", - email, name ? name : ""); - break; - case MU_CONFIG_FORMAT_WL: - each_contact_wl (email, name, ecdata->nicks); - break; - case MU_CONFIG_FORMAT_ORG_CONTACT: - each_contact_org_contact (email, name); - break; - case MU_CONFIG_FORMAT_BBDB: - each_contact_bbdb (email, name, tstamp); - break; - case MU_CONFIG_FORMAT_CSV: - each_contact_csv (email, name); - break; - default: - print_plain (email, name, ecdata->color); - } + if (ecdata->rx && + !g_regex_match (ecdata->rx, email, 0, NULL) && + !g_regex_match (ecdata->rx, name ? name : "", 0, NULL)) + return; + + ++ecdata->n; + + switch (ecdata->format) { + case MU_CONFIG_FORMAT_MUTT_ALIAS: + each_contact_mutt_alias (email, name, ecdata->nicks); + break; + case MU_CONFIG_FORMAT_MUTT_AB: + mu_util_print_encoded ("%s\t%s\t\n", + email, name ? name : ""); + break; + case MU_CONFIG_FORMAT_WL: + each_contact_wl (email, name, ecdata->nicks); + break; + case MU_CONFIG_FORMAT_ORG_CONTACT: + each_contact_org_contact (email, name); + break; + case MU_CONFIG_FORMAT_BBDB: + each_contact_bbdb (email, name, last_seen); + break; + case MU_CONFIG_FORMAT_CSV: + each_contact_csv (email, name); + break; + case MU_CONFIG_FORMAT_DEBUG: { + char datebuf[32]; + strftime(datebuf, sizeof(datebuf), "%F %T", + gmtime(&last_seen)); + g_print ("%s\n\tname: %s\n\t%s\n\tpersonal: %s\n\tfreq: %zu\n" + "\tlast-seen: %s\n", + email, + name ? name : "", + full_address, + personal ? "yes" : "no", + freq, + datebuf); + } break; + default: + print_plain (email, name, ecdata->color); + } } static MuError -run_cmd_cfind (const char* pattern, - gboolean personal, time_t after, - MuConfigFormat format, - gboolean color, GError **err) +run_cmd_cfind (MuStore *store, + const char* pattern, + gboolean personal, + time_t after, + MuConfigFormat format, + gboolean color, + GError **err) { - gboolean rv; - MuContacts *contacts; - size_t num; - ECData ecdata; + gboolean rv; + MuContacts *contacts; + ECData ecdata; - ecdata.personal = personal; - 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); + memset(&ecdata, 0, sizeof(ecdata)); - contacts = mu_contacts_new - (mu_runtime_path(MU_RUNTIME_PATH_CONTACTS)); - if (!contacts) { - g_set_error (err, MU_ERROR_DOMAIN, - MU_ERROR_CONTACTS_CANNOT_RETRIEVE, - "could not retrieve contacts"); - return MU_ERROR_CONTACTS_CANNOT_RETRIEVE; - } + if (pattern) { + ecdata.rx = g_regex_new (pattern, + G_REGEX_CASELESS|G_REGEX_OPTIMIZE, + 0, err); + if (!ecdata.rx) + return MU_ERROR_CONTACTS; + } - print_header (format); - rv = mu_contacts_foreach (contacts, - (MuContactsForeachFunc)each_contact, - &ecdata, pattern, &num); - g_hash_table_unref (ecdata.nicks); - mu_contacts_destroy (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); + print_header (format); + rv = mu_contacts_foreach (mu_store_contacts(store), + (MuContactsForeachFunc)each_contact, &ecdata); + g_hash_table_unref (ecdata.nicks); - if (num == 0) { - g_warning ("no matching contacts found"); - return MU_ERROR_NO_MATCHES; - } + if (ecdata.rx) + g_regex_unref (ecdata.rx); - return rv ? MU_OK : MU_ERROR_CONTACTS; + if (ecdata.n == 0) { + g_warning ("no matching contacts found"); + return MU_ERROR_NO_MATCHES; + } + + return rv ? MU_OK : MU_ERROR_CONTACTS; } static gboolean cfind_params_valid (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: - break; - default: - g_warning ("invalid output format %s", - opts->formatstr ? opts->formatstr : ""); - 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_warning ("invalid output format %s", + opts->formatstr ? opts->formatstr : ""); + return FALSE; + } - /* only one pattern allowed */ - if (opts->params[1] && opts->params[2]) { - g_warning ("usage: mu cfind [options] []"); - return FALSE; - } + /* only one pattern allowed */ + if (opts->params[1] && opts->params[2]) { + g_warning ("usage: mu cfind [options] []"); + return FALSE; + } - return TRUE; + return TRUE; } - MuError -mu_cmd_cfind (MuConfig *opts, GError **err) +mu_cmd_cfind (MuStore *store, 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 (store, 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)) { - g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS, - "invalid parameters"); - return MU_ERROR_IN_PARAMETERS; - } + if (!cfind_params_valid (opts)) { + g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS, + "invalid parameters"); + return MU_ERROR_IN_PARAMETERS; + } - return run_cmd_cfind (opts->params[1], - opts->personal, - opts->after, - opts->format, - !opts->nocolor, - err); + return run_cmd_cfind (store, + opts->params[1], + opts->personal, + opts->after, + opts->format, + !opts->nocolor, + err); } diff --git a/mu/mu-cmd-server.c b/mu/mu-cmd-server.c index bf14cfbc..36a1b7f8 100644 --- a/mu/mu-cmd-server.c +++ b/mu/mu-cmd-server.c @@ -1,6 +1,5 @@ -/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/ /* -** Copyright (C) 2011-2017 Dirk-Jan C. Binnema +** Copyright (C) 2011-2019 Dirk-Jan C. Binnema ** ** This program is free software; you can redistribute it and/or modify it ** under the terms of the GNU General Public License as published by the @@ -64,33 +63,33 @@ static gboolean MU_TERMINATE; static void sig_handler (int sig) { - MU_TERMINATE = TRUE; + MU_TERMINATE = TRUE; } static 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 }; - MU_TERMINATE = FALSE; + MU_TERMINATE = FALSE; - action.sa_handler = sig_handler; - sigemptyset(&action.sa_mask); - action.sa_flags = SA_RESETHAND; + action.sa_handler = sig_handler; + 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], 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], strerror (errno));; } /************************************************************************/ /* - * Markers for/after the lenght cookie that precedes the expression we - * write to output. We use octal 376, 377 (ie, 0xfe, 0xff) as they - * will never occur in utf8 */ + * Markers for/after the length cookie that precedes the expression we write to + * output. We use octal 376, 377 (ie, 0xfe, 0xff) as they will never occur in + * utf8 */ #define COOKIE_PRE '\376' @@ -99,214 +98,214 @@ install_sig_handler (void) static void G_GNUC_PRINTF(1, 2) print_expr (const char* frm, ...) { - char *expr, *expr_orig; - va_list ap; - ssize_t rv; - size_t exprlen, lenlen; - char cookie[16]; - static int outfd = 0; + char *expr, *expr_orig; + va_list ap; + ssize_t rv; + size_t exprlen, lenlen; + char cookie[16]; + static int outfd = 0; #if defined(__CYGWIN__ )&& !defined (_WIN32) - const size_t writestep = 4096 * 16; - size_t bytestowrite = 0; + const size_t writestep = 4096 * 16; + size_t bytestowrite = 0; #endif - if (outfd == 0) - outfd = fileno (stdout); + if (outfd == 0) + outfd = fileno (stdout); - expr = NULL; + expr = NULL; - va_start (ap, frm); - exprlen = g_vasprintf (&expr, frm, ap); - va_end (ap); + va_start (ap, frm); + exprlen = g_vasprintf (&expr, frm, ap); + va_end (ap); - /* this cookie tells the frontend where to expect the next - * expression */ + /* this cookie tells the frontend where to expect the next + * expression */ - cookie[0] = COOKIE_PRE; - lenlen = sprintf(cookie + 1, "%x", - (unsigned)exprlen + 1); /* + 1 for \n */ - cookie[lenlen + 1] = COOKIE_POST; + cookie[0] = COOKIE_PRE; + lenlen = sprintf(cookie + 1, "%x", + (unsigned)exprlen + 1); /* + 1 for \n */ + cookie[lenlen + 1] = COOKIE_POST; - /* write the cookie, ie. - * COOKIE_PRE COOKIE_POST - */ - rv = write (outfd, cookie, lenlen + 2); - if (rv != -1) { - expr_orig = expr; + /* write the cookie, ie. + * COOKIE_PRE COOKIE_POST + */ + rv = write (outfd, cookie, lenlen + 2); + if (rv != -1) { + expr_orig = expr; #if defined (__CYGWIN__) && !defined(_WIN32) - /* CYGWIN doesn't like big packets */ - while (exprlen > 0) { - bytestowrite = exprlen > writestep ? writestep : exprlen; - rv = write(outfd, expr, bytestowrite); - expr += bytestowrite; - exprlen -= bytestowrite; - } + /* CYGWIN doesn't like big packets */ + while (exprlen > 0) { + bytestowrite = exprlen > writestep ? writestep : exprlen; + rv = write(outfd, expr, bytestowrite); + expr += bytestowrite; + exprlen -= bytestowrite; + } #else - rv = write (outfd, expr, exprlen); + rv = write (outfd, expr, exprlen); #endif - g_free (expr_orig); - } - if (rv != -1) - rv = write (outfd, "\n", 1); - if (rv == -1) { - g_critical ("%s: write() failed: %s", - __func__, strerror(errno)); - /* terminate ourselves */ - raise (SIGTERM); - } + g_free (expr_orig); + } + if (rv != -1) + rv = write (outfd, "\n", 1); + if (rv == -1) { + g_critical ("%s: write() failed: %s", + __func__, strerror(errno)); + /* terminate ourselves */ + raise (SIGTERM); + } } static MuError print_error (MuError errcode, const char *msg) { - char *str; + char *str; - str = mu_str_escape_c_literal (msg, TRUE); - print_expr ("(:error %u :message %s)", errcode, str); - g_free (str); + str = mu_str_escape_c_literal (msg, TRUE); + print_expr ("(:error %u :message %s)", errcode, str); + g_free (str); - return errcode; + return errcode; } static MuError print_and_clear_g_error (GError **err) { - MuError rv; + MuError rv; - if (err && *err) - rv = print_error ((*err)->code, (*err)->message); - else - rv = print_error (MU_ERROR_INTERNAL, "unknown error"); + if (err && *err) + rv = print_error ((*err)->code, (*err)->message); + else + rv = print_error (MU_ERROR_INTERNAL, "unknown error"); - g_clear_error (err); + g_clear_error (err); - return rv; + return rv; } static GHashTable* read_command_line (GError **err) { - char *line; - GHashTable *hash; - GString *gstr; + char *line; + GHashTable *hash; + GString *gstr; - line = NULL; - gstr = g_string_sized_new (512); + line = NULL; + gstr = g_string_sized_new (512); - fputs (";; mu> ", stdout); + fputs (";; mu> ", stdout); - do { - int kar; + do { + int kar; - kar = fgetc (stdin); - if (kar == '\n' || kar == EOF) - break; - else - gstr = g_string_append_c (gstr, (char)kar); + kar = fgetc (stdin); + if (kar == '\n' || kar == EOF) + break; + else + gstr = g_string_append_c (gstr, (char)kar); - } while (1); + } while (1); - line = g_string_free (gstr, FALSE); + line = g_string_free (gstr, FALSE); - if (!mu_str_is_empty (line)) - hash = mu_str_parse_arglist (line, err); - else - hash = NULL; + if (!mu_str_is_empty (line)) + hash = mu_str_parse_arglist (line, err); + else + hash = NULL; - g_free (line); + g_free (line); - return hash; + return hash; } static const char* get_string_from_args (GHashTable *args, const char *param, gboolean optional, - GError **err) + GError **err) { - const char *str; + const char *str; - str = g_hash_table_lookup (args, param); - if (!str && !optional) - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "parameter '%s' not found", param); - return str; + str = g_hash_table_lookup (args, param); + if (!str && !optional) + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "parameter '%s' not found", param); + return str; } static gboolean get_bool_from_args (GHashTable *args, const char *param, gboolean optional, - GError **err) + GError **err) { - const char *val; + const char *val; - val = get_string_from_args (args, param, optional, err); - if (err && (*err != NULL)) - return FALSE; + val = get_string_from_args (args, param, optional, err); + if (err && (*err != NULL)) + return FALSE; - if (g_strcmp0 (val, "true") == 0) - return TRUE; + if (g_strcmp0 (val, "true") == 0) + return TRUE; - if (!val || g_strcmp0 (val, "false") == 0) - return FALSE; + if (!val || g_strcmp0 (val, "false") == 0) + return FALSE; - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "invalid value for parameter '%s'", param); - return FALSE; + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "invalid value for parameter '%s'", param); + return FALSE; } #define GET_STRING_OR_ERROR_RETURN(ARGS,PARAM,SP,E) \ - do { \ - *(SP) = get_string_from_args ((ARGS),(PARAM),FALSE,(E)); \ - if (!(*(SP))) \ - return MU_G_ERROR_CODE((E)); \ - } while (0); + do { \ + *(SP) = get_string_from_args ((ARGS),(PARAM),FALSE,(E)); \ + if (!(*(SP))) \ + return MU_G_ERROR_CODE((E)); \ + } while (0); /* get a *list* of all messages with the given message id */ static GSList* get_docids_from_msgids (MuQuery *query, const char *msgid, - int max, GError **err) + int max, GError **err) { - char xprefix; - char *rawq, *tmp; - MuMsgIter *iter; - GSList *lst; + char xprefix; + char *rawq, *tmp; + MuMsgIter *iter; + GSList *lst; - if (!msgid || strlen(msgid) > MU_STORE_MAX_TERM_LENGTH - 1) { - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "invalid message-id '%s' (length=%zu)", - msgid, strlen(msgid)); - return NULL; - } + if (!msgid || strlen(msgid) > MU_STORE_MAX_TERM_LENGTH - 1) { + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "invalid message-id '%s' (length=%zu)", + msgid, strlen(msgid)); + return NULL; + } - xprefix = mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_MSGID); - /*XXX this is a bit dodgy */ - tmp = g_ascii_strdown(msgid, -1); - rawq = g_strdup_printf("%c%s", xprefix, tmp); - g_free(tmp); - iter = mu_query_run (query, rawq, MU_MSG_FIELD_ID_NONE, - max, MU_QUERY_FLAG_RAW, err); - g_free (rawq); + xprefix = mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_MSGID); + /*XXX this is a bit dodgy */ + tmp = g_ascii_strdown(msgid, -1); + rawq = g_strdup_printf("%c%s", xprefix, tmp); + g_free(tmp); + iter = mu_query_run (query, rawq, MU_MSG_FIELD_ID_NONE, + max, MU_QUERY_FLAG_RAW, err); + g_free (rawq); - if (!iter || mu_msg_iter_is_done (iter)) { - mu_util_g_set_error (err, MU_ERROR_NO_MATCHES, - "could not find message(s) for msgid %s", - msgid); - return NULL; - } + if (!iter || mu_msg_iter_is_done (iter)) { + mu_util_g_set_error (err, MU_ERROR_NO_MATCHES, + "could not find message(s) for msgid %s", + msgid); + return NULL; + } - lst = NULL; - do { - lst = g_slist_prepend - (lst, GSIZE_TO_POINTER(mu_msg_iter_get_docid (iter))); - } while (mu_msg_iter_next (iter)); - mu_msg_iter_destroy (iter); + lst = NULL; + do { + lst = g_slist_prepend + (lst, GSIZE_TO_POINTER(mu_msg_iter_get_docid (iter))); + } while (mu_msg_iter_next (iter)); + mu_msg_iter_destroy (iter); - return lst; + return lst; } @@ -317,47 +316,47 @@ get_docids_from_msgids (MuQuery *query, const char *msgid, static unsigned determine_docid (MuQuery *query, GHashTable *args, GError **err) { - GSList *docids; - unsigned docid; - const char* docidstr, *msgidstr; + GSList *docids; + unsigned docid; + const char* docidstr, *msgidstr; - docidstr = get_string_from_args (args, "docid", TRUE, err); - if (docidstr) - return atoi (docidstr); + docidstr = get_string_from_args (args, "docid", TRUE, err); + if (docidstr) + return atoi (docidstr); - /* no docid: param; use msgid: instead */ - msgidstr = get_string_from_args (args, "msgid", TRUE, err); - if (!msgidstr) { - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "neither docid nor msgid specified"); - return MU_STORE_INVALID_DOCID; - } + /* no docid: param; use msgid: instead */ + msgidstr = get_string_from_args (args, "msgid", TRUE, err); + if (!msgidstr) { + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "neither docid nor msgid specified"); + return MU_STORE_INVALID_DOCID; + } - docids = get_docids_from_msgids (query, msgidstr, 1, err); - if (!docids) - return MU_STORE_INVALID_DOCID; + docids = get_docids_from_msgids (query, msgidstr, 1, err); + if (!docids) + return MU_STORE_INVALID_DOCID; - docid = GPOINTER_TO_UINT(docids->data); - g_slist_free (docids); + docid = GPOINTER_TO_UINT(docids->data); + g_slist_free (docids); - return docid; + return docid; } #define DOCID_VALID_OR_ERROR_RETURN(DOCID,E) \ - if ((DOCID)==MU_STORE_INVALID_DOCID) { \ - mu_util_g_set_error((E),MU_ERROR_IN_PARAMETERS, \ - "invalid docid"); \ - return MU_G_ERROR_CODE((E)); \ - } + if ((DOCID)==MU_STORE_INVALID_DOCID) { \ + mu_util_g_set_error((E),MU_ERROR_IN_PARAMETERS, \ + "invalid docid"); \ + return MU_G_ERROR_CODE((E)); \ + } #define EQSTR(S1,S2) (g_strcmp0((S1),(S2))==0) struct _ServerContext { - MuStore *store; - MuQuery *query; + MuStore *store; + MuQuery *query; }; typedef struct _ServerContext ServerContext; @@ -365,90 +364,88 @@ typedef struct _ServerContext ServerContext; /* implementation for the commands -- for each command , there is a * dedicated function cmd_. These function all are of the type CmdFunc * - * these functions return errors only if they don't handle them - * themselves, where 'handling' is defined as 'report it using - * print_and_clear_g_error' + * these functions return errors only if they don't handle them themselves, + * where 'handling' is defined as 'report it using print_and_clear_g_error' * * if function return non-MU_OK, the repl will print the error instead */ typedef MuError (*CmdFunc) (ServerContext*,GHashTable*,GError**); -/* 'add' adds a message to the database, and takes two parameters: - * 'path', which is the full path to the message, and 'maildir', which - * is the maildir this message lives in (e.g. "/inbox"). response with - * an (:info ...) message with information about the newly added - * message (details: see code below) +/* 'add' adds a message to the database, and takes two parameters: 'path', which + * is the full path to the message, and 'maildir', which is the maildir this + * message lives in (e.g. "/inbox"). response with an (:info ...) message with + * information about the newly added message (details: see code below) */ static MuError cmd_add (ServerContext *ctx, GHashTable *args, GError **err) { - unsigned docid; - const char *maildir, *path; - MuMsg *msg; - gchar *sexp; + unsigned docid; + const char *maildir, *path; + MuMsg *msg; + gchar *sexp; - GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); - GET_STRING_OR_ERROR_RETURN (args, "maildir", &maildir, err); + GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); + GET_STRING_OR_ERROR_RETURN (args, "maildir", &maildir, err); - docid = mu_store_add_path (ctx->store, path, maildir, err); - if (docid == MU_STORE_INVALID_DOCID) - print_and_clear_g_error (err); - else { - gchar *escpath; - escpath = mu_str_escape_c_literal (path, TRUE); - print_expr ("(:info add :path %s :docid %u)", escpath, docid); + docid = mu_store_add_path (ctx->store, path, maildir, err); + if (docid == MU_STORE_INVALID_DOCID) + print_and_clear_g_error (err); + else { + gchar *escpath; + escpath = mu_str_escape_c_literal (path, TRUE); + print_expr ("(:info add :path %s :docid %u)", escpath, docid); - msg = mu_store_get_msg (ctx->store, docid, err); - if (msg) { - sexp = mu_msg_to_sexp (msg, docid, NULL, - MU_MSG_OPTION_VERIFY); - print_expr ("(:update %s :move nil)", sexp); + msg = mu_store_get_msg (ctx->store, docid, err); + if (msg) { + sexp = mu_msg_to_sexp (msg, docid, NULL, + MU_MSG_OPTION_VERIFY); + print_expr ("(:update %s :move nil)", sexp); - mu_msg_unref(msg); - g_free (sexp); - } - g_free (escpath); - } + mu_msg_unref(msg); + g_free (sexp); + } + g_free (escpath); + } - return MU_OK; + return MU_OK; } struct _PartInfo { - GSList *attlist; - MuMsgOptions opts; + GSList *attlist; + MuMsgOptions opts; }; typedef struct _PartInfo PartInfo; static void each_part (MuMsg *msg, MuMsgPart *part, PartInfo *pinfo) { - char *att, *cachefile, *encfile; - GError *err; + char *att, *cachefile, *encfile; + GError *err; - /* exclude things that don't look like proper attachments, - * unless they're images */ - if (!mu_msg_part_maybe_attachment(part)) - return; + /* exclude things that don't look like proper attachments, + * unless they're images */ + if (!mu_msg_part_maybe_attachment(part)) + return; - err = NULL; - cachefile = mu_msg_part_save_temp (msg, - pinfo->opts|MU_MSG_OPTION_OVERWRITE, - part->index, &err); - if (!cachefile) { - print_and_clear_g_error (&err); - return; - } + err = NULL; + cachefile = mu_msg_part_save_temp (msg, + pinfo->opts|MU_MSG_OPTION_OVERWRITE, + part->index, &err); + if (!cachefile) { + print_and_clear_g_error (&err); + return; + } - encfile = mu_str_escape_c_literal(cachefile, TRUE); - g_free (cachefile); + encfile = mu_str_escape_c_literal(cachefile, TRUE); + g_free (cachefile); - att = g_strdup_printf ( - "(:file-name %s :mime-type \"%s/%s\")", - encfile, part->type, part->subtype); - pinfo->attlist = g_slist_append (pinfo->attlist, att); - g_free (encfile); + att = g_strdup_printf ( + "(:file-name %s :mime-type \"%s/%s\")", + encfile, part->type, part->subtype); + pinfo->attlist = g_slist_append (pinfo->attlist, att); + g_free (encfile); } @@ -462,58 +459,58 @@ each_part (MuMsg *msg, MuMsgPart *part, PartInfo *pinfo) static gchar* include_attachments (MuMsg *msg, MuMsgOptions opts) { - GSList *cur; - GString *gstr; - PartInfo pinfo; + GSList *cur; + GString *gstr; + PartInfo pinfo; - pinfo.attlist = NULL; - pinfo.opts = opts; - mu_msg_part_foreach (msg, opts, - (MuMsgPartForeachFunc)each_part, - &pinfo); + pinfo.attlist = NULL; + pinfo.opts = opts; + mu_msg_part_foreach (msg, opts, + (MuMsgPartForeachFunc)each_part, + &pinfo); - gstr = g_string_sized_new (512); - gstr = g_string_append_c (gstr, '('); - for (cur = pinfo.attlist; cur; cur = g_slist_next (cur)) - g_string_append (gstr, (gchar*)cur->data); - gstr = g_string_append_c (gstr, ')'); + gstr = g_string_sized_new (512); + gstr = g_string_append_c (gstr, '('); + for (cur = pinfo.attlist; cur; cur = g_slist_next (cur)) + g_string_append (gstr, (gchar*)cur->data); + gstr = g_string_append_c (gstr, ')'); - mu_str_free_list (pinfo.attlist); + mu_str_free_list (pinfo.attlist); - return g_string_free (gstr, FALSE); + return g_string_free (gstr, FALSE); } static MuMsgOptions get_encrypted_msg_opts (GHashTable *args) { - MuMsgOptions opts; + MuMsgOptions opts; - opts = MU_MSG_OPTION_NONE; + opts = MU_MSG_OPTION_NONE; - if (get_bool_from_args (args, "use-agent", FALSE, NULL)) - opts |= MU_MSG_OPTION_USE_AGENT; - if (get_bool_from_args (args, "extract-encrypted", FALSE, NULL)) - opts |= MU_MSG_OPTION_DECRYPT; + if (get_bool_from_args (args, "use-agent", FALSE, NULL)) + opts |= MU_MSG_OPTION_USE_AGENT; + if (get_bool_from_args (args, "extract-encrypted", FALSE, NULL)) + opts |= MU_MSG_OPTION_DECRYPT; - return opts; + return opts; } enum { NEW, REPLY, FORWARD, EDIT, RESEND, INVALID_TYPE }; static unsigned compose_type (const char *typestr) { - if (EQSTR (typestr, "reply")) - return REPLY; - else if (EQSTR (typestr, "forward")) - return FORWARD; - else if (EQSTR (typestr, "edit")) - return EDIT; - else if (EQSTR (typestr, "resend")) - return RESEND; - else if (EQSTR (typestr, "new")) - return NEW; - else - return INVALID_TYPE; + if (EQSTR (typestr, "reply")) + return REPLY; + else if (EQSTR (typestr, "forward")) + return FORWARD; + else if (EQSTR (typestr, "edit")) + return EDIT; + else if (EQSTR (typestr, "resend")) + return RESEND; + else if (EQSTR (typestr, "new")) + return NEW; + else + return INVALID_TYPE; } /* 'compose' produces the un-changed *original* message sexp (ie., the message @@ -530,89 +527,90 @@ compose_type (const char *typestr) static MuError cmd_compose (ServerContext *ctx, GHashTable *args, GError **err) { - const gchar *typestr; - char *sexp, *atts; - unsigned ctype; - MuMsgOptions opts; + const gchar *typestr; + char *sexp, *atts; + unsigned ctype; + MuMsgOptions opts; - opts = get_encrypted_msg_opts (args); + opts = get_encrypted_msg_opts (args); - GET_STRING_OR_ERROR_RETURN (args, "type", &typestr, err); + GET_STRING_OR_ERROR_RETURN (args, "type", &typestr, err); - ctype = compose_type (typestr); - if (ctype == INVALID_TYPE) { - print_error (MU_ERROR_IN_PARAMETERS, "invalid type to compose"); - return MU_OK; - } + ctype = compose_type (typestr); + if (ctype == INVALID_TYPE) { + print_error (MU_ERROR_IN_PARAMETERS, "invalid type to compose"); + return MU_OK; + } - if (ctype == REPLY || ctype == FORWARD || - ctype == EDIT || ctype == RESEND) { - MuMsg *msg; - const char *docidstr; - GET_STRING_OR_ERROR_RETURN (args, "docid", &docidstr, err); - msg = mu_store_get_msg (ctx->store, atoi(docidstr), err); - if (!msg) { - print_and_clear_g_error (err); - return MU_OK; - } - sexp = mu_msg_to_sexp (msg, atoi(docidstr), NULL, opts); - atts = (ctype == FORWARD) ? - include_attachments (msg, opts) : NULL; - mu_msg_unref (msg); - } else - atts = sexp = NULL; + if (ctype == REPLY || ctype == FORWARD || + ctype == EDIT || ctype == RESEND) { + MuMsg *msg; + const char *docidstr; + GET_STRING_OR_ERROR_RETURN (args, "docid", &docidstr, err); + msg = mu_store_get_msg (ctx->store, atoi(docidstr), err); + if (!msg) { + print_and_clear_g_error (err); + return MU_OK; + } + sexp = mu_msg_to_sexp (msg, atoi(docidstr), NULL, opts); + atts = (ctype == FORWARD) ? + include_attachments (msg, opts) : NULL; + mu_msg_unref (msg); + } else + atts = sexp = NULL; - print_expr ("(:compose %s :original %s :include %s)", - typestr, sexp ? sexp : "nil", atts ? atts : "nil"); + print_expr ("(:compose %s :original %s :include %s)", + typestr, sexp ? sexp : "nil", atts ? atts : "nil"); - g_free (sexp); - g_free (atts); + g_free (sexp); + g_free (atts); - return MU_OK; + return MU_OK; } struct _SexpData { - GString *gstr; - gboolean personal; - time_t after; + GString *gstr; + gboolean personal; + time_t last_seen; + gint64 tstamp; + size_t rank; }; -typedef struct _SexpData SexpData; - +typedef struct _SexpData SexpData; static void -each_contact_sexp (const char *email, const char *name, gboolean personal, - time_t tstamp, unsigned freq, SexpData *sdata) +each_contact_sexp (const char* full_address, + const char *email, const char *name, gboolean personal, + time_t last_seen, unsigned freq, + gint64 tstamp, SexpData *sdata) { - char *escmail, *escname; + char *escaddr; - /* (maybe) only include 'personal' contacts */ - if (sdata->personal && !personal) - return; + sdata->rank++; - /* only include newer-than-x contacts */ - if (tstamp < sdata->after) - return; + /* since the last time we got some contacts */ + if (sdata->tstamp > tstamp) + return; - /* only include *real* e-mail addresses (ignore local - * addresses... there's little to complete there anyway...) */ - if (!email || !strstr (email, "@")) - return; + /* (maybe) only include 'personal' contacts */ + if (sdata->personal && !personal) + return; - escmail = mu_str_escape_c_literal (email, TRUE); - escname = name ? mu_str_escape_c_literal (name, TRUE) : NULL; + /* only include newer-than-x contacts */ + if (sdata->last_seen > last_seen) + return; - g_string_append_printf ( - sdata->gstr, - "(:mail %s :name %s :tstamp %u :freq %u :personal %s)\n", - escmail, - escname ? escname : "nil", - (unsigned)tstamp, - freq, - sdata->personal ? "t" : "nil"); + /* only include *real* e-mail addresses (ignore local + * addresses... there's little to complete there anyway...) */ + if (!email || !strstr (email, "@")) + return; - g_free (escname); - g_free (escmail); + escaddr = mu_str_escape_c_literal (full_address, TRUE); + + g_string_append_printf (sdata->gstr, "(%s . %zu)\n", + escaddr, sdata->rank); + + g_free (escaddr); } @@ -620,60 +618,73 @@ each_contact_sexp (const char *email, const char *name, gboolean personal, * get all contacts as an s-expression * * @param self contacts object - * @param personal_only whether to restrict the list to 'personal' email addresses + * @param personal_only whether to restrict the list to 'personal' email + * addresses * * @return the sexp */ static char* -contacts_to_sexp (MuContacts *contacts, gboolean personal, time_t after) +contacts_to_sexp (MuContacts *contacts, gboolean personal, + time_t last_seen, gint64 tstamp) { - SexpData sdata; + SexpData sdata; + gint64 cutoff; - g_return_val_if_fail (contacts, NULL); + g_return_val_if_fail (contacts, NULL); - sdata.personal = personal; - sdata.after = after; + memset (&sdata, 0, sizeof(SexpData)); - /* make a guess for the initial size */ - sdata.gstr = g_string_sized_new (mu_contacts_count(contacts) * 128); - sdata.gstr = g_string_append (sdata.gstr, "(:contacts ("); - mu_contacts_foreach (contacts, - (MuContactsForeachFunc)each_contact_sexp, - &sdata, NULL, NULL); - sdata.gstr = g_string_append (sdata.gstr, "))"); + sdata.personal = personal; + sdata.last_seen = last_seen; + sdata.tstamp = tstamp; + sdata.rank = 0; - return g_string_free (sdata.gstr, FALSE); + /* make a guess for the initial size */ + sdata.gstr = g_string_sized_new (mu_contacts_count(contacts) * 128); + g_string_append (sdata.gstr, "(:contacts ("); + + cutoff = g_get_monotonic_time(); + mu_contacts_foreach (contacts, + (MuContactsForeachFunc)each_contact_sexp, &sdata); + /* pass a string, elisp doesn't like 64-bit nums */ + g_string_append_printf (sdata.gstr, + ") :tstamp \"%" G_GINT64_FORMAT "\")", cutoff); + + return g_string_free (sdata.gstr, FALSE); } static MuError cmd_contacts (ServerContext *ctx, GHashTable *args, GError **err) { - MuContacts *contacts; - char *sexp; - gboolean personal; - time_t after; - const char *str; + MuContacts *contacts; + char *sexp; + gboolean personal; + time_t after; + const char *str; + gint64 tstamp; - personal = get_bool_from_args (args, "personal", TRUE, NULL); - str = get_string_from_args (args, "after", TRUE, NULL); - after = str ? (time_t)atoi(str) : 0; + personal = get_bool_from_args (args, "personal", TRUE, NULL); + str = get_string_from_args (args, "after", TRUE, NULL); + after = str ? (time_t)atoi(str) : 0; - contacts = mu_contacts_new - (mu_runtime_path (MU_RUNTIME_PATH_CONTACTS)); - if (!contacts) { - print_error (MU_ERROR_INTERNAL, - "failed to open contacts cache"); - return MU_OK; - } + // only get contacts updated since tstamp. + str = get_string_from_args (args, "tstamp", TRUE, NULL); + tstamp = str ? g_ascii_strtoll (str, NULL, 10) : 0; - /* dump the contacts cache as a giant sexp */ - sexp = contacts_to_sexp (contacts, personal, after); - print_expr ("%s\n", sexp); - g_free (sexp); + contacts = mu_store_contacts(ctx->store); + if (!contacts) { + print_error (MU_ERROR_INTERNAL, + "failed to get contacts cache"); + return MU_OK; + } - mu_contacts_destroy (contacts); - return MU_OK; + /* dump the contacts cache as a giant sexp */ + sexp = contacts_to_sexp (contacts, personal, after, tstamp); + print_expr ("%s\n", sexp); + g_free (sexp); + + return MU_OK; } @@ -681,191 +692,192 @@ cmd_contacts (ServerContext *ctx, GHashTable *args, GError **err) static unsigned print_sexps (MuMsgIter *iter, unsigned maxnum) { - unsigned u; - u = 0; + unsigned u; + u = 0; - while (!mu_msg_iter_is_done (iter) && u < maxnum && !MU_TERMINATE) { + while (!mu_msg_iter_is_done (iter) && u < maxnum && !MU_TERMINATE) { - MuMsg *msg; - msg = mu_msg_iter_get_msg_floating (iter); + MuMsg *msg; + msg = mu_msg_iter_get_msg_floating (iter); - if (mu_msg_is_readable (msg)) { - char *sexp; - const MuMsgIterThreadInfo* ti; - ti = mu_msg_iter_get_thread_info (iter); - sexp = mu_msg_to_sexp (msg, mu_msg_iter_get_docid (iter), - ti, MU_MSG_OPTION_HEADERS_ONLY); - print_expr ("%s", sexp); - g_free (sexp); - ++u; - } - mu_msg_iter_next (iter); - } - return u; + if (mu_msg_is_readable (msg)) { + char *sexp; + const MuMsgIterThreadInfo* ti; + ti = mu_msg_iter_get_thread_info (iter); + sexp = mu_msg_to_sexp (msg, + mu_msg_iter_get_docid (iter), + ti, MU_MSG_OPTION_HEADERS_ONLY); + print_expr ("%s", sexp); + g_free (sexp); + ++u; + } + mu_msg_iter_next (iter); + } + return u; } static MuError save_part (MuMsg *msg, unsigned docid, unsigned index, - MuMsgOptions opts, GHashTable *args, GError **err) + MuMsgOptions opts, GHashTable *args, GError **err) { - gboolean rv; - const gchar *path; - gchar *escpath; + gboolean rv; + const gchar *path; + gchar *escpath; - GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); + GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); - rv = mu_msg_part_save (msg, opts | MU_MSG_OPTION_OVERWRITE, - path, index, err); - if (!rv) { - print_and_clear_g_error (err); - return MU_OK; - } + rv = mu_msg_part_save (msg, opts | MU_MSG_OPTION_OVERWRITE, + path, index, err); + if (!rv) { + print_and_clear_g_error (err); + return MU_OK; + } - escpath = mu_str_escape_c_literal (path, FALSE); - print_expr ("(:info save :message \"%s has been saved\")", - escpath); + escpath = mu_str_escape_c_literal (path, FALSE); + print_expr ("(:info save :message \"%s has been saved\")", + escpath); - g_free (escpath); - return MU_OK; + g_free (escpath); + return MU_OK; } static MuError open_part (MuMsg *msg, unsigned docid, unsigned index, - MuMsgOptions opts, GError **err) + MuMsgOptions opts, GError **err) { - char *targetpath; - gboolean rv; + char *targetpath; + gboolean rv; - targetpath = mu_msg_part_get_cache_path (msg, opts, index, err); - if (!targetpath) - return print_and_clear_g_error (err); + targetpath = mu_msg_part_get_cache_path (msg, opts, index, err); + if (!targetpath) + return print_and_clear_g_error (err); - rv = mu_msg_part_save (msg, opts | MU_MSG_OPTION_USE_EXISTING, - targetpath, index, err); - if (!rv) { - print_and_clear_g_error (err); - goto leave; - } + rv = mu_msg_part_save (msg, opts | MU_MSG_OPTION_USE_EXISTING, + targetpath, index, err); + if (!rv) { + print_and_clear_g_error (err); + goto leave; + } - rv = mu_util_play (targetpath, TRUE,/*allow local*/ - FALSE/*allow remote*/, err); - if (!rv) - print_and_clear_g_error (err); - else { - gchar *path; - path = mu_str_escape_c_literal (targetpath, FALSE); - print_expr ("(:info open :message \"%s has been opened\")", - path); - g_free (path); - } + rv = mu_util_play (targetpath, TRUE,/*allow local*/ + FALSE/*allow remote*/, err); + if (!rv) + print_and_clear_g_error (err); + else { + gchar *path; + path = mu_str_escape_c_literal (targetpath, FALSE); + print_expr ("(:info open :message \"%s has been opened\")", + path); + g_free (path); + } leave: - g_free (targetpath); - return MU_OK; + g_free (targetpath); + return MU_OK; } static MuError temp_part (MuMsg *msg, unsigned docid, unsigned index, - MuMsgOptions opts, GHashTable *args, GError **err) + MuMsgOptions opts, GHashTable *args, GError **err) { - const char *what, *param; - char *path; + const char *what, *param; + char *path; - GET_STRING_OR_ERROR_RETURN (args, "what", &what, err); - param = get_string_from_args (args, "param", TRUE, NULL); + GET_STRING_OR_ERROR_RETURN (args, "what", &what, err); + param = get_string_from_args (args, "param", TRUE, NULL); - path = mu_msg_part_get_cache_path (msg, opts, index, err); - if (!path) - print_and_clear_g_error (err); - else if (!mu_msg_part_save (msg, opts | MU_MSG_OPTION_USE_EXISTING, - path, index, err)) - print_and_clear_g_error (err); - else { - gchar *escpath; - escpath = mu_str_escape_c_literal (path, FALSE); + path = mu_msg_part_get_cache_path (msg, opts, index, err); + if (!path) + print_and_clear_g_error (err); + else if (!mu_msg_part_save (msg, opts | MU_MSG_OPTION_USE_EXISTING, + path, index, err)) + print_and_clear_g_error (err); + else { + gchar *escpath; + escpath = mu_str_escape_c_literal (path, FALSE); - if (param) { - char *escparam; - escparam = mu_str_escape_c_literal (param, FALSE); - print_expr ("(:temp \"%s\"" - " :what \"%s\"" - " :docid %u" - " :param \"%s\""")", - escpath, what, docid, escparam); - g_free (escparam); - } else - print_expr ("(:temp \"%s\" :what \"%s\" :docid %u)", - escpath, what, docid); + if (param) { + char *escparam; + escparam = mu_str_escape_c_literal (param, FALSE); + print_expr ("(:temp \"%s\"" + " :what \"%s\"" + " :docid %u" + " :param \"%s\""")", + escpath, what, docid, escparam); + g_free (escparam); + } else + print_expr ("(:temp \"%s\" :what \"%s\" :docid %u)", + escpath, what, docid); - g_free (escpath); + g_free (escpath); - } + } - g_free (path); - return MU_OK; + g_free (path); + return MU_OK; } enum { SAVE, OPEN, TEMP, INVALID_ACTION }; static int action_type (const char *actionstr) { - if (EQSTR (actionstr, "save")) - return SAVE; - else if (EQSTR (actionstr, "open")) - return OPEN; - else if (EQSTR (actionstr, "temp")) - return TEMP; - else - return INVALID_ACTION; + if (EQSTR (actionstr, "save")) + return SAVE; + else if (EQSTR (actionstr, "open")) + return OPEN; + else if (EQSTR (actionstr, "temp")) + return TEMP; + else + return INVALID_ACTION; } /* 'extract' extracts some mime part from a message */ static MuError cmd_extract (ServerContext *ctx, GHashTable *args, GError **err) { - MuMsg *msg; - int docid, index, action; - MuError rv; - MuMsgOptions opts; - const char* actionstr, *indexstr; + MuMsg *msg; + int docid, index, action; + MuError rv; + MuMsgOptions opts; + const char* actionstr, *indexstr; - opts = get_encrypted_msg_opts (args); - rv = MU_ERROR; + opts = get_encrypted_msg_opts (args); + rv = MU_ERROR; - /* read parameters */ - GET_STRING_OR_ERROR_RETURN (args, "action", &actionstr, err); - GET_STRING_OR_ERROR_RETURN (args, "index", &indexstr, err); - index = atoi (indexstr); - docid = determine_docid (ctx->query, args, err); - if (docid == MU_STORE_INVALID_DOCID) { - print_and_clear_g_error (err); - return MU_OK; - } + /* read parameters */ + GET_STRING_OR_ERROR_RETURN (args, "action", &actionstr, err); + GET_STRING_OR_ERROR_RETURN (args, "index", &indexstr, err); + index = atoi (indexstr); + docid = determine_docid (ctx->query, args, err); + if (docid == MU_STORE_INVALID_DOCID) { + print_and_clear_g_error (err); + return MU_OK; + } - if ((action = action_type (actionstr)) == INVALID_ACTION) { - print_error (MU_ERROR_IN_PARAMETERS, "invalid action"); - return MU_OK; - } - msg = mu_store_get_msg (ctx->store, docid, err); - if (!msg) { - print_error (MU_ERROR, "failed to get message"); - return MU_OK; - } + if ((action = action_type (actionstr)) == INVALID_ACTION) { + print_error (MU_ERROR_IN_PARAMETERS, "invalid action"); + return MU_OK; + } + msg = mu_store_get_msg (ctx->store, docid, err); + if (!msg) { + print_error (MU_ERROR, "failed to get message"); + return MU_OK; + } - switch (action) { - case SAVE: rv = save_part (msg, docid, index, opts, args, err); break; - case OPEN: rv = open_part (msg, docid, index, opts, err); break; - case TEMP: rv = temp_part (msg, docid, index, opts, args, err); break; - default: print_error (MU_ERROR_INTERNAL, "unknown action"); - } + switch (action) { + case SAVE: rv = save_part (msg, docid, index, opts, args, err); break; + case OPEN: rv = open_part (msg, docid, index, opts, err); break; + case TEMP: rv = temp_part (msg, docid, index, opts, args, err); break; + default: print_error (MU_ERROR_INTERNAL, "unknown action"); + } - if (rv != MU_OK) - print_and_clear_g_error (err); + if (rv != MU_OK) + print_and_clear_g_error (err); - mu_msg_unref (msg); - return MU_OK; + mu_msg_unref (msg); + return MU_OK; } #define MAX_NUM_DEFAULT 500 @@ -873,45 +885,45 @@ cmd_extract (ServerContext *ctx, GHashTable *args, GError **err) /* parse the find parameters, and return the values as out params */ static MuError get_find_params (GHashTable *args, MuMsgFieldId *sortfield, - int *maxnum, MuQueryFlags *qflags, GError **err) + int *maxnum, MuQueryFlags *qflags, GError **err) { - const char *maxnumstr, *sortfieldstr; + const char *maxnumstr, *sortfieldstr; - /* defaults */ - *maxnum = MAX_NUM_DEFAULT; - *qflags = MU_QUERY_FLAG_NONE; - *sortfield = MU_MSG_FIELD_ID_NONE; + /* defaults */ + *maxnum = MAX_NUM_DEFAULT; + *qflags = MU_QUERY_FLAG_NONE; + *sortfield = MU_MSG_FIELD_ID_NONE; - /* field to sort by */ - sortfieldstr = get_string_from_args (args, "sortfield", TRUE, NULL); - if (sortfieldstr) { - *sortfield = mu_msg_field_id_from_name (sortfieldstr, FALSE); - /* note: shortcuts are not allowed here */ - if (*sortfield == MU_MSG_FIELD_ID_NONE) { - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "not a valid sort field: '%s'", - sortfield); - return MU_G_ERROR_CODE(err); - } - } else - *sortfield = MU_MSG_FIELD_ID_DATE; + /* field to sort by */ + sortfieldstr = get_string_from_args (args, "sortfield", TRUE, NULL); + if (sortfieldstr) { + *sortfield = mu_msg_field_id_from_name (sortfieldstr, FALSE); + /* note: shortcuts are not allowed here */ + if (*sortfield == MU_MSG_FIELD_ID_NONE) { + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "not a valid sort field: '%s'", + sortfield); + return MU_G_ERROR_CODE(err); + } + } else + *sortfield = MU_MSG_FIELD_ID_DATE; - /* maximum number of results */ - maxnumstr = get_string_from_args (args, "maxnum", TRUE, NULL); - if (maxnumstr) - *maxnum = atoi (maxnumstr); + /* maximum number of results */ + maxnumstr = get_string_from_args (args, "maxnum", TRUE, NULL); + if (maxnumstr) + *maxnum = atoi (maxnumstr); - if (get_bool_from_args (args, "reverse", TRUE, NULL)) - *qflags |= MU_QUERY_FLAG_DESCENDING; - if (get_bool_from_args (args, "skip-dups", TRUE, NULL)) - *qflags |= MU_QUERY_FLAG_SKIP_DUPS; - if (get_bool_from_args (args, "include-related", TRUE, NULL)) - *qflags |= MU_QUERY_FLAG_INCLUDE_RELATED; - if (get_bool_from_args (args, "threads", TRUE, NULL)) - *qflags |= MU_QUERY_FLAG_THREADS; + if (get_bool_from_args (args, "reverse", TRUE, NULL)) + *qflags |= MU_QUERY_FLAG_DESCENDING; + if (get_bool_from_args (args, "skip-dups", TRUE, NULL)) + *qflags |= MU_QUERY_FLAG_SKIP_DUPS; + if (get_bool_from_args (args, "include-related", TRUE, NULL)) + *qflags |= MU_QUERY_FLAG_INCLUDE_RELATED; + if (get_bool_from_args (args, "threads", TRUE, NULL)) + *qflags |= MU_QUERY_FLAG_THREADS; - return MU_OK; + return MU_OK; } @@ -927,173 +939,134 @@ get_find_params (GHashTable *args, MuMsgFieldId *sortfield, static MuError cmd_find (ServerContext *ctx, GHashTable *args, GError **err) { - MuMsgIter *iter; - unsigned foundnum; - int maxnum; - MuMsgFieldId sortfield; - const char *querystr; - MuQueryFlags qflags; - char *query; + MuMsgIter *iter; + unsigned foundnum; + int maxnum; + MuMsgFieldId sortfield; + const char *querystr; + MuQueryFlags qflags; + char *query; - GET_STRING_OR_ERROR_RETURN (args, "query", &querystr, err); - if (get_find_params (args, &sortfield, &maxnum, &qflags, err) - != MU_OK) { - print_and_clear_g_error (err); - return MU_OK; - } + GET_STRING_OR_ERROR_RETURN (args, "query", &querystr, err); + if (get_find_params (args, &sortfield, &maxnum, &qflags, err) + != MU_OK) { + print_and_clear_g_error (err); + return MU_OK; + } - { - char *s; - gsize len; - s = (char*)g_base64_decode (querystr, &len); - query = g_strndup (s, len); - g_free (s); - } + { + char *s; + gsize len; + s = (char*)g_base64_decode (querystr, &len); + query = g_strndup (s, len); + g_free (s); + } - /* note: when we're threading, we get *all* matching messages, - * and then only return maxnum; this is so that we maximimize - * the change of all messages in a thread showing up */ + /* note: when we're threading, we get *all* matching messages, + * and then only return maxnum; this is so that we maximimize + * the change of all messages in a thread showing up */ - iter = mu_query_run (ctx->query, query, sortfield, - maxnum, qflags, err); - g_free (query); - if (!iter) { - print_and_clear_g_error (err); - return MU_OK; - } + iter = mu_query_run (ctx->query, query, sortfield, + maxnum, qflags, err); + g_free (query); + if (!iter) { + print_and_clear_g_error (err); + return MU_OK; + } - /* before sending new results, send an 'erase' message, so the - * frontend knows it should erase the headers buffer. this - * will ensure that the output of two finds will not be - * mixed. */ - print_expr ("(:erase t)"); - foundnum = print_sexps (iter, maxnum); - print_expr ("(:found %u)", foundnum); - mu_msg_iter_destroy (iter); + /* before sending new results, send an 'erase' message, so the + * frontend knows it should erase the headers buffer. this + * will ensure that the output of two finds will not be + * mixed. */ + print_expr ("(:erase t)"); + foundnum = print_sexps (iter, maxnum); + print_expr ("(:found %u)", foundnum); + mu_msg_iter_destroy (iter); - return MU_OK; + return MU_OK; } - -/* static gpointer */ -/* start_guile (GuileData *data) */ -/* { */ -/* g_print ("starting guile"); */ -/* sleep (10); */ -/* } */ - - - - -#ifdef BUILD_GUILE -static MuError -cmd_guile (ServerContext *ctx, GHashTable *args, GError **err) -{ - const char *eval; - - eval = get_string_from_args (args, "eval", TRUE, NULL); - - if (!eval) { - print_error (MU_ERROR_IN_PARAMETERS, "guile: expected: 'eval'"); - return MU_OK; - } - - return MU_OK; -} -#else /*!BUILD_GUILE*/ -static MuError -cmd_guile (ServerContext *ctx, GHashTable *args, GError **err) -{ - print_error (MU_ERROR_INTERNAL, - "this mu does not have guile support"); - return MU_OK; -} -#endif /*BUILD_GUILE*/ - - - - static MuError index_msg_cb (MuIndexStats *stats, void *user_data) { - if (MU_TERMINATE) - return MU_STOP; + if (MU_TERMINATE) + return MU_STOP; - if (stats->_processed % 1000) - return MU_OK; + if (stats->_processed % 1000) + return MU_OK; - print_expr ("(:info index :status running " - ":processed %u :updated %u)", - stats->_processed, stats->_updated); + print_expr ("(:info index :status running " + ":processed %u :updated %u)", + stats->_processed, stats->_updated); - return MU_OK; + return MU_OK; } static void set_my_addresses (MuStore *store, const char *addrstr) { - char **my_addresses; + char **my_addresses; - if (!addrstr) - return; + if (!addrstr) + return; - my_addresses = g_strsplit (addrstr, ",", -1); - mu_store_set_my_addresses (store, (const char**)my_addresses); + my_addresses = g_strsplit (addrstr, ",", -1); + mu_store_set_my_addresses (store, (const char**)my_addresses); - g_strfreev (my_addresses); + g_strfreev (my_addresses); } static char* get_checked_path (const char *path) { - char *cpath; + char *cpath; - cpath = mu_util_dir_expand(path); - if (!cpath || - !mu_util_check_dir (cpath, TRUE, FALSE)) { - print_error (MU_ERROR_IN_PARAMETERS, - "not a readable dir: '%s'"); - g_free (cpath); - return NULL; - } + cpath = mu_util_dir_expand(path); + if (!cpath || + !mu_util_check_dir (cpath, TRUE, FALSE)) { + print_error (MU_ERROR_IN_PARAMETERS, + "not a readable dir: '%s'"); + g_free (cpath); + return NULL; + } - return cpath; + return cpath; } static MuError index_and_maybe_cleanup (MuIndex *index, const char *path, - gboolean cleanup, gboolean lazy_check, GError **err) + gboolean cleanup, gboolean lazy_check, GError **err) { - MuError rv; - MuIndexStats stats, stats2; + MuError rv; + MuIndexStats stats, stats2; - mu_index_stats_clear (&stats); - rv = mu_index_run (index, path, FALSE, lazy_check, &stats, - index_msg_cb, NULL, NULL); + mu_index_stats_clear (&stats); + rv = mu_index_run (index, path, FALSE, lazy_check, &stats, + index_msg_cb, NULL, NULL); - if (rv != MU_OK && rv != MU_STOP) { - mu_util_g_set_error (err, MU_ERROR_INTERNAL, "indexing failed"); - return rv; - } + if (rv != MU_OK && rv != MU_STOP) { + mu_util_g_set_error (err, MU_ERROR_INTERNAL, "indexing failed"); + return rv; + } - mu_index_stats_clear (&stats2); - if (cleanup) { - rv = mu_index_cleanup (index, &stats2, NULL, NULL, err); - if (rv != MU_OK && rv != MU_STOP) { - mu_util_g_set_error (err, MU_ERROR_INTERNAL, - "cleanup failed"); - return rv; - } - } + mu_index_stats_clear (&stats2); + if (cleanup) { + rv = mu_index_cleanup (index, &stats2, NULL, NULL, err); + if (rv != MU_OK && rv != MU_STOP) { + mu_util_g_set_error (err, MU_ERROR_INTERNAL, + "cleanup failed"); + return rv; + } + } - print_expr ("(:info index :status complete " - ":processed %u :updated %u :cleaned-up %u)", - stats._processed, stats._updated, stats2._cleaned_up); + print_expr ("(:info index :status complete " + ":processed %u :updated %u :cleaned-up %u)", + stats._processed, stats._updated, stats2._cleaned_up); - return rv; + return rv; } /* @@ -1103,37 +1076,40 @@ index_and_maybe_cleanup (MuIndex *index, const char *path, static MuError cmd_index (ServerContext *ctx, GHashTable *args, GError **err) { - MuIndex *index; - const char *argpath; - char *path; - gboolean cleanup, lazy_check; + MuIndex *index; + const char *argpath; + char *path; + gboolean cleanup, lazy_check, contacts; - index = NULL; + index = NULL; - GET_STRING_OR_ERROR_RETURN (args, "path", &argpath, err); - if (!(path = get_checked_path (argpath))) - goto leave; + GET_STRING_OR_ERROR_RETURN (args, "path", &argpath, err); + if (!(path = get_checked_path (argpath))) + goto leave; - set_my_addresses (ctx->store, get_string_from_args - (args, "my-addresses", TRUE, NULL)); + set_my_addresses (ctx->store, get_string_from_args + (args, "my-addresses", TRUE, NULL)); - if (!(index = mu_index_new (ctx->store, err))) - goto leave; + if (!(index = mu_index_new (ctx->store, err))) + goto leave; - cleanup = get_bool_from_args (args, "cleanup", TRUE, NULL); - lazy_check = get_bool_from_args (args, "lazy-check", TRUE, NULL); + cleanup = get_bool_from_args (args, "cleanup", TRUE, NULL); + lazy_check = get_bool_from_args (args, "lazy-check", TRUE, NULL); + lazy_check = get_bool_from_args (args, "contacts", TRUE, NULL); - index_and_maybe_cleanup (index, path, cleanup, lazy_check, err); + index_and_maybe_cleanup (index, path, + cleanup, lazy_check, + err); leave: - g_free (path); + g_free (path); - if (err && *err) - print_and_clear_g_error (err); + if (err && *err) + print_and_clear_g_error (err); - mu_index_destroy (index); + mu_index_destroy (index); - return MU_OK; + return MU_OK; } @@ -1143,17 +1119,17 @@ leave: static MuError cmd_mkdir (ServerContext *ctx, GHashTable *args, GError **err) { - const char *path; + const char *path; - GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); + GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); - if (!mu_maildir_mkdir (path, 0755, FALSE, err)) - print_and_clear_g_error (err); - else - print_expr ("(:info mkdir :message \"%s has been created\")", - path); + if (!mu_maildir_mkdir (path, 0755, FALSE, err)) + print_and_clear_g_error (err); + else + print_expr ("(:info mkdir :message \"%s has been created\")", + path); - return MU_OK; + return MU_OK; } @@ -1161,96 +1137,96 @@ cmd_mkdir (ServerContext *ctx, GHashTable *args, GError **err) static MuFlags get_flags (const char *path, const char *flagstr) { - if (!flagstr) - return MU_FLAG_NONE; /* ie., ignore flags */ - else { - /* if there's a '+' or '-' sign in the string, it must - * be a flag-delta */ - if (strstr (flagstr, "+") || strstr (flagstr, "-")) { - MuFlags oldflags; - oldflags = mu_maildir_get_flags_from_path (path); - return mu_flags_from_str_delta (flagstr, oldflags, - MU_FLAG_TYPE_ANY); - } else - return mu_flags_from_str (flagstr, MU_FLAG_TYPE_ANY, - TRUE /*ignore invalid*/); - } + if (!flagstr) + return MU_FLAG_NONE; /* ie., ignore flags */ + else { + /* if there's a '+' or '-' sign in the string, it must + * be a flag-delta */ + if (strstr (flagstr, "+") || strstr (flagstr, "-")) { + MuFlags oldflags; + oldflags = mu_maildir_get_flags_from_path (path); + return mu_flags_from_str_delta (flagstr, oldflags, + MU_FLAG_TYPE_ANY); + } else + return mu_flags_from_str (flagstr, MU_FLAG_TYPE_ANY, + TRUE /*ignore invalid*/); + } } static MuError do_move (MuStore *store, unsigned docid, MuMsg *msg, const char *maildir, - MuFlags flags, gboolean new_name, gboolean no_view, GError **err) + MuFlags flags, gboolean new_name, gboolean no_view, GError **err) { - unsigned rv; - gchar *sexp; - gboolean different_mdir; + unsigned rv; + gchar *sexp; + gboolean different_mdir; - if (!maildir) { - maildir = mu_msg_get_maildir (msg); - different_mdir = FALSE; - } else - /* are we moving to a different mdir, or is it just flags? */ - different_mdir = - (g_strcmp0 (maildir, mu_msg_get_maildir(msg)) != 0); + if (!maildir) { + maildir = mu_msg_get_maildir (msg); + different_mdir = FALSE; + } else + /* are we moving to a different mdir, or is it just flags? */ + different_mdir = + (g_strcmp0 (maildir, mu_msg_get_maildir(msg)) != 0); - if (!mu_msg_move_to_maildir (msg, maildir, flags, TRUE, - new_name, err)) - return MU_G_ERROR_CODE (err); + if (!mu_msg_move_to_maildir (msg, maildir, flags, TRUE, + new_name, err)) + return MU_G_ERROR_CODE (err); - /* after mu_msg_move_to_maildir, path will be the *new* path, - * and flags and maildir fields will be updated as wel */ - rv = mu_store_update_msg (store, docid, msg, err); - if (rv == MU_STORE_INVALID_DOCID) { - mu_util_g_set_error (err, MU_ERROR_XAPIAN, - "failed to store updated message"); - print_and_clear_g_error (err); - } + /* after mu_msg_move_to_maildir, path will be the *new* path, + * and flags and maildir fields will be updated as wel */ + rv = mu_store_update_msg (store, docid, msg, err); + if (rv == MU_STORE_INVALID_DOCID) { + mu_util_g_set_error (err, MU_ERROR_XAPIAN, + "failed to store updated message"); + print_and_clear_g_error (err); + } - sexp = mu_msg_to_sexp (msg, docid, NULL, MU_MSG_OPTION_VERIFY); - /* note, the :move t thing is a hint to the frontend that it - * could remove the particular header */ - print_expr ("(:update %s :move %s :maybe-view %s)", sexp, - different_mdir ? "t" : "nil", - no_view ? "nil" : "t"); - g_free (sexp); + sexp = mu_msg_to_sexp (msg, docid, NULL, MU_MSG_OPTION_VERIFY); + /* note, the :move t thing is a hint to the frontend that it + * could remove the particular header */ + print_expr ("(:update %s :move %s :maybe-view %s)", sexp, + different_mdir ? "t" : "nil", + no_view ? "nil" : "t"); + g_free (sexp); - return MU_OK; + return MU_OK; } static MuError move_docid (MuStore *store, unsigned docid, const char* flagstr, - gboolean new_name, gboolean no_view, GError **err) + gboolean new_name, gboolean no_view, GError **err) { - MuMsg *msg; - MuError rv; - MuFlags flags; + MuMsg *msg; + MuError rv; + MuFlags flags; - rv = MU_ERROR; - msg = mu_store_get_msg (store, docid, err); + rv = MU_ERROR; + msg = mu_store_get_msg (store, docid, err); - if (!msg) - goto leave; + if (!msg) + goto leave; - flags = flagstr ? get_flags (mu_msg_get_path(msg), flagstr) : - mu_msg_get_flags (msg); + flags = flagstr ? get_flags (mu_msg_get_path(msg), flagstr) : + mu_msg_get_flags (msg); - if (flags == MU_FLAG_INVALID) { - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "invalid flags"); - goto leave; - } + if (flags == MU_FLAG_INVALID) { + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "invalid flags"); + goto leave; + } - rv = do_move (store, docid, msg, NULL, flags, - new_name, no_view, err); + rv = do_move (store, docid, msg, NULL, flags, + new_name, no_view, err); leave: - if (msg) - mu_msg_unref (msg); - if (rv != MU_OK) - print_and_clear_g_error (err); + if (msg) + mu_msg_unref (msg); + if (rv != MU_OK) + print_and_clear_g_error (err); - return rv; + return rv; } @@ -1262,34 +1238,34 @@ leave: static gboolean move_msgid_maybe (ServerContext *ctx, GHashTable *args, GError **err) { - GSList *docids, *cur; - const char* maildir, *msgid, *flagstr; - gboolean new_name, no_view; + GSList *docids, *cur; + const char* maildir, *msgid, *flagstr; + gboolean new_name, no_view; - maildir = get_string_from_args (args, "maildir", TRUE, err); - msgid = get_string_from_args (args, "msgid", TRUE, err); - flagstr = get_string_from_args (args, "flags", TRUE, err); - new_name = get_bool_from_args (args, "newname", TRUE, err); - no_view = get_bool_from_args (args, "noupdate", TRUE, err); + maildir = get_string_from_args (args, "maildir", TRUE, err); + msgid = get_string_from_args (args, "msgid", TRUE, err); + flagstr = get_string_from_args (args, "flags", TRUE, err); + new_name = get_bool_from_args (args, "newname", TRUE, err); + no_view = get_bool_from_args (args, "noupdate", TRUE, err); - /* you cannot use 'maildir' for multiple messages at once */ - if (!msgid || !flagstr || maildir) - return FALSE; + /* you cannot use 'maildir' for multiple messages at once */ + if (!msgid || !flagstr || maildir) + return FALSE; - if (!(docids = get_docids_from_msgids (ctx->query, msgid, - -1/*unlimited*/, err))) { - print_and_clear_g_error (err); - return TRUE; - } + if (!(docids = get_docids_from_msgids (ctx->query, msgid, + -1/*unlimited*/, err))) { + print_and_clear_g_error (err); + return TRUE; + } - for (cur = docids; cur; cur = g_slist_next(cur)) - if (move_docid (ctx->store, GPOINTER_TO_SIZE(cur->data), - flagstr, new_name, no_view, err) != MU_OK) - break; + for (cur = docids; cur; cur = g_slist_next(cur)) + if (move_docid (ctx->store, GPOINTER_TO_SIZE(cur->data), + flagstr, new_name, no_view, err) != MU_OK) + break; - g_slist_free (docids); + g_slist_free (docids); - return TRUE; + return TRUE; } @@ -1306,54 +1282,54 @@ move_msgid_maybe (ServerContext *ctx, GHashTable *args, GError **err) static MuError cmd_move (ServerContext *ctx, GHashTable *args, GError **err) { - unsigned docid; - MuMsg *msg; - MuFlags flags; - const char *maildir, *flagstr; - gboolean new_name, no_view; + unsigned docid; + MuMsg *msg; + MuFlags flags; + const char *maildir, *flagstr; + gboolean new_name, no_view; - /* check if the move is based on the message id; if so, handle - * it in move_msgid_maybe */ - if (move_msgid_maybe (ctx, args, err)) - return MU_OK; + /* check if the move is based on the message id; if so, handle + * it in move_msgid_maybe */ + if (move_msgid_maybe (ctx, args, err)) + return MU_OK; - maildir = get_string_from_args (args, "maildir", TRUE, err); - flagstr = get_string_from_args (args, "flags", TRUE, err); - new_name = get_bool_from_args (args, "newname", TRUE, err); - no_view = get_bool_from_args (args, "noupdate", TRUE, err); + maildir = get_string_from_args (args, "maildir", TRUE, err); + flagstr = get_string_from_args (args, "flags", TRUE, err); + new_name = get_bool_from_args (args, "newname", TRUE, err); + no_view = get_bool_from_args (args, "noupdate", TRUE, err); - docid = determine_docid (ctx->query, args, err); - if (docid == MU_STORE_INVALID_DOCID || - !(msg = mu_store_get_msg (ctx->store, docid, err))) { - print_and_clear_g_error (err); - return MU_OK; - } + docid = determine_docid (ctx->query, args, err); + if (docid == MU_STORE_INVALID_DOCID || + !(msg = mu_store_get_msg (ctx->store, docid, err))) { + print_and_clear_g_error (err); + return MU_OK; + } - /* if maildir was not specified, take the current one */ - if (!maildir) - maildir = mu_msg_get_maildir (msg); + /* if maildir was not specified, take the current one */ + if (!maildir) + maildir = mu_msg_get_maildir (msg); - /* determine the real target flags, which come from the - * flags-parameter we received (ie., flagstr), if any, plus - * the existing message flags. */ - if (flagstr) - flags = get_flags (mu_msg_get_path(msg), flagstr); - else - flags = mu_msg_get_flags (msg); + /* determine the real target flags, which come from the + * flags-parameter we received (ie., flagstr), if any, plus + * the existing message flags. */ + if (flagstr) + flags = get_flags (mu_msg_get_path(msg), flagstr); + else + flags = mu_msg_get_flags (msg); - if (flags == MU_FLAG_INVALID) { - print_error (MU_ERROR_IN_PARAMETERS, "invalid flags"); - goto leave; - } + if (flags == MU_FLAG_INVALID) { + print_error (MU_ERROR_IN_PARAMETERS, "invalid flags"); + goto leave; + } - if ((do_move (ctx->store, docid, msg, maildir, flags, - new_name, no_view, err) - != MU_OK)) - print_and_clear_g_error (err); + if ((do_move (ctx->store, docid, msg, maildir, flags, + new_name, no_view, err) + != MU_OK)) + print_and_clear_g_error (err); leave: - mu_msg_unref (msg); - return MU_OK; + mu_msg_unref (msg); + return MU_OK; } @@ -1364,22 +1340,22 @@ leave: static MuError cmd_ping (ServerContext *ctx, GHashTable *args, GError **err) { - unsigned doccount; - doccount = mu_store_count (ctx->store, err); + unsigned doccount; + doccount = mu_store_count (ctx->store, err); - if (doccount == (unsigned)-1) - return print_and_clear_g_error (err); + if (doccount == (unsigned)-1) + return print_and_clear_g_error (err); - print_expr ("(:pong \"" PACKAGE_NAME "\" " - " :props (:crypto %s :guile %s " - " :version \"" VERSION "\" " - " :doccount %u))", - mu_util_supports (MU_FEATURE_CRYPTO) ? "t" : "nil", - mu_util_supports (MU_FEATURE_GUILE|MU_FEATURE_GNUPLOT) - ? "t" : "nil", - doccount); + print_expr ("(:pong \"" PACKAGE_NAME "\" " + " :props (:crypto %s :guile %s " + " :version \"" VERSION "\" " + " :doccount %u))", + mu_util_supports (MU_FEATURE_CRYPTO) ? "t" : "nil", + mu_util_supports (MU_FEATURE_GUILE|MU_FEATURE_GNUPLOT) + ? "t" : "nil", + doccount); - return MU_OK; + return MU_OK; } @@ -1387,9 +1363,9 @@ cmd_ping (ServerContext *ctx, GHashTable *args, GError **err) static MuError cmd_quit (ServerContext *ctx, GHashTable *args , GError **err) { - print_expr (";; quitting"); + print_expr (";; quitting"); - return MU_STOP; + return MU_STOP; } @@ -1403,25 +1379,25 @@ cmd_quit (ServerContext *ctx, GHashTable *args , GError **err) static const char* get_path_from_docid (MuStore *store, unsigned docid, GError **err) { - MuMsg *msg; - const char* msgpath; - static char path[PATH_MAX + 1]; + MuMsg *msg; + const char* msgpath; + static char path[PATH_MAX + 1]; - msg = mu_store_get_msg (store, docid, err); - if (!msg) - return NULL; + msg = mu_store_get_msg (store, docid, err); + if (!msg) + return NULL; - msgpath = mu_msg_get_path (msg); - if (!msgpath) { - mu_msg_unref (msg); - return NULL; - } + msgpath = mu_msg_get_path (msg); + if (!msgpath) { + mu_msg_unref (msg); + return NULL; + } - strncpy (path, msgpath, sizeof(path) - 1); - path[sizeof(path)-1] = '\0'; + strncpy (path, msgpath, sizeof(path) - 1); + path[sizeof(path)-1] = '\0'; - mu_msg_unref (msg); - return path; + mu_msg_unref (msg); + return path; } @@ -1432,36 +1408,36 @@ get_path_from_docid (MuStore *store, unsigned docid, GError **err) static MuError cmd_remove (ServerContext *ctx, GHashTable *args, GError **err) { - unsigned docid; - const char *path; + unsigned docid; + const char *path; - docid = determine_docid (ctx->query, args, err); - if (docid == MU_STORE_INVALID_DOCID) { - print_and_clear_g_error (err); - return MU_OK; - } + docid = determine_docid (ctx->query, args, err); + if (docid == MU_STORE_INVALID_DOCID) { + print_and_clear_g_error (err); + return MU_OK; + } - path = get_path_from_docid (ctx->store, docid, err); - if (!path) { - print_and_clear_g_error (err); - return MU_OK; - } + path = get_path_from_docid (ctx->store, docid, err); + if (!path) { + print_and_clear_g_error (err); + return MU_OK; + } - if (unlink (path) != 0) { - mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_UNLINK, - "%s", strerror (errno)); - print_and_clear_g_error (err); - return MU_OK; - } + if (unlink (path) != 0) { + mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_UNLINK, + "%s", strerror (errno)); + print_and_clear_g_error (err); + return MU_OK; + } - if (!mu_store_remove_path (ctx->store, path)) { - print_error (MU_ERROR_XAPIAN_REMOVE_FAILED, - "failed to remove from database"); - return MU_OK; - } + if (!mu_store_remove_path (ctx->store, path)) { + print_error (MU_ERROR_XAPIAN_REMOVE_FAILED, + "failed to remove from database"); + return MU_OK; + } - print_expr ("(:remove %u)", docid); - return MU_OK; + print_expr ("(:remove %u)", docid); + return MU_OK; } /* 'add' adds a message to the database, and takes two parameters: @@ -1473,43 +1449,43 @@ cmd_remove (ServerContext *ctx, GHashTable *args, GError **err) static MuError cmd_sent (ServerContext *ctx, GHashTable *args, GError **err) { - unsigned docid; - const char *maildir, *path; + unsigned docid; + const char *maildir, *path; - GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); - GET_STRING_OR_ERROR_RETURN (args, "maildir", &maildir, err); + GET_STRING_OR_ERROR_RETURN (args, "path", &path, err); + GET_STRING_OR_ERROR_RETURN (args, "maildir", &maildir, err); - docid = mu_store_add_path (ctx->store, path, maildir, err); - if (docid == MU_STORE_INVALID_DOCID) - print_and_clear_g_error (err); - else { - gchar *escpath; - escpath = mu_str_escape_c_literal (path, TRUE); - print_expr ("(:sent t :path %s :docid %u)", - escpath, docid); - g_free (escpath); - } + docid = mu_store_add_path (ctx->store, path, maildir, err); + if (docid == MU_STORE_INVALID_DOCID) + print_and_clear_g_error (err); + else { + gchar *escpath; + escpath = mu_str_escape_c_literal (path, TRUE); + print_expr ("(:sent t :path %s :docid %u)", + escpath, docid); + g_free (escpath); + } - return MU_OK; + return MU_OK; } static MuMsgOptions get_view_msg_opts (GHashTable *args) { - MuMsgOptions opts; + MuMsgOptions opts; - opts = MU_MSG_OPTION_VERIFY; + opts = MU_MSG_OPTION_VERIFY; - if (get_bool_from_args (args, "extract-images", FALSE, NULL)) - opts |= MU_MSG_OPTION_EXTRACT_IMAGES; - if (get_bool_from_args (args, "use-agent", FALSE, NULL)) - opts |= MU_MSG_OPTION_USE_AGENT; - if (get_bool_from_args (args, "auto-retrieve-key", FALSE, NULL)) - opts |= MU_MSG_OPTION_AUTO_RETRIEVE; - if (get_bool_from_args (args, "extract-encrypted", FALSE, NULL)) - opts |= MU_MSG_OPTION_DECRYPT; + if (get_bool_from_args (args, "extract-images", FALSE, NULL)) + opts |= MU_MSG_OPTION_EXTRACT_IMAGES; + if (get_bool_from_args (args, "use-agent", FALSE, NULL)) + opts |= MU_MSG_OPTION_USE_AGENT; + if (get_bool_from_args (args, "auto-retrieve-key", FALSE, NULL)) + opts |= MU_MSG_OPTION_AUTO_RETRIEVE; + if (get_bool_from_args (args, "extract-encrypted", FALSE, NULL)) + opts |= MU_MSG_OPTION_DECRYPT; - return opts; + return opts; } /* 'view' gets a full (including body etc.) sexp for some message, @@ -1518,41 +1494,41 @@ get_view_msg_opts (GHashTable *args) static MuError cmd_view (ServerContext *ctx, GHashTable *args, GError **err) { - MuMsg *msg; - const gchar *path; - char *sexp; - MuMsgOptions opts; - unsigned docid; + MuMsg *msg; + const gchar *path; + char *sexp; + MuMsgOptions opts; + unsigned docid; - opts = get_view_msg_opts (args); + opts = get_view_msg_opts (args); - /* when 'path' is specified, get the message at path */ - path = get_string_from_args (args, "path", FALSE, NULL); + /* when 'path' is specified, get the message at path */ + path = get_string_from_args (args, "path", FALSE, NULL); - if (path) { - docid = 0; - msg = mu_msg_new_from_file (path, NULL, err); - } else { - docid = determine_docid (ctx->query, args, err); - if (docid == MU_STORE_INVALID_DOCID) { - print_and_clear_g_error (err); - return MU_OK; - } - msg = mu_store_get_msg (ctx->store, docid, err); - } + if (path) { + docid = 0; + msg = mu_msg_new_from_file (path, NULL, err); + } else { + docid = determine_docid (ctx->query, args, err); + if (docid == MU_STORE_INVALID_DOCID) { + print_and_clear_g_error (err); + return MU_OK; + } + msg = mu_store_get_msg (ctx->store, docid, err); + } - if (!msg) { - print_and_clear_g_error (err); - return MU_OK; - } + if (!msg) { + print_and_clear_g_error (err); + return MU_OK; + } - sexp = mu_msg_to_sexp (msg, docid, NULL, opts); - mu_msg_unref (msg); + sexp = mu_msg_to_sexp (msg, docid, NULL, opts); + mu_msg_unref (msg); - print_expr ("(:view %s)\n", sexp); - g_free (sexp); + print_expr ("(:view %s)\n", sexp); + g_free (sexp); - return MU_OK; + return MU_OK; } @@ -1564,42 +1540,41 @@ cmd_view (ServerContext *ctx, GHashTable *args, GError **err) static MuError handle_args (ServerContext *ctx, GHashTable *args, GError **err) { - unsigned u; - const char *cmd; - struct { - const char *cmd; - CmdFunc func; - } cmd_map[] = { - { "add", cmd_add }, - { "compose", cmd_compose }, - { "contacts", cmd_contacts }, - { "extract", cmd_extract }, - { "find", cmd_find }, - { "guile", cmd_guile }, - { "index", cmd_index }, - { "mkdir", cmd_mkdir }, - { "move", cmd_move }, - { "ping", cmd_ping }, - { "quit", cmd_quit }, - { "remove", cmd_remove }, - { "sent", cmd_sent }, - { "view", cmd_view } - }; + unsigned u; + const char *cmd; + struct { + const char *cmd; + CmdFunc func; + } cmd_map[] = { + { "add", cmd_add }, + { "compose", cmd_compose }, + { "contacts", cmd_contacts }, + { "extract", cmd_extract }, + { "find", cmd_find }, + { "index", cmd_index }, + { "mkdir", cmd_mkdir }, + { "move", cmd_move }, + { "ping", cmd_ping }, + { "quit", cmd_quit }, + { "remove", cmd_remove }, + { "sent", cmd_sent }, + { "view", cmd_view } + }; - cmd = g_hash_table_lookup (args, "cmd"); + cmd = g_hash_table_lookup (args, "cmd"); - /* ignore empty */ - if (mu_str_is_empty (cmd)) - return MU_OK; + /* ignore empty */ + if (mu_str_is_empty (cmd)) + return MU_OK; - for (u = 0; u != G_N_ELEMENTS (cmd_map); ++u) - if (g_strcmp0(cmd, cmd_map[u].cmd) == 0) - return cmd_map[u].func (ctx, args, err); + for (u = 0; u != G_N_ELEMENTS (cmd_map); ++u) + if (g_strcmp0(cmd, cmd_map[u].cmd) == 0) + return cmd_map[u].func (ctx, args, err); - mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, - "unknown command '%s'", cmd ? cmd : ""); + mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS, + "unknown command '%s'", cmd ? cmd : ""); - return MU_G_ERROR_CODE (err); + return MU_G_ERROR_CODE (err); } @@ -1607,56 +1582,56 @@ handle_args (ServerContext *ctx, GHashTable *args, GError **err) MuError mu_cmd_server (MuStore *store, MuConfig *opts/*unused*/, GError **err) { - ServerContext ctx; - gboolean do_quit; + ServerContext ctx; + gboolean do_quit; - g_return_val_if_fail (store, MU_ERROR_INTERNAL); + g_return_val_if_fail (store, MU_ERROR_INTERNAL); - ctx.store = store; - ctx.query = mu_query_new (store, err); - if (!ctx.query) - return MU_G_ERROR_CODE (err); + ctx.store = store; + ctx.query = mu_query_new (store, err); + if (!ctx.query) + return MU_G_ERROR_CODE (err); - srand (time(NULL)*getpid()); + srand (time(NULL)*getpid()); - install_sig_handler (); + install_sig_handler (); - g_print (";; welcome to " PACKAGE_STRING "\n"); + g_print (";; welcome to " PACKAGE_STRING "\n"); - /* the main REPL */ - do_quit = FALSE; - while (!MU_TERMINATE && !do_quit) { + /* the main REPL */ + do_quit = FALSE; + while (!MU_TERMINATE && !do_quit) { - GHashTable *args; - GError *my_err; + GHashTable *args; + GError *my_err; - /* args will receive a the command as a list of - * strings. returning NULL indicates an error */ - my_err = NULL; - args = read_command_line (&my_err); - if (!args) { - if (feof(stdin)) - break; - if (my_err) - print_and_clear_g_error (&my_err); - continue; - } + /* args will receive a the command as a list of + * strings. returning NULL indicates an error */ + my_err = NULL; + args = read_command_line (&my_err); + if (!args) { + if (feof(stdin)) + break; + if (my_err) + print_and_clear_g_error (&my_err); + continue; + } - switch (handle_args (&ctx, args, &my_err)) { - case MU_OK: - break; - case MU_STOP: - do_quit = TRUE; - break; - default: /* some error occurred */ - print_and_clear_g_error (&my_err); - } + switch (handle_args (&ctx, args, &my_err)) { + case MU_OK: + break; + case MU_STOP: + do_quit = TRUE; + break; + default: /* some error occurred */ + print_and_clear_g_error (&my_err); + } - g_hash_table_destroy (args); - } + g_hash_table_destroy (args); + } - mu_store_flush (ctx.store); - mu_query_destroy (ctx.query); + mu_store_flush (ctx.store); + mu_query_destroy (ctx.query); - return MU_OK; + return MU_OK; } diff --git a/mu/mu-cmd.c b/mu/mu-cmd.c index d887f32f..55841315 100644 --- a/mu/mu-cmd.c +++ b/mu/mu-cmd.c @@ -644,13 +644,14 @@ mu_cmd_execute (MuConfig *opts, GError **err) /* already handled in mu-config.c */ case MU_CONFIG_CMD_HELP: return MU_OK; - case MU_CONFIG_CMD_CFIND: merr = mu_cmd_cfind (opts, err); break; case MU_CONFIG_CMD_MKDIR: merr = mu_cmd_mkdir (opts, err); break; case MU_CONFIG_CMD_SCRIPT: merr = mu_cmd_script (opts, err); break; case MU_CONFIG_CMD_VIEW: merr = mu_cmd_view (opts, err); break; case MU_CONFIG_CMD_VERIFY: merr = mu_cmd_verify (opts, err); break; case MU_CONFIG_CMD_EXTRACT: merr = mu_cmd_extract (opts, err); break; + case MU_CONFIG_CMD_CFIND: + merr = with_store (mu_cmd_cfind, opts, TRUE, err); break; case MU_CONFIG_CMD_FIND: merr = with_store (mu_cmd_find, opts, TRUE, err); break; case MU_CONFIG_CMD_INDEX: diff --git a/mu/mu-cmd.h b/mu/mu-cmd.h index b8693ec0..9332d94c 100644 --- a/mu/mu-cmd.h +++ b/mu/mu-cmd.h @@ -118,13 +118,14 @@ MuError mu_cmd_script (MuConfig *opts, GError **err); /** * execute the cfind command * + * @param store store object to use * @param opts configuration options * @param err receives error information, or NULL * * @return MU_OK (0) if the command succeeds, * some error code otherwise */ -MuError mu_cmd_cfind (MuConfig *opts, GError **err); +MuError mu_cmd_cfind (MuStore *store, MuConfig *opts, GError **err); /** diff --git a/mu/mu-config.c b/mu/mu-config.c index 0ee2d352..27a49013 100644 --- a/mu/mu-config.c +++ b/mu/mu-config.c @@ -54,7 +54,8 @@ get_output_format (const char *formatstr) {"json", MU_CONFIG_FORMAT_JSON}, {"xml", MU_CONFIG_FORMAT_XML}, {"xquery", MU_CONFIG_FORMAT_XQUERY}, - {"mquery", MU_CONFIG_FORMAT_MQUERY} + {"mquery", MU_CONFIG_FORMAT_MQUERY}, + {"debug", MU_CONFIG_FORMAT_DEBUG} }; for (i = 0; i != G_N_ELEMENTS(formats); i++) diff --git a/mu/mu-config.h b/mu/mu-config.h index 07a2e5da..1c458236 100644 --- a/mu/mu-config.h +++ b/mu/mu-config.h @@ -47,6 +47,7 @@ enum _MuConfigFormat { 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) */