X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fthread.cc;h=3738baa90978563dcfacc2b62f820402f8790fa1;hp=b8be3e1b5e889f5b873fe21fe50c6a0c6038db44;hb=a4ce6cfbc63c53934c4c06f1b00ffef1c560b3b5;hpb=cd19671f51b8f87303de6ab536afd6aa36efec61 diff --git a/lib/thread.cc b/lib/thread.cc index b8be3e1b..3738baa9 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -21,8 +21,6 @@ #include "notmuch-private.h" #include "database-private.h" -#include - #include #include /* GHashTable */ @@ -31,8 +29,10 @@ struct _notmuch_thread { char *thread_id; char *subject; GHashTable *authors_hash; + GPtrArray *authors_array; + GHashTable *matched_authors_hash; + int has_non_matched_authors; char *authors; - char *nonmatched_authors; GHashTable *tags; notmuch_message_list_t *message_list; @@ -47,16 +47,26 @@ static int _notmuch_thread_destructor (notmuch_thread_t *thread) { g_hash_table_unref (thread->authors_hash); + g_hash_table_unref (thread->matched_authors_hash); g_hash_table_unref (thread->tags); g_hash_table_unref (thread->message_hash); + if (thread->authors_array) { + g_ptr_array_free (thread->authors_array, TRUE); + thread->authors_array = NULL; + } + return 0; } +/* Add each author of the thread to the thread's authors_hash and the + * thread's authors_array. */ static void _thread_add_author (notmuch_thread_t *thread, const char *author) { + char *author_copy; + if (author == NULL) return; @@ -64,97 +74,78 @@ _thread_add_author (notmuch_thread_t *thread, author, NULL, NULL)) return; - g_hash_table_insert (thread->authors_hash, xstrdup (author), NULL); + author_copy = talloc_strdup (thread, author); + + g_hash_table_insert (thread->authors_hash, author_copy, NULL); + + g_ptr_array_add (thread->authors_array, author_copy); +} + +/* Add each matched author of the thread to the thread's + * matched_authors_hash and to the thread's authors string. */ +static void +_thread_add_matched_author (notmuch_thread_t *thread, + const char *author) +{ + char *author_copy; + + if (author == NULL) + return; + + if (g_hash_table_lookup_extended (thread->matched_authors_hash, + author, NULL, NULL)) + return; + + author_copy = talloc_strdup (thread, author); + + g_hash_table_insert (thread->matched_authors_hash, author_copy, NULL); if (thread->authors) thread->authors = talloc_asprintf (thread, "%s, %s", thread->authors, author); else - thread->authors = talloc_strdup (thread, author); + thread->authors = author_copy; } -/* - * move authors of matched messages in the thread to - * the front of the authors list, but keep them in - * existing order within their group - */ +/* Copy any authors from the authors array that were not also matched + * authors onto the end of the thread's authors string. + * We use a '|' to separate matched and unmatched authors. */ static void -_thread_move_matched_author (notmuch_thread_t *thread, - const char *author) +_complete_thread_authors (notmuch_thread_t *thread) { - char *authors_copy; - char *current_author; - char *last_pipe,*next_pipe; - int idx,nm_start,author_len,authors_len; - - if (thread->authors == NULL || author == NULL) - return; - if (thread->nonmatched_authors == NULL) - thread->nonmatched_authors = thread->authors; - author_len = strlen(author); - authors_len = strlen(thread->authors); - if (author_len == authors_len) { - /* just one author */ - thread->nonmatched_authors += author_len; - return; - } - current_author = strcasestr(thread->authors, author); - if (current_author == NULL) - return; - /* how far inside the nonmatched authors is our author? */ - idx = current_author - thread->nonmatched_authors; - if (idx < 0) { - /* already among matched authors */ - return; - } - /* are there any authors in the list after our author? */ - if (thread->nonmatched_authors + author_len < thread->authors + authors_len) { - /* we have to make changes, so let's get a temp copy */ - authors_copy = talloc_strdup(thread,thread->authors); - /* nm_start is the offset into where the non-matched authors start */ - nm_start = thread->nonmatched_authors - thread->authors; - /* copy this author and add the "| " - the if clause above tells us there's more */ - strncpy(thread->nonmatched_authors,author,author_len); - strncpy(thread->nonmatched_authors+author_len,"| ",2); - thread->nonmatched_authors += author_len+2; - if (idx > 0) { - /* we are actually moving authors around, not just changing the separator - * first copy the authors that came BEFORE our author */ - strncpy(thread->nonmatched_authors, authors_copy+nm_start, idx-2); - /* finally, if there are authors AFTER our author, copy those */ - if(author_len+nm_start+idx < authors_len) { - strncpy(thread->nonmatched_authors + idx - 2,", ",2); - strncpy(thread->nonmatched_authors + idx, authors_copy+nm_start + idx + author_len + 2, - authors_len - (nm_start + idx + author_len + 2)); - } - } - /* finally let's make sure there's just one '|' in the authors string */ - last_pipe = strchr(thread->authors,'|'); - while (last_pipe) { - next_pipe = strchr(last_pipe+1,'|'); - if (next_pipe) - *last_pipe = ','; - last_pipe = next_pipe; + unsigned int i; + char *author; + + for (i = 0; i < thread->authors_array->len; i++) { + author = (char *) g_ptr_array_index (thread->authors_array, i); + if (g_hash_table_lookup_extended (thread->matched_authors_hash, + author, NULL, NULL)) + continue; + if (thread->has_non_matched_authors) { + thread->authors = talloc_asprintf (thread, "%s, %s", + thread->authors, + author); + } else { + thread->authors = talloc_asprintf (thread, "%s| %s", + thread->authors, + author); + thread->has_non_matched_authors = 1; } - } else { - thread->nonmatched_authors += author_len; - /* so now all authors are matched - let's remove the '|' */ - last_pipe = strchr(thread->authors,'|'); - if (last_pipe) - *last_pipe = ','; } - return; + + g_ptr_array_free (thread->authors_array, TRUE); + thread->authors_array = NULL; } -/* clean up the uggly "Lastname, Firstname" format that some mail systems +/* clean up the ugly "Lastname, Firstname" format that some mail systems * (most notably, Exchange) are creating to be "Firstname Lastname" * To make sure that we don't change other potential situations where a * comma is in the name, we check that we match one of these patterns * "Last, First" * "Last, First MI" */ -char * +static char * _thread_cleanup_author (notmuch_thread_t *thread, const char *author, const char *from) { @@ -163,11 +154,19 @@ _thread_cleanup_author (notmuch_thread_t *thread, char *blank; int fname,lname; + if (author == NULL) + return NULL; clean_author = talloc_strdup(thread, author); if (clean_author == NULL) return NULL; + /* check if there's a comma in the name and that there's a + * component of the name behind it (so the name doesn't end with + * the comma - in which case the string that strchr finds is just + * one character long ",\0"). + * Otherwise just return the copy of the original author name that + * we just made*/ comma = strchr(author,','); - if (comma) { + if (comma && strlen(comma) > 1) { /* let's assemble what we think is the correct name */ lname = comma - author; fname = strlen(author) - lname - 2; @@ -187,7 +186,6 @@ _thread_cleanup_author (notmuch_thread_t *thread, /* we didn't identify this as part of the email address * so let's punt and return the original author */ strcpy (clean_author, author); - } return clean_author; } @@ -290,11 +288,17 @@ _thread_add_matched_message (notmuch_thread_t *thread, date = notmuch_message_get_date (message); - if (date < thread->oldest || ! thread->matched_messages) + if (date < thread->oldest || ! thread->matched_messages) { thread->oldest = date; + if (sort == NOTMUCH_SORT_OLDEST_FIRST) + _thread_set_subject_from_message (thread, message); + } - if (date > thread->newest || ! thread->matched_messages) + if (date > thread->newest || ! thread->matched_messages) { thread->newest = date; + if (sort != NOTMUCH_SORT_OLDEST_FIRST) + _thread_set_subject_from_message (thread, message); + } thread->matched_messages++; @@ -304,13 +308,8 @@ _thread_add_matched_message (notmuch_thread_t *thread, notmuch_message_set_flag (hashed_message, NOTMUCH_MESSAGE_FLAG_MATCH, 1); } - _thread_move_matched_author (thread,notmuch_message_get_author(hashed_message)); - if ((sort == NOTMUCH_SORT_OLDEST_FIRST && date <= thread->newest) || - (sort != NOTMUCH_SORT_OLDEST_FIRST && date == thread->newest)) - { - _thread_set_subject_from_message (thread, message); - } + _thread_add_matched_author (thread, notmuch_message_get_author (hashed_message)); } static void @@ -430,9 +429,13 @@ _notmuch_thread_create (void *ctx, thread->thread_id = talloc_strdup (thread, thread_id); thread->subject = NULL; thread->authors_hash = g_hash_table_new_full (g_str_hash, g_str_equal, - free, NULL); + NULL, NULL); + thread->authors_array = g_ptr_array_new (); + thread->matched_authors_hash = g_hash_table_new_full (g_str_hash, + g_str_equal, + NULL, NULL); thread->authors = NULL; - thread->nonmatched_authors = NULL; + thread->has_non_matched_authors = 0; thread->tags = g_hash_table_new_full (g_str_hash, g_str_equal, free, NULL); @@ -493,6 +496,8 @@ _notmuch_thread_create (void *ctx, notmuch_query_destroy (matched_query); } + _complete_thread_authors (thread); + _resolve_thread_relationships (thread); return thread;