Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/cmd list terms #38

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions lib/mu-store-read.cc
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,31 @@ mu_store_foreach (MuStore *self,
return MU_OK;
}

MuError
mu_store_foreach_term (MuStore *self,
MuStoreForeachTermFunc func, void *user_data, GError **err)
{
g_return_val_if_fail (self, MU_ERROR);
g_return_val_if_fail (func, MU_ERROR);

try {
Xapian::Database &db = *self->db_read_only();

for (Xapian::TermIterator iter = db.allterms_begin();
iter != db.allterms_end(); ++iter) {
const std::string &term(*iter);
unsigned int term_freq = iter.get_termfreq();
MuError res = func (term.c_str(), term_freq, user_data);
if (res != MU_OK)
return res;
}

} MU_XAPIAN_CATCH_BLOCK_G_ERROR_RETURN(err, MU_ERROR_XAPIAN,
MU_ERROR_XAPIAN);

return MU_OK;
}



MuMsg*
Expand Down
17 changes: 17 additions & 0 deletions lib/mu-store.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,23 @@ typedef MuError (*MuStoreForeachFunc) (const char* path,
MuError mu_store_foreach (MuStore *self, MuStoreForeachFunc func,
void *user_data, GError **err);

/**
* call a function for each term in the database
*
* @param self a valid store
* @param func a callback function to to call for each term
* @param user_data a user pointer passed to the callback function
* @param err to receive error info or NULL. err->code is MuError value
*
* @return MU_OK if all went well, MU_STOP if the foreach was interrupted,
* MU_ERROR in case of error
*/
typedef MuError (*MuStoreForeachTermFunc) (const char* term,
const unsigned int term_freq,
void *user_data);
MuError mu_store_foreach_term (MuStore *self, MuStoreForeachTermFunc func,
void *user_data, GError **err);

/**
* set metadata for this MuStore
*
Expand Down
1 change: 1 addition & 0 deletions mu/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mu_SOURCES= \
mu-config.h \
mu-cmd-extract.c \
mu-cmd-find.c \
mu-cmd-inspect.c \
mu-cmd-index.c \
mu-cmd-server.c \
mu-cmd.c \
Expand Down
236 changes: 236 additions & 0 deletions mu/mu-cmd-inspect.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/

/*
** Copyright (C) 2008-2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** 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.
**
** 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 <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>

#include "mu-msg.h"
#include "mu-str.h"
#include "mu-date.h"
#include "mu-maildir.h"
#include "mu-runtime.h"

#include "mu-util.h"
#include "mu-cmd.h"
#include "mu-msg-fields.h"

/* Reverse-mapping of Xapian prefix character (as returned from "mu_msg_field_xapian_prefix()"
back to "enum enum _MuMsgFieldId" .
The index to this table is the prefix character (thus, 256 entries). */
typedef struct
{
gboolean valid; /* if TRUE, such a prefix does exist in mu */
gboolean print; /* if TRUE, print terms of this type */
const char* name; /* name of the field, as returned by mu_msg_field_name() */
char shortcut; /* shortcut, as returned by mu_msg_field_shortcut() */
MuMsgFieldType type; /* as returned by mu_msg_field_type() */
} FieldType;
FieldType field_types[256];

static void fill_prefix_ids()
{
memset(&field_types, 0, sizeof(field_types));
for (MuMsgFieldId i = 0 ;i < MU_MSG_FIELD_ID_NUM ; ++i) {
char prefix = mu_msg_field_xapian_prefix(i);
unsigned int j = (unsigned int)prefix;
if (j>0) {
field_types[j].valid = TRUE;
field_types[j].print = FALSE; /* by default, no types will be printed */
field_types[j].name = mu_msg_field_name(i);
field_types[j].shortcut = mu_msg_field_shortcut(i);
field_types[j].type = mu_msg_field_type(i);
}
}
}

/* Print information about the available types */
static void print_types()
{
g_print("DB\tfind\tID\tname\n");
for (MuMsgFieldId i = 0 ;i < MU_MSG_FIELD_ID_NUM ; ++i) {
char prefix = mu_msg_field_xapian_prefix(i);
unsigned int j = (unsigned int)prefix;

if (field_types[j].print) {
g_print("%c\t%c\t%d\t%s\n",
j,
field_types[j].shortcut?field_types[j].shortcut:'-', i,
field_types[j].name?field_types[j].name:"-");
}
}
}

/* Sets the types to print, based on the command-line parameters */
static gboolean set_types_to_print(gchar** params)
{
if (params==NULL || params[0]==NULL) {
g_warning("Internal error: mu inspect: got empty opt->params");
return FALSE;
}

/* no types specified, print all types */
if (params[1]==NULL) {
for (MuMsgFieldId i = 0 ;i < MU_MSG_FIELD_ID_NUM ; ++i) {
char prefix = mu_msg_field_xapian_prefix(i);
unsigned int j = (unsigned int)prefix;
if (j>0)
field_types[j].print = TRUE;
}
return TRUE;
}

/* at least one type specified, show only request types */
for (int p=1;params[p];++p) {
gboolean found = FALSE;
for (MuMsgFieldId i = 0 ;i < MU_MSG_FIELD_ID_NUM ; ++i) {
char prefix = mu_msg_field_xapian_prefix(i);
unsigned int j = (unsigned int)prefix;

if (field_types[j].name &&
strcmp(field_types[j].name, params[p])==0) {
field_types[j].print = TRUE;
found = TRUE;
break;
}
}
if (!found) {
g_warning("error: type '%s' does not exist.\n", params[p]);
return FALSE;
}
}

return TRUE;

}


static MuError print_term(const char* term,
const unsigned int term_freq,
void *store)
{
unsigned int prefix;
const char* term_value;

g_return_val_if_fail (term!=NULL, MU_ERROR_INTERNAL);
g_return_val_if_fail (*term!=0, MU_ERROR_INTERNAL);

prefix = (unsigned int)term[0]; /* first letter of each term is the mu xapian prefix */
term_value = &term[1];

g_return_val_if_fail (field_types[prefix].valid, MU_ERROR_INTERNAL);
g_return_val_if_fail (*term_value!=0, MU_ERROR_INTERNAL);

if (field_types[prefix].print) {
g_print("%s\t%s\t%u\n",field_types[prefix].name,term_value,term_freq);
}

return MU_OK;
}

static gboolean
execute_inspect (MuStore *store, MuConfig *opts, GError **err)
{
MuError foreach_err;
foreach_err = mu_store_foreach_term(store, print_term, store, err);
return (foreach_err==MU_OK);
}


static gboolean
format_params_valid (MuConfig *opts, GError **err)
{
switch (opts->format) {
case MU_CONFIG_FORMAT_EXEC:
break;
case MU_CONFIG_FORMAT_PLAIN:
break;
default: mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
"invalid output format %s",
opts->formatstr ? opts->formatstr : "<none>");
return FALSE;
}
return TRUE;
}

