--- /dev/null
+Return-Path: <BATV+bfcd26d6da2a49b2fc9f+2418+infradead.org+hohndel@bombadil.srs.infradead.org>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id 9B2234196F0\r
+ for <notmuch@notmuchmail.org>; Tue, 6 Apr 2010 22:52:31 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -4.2\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-4.2 tagged_above=-999 required=5\r
+ tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3] autolearn=ham\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id F21i+NaAOsCW for <notmuch@notmuchmail.org>;\r
+ Tue, 6 Apr 2010 22:52:30 -0700 (PDT)\r
+Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34])\r
+ by olra.theworths.org (Postfix) with ESMTP id 1BC29431FC1\r
+ for <notmuch@notmuchmail.org>; Tue, 6 Apr 2010 22:52:30 -0700 (PDT)\r
+Received: from localhost ([::1] helo=localhost.localdomain)\r
+ by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))\r
+ id 1NzOBh-0003IW-Ep\r
+ for notmuch@notmuchmail.org; Wed, 07 Apr 2010 05:52:29 +0000\r
+Received: by localhost.localdomain (Postfix, from userid 500)\r
+ id D52BCC007F; Tue, 6 Apr 2010 22:52:28 -0700 (PDT)\r
+From: Dirk Hohndel <hohndel@infradead.org>\r
+To: notmuch <notmuch@notmuchmail.org>\r
+Subject: [RFC] reordering and cleanup of thread authors\r
+Date: Tue, 06 Apr 2010 22:52:28 -0700\r
+Message-ID: <m31veru7vn.fsf@x200.gr8dns.org>\r
+MIME-Version: 1.0\r
+Content-Type: text/plain; charset=us-ascii\r
+X-SRS-Rewrite: SMTP reverse-path rewritten from <hohndel@infradead.org> by\r
+ bombadil.infradead.org See http://www.infradead.org/rpr.html\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Wed, 07 Apr 2010 05:52:31 -0000\r
+\r
+\r
+This is based in part on some discussion on IRC today.\r
+When a thread is displayed in the search results, previously the authors\r
+were always displayed in chronological order. But if only part of the\r
+thread matches the query, that may or may not be the intuitive thing to\r
+do.\r
+Imagine the default "+inbox" query. Those mails in the thread that\r
+match the query are actually "new" (whatever that means). And some\r
+people seem to think that it would be much better to see those author\r
+names first. For example, imagine a long and drawn out thread that once\r
+was started by me; you have long read the older part of the thread and\r
+removed the inbox tag. Whenever a new email comes in on this thread, the\r
+author column in the search display will first show "Dirk Hohndel" - I\r
+think it should first show the actual author(s) of the new mail(s).\r
+\r
+The second cleanup that I've done in this context is to convert all\r
+author names into the much easier to parse "Firstname Lastname"\r
+format. Some broken mail systems (cough - Exchange - Cough) seem to\r
+prefer "Lastname, Firstname" - which makes the comma separated list of\r
+authors really hard to parse at one glance. Worse, it creates douplicate\r
+entries if a person happens to show in both orders. So this does a\r
+rather simplistic "look for a comma, if it's there, reorder" approach to\r
+cleaning up the author name.\r
+\r
+I don't think this is ready to be pulled. There was a strong request on\r
+IRC to make the re-ordering of the author names configurable. I think\r
+the cleanup of the names (First Last) should be configurable as well.\r
+And of course I wonder about my implementation, given that I'm still\r
+trying to wrap my mind around the current code base.\r
+\r
+Thanks\r
+\r
+/D\r
+\r
+diff --git a/lib/message.cc b/lib/message.cc\r
+index 721c9a6..ac0afd9 100644\r
+--- a/lib/message.cc\r
++++ b/lib/message.cc\r
+@@ -35,6 +35,7 @@ struct _notmuch_message {\r
+ char *thread_id;\r
+ char *in_reply_to;\r
+ char *filename;\r
++ char *author;\r
+ notmuch_message_file_t *message_file;\r
+ notmuch_message_list_t *replies;\r
+ unsigned long flags;\r
+@@ -110,6 +111,7 @@ _notmuch_message_create (const void *talloc_owner,\r
+ message->in_reply_to = NULL;\r
+ message->filename = NULL;\r
+ message->message_file = NULL;\r
++ message->author = NULL;\r
+ \r
+ message->replies = _notmuch_message_list_create (message);\r
+ if (unlikely (message->replies == NULL)) {\r
+@@ -533,6 +535,20 @@ notmuch_message_get_tags (notmuch_message_t *message)\r
+ return _notmuch_convert_tags(message, i, end);\r
+ }\r
+ \r
++const char *\r
++notmuch_message_get_author (notmuch_message_t *message)\r
++{\r
++ return message->author;\r
++}\r
++\r
++void\r
++notmuch_message_set_author (notmuch_message_t *message,\r
++ const char *author)\r
++{\r
++ message->author = talloc_strdup(message, author);\r
++ return;\r
++}\r
++\r
+ void\r
+ _notmuch_message_set_date (notmuch_message_t *message,\r
+ const char *date)\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index 88da078..79638bb 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -771,6 +771,17 @@ notmuch_message_set_flag (notmuch_message_t *message,\r
+ time_t\r
+ notmuch_message_get_date (notmuch_message_t *message);\r
+ \r
++/* Set the author member of 'message' - this is the representation used\r
++ * when displaying the message\r
++ */\r
++void\r
++notmuch_message_set_author (notmuch_message_t *message, const char *author);\r
++\r
++/* Get the author member of 'message'\r
++ */\r
++const char *\r
++notmuch_message_get_author (notmuch_message_t *message);\r
++\r
+ /* Get the value of the specified header from 'message'.\r
+ *\r
+ * The value will be read from the actual message file, not from the\r
+diff --git a/lib/thread.cc b/lib/thread.cc\r
+index 48c070e..c3c83a3 100644\r
+--- a/lib/thread.cc\r
++++ b/lib/thread.cc\r
+@@ -32,6 +32,7 @@ struct _notmuch_thread {\r
+ char *subject;\r
+ GHashTable *authors_hash;\r
+ char *authors;\r
++ char *nonmatched_authors;\r
+ GHashTable *tags;\r
+ \r
+ notmuch_message_list_t *message_list;\r
+@@ -69,8 +70,95 @@ _thread_add_author (notmuch_thread_t *thread,\r
+ thread->authors = talloc_asprintf (thread, "%s, %s",\r
+ thread->authors,\r
+ author);\r
+- else\r
++ else {\r
+ thread->authors = talloc_strdup (thread, author);\r
++ }\r
++}\r
++\r
++/*\r
++ * move authors of matched messages in the thread to \r
++ * the front of the authors list, but keep them in\r
++ * oldest first order within their group\r
++ */\r
++static void\r
++_thread_move_matched_author (notmuch_thread_t *thread,\r
++ const char *author)\r
++{\r
++ char *authorscopy;\r
++ char *currentauthor;\r
++ int idx,nmstart,author_len,authors_len;\r
++\r
++ if (thread->authors == NULL)\r
++ return;\r
++ if (thread->nonmatched_authors == NULL)\r
++ thread->nonmatched_authors = thread->authors;\r
++ author_len = strlen(author);\r
++ authors_len = strlen(thread->authors);\r
++ if (author_len == authors_len) {\r
++ /* just one author */\r
++ thread->nonmatched_authors += author_len;\r
++ return;\r
++ }\r
++ currentauthor = strcasestr(thread->authors, author);\r
++ if (currentauthor == NULL)\r
++ return;\r
++ idx = currentauthor - thread->nonmatched_authors;\r
++ if (idx < 0) {\r
++ /* already among matched authors */\r
++ return;\r
++ }\r
++ if (thread->nonmatched_authors + author_len < thread->authors + authors_len) {\r
++ /* we have to make changes, so let's get a temp copy */\r
++ authorscopy = strdup(thread->authors);\r
++ if (authorscopy == NULL)\r
++ return;\r
++ /* nmstart is the offset into where the non-matched authors start */\r
++ nmstart = thread->nonmatched_authors - thread->authors;\r
++ /* copy this author and add the "| " - the if clause above tells us there's more */\r
++ strncpy(thread->nonmatched_authors,author,author_len);\r
++ strncpy(thread->nonmatched_authors+author_len,"| ",2);\r
++ thread->nonmatched_authors += author_len+2; \r
++ if (idx > 0) {\r
++ /* we are actually moving authors around, not just changing the separator\r
++ * first copy the authors that came BEFORE our author */\r
++ strncpy(thread->nonmatched_authors, authorscopy+nmstart, idx-2);\r
++ /* finally, if there are authors AFTER our author, copy those */\r
++ if(author_len+nmstart+idx < authors_len) {\r
++ strncpy(thread->nonmatched_authors + idx - 2,", ",2);\r
++ strncpy(thread->nonmatched_authors + idx, authorscopy+nmstart + idx + author_len + 2, \r
++ authors_len - (nmstart + idx + author_len + 2));\r
++ }\r
++ }\r
++ free(authorscopy);\r
++ } else {\r
++ thread->nonmatched_authors += author_len;\r
++ }\r
++ return;\r
++}\r
++\r
++/* clean up the uggly "Lastname, Firstname" format to be "Firstname Lastname" \r
++ */\r
++char *\r
++_thread_cleanup_author (notmuch_thread_t *thread,\r
++ const char *author)\r
++{\r
++ char *cleanauthor;\r
++ const char *comma;\r
++ int fname,lname;\r
++\r
++ cleanauthor = talloc_strdup(thread, author);\r
++ if (cleanauthor == NULL)\r
++ return NULL;\r
++ comma = strchr(author,',');\r
++ if (comma) {\r
++ lname = comma - author;\r
++ fname = strlen(author) - lname - 2;\r
++ strncpy(cleanauthor, comma + 2, fname);\r
++ *(cleanauthor+fname) = ' ';\r
++ strncpy(cleanauthor + fname + 1, author, lname);\r
++ *(cleanauthor+fname+1+lname) = '\0';\r
++ }\r
++ return cleanauthor;\r
+ }\r
+ \r
+ /* Add 'message' as a message that belongs to 'thread'.\r
+@@ -87,6 +175,7 @@ _thread_add_message (notmuch_thread_t *thread,\r
+ InternetAddressList *list;\r
+ InternetAddress *address;\r
+ const char *from, *author;\r
++ char *cleanauthor;\r
+ \r
+ _notmuch_message_list_add_message (thread->message_list,\r
+ talloc_steal (thread, message));\r
+@@ -107,7 +196,9 @@ _thread_add_message (notmuch_thread_t *thread,\r
+ mailbox = INTERNET_ADDRESS_MAILBOX (address);\r
+ author = internet_address_mailbox_get_addr (mailbox);\r
+ }\r
+- _thread_add_author (thread, author);\r
++ cleanauthor = _thread_cleanup_author (thread, author);\r
++ _thread_add_author (thread, cleanauthor );\r
++ notmuch_message_set_author (message, cleanauthor);\r
+ }\r
+ g_object_unref (G_OBJECT (list));\r
+ }\r
+@@ -150,6 +241,7 @@ _thread_add_matched_message (notmuch_thread_t *thread,\r
+ notmuch_message_set_flag (hashed_message,\r
+ NOTMUCH_MESSAGE_FLAG_MATCH, 1);\r
+ }\r
++ _thread_move_matched_author (thread,notmuch_message_get_author(hashed_message));\r
+ }\r
+ \r
+ static void\r
+@@ -251,6 +343,7 @@ _notmuch_thread_create (void *ctx,\r
+ thread->authors_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
+ free, NULL);\r
+ thread->authors = NULL;\r
++ thread->nonmatched_authors = NULL;\r
+ thread->tags = g_hash_table_new_full (g_str_hash, g_str_equal,\r
+ free, NULL);\r
+ \r
+\r
+\r
+-- \r
+Dirk Hohndel\r
+Intel Open Source Technology Center\r