Re: [feature request] emacs: use `notmuch insert` for FCC
[notmuch-archives.git] / af / 5d63e5de6e76afe50466cb3bdee564d8ab4738
1 Return-Path: <michiel@michielbuddingh.net>\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 80165431FBC\r
6         for <notmuch@notmuchmail.org>; Sun, 22 Nov 2009 01:33:56 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 Received: from olra.theworths.org ([127.0.0.1])\r
9         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
10         with ESMTP id h+nbv20yqM7Y for <notmuch@notmuchmail.org>;\r
11         Sun, 22 Nov 2009 01:33:55 -0800 (PST)\r
12 Received: from aegir.org.uk (aegir.org.uk [87.238.170.13])\r
13         by olra.theworths.org (Postfix) with ESMTP id A34BB431FAE\r
14         for <notmuch@notmuchmail.org>; Sun, 22 Nov 2009 01:33:54 -0800 (PST)\r
15 Received: by aegir.org.uk (Postfix, from userid 80)\r
16         id B57832E033; Sun, 22 Nov 2009 10:33:53 +0100 (CET)\r
17 To: <notmuch@notmuchmail.org>\r
18 MIME-Version: 1.0\r
19 Date: Sun, 22 Nov 2009 10:33:53 +0100\r
20 From: Michiel Buddingh' <michiel@michielbuddingh.net>\r
21 In-Reply-To: <87d43b2oif.fsf@yoom.home.cworth.org>\r
22 References: <87fx8bygi7.fsf@linux.vnet.ibm.com>\r
23         <87bpiv4t9h.fsf@yoom.home.cworth.org>\r
24         <87y6lz39nd.fsf@yoom.home.cworth.org>\r
25         <20091121221207.GB17268@jukie.net>\r
26         <9cce5525b093b87fe74d427954ffad89@localhost>\r
27         <87d43b2oif.fsf@yoom.home.cworth.org>\r
28 Message-ID: <9bfdedddeab9c58cd45d8d448323d0fc@localhost>\r
29 X-Sender: michiel@michielbuddingh.net\r
30 User-Agent: RoundCube Webmail/0.1\r
31 Content-Transfer-Encoding: 8bit\r
32 Content-Type: text/plain; charset=UTF-8\r
33 Subject: Re: [notmuch] [PATCH] notmuch: Add Maildir directory name as tag\r
34  name for messages\r
35 X-BeenThere: notmuch@notmuchmail.org\r
36 X-Mailman-Version: 2.1.12\r
37 Precedence: list\r
38 List-Id: "Use and development of the notmuch mail system."\r
39         <notmuch.notmuchmail.org>\r
40 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
41         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
42 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
43 List-Post: <mailto:notmuch@notmuchmail.org>\r
44 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
45 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
46         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
47 X-List-Received-Date: Sun, 22 Nov 2009 09:33:56 -0000\r
48 \r
49 \r
50 On Sun, 22 Nov 2009 05:04:56 +0100, Carl Worth <cworth@cworth.org> wrote:\r
51 > Hi Michel, welcome to Notmuch!\r
52 \r
53 Thanks, and apologies for the accidental base64 encoding.\r
54 \r
55 First things first:\r
56 \r
57 >> In the mean time, I've made a smaller, hopefully more harmless \r
58 >> patch to let 'notmuch new' mark messages stored in a Maildir 'cur'\r
59 >> folder as 'read' rather than 'unread'.\r
60\r
61 > Can others who have more experience weigh in here? Will this do the\r
62 > right thing for you? Do mail clients wait to move things into "cur"\r
63 > after the user has actually read them, or is that just a place where\r
64 > they are moved when the MUA _receives_ them?\r
65 \r
66 You're absolutely right, and I'm a fool (because I _knew_ this, but\r
67 forgot).  Maildir stores flags (seen, replied, flagged, trashed,\r
68 passed) in file names.\r
69 \r
70 On the positive side, this allows us to map these flags onto tags,\r
71 at least for indexing (the patch at the bottom implements this), and,\r
72 if I can pry you away from your principles, later for modification\r
73 as well.\r
74 \r
75 >> Any attempt to match tags up to directories will eventually have \r
76 >> to deal with with the fact that tags can't be neatly mapped onto \r
77 >> them.  If I remove a directory-tag from a message, does this \r
78 >> mean the message is removed from that directory?  What if a \r
79 >> message has two directory-tags, does it mean it's present in both\r
80 >> directories?\r
81\r
82 > Right. We definitely don't want a strong mapping here.\r
83 \r
84 I propose that the maildir 'storage_type' could make an exception for\r
85 standard Maildir flags.  It'll take relatively little effort to\r
86 special-case the abovementioned flags, and it'd be a huge boon to\r
87 interoperability.\r
88 \r
89 >> At the same time, this kind of interoperability would be highly\r
90 >> desirable to those of us who access their mail using other  \r
91 >> clients (webmail, mobile phones, etc.) that expect hierarchical\r
92 >> ordering.\r
93\r
94 > That kind of thing is going to be "harder".\r
95\r
96 > So far we're trying to stick with the principle that notmuch itself\r
97 > doesn't mess with the data store.\r
98 \r
99 I respect your desire to stick to that principle.  But I also know \r
100 that purity and simplicity, generally speaking, are unattainable\r
101 luxuries for most applications that handle mail.\r
102 \r
103 > But then, we also want notmuch to be\r
104 > very scriptable, so someone might write a tool that uses notmuch search\r
105 > to export a set of hierarchical maildirs based on the tag names. (These\r
106 > could even just be populated with symlinks like mairix does.) So\r
107 > something like that could be really useful for integrating.\r
108 \r
109 That is a very interesting idea.  On the other hand, interoperability\r
110 with Maildir mail stores is unlikely to be a corner case.  The MTA is\r
111 probably going to deliver new mail to a Maildir, procmail understands it,\r
112 etc.  I'd feel more comfortable relegating this integration to a \r
113 scripted glue layer if I knew for certain such a glue layer would be\r
114 up to the task.\r
115  \r
116 > I'm very much of the opinion that the user shouldn't care at all about\r
117 > the storage of the actual mail files that notmuch indexes.\r
118 \r
119 The user certainly shouldn't, but I'm not sure that notmuch can remain\r
120 as agnostic about the actual storage of messages as planned.\r
121 \r
122 Another thing; notmuch currently indexes by message-id (or SHA-1 hash\r
123 if that is not present).  Maildir, on the other hand, uses file names\r
124 as stable (when stripped of the parts trailing the colon) unique \r
125 (knock on wood) identifiers.  A Maildir-aware notmuch could incorporate\r
126 this to be far more resistant to bulk mail moves done by other clients,\r
127 by using filename lookups to avoid accessing and parsing the mail \r
128 files themselves.\r
129 \r
130 I should re-iterate that I'm new to notmuch, and it's obvious that I'm\r
131 trying to beat it into becoming something it was never intended to be;\r
132 on the other hand, I'd like people to chime in on this.\r
133 \r
134 again via webmail,\r
135 Michiel Buddingh'\r
136 \r
137 ---\r
138  notmuch-client.h |   10 ++++++\r
139  notmuch-config.c |   33 +++++++++++++++++--\r
140  notmuch-new.c    |   95\r
141 +++++++++++++++++++++++++++++++++++++++++++++++------\r
142  3 files changed, 124 insertions(+), 14 deletions(-)\r
143 \r
144 diff --git a/notmuch-client.h b/notmuch-client.h\r
145 index ea77686..c39be06 100644\r
146 --- a/notmuch-client.h\r
147 +++ b/notmuch-client.h\r
148 @@ -69,12 +69,16 @@\r
149  #define STRNCMP_LITERAL(var, literal) \\r
150      strncmp ((var), (literal), sizeof (literal) - 1)\r
151  \r
152 +enum storage_type { UNSET, NONE, MAILDIR };\r
153 +\r
154  typedef void (*add_files_callback_t) (notmuch_message_t *message);\r
155  \r
156  typedef struct {\r
157      int ignore_read_only_directories;\r
158      int saw_read_only_directory;\r
159  \r
160 +    enum storage_type storage_type;\r
161 +\r
162      int total_files;\r
163      int processed_files;\r
164      int added_messages;\r
165 @@ -179,7 +183,13 @@ notmuch_config_set_user_other_email (notmuch_config_t\r
166 *config,\r
167                                      const char *other_email[],\r
168                                      size_t length);\r
169  \r
170 +enum storage_type\r
171 +notmuch_config_get_storage_type (notmuch_config_t *config);\r
172 +\r
173  notmuch_bool_t\r
174  debugger_is_active (void);\r
175  \r
176 +\r
177 +\r
178 +\r
179  #endif\r
180 diff --git a/notmuch-config.c b/notmuch-config.c\r
181 index aaa0372..13bd341 100644\r
182 --- a/notmuch-config.c\r
183 +++ b/notmuch-config.c\r
184 @@ -31,11 +31,13 @@ static const char toplevel_config_comment[] =\r
185  static const char database_config_comment[] =\r
186      " Database configuration\n"\r
187      "\n"\r
188 -    " The only value supported here is 'path' which should be the\r
189 top-level\n"\r
190 +    " The most important value here is 'path' which should be the\r
191 top-level\n"\r
192      " directory where your mail currently exists and to where mail will\r
193 be\n"\r
194      " delivered in the future. Files should be individual email\r
195 messages.\n"\r
196      " Notmuch will store its database within a sub-directory of the\r
197 path\n"\r
198 -    " configured here named \".notmuch\".\n";\r
199 +    " configured here named \".notmuch\".\n"\r
200 +    " The other value is 'storage_type', which can currently be set to\n"\r
201 +    " 'maildir' or 'none'.\n";\r
202  \r
203  static const char user_config_comment[] =\r
204      " User configuration\n"\r
205 @@ -62,6 +64,8 @@ struct _notmuch_config {\r
206      char *user_primary_email;\r
207      char **user_other_email;\r
208      size_t user_other_email_length;\r
209 +\r
210 +    enum storage_type storage_type;\r
211  };\r
212  \r
213  static int\r
214 @@ -193,6 +197,7 @@ notmuch_config_open (void *ctx,\r
215      config->user_primary_email = NULL;\r
216      config->user_other_email = NULL;\r
217      config->user_other_email_length = 0;\r
218 +    config->storage_type = UNSET;\r
219  \r
220      if (! g_key_file_load_from_file (config->key_file,\r
221                                      config->filename,\r
222 @@ -257,7 +262,7 @@ notmuch_config_open (void *ctx,\r
223             talloc_free (email);\r
224         }\r
225      }\r
226 -\r
227 +    \r
228      /* When we create a new configuration file here, we  add some\r
229       * comments to help the user understand what can be done. */\r
230      if (is_new) {\r
231 @@ -334,6 +339,28 @@ notmuch_config_get_database_path (notmuch_config_t\r
232 *config)\r
233      return config->database_path;\r
234  }\r
235  \r
236 +enum storage_type\r
237 +notmuch_config_get_storage_type (notmuch_config_t * config)\r
238 +{\r
239 +    char * type;\r
240 +\r
241 +    if (config->storage_type == UNSET) {\r
242 +       type = g_key_file_get_string (config->key_file,\r
243 +                                     "database", "storage_type", NULL);\r
244 +       if (type) {\r
245 +           if (strcasecmp(type, "maildir") == 0) {\r
246 +               config->storage_type = MAILDIR;\r
247 +           } else if (strcasecmp(type, "none") == 0) {\r
248 +               config->storage_type = NONE;\r
249 +           }\r
250 +       }\r
251 +    }\r
252 +\r
253 +    return config->storage_type;\r
254 +}\r
255 +\r
256 +\r
257 +\r
258  void\r
259  notmuch_config_set_database_path (notmuch_config_t *config,\r
260                                   const char *database_path)\r
261 diff --git a/notmuch-new.c b/notmuch-new.c\r
262 index 0dd2784..0918774 100644\r
263 --- a/notmuch-new.c\r
264 +++ b/notmuch-new.c\r
265 @@ -41,12 +41,65 @@ handle_sigint (unused (int sig))\r
266  }\r
267  \r
268  static void\r
269 -tag_inbox_and_unread (notmuch_message_t *message)\r
270 +tag_as_inbox (notmuch_message_t *message)\r
271  {\r
272      notmuch_message_add_tag (message, "inbox");\r
273 +}\r
274 +\r
275 +static void\r
276 +tag_as_unread (notmuch_message_t *message)\r
277 +{\r
278      notmuch_message_add_tag (message, "unread");\r
279  }\r
280  \r
281 +\r
282 +static void\r
283 +derive_tags_from_maildir_flags (notmuch_message_t *message, const char *\r
284 path) \r
285 +{\r
286 +    int seen = FALSE;\r
287 +    int end_of_flags = FALSE;\r
288 +    size_t l = strlen(path);\r
289 +\r
290 +    /* Non-experimental message flags start with this */\r
291 +    char * i = strstr(path, ":2,");\r
292 +    if (i != NULL) {\r
293 +\r
294 +       i += 3;\r
295 +       for (; i < (path + l) && !end_of_flags; i++) {\r
296 +           switch (*i) {\r
297 +           case 'F': /* flagged */\r
298 +               notmuch_message_add_tag (message, "flagged");\r
299 +               break;\r
300 +           case 'R': /* the message has been replied to */\r
301 +               notmuch_message_add_tag (message, "replied");\r
302 +               break;\r
303 +           case 'D': \r
304 +               notmuch_message_add_tag (message, "draft");\r
305 +               break;\r
306 +           case 'S': /* Indicate a message has been read */\r
307 +               notmuch_message_add_tag (message, "seen");\r
308 +               seen = TRUE;\r
309 +               break;\r
310 +           case 'T': /* Indicates a message has been marked as trash */\r
311 +               notmuch_message_add_tag (message, "trashed");\r
312 +               break;\r
313 +           case 'P': /* indicates a message has been forwarded */\r
314 +               notmuch_message_add_tag (message, "passed");\r
315 +               break;\r
316 +           default:\r
317 +               end_of_flags = TRUE;\r
318 +               break;\r
319 +           }\r
320 +       }\r
321 +    }\r
322 +    \r
323 +    if (i == NULL || !seen) { \r
324 +       /* mark messages without any flags, or the seen flag as 'unseen' */\r
325 +       notmuch_message_add_tag (message, "unseen");\r
326 +    }\r
327 +}\r
328 +\r
329 +\r
330  static void\r
331  add_files_print_progress (add_files_state_t *state)\r
332  {\r
333 @@ -104,6 +157,7 @@ static notmuch_status_t\r
334  add_files_recursive (notmuch_database_t *notmuch,\r
335                      const char *path,\r
336                      struct stat *st,\r
337 +                    int scan_files,\r
338                      add_files_state_t *state)\r
339  {\r
340      DIR *dir = NULL;\r
341 @@ -119,11 +173,9 @@ add_files_recursive (notmuch_database_t *notmuch,\r
342       * directory, (with this being a clear clue from the user to\r
343       * Notmuch that new mail won't be arriving there and we need not\r
344       * look. */\r
345 -    if (state->ignore_read_only_directories &&\r
346 -       (st->st_mode & S_IWUSR) == 0)\r
347 -    {\r
348 +    if (((st->st_mode & S_IWUSR) == 0) &&\r
349 (state->ignore_read_only_directories)) {\r
350         state->saw_read_only_directory = TRUE;\r
351 -       goto DONE;\r
352 +       goto DONE;          \r
353      }\r
354  \r
355      path_mtime = st->st_mtime;\r
356 @@ -173,7 +225,7 @@ add_files_recursive (notmuch_database_t *notmuch,\r
357             continue;\r
358         }\r
359  \r
360 -       if (S_ISREG (st->st_mode)) {\r
361 +       if (S_ISREG (st->st_mode) && scan_files) {\r
362             /* If the file hasn't been modified since the last\r
363              * add_files, then we need not look at it. */\r
364             if (path_dbtime == 0 || st->st_mtime > path_dbtime) {\r
365 @@ -184,7 +236,11 @@ add_files_recursive (notmuch_database_t *notmuch,\r
366                     /* success */\r
367                     case NOTMUCH_STATUS_SUCCESS:\r
368                         state->added_messages++;\r
369 -                       tag_inbox_and_unread (message);\r
370 +                       tag_as_inbox (message);\r
371 +                       if (state->storage_type == MAILDIR)\r
372 +                           derive_tags_from_maildir_flags (message, next);\r
373 +                       else \r
374 +                           tag_as_unread (message);\r
375                         break;\r
376                     /* Non-fatal issues (go on to next file) */\r
377                     case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:\r
378 @@ -223,9 +279,25 @@ add_files_recursive (notmuch_database_t *notmuch,\r
379                 }\r
380             }\r
381         } else if (S_ISDIR (st->st_mode)) {\r
382 -           status = add_files_recursive (notmuch, next, st, state);\r
383 -           if (status && ret == NOTMUCH_STATUS_SUCCESS)\r
384 -               ret = status;\r
385 +           if (state->storage_type == MAILDIR) {\r
386 +               char * leaf = basename(next);\r
387 +               \r
388 +               if (strcmp(leaf, "cur") == 0) {\r
389 +                   status = add_files_recursive (notmuch, next, st, TRUE, state);\r
390 +               } else if (strcmp(leaf, "tmp") == 0) {\r
391 +                   /* respect Maildir specification and don't touch files in tmp */\r
392 +                   continue;\r
393 +               } else if (strcmp(leaf, "new") == 0) {\r
394 +                   status = add_files_recursive (notmuch, next, st, TRUE, state);\r
395 +               } else {\r
396 +                   /* Perhaps add in tags? */\r
397 +                   status = add_files_recursive (notmuch, next, st, FALSE, state);\r
398 +               }\r
399 +           } else {\r
400 +               status = add_files_recursive (notmuch, next, st, TRUE, state);\r
401 +               if (status && ret == NOTMUCH_STATUS_SUCCESS)\r
402 +                   ret = status;\r
403 +           }\r
404         }\r
405  \r
406         talloc_free (next);\r
407 @@ -292,7 +364,7 @@ add_files (notmuch_database_t *notmuch,\r
408         timer_is_active = TRUE;\r
409      }\r
410  \r
411 -    status = add_files_recursive (notmuch, path, &st, state);\r
412 +    status = add_files_recursive (notmuch, path, &st, TRUE, state);\r
413  \r
414      /* Now stop the timer. */\r
415      if (timer_is_active) {\r
416 @@ -437,6 +509,7 @@ notmuch_new_command (void *ctx,\r
417      add_files_state.saw_read_only_directory = FALSE;\r
418      add_files_state.processed_files = 0;\r
419      add_files_state.added_messages = 0;\r
420 +    add_files_state.storage_type = notmuch_config_get_storage_type\r
421 (config);\r
422      gettimeofday (&add_files_state.tv_start, NULL);\r
423  \r
424      ret = add_files (notmuch, db_path, &add_files_state);\r
425 -- \r
426 1.6.5.3\r