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
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
35 X-BeenThere: notmuch@notmuchmail.org
\r
36 X-Mailman-Version: 2.1.12
\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
50 On Sun, 22 Nov 2009 05:04:56 +0100, Carl Worth <cworth@cworth.org> wrote:
\r
51 > Hi Michel, welcome to Notmuch!
\r
53 Thanks, and apologies for the accidental base64 encoding.
\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
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
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
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
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
82 > Right. We definitely don't want a strong mapping here.
\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
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
94 > That kind of thing is going to be "harder".
\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
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
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
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
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
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
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
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
138 notmuch-client.h | 10 ++++++
\r
139 notmuch-config.c | 33 +++++++++++++++++--
\r
141 +++++++++++++++++++++++++++++++++++++++++++++++------
\r
142 3 files changed, 124 insertions(+), 14 deletions(-)
\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
152 +enum storage_type { UNSET, NONE, MAILDIR };
\r
154 typedef void (*add_files_callback_t) (notmuch_message_t *message);
\r
157 int ignore_read_only_directories;
\r
158 int saw_read_only_directory;
\r
160 + enum storage_type storage_type;
\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
167 const char *other_email[],
\r
171 +notmuch_config_get_storage_type (notmuch_config_t *config);
\r
174 debugger_is_active (void);
\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
188 - " The only value supported here is 'path' which should be the
\r
190 + " The most important value here is 'path' which should be the
\r
192 " directory where your mail currently exists and to where mail will
\r
194 " delivered in the future. Files should be individual email
\r
196 " Notmuch will store its database within a sub-directory of the
\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
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
210 + enum storage_type storage_type;
\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
220 if (! g_key_file_load_from_file (config->key_file,
\r
222 @@ -257,7 +262,7 @@ notmuch_config_open (void *ctx,
\r
223 talloc_free (email);
\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
231 @@ -334,6 +339,28 @@ notmuch_config_get_database_path (notmuch_config_t
\r
233 return config->database_path;
\r
237 +notmuch_config_get_storage_type (notmuch_config_t * config)
\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
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
253 + return config->storage_type;
\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
269 -tag_inbox_and_unread (notmuch_message_t *message)
\r
270 +tag_as_inbox (notmuch_message_t *message)
\r
272 notmuch_message_add_tag (message, "inbox");
\r
276 +tag_as_unread (notmuch_message_t *message)
\r
278 notmuch_message_add_tag (message, "unread");
\r
283 +derive_tags_from_maildir_flags (notmuch_message_t *message, const char *
\r
286 + int seen = FALSE;
\r
287 + int end_of_flags = FALSE;
\r
288 + size_t l = strlen(path);
\r
290 + /* Non-experimental message flags start with this */
\r
291 + char * i = strstr(path, ":2,");
\r
295 + for (; i < (path + l) && !end_of_flags; i++) {
\r
297 + case 'F': /* flagged */
\r
298 + notmuch_message_add_tag (message, "flagged");
\r
300 + case 'R': /* the message has been replied to */
\r
301 + notmuch_message_add_tag (message, "replied");
\r
304 + notmuch_message_add_tag (message, "draft");
\r
306 + case 'S': /* Indicate a message has been read */
\r
307 + notmuch_message_add_tag (message, "seen");
\r
310 + case 'T': /* Indicates a message has been marked as trash */
\r
311 + notmuch_message_add_tag (message, "trashed");
\r
313 + case 'P': /* indicates a message has been forwarded */
\r
314 + notmuch_message_add_tag (message, "passed");
\r
317 + end_of_flags = TRUE;
\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
331 add_files_print_progress (add_files_state_t *state)
\r
333 @@ -104,6 +157,7 @@ static notmuch_status_t
\r
334 add_files_recursive (notmuch_database_t *notmuch,
\r
338 add_files_state_t *state)
\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
345 - if (state->ignore_read_only_directories &&
\r
346 - (st->st_mode & S_IWUSR) == 0)
\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
355 path_mtime = st->st_mtime;
\r
356 @@ -173,7 +225,7 @@ add_files_recursive (notmuch_database_t *notmuch,
\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
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
374 + tag_as_unread (message);
\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
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
385 + if (state->storage_type == MAILDIR) {
\r
386 + char * leaf = basename(next);
\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
393 + } else if (strcmp(leaf, "new") == 0) {
\r
394 + status = add_files_recursive (notmuch, next, st, TRUE, state);
\r
396 + /* Perhaps add in tags? */
\r
397 + status = add_files_recursive (notmuch, next, st, FALSE, state);
\r
400 + status = add_files_recursive (notmuch, next, st, TRUE, state);
\r
401 + if (status && ret == NOTMUCH_STATUS_SUCCESS)
\r
406 talloc_free (next);
\r
407 @@ -292,7 +364,7 @@ add_files (notmuch_database_t *notmuch,
\r
408 timer_is_active = TRUE;
\r
411 - status = add_files_recursive (notmuch, path, &st, state);
\r
412 + status = add_files_recursive (notmuch, path, &st, TRUE, state);
\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
422 gettimeofday (&add_files_state.tv_start, NULL);
\r
424 ret = add_files (notmuch, db_path, &add_files_state);
\r