mu/src/mu-msg-fields.c

436 lines
11 KiB
C

/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
/*
** Copyright (C) 2008-2011 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 of the License, 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.
**
*/
#include <string.h>
#include "mu-msg-fields.h"
/*
* note: the differences for our purposes between a xapian field and a
* term: - there is only a single value for some item in per document
* (msg), ie. one value containing the list of To: addresses - there
* can be multiple terms, each containing e.g. one of the To:
* addresses - searching uses terms, but to display some field, it
* must be in the value (at least when using MuMsgIter)
*/
enum _FieldFlags {
FLAG_GMIME = 1 << 0, /* field retrieved through
* gmime */
FLAG_XAPIAN_INDEX = 1 << 1, /* field is indexed in
* xapian (i.e., the text
* is processed */
FLAG_XAPIAN_TERM = 1 << 2, /* field stored as term in
* xapian (so it can be searched) */
FLAG_XAPIAN_VALUE = 1 << 3, /* field stored as value in
* xapian (so the literal
* value can be
* retrieved) */
FLAG_XAPIAN_CONTACT = 1 << 4, /* field contains one or more
* e-mail-addresses */
FLAG_XAPIAN_ESCAPE = 1 << 5, /* field needs escaping for
* xapian (so the xapian
* query does not get
* confused) */
FLAG_XAPIAN_BOOLEAN = 1 << 6, /* use 'add_boolean_prefix'
* for Xapian queries;
* wildcards do NOT WORK
* for such fields */
FLAG_XAPIAN_PREFIX_ONLY = 1 << 7, /* whether this fields
* matches only when the
* prefix is explicitly
* included in the search
* query -- e.g., the text
* body */
FLAG_NORMALIZE = 1 << 8, /* field needs flattening for
* case/accents */
FLAG_DONT_CACHE = 1 << 9 /* don't cache this field in
* the MuMsg cache */
};
typedef enum _FieldFlags FieldFlags;
/*
* this struct describes the fields of an e-mail
/*/
struct _MuMsgField {
MuMsgFieldId _id; /* the id of the field */
MuMsgFieldType _type; /* the type of the field */
const char *_name; /* the name of the field */
const char _shortcut; /* the shortcut for use in
* --fields and sorting */
const char _xprefix; /* the Xapian-prefix */
FieldFlags _flags; /* the flags that tells us
* what to do */
};
typedef struct _MuMsgField MuMsgField;
/* the name and shortcut fields must be lower case, or they might be
* misinterpreted by the query-preprocesser which turns queries into
* lowercase */
static const MuMsgField FIELD_DATA[] = {
{
MU_MSG_FIELD_ID_BCC,
MU_MSG_FIELD_TYPE_STRING,
"bcc" , 'h', 'H', /* 'hidden */
FLAG_GMIME | FLAG_XAPIAN_CONTACT |
FLAG_XAPIAN_VALUE
},
{
MU_MSG_FIELD_ID_BODY_TEXT,
MU_MSG_FIELD_TYPE_STRING,
"body", 'b', 'B',
FLAG_GMIME | FLAG_XAPIAN_INDEX | FLAG_NORMALIZE |
FLAG_DONT_CACHE
},
{
MU_MSG_FIELD_ID_BODY_HTML,
MU_MSG_FIELD_TYPE_STRING,
"bodyhtml", 'h', 0,
FLAG_GMIME | FLAG_DONT_CACHE
},
{
MU_MSG_FIELD_ID_CC,
MU_MSG_FIELD_TYPE_STRING,
"cc", 'c', 'C',
FLAG_GMIME | FLAG_XAPIAN_CONTACT | FLAG_XAPIAN_VALUE
},
{
MU_MSG_FIELD_ID_DATE,
MU_MSG_FIELD_TYPE_TIME_T,
"date", 'd', 'D',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_BOOLEAN | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_EMBEDDED_TEXT,
MU_MSG_FIELD_TYPE_STRING,
"embed", 'e', 'E',
FLAG_GMIME | FLAG_XAPIAN_INDEX | FLAG_NORMALIZE |
FLAG_DONT_CACHE
},
{
MU_MSG_FIELD_ID_FILE,
MU_MSG_FIELD_TYPE_STRING,
"file" , 'j', 'J',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_NORMALIZE |
FLAG_DONT_CACHE | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_FLAGS,
MU_MSG_FIELD_TYPE_INT,
"flag", 'g', 'G', /* flaGs */
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_FROM,
MU_MSG_FIELD_TYPE_STRING,
"from", 'f', 'F',
FLAG_GMIME | FLAG_XAPIAN_CONTACT | FLAG_XAPIAN_VALUE
},
{
MU_MSG_FIELD_ID_PATH,
MU_MSG_FIELD_TYPE_STRING,
"path", 'l', 'L', /* 'l' for location */
FLAG_GMIME | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_BOOLEAN | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_MAILDIR,
MU_MSG_FIELD_TYPE_STRING,
"maildir", 'm', 'M',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_NORMALIZE | FLAG_XAPIAN_ESCAPE | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_MIME,
MU_MSG_FIELD_TYPE_STRING,
"mime" , 'y', 'Y',
FLAG_XAPIAN_TERM | FLAG_XAPIAN_ESCAPE | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_PRIO,
MU_MSG_FIELD_TYPE_INT,
"prio", 'p', 'P',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_SIZE,
MU_MSG_FIELD_TYPE_BYTESIZE,
"size", 'z', 'Z', /* siZe */
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_SUBJECT,
MU_MSG_FIELD_TYPE_STRING,
"subject", 's', 'S',
FLAG_GMIME | FLAG_XAPIAN_INDEX | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_TERM | FLAG_NORMALIZE | FLAG_XAPIAN_ESCAPE
},
{
MU_MSG_FIELD_ID_TO,
MU_MSG_FIELD_TYPE_STRING,
"to", 't', 'T',
FLAG_GMIME | FLAG_XAPIAN_CONTACT | FLAG_XAPIAN_VALUE
},
{
MU_MSG_FIELD_ID_MSGID,
MU_MSG_FIELD_TYPE_STRING,
"msgid", 'i', 'I', /* 'i' for Id */
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_VALUE |
FLAG_XAPIAN_ESCAPE | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_REFS,
MU_MSG_FIELD_TYPE_STRING_LIST,
NULL, 'r', 'R',
FLAG_GMIME | FLAG_XAPIAN_VALUE | FLAG_XAPIAN_PREFIX_ONLY
},
{
MU_MSG_FIELD_ID_TAGS,
MU_MSG_FIELD_TYPE_STRING_LIST,
"tag", 'x', 'X',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_PREFIX_ONLY |
FLAG_NORMALIZE | FLAG_XAPIAN_ESCAPE
},
{ /* special, internal field, to get a unique key */
MU_MSG_FIELD_ID_UID,
MU_MSG_FIELD_TYPE_STRING,
"uid", 0, 'U',
FLAG_XAPIAN_TERM | FLAG_XAPIAN_PREFIX_ONLY
}
/* note, mu-store also use the 'Q' internal prefix for its uids */
};
/* the MsgField data in an array, indexed by the MsgFieldId;
* this allows for O(1) access
*/
static MuMsgField* _msg_field_data[MU_MSG_FIELD_ID_NUM];
static const MuMsgField* mu_msg_field (MuMsgFieldId id)
{
static gboolean _initialized = FALSE;
/* initialize the array, but only once... */
if (G_UNLIKELY(!_initialized)) {
int i;
for (i = 0; i != G_N_ELEMENTS(FIELD_DATA); ++i)
_msg_field_data[FIELD_DATA[i]._id] =
(MuMsgField*)&FIELD_DATA[i];
_initialized = TRUE;
}
return _msg_field_data[id];
}
void
mu_msg_field_foreach (MuMsgFieldForEachFunc func, gconstpointer data)
{
int i;
for (i = 0; i != MU_MSG_FIELD_ID_NUM; ++i)
func (i, data);
}
MuMsgFieldId
mu_msg_field_id_from_name (const char* str, gboolean err)
{
int i;
g_return_val_if_fail (str, MU_MSG_FIELD_ID_NONE);
for (i = 0; i != G_N_ELEMENTS(FIELD_DATA); ++i)
if (g_strcmp0(str, FIELD_DATA[i]._name) == 0)
return FIELD_DATA[i]._id;
if (err)
g_return_val_if_reached (MU_MSG_FIELD_ID_NONE);
return MU_MSG_FIELD_ID_NONE;
}
MuMsgFieldId
mu_msg_field_id_from_shortcut (char kar, gboolean err)
{
int i;
for (i = 0; i != G_N_ELEMENTS(FIELD_DATA); ++i)
if (kar == FIELD_DATA[i]._shortcut)
return FIELD_DATA[i]._id;
if (err)
g_return_val_if_reached (MU_MSG_FIELD_ID_NONE);
return MU_MSG_FIELD_ID_NONE;
}
gboolean
mu_msg_field_gmime (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_GMIME ? TRUE: FALSE;
}
gboolean
mu_msg_field_xapian_index (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_XAPIAN_INDEX ? TRUE: FALSE;
}
gboolean
mu_msg_field_xapian_value (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_XAPIAN_VALUE ? TRUE: FALSE;
}
gboolean
mu_msg_field_xapian_term (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_XAPIAN_TERM ? TRUE: FALSE;
}
gboolean
mu_msg_field_uses_boolean_prefix (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_XAPIAN_BOOLEAN?TRUE:FALSE;
}
gboolean
mu_msg_field_needs_prefix (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags &
FLAG_XAPIAN_PREFIX_ONLY ? TRUE: FALSE;
}
gboolean
mu_msg_field_is_cacheable (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
/* note the FALSE: TRUE */
return mu_msg_field(id)->_flags & FLAG_DONT_CACHE ? FALSE : TRUE;
}
gboolean
mu_msg_field_xapian_contact (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_XAPIAN_CONTACT ? TRUE: FALSE;
}
gboolean
mu_msg_field_normalize (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_NORMALIZE ? TRUE: FALSE;
}
gboolean
mu_msg_field_xapian_escape (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),FALSE);
return mu_msg_field(id)->_flags & FLAG_XAPIAN_ESCAPE ? TRUE: FALSE;
}
gboolean
mu_msg_field_is_numeric (MuMsgFieldId mfid)
{
MuMsgFieldType type;
g_return_val_if_fail (mu_msg_field_id_is_valid(mfid),FALSE);
type = mu_msg_field_type (mfid);
return type == MU_MSG_FIELD_TYPE_BYTESIZE ||
type == MU_MSG_FIELD_TYPE_TIME_T ||
type == MU_MSG_FIELD_TYPE_INT;
}
const char*
mu_msg_field_name (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),NULL);
return mu_msg_field(id)->_name;
}
char
mu_msg_field_shortcut (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),0);
return mu_msg_field(id)->_shortcut;
}
char
mu_msg_field_xapian_prefix (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),0);
return mu_msg_field(id)->_xprefix;
}
MuMsgFieldType
mu_msg_field_type (MuMsgFieldId id)
{
g_return_val_if_fail (mu_msg_field_id_is_valid(id),
MU_MSG_FIELD_TYPE_NONE);
return mu_msg_field(id)->_type;
}