* <many>: update for mu-msg-field change

This commit is contained in:
Dirk-Jan C. Binnema 2010-11-20 14:43:04 +02:00
parent 7f617e32f0
commit b69cf8f589
12 changed files with 306 additions and 224 deletions

View File

@ -70,20 +70,23 @@ print_xapian_query (MuQuery *xapian, const gchar *query)
} }
/* returns NULL if there is an error */ /* returns NULL if there is an error */
const MuMsgField* static MuMsgFieldId
sort_field_from_string (const char* fieldstr) sort_field_from_string (const char* fieldstr)
{ {
const MuMsgField *field; MuMsgFieldId mfid;
field = mu_msg_field_from_name (fieldstr); mfid = mu_msg_field_id_from_name (fieldstr, FALSE);
if (!field && strlen(fieldstr) == 1) /* not found? try a shortcut */
field = mu_msg_field_from_shortcut(fieldstr[0]); if (mfid == MU_MSG_FIELD_ID_NONE &&
strlen(fieldstr) == 1)
if (!field) mfid = mu_msg_field_id_from_shortcut(fieldstr[0],
g_printerr ("not a valid sort field: '%s'\n", FALSE);
fieldstr);
return field; if (mfid == MU_MSG_FIELD_ID_NONE)
g_warning ("Not a valid sort field: '%s'\n",
fieldstr);
return mfid;
} }
@ -133,26 +136,28 @@ static gboolean
run_query (MuQuery *xapian, const gchar *query, MuConfigOptions *opts) run_query (MuQuery *xapian, const gchar *query, MuConfigOptions *opts)
{ {
MuMsgIter *iter; MuMsgIter *iter;
const MuMsgField *sortfield; MuMsgFieldId sortid;
size_t matches; size_t matches;
sortfield = NULL; sortid = MU_MSG_FIELD_ID_NONE;
if (opts->sortfield) { if (opts->sortfield) {
sortfield = sort_field_from_string (opts->sortfield); sortid = sort_field_from_string (opts->sortfield);
if (!sortfield) /* error occured? */ if (sortid == MU_MSG_FIELD_ID_NONE) /* error occured? */
return FALSE; return FALSE;
} }
iter = mu_query_run (xapian, query, sortfield, !opts->descending, 0); iter = mu_query_run (xapian, query, sortid, !opts->descending, 0);
if (!iter) { if (!iter) {
g_printerr ("error: running query failed\n"); g_printerr ("error: running query failed\n");
return FALSE; return FALSE;
} }
if (opts->linksdir) if (opts->linksdir)
matches = make_links (iter, opts->linksdir, opts->clearlinks); matches = make_links (iter, opts->linksdir,
opts->clearlinks);
else else
matches = print_rows (iter, opts->fields, opts->summary_len); matches = print_rows (iter, opts->fields,
opts->summary_len);
if (matches == 0) if (matches == 0)
g_printerr ("No matches found\n"); g_printerr ("No matches found\n");

View File

@ -181,54 +181,50 @@ mu_msg_iter_is_done (MuMsgIter *iter)
const gchar* const gchar*
mu_msg_iter_get_field (MuMsgIter *iter, const MuMsgField *field) mu_msg_iter_get_field (MuMsgIter *iter, MuMsgFieldId mfid)
{ {
g_return_val_if_fail (field, NULL);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
g_return_val_if_fail (mu_msg_field_id_is_valid(mfid), NULL);
try { try {
MuMsgFieldId id; if (!iter->_str[mfid]) { /* cache the value */
id = mu_msg_field_id (field);
if (!iter->_str[id]) { /* cache the value */
Xapian::Document doc (iter->_cursor.get_document()); Xapian::Document doc (iter->_cursor.get_document());
iter->_str[id] = g_strdup (doc.get_value(id).c_str()); iter->_str[mfid] =
g_strdup (doc.get_value(mfid).c_str());
} }
return iter->_str[id]; return iter->_str[mfid];
} MU_XAPIAN_CATCH_BLOCK_RETURN(NULL); } MU_XAPIAN_CATCH_BLOCK_RETURN(NULL);
} }
gint64 gint64
mu_msg_iter_get_field_numeric (MuMsgIter *iter, mu_msg_iter_get_field_numeric (MuMsgIter *iter, MuMsgFieldId mfid)
const MuMsgField *field)
{ {
g_return_val_if_fail (field, -1);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), -1); g_return_val_if_fail (!mu_msg_iter_is_done(iter), -1);
g_return_val_if_fail (mu_msg_field_is_numeric(field), -1); g_return_val_if_fail (mu_msg_field_is_numeric(mfid), -1);
try { try {
return static_cast<gint64>( return static_cast<gint64>(
Xapian::sortable_unserialise( Xapian::sortable_unserialise(
mu_msg_iter_get_field(iter, field))); mu_msg_iter_get_field(iter, mfid)));
} MU_XAPIAN_CATCH_BLOCK_RETURN(static_cast<gint64>(-1)); } MU_XAPIAN_CATCH_BLOCK_RETURN(static_cast<gint64>(-1));
} }
static const gchar* // static const gchar*
get_field (MuMsgIter *iter, MuMsgFieldId id) // get_field (MuMsgIter *iter, MuMsgFieldId mfid)
{ // {
return mu_msg_iter_get_field(iter, mu_msg_field_from_id (id)); // return mu_msg_iter_get_field(iter, mfid);
} // }
static long static long
get_field_number (MuMsgIter *iter, MuMsgFieldId id) get_field_number (MuMsgIter *iter, MuMsgFieldId mfid)
{ {
const char* str = get_field (iter, id); const char* str = mu_msg_iter_get_field(iter, mfid);
return str ? atol (str) : 0; return str ? atol (str) : 0;
} }
@ -250,14 +246,14 @@ const char*
mu_msg_iter_get_path (MuMsgIter *iter) mu_msg_iter_get_path (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_PATH); return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_PATH);
} }
const char* const char*
mu_msg_iter_get_maildir (MuMsgIter *iter) mu_msg_iter_get_maildir (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_MAILDIR); return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_MAILDIR);
} }
@ -266,14 +262,14 @@ const char*
mu_msg_iter_get_from (MuMsgIter *iter) mu_msg_iter_get_from (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_FROM); return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_FROM);
} }
const char* const char*
mu_msg_iter_get_to (MuMsgIter *iter) mu_msg_iter_get_to (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_TO); return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_TO);
} }
@ -281,7 +277,7 @@ const char*
mu_msg_iter_get_cc (MuMsgIter *iter) mu_msg_iter_get_cc (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_CC); return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_CC);
} }
@ -289,7 +285,7 @@ const char*
mu_msg_iter_get_subject (MuMsgIter *iter) mu_msg_iter_get_subject (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL); g_return_val_if_fail (!mu_msg_iter_is_done(iter), NULL);
return get_field (iter, MU_MSG_FIELD_ID_SUBJECT); return mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_SUBJECT);
} }
@ -297,45 +293,39 @@ size_t
mu_msg_iter_get_size (MuMsgIter *iter) mu_msg_iter_get_size (MuMsgIter *iter)
{ {
g_return_val_if_fail (!mu_msg_iter_is_done(iter), 0); g_return_val_if_fail (!mu_msg_iter_is_done(iter), 0);
return static_cast<size_t>(get_field_number (iter, MU_MSG_FIELD_ID_SIZE)); return static_cast<size_t>(get_field_number
(iter, MU_MSG_FIELD_ID_SIZE));
} }
time_t time_t
mu_msg_iter_get_date (MuMsgIter *iter) mu_msg_iter_get_date (MuMsgIter *iter)
{ {
static const MuMsgField *date_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_DATE);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), 0); g_return_val_if_fail (!mu_msg_iter_is_done(iter), 0);
try { try {
return static_cast<time_t>( return static_cast<time_t>(
Xapian::sortable_unserialise( Xapian::sortable_unserialise(
mu_msg_iter_get_field(iter, date_field))); mu_msg_iter_get_field
(iter,MU_MSG_FIELD_ID_DATE)));
} MU_XAPIAN_CATCH_BLOCK_RETURN(0); } MU_XAPIAN_CATCH_BLOCK_RETURN(0);
} }
MuMsgFlags MuMsgFlags
mu_msg_iter_get_flags (MuMsgIter *iter) mu_msg_iter_get_flags (MuMsgIter *iter)
{ {
static const MuMsgField *flags_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_FLAGS);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), MU_MSG_FLAG_NONE); g_return_val_if_fail (!mu_msg_iter_is_done(iter), MU_MSG_FLAG_NONE);
return static_cast<MuMsgFlags>(mu_msg_iter_get_field_numeric return static_cast<MuMsgFlags>(mu_msg_iter_get_field_numeric
(iter, flags_field)); (iter, MU_MSG_FIELD_ID_FLAGS));
} }
MuMsgPrio MuMsgPrio
mu_msg_iter_get_prio (MuMsgIter *iter) mu_msg_iter_get_prio (MuMsgIter *iter)
{ {
static const MuMsgField *prio_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_PRIO);
g_return_val_if_fail (!mu_msg_iter_is_done(iter), MU_MSG_PRIO_NONE); g_return_val_if_fail (!mu_msg_iter_is_done(iter), MU_MSG_PRIO_NONE);
return static_cast<MuMsgPrio>(mu_msg_iter_get_field_numeric return static_cast<MuMsgPrio>(mu_msg_iter_get_field_numeric
(iter, prio_field)); (iter, MU_MSG_FIELD_ID_PRIO));
} }

