* <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,6 +1,6 @@
.TH MU-EASY 1 "August 2011" "User Manuals" .TH MU-EASY 1 "November 2011" "User Manuals"
.SH NAME .SH NAME
mu easy \- a quick introduction to mu mu easy \- a quick introduction to mu
@ -24,7 +24,7 @@ you won't be able to index/search your mail.
Before you can search e-mails, you'll first need to index them: Before you can search e-mails, you'll first need to index them:
.nf .nf
\fB$ mu index\fR \fB$ mu index\fR
.fi .fi
The process can take a few minutes, depending on the amount of mail you have, The process can take a few minutes, depending on the amount of mail you have,
@ -54,7 +54,7 @@ some examples for common cases.
First, let's search for all messages sent to Julius Caesar regarding fruit: First, let's search for all messages sent to Julius Caesar regarding fruit:
.nf .nf
\fB$ mu find t:julius fruit\fR \fB$ mu find t:julius fruit\fR
.fi .fi
This should return something like: This should return something like:
@ -73,7 +73,7 @@ date/sender/subject. However, we can change this using the \fI--fields\fR
parameter (see the \fBmu-find\fR man page for the details): parameter (see the \fBmu-find\fR man page for the details):
.nf .nf
\fB$ mu find --fields="t s" t:julius fruit\fR \fB$ mu find --fields="t s" t:julius fruit\fR
.fi .fi
In other words, display the 'To:'-field (t) and the subject (s). This should In other words, display the 'To:'-field (t) and the subject (s). This should
@ -90,7 +90,7 @@ is, it displays messages that match all the parameters. However, we can use
logical OR as well: logical OR as well:
.nf .nf
\fB$ mu find t:julius OR f:socrates\fR \fB$ mu find t:julius OR f:socrates\fR
.fi .fi
In other words, display messages that are either sent to Julius Caesar In other words, display messages that are either sent to Julius Caesar
@ -106,7 +106,7 @@ a 'summary' of the first lines of the message using the \fI--summary\fR
option, which will 'summarize' the first \fIn\fR lines of the message: option, which will 'summarize' the first \fIn\fR lines of the message:
.nf .nf
\fB$ mu find --summary napoleon m:/archive\fR \fB$ mu find --summary napoleon m:/archive\fR
.fi .fi
.nf .nf
@ -130,21 +130,21 @@ version 0.9 or later.
Get all important messages which are signed: Get all important messages which are signed:
.nf .nf
\fB$ mu find flag:signed prio:high \fR \fB$ mu find flag:signed prio:high \fR
.fi .fi
Get all messages from Jim without an attachment: Get all messages from Jim without an attachment:
.nf .nf
\fB$ mu find from:jim AND NOT flag:attach\fR \fB$ mu find from:jim AND NOT flag:attach\fR
.fi .fi
Get all unread messages where the subject mentions Ångström: Get all unread messages where the subject mentions Ångström:
.nf .nf
\fB$ mu find subject:Ångström flag:unread\fR \fB$ mu find subject:Ångström flag:unread\fR
.fi .fi
which is equivalent to: which is equivalent to:
.nf .nf
\fB$ mu find subject:angstrom flag:unread\fR \fB$ mu find subject:angstrom flag:unread\fR
.fi .fi
because does mu is case-insensitive and accent-insensitive. because does mu is case-insensitive and accent-insensitive.
@ -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
@ -195,14 +214,14 @@ need its path. To get the path (think \fBl\fRocation) for our first example we
can use: can use:
.nf .nf
\fB$ mu find --fields="l" t:julius fruit\fR \fB$ mu find --fields="l" t:julius fruit\fR
.fi .fi
And we'll get someting like: And we'll get someting like:
.nf .nf
/home/someuser/Maildir/archive/cur/1266188485_0.6850.cthulhu:2, /home/someuser/Maildir/archive/cur/1266188485_0.6850.cthulhu:2,
.fi .fi
We can now display this message: We can now display this message:
.nf .nf
\fB$ mu view /home/someuser/Maildir/archive/cur/1266188485_0.6850.cthulhu:2,\fR \fB$ mu view /home/someuser/Maildir/archive/cur/1266188485_0.6850.cthulhu:2,\fR
@ -225,7 +244,7 @@ find \fIcontacts\fR, that is, names + addresses. Without any search
expression, \fBmu cfind\fR lists all of your contacts. expression, \fBmu cfind\fR lists all of your contacts.
.nf .nf
\fB$ mu cfind julius\fR \fB$ mu cfind julius\fR
.fi .fi
will find all contacts with 'julius' in either name or e-mail address. Note will find all contacts with 'julius' in either name or e-mail address. Note
@ -237,7 +256,7 @@ program. For example, to export your contact information to a \fBmutt\fR
address book file, you can use something like: address book file, you can use something like:
.nf .nf
\fB$ mu cfind --format=mutt-alias > ~/mutt-aliases \fR \fB$ mu cfind --format=mutt-alias > ~/mutt-aliases \fR
.fi .fi
Then, you can use them in \fBmutt\fR if you add something like \fBsource Then, you can use them in \fBmutt\fR if you add something like \fBsource

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

@ -29,7 +29,9 @@ G_BEGIN_DECLS
enum _MuMsgFieldId { 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,