* <many> add support for searching attachment mime-types

- updated manpages
  - some cleanups

  Note, requires a --rebuild
This commit is contained in:
djcb
2011-11-11 09:13:35 +02:00
parent 0abe2e307a
commit d93186e0e3
9 changed files with 116 additions and 40 deletions

2
NEWS
View File

@ -3,6 +3,8 @@
** Release 0.9.8 <> ** Release 0.9.8 <>
- '--descending' has been renamed into '--reverse' - '--descending' has been renamed into '--reverse'
- search for attachment MIME-type using 'attmime:' or 'y:'
- experimental emacs-based mail client
* Release 0.9.7 <> * Release 0.9.7 <>

View File

@ -1,4 +1,4 @@
.TH MU-EASY 1 "August 2011" "User Manuals" .TH MU-EASY 1 "November 2011" "User Manuals"
.SH NAME .SH NAME
@ -159,7 +159,7 @@ Get all messages received today:
\fB$ mu find date:today..now\fR \fB$ mu find date:today..now\fR
.fi .fi
Get all message we got in the last two weeks about emacs: Get all messages we got in the last two weeks about emacs:
.nf .nf
\fB$ mu find date:2w..now emacs\fR \fB$ mu find date:2w..now emacs\fR
.fi .fi
@ -182,6 +182,25 @@ filename, for example:
.fi .fi
will get you all message with an attachment starting with 'pic'. will get you all message with an attachment starting with 'pic'.
If you want to find attachments with a certain MIME-type, you can use the
following:
Get all messages with PDF attachments:
.nf
\fB$ mu find attmime:application/pdf\fR
.fi
or even:
Get all messages with image attachments:
.nf
\fB$ mu find 'attmime:image/*'\fR
.fi
Note that (1) the '*' wildcard can only be used as the rightmost thing in a
search query, and (2) that you need to quote the search term, because
otherwise your shell will interpret the '*' (expanding it to all files in the
current directory -- probably not what you want).
.SH DISPLAYING MESSAGES .SH DISPLAYING MESSAGES

View File

@ -1,4 +1,4 @@
.TH MU FIND 1 "July 2011" "User Manuals" .TH MU FIND 1 "November 2011" "User Manuals"
.SH NAME .SH NAME
@ -123,6 +123,7 @@ search fields and their abbreviations:
date,d Date-Range date,d Date-Range
size,z Message size size,z Message size
attach,a Attachment filename attach,a Attachment filename
attmime,y Attachment MIME-type
tag,x Tag for the message (contents of the \fIX-Label\fR field) tag,x Tag for the message (contents of the \fIX-Label\fR field)
.fi .fi
@ -474,6 +475,23 @@ Find all unread messages with attachments:
.fi .fi
Find all messages with PDF-attachments:
.nf
$ mu find attmime:application/pdf
.fi
Find all messages with attached images:
.nf
$ mu find 'attmime:image/*'
.fi
Note[1]: the argument needs to be quoted, or the shell will interpret the '*'
Note[2]: the '*' wild card can only be used as the last (rightmost) part of a
search term.
.SS Integrating mu find with mail clients .SS Integrating mu find with mail clients
.TP .TP

View File

