Re: How does notmuch track mails?
[notmuch-archives.git] / a5 / 927047658ff59ba92a76ec20946afcf3f7f668
1 Return-Path: <BATV+bbc4756b788e67be553a+2433+infradead.org+hohndel@bombadil.srs.infradead.org>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 294294196F2\r
6         for <notmuch@notmuchmail.org>; Wed, 21 Apr 2010 20:58:31 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -4.2\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-4.2 tagged_above=-999 required=5\r
12         tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3] autolearn=ham\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id LH20GX3chCfC for <notmuch@notmuchmail.org>;\r
16         Wed, 21 Apr 2010 20:58:29 -0700 (PDT)\r
17 Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34])\r
18         by olra.theworths.org (Postfix) with ESMTP id 70A3A431FC1\r
19         for <notmuch@notmuchmail.org>; Wed, 21 Apr 2010 20:58:29 -0700 (PDT)\r
20 Received: from localhost ([::1] helo=x200.gr8dns.org)\r
21         by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux))\r
22         id 1O4nYa-00036z-EV\r
23         for notmuch@notmuchmail.org; Thu, 22 Apr 2010 03:58:28 +0000\r
24 Received: by x200.gr8dns.org (Postfix, from userid 500)\r
25         id EF0B0C0212; Wed, 21 Apr 2010 20:58:27 -0700 (PDT)\r
26 From: Dirk Hohndel <hohndel@infradead.org>\r
27 To: notmuch <notmuch@notmuchmail.org>\r
28 Subject: [PATCH] Reordering of thread authors to list matching authors first\r
29 In-Reply-To: <m3aaswyw9t.fsf@x200.gr8dns.org>\r
30 References: <m31veru7vn.fsf@x200.gr8dns.org> <87zl1d5fc0.fsf@steelpick.2x.cz>\r
31         <m3zl1cfsb4.fsf@x200.gr8dns.org>\r
32         <87aatcysw8.fsf@wsheee.localdomain>\r
33         <m3wrwg6n9y.fsf@x200.gr8dns.org> <m3aaswyw9t.fsf@x200.gr8dns.org>\r
34 Date: Wed, 21 Apr 2010 20:58:27 -0700\r
35 Message-ID: <m38w8gyw7w.fsf@x200.gr8dns.org>\r
36 User-Agent: notmuch 0.2-52-ga28d2fe (Emacs 23.1.1/i386-redhat-linux-gnu)\r
37 MIME-Version: 1.0\r
38 Content-Type: text/plain; charset=us-ascii\r
39 X-SRS-Rewrite: SMTP reverse-path rewritten from <hohndel@infradead.org> by\r
40         bombadil.infradead.org See http://www.infradead.org/rpr.html\r
41 X-BeenThere: notmuch@notmuchmail.org\r
42 X-Mailman-Version: 2.1.13\r
43 Precedence: list\r
44 List-Id: "Use and development of the notmuch mail system."\r
45         <notmuch.notmuchmail.org>\r
46 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
47         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
48 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
49 List-Post: <mailto:notmuch@notmuchmail.org>\r
50 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
51 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
52         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
53 X-List-Received-Date: Thu, 22 Apr 2010 03:58:31 -0000\r
54 \r
55 \r
56 When displaying threads as result of a search it makes sense to list those\r
57 authors first who match the search. The matching authors are separated from the\r
58 non-matching ones with a '|' instead of a ','\r
59 \r
60 Imagine the default "+inbox" query. Those mails in the thread that\r
61 match the query are actually "new" (whatever that means). And some\r
62 people seem to think that it would be much better to see those author\r
63 names first. For example, imagine a long and drawn out thread that once\r
64 was started by me; you have long read the older part of the thread and\r
65 removed the inbox tag. Whenever a new email comes in on this thread,\r
66 prior to this patch the author column in the search display will first show\r
67 "Dirk Hohndel" - I think it should first show the actual author(s) of the new\r
68 mail(s).\r
69 \r
70 Signed-off-by: Dirk Hohndel <hohndel@infradead.org>\r
71 ---\r
72  lib/message.cc |   16 ++++++++++++\r
73  lib/notmuch.h  |   11 ++++++++\r
74  lib/thread.cc  |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
75  3 files changed, 101 insertions(+), 0 deletions(-)\r
76 \r
77 diff --git a/lib/message.cc b/lib/message.cc\r
78 index 721c9a6..ac0afd9 100644\r
79 --- a/lib/message.cc\r
80 +++ b/lib/message.cc\r
81 @@ -35,6 +35,7 @@ struct _notmuch_message {\r
82      char *thread_id;\r
83      char *in_reply_to;\r
84      char *filename;\r
85 +    char *author;\r
86      notmuch_message_file_t *message_file;\r
87      notmuch_message_list_t *replies;\r
88      unsigned long flags;\r
89 @@ -110,6 +111,7 @@ _notmuch_message_create (const void *talloc_owner,\r
90      message->in_reply_to = NULL;\r
91      message->filename = NULL;\r
92      message->message_file = NULL;\r
93 +    message->author = NULL;\r
94  \r
95      message->replies = _notmuch_message_list_create (message);\r
96      if (unlikely (message->replies == NULL)) {\r
97 @@ -533,6 +535,20 @@ notmuch_message_get_tags (notmuch_message_t *message)\r
98      return _notmuch_convert_tags(message, i, end);\r
99  }\r
100  \r
101 +const char *\r
102 +notmuch_message_get_author (notmuch_message_t *message)\r
103 +{\r
104 +    return message->author;\r
105 +}\r
106 +\r
107 +void\r
108 +notmuch_message_set_author (notmuch_message_t *message,\r
109 +                           const char *author)\r
110 +{\r
111 +    message->author = talloc_strdup(message, author);\r
112 +    return;\r
113 +}\r
114 +\r
115  void\r
116  _notmuch_message_set_date (notmuch_message_t *message,\r
117                            const char *date)\r
118 diff --git a/lib/notmuch.h b/lib/notmuch.h\r
119 index bae48a6..769f747 100644\r
120 --- a/lib/notmuch.h\r
121 +++ b/lib/notmuch.h\r
122 @@ -773,6 +773,17 @@ notmuch_message_set_flag (notmuch_message_t *message,\r
123  time_t\r
124  notmuch_message_get_date  (notmuch_message_t *message);\r
125  \r
126 +/* Set the author member of 'message' - this is the representation used\r
127 + * when displaying the message\r
128 + */\r
129 +void\r
130 +notmuch_message_set_author (notmuch_message_t *message, const char *author);\r
131 +\r
132 +/* Get the author member of 'message'\r
133 + */\r
134 +const char *\r
135 +notmuch_message_get_author (notmuch_message_t *message);\r
136 +\r
137  /* Get the value of the specified header from 'message'.\r
138   *\r
139   * The value will be read from the actual message file, not from the\r
140 diff --git a/lib/thread.cc b/lib/thread.cc\r
141 index e514bf8..baa0d7f 100644\r
142 --- a/lib/thread.cc\r
143 +++ b/lib/thread.cc\r
144 @@ -32,6 +32,7 @@ struct _notmuch_thread {\r
145      char *subject;\r
146      GHashTable *authors_hash;\r
147      char *authors;\r
148 +    char *nonmatched_authors;\r
149      GHashTable *tags;\r
150  \r
151      notmuch_message_list_t *message_list;\r
152 @@ -73,6 +74,76 @@ _thread_add_author (notmuch_thread_t *thread,\r
153         thread->authors = talloc_strdup (thread, author);\r
154  }\r
155  \r
156 +/*\r
157 + * move authors of matched messages in the thread to \r
158 + * the front of the authors list, but keep them in\r
159 + * existing order within their group\r
160 + */\r
161 +static void\r
162 +_thread_move_matched_author (notmuch_thread_t *thread,\r
163 +                            const char *author)\r
164 +{\r
165 +    char *authorscopy;\r
166 +    char *currentauthor;\r
167 +    char *lastpipe,*nextpipe;\r
168 +    int idx,nmstart,author_len,authors_len;\r
169 +\r
170 +    if (thread->authors == NULL || author == NULL)\r
171 +       return;\r
172 +    if (thread->nonmatched_authors == NULL)\r
173 +       thread->nonmatched_authors = thread->authors;\r
174 +    author_len = strlen(author);\r
175 +    authors_len = strlen(thread->authors);\r
176 +    if (author_len == authors_len) {\r
177 +       /* just one author */\r
178 +       thread->nonmatched_authors += author_len;\r
179 +       return;\r
180 +    }\r
181 +    currentauthor = strcasestr(thread->authors, author);\r
182 +    if (currentauthor == NULL)\r
183 +       return;\r
184 +    /* how far inside the nonmatched authors is our author? */\r
185 +    idx = currentauthor - thread->nonmatched_authors;\r
186 +    if (idx < 0) {\r
187 +       /* already among matched authors */\r
188 +       return;\r
189 +    }\r
190 +    /* are there any authors in the list after our author? */\r
191 +    if (thread->nonmatched_authors + author_len < thread->authors + authors_len) {\r
192 +       /* we have to make changes, so let's get a temp copy */\r
193 +       authorscopy = xstrdup(thread->authors);\r
194 +       /* nmstart is the offset into where the non-matched authors start */\r
195 +       nmstart = thread->nonmatched_authors - thread->authors;\r
196 +       /* copy this author and add the "| " - the if clause above tells us there's more */\r
197 +       strncpy(thread->nonmatched_authors,author,author_len);\r
198 +       strncpy(thread->nonmatched_authors+author_len,"| ",2);\r
199 +       thread->nonmatched_authors += author_len+2;     \r
200 +       if (idx > 0) {\r
201 +         /* we are actually moving authors around, not just changing the separator\r
202 +          * first copy the authors that came BEFORE our author */\r
203 +         strncpy(thread->nonmatched_authors, authorscopy+nmstart, idx-2);\r
204 +         /* finally, if there are authors AFTER our author, copy those */\r
205 +         if(author_len+nmstart+idx < authors_len) {\r
206 +           strncpy(thread->nonmatched_authors + idx - 2,", ",2);\r
207 +           strncpy(thread->nonmatched_authors + idx, authorscopy+nmstart + idx + author_len + 2, \r
208 +                   authors_len - (nmstart + idx + author_len + 2));\r
209 +         }\r
210 +       }\r
211 +       free(authorscopy);\r
212 +       /* finally let's make sure there's just one '|' in the authors string */\r
213 +       lastpipe = strchr(thread->authors,'|');\r
214 +       while (lastpipe) {\r
215 +           nextpipe = strchr(lastpipe+1,'|');\r
216 +           if (nextpipe)\r
217 +               *lastpipe = ',';\r
218 +           lastpipe = nextpipe;\r
219 +       }\r
220 +    } else {\r
221 +       thread->nonmatched_authors += author_len;\r
222 +    }\r
223 +    return;\r
224 +}\r
225 +\r
226  /* Add 'message' as a message that belongs to 'thread'.\r
227   *\r
228   * The 'thread' will talloc_steal the 'message' and hold onto a\r
229 @@ -108,6 +179,7 @@ _thread_add_message (notmuch_thread_t *thread,\r
230                 author = internet_address_mailbox_get_addr (mailbox);\r
231             }\r
232             _thread_add_author (thread, author);\r
233 +           notmuch_message_set_author (message, author);\r
234         }\r
235         g_object_unref (G_OBJECT (list));\r
236      }\r
237 @@ -162,6 +234,7 @@ _thread_add_matched_message (notmuch_thread_t *thread,\r
238         notmuch_message_set_flag (hashed_message,\r
239                                   NOTMUCH_MESSAGE_FLAG_MATCH, 1);\r
240      }\r
241 +    _thread_move_matched_author (thread,notmuch_message_get_author(hashed_message));\r
242  }\r
243  \r
244  static void\r
245 @@ -283,6 +356,7 @@ _notmuch_thread_create (void *ctx,\r
246      thread->authors_hash = g_hash_table_new_full (g_str_hash, g_str_equal,\r
247                                                   free, NULL);\r
248      thread->authors = NULL;\r
249 +    thread->nonmatched_authors = NULL;\r
250      thread->tags = g_hash_table_new_full (g_str_hash, g_str_equal,\r
251                                           free, NULL);\r
252  \r
253 -- \r
254 1.6.6.1\r
255 \r
256 \r
257 -- \r
258 Dirk Hohndel\r
259 Intel Open Source Technology Center\r