[RFC] reordering and cleanup of thread authors
authorDirk Hohndel <hohndel@infradead.org>
Wed, 7 Apr 2010 05:52:28 +0000 (22:52 +1700)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:36:30 +0000 (09:36 -0800)
6f/398c9188318eaec8cef2b626d6ec993d79cba9 [new file with mode: 0644]

diff --git a/6f/398c9188318eaec8cef2b626d6ec993d79cba9 b/6f/398c9188318eaec8cef2b626d6ec993d79cba9
new file mode 100644 (file)
index 0000000..f76be60
--- /dev/null
@@ -0,0 +1,294 @@
+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