@ -34,24 +34,31 @@ enum _FieldFlags {
FLAG_GMIME = 1 << 0, /* field retrieved through FLAG_GMIME = 1 << 0, /* field retrieved through
* gmime */ * gmime */
FLAG_XAPIAN_INDEX = 1 << 1, /* field is indexed in FLAG_XAPIAN_INDEX = 1 << 1, /* field is indexed in
* xapian */ * xapian (i.e., the text
* is processed */
FLAG_XAPIAN_TERM = 1 << 2, /* field stored as term in FLAG_XAPIAN_TERM = 1 << 2, /* field stored as term in
* xapian */ * xapian (so it can be searched) */
FLAG_XAPIAN_VALUE = 1 << 3, /* field stored as value in FLAG_XAPIAN_VALUE = 1 << 3, /* field stored as value in
* xapian */ * xapian (so the literal
* value can be
* retrieved) */
FLAG_XAPIAN_CONTACT = 1 << 4, /* field contains one or more FLAG_XAPIAN_CONTACT = 1 << 4, /* field contains one or more
* e-mail-addresses */ * e-mail-addresses */
FLAG_XAPIAN_ESCAPE = 1 << 5, /* field needs escaping for FLAG_XAPIAN_ESCAPE = 1 << 5, /* field needs escaping for
* xapian */ * xapian (so the xapian
* query does not get
* confused) */
FLAG_XAPIAN_BOOLEAN = 1 << 6, /* use 'add_boolean_prefix' FLAG_XAPIAN_BOOLEAN = 1 << 6, /* use 'add_boolean_prefix'
* for Xapian queries */ * for Xapian queries */
FLAG_XAPIAN_PREFIX_ONLY = 1 << 7, /* whether this fields FLAG_XAPIAN_PREFIX_ONLY = 1 << 7, /* whether this fields
* matches only when the * matches only when the
* prefix is explicitly * prefix is explicitly
* included */ * included in the search
* query -- e.g., the text
* body */
FLAG_NORMALIZE = 1 << 8, /* field needs flattening for FLAG_NORMALIZE = 1 << 8, /* field needs flattening for
* case/accents */ * case/accents */
FLAG_DONT_CACHE = 1 << 9 /* don't cache this field in FLAG_DONT_CACHE = 1 << 9, /* don't cache this field in
* the MuMsg cache */ * the MuMsg cache */
}; };
typedef enum _FieldFlags FieldFlags; typedef enum _FieldFlags FieldFlags;
@ -81,8 +88,14 @@ static const MuMsgField FIELD_DATA[] = {
MU_MSG_FIELD_ID_ATTACH, MU_MSG_FIELD_ID_ATTACH,
MU_MSG_FIELD_TYPE_STRING, MU_MSG_FIELD_TYPE_STRING,
"attach" , 'a', 'A', "attach" , 'a', 'A',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_NORMALIZE | FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_NORMALIZE | FLAG_DONT_CACHE
FLAG_DONT_CACHE },
{
MU_MSG_FIELD_ID_ATTACH_MIME_TYPE,
MU_MSG_FIELD_TYPE_STRING,
"attmime" , 'y', 'Y',
FLAG_XAPIAN_TERM | FLAG_XAPIAN_ESCAPE
}, },
{ {
@ -213,6 +226,13 @@ static const MuMsgField FIELD_DATA[] = {
"tag", 'x', 'X', "tag", 'x', 'X',
FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_PREFIX_ONLY | FLAG_GMIME | FLAG_XAPIAN_TERM | FLAG_XAPIAN_PREFIX_ONLY |
FLAG_NORMALIZE | FLAG_XAPIAN_ESCAPE 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
} }
/* note, mu-store also use the 'Q' internal prefix for its uids */ /* note, mu-store also use the 'Q' internal prefix for its uids */

View File

@ -30,6 +30,8 @@ enum _MuMsgFieldId {
/* first all the string-based ones */ /* first all the string-based ones */
MU_MSG_FIELD_ID_ATTACH = 0, MU_MSG_FIELD_ID_ATTACH = 0,
MU_MSG_FIELD_ID_ATTACH_MIME_TYPE, /* mime-type */
MU_MSG_FIELD_ID_BCC, MU_MSG_FIELD_ID_BCC,
MU_MSG_FIELD_ID_BODY_HTML, MU_MSG_FIELD_ID_BODY_HTML,
MU_MSG_FIELD_ID_BODY_TEXT, MU_MSG_FIELD_ID_BODY_TEXT,
@ -40,6 +42,9 @@ enum _MuMsgFieldId {
MU_MSG_FIELD_ID_PATH, MU_MSG_FIELD_ID_PATH,
MU_MSG_FIELD_ID_SUBJECT, MU_MSG_FIELD_ID_SUBJECT,
MU_MSG_FIELD_ID_TO, MU_MSG_FIELD_ID_TO,
MU_MSG_FIELD_ID_UID, /* special, generated from path */
/* MU_MSG_STRING_FIELD_ID_NUM, see below */ /* MU_MSG_STRING_FIELD_ID_NUM, see below */
/* string list items... */ /* string list items... */
@ -59,7 +64,7 @@ typedef guint8 MuMsgFieldId;
/* some specials... */ /* some specials... */
static const MuMsgFieldId MU_MSG_FIELD_ID_NONE = (MuMsgFieldId)-1; static const MuMsgFieldId MU_MSG_FIELD_ID_NONE = (MuMsgFieldId)-1;
#define MU_MSG_STRING_FIELD_ID_NUM (MU_MSG_FIELD_ID_TO + 1) #define MU_MSG_STRING_FIELD_ID_NUM (MU_MSG_FIELD_ID_UID + 1)
#define mu_msg_field_id_is_valid(MFID) \ #define mu_msg_field_id_is_valid(MFID) \
((MFID) < MU_MSG_FIELD_ID_NUM) ((MFID) < MU_MSG_FIELD_ID_NUM)

View File

@ -594,7 +594,7 @@ get_body (MuMsgFile *self, gboolean want_html)
/* note, str may be NULL (no body), but that's not necessarily /* note, str may be NULL (no body), but that's not necessarily
* an error; we only warn when an actual error occured */ * an error; we only warn when an actual error occured */
if (err) if (err)
g_warning ("error occured while retrieving %s body" g_warning ("error occured while retrieving %s body "
"for message %s", "for message %s",
want_html ? "html" : "text", self->_path); want_html ? "html" : "text", self->_path);
return str; return str;

View File

@ -225,9 +225,4 @@ private:
}; };
/* Xapian DB prefix for the UID value */
#define MU_STORE_UID_PREFIX "Q"
#endif /*__MU_STORE_PRIV_HH__*/ #endif /*__MU_STORE_PRIV_HH__*/

View File

@ -50,6 +50,8 @@ _MuStore::get_uid_term (const char* path)
unsigned djbhash, bkdrhash, bkdrseed; unsigned djbhash, bkdrhash, bkdrseed;
unsigned u; unsigned u;
static char hex[18]; static char hex[18];
static const char uid_prefix =
mu_msg_field_xapian_prefix(MU_MSG_FIELD_ID_UID);
djbhash = 5381; djbhash = 5381;
bkdrhash = 0; bkdrhash = 0;
@ -60,9 +62,8 @@ _MuStore::get_uid_term (const char* path)
bkdrhash = bkdrhash * bkdrseed + path[u]; bkdrhash = bkdrhash * bkdrseed + path[u];
} }
snprintf (hex, sizeof(hex), snprintf (hex, sizeof(hex), "%c%08x%08x",
MU_STORE_UID_PREFIX "%08x%08x", uid_prefix, djbhash, bkdrhash);
djbhash, bkdrhash);
return hex; return hex;
} }

View File

@ -405,19 +405,32 @@ struct PartData {
static void static void
each_part (MuMsg *msg, MuMsgPart *part, PartData *pdata) each_part (MuMsg *msg, MuMsgPart *part, PartData *pdata)
{ {
static const std::string
att (prefix(MU_MSG_FIELD_ID_ATTACH)),
mime (prefix(MU_MSG_FIELD_ID_ATTACH_MIME_TYPE));
if (mu_msg_part_looks_like_attachment (part, TRUE) && if (mu_msg_part_looks_like_attachment (part, TRUE) &&
(part->file_name)) { (part->file_name)) {
char val[MuStore::MAX_TERM_LENGTH + 1]; char val[MuStore::MAX_TERM_LENGTH + 1];
strncpy (val, part->file_name, sizeof(val)); strncpy (val, part->file_name, sizeof(val));
/* now, let's create a terms... */ /* now, let's create a term... */
mu_str_normalize_in_place (val, TRUE); mu_str_normalize_in_place (val, TRUE);
mu_str_ascii_xapian_escape_in_place (val); mu_str_ascii_xapian_escape_in_place (val);
pdata->_doc.add_term pdata->_doc.add_term
(prefix(pdata->_mfid) + (att + std::string(val, 0, MuStore::MAX_TERM_LENGTH));
std::string(val, 0, MuStore::MAX_TERM_LENGTH));
/* save the mime type */
if (part->type) {
gchar *str;
str = g_strdup_printf ("%s/%s", part->type, part->subtype);
pdata->_doc.add_term
(mime + std::string(str, 0, MuStore::MAX_TERM_LENGTH));
g_free (str);
} else
pdata->_doc.add_term (mime + "application/octet-stream");
} }
} }
@ -482,9 +495,12 @@ add_terms_values (MuMsgFieldId mfid, MsgDoc* msgdoc)
case MU_MSG_FIELD_ID_BODY_TEXT: case MU_MSG_FIELD_ID_BODY_TEXT:
add_terms_values_body (*msgdoc->_doc, msgdoc->_msg, mfid); add_terms_values_body (*msgdoc->_doc, msgdoc->_msg, mfid);
break; break;
case MU_MSG_FIELD_ID_ATTACH: case MU_MSG_FIELD_ID_ATTACH: /* also takes care of MU_MSG_FIELD_ID_ATTACH_MIME */
add_terms_values_attach (*msgdoc->_doc, msgdoc->_msg, mfid); add_terms_values_attach (*msgdoc->_doc, msgdoc->_msg, mfid);
break; break;
case MU_MSG_FIELD_ID_ATTACH_MIME_TYPE:
case MU_MSG_FIELD_ID_UID:
break; /* already taken care of elsewhere */
default: default:
if (mu_msg_field_is_numeric (mfid)) if (mu_msg_field_is_numeric (mfid))
add_terms_values_number (*msgdoc->_doc, msgdoc->_msg, add_terms_values_number (*msgdoc->_doc, msgdoc->_msg,