X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;ds=sidebyside;f=lib%2Findex.cc;h=d9612e031101e3f96d1c975bbe161e9b933be95f;hb=20c15bc820bee78cee62060a4f8cd027aa374f42;hp=0eb2774a28a5f3f12964c1959e45ba1ab83a6309;hpb=3767c6f9f9c4719f36569daa05cd56470b3fd00f;p=notmuch diff --git a/lib/index.cc b/lib/index.cc index 0eb2774a..d9612e03 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -12,7 +12,7 @@ * 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, see http://www.gnu.org/licenses/ . + * along with this program. If not, see https://www.gnu.org/licenses/ . * * Author: Carl Worth */ @@ -24,19 +24,13 @@ #include -/* Oh, how I wish that gobject didn't require so much noisy boilerplate! */ -#define NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE (notmuch_filter_discard_uuencode_get_type ()) -#define NOTMUCH_FILTER_DISCARD_UUENCODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE, NotmuchFilterDiscardUuencode)) -#define NOTMUCH_FILTER_DISCARD_UUENCODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE, NotmuchFilterDiscardUuencodeClass)) -#define NOTMUCH_IS_FILTER_DISCARD_UUENCODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE)) -#define NOTMUCH_IS_FILTER_DISCARD_UUENCODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE)) -#define NOTMUCH_FILTER_DISCARD_UUENCODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE, NotmuchFilterDiscardUuencodeClass)) - -typedef struct _NotmuchFilterDiscardUuencode NotmuchFilterDiscardUuencode; -typedef struct _NotmuchFilterDiscardUuencodeClass NotmuchFilterDiscardUuencodeClass; +/* Oh, how I wish that gobject didn't require so much noisy boilerplate! + * (Though I have at least eliminated some of the stock set...) */ +typedef struct _NotmuchFilterDiscardNonTerm NotmuchFilterDiscardNonTerm; +typedef struct _NotmuchFilterDiscardNonTermClass NotmuchFilterDiscardNonTermClass; /** - * NotmuchFilterDiscardUuencode: + * NotmuchFilterDiscardNonTerm: * * @parent_object: parent #GMimeFilter * @encode: encoding vs decoding @@ -60,22 +54,18 @@ typedef struct _NotmuchFilterDiscardUuencodeClass NotmuchFilterDiscardUuencodeCl * final line of encoded data (the line not starting with M) will be * indexed. **/ -struct _NotmuchFilterDiscardUuencode { +struct _NotmuchFilterDiscardNonTerm { GMimeFilter parent_object; int state; }; -struct _NotmuchFilterDiscardUuencodeClass { +struct _NotmuchFilterDiscardNonTermClass { GMimeFilterClass parent_class; }; -GType notmuch_filter_discard_uuencode_get_type (void); - -GMimeFilter *notmuch_filter_discard_uuencode_new (void); +static GMimeFilter *notmuch_filter_discard_non_term_new (void); -static void notmuch_filter_discard_uuencode_class_init (NotmuchFilterDiscardUuencodeClass *klass); -static void notmuch_filter_discard_uuencode_init (NotmuchFilterDiscardUuencode *filter, NotmuchFilterDiscardUuencodeClass *klass); -static void notmuch_filter_discard_uuencode_finalize (GObject *object); +static void notmuch_filter_discard_non_term_finalize (GObject *object); static GMimeFilter *filter_copy (GMimeFilter *filter); static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, @@ -87,40 +77,15 @@ static void filter_reset (GMimeFilter *filter); static GMimeFilterClass *parent_class = NULL; -GType -notmuch_filter_discard_uuencode_get_type (void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (NotmuchFilterDiscardUuencodeClass), - NULL, /* base_class_init */ - NULL, /* base_class_finalize */ - (GClassInitFunc) notmuch_filter_discard_uuencode_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (NotmuchFilterDiscardUuencode), - 0, /* n_preallocs */ - (GInstanceInitFunc) notmuch_filter_discard_uuencode_init, - NULL /* value_table */ - }; - - type = g_type_register_static (GMIME_TYPE_FILTER, "NotmuchFilterDiscardUuencode", &info, (GTypeFlags) 0); - } - - return type; -} - static void -notmuch_filter_discard_uuencode_class_init (NotmuchFilterDiscardUuencodeClass *klass) +notmuch_filter_discard_non_term_class_init (NotmuchFilterDiscardNonTermClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass); parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER); - object_class->finalize = notmuch_filter_discard_uuencode_finalize; + object_class->finalize = notmuch_filter_discard_non_term_finalize; filter_class->copy = filter_copy; filter_class->filter = filter_filter; @@ -129,14 +94,7 @@ notmuch_filter_discard_uuencode_class_init (NotmuchFilterDiscardUuencodeClass *k } static void -notmuch_filter_discard_uuencode_init (NotmuchFilterDiscardUuencode *filter, NotmuchFilterDiscardUuencodeClass *klass) -{ - (void) klass; - filter->state = 0; -} - -static void -notmuch_filter_discard_uuencode_finalize (GObject *object) +notmuch_filter_discard_non_term_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -145,14 +103,14 @@ static GMimeFilter * filter_copy (GMimeFilter *gmime_filter) { (void) gmime_filter; - return notmuch_filter_discard_uuencode_new (); + return notmuch_filter_discard_non_term_new (); } static void filter_filter (GMimeFilter *gmime_filter, char *inbuf, size_t inlen, size_t prespace, char **outbuf, size_t *outlen, size_t *outprespace) { - NotmuchFilterDiscardUuencode *filter = (NotmuchFilterDiscardUuencode *) gmime_filter; + NotmuchFilterDiscardNonTerm *filter = (NotmuchFilterDiscardNonTerm *) gmime_filter; register const char *inptr = inbuf; const char *inend = inbuf + inlen; char *outptr; @@ -186,7 +144,7 @@ filter_filter (GMimeFilter *gmime_filter, char *inbuf, size_t inlen, size_t pres {9, ' ', ' ', 10, 0}, {10, '\n', '\n', 11, 10}, {11, 'M', 'M', 12, 0}, - {12, ' ', '`', 12, 11} + {12, ' ', '`', 12, 11} }; int next; @@ -227,22 +185,40 @@ filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace static void filter_reset (GMimeFilter *gmime_filter) { - NotmuchFilterDiscardUuencode *filter = (NotmuchFilterDiscardUuencode *) gmime_filter; + NotmuchFilterDiscardNonTerm *filter = (NotmuchFilterDiscardNonTerm *) gmime_filter; filter->state = 0; } /** - * notmuch_filter_discard_uuencode_new: + * notmuch_filter_discard_non_term_new: * - * Returns: a new #NotmuchFilterDiscardUuencode filter. + * Returns: a new #NotmuchFilterDiscardNonTerm filter. **/ -GMimeFilter * -notmuch_filter_discard_uuencode_new (void) +static GMimeFilter * +notmuch_filter_discard_non_term_new (void) { - NotmuchFilterDiscardUuencode *filter; + static GType type = 0; + NotmuchFilterDiscardNonTerm *filter; + + if (!type) { + static const GTypeInfo info = { + sizeof (NotmuchFilterDiscardNonTermClass), + NULL, /* base_class_init */ + NULL, /* base_class_finalize */ + (GClassInitFunc) notmuch_filter_discard_non_term_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (NotmuchFilterDiscardNonTerm), + 0, /* n_preallocs */ + NULL, /* instance_init */ + NULL /* value_table */ + }; + + type = g_type_register_static (GMIME_TYPE_FILTER, "NotmuchFilterDiscardNonTerm", &info, (GTypeFlags) 0); + } - filter = (NotmuchFilterDiscardUuencode *) g_object_newv (NOTMUCH_TYPE_FILTER_DISCARD_UUENCODE, 0, NULL); + filter = (NotmuchFilterDiscardNonTerm *) g_object_newv (type, 0, NULL); filter->state = 0; return (GMimeFilter *) filter; @@ -255,26 +231,22 @@ _index_address_mailbox (notmuch_message_t *message, InternetAddress *address) { InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX (address); - const char *name, *addr; + const char *name, *addr, *combined; void *local = talloc_new (message); name = internet_address_get_name (address); addr = internet_address_mailbox_get_addr (mailbox); - /* In the absence of a name, we'll strip the part before the @ - * from the address. */ - if (! name) { - const char *at; + /* Combine the name and address and index them as a phrase. */ + if (name && addr) + combined = talloc_asprintf (local, "%s %s", name, addr); + else if (name) + combined = name; + else + combined = addr; - at = strchr (addr, '@'); - if (at) - name = talloc_strndup (local, addr, at - addr); - } - - if (name) - _notmuch_message_gen_terms (message, prefix_name, name); - if (addr) - _notmuch_message_gen_terms (message, prefix_name, addr); + if (combined) + _notmuch_message_gen_terms (message, prefix_name, combined); talloc_free (local); } @@ -328,49 +300,57 @@ _index_address_list (notmuch_message_t *message, } } -static const char * -skip_re_in_subject (const char *subject) -{ - const char *s = subject; - - if (subject == NULL) - return NULL; - - while (*s) { - while (*s && isspace (*s)) - s++; - if (strncasecmp (s, "re:", 3) == 0) - s += 3; - else - break; - } - - return s; -} - /* Callback to generate terms for each mime part of a message. */ static void _index_mime_part (notmuch_message_t *message, GMimeObject *part) { GMimeStream *stream, *filter; - GMimeFilter *discard_uuencode_filter; + GMimeFilter *discard_non_term_filter; GMimeDataWrapper *wrapper; GByteArray *byte_array; GMimeContentDisposition *disposition; char *body; + const char *charset; + + if (! part) { + _notmuch_database_log (_notmuch_message_database (message), + "Warning: Not indexing empty mime part.\n"); + return; + } + + GMimeContentType *content_type = g_mime_object_get_content_type(part); + if (content_type) { + char *mime_string = g_mime_content_type_to_string(content_type); + if (mime_string) + { + _notmuch_message_gen_terms (message, "mimetype", mime_string); + g_free(mime_string); + } + } if (GMIME_IS_MULTIPART (part)) { GMimeMultipart *multipart = GMIME_MULTIPART (part); int i; + if (GMIME_IS_MULTIPART_SIGNED (multipart)) + _notmuch_message_add_term (message, "tag", "signed"); + + if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) + _notmuch_message_add_term (message, "tag", "encrypted"); + for (i = 0; i < g_mime_multipart_get_count (multipart); i++) { if (GMIME_IS_MULTIPART_SIGNED (multipart)) { /* Don't index the signature. */ if (i == 1) continue; if (i > 1) - fprintf (stderr, "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n"); + _notmuch_database_log (_notmuch_message_database (message), + "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n"); + } + if (GMIME_IS_MULTIPART_ENCRYPTED (multipart)) { + /* Don't index encrypted parts. */ + continue; } _index_mime_part (message, g_mime_multipart_get_part (multipart, i)); @@ -389,14 +369,16 @@ _index_mime_part (notmuch_message_t *message, } if (! (GMIME_IS_PART (part))) { - fprintf (stderr, "Warning: Not indexing unknown mime part: %s.\n", - g_type_name (G_OBJECT_TYPE (part))); + _notmuch_database_log (_notmuch_message_database (message), + "Warning: Not indexing unknown mime part: %s.\n", + g_type_name (G_OBJECT_TYPE (part))); return; } disposition = g_mime_object_get_content_disposition (part); if (disposition && - strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0) + strcasecmp (g_mime_content_disposition_get_disposition (disposition), + GMIME_DISPOSITION_ATTACHMENT) == 0) { const char *filename = g_mime_part_get_filename (GMIME_PART (part)); @@ -414,10 +396,24 @@ _index_mime_part (notmuch_message_t *message, g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (stream), FALSE); filter = g_mime_stream_filter_new (stream); - discard_uuencode_filter = notmuch_filter_discard_uuencode_new (); + discard_non_term_filter = notmuch_filter_discard_non_term_new (); g_mime_stream_filter_add (GMIME_STREAM_FILTER (filter), - discard_uuencode_filter); + discard_non_term_filter); + + charset = g_mime_object_get_content_type_parameter (part, "charset"); + if (charset) { + GMimeFilter *charset_filter; + charset_filter = g_mime_filter_charset_new (charset, "UTF-8"); + /* This result can be NULL for things like "unknown-8bit". + * Don't set a NULL filter as that makes GMime print + * annoying assertion-failure messages on stderr. */ + if (charset_filter) { + g_mime_stream_filter_add (GMIME_STREAM_FILTER (filter), + charset_filter); + g_object_unref (charset_filter); + } + } wrapper = g_mime_part_get_content_object (GMIME_PART (part)); if (wrapper) @@ -425,7 +421,7 @@ _index_mime_part (notmuch_message_t *message, g_object_unref (stream); g_object_unref (filter); - g_object_unref (discard_uuencode_filter); + g_object_unref (discard_non_term_filter); g_byte_array_append (byte_array, (guint8 *) "\0", 1); body = (char *) g_byte_array_free (byte_array, FALSE); @@ -439,59 +435,36 @@ _index_mime_part (notmuch_message_t *message, notmuch_status_t _notmuch_message_index_file (notmuch_message_t *message, - const char *filename) + notmuch_message_file_t *message_file) { - GMimeStream *stream = NULL; - GMimeParser *parser = NULL; - GMimeMessage *mime_message = NULL; + GMimeMessage *mime_message; InternetAddressList *addresses; - FILE *file = NULL; const char *from, *subject; - notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; - static int initialized = 0; - - if (! initialized) { - g_mime_init (0); - initialized = 1; - } - - file = fopen (filename, "r"); - if (! file) { - fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno)); - ret = NOTMUCH_STATUS_FILE_ERROR; - goto DONE; - } - - /* Evil GMime steals my FILE* here so I won't fclose it. */ - stream = g_mime_stream_file_new (file); + notmuch_status_t status; - parser = g_mime_parser_new_with_stream (stream); - - mime_message = g_mime_parser_construct_message (parser); + status = _notmuch_message_file_get_mime_message (message_file, + &mime_message); + if (status) + return status; from = g_mime_message_get_sender (mime_message); - addresses = internet_address_list_parse_string (from); - _index_address_list (message, "from", addresses); + addresses = internet_address_list_parse_string (from); + if (addresses) { + _index_address_list (message, "from", addresses); + g_object_unref (addresses); + } addresses = g_mime_message_get_all_recipients (mime_message); - _index_address_list (message, "to", addresses); + if (addresses) { + _index_address_list (message, "to", addresses); + g_object_unref (addresses); + } subject = g_mime_message_get_subject (mime_message); - subject = skip_re_in_subject (subject); _notmuch_message_gen_terms (message, "subject", subject); _index_mime_part (message, g_mime_message_get_mime_part (mime_message)); - DONE: - if (mime_message) - g_object_unref (mime_message); - - if (parser) - g_object_unref (parser); - - if (stream) - g_object_unref (stream); - - return ret; + return NOTMUCH_STATUS_SUCCESS; }