static gboolean
query_params_valid (MuConfig *opts, GError **err)
{
const gchar *xpath;

xpath = mu_runtime_path (MU_RUNTIME_PATH_XAPIANDB);

if (mu_util_check_dir (xpath, TRUE, FALSE))
return TRUE;

mu_util_g_set_error (err, MU_ERROR_FILE_CANNOT_READ,
"'%s' is not a readable Xapian directory",
xpath);
return FALSE;
}


static void
show_usage (void)
{
g_print ("%s", "usage: mu inspect <search expression>\n");
}


MuError
mu_cmd_inspect (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_INSPECT,
MU_ERROR_INTERNAL);

if (opts->exec)
opts->format = MU_CONFIG_FORMAT_EXEC; /* pseudo format */

if (!query_params_valid (opts, err) || !format_params_valid(opts, err)) {

if (MU_G_ERROR_CODE(err) == MU_ERROR_IN_PARAMETERS)
show_usage ();

return MU_G_ERROR_CODE (err);
}

fill_prefix_ids();
if (!set_types_to_print(opts->params))
return MU_ERROR_INTERNAL;

if (opts->print_types) {
print_types();
return MU_OK;
}

if (!execute_inspect (store, opts, err))
return MU_G_ERROR_CODE(err);
else
return MU_OK;
}
4 changes: 3 additions & 1 deletion mu/mu-cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ show_usage (void)
{
g_print ("usage: mu command [options] [parameters]\n");
g_print ("where command is one of index, find, cfind, view, mkdir, "
"extract, add, remove or server\n");
"extract, add, remove, inspect or server\n");
g_print ("see the mu, mu-<command> or mu-easy manpages for "
"more information\n");
}
Expand Down Expand Up @@ -580,6 +580,8 @@ mu_cmd_execute (MuConfig *opts, GError **err)
return with_store (mu_cmd_remove, opts, FALSE, err);
case MU_CONFIG_CMD_SERVER:
return with_store (mu_cmd_server, opts, FALSE, err);
case MU_CONFIG_CMD_INSPECT:
return with_store (mu_cmd_inspect, opts, TRUE, err);
default:
show_usage ();
g_set_error (err, MU_ERROR_DOMAIN, MU_ERROR_IN_PARAMETERS,
Expand Down
11 changes: 11 additions & 0 deletions mu/mu-cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ MuError mu_cmd_server (MuStore *store, MuConfig *opts, GError**/*unused*/);
*/
MuError mu_cmd_verify (MuConfig *opts, GError **err);

/**
* execute the inspect command (to list all indexed terms)
* @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_inspect (MuStore *store, MuConfig *opts, GError**/*unused*/);


