* mu-cfind: some cleanups / better help

This commit is contained in:
djcb 2012-10-24 23:47:47 +03:00
parent 7f20ab33b9
commit a01196499f
8 changed files with 260 additions and 260 deletions

View File

@ -55,30 +55,6 @@ struct _MuContacts {
}; };
/*
* we use the e-mail address to create a key in the GKeyFile, but we
* have to mutilate a bit so that it's (a) *cough* practically-unique
* and (b) valid as a GKeyFile group name (ie., valid utf8, no control
* chars, no '[' or ']')
*/
static const char*
encode_email_address (const char *addr)
{
static char enc[254 + 1]; /* max size for an e-mail addr */
char *cur;
if (!addr)
return FALSE;
/* make sure chars are with {' ' .. '~'}, and not '[' ']' */
for (cur = strncpy(enc, addr, sizeof(enc)); *cur != '\0'; ++cur)
if (!isalnum(*cur)) {
*cur = 'A' + (*cur % ('Z' - 'A'));
} else
*cur = tolower(*cur);
return enc;
}
static GKeyFile* static GKeyFile*
load_key_file (const char *path) load_key_file (const char *path)
@ -235,31 +211,53 @@ mu_contacts_clear (MuContacts *self)
} }
/*
* we use the e-mail address to create a key in the GKeyFile, but we
* have to mutilate a bit so that it's (a) *cough* practically-unique
* and (b) valid as a GKeyFile group name (ie., valid utf8, no control
* chars, no '[' or ']')
*/
static const char*
encode_email_address (const char *addr)
{
static char enc[254 + 1]; /* max size for an e-mail addr */
char *cur;
if (!addr)
return FALSE;
/* make sure chars are with {' ' .. '~'}, and not '[' ']' */
for (cur = strncpy(enc, addr, sizeof(enc)); *cur != '\0'; ++cur)
if (!isalnum(*cur)) {
*cur = 'A' + (*cur % ('Z' - 'A'));
} else
*cur = tolower(*cur);
return enc;
}
gboolean gboolean
mu_contacts_add (MuContacts *self, const char *email, const char *name, mu_contacts_add (MuContacts *self, const char *addr, const char *name,
gboolean personal, time_t tstamp) gboolean personal, time_t tstamp)
{ {
ContactInfo *cinfo; ContactInfo *cinfo;
const char* group; const char *group;
g_return_val_if_fail (self, FALSE); g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (email, FALSE); g_return_val_if_fail (addr, FALSE);
/* add the info, if either there is no info for this email /* add the info, if either there is no info for this email
* yet, *OR* the new one is more recent and does not have an * yet, *OR* the new one is more recent and does not have an
* empty name */ * empty name */
group = encode_email_address (email); group = encode_email_address (addr);
cinfo = (ContactInfo*) g_hash_table_lookup (self->_hash, group); cinfo = (ContactInfo*) g_hash_table_lookup (self->_hash, group);
if (!cinfo || (cinfo->_tstamp < tstamp && !mu_str_is_empty(name))) { if (!cinfo || (cinfo->_tstamp < tstamp && !mu_str_is_empty(name))) {
ContactInfo *ci; ContactInfo *ci;
ci = contact_info_new (g_strdup(email), ci = contact_info_new (g_strdup(addr),
name ? g_strdup(name) : NULL, personal, name ? g_strdup(name) : NULL, personal,
tstamp); tstamp);
g_hash_table_insert (self->_hash, g_strdup(group), ci); g_hash_table_insert (self->_hash, g_strdup(group), ci);
return self->_dirty = TRUE; return self->_dirty = TRUE;
} }

View File

@ -625,102 +625,6 @@ mu_str_convert_to_utf8 (const char* buffer, const char *charset)
} }
gchar*
mu_str_guess_last_name (const char *name)
{
const gchar *lastsp;
if (!name)
return g_strdup ("");
lastsp = g_strrstr (name, " ");
return g_strdup (lastsp ? lastsp + 1 : "");
}
gchar*
mu_str_guess_first_name (const char *name)
{
const gchar *lastsp;
if (!name)
return g_strdup ("");
lastsp = g_strrstr (name, " ");
if (lastsp)
return g_strndup (name, lastsp - name);
else
return g_strdup (name);
}
static gchar*
cleanup_str (const char* str)
{
gchar *s;
const gchar *cur;
unsigned i;
if (mu_str_is_empty(str))
return g_strdup ("");
s = g_new0 (char, strlen(str) + 1);
for (cur = str, i = 0; *cur; ++cur) {
if (ispunct(*cur) || isspace(*cur))
continue;
else
s[i++] = *cur;
}
return s;
}
gchar*
mu_str_guess_nick (const char* name)
{
gchar *fname, *lname, *nick;
gchar initial[7];
fname = mu_str_guess_first_name (name);
lname = mu_str_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;
}
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);
leave:
{
gchar *tmp;
tmp = cleanup_str (nick);
g_free (nick);
nick = tmp;
}
return nick;
}
gchar* gchar*
mu_str_quoted_from_strv (const gchar **params) mu_str_quoted_from_strv (const gchar **params)
{ {

View File

@ -319,45 +319,6 @@ void mu_str_free_list (GSList *lst);
const gchar* mu_str_subject_normalize (const gchar* str); const gchar* mu_str_subject_normalize (const gchar* str);
/**
* guess some nick name for the given name; if we can determine an
* first name, last name, the nick will be first name + the first char
* of the last name. otherwise, it's just the first name. clearly,
* this is just a rough guess for setting an initial value for nicks.
*
* @param name a name
*
* @return the guessed nick, as a newly allocated string (free with g_free)
*/
gchar* mu_str_guess_nick (const char* name)
G_GNUC_WARN_UNUSED_RESULT;
/**
* guess the first name for the given name; clearly,
* this is just a rough guess for setting an initial value.
*
* @param name a name
*
* @return the first name, as a newly allocated string (free with
* g_free)
*/
gchar* mu_str_guess_first_name (const char* name)
G_GNUC_WARN_UNUSED_RESULT;
/**
* guess the last name for the given name; clearly,
* this is just a rough guess for setting an initial value.
*
* @param name a name
*
* @return the last name, as a newly allocated string (free with
* g_free)
*/
gchar* mu_str_guess_last_name (const char* name)
G_GNUC_WARN_UNUSED_RESULT;
/** /**
* take a list of strings, and return the concatenation of their * take a list of strings, and return the concatenation of their
* quoted forms * quoted forms

View File

@ -368,77 +368,77 @@ test_mu_str_to_list_strip (void)
static void /* static void */
test_mu_str_guess_first_name (void) /* test_mu_str_guess_first_name (void) */
{ /* { */
int i; /* int i; */
struct { /* struct { */
char *src, *exp; /* char *src, *exp; */
} tests[] = { /* } tests[] = { */
{ "Richard M. Stallman", "Richard M." }, /* { "Richard M. Stallman", "Richard M." }, */
{ "John Rambo", "John" }, /* { "John Rambo", "John" }, */
{ "Ivanhoe", "Ivanhoe" }, /* { "Ivanhoe", "Ivanhoe" }, */
{ "", "" } /* { "", "" } */
}; /* }; */
for (i = 0; i != G_N_ELEMENTS(tests); ++i) { /* for (i = 0; i != G_N_ELEMENTS(tests); ++i) { */
gchar *s; /* gchar *s; */
s = mu_str_guess_first_name (tests[i].src); /* s = mu_str_guess_first_name (tests[i].src); */
g_assert_cmpstr (s, ==, tests[i].exp); /* g_assert_cmpstr (s, ==, tests[i].exp); */
g_free (s); /* g_free (s); */
} /* } */
} /* } */
static void /* static void */
test_mu_str_guess_last_name (void) /* test_mu_str_guess_last_name (void) */
{ /* { */
int i; /* int i; */
struct { /* struct { */
char *src, *exp; /* char *src, *exp; */
} tests[] = { /* } tests[] = { */
{ "Richard M. Stallman", "Stallman" }, /* { "Richard M. Stallman", "Stallman" }, */
{ "John Rambo", "Rambo" }, /* { "John Rambo", "Rambo" }, */
{ "Ivanhoe", "" }, /* { "Ivanhoe", "" }, */
{ "", "" } /* { "", "" } */
}; /* }; */
for (i = 0; i != G_N_ELEMENTS(tests); ++i) { /* for (i = 0; i != G_N_ELEMENTS(tests); ++i) { */
gchar *s; /* gchar *s; */
s = mu_str_guess_last_name (tests[i].src); /* s = mu_str_guess_last_name (tests[i].src); */
g_assert_cmpstr (s, ==, tests[i].exp); /* g_assert_cmpstr (s, ==, tests[i].exp); */
g_free (s); /* g_free (s); */
} /* } */
} /* } */
static void /* static void */
test_mu_str_guess_nick (void) /* test_mu_str_guess_nick (void) */
{ /* { */
int i; /* int i; */
struct { /* struct { */
char *src, *exp; /* char *src, *exp; */
} tests[] = { /* } tests[] = { */
{ "Richard M. Stallman", "RichardMS" }, /* { "Richard M. Stallman", "RichardMS" }, */
{ "John Rambo", "JohnR" }, /* { "John Rambo", "JohnR" }, */
{ "Ivanhoe", "Ivanhoe" }, /* { "Ivanhoe", "Ivanhoe" }, */
{ "", "" } /* { "", "" } */
}; /* }; */
for (i = 0; i != G_N_ELEMENTS(tests); ++i) { /* for (i = 0; i != G_N_ELEMENTS(tests); ++i) { */
gchar *s; /* gchar *s; */
s = mu_str_guess_nick (tests[i].src); /* s = mu_str_guess_nick (tests[i].src); */
g_assert_cmpstr (s, ==, tests[i].exp); /* g_assert_cmpstr (s, ==, tests[i].exp); */
g_free (s); /* g_free (s); */
} /* } */
} /* } */
@ -509,12 +509,12 @@ main (int argc, char *argv[])
g_test_add_func ("/mu-str/mu-str-esc-to-list", g_test_add_func ("/mu-str/mu-str-esc-to-list",
test_mu_str_esc_to_list); test_mu_str_esc_to_list);
g_test_add_func ("/mu-str/mu_str_guess_first_name", /* g_test_add_func ("/mu-str/mu_str_guess_first_name", */
test_mu_str_guess_first_name); /* test_mu_str_guess_first_name); */
g_test_add_func ("/mu-str/mu_str_guess_last_name", /* g_test_add_func ("/mu-str/mu_str_guess_last_name", */
test_mu_str_guess_last_name); /* test_mu_str_guess_last_name); */
g_test_add_func ("/mu-str/mu_str_guess_nick", /* g_test_add_func ("/mu-str/mu_str_guess_nick", */
test_mu_str_guess_nick); /* test_mu_str_guess_nick); */
g_test_add_func ("/mu-str/mu_str_subject_normalize", g_test_add_func ("/mu-str/mu_str_subject_normalize",
test_mu_str_subject_normalize); test_mu_str_subject_normalize);

View File

@ -23,6 +23,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "mu-cmd.h" #include "mu-cmd.h"
#include "mu-util.h" #include "mu-util.h"
@ -31,6 +33,127 @@
#include "mu-contacts.h" #include "mu-contacts.h"
#include "mu-runtime.h" #include "mu-runtime.h"
/**
* guess the last name for the given name; clearly,
* this is just a rough guess for setting an initial value.
*
* @param name a name
*
* @return the last name, as a newly allocated string (free with
* g_free)
*/
static gchar*
guess_last_name (const char *name)
{
const gchar *lastsp;
if (!name)
return g_strdup ("");
lastsp = g_strrstr (name, " ");
return g_strdup (lastsp ? lastsp + 1 : "");
}
/**
* guess the first name for the given name; clearly,
* this is just a rough guess for setting an initial value.
*
* @param name a name
*
* @return the first name, as a newly allocated string (free with
* g_free)
*/
static gchar*
guess_first_name (const char *name)
{
const gchar *lastsp;
if (!name)
return g_strdup ("");
lastsp = g_strrstr (name, " ");
if (lastsp)
return g_strndup (name, lastsp - name);
else
return g_strdup (name);
}
/**
* guess some nick name for the given name; if we can determine an
* first name, last name, the nick will be first name + the first char
* of the last name. otherwise, it's just the first name. clearly,
* this is just a rough guess for setting an initial value for nicks.
*
* @param name a name
*
* @return the guessed nick, as a newly allocated string (free with g_free)
*/
static gchar*
cleanup_str (const char* str)
{
gchar *s;
const gchar *cur;
unsigned i;
if (mu_str_is_empty(str))
return g_strdup ("");
s = g_new0 (char, strlen(str) + 1);
for (cur = str, i = 0; *cur; ++cur) {
if (ispunct(*cur) || isspace(*cur))
continue;
else
s[i++] = *cur;
}
return s;
}
static gchar*
guess_nick (const char* name)
{
gchar *fname, *lname, *nick;
gchar initial[7];
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;
}
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);
leave:
{
gchar *tmp;
tmp = cleanup_str (nick);
g_free (nick);
nick = tmp;
}
return nick;
}
static void static void
print_header (MuConfigFormat format) print_header (MuConfigFormat format)
{ {
@ -52,8 +175,8 @@ each_contact_bbdb (const char *email, const char *name, time_t tstamp)
{ {
char *fname, *lname, *now, *timestamp; char *fname, *lname, *now, *timestamp;
fname = mu_str_guess_first_name (name); fname = guess_first_name (name);
lname = mu_str_guess_last_name (name); lname = guess_last_name (name);
now = mu_date_str ("%Y-%m-%d", time(NULL)); now = mu_date_str ("%Y-%m-%d", time(NULL));
timestamp = mu_date_str ("%Y-%m-%d", tstamp); timestamp = mu_date_str ("%Y-%m-%d", tstamp);
@ -76,7 +199,7 @@ each_contact_mutt_alias (const char *email, const char *name)
if (!name) if (!name)
return; return;
nick = mu_str_guess_nick (name); nick = guess_nick (name);
mu_util_print_encoded ("alias %s %s <%s>\n", mu_util_print_encoded ("alias %s %s <%s>\n",
nick, name, email); nick, name, email);
g_free (nick); g_free (nick);
@ -92,7 +215,7 @@ each_contact_wl (const char *email, const char *name)
if (!name) if (!name)
return; return;
nick = mu_str_guess_nick (name); nick = guess_nick (name);
mu_util_print_encoded ("%s \"%s\" \"%s\"\n", mu_util_print_encoded ("%s \"%s\" \"%s\"\n",
email, nick, name); email, nick, name);
g_free (nick); g_free (nick);

View File

@ -273,7 +273,7 @@ config_options_group_cfind (void)
GOptionGroup *og; GOptionGroup *og;
GOptionEntry entries[] = { GOptionEntry entries[] = {
{"format", 'o', 0, G_OPTION_ARG_STRING, &MU_CONFIG.formatstr, {"format", 'o', 0, G_OPTION_ARG_STRING, &MU_CONFIG.formatstr,
"output format ('plain'(*), 'mutt', 'wanderlust'," "output format ('plain'(*), 'mutt', 'wl',"
"'org-contact', 'csv')", "<format>"}, "'org-contact', 'csv')", "<format>"},
{"personal", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.personal, {"personal", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.personal,
"whether to only get 'personal' contacts", NULL}, "whether to only get 'personal' contacts", NULL},
@ -476,7 +476,7 @@ cmd_from_string (const char *str)
static gboolean static gboolean
parse_cmd (int *argcp, char ***argvp) parse_cmd (int *argcp, char ***argvp, GError **err)
{ {
MU_CONFIG.cmd = MU_CONFIG_CMD_NONE; MU_CONFIG.cmd = MU_CONFIG_CMD_NONE;
MU_CONFIG.cmdstr = NULL; MU_CONFIG.cmdstr = NULL;
@ -492,6 +492,23 @@ parse_cmd (int *argcp, char ***argvp)
MU_CONFIG.cmdstr = (*argvp)[1]; MU_CONFIG.cmdstr = (*argvp)[1];
MU_CONFIG.cmd = cmd_from_string (MU_CONFIG.cmdstr); MU_CONFIG.cmd = cmd_from_string (MU_CONFIG.cmdstr);
#ifndef BUILD_GUILE
if (MU_CONFIG.cmd == MU_CONFIG_CMD_SCRIPT) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"command 'script' not supported");
return FALSE;
}
#endif /*!BUILD_GUILE*/
#ifndef BUILD_CRYPTO
if (MU_CONFIG.cmd == MU_CONFIG_CMD_VERIFIY) {
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"command 'verify' not supported");
return FALSE;
}
#endif /*!BUILD_CRYPTO */
return TRUE; return TRUE;
} }
@ -627,9 +644,8 @@ show_usage (void)
static gboolean static gboolean
parse_params (int *argcp, char ***argvp) parse_params (int *argcp, char ***argvp, GError **err)
{ {
GError *err;
GOptionContext *context; GOptionContext *context;
GOptionGroup *group; GOptionGroup *group;
gboolean rv; gboolean rv;
@ -648,44 +664,32 @@ parse_params (int *argcp, char ***argvp)
case MU_CONFIG_CMD_HELP: case MU_CONFIG_CMD_HELP:
/* 'help' is special; sucks in the options of the /* 'help' is special; sucks in the options of the
* command after it */ * command after it */
rv = g_option_context_parse (context, argcp, argvp, &err) && rv = g_option_context_parse (context, argcp, argvp, err) &&
cmd_help (); cmd_help ();
break; break;
case MU_CONFIG_CMD_SCRIPT:
/* script feeds the rest of the options to the script, so
* we accept all of them */
g_option_context_set_ignore_unknown_options (context, TRUE);
/* fall through */
default: default:
group = get_option_group (MU_CONFIG.cmd); group = get_option_group (MU_CONFIG.cmd);
if (group) if (group)
g_option_context_add_group(context, group); g_option_context_add_group(context, group);
rv = g_option_context_parse (context, argcp, argvp, &err); rv = g_option_context_parse (context, argcp, argvp, err);
} }
g_option_context_free (context); g_option_context_free (context);
if (rv) return rv ? TRUE : FALSE;
return TRUE;
/* something when wrong */
g_printerr ("mu: option error: %s\n", err ? err->message : "?");
g_clear_error (&err);
return FALSE;
} }
MuConfig* MuConfig*
mu_config_init (int *argcp, char ***argvp) mu_config_init (int *argcp, char ***argvp, GError **err)
{ {
g_return_val_if_fail (argcp && argvp, NULL); g_return_val_if_fail (argcp && argvp, NULL);
memset (&MU_CONFIG, 0, sizeof(MU_CONFIG)); memset (&MU_CONFIG, 0, sizeof(MU_CONFIG));
if (!parse_cmd (argcp, argvp)) if (!parse_cmd (argcp, argvp, err))
goto errexit; goto errexit;
if (!parse_params(argcp, argvp)) if (!parse_params(argcp, argvp, err))
goto errexit; goto errexit;
/* fill in the defaults if user did not specify */ /* fill in the defaults if user did not specify */

View File

@ -188,12 +188,14 @@ typedef struct _MuConfig MuConfig;
* mu_config_init, you should also call mu_config_uninit when the data * mu_config_init, you should also call mu_config_uninit when the data
* is no longer needed. * is no longer needed.
* *
* Note that is _static_ data, ie., mu_config_init will always return * Note that this is _static_ data, ie., mu_config_init will always
* the same pointer * return the same pointer
* *
* @param opts options * @param argcp: pointer to argc
* @param argvp: pointer to argv
* @param err: receives error information
*/ */
MuConfig *mu_config_init (int *argcp, char ***argvp) MuConfig *mu_config_init (int *argcp, char ***argvp, GError **err)
G_GNUC_WARN_UNUSED_RESULT; G_GNUC_WARN_UNUSED_RESULT;
/** /**
* free the MuConfig structure * free the MuConfig structure

View File

@ -27,10 +27,18 @@ files must be specified with an absolute path.
#BEGIN MU_CONFIG_CMD_CFIND #BEGIN MU_CONFIG_CMD_CFIND
#STRING #STRING
mu cfind [options] [<pattern>] mu cfind [options] [--format=<format>] [<pattern>]
#STRING #STRING
mu cfind is the mu command to find contacts in the mu database and export them mu cfind is the mu command to find contacts in the mu database and export them
for use in other programs. for use in other programs.
<format> is one of:
mutt-alias
mutt-ab
wl
csv
org-contact
bbdb
#END #END
#BEGIN MU_CONFIG_CMD_EXTRACT #BEGIN MU_CONFIG_CMD_EXTRACT