View File

@ -198,7 +198,7 @@ MuMsgPrio mu_msg_iter_get_prio (MuMsgIter *iter);
* @return the field value, or NULL * @return the field value, or NULL
*/ */
const gchar* mu_msg_iter_get_field (MuMsgIter *iter, const gchar* mu_msg_iter_get_field (MuMsgIter *iter,
const MuMsgField *field); MuMsgFieldId mfid);
/** /**
* get some numeric message field * get some numeric message field
@ -209,7 +209,7 @@ const gchar* mu_msg_iter_get_field (MuMsgIter *iter,
* @return the field value, or -1 in case of error * @return the field value, or -1 in case of error
*/ */
gint64 mu_msg_iter_get_field_numeric (MuMsgIter *iter, gint64 mu_msg_iter_get_field_numeric (MuMsgIter *iter,
const MuMsgField *field); MuMsgFieldId mfid);
G_END_DECLS G_END_DECLS
#endif /*__MU_MSG_ITER_H__*/ #endif /*__MU_MSG_ITER_H__*/

View File

@ -751,15 +751,11 @@ mu_msg_get_summary (MuMsg *msg, size_t max_lines)
const char* const char*
mu_msg_get_field_string (MuMsg *msg, const MuMsgField* field) mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid)
{ {
MuMsgFieldId id;
g_return_val_if_fail (msg, NULL); g_return_val_if_fail (msg, NULL);
id = mu_msg_field_id (field);
g_return_val_if_fail (id != MU_MSG_FIELD_ID_NONE, NULL);
switch (id) { switch (mfid) {
case MU_MSG_FIELD_ID_BODY_TEXT: return mu_msg_get_body_text (msg); case MU_MSG_FIELD_ID_BODY_TEXT: return mu_msg_get_body_text (msg);
case MU_MSG_FIELD_ID_BODY_HTML: return mu_msg_get_body_html (msg); case MU_MSG_FIELD_ID_BODY_HTML: return mu_msg_get_body_html (msg);
case MU_MSG_FIELD_ID_CC: return mu_msg_get_cc (msg); case MU_MSG_FIELD_ID_CC: return mu_msg_get_cc (msg);
@ -775,15 +771,11 @@ mu_msg_get_field_string (MuMsg *msg, const MuMsgField* field)
} }
gint64 gint64
mu_msg_get_field_numeric (MuMsg *msg, const MuMsgField* field) mu_msg_get_field_numeric (MuMsg *msg, const MuMsgFieldId mfid)
{ {
MuMsgFieldId id;
g_return_val_if_fail (msg, 0); g_return_val_if_fail (msg, 0);
id = mu_msg_field_id (field);
g_return_val_if_fail (id != MU_MSG_FIELD_ID_NONE, 0);
switch (id) { switch (mfid) {
case MU_MSG_FIELD_ID_DATE: case MU_MSG_FIELD_ID_DATE:
return mu_msg_get_date(msg); return mu_msg_get_date(msg);
case MU_MSG_FIELD_ID_FLAGS: case MU_MSG_FIELD_ID_FLAGS:
@ -793,7 +785,7 @@ mu_msg_get_field_numeric (MuMsg *msg, const MuMsgField* field)
case MU_MSG_FIELD_ID_SIZE: case MU_MSG_FIELD_ID_SIZE:
return mu_msg_get_size(msg); return mu_msg_get_size(msg);
default: default:
g_warning ("%s: %u", __FUNCTION__, (guint)id); g_warning ("%s: %u", __FUNCTION__, mfid);
g_return_val_if_reached (0); g_return_val_if_reached (0);
} }
} }

View File

@ -238,8 +238,8 @@ size_t mu_msg_get_size (MuMsg *msg);
* *
* @return a string that should not be freed * @return a string that should not be freed
*/ */
const char* mu_msg_get_field_string (MuMsg *msg, const char* mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid);
const MuMsgField* field);
/** /**
* get some field value as string * get some field value as string
@ -249,8 +249,7 @@ const char* mu_msg_get_field_string (MuMsg *msg,
* *
* @return a string that should not be freed * @return a string that should not be freed
*/ */
gint64 mu_msg_get_field_numeric (MuMsg *msg, gint64 mu_msg_get_field_numeric (MuMsg *msg, MuMsgFieldId mfid);
const MuMsgField* field);
/** /**
* get the message priority for this message (MU_MSG_PRIO_LOW, * get the message priority for this message (MU_MSG_PRIO_LOW,

View File

@ -57,15 +57,12 @@ gboolean
mu_output_link_row (MuMsgIter *iter, const char* linksdir) mu_output_link_row (MuMsgIter *iter, const char* linksdir)
{ {
const char *path; const char *path;
const MuMsgField *pathfield;
g_return_val_if_fail (iter, FALSE); g_return_val_if_fail (iter, FALSE);
g_return_val_if_fail (linksdir, FALSE); g_return_val_if_fail (linksdir, FALSE);
g_return_val_if_fail (!mu_msg_iter_is_done (iter), FALSE); g_return_val_if_fail (!mu_msg_iter_is_done (iter), FALSE);
pathfield = mu_msg_field_from_id (MU_MSG_FIELD_ID_PATH); path = mu_msg_iter_get_field (iter, MU_MSG_FIELD_ID_PATH);
path = mu_msg_iter_get_field (iter, pathfield);
if (!path) if (!path)
return FALSE; return FALSE;

View File

@ -40,34 +40,31 @@
static const gchar* static const gchar*
display_field (MuMsgIter *iter, const MuMsgField* field) display_field (MuMsgIter *iter, MuMsgFieldId mfid)
{ {
gint64 val; gint64 val;
switch (mu_msg_field_type(field)) { switch (mu_msg_field_type(mfid)) {
case MU_MSG_FIELD_TYPE_STRING: case MU_MSG_FIELD_TYPE_STRING:
return mu_msg_iter_get_field (iter, field); return mu_msg_iter_get_field (iter, mfid);
case MU_MSG_FIELD_TYPE_INT: case MU_MSG_FIELD_TYPE_INT:
if (mu_msg_field_id(field) == MU_MSG_FIELD_ID_PRIO) { if (mfid == MU_MSG_FIELD_ID_PRIO) {
val = mu_msg_iter_get_field_numeric (iter, field); val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_prio ((MuMsgPrio)val); return mu_msg_str_prio ((MuMsgPrio)val);
} } else if (mfid == MU_MSG_FIELD_ID_FLAGS) {
val = mu_msg_iter_get_field_numeric (iter, mfid);
if (mu_msg_field_id(field) == MU_MSG_FIELD_ID_FLAGS) { return mu_msg_str_flags_s ((MuMsgFlags)val);
val = mu_msg_iter_get_field_numeric (iter, field); } else /* as string */
return mu_msg_str_flags_s ((MuMsgPrio)val); return mu_msg_iter_get_field (iter, mfid);
}
return mu_msg_iter_get_field (iter, field); /* as string */
case MU_MSG_FIELD_TYPE_TIME_T: case MU_MSG_FIELD_TYPE_TIME_T:
val = mu_msg_iter_get_field_numeric (iter, field); val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_date_s ("%c", (time_t)val); return mu_msg_str_date_s ("%c", (time_t)val);
case MU_MSG_FIELD_TYPE_BYTESIZE: case MU_MSG_FIELD_TYPE_BYTESIZE:
val = mu_msg_iter_get_field_numeric (iter, field); val = mu_msg_iter_get_field_numeric (iter, mfid);
return mu_msg_str_size_s ((unsigned)val); return mu_msg_str_size_s ((unsigned)val);
default: default:
g_return_val_if_reached (NULL); g_return_val_if_reached (NULL);
@ -107,14 +104,15 @@ mu_output_plain_row (MuMsgIter *iter, const char *fields, size_t summary_len)
myfields = fields; myfields = fields;
while (*myfields) { while (*myfields) {
const MuMsgField* field; MuMsgFieldId mfid;
field = mu_msg_field_from_shortcut (*myfields); mfid = mu_msg_field_id_from_shortcut (*myfields, FALSE);
if (!field || ( !mu_msg_field_xapian_value (field) && if (mfid == MU_MSG_FIELD_ID_NONE ||
!mu_msg_field_xapian_contact (field))) ( !mu_msg_field_xapian_value (mfid) &&
!mu_msg_field_xapian_contact (mfid)))
len += printf ("%c", *myfields); len += printf ("%c", *myfields);
else else
len += printf ("%s", len += printf ("%s",
display_field(iter, field)); display_field(iter, mfid));
++myfields; ++myfields;
} }

View File

@ -32,8 +32,7 @@
#include "mu-util-db.h" #include "mu-util-db.h"
#include "mu-msg-str.h" #include "mu-msg-str.h"
static void add_prefix (const MuMsgField* field, static void add_prefix (MuMsgFieldId field, Xapian::QueryParser* qparser);
Xapian::QueryParser* qparser);
struct _MuQuery { struct _MuQuery {
Xapian::Database* _db; Xapian::Database* _db;
@ -51,14 +50,23 @@ init_mu_query (MuQuery *mqx, const char* dbpath)
mqx->_db = new Xapian::Database(dbpath); mqx->_db = new Xapian::Database(dbpath);
mqx->_qparser = new Xapian::QueryParser; mqx->_qparser = new Xapian::QueryParser;
mqx->_qparser->set_database(*mqx->_db); mqx->_qparser->set_database (*mqx->_db);
mqx->_qparser->set_default_op(Xapian::Query::OP_AND); mqx->_qparser->set_default_op (Xapian::Query::OP_AND);
mqx->_qparser->set_stemming_strategy //mqx->_qparser->set_stemming_strategy (Xapian::QueryParser::STEM_NONE);
(Xapian::QueryParser::STEM_ALL);
memset (mqx->_sorters, 0, sizeof(mqx->_sorters)); memset (mqx->_sorters, 0, sizeof(mqx->_sorters));
mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_prefix, mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_prefix,
(gpointer)mqx->_qparser); (gpointer)mqx->_qparser);
////// FIXME
// g_print ("synonyms:");
// for (Xapian::TermIterator iter = mqx->_db->synonym_keys_begin();
// iter != mqx->_db->synonym_keys_end(); ++iter) {
// for (Xapian::TermIterator jter = mqx->_db->synonyms_begin(*iter);
// jter != mqx->_db->synonyms_end(*iter); ++jter) {
// g_print ("%s => %s\n", (*iter).c_str(), (*jter).c_str());
// }
// }
return TRUE; return TRUE;
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
@ -95,8 +103,9 @@ get_query (MuQuery * mqx, const char* searchexpr, int *err = 0) {
(searchexpr, (searchexpr,
Xapian::QueryParser::FLAG_BOOLEAN | Xapian::QueryParser::FLAG_BOOLEAN |
Xapian::QueryParser::FLAG_PHRASE | Xapian::QueryParser::FLAG_PHRASE |
Xapian::QueryParser::FLAG_AUTO_SYNONYMS |
Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE); Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE);
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
if (err) if (err)
@ -106,22 +115,43 @@ get_query (MuQuery * mqx, const char* searchexpr, int *err = 0) {
} }
static void static void
add_prefix (const MuMsgField* field, Xapian::QueryParser* qparser) add_prefix (MuMsgFieldId mfid, Xapian::QueryParser* qparser)
{ {
if (!mu_msg_field_xapian_index(field) && static char pfx[] = "\0\0";
!mu_msg_field_xapian_term(field) && static char shortcut[] = "\0\0";
!mu_msg_field_xapian_contact(field))
if (!mu_msg_field_xapian_index(mfid) &&
!mu_msg_field_xapian_term(mfid) &&
!mu_msg_field_xapian_contact(mfid))
return; return;
const std::string prefix (mu_msg_field_xapian_prefix(field)); pfx[0] = mu_msg_field_xapian_prefix (mfid);
shortcut[0] = mu_msg_field_shortcut (mfid);
qparser->add_boolean_prefix try {
(std::string(mu_msg_field_name(field)), prefix);
qparser->add_boolean_prefix
(std::string(mu_msg_field_shortcut(field)), prefix);
/* make the empty string match this field too*/ if (mfid == MU_MSG_FIELD_ID_MSGID ||
qparser->add_prefix ("", prefix); mfid == MU_MSG_FIELD_ID_MAILDIR ||
mu_msg_field_type (mfid) != MU_MSG_FIELD_TYPE_STRING ||
mu_msg_field_xapian_contact(mfid)) {
qparser->add_boolean_prefix
(mu_msg_field_name(mfid), pfx);
qparser->add_boolean_prefix (shortcut, pfx);
/* make the empty string match this field too*/
qparser->add_prefix ("", pfx);
} else {
qparser->add_boolean_prefix
(mu_msg_field_name(mfid), pfx);
qparser->add_prefix (shortcut, pfx);
/* make the empty string match this field too*/
qparser->add_prefix ("", pfx);
}
} MU_XAPIAN_CATCH_BLOCK;
} }
MuQuery* MuQuery*
@ -162,10 +192,11 @@ mu_query_new (const char* xpath)
void void
mu_query_destroy (MuQuery *self) mu_query_destroy (MuQuery *self)
{ {
if (self) { if (!self)
uninit_mu_query (self); return;
g_free (self);
} uninit_mu_query (self);
g_free (self);
} }
struct _CheckPrefix { struct _CheckPrefix {
@ -176,21 +207,21 @@ struct _CheckPrefix {
typedef struct _CheckPrefix CheckPrefix; typedef struct _CheckPrefix CheckPrefix;
static void static void
each_check_prefix (const MuMsgField *field, CheckPrefix *cpfx) each_check_prefix (MuMsgFieldId mfid, CheckPrefix *cpfx)
{ {
const char *field_name, *field_shortcut; const char *field_name;
char field_shortcut;
if (cpfx->match) if (!cpfx || cpfx->match)
return; return;
field_shortcut = mu_msg_field_shortcut (field); field_shortcut = mu_msg_field_shortcut (mfid);
if (field_shortcut && if (field_shortcut == cpfx->pfx[0]) {
strncmp (cpfx->pfx, field_shortcut, cpfx->len) == 0) {
cpfx->match = TRUE; cpfx->match = TRUE;
return; return;
} }
field_name = mu_msg_field_name (field); field_name = mu_msg_field_name (mfid);
if (field_name && if (field_name &&
strncmp (cpfx->pfx, field_name, cpfx->len) == 0) { strncmp (cpfx->pfx, field_name, cpfx->len) == 0) {
cpfx->match = TRUE; cpfx->match = TRUE;
@ -265,11 +296,13 @@ mu_query_preprocess (const char *query)
MuMsgIter* MuMsgIter*
mu_query_run (MuQuery *self, const char* searchexpr, mu_query_run (MuQuery *self, const char* searchexpr,
const MuMsgField* sortfield, gboolean ascending, MuMsgFieldId sortfieldid, gboolean ascending,
size_t batchsize) size_t batchsize)
{ {
g_return_val_if_fail (self, NULL); g_return_val_if_fail (self, NULL);
g_return_val_if_fail (searchexpr, NULL); g_return_val_if_fail (searchexpr, NULL);
g_return_val_if_fail (mu_msg_field_id_is_valid (sortfieldid) ||
sortfieldid == MU_MSG_FIELD_ID_NONE, NULL);
try { try {
char *preprocessed; char *preprocessed;
@ -290,9 +323,9 @@ mu_query_run (MuQuery *self, const char* searchexpr,
if (batchsize == 0) if (batchsize == 0)
batchsize = self->_db->get_doccount(); batchsize = self->_db->get_doccount();
if (sortfield) if (sortfieldid != MU_MSG_FIELD_ID_NONE)
enq.set_sort_by_value ( enq.set_sort_by_value (
(Xapian::valueno)mu_msg_field_id(sortfield), (Xapian::valueno)sortfieldid,
ascending); ascending);
enq.set_query(q); enq.set_query(q);
@ -312,7 +345,7 @@ mu_query_as_string (MuQuery *self, const char *searchexpr)
try { try {
char *preprocessed; char *preprocessed;
int err (0); int err (0);
preprocessed = mu_query_preprocess (searchexpr); preprocessed = mu_query_preprocess (searchexpr);
Xapian::Query q(get_query(self, preprocessed, &err)); Xapian::Query q(get_query(self, preprocessed, &err));

View File

@ -63,7 +63,8 @@ char* mu_query_version (MuQuery *store) G_GNUC_WARN_UNUSED_RESULT;
* *
* @param self a valid MuQuery instance * @param self a valid MuQuery instance
* @param expr the search expression * @param expr the search expression
* @param sortfield the field to sort by or NULL * @param sortfield the field id to sort by or MU_MSG_FIELD_ID_NONE if
* sorting is not desired
* @param ascending if TRUE sort in ascending (A-Z) order, otherwise, * @param ascending if TRUE sort in ascending (A-Z) order, otherwise,
* sort in descending (Z-A) order * sort in descending (Z-A) order
* @param batchsize the size of batches to receive; this is mainly for * @param batchsize the size of batches to receive; this is mainly for
@ -76,7 +77,7 @@ char* mu_query_version (MuQuery *store) G_GNUC_WARN_UNUSED_RESULT;
*/ */
MuMsgIter* mu_query_run (MuQuery *self, MuMsgIter* mu_query_run (MuQuery *self,
const char* expr, const char* expr,
const MuMsgField* sortfield, MuMsgFieldId sortfieldid,
gboolean ascending, gboolean ascending,
size_t batchsize) G_GNUC_WARN_UNUSED_RESULT; size_t batchsize) G_GNUC_WARN_UNUSED_RESULT;

View File

@ -40,12 +40,60 @@
struct _MuStore { struct _MuStore {
Xapian::WritableDatabase *_db; Xapian::WritableDatabase *_db;
char *_version;
/* transaction handling */ /* transaction handling */
bool _in_transaction; bool _in_transaction;
int _processed; int _processed;
size_t _trx_size; size_t _trx_size;
}; };
static void
add_synonyms (MuStore *store)
{
std::string pfx (1, mu_msg_field_xapian_prefix
(MU_MSG_FIELD_ID_FLAGS));
store->_db->add_synonym (pfx + "n", pfx + "new");
store->_db->add_synonym (pfx + "unread", pfx + "n");
store->_db->add_synonym (pfx + "attach", pfx + "a");
store->_db->add_synonym (pfx + "attachment", pfx + "a");
store->_db->add_synonym ("Bfoo", "Bbar");
store->_db->add_synonym ("Gnew", "Gn");
}
static gboolean
check_version (MuStore *store)
{
/* FIXME clear up versioning semantics */
const gchar *version;
version = mu_store_version (store);
/* no version yet? it must be a new db then; we'll set the version */
if (!version) {
if (!mu_store_set_version (store, MU_XAPIAN_DB_VERSION)) {
g_warning ("failed to set database version");
return FALSE;
}
return TRUE; /* ok, done. */
}
/* we have a version, but is it the right one? */
if (std::strcmp (version, MU_XAPIAN_DB_VERSION) != 0) {
g_warning ("expected db version %s, but got %s",
MU_XAPIAN_DB_VERSION, version);
return FALSE;
}
return TRUE;
}
MuStore* MuStore*
mu_store_new (const char* xpath) mu_store_new (const char* xpath)
{ {
@ -55,15 +103,22 @@ mu_store_new (const char* xpath)
try { try {
store = g_new0(MuStore,1); store = g_new0(MuStore,1);
store->_db = new Xapian::WritableDatabase store->_db = new Xapian::WritableDatabase (xpath,
(xpath, Xapian::DB_CREATE_OR_OPEN); Xapian::DB_CREATE_OR_OPEN);
if (!check_version (store)) {
mu_store_destroy (store);
return NULL;
}
/* keep count of processed docs */ /* keep count of processed docs */
store->_trx_size = MU_STORE_TRX_SIZE; store->_trx_size = MU_STORE_TRX_SIZE;
store->_in_transaction = false; store->_in_transaction = false;
store->_processed = 0; store->_processed = 0;
add_synonyms (store);
MU_WRITE_LOG ("%s: opened %s", __FUNCTION__, xpath); MU_WRITE_LOG ("%s: opened %s", __FUNCTION__, xpath);
return store; return store;
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
@ -75,6 +130,26 @@ mu_store_new (const char* xpath)
} }
void
mu_store_destroy (MuStore *store)
{
if (!store)
return;
try {
mu_store_flush (store);
MU_WRITE_LOG ("closing xapian database with %d documents",
(int)store->_db->get_doccount());
g_free (store->_version);
delete store->_db;
g_free (store);
} MU_XAPIAN_CATCH_BLOCK;
}
unsigned unsigned
mu_store_count (MuStore *store) mu_store_count (MuStore *store)
@ -90,17 +165,18 @@ mu_store_count (MuStore *store)
} }
char* const char*
mu_store_version (MuStore *store) mu_store_version (MuStore *store)
{ {
g_return_val_if_fail (store, NULL); g_return_val_if_fail (store, NULL);
try { try {
const std::string version ( std::string v;
store->_db->get_metadata (MU_XAPIAN_VERSION_KEY)); v = store->_db->get_metadata (MU_XAPIAN_VERSION_KEY);
return version.empty() ? NULL : g_strdup (version.c_str()); g_free (store->_version);
return store->_version = v.empty() ? NULL : g_strdup (v.c_str());
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
return NULL; return NULL;
@ -118,7 +194,7 @@ mu_store_set_version (MuStore *store, const char* version)
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
return FALSE; return FALSE;
} }
@ -153,23 +229,6 @@ rollback_trx_if (MuStore *store, gboolean cond)
} }
void
mu_store_destroy (MuStore *store)
{
if (!store)
return;
try {
mu_store_flush (store);
MU_WRITE_LOG ("closing xapian database with %d documents",
(int)store->_db->get_doccount());
delete store->_db;
g_free (store);
} MU_XAPIAN_CATCH_BLOCK;
}
void void
mu_store_flush (MuStore *store) mu_store_flush (MuStore *store)
@ -178,7 +237,7 @@ mu_store_flush (MuStore *store)
try { try {
commit_trx_if (store, store->_in_transaction); commit_trx_if (store, store->_in_transaction);
store->_db->flush (); store->_db->flush (); /* => commit, post X 1.1.x */
} MU_XAPIAN_CATCH_BLOCK; } MU_XAPIAN_CATCH_BLOCK;
} }
@ -186,30 +245,40 @@ mu_store_flush (MuStore *store)
static void static void
add_terms_values_number (Xapian::Document& doc, MuMsg *msg, add_terms_values_number (Xapian::Document& doc, MuMsg *msg,
const MuMsgField* field) MuMsgFieldId mfid)
{ {
const std::string pfx (mu_msg_field_xapian_prefix(field), 1); const std::string pfx (1, mu_msg_field_xapian_prefix(mfid));
gint64 num = mu_msg_get_field_numeric (msg, field); gint64 num = mu_msg_get_field_numeric (msg, mfid);
const std::string numstr (Xapian::sortable_serialise((double)num)); const std::string numstr (Xapian::sortable_serialise((double)num));
doc.add_value ((Xapian::valueno)mu_msg_field_id(field), numstr); doc.add_value ((Xapian::valueno)mfid, numstr);
doc.add_term (pfx + numstr);
if (mfid == MU_MSG_FIELD_ID_FLAGS) {
const char* flags, *cur;
cur = flags = mu_msg_flags_to_str_s ((MuMsgFlags)num);
while (cur && *cur) {
char kar = tolower (*cur);
doc.add_term (pfx + kar);
++cur;
}
} else
doc.add_term (pfx + numstr);
} }
static void static void
add_terms_values_string (Xapian::Document& doc, MuMsg *msg, add_terms_values_string (Xapian::Document& doc, MuMsg *msg,
const MuMsgField* field) MuMsgFieldId mfid)
{ {
const char* str; const char* str;
str = mu_msg_get_field_string (msg, field); str = mu_msg_get_field_string (msg, mfid);
if (!str) if (!str)
return; return;
const std::string value (str); const std::string value (str);
const std::string prefix (mu_msg_field_xapian_prefix(field)); const std::string prefix (1, mu_msg_field_xapian_prefix(mfid));
if (mu_msg_field_xapian_index (field)) { if (mu_msg_field_xapian_index (mfid)) {
Xapian::TermGenerator termgen; Xapian::TermGenerator termgen;
gchar *norm (mu_msg_str_normalize(str, TRUE)); gchar *norm (mu_msg_str_normalize(str, TRUE));
termgen.set_document (doc); termgen.set_document (doc);
@ -217,28 +286,24 @@ add_terms_values_string (Xapian::Document& doc, MuMsg *msg,
g_free(norm); g_free(norm);
} }
if (mu_msg_field_xapian_term(field)) { if (mu_msg_field_xapian_term(mfid)) {
/* terms can be up to MU_STORE_MAX_TERM_LENGTH (240) /* add a normalized version (accents removed,
* long; this is a Xapian limit */ * lowercase) */
// doc.add_term (std::string (prefix + value, 0,
// MU_STORE_MAX_TERM_LENGTH));
/* add a normalized version as well (accents removed,
* lowercase), if it's actually different */
gchar *norm = mu_msg_str_normalize(str, TRUE); gchar *norm = mu_msg_str_normalize(str, TRUE);
doc.add_term (std::string (prefix + std::string(norm), 0, doc.add_term (std::string (prefix + std::string(norm), 0,
MU_STORE_MAX_TERM_LENGTH)); MU_STORE_MAX_TERM_LENGTH));
g_free (norm); g_free (norm);
} }
if (mu_msg_field_xapian_value(field)) /* the value is what we'll display; the unchanged original */
doc.add_value ((Xapian::valueno)mu_msg_field_id (field), if (mu_msg_field_xapian_value(mfid))
doc.add_value ((Xapian::valueno)mfid,
value); value);
} }
static void static void
add_terms_values_body (Xapian::Document& doc, MuMsg *msg, add_terms_values_body (Xapian::Document& doc, MuMsg *msg,
const MuMsgField* field) MuMsgFieldId mfid)
{ {
const char *str; const char *str;
char *norm; char *norm;
@ -257,7 +322,8 @@ add_terms_values_body (Xapian::Document& doc, MuMsg *msg,
termgen.set_document(doc); termgen.set_document(doc);
norm = mu_msg_str_normalize (str, TRUE); norm = mu_msg_str_normalize (str, TRUE);
termgen.index_text(norm, 1, mu_msg_field_xapian_prefix(field)); termgen.index_text_without_positions
(norm, 1, std::string(1,mu_msg_field_xapian_prefix(mfid)));
g_free (norm); g_free (norm);
} }
@ -268,33 +334,34 @@ struct _MsgDoc {
typedef struct _MsgDoc MsgDoc; typedef struct _MsgDoc MsgDoc;
static void static void
add_terms_values (const MuMsgField* field, MsgDoc* msgdoc) add_terms_values (MuMsgFieldId mfid, MsgDoc* msgdoc)
{ {
MuMsgFieldType type; MuMsgFieldType type;
/* note: contact-stuff (To/Cc/From) will handled in /* note: contact-stuff (To/Cc/From) will handled in
* add_contact_info, not here */ * add_contact_info, not here */
if (!mu_msg_field_xapian_index(field) && if (!mu_msg_field_xapian_index(mfid) &&
!mu_msg_field_xapian_term(field) && !mu_msg_field_xapian_term(mfid) &&
!mu_msg_field_xapian_value(field)) !mu_msg_field_xapian_value(mfid))
return; return;
type = mu_msg_field_type (field); type = mu_msg_field_type (mfid);
if (type == MU_MSG_FIELD_TYPE_STRING) { if (type == MU_MSG_FIELD_TYPE_STRING) {
if (mu_msg_field_id (field) == MU_MSG_FIELD_ID_BODY_TEXT) if (mfid == MU_MSG_FIELD_ID_BODY_TEXT)
add_terms_values_body (*msgdoc->_doc, msgdoc->_msg, add_terms_values_body (*msgdoc->_doc, msgdoc->_msg,
field); mfid);
else else
add_terms_values_string (*msgdoc->_doc, msgdoc->_msg, add_terms_values_string (*msgdoc->_doc, msgdoc->_msg,
field); mfid);
return; return;
} }
if (type == MU_MSG_FIELD_TYPE_BYTESIZE || if (type == MU_MSG_FIELD_TYPE_BYTESIZE ||
type == MU_MSG_FIELD_TYPE_TIME_T || type == MU_MSG_FIELD_TYPE_TIME_T ||
type == MU_MSG_FIELD_TYPE_INT) { type == MU_MSG_FIELD_TYPE_INT) {
add_terms_values_number (*msgdoc->_doc, msgdoc->_msg, field); add_terms_values_number (*msgdoc->_doc, msgdoc->_msg,
mfid);
return; return;
} }
@ -305,39 +372,38 @@ add_terms_values (const MuMsgField* field, MsgDoc* msgdoc)
static void static void
each_contact_info (MuMsgContact *contact, MsgDoc *data) each_contact_info (MuMsgContact *contact, MsgDoc *data)
{ {
std::string pfx; const std::string *pfxp;
static const MuMsgField *to_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_TO);
static const MuMsgField *from_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_FROM);
static const MuMsgField *cc_field =
mu_msg_field_from_id (MU_MSG_FIELD_ID_CC);
static const std::string to_pfx (mu_msg_field_xapian_prefix(to_field)); static const std::string to_pfx (1,
static const std::string from_pfx (mu_msg_field_xapian_prefix(from_field)); mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_TO));
static const std::string cc_pfx (mu_msg_field_xapian_prefix(cc_field)); static const std::string from_pfx (1,
mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_FROM));
static const std::string cc_pfx (1,
mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_CC));
/* use ptr to string to prevent copy... */
switch (contact->type) { switch (contact->type) {
case MU_MSG_CONTACT_TYPE_TO: pfx = to_pfx; break; case MU_MSG_CONTACT_TYPE_TO: pfxp = &to_pfx; break;
case MU_MSG_CONTACT_TYPE_FROM: pfx = from_pfx; break; case MU_MSG_CONTACT_TYPE_FROM: pfxp = &from_pfx; break;
case MU_MSG_CONTACT_TYPE_CC: pfx = cc_pfx; break; case MU_MSG_CONTACT_TYPE_CC: pfxp = &cc_pfx; break;
default: return; /* other types (like bcc) are ignored */ default: return;
/* other types (like bcc) are ignored */
} }
if (contact->name && strlen(contact->name) > 0) { if (contact->name && strlen(contact->name) > 0) {
Xapian::TermGenerator termgen; Xapian::TermGenerator termgen;
termgen.set_document (*data->_doc); termgen.set_document (*data->_doc);
char *norm = mu_msg_str_normalize (contact->name, TRUE); char *norm = mu_msg_str_normalize (contact->name, TRUE);
termgen.index_text_without_positions (norm, 1, pfx); termgen.index_text_without_positions (norm, 1, *pfxp);
g_free (norm); g_free (norm);
} }
/* don't normalize e-mail address, but do lowercase it */ /* don't normalize e-mail address, but do lowercase it */
if (contact->address && strlen (contact->address)) { if (contact->address && strlen (contact->address)) {
char *lower = g_utf8_strdown (contact->address, -1); char *lower = g_utf8_strdown (contact->address, -1);
data->_doc->add_term (std::string (pfx + lower, 0, data->_doc->add_term
MU_STORE_MAX_TERM_LENGTH)); (std::string (*pfxp + lower, 0,
MU_STORE_MAX_TERM_LENGTH));
g_free (lower); g_free (lower);
} }
} }
@ -347,10 +413,8 @@ each_contact_info (MuMsgContact *contact, MsgDoc *data)
static std::string static std::string
get_message_uid (const char* path) get_message_uid (const char* path)
{ {
static const MuMsgField* pathfield =
mu_msg_field_from_id(MU_MSG_FIELD_ID_PATH);
static const std::string pathprefix static const std::string pathprefix
(mu_msg_field_xapian_prefix(pathfield)); (1, mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_PATH));
return pathprefix + path; return pathprefix + path;
} }
@ -377,8 +441,8 @@ mu_store_store (MuStore *store, MuMsg *msg)
/* we must add a unique term, so we can replace /* we must add a unique term, so we can replace
* matching documents */ * matching documents */
newdoc.add_term (uid); newdoc.add_term (uid);
mu_msg_field_foreach ((MuMsgFieldForEachFunc)add_terms_values, mu_msg_field_foreach
&msgdoc); ((MuMsgFieldForEachFunc)add_terms_values, &msgdoc);
/* also store the contact-info as separate terms */ /* also store the contact-info as separate terms */
mu_msg_contact_foreach (msg, mu_msg_contact_foreach (msg,
(MuMsgContactForeachFunc)each_contact_info, (MuMsgContactForeachFunc)each_contact_info,

View File

@ -45,7 +45,7 @@ MuStore* mu_store_new (const char* path);
* *
* @param store a valid store, or NULL * @param store a valid store, or NULL
*/ */
void mu_store_destroy (MuStore *store); void mu_store_destroy (MuStore *store);
/** /**
@ -59,13 +59,15 @@ void mu_store_destroy (MuStore *store);
unsigned mu_store_count (MuStore *store); unsigned mu_store_count (MuStore *store);
/** /**
* get a version string for the database * get a version string for the database; it's a const string, which
* is valid as long MuStore exists and mu_store_version is not called
* again.
* *
* @param store a valid MuStore * @param store a valid MuStore
* *
* @return the version string (free with g_free), or NULL in case of error * @return the version string or NULL in case of error
*/ */
char* mu_store_version (MuStore *store); const char* mu_store_version (MuStore *store);
/** /**
* set the version string for the database * set the version string for the database

View File

@ -311,7 +311,8 @@ run_query (const char *xpath, const char *query)
return NULL; return NULL;
} }
iter = mu_query_run (xapian, query, NULL, TRUE, 0); iter = mu_query_run (xapian, query, MU_MSG_FIELD_ID_NONE,
TRUE, 0);
mu_query_destroy (xapian); mu_query_destroy (xapian);
if (!iter) { if (!iter) {
g_warning ("error: running query failed\n"); g_warning ("error: running query failed\n");