/**
* execute some mu command, based on 'opts'
Expand Down
24 changes: 23 additions & 1 deletion mu/mu-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,25 @@ config_options_group_server (void)
return og;
}

static GOptionGroup*
config_options_group_inspect (void)
{
GOptionGroup *og;
GOptionEntry entries[] = {
{"types", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.print_types,
"List all available types", NULL},
{NULL, 0, 0, 0, NULL, NULL, NULL}
};

og = g_option_group_new("inspect",
"options for the 'inspect' command",
"", NULL, NULL);
g_option_group_add_entries(og, entries);

return og;
}



static MuConfigCmd
cmd_from_string (const char *str)
Expand All @@ -405,7 +424,8 @@ cmd_from_string (const char *str)
{ "remove", MU_CONFIG_CMD_REMOVE },
{ "server", MU_CONFIG_CMD_SERVER },
{ "verify", MU_CONFIG_CMD_VERIFY },
{ "view", MU_CONFIG_CMD_VIEW }
{ "view", MU_CONFIG_CMD_VIEW },
{ "inspect", MU_CONFIG_CMD_INSPECT }
};


Expand Down Expand Up @@ -459,6 +479,8 @@ get_option_group (MuConfigCmd cmd)
return config_options_group_view();
case MU_CONFIG_CMD_SERVER:
return config_options_group_server();
case MU_CONFIG_CMD_INSPECT:
return config_options_group_inspect();
default:
return NULL; /* no group to add */
}
Expand Down
4 changes: 4 additions & 0 deletions mu/mu-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ enum _MuConfigCmd {
MU_CONFIG_CMD_SERVER,
MU_CONFIG_CMD_VERIFY,
MU_CONFIG_CMD_VIEW,
MU_CONFIG_CMD_INSPECT,

MU_CONFIG_CMD_NONE
};
Expand Down Expand Up @@ -150,6 +151,9 @@ struct _MuConfig {
gboolean personal; /* only show 'personal' addresses */
/* also 'after' --> see above */

/* options for inspect */
gboolean print_types; /* list all available types, instead of terms */

/* output to a maildir with symlinks */
char *linksdir; /* maildir to output symlinks */
gboolean clearlinks; /* clear a linksdir before filling */
Expand Down
Loading