diff --git a/man/mu-find.1 b/man/mu-find.1 index 7f252269..2517b56a 100644 --- a/man/mu-find.1 +++ b/man/mu-find.1 @@ -1,4 +1,4 @@ -.TH MU FIND 1 "March 2011" "User Manuals" +.TH MU FIND 1 "April 2011" "User Manuals" .SH NAME @@ -273,6 +273,7 @@ search parameters; the complete list: s Message \fBs\fRubject i Message-\fBi\fRd m \fBm\fRaildir + r \fBr\fReferences (message ids In-reply-to, References as comma-separated list) .fi diff --git a/src/mu-msg-fields.c b/src/mu-msg-fields.c index c176952d..c466dfca 100644 --- a/src/mu-msg-fields.c +++ b/src/mu-msg-fields.c @@ -158,6 +158,13 @@ static const MuMsgField FIELD_DATA[] = { MU_MSG_FIELD_TYPE_TIME_T, "timestamp", 'x', 0, FLAG_GMIME + }, + + { + MU_MSG_FIELD_ID_REFS, + MU_MSG_FIELD_TYPE_STRING, + "refs", 'r', 'R', + FLAG_GMIME | FLAG_XAPIAN_VALUE } }; diff --git a/src/mu-msg-fields.h b/src/mu-msg-fields.h index 028a9559..91e49438 100644 --- a/src/mu-msg-fields.h +++ b/src/mu-msg-fields.h @@ -41,7 +41,8 @@ enum _MuMsgFieldId { MU_MSG_FIELD_ID_TO, MU_MSG_FIELD_ID_MSGID, MU_MSG_FIELD_ID_TIMESTAMP, - + MU_MSG_FIELD_ID_REFS, + MU_MSG_FIELD_ID_NUM, /* fake fields */ diff --git a/src/mu-msg-priv.h b/src/mu-msg-priv.h index f98cd94d..3a085243 100644 --- a/src/mu-msg-priv.h +++ b/src/mu-msg-priv.h @@ -43,6 +43,8 @@ enum _StringFields { MDIR_FIELD, /* the maildir */ FLAGS_FIELD_STR, /* message flags */ + + REFS_FIELD, /* msg references, as a comma-sep'd string */ FIELD_NUM }; @@ -59,6 +61,8 @@ struct _MuMsg { size_t _size; time_t _timestamp; MuMsgPrio _prio; + + GSList *_refs; /* msgids of message we refer to */ }; G_END_DECLS diff --git a/src/mu-msg.c b/src/mu-msg.c index 283f651e..37b9b719 100644 --- a/src/mu-msg.c +++ b/src/mu-msg.c @@ -80,6 +80,9 @@ mu_msg_destroy (MuMsg *msg) for (i = 0; i != FIELD_NUM; ++i) g_free (msg->_fields[i]); + + g_slist_foreach (msg->_refs, (GFunc)g_free, NULL); + g_slist_free (msg->_refs); g_slice_free (MuMsg, msg); } @@ -214,7 +217,8 @@ mu_msg_new (const char* filepath, const gchar* mdir, GError **err) msg = g_slice_new0 (MuMsg); msg->_prio = MU_MSG_PRIO_NONE; msg->_refcount = 1; - + msg->_refs = NULL; + if (!init_file_metadata(msg, filepath, mdir, err)) { mu_msg_unref (msg); return NULL; @@ -814,6 +818,92 @@ mu_msg_get_summary (MuMsg *msg, size_t max_lines) } +static GSList* +get_msgids_from_header (MuMsg *msg, const char* header) +{ + GSList *msgids; + const char *str; + + msgids = NULL; + str = g_mime_object_get_header (GMIME_OBJECT(msg->_mime_msg), + header); + + /* get stuff from the 'references' header */ + if (str) { + const GMimeReferences *cur; + GMimeReferences *mime_refs; + mime_refs = g_mime_references_decode (str); + for (cur = mime_refs; cur; cur = g_mime_references_get_next(cur)) { + const char* msgid; + msgid = g_mime_references_get_message_id (cur); + if (msgid) + msgids = g_slist_prepend (msgids, g_strdup (msgid)); + } + g_mime_references_free (mime_refs); + } + + return g_slist_reverse (msgids); +} + +const char* +mu_msg_get_references_str (MuMsg *msg) +{ + const GSList *refs; + gchar *refsstr; + + g_return_val_if_fail (msg, NULL); + + if (msg->_fields[REFS_FIELD]) + return msg->_fields[REFS_FIELD]; + + refsstr = NULL; + refs = mu_msg_get_references (msg); + if (refs) { + const GSList *cur; + for (cur = refs; cur; cur = g_slist_next(cur)) { + char *tmp; + tmp = g_strdup_printf ("%s%s%s", + refsstr ? refsstr : "", + refsstr ? "," : "", + g_strdup((gchar*)cur->data)); + g_free (refsstr); + refsstr = tmp; + } + } + + return msg->_fields[REFS_FIELD] = refsstr; +} + + +const GSList* +mu_msg_get_references (MuMsg *msg) +{ + GSList *refs, *inreply; + + g_return_val_if_fail (msg, NULL); + + if (msg->_refs) + return msg->_refs; + + refs = get_msgids_from_header (msg, "References"); + + /* now, add in-reply-to:, we only take the first one if there + * are more */ + inreply = get_msgids_from_header (msg, "In-reply-to"); + if (inreply) { + refs = g_slist_prepend (refs, g_strdup ((gchar*)inreply->data)); + g_slist_foreach (inreply, (GFunc)g_free, NULL); + g_slist_free (inreply); + } + + /* put in proper order */ + msg->_refs = g_slist_reverse (refs); + + return msg->_refs; +} + + + const char* mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid) { @@ -829,6 +919,7 @@ mu_msg_get_field_string (MuMsg *msg, MuMsgFieldId mfid) case MU_MSG_FIELD_ID_TO: return mu_msg_get_to (msg); case MU_MSG_FIELD_ID_MSGID: return mu_msg_get_msgid (msg); case MU_MSG_FIELD_ID_MAILDIR: return mu_msg_get_maildir (msg); + case MU_MSG_FIELD_ID_REFS: return mu_msg_get_references_str (msg); default: g_return_val_if_reached (NULL); } diff --git a/src/mu-msg.h b/src/mu-msg.h index 18c2ac80..ccc946f7 100644 --- a/src/mu-msg.h +++ b/src/mu-msg.h @@ -292,6 +292,28 @@ MuMsgPrio mu_msg_get_prio (MuMsg *msg); time_t mu_msg_get_timestamp (MuMsg *msg); +/** + * get a list of message ids this message refers to -- this is based + * on the References: and In-reply-to: headers. + * + * @param msg a valid MuMsg instance + * + * @return a list of message id, with the most immediate parent as the + * last element. Don't modify/free this list. + */ +const GSList *mu_msg_get_references (MuMsg *msg); + + +/** + * get the list of references as a comma-separated string + * + * @param msg a valid MuMsg + * + * @return a comma-separated string with the references or NULL if + * there are none. Don't modify/free + */ +const char* mu_msg_get_references_str (MuMsg *msg); + G_END_DECLS #endif /*__MU_MSG_H__*/