Reply code with TEXT/PLAIN
I am not certain if this is a bug or a request to work around broken mailers. I tried replying to a message today (with recent git) and got an empty message. I looked at the json output for reply and it contains the message but the content type is TEXT/PLAIN rather than text/plain. This seems to mean it doesn't match in notmuch-match-content-type (notmuch-lib.el) called from notmuch-mua-get-quotable-parts (in notmuch-mua.el); and so does not get included. Making the match case-insensitive `fixed' the problem. I don't know whether content-types are allowed to be upper-case but I seem to have several mails where they are. I am also not sure whether the correct fix is in the emacs code, or in the cli reply format (i.e. perhaps the reply format should lower-case the content-type). Best wishes Mark PS Sorry Adam for the duplicate: I sent from a wrong address (my fault this time)!
[BUG/PATCH 2/2] emacs: Fix replying from alternate addresses
The bug was that notmuch-mua-mail used `mail-header` to check whether it was passed a "From" header. The implementation of `mail-header` must try to compare symbols instead of strings when looking for headers, as it was returning nil when a From header was present. This is probably because the mail functions construct headers as alists with symbols for the header names, while our code uses strings for the header names. Since we don't use `mail-header` anywhere else, and `message-mail` is perfectly happy to accept string header names, the fix is just to use `assoc` to look for the From header, so that the strings get compared properly. --- emacs/notmuch-mua.el |4 ++-- test/emacs |1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index 6aae3a0..9805d79 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -187,7 +187,7 @@ OTHER-ARGS are passed through to `message-mail'." (when (not (string= "" user-agent)) (push (cons "User-Agent" user-agent) other-headers - (unless (mail-header 'From other-headers) + (unless (assoc "From" other-headers) (push (cons "From" (concat (notmuch-user-name) " <" (notmuch-user-primary-email) ">")) other-headers)) @@ -250,7 +250,7 @@ the From: address first." (interactive "P") (let ((other-headers (when (or prompt-for-sender notmuch-always-prompt-for-sender) - (list (cons 'From (notmuch-mua-prompt-for-sender)) + (list (cons "From" (notmuch-mua-prompt-for-sender)) (notmuch-mua-mail nil nil other-headers))) (defun notmuch-mua-new-forward-message (&optional prompt-for-sender) diff --git a/test/emacs b/test/emacs index fa5d706..08db1ee 100755 --- a/test/emacs +++ b/test/emacs @@ -275,7 +275,6 @@ EOF test_expect_equal_file OUTPUT EXPECTED test_begin_subtest "Reply from alternate address within emacs" -test_subtest_known_broken add_message '[from]="Sender "' \ [to]=test_suite_other at notmuchmail.org \ [subject]=notmuch-reply-test \ -- 1.7.5.4
[BUG/PATCH 1/2] test: Tests for reply from alternate addresses in emacs
Since the recent reply changes were pushed, there has been a bug that causes emacs to always reply from the primary address, even if the JSON or default CLI reply output uses an alternate address. This adds two tests to the emacs test library based on the two "Reply form..." tests in the reply test library. One is currently marked broken. --- test/emacs | 52 1 files changed, 52 insertions(+), 0 deletions(-) diff --git a/test/emacs b/test/emacs index 8a28705..fa5d706 100755 --- a/test/emacs +++ b/test/emacs @@ -274,6 +274,58 @@ Notmuch Test Suite writes: EOF test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest "Reply from alternate address within emacs" +test_subtest_known_broken +add_message '[from]="Sender "' \ +[to]=test_suite_other at notmuchmail.org \ +[subject]=notmuch-reply-test \ + '[date]="Tue, 05 Jan 2010 15:43:56 -"' \ + '[body]="reply from alternate address"' + +test_emacs "(notmuch-search \"id:\\\"${gen_msg_id}\\\"\") + (notmuch-test-wait) + (notmuch-search-reply-to-thread) + (test-output)" +sed -i -e 's/^In-Reply-To: <.*>$/In-Reply-To: /' OUTPUT +catreply from alternate address +EOF +test_expect_equal_file OUTPUT EXPECTED + +test_begin_subtest "Reply from address in named group list within emacs" +add_message '[from]="Sender "' \ +'[to]=group:test_suite at notmuchmail.org,someone at example.com\;' \ + [cc]=test_suite_other at notmuchmail.org \ + [subject]=notmuch-reply-test \ +'[date]="Tue, 05 Jan 2010 15:43:56 -"' \ +'[body]="Reply from address in named group list"' + +test_emacs "(notmuch-search \"id:\\\"${gen_msg_id}\\\"\") + (notmuch-test-wait) + (notmuch-search-reply-to-thread) + (test-output)" +sed -i -e 's/^In-Reply-To: <.*>$/In-Reply-To: /' OUTPUT +cat Reply from address in named group list +EOF +test_expect_equal_file OUTPUT EXPECTED + test_begin_subtest "Reply within emacs to a multipart/mixed message" test_emacs '(notmuch-show "id:20091118002059.067214ed at hikari") (notmuch-show-reply) -- 1.7.5.4
[BUG/PATCH 0/2] Replying from other addresses in emacs
Hi everyone, This patch series adds a test for and fixes a bug that Dmitry pointed out on IRC yesterday: When replying to mail sent to an other_address, the CLI correctly sets the From header to the address that received the message. This works correctly in the default format and the JSON format. However, emacs was ignoring the provided From header and inserting the primary address, due to an incompatibility between how we construct the header list and how the `mail-header` function from the message library looks up header values in the list. People with other_addresses who are using the latest reply changes should probably apply this patch right away. Without it, you might end up replying to messages from the wrong address. Adam Wolfe Gordon (2): test: Tests for reply from alternate addresses in emacs emacs: Fix replying from alternate addresses emacs/notmuch-mua.el |4 +- test/emacs | 51 ++ 2 files changed, 53 insertions(+), 2 deletions(-) -- 1.7.5.4
Reply code with TEXT/PLAIN
Hi Mark, On Sat, Mar 24, 2012 at 15:49, Mark Walters wrote: > I am not certain if this is a bug or a request to work around broken > mailers. I tried replying to a message today (with recent git) and got > an empty message. I looked at the json output for reply and it contains > the message but the content type is TEXT/PLAIN rather than > text/plain. > > This seems to mean it doesn't match in notmuch-match-content-type > (notmuch-lib.el) called from notmuch-mua-get-quotable-parts (in > notmuch-mua.el); and so does not get included. > > Making the match case-insensitive `fixed' the problem. > > I don't know whether content-types are allowed ?to be upper-case but I > seem to have several mails where they are. I am also not sure whether > the correct fix is in the emacs code, or in the cli reply format > (i.e. perhaps the reply format should lower-case the content-type). A bit of Googling indicates that MIME types should be case insensitive (i.e. TEXT/PLAIN should match text/plain). Given this, I think it makes sense to change the emacs function regardless of whether it makes sense for the CLI to output them in lower-case. notmuch-match-content-type was put in notmuch-lib.el instead of in notmuch-mua.el because it was thought that it might become useful elsewhere later, so having it compare mime types correctly ensures that future uses don't need to sanitize input to it. Since you've already made the change for yourself, do you want to send a patch? Cheers.
[PATCH 3/3] cli: refactor "notmuch restore" message tagging into a separate function
Refactor to make tagging code easier to reuse in the future. No functional changes. Signed-off-by: Jani Nikula --- notmuch-client.h |5 +++ notmuch-restore.c | 73 ++- notmuch-tag.c | 75 + 3 files changed, 83 insertions(+), 70 deletions(-) diff --git a/notmuch-client.h b/notmuch-client.h index fa04fa2..7e3deee 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -203,6 +203,11 @@ json_quote_chararray (const void *ctx, const char *str, const size_t len); char * json_quote_str (const void *ctx, const char *str); +int +tag_message (void *ctx, notmuch_database_t *notmuch, const char *message_id, +char *file_tags, notmuch_bool_t remove_all, +notmuch_bool_t synchronize_flags); + /* notmuch-config.c */ typedef struct _notmuch_config notmuch_config_t; diff --git a/notmuch-restore.c b/notmuch-restore.c index 87d9772..bd6b884 100644 --- a/notmuch-restore.c +++ b/notmuch-restore.c @@ -88,11 +88,7 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[]) while ((line_len = getline (&line, &line_size, input)) != -1) { regmatch_t match[3]; - char *message_id, *file_tags, *tag, *next; - notmuch_message_t *message = NULL; - notmuch_status_t status; - notmuch_tags_t *db_tags; - char *db_tags_str; + char *message_id, *file_tags; chomp_newline (line); @@ -109,72 +105,9 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[]) file_tags = xstrndup (line + match[2].rm_so, match[2].rm_eo - match[2].rm_so); - status = notmuch_database_find_message (notmuch, message_id, &message); - if (status || message == NULL) { - fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n", -message ? "" : "missing ", message_id); - if (status) - fprintf (stderr, "%s\n", -notmuch_status_to_string(status)); - goto NEXT_LINE; - } - - /* In order to detect missing messages, this check/optimization is -* intentionally done *after* first finding the message. */ - if (accumulate && (file_tags == NULL || *file_tags == '\0')) - { - goto NEXT_LINE; - } - - db_tags_str = NULL; - for (db_tags = notmuch_message_get_tags (message); -notmuch_tags_valid (db_tags); -notmuch_tags_move_to_next (db_tags)) - { - const char *tag = notmuch_tags_get (db_tags); - - if (db_tags_str) - db_tags_str = talloc_asprintf_append (db_tags_str, " %s", tag); - else - db_tags_str = talloc_strdup (message, tag); - } - - if (((file_tags == NULL || *file_tags == '\0') && -(db_tags_str == NULL || *db_tags_str == '\0')) || - (file_tags && db_tags_str && strcmp (file_tags, db_tags_str) == 0)) - { - goto NEXT_LINE; - } - - notmuch_message_freeze (message); - - if (!accumulate) - notmuch_message_remove_all_tags (message); - - next = file_tags; - while (next) { - tag = strsep (&next, " "); - if (*tag == '\0') - continue; - status = notmuch_message_add_tag (message, tag); - if (status) { - fprintf (stderr, -"Error applying tag %s to message %s:\n", -tag, message_id); - fprintf (stderr, "%s\n", -notmuch_status_to_string (status)); - } - } - - notmuch_message_thaw (message); - - if (synchronize_flags) - notmuch_message_tags_to_maildir_flags (message); + tag_message (ctx, notmuch, message_id, file_tags, !accumulate, +synchronize_flags); - NEXT_LINE: - if (message) - notmuch_message_destroy (message); - message = NULL; free (message_id); free (file_tags); } diff --git a/notmuch-tag.c b/notmuch-tag.c index c4e3f9d..3aeb878 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -161,6 +161,81 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, } int +tag_message (void *ctx, notmuch_database_t *notmuch, const char *message_id, +char *file_tags, notmuch_bool_t remove_all, +notmuch_bool_t synchronize_flags) +{ +notmuch_status_t status; +notmuch_tags_t *db_tags; +char *db_tags_str; +notmuch_message_t *message = NULL; +const char *tag; +char *next; +int ret = 0; + +status = notmuch_database_find_message (notmuch, message_id, &message); +if (status || message == NULL) { + fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n", +message ? "" : "missing ", message_id); + if (status) + fprintf (st
[PATCH 2/3] cli: refactor "notmuch tag" query tagging into a separate function
Refactor to make tagging code easier to reuse in the future. No functional changes. Signed-off-by: Jani Nikula --- notmuch-tag.c | 101 - 1 files changed, 57 insertions(+), 44 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 98b2126..c4e3f9d 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -106,6 +106,60 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, return query_string; } +static int +tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, + tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags) +{ +notmuch_query_t *query; +notmuch_messages_t *messages; +notmuch_message_t *message; +int i; + +/* Optimize the query so it excludes messages that already have + * the specified set of tags. */ +query_string = _optimize_tag_query (ctx, query_string, tag_ops); +if (query_string == NULL) { + fprintf (stderr, "Out of memory.\n"); + return 1; +} + +query = notmuch_query_create (notmuch, query_string); +if (query == NULL) { + fprintf (stderr, "Out of memory.\n"); + return 1; +} + +/* tagging is not interested in any special sort order */ +notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); + +for (messages = notmuch_query_search_messages (query); +notmuch_messages_valid (messages) && !interrupted; +notmuch_messages_move_to_next (messages)) +{ + message = notmuch_messages_get (messages); + + notmuch_message_freeze (message); + + for (i = 0; tag_ops[i].tag; i++) { + if (tag_ops[i].remove) + notmuch_message_remove_tag (message, tag_ops[i].tag); + else + notmuch_message_add_tag (message, tag_ops[i].tag); + } + + notmuch_message_thaw (message); + + if (synchronize_flags) + notmuch_message_tags_to_maildir_flags (message); + + notmuch_message_destroy (message); +} + +notmuch_query_destroy (query); + +return interrupted; +} + int notmuch_tag_command (void *ctx, int argc, char *argv[]) { @@ -114,12 +168,10 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) char *query_string; notmuch_config_t *config; notmuch_database_t *notmuch; -notmuch_query_t *query; -notmuch_messages_t *messages; -notmuch_message_t *message; struct sigaction action; notmuch_bool_t synchronize_flags; int i; +int ret; /* Setup our handler for SIGINT */ memset (&action, 0, sizeof (struct sigaction)); @@ -167,14 +219,6 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) return 1; } -/* Optimize the query so it excludes messages that already have - * the specified set of tags. */ -query_string = _optimize_tag_query (ctx, query_string, tag_ops); -if (query_string == NULL) { - fprintf (stderr, "Out of memory.\n"); - return 1; -} - config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) return 1; @@ -186,40 +230,9 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config); -query = notmuch_query_create (notmuch, query_string); -if (query == NULL) { - fprintf (stderr, "Out of memory.\n"); - return 1; -} - -/* tagging is not interested in any special sort order */ -notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); +ret = tag_query (ctx, notmuch, query_string, tag_ops, synchronize_flags); -for (messages = notmuch_query_search_messages (query); -notmuch_messages_valid (messages) && !interrupted; -notmuch_messages_move_to_next (messages)) -{ - message = notmuch_messages_get (messages); - - notmuch_message_freeze (message); - - for (i = 0; tag_ops[i].tag; i++) { - if (tag_ops[i].remove) - notmuch_message_remove_tag (message, tag_ops[i].tag); - else - notmuch_message_add_tag (message, tag_ops[i].tag); - } - - notmuch_message_thaw (message); - - if (synchronize_flags) - notmuch_message_tags_to_maildir_flags (message); - - notmuch_message_destroy (message); -} - -notmuch_query_destroy (query); notmuch_database_close (notmuch); -return interrupted; +return ret; } -- 1.7.5.4
[PATCH 1/3] cli: refactor "notmuch tag" data structures for tagging operations
To simplify code, keep all tagging operations in a single array instead of separate add and remove arrays. Apply tag changes in the order specified on the command line, instead of first removing and then adding the tags. This results in a minor functional change: If a tag is both added and removed, the last specified operation is now used. Previously the tag was always added. Signed-off-by: Jani Nikula --- notmuch-tag.c | 80 +--- 1 files changed, 36 insertions(+), 44 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 36b9b09..98b2126 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -53,10 +53,14 @@ _escape_tag (char *buf, const char *tag) return buf; } +typedef struct { +const char *tag; +notmuch_bool_t remove; +} tag_operation_t; + static char * -_optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], -int *add_tags, int add_tags_count, -int *remove_tags, int remove_tags_count) +_optimize_tag_query (void *ctx, const char *orig_query_string, +const tag_operation_t *tag_ops) { /* This is subtler than it looks. Xapian ignores the '-' operator * at the beginning both queries and parenthesized groups and, @@ -74,12 +78,9 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], /* Allocate a buffer for escaping tags. This is large enough to * hold a fully escaped tag with every character doubled plus * enclosing quotes and a NUL. */ -for (i = 0; i < add_tags_count; i++) - if (strlen (argv[add_tags[i]] + 1) > max_tag_len) - max_tag_len = strlen (argv[add_tags[i]] + 1); -for (i = 0; i < remove_tags_count; i++) - if (strlen (argv[remove_tags[i]] + 1) > max_tag_len) - max_tag_len = strlen (argv[remove_tags[i]] + 1); +for (i = 0; tag_ops[i].tag; i++) + if (strlen (tag_ops[i].tag) > max_tag_len) + max_tag_len = strlen (tag_ops[i].tag); escaped = talloc_array(ctx, char, max_tag_len * 2 + 3); if (!escaped) return NULL; @@ -90,16 +91,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], else query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string); -for (i = 0; i < add_tags_count && query_string; i++) { - query_string = talloc_asprintf_append_buffer ( - query_string, "%snot tag:%s", join, - _escape_tag (escaped, argv[add_tags[i]] + 1)); - join = " or "; -} -for (i = 0; i < remove_tags_count && query_string; i++) { +for (i = 0; tag_ops[i].tag && query_string; i++) { query_string = talloc_asprintf_append_buffer ( - query_string, "%stag:%s", join, - _escape_tag (escaped, argv[remove_tags[i]] + 1)); + query_string, "%s%stag:%s", join, + tag_ops[i].remove ? "" : "not ", + _escape_tag (escaped, tag_ops[i].tag)); join = " or "; } @@ -113,9 +109,8 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], int notmuch_tag_command (void *ctx, int argc, char *argv[]) { -int *add_tags, *remove_tags; -int add_tags_count = 0; -int remove_tags_count = 0; +tag_operation_t *tag_ops; +int tag_ops_count = 0; char *query_string; notmuch_config_t *config; notmuch_database_t *notmuch; @@ -133,35 +128,34 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) action.sa_flags = SA_RESTART; sigaction (SIGINT, &action, NULL); -add_tags = talloc_size (ctx, argc * sizeof (int)); -if (add_tags == NULL) { - fprintf (stderr, "Out of memory.\n"); - return 1; -} +argc--; argv++; /* skip subcommand argument */ -remove_tags = talloc_size (ctx, argc * sizeof (int)); -if (remove_tags == NULL) { +/* Array of tagging operations (add or remove), terminated with an + * empty element. */ +tag_ops = talloc_array (ctx, tag_operation_t, argc + 1); +if (tag_ops == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } -argc--; argv++; /* skip subcommand argument */ - for (i = 0; i < argc; i++) { if (strcmp (argv[i], "--") == 0) { i++; break; } - if (argv[i][0] == '+') { - add_tags[add_tags_count++] = i; - } else if (argv[i][0] == '-') { - remove_tags[remove_tags_count++] = i; + if (argv[i][0] == '+' || argv[i][0] == '-') { + tag_ops[tag_ops_count++] = (tag_operation_t) { + .tag = argv[i] + 1, + .remove = argv[i][0] == '-', + }; } else { break; } } -if (add_tags_count == 0 && remove_tags_count == 0) { +tag_ops[tag_ops_count].tag = NULL; + +if (tag_ops_count == 0) { fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");
[PATCH 0/3] cli: notmuch tag/restore refactoring
Hi, here's some refactoring of notmuch tag/restore with mostly non-functional changes, in preparation of later, more interesting changes to dump/restore/tag. BR, Jani. Jani Nikula (3): cli: refactor "notmuch tag" data structures for tagging operations cli: refactor "notmuch tag" query tagging into a separate function cli: refactor "notmuch restore" message tagging into a separate function notmuch-client.h |5 + notmuch-restore.c | 73 +--- notmuch-tag.c | 242 +++-- 3 files changed, 169 insertions(+), 151 deletions(-) -- 1.7.5.4
[PATCH] emacs: content-type comparison should be case insensitive.
The function notmuch-match-content-type was comparing content types case sensitively. Fix it so it tests case insensitively. This fixes a bug where emacs would not include any body when replying to a message with content-type TEXT/PLAIN. --- emacs/notmuch-lib.el |5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el index c146748..a754de7 100644 --- a/emacs/notmuch-lib.el +++ b/emacs/notmuch-lib.el @@ -185,8 +185,9 @@ the user hasn't set this variable with the old or new value." (st2 (notmuch-split-content-type t2))) (if (or (string= (cadr st1) "*") (string= (cadr st2) "*")) - (string= (car st1) (car st2)) - (string= t1 t2 + ;; Comparison of content types should be case insensitive. + (string= (downcase (car st1)) (downcase (car st2))) + (string= (downcase t1) (downcase t2) (defvar notmuch-multipart/alternative-discouraged '( -- 1.7.9.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[BUG/PATCH 1/2] test: Tests for reply from alternate addresses in emacs
Since the recent reply changes were pushed, there has been a bug that causes emacs to always reply from the primary address, even if the JSON or default CLI reply output uses an alternate address. This adds two tests to the emacs test library based on the two "Reply form..." tests in the reply test library. One is currently marked broken. --- test/emacs | 52 1 files changed, 52 insertions(+), 0 deletions(-) diff --git a/test/emacs b/test/emacs index 8a28705..fa5d706 100755 --- a/test/emacs +++ b/test/emacs @@ -274,6 +274,58 @@ Notmuch Test Suite writes: EOF test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest "Reply from alternate address within emacs" +test_subtest_known_broken +add_message '[from]="Sender "' \ +[to]=test_suite_ot...@notmuchmail.org \ +[subject]=notmuch-reply-test \ + '[date]="Tue, 05 Jan 2010 15:43:56 -"' \ + '[body]="reply from alternate address"' + +test_emacs "(notmuch-search \"id:\\\"${gen_msg_id}\\\"\") + (notmuch-test-wait) + (notmuch-search-reply-to-thread) + (test-output)" +sed -i -e 's/^In-Reply-To: <.*>$/In-Reply-To: /' OUTPUT +catreply from alternate address +EOF +test_expect_equal_file OUTPUT EXPECTED + +test_begin_subtest "Reply from address in named group list within emacs" +add_message '[from]="Sender "' \ +'[to]=group:test_su...@notmuchmail.org,some...@example.com\;' \ + [cc]=test_suite_ot...@notmuchmail.org \ + [subject]=notmuch-reply-test \ +'[date]="Tue, 05 Jan 2010 15:43:56 -"' \ +'[body]="Reply from address in named group list"' + +test_emacs "(notmuch-search \"id:\\\"${gen_msg_id}\\\"\") + (notmuch-test-wait) + (notmuch-search-reply-to-thread) + (test-output)" +sed -i -e 's/^In-Reply-To: <.*>$/In-Reply-To: /' OUTPUT +cat Reply from address in named group list +EOF +test_expect_equal_file OUTPUT EXPECTED + test_begin_subtest "Reply within emacs to a multipart/mixed message" test_emacs '(notmuch-show "id:20091118002059.067214ed@hikari") (notmuch-show-reply) -- 1.7.5.4 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[BUG/PATCH 0/2] Replying from other addresses in emacs
Hi everyone, This patch series adds a test for and fixes a bug that Dmitry pointed out on IRC yesterday: When replying to mail sent to an other_address, the CLI correctly sets the From header to the address that received the message. This works correctly in the default format and the JSON format. However, emacs was ignoring the provided From header and inserting the primary address, due to an incompatibility between how we construct the header list and how the `mail-header` function from the message library looks up header values in the list. People with other_addresses who are using the latest reply changes should probably apply this patch right away. Without it, you might end up replying to messages from the wrong address. Adam Wolfe Gordon (2): test: Tests for reply from alternate addresses in emacs emacs: Fix replying from alternate addresses emacs/notmuch-mua.el |4 +- test/emacs | 51 ++ 2 files changed, 53 insertions(+), 2 deletions(-) -- 1.7.5.4 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[BUG/PATCH 2/2] emacs: Fix replying from alternate addresses
The bug was that notmuch-mua-mail used `mail-header` to check whether it was passed a "From" header. The implementation of `mail-header` must try to compare symbols instead of strings when looking for headers, as it was returning nil when a From header was present. This is probably because the mail functions construct headers as alists with symbols for the header names, while our code uses strings for the header names. Since we don't use `mail-header` anywhere else, and `message-mail` is perfectly happy to accept string header names, the fix is just to use `assoc` to look for the From header, so that the strings get compared properly. --- emacs/notmuch-mua.el |4 ++-- test/emacs |1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index 6aae3a0..9805d79 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -187,7 +187,7 @@ OTHER-ARGS are passed through to `message-mail'." (when (not (string= "" user-agent)) (push (cons "User-Agent" user-agent) other-headers - (unless (mail-header 'From other-headers) + (unless (assoc "From" other-headers) (push (cons "From" (concat (notmuch-user-name) " <" (notmuch-user-primary-email) ">")) other-headers)) @@ -250,7 +250,7 @@ the From: address first." (interactive "P") (let ((other-headers (when (or prompt-for-sender notmuch-always-prompt-for-sender) - (list (cons 'From (notmuch-mua-prompt-for-sender)) + (list (cons "From" (notmuch-mua-prompt-for-sender)) (notmuch-mua-mail nil nil other-headers))) (defun notmuch-mua-new-forward-message (&optional prompt-for-sender) diff --git a/test/emacs b/test/emacs index fa5d706..08db1ee 100755 --- a/test/emacs +++ b/test/emacs @@ -275,7 +275,6 @@ EOF test_expect_equal_file OUTPUT EXPECTED test_begin_subtest "Reply from alternate address within emacs" -test_subtest_known_broken add_message '[from]="Sender "' \ [to]=test_suite_ot...@notmuchmail.org \ [subject]=notmuch-reply-test \ -- 1.7.5.4 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: Reply code with TEXT/PLAIN
Hi Mark, On Sat, Mar 24, 2012 at 15:49, Mark Walters wrote: > I am not certain if this is a bug or a request to work around broken > mailers. I tried replying to a message today (with recent git) and got > an empty message. I looked at the json output for reply and it contains > the message but the content type is TEXT/PLAIN rather than > text/plain. > > This seems to mean it doesn't match in notmuch-match-content-type > (notmuch-lib.el) called from notmuch-mua-get-quotable-parts (in > notmuch-mua.el); and so does not get included. > > Making the match case-insensitive `fixed' the problem. > > I don't know whether content-types are allowed to be upper-case but I > seem to have several mails where they are. I am also not sure whether > the correct fix is in the emacs code, or in the cli reply format > (i.e. perhaps the reply format should lower-case the content-type). A bit of Googling indicates that MIME types should be case insensitive (i.e. TEXT/PLAIN should match text/plain). Given this, I think it makes sense to change the emacs function regardless of whether it makes sense for the CLI to output them in lower-case. notmuch-match-content-type was put in notmuch-lib.el instead of in notmuch-mua.el because it was thought that it might become useful elsewhere later, so having it compare mime types correctly ensures that future uses don't need to sanitize input to it. Since you've already made the change for yourself, do you want to send a patch? Cheers. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/3] cli: refactor "notmuch tag" data structures for tagging operations
On Sat, 24 Mar 2012 18:14:35 +0200, Jani Nikula wrote: > + if (argv[i][0] == '+' || argv[i][0] == '-') { > + tag_ops[tag_ops_count++] = (tag_operation_t) { > + .tag = argv[i] + 1, > + .remove = argv[i][0] == '-', > + }; I'm not sure if this is a worthwhile use of a C99. Wouldn't it be simpler to just use two assignments? and maybe increment the index after? Still 3 lines of code. Other than that, this patch looked ok to me. I think it probably deserves a NEWS patch that the ordering behaviour changed. I do think the new order is more sensible, and the old one was never documented. d
Reply code with TEXT/PLAIN
I am not certain if this is a bug or a request to work around broken mailers. I tried replying to a message today (with recent git) and got an empty message. I looked at the json output for reply and it contains the message but the content type is TEXT/PLAIN rather than text/plain. This seems to mean it doesn't match in notmuch-match-content-type (notmuch-lib.el) called from notmuch-mua-get-quotable-parts (in notmuch-mua.el); and so does not get included. Making the match case-insensitive `fixed' the problem. I don't know whether content-types are allowed to be upper-case but I seem to have several mails where they are. I am also not sure whether the correct fix is in the emacs code, or in the cli reply format (i.e. perhaps the reply format should lower-case the content-type). Best wishes Mark PS Sorry Adam for the duplicate: I sent from a wrong address (my fault this time)! ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Questions from a user new to notmuch
On Sat, 24 Mar 2012 10:04:48 +, Patrick Totzke wrote: > Quoting Austin Clements (2012-03-22 22:39:07) > >> 2. I received a message that was addressed to a distribution group and > >>tried to reply. Because the TO: address is not my address, notmuch > >>fails to guess the proper FROM: address to set. Is there a way to > >>handle this use case? This is with the emacs notmuch client. > > > >Not in general, since notmuch doesn't know where the mail was > >addressed to. I believe some people have solved problems like this > >using Emacs hooks, but I don't know the details. > > Does the notmuch CLI not use the 'Delivered-To' header for this? To decide which from address to use for replying, the CLI (and therefore emacs ui) looks for primary and other email addresses in the reply-to/from, to, cc, bcc, envelope-to, x-original-to, and finally received headers, in this order, before falling back to just using primary email. If someone is interested (read: I'm too busy right now), and it's desirable, it would be a one-liner to add delivered-to in the to_headers array in guess_from_received_header() in notmuch-reply.c. Plus a few dozen lines of test code. ;) BR, Jani.
Questions from a user new to notmuch
On Thu, 22 Mar 2012 18:39:07 -0400, Austin Clements wrote: > Quoth Kyle Sexton on Mar 21 at 10:21 pm: > > 1. Using offlineimap to store mail into a Maildir, is it safe to move an > >already indexed message to a different folder from some other client? > > Yes, mostly. You'll have to run notmuch new for notmuch to detect the > move, but it will detect it as a move. I say "mostly" because until > you run notmuch new, notmuch won't find the message file, so it won't > be able to display the message and won't be able to synchronize any > tag changes to its maildir flags. If maildir.synchronize_flags is enabled (it is by default) you should take extra care to have the mail store and notmuch database in sync (by running "notmuch new") before changing tags that are synced with maildir flags. Otherwise, the following scenario is possible: 1) Rename file with id:message-id in another client. Note that maildir flag changes are also renames. 2) "notmuch tag -unread id:message-id" will remove unread tag from the message, but won't find the message file, and is thus unable to sync the tag change to the S maildir flag. The syncing just silently fails. 3) The next "notmuch new" syncs maildir flags to tags, adding unread tag back to id:message-id, losing your tag change. This could be considered a bug in notmuch, but not an easy one to fix race free. See http://notmuchmail.org/special-tags/ and your .notmuch-config for details about maildir flag synchronization. BR, Jani.
[PATCH 0/3] Rewrite default reply format
Austin Clements writes: > The default reply format is the last bastion of the old message > formatter style. This series converts it to the new self-recursive > style. After this, there will be one last series to rip out the > compatibility code and do final cleanup. Works fine, patches look good... just 2 "spacing" questions: in id:"1332473647-9133-2-git-send-email-amdragon at mit.edu" + typedef enum { + NOTMUCH_SHOW_TEXT_PART_REPLY = 1<<0, + } notmuch_show_text_part_flags; Should this be like: NOTMUCH_SHOW_TEXT_PART_REPLY = (1 << 0), and this + * If flags&NOTMUCH_SHOW_TEXT_PART_REPLY, this prepends "> " to each + * output line. + * like: + * If flags & NOTMUCH_SHOW_TEXT_PART_REPLY, this prepends "> " to each Tomi
[RFC] Split notmuch_database_close into two functions
Justus Winter <4winter at informatik.uni-hamburg.de> writes: > I propose to split the function notmuch_database_close into > notmuch_database_close and notmuch_database_destroy so that long > running processes like alot can close the database while still using > data obtained from queries to that database. > > I've updated the tools, the go, ruby and python bindings to use > notmuch_database_destroy instead of notmuch_database_close to destroy > database objects. This looks like a good idea. grep _destroy *.c outputs plenty of other matches so this is not a new term here. I wonder what (backward) compability issues there are, though. In message id:"1332291311-28954-2-git-send-email-4winter at informatik.uni-hamburg.de" there was typo in comment: notmuch_database_destroyed ? > > Cheers, > Justus Tomi
[PATCH] vim: fix regex after "notmuch show" output change
Jakob writes: > The new field "excluded" was added to the output and made this regex fail. > --- Is this regexp part below good ? > +... match:\([0-9]*\) excluded:\([[0-9]*\) filename:\(.*\)$', ... ( --> excluded:\([[0-9]*\) <-- ) Otherwise lookg good (I think). Tomi > vim/plugin/notmuch.vim |5 +++-- > 1 files changed, 3 insertions(+), 2 deletions(-) > > diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim > index 21985c7..92e1b50 100644 > --- a/vim/plugin/notmuch.vim > +++ b/vim/plugin/notmuch.vim > @@ -48,7 +48,7 @@ let s:notmuch_defaults = { > \ 'g:notmuch_show_part_end_regexp': 'part}' >, > \ 'g:notmuch_show_marker_regexp':' > \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$', > \ > -\ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) > depth:\([0-9]*\) match:\([0-9]*\) filename:\(.*\)$', > +\ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) > depth:\([0-9]*\) match:\([0-9]*\) excluded:\([[0-9]*\) filename:\(.*\)$', > \ 'g:notmuch_show_tags_regexp': '(\([^)]*\))$' > , > \ > \ 'g:notmuch_show_signature_regexp': '^\(-- \?\|_\+\)$' > , > @@ -870,7 +870,8 @@ function! s:NM_cmd_show_parse(inlines) > let msg['id'] = m[1] > let msg['depth'] = m[2] > let msg['match'] = m[3] > -let msg['filename'] = m[4] > +let msg['excluded'] = m[4] > +let msg['filename'] = m[5] > endif > > let in_message = 1 > -- > 1.7.9.1 > > ___ > notmuch mailing list > notmuch at notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch
Questions from a user new to notmuch
Quoting Austin Clements (2012-03-22 22:39:07) >> 2. I received a message that was addressed to a distribution group and >>tried to reply. Because the TO: address is not my address, notmuch >>fails to guess the proper FROM: address to set. Is there a way to >>handle this use case? This is with the emacs notmuch client. > >Not in general, since notmuch doesn't know where the mail was >addressed to. I believe some people have solved problems like this >using Emacs hooks, but I don't know the details. Does the notmuch CLI not use the 'Delivered-To' header for this? /p
[PATCH 3/3] cli: refactor "notmuch restore" message tagging into a separate function
Refactor to make tagging code easier to reuse in the future. No functional changes. Signed-off-by: Jani Nikula --- notmuch-client.h |5 +++ notmuch-restore.c | 73 ++- notmuch-tag.c | 75 + 3 files changed, 83 insertions(+), 70 deletions(-) diff --git a/notmuch-client.h b/notmuch-client.h index fa04fa2..7e3deee 100644 --- a/notmuch-client.h +++ b/notmuch-client.h @@ -203,6 +203,11 @@ json_quote_chararray (const void *ctx, const char *str, const size_t len); char * json_quote_str (const void *ctx, const char *str); +int +tag_message (void *ctx, notmuch_database_t *notmuch, const char *message_id, +char *file_tags, notmuch_bool_t remove_all, +notmuch_bool_t synchronize_flags); + /* notmuch-config.c */ typedef struct _notmuch_config notmuch_config_t; diff --git a/notmuch-restore.c b/notmuch-restore.c index 87d9772..bd6b884 100644 --- a/notmuch-restore.c +++ b/notmuch-restore.c @@ -88,11 +88,7 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[]) while ((line_len = getline (&line, &line_size, input)) != -1) { regmatch_t match[3]; - char *message_id, *file_tags, *tag, *next; - notmuch_message_t *message = NULL; - notmuch_status_t status; - notmuch_tags_t *db_tags; - char *db_tags_str; + char *message_id, *file_tags; chomp_newline (line); @@ -109,72 +105,9 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[]) file_tags = xstrndup (line + match[2].rm_so, match[2].rm_eo - match[2].rm_so); - status = notmuch_database_find_message (notmuch, message_id, &message); - if (status || message == NULL) { - fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n", -message ? "" : "missing ", message_id); - if (status) - fprintf (stderr, "%s\n", -notmuch_status_to_string(status)); - goto NEXT_LINE; - } - - /* In order to detect missing messages, this check/optimization is -* intentionally done *after* first finding the message. */ - if (accumulate && (file_tags == NULL || *file_tags == '\0')) - { - goto NEXT_LINE; - } - - db_tags_str = NULL; - for (db_tags = notmuch_message_get_tags (message); -notmuch_tags_valid (db_tags); -notmuch_tags_move_to_next (db_tags)) - { - const char *tag = notmuch_tags_get (db_tags); - - if (db_tags_str) - db_tags_str = talloc_asprintf_append (db_tags_str, " %s", tag); - else - db_tags_str = talloc_strdup (message, tag); - } - - if (((file_tags == NULL || *file_tags == '\0') && -(db_tags_str == NULL || *db_tags_str == '\0')) || - (file_tags && db_tags_str && strcmp (file_tags, db_tags_str) == 0)) - { - goto NEXT_LINE; - } - - notmuch_message_freeze (message); - - if (!accumulate) - notmuch_message_remove_all_tags (message); - - next = file_tags; - while (next) { - tag = strsep (&next, " "); - if (*tag == '\0') - continue; - status = notmuch_message_add_tag (message, tag); - if (status) { - fprintf (stderr, -"Error applying tag %s to message %s:\n", -tag, message_id); - fprintf (stderr, "%s\n", -notmuch_status_to_string (status)); - } - } - - notmuch_message_thaw (message); - - if (synchronize_flags) - notmuch_message_tags_to_maildir_flags (message); + tag_message (ctx, notmuch, message_id, file_tags, !accumulate, +synchronize_flags); - NEXT_LINE: - if (message) - notmuch_message_destroy (message); - message = NULL; free (message_id); free (file_tags); } diff --git a/notmuch-tag.c b/notmuch-tag.c index c4e3f9d..3aeb878 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -161,6 +161,81 @@ tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, } int +tag_message (void *ctx, notmuch_database_t *notmuch, const char *message_id, +char *file_tags, notmuch_bool_t remove_all, +notmuch_bool_t synchronize_flags) +{ +notmuch_status_t status; +notmuch_tags_t *db_tags; +char *db_tags_str; +notmuch_message_t *message = NULL; +const char *tag; +char *next; +int ret = 0; + +status = notmuch_database_find_message (notmuch, message_id, &message); +if (status || message == NULL) { + fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n", +message ? "" : "missing ", message_id); + if (status) + fpr
[PATCH 2/3] cli: refactor "notmuch tag" query tagging into a separate function
Refactor to make tagging code easier to reuse in the future. No functional changes. Signed-off-by: Jani Nikula --- notmuch-tag.c | 101 - 1 files changed, 57 insertions(+), 44 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 98b2126..c4e3f9d 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -106,6 +106,60 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, return query_string; } +static int +tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, + tag_operation_t *tag_ops, notmuch_bool_t synchronize_flags) +{ +notmuch_query_t *query; +notmuch_messages_t *messages; +notmuch_message_t *message; +int i; + +/* Optimize the query so it excludes messages that already have + * the specified set of tags. */ +query_string = _optimize_tag_query (ctx, query_string, tag_ops); +if (query_string == NULL) { + fprintf (stderr, "Out of memory.\n"); + return 1; +} + +query = notmuch_query_create (notmuch, query_string); +if (query == NULL) { + fprintf (stderr, "Out of memory.\n"); + return 1; +} + +/* tagging is not interested in any special sort order */ +notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); + +for (messages = notmuch_query_search_messages (query); +notmuch_messages_valid (messages) && !interrupted; +notmuch_messages_move_to_next (messages)) +{ + message = notmuch_messages_get (messages); + + notmuch_message_freeze (message); + + for (i = 0; tag_ops[i].tag; i++) { + if (tag_ops[i].remove) + notmuch_message_remove_tag (message, tag_ops[i].tag); + else + notmuch_message_add_tag (message, tag_ops[i].tag); + } + + notmuch_message_thaw (message); + + if (synchronize_flags) + notmuch_message_tags_to_maildir_flags (message); + + notmuch_message_destroy (message); +} + +notmuch_query_destroy (query); + +return interrupted; +} + int notmuch_tag_command (void *ctx, int argc, char *argv[]) { @@ -114,12 +168,10 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) char *query_string; notmuch_config_t *config; notmuch_database_t *notmuch; -notmuch_query_t *query; -notmuch_messages_t *messages; -notmuch_message_t *message; struct sigaction action; notmuch_bool_t synchronize_flags; int i; +int ret; /* Setup our handler for SIGINT */ memset (&action, 0, sizeof (struct sigaction)); @@ -167,14 +219,6 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) return 1; } -/* Optimize the query so it excludes messages that already have - * the specified set of tags. */ -query_string = _optimize_tag_query (ctx, query_string, tag_ops); -if (query_string == NULL) { - fprintf (stderr, "Out of memory.\n"); - return 1; -} - config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) return 1; @@ -186,40 +230,9 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config); -query = notmuch_query_create (notmuch, query_string); -if (query == NULL) { - fprintf (stderr, "Out of memory.\n"); - return 1; -} - -/* tagging is not interested in any special sort order */ -notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); +ret = tag_query (ctx, notmuch, query_string, tag_ops, synchronize_flags); -for (messages = notmuch_query_search_messages (query); -notmuch_messages_valid (messages) && !interrupted; -notmuch_messages_move_to_next (messages)) -{ - message = notmuch_messages_get (messages); - - notmuch_message_freeze (message); - - for (i = 0; tag_ops[i].tag; i++) { - if (tag_ops[i].remove) - notmuch_message_remove_tag (message, tag_ops[i].tag); - else - notmuch_message_add_tag (message, tag_ops[i].tag); - } - - notmuch_message_thaw (message); - - if (synchronize_flags) - notmuch_message_tags_to_maildir_flags (message); - - notmuch_message_destroy (message); -} - -notmuch_query_destroy (query); notmuch_database_close (notmuch); -return interrupted; +return ret; } -- 1.7.5.4 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/3] cli: refactor "notmuch tag" data structures for tagging operations
To simplify code, keep all tagging operations in a single array instead of separate add and remove arrays. Apply tag changes in the order specified on the command line, instead of first removing and then adding the tags. This results in a minor functional change: If a tag is both added and removed, the last specified operation is now used. Previously the tag was always added. Signed-off-by: Jani Nikula --- notmuch-tag.c | 80 +--- 1 files changed, 36 insertions(+), 44 deletions(-) diff --git a/notmuch-tag.c b/notmuch-tag.c index 36b9b09..98b2126 100644 --- a/notmuch-tag.c +++ b/notmuch-tag.c @@ -53,10 +53,14 @@ _escape_tag (char *buf, const char *tag) return buf; } +typedef struct { +const char *tag; +notmuch_bool_t remove; +} tag_operation_t; + static char * -_optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], -int *add_tags, int add_tags_count, -int *remove_tags, int remove_tags_count) +_optimize_tag_query (void *ctx, const char *orig_query_string, +const tag_operation_t *tag_ops) { /* This is subtler than it looks. Xapian ignores the '-' operator * at the beginning both queries and parenthesized groups and, @@ -74,12 +78,9 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], /* Allocate a buffer for escaping tags. This is large enough to * hold a fully escaped tag with every character doubled plus * enclosing quotes and a NUL. */ -for (i = 0; i < add_tags_count; i++) - if (strlen (argv[add_tags[i]] + 1) > max_tag_len) - max_tag_len = strlen (argv[add_tags[i]] + 1); -for (i = 0; i < remove_tags_count; i++) - if (strlen (argv[remove_tags[i]] + 1) > max_tag_len) - max_tag_len = strlen (argv[remove_tags[i]] + 1); +for (i = 0; tag_ops[i].tag; i++) + if (strlen (tag_ops[i].tag) > max_tag_len) + max_tag_len = strlen (tag_ops[i].tag); escaped = talloc_array(ctx, char, max_tag_len * 2 + 3); if (!escaped) return NULL; @@ -90,16 +91,11 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], else query_string = talloc_asprintf (ctx, "( %s ) and (", orig_query_string); -for (i = 0; i < add_tags_count && query_string; i++) { - query_string = talloc_asprintf_append_buffer ( - query_string, "%snot tag:%s", join, - _escape_tag (escaped, argv[add_tags[i]] + 1)); - join = " or "; -} -for (i = 0; i < remove_tags_count && query_string; i++) { +for (i = 0; tag_ops[i].tag && query_string; i++) { query_string = talloc_asprintf_append_buffer ( - query_string, "%stag:%s", join, - _escape_tag (escaped, argv[remove_tags[i]] + 1)); + query_string, "%s%stag:%s", join, + tag_ops[i].remove ? "" : "not ", + _escape_tag (escaped, tag_ops[i].tag)); join = " or "; } @@ -113,9 +109,8 @@ _optimize_tag_query (void *ctx, const char *orig_query_string, char *argv[], int notmuch_tag_command (void *ctx, int argc, char *argv[]) { -int *add_tags, *remove_tags; -int add_tags_count = 0; -int remove_tags_count = 0; +tag_operation_t *tag_ops; +int tag_ops_count = 0; char *query_string; notmuch_config_t *config; notmuch_database_t *notmuch; @@ -133,35 +128,34 @@ notmuch_tag_command (void *ctx, int argc, char *argv[]) action.sa_flags = SA_RESTART; sigaction (SIGINT, &action, NULL); -add_tags = talloc_size (ctx, argc * sizeof (int)); -if (add_tags == NULL) { - fprintf (stderr, "Out of memory.\n"); - return 1; -} +argc--; argv++; /* skip subcommand argument */ -remove_tags = talloc_size (ctx, argc * sizeof (int)); -if (remove_tags == NULL) { +/* Array of tagging operations (add or remove), terminated with an + * empty element. */ +tag_ops = talloc_array (ctx, tag_operation_t, argc + 1); +if (tag_ops == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } -argc--; argv++; /* skip subcommand argument */ - for (i = 0; i < argc; i++) { if (strcmp (argv[i], "--") == 0) { i++; break; } - if (argv[i][0] == '+') { - add_tags[add_tags_count++] = i; - } else if (argv[i][0] == '-') { - remove_tags[remove_tags_count++] = i; + if (argv[i][0] == '+' || argv[i][0] == '-') { + tag_ops[tag_ops_count++] = (tag_operation_t) { + .tag = argv[i] + 1, + .remove = argv[i][0] == '-', + }; } else { break; } } -if (add_tags_count == 0 && remove_tags_count == 0) { +tag_ops[tag_ops_count].tag = NULL; + +if (tag_ops_count == 0) { fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n");
[PATCH 0/3] cli: notmuch tag/restore refactoring
Hi, here's some refactoring of notmuch tag/restore with mostly non-functional changes, in preparation of later, more interesting changes to dump/restore/tag. BR, Jani. Jani Nikula (3): cli: refactor "notmuch tag" data structures for tagging operations cli: refactor "notmuch tag" query tagging into a separate function cli: refactor "notmuch restore" message tagging into a separate function notmuch-client.h |5 + notmuch-restore.c | 73 +--- notmuch-tag.c | 242 +++-- 3 files changed, 169 insertions(+), 151 deletions(-) -- 1.7.5.4 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: Questions from a user new to notmuch
On Sat, 24 Mar 2012 10:04:48 +, Patrick Totzke wrote: > Quoting Austin Clements (2012-03-22 22:39:07) > >> 2. I received a message that was addressed to a distribution group and > >>tried to reply. Because the TO: address is not my address, notmuch > >>fails to guess the proper FROM: address to set. Is there a way to > >>handle this use case? This is with the emacs notmuch client. > > > >Not in general, since notmuch doesn't know where the mail was > >addressed to. I believe some people have solved problems like this > >using Emacs hooks, but I don't know the details. > > Does the notmuch CLI not use the 'Delivered-To' header for this? To decide which from address to use for replying, the CLI (and therefore emacs ui) looks for primary and other email addresses in the reply-to/from, to, cc, bcc, envelope-to, x-original-to, and finally received headers, in this order, before falling back to just using primary email. If someone is interested (read: I'm too busy right now), and it's desirable, it would be a one-liner to add delivered-to in the to_headers array in guess_from_received_header() in notmuch-reply.c. Plus a few dozen lines of test code. ;) BR, Jani. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: Questions from a user new to notmuch
On Thu, 22 Mar 2012 18:39:07 -0400, Austin Clements wrote: > Quoth Kyle Sexton on Mar 21 at 10:21 pm: > > 1. Using offlineimap to store mail into a Maildir, is it safe to move an > >already indexed message to a different folder from some other client? > > Yes, mostly. You'll have to run notmuch new for notmuch to detect the > move, but it will detect it as a move. I say "mostly" because until > you run notmuch new, notmuch won't find the message file, so it won't > be able to display the message and won't be able to synchronize any > tag changes to its maildir flags. If maildir.synchronize_flags is enabled (it is by default) you should take extra care to have the mail store and notmuch database in sync (by running "notmuch new") before changing tags that are synced with maildir flags. Otherwise, the following scenario is possible: 1) Rename file with id:message-id in another client. Note that maildir flag changes are also renames. 2) "notmuch tag -unread id:message-id" will remove unread tag from the message, but won't find the message file, and is thus unable to sync the tag change to the S maildir flag. The syncing just silently fails. 3) The next "notmuch new" syncs maildir flags to tags, adding unread tag back to id:message-id, losing your tag change. This could be considered a bug in notmuch, but not an easy one to fix race free. See http://notmuchmail.org/special-tags/ and your .notmuch-config for details about maildir flag synchronization. BR, Jani. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 0/3] Rewrite default reply format
Austin Clements writes: > The default reply format is the last bastion of the old message > formatter style. This series converts it to the new self-recursive > style. After this, there will be one last series to rip out the > compatibility code and do final cleanup. Works fine, patches look good... just 2 "spacing" questions: in id:"1332473647-9133-2-git-send-email-amdra...@mit.edu" + typedef enum { + NOTMUCH_SHOW_TEXT_PART_REPLY = 1<<0, + } notmuch_show_text_part_flags; Should this be like: NOTMUCH_SHOW_TEXT_PART_REPLY = (1 << 0), and this + * If flags&NOTMUCH_SHOW_TEXT_PART_REPLY, this prepends "> " to each + * output line. + * like: + * If flags & NOTMUCH_SHOW_TEXT_PART_REPLY, this prepends "> " to each Tomi ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: Questions from a user new to notmuch
Quoting Austin Clements (2012-03-22 22:39:07) >> 2. I received a message that was addressed to a distribution group and >>tried to reply. Because the TO: address is not my address, notmuch >>fails to guess the proper FROM: address to set. Is there a way to >>handle this use case? This is with the emacs notmuch client. > >Not in general, since notmuch doesn't know where the mail was >addressed to. I believe some people have solved problems like this >using Emacs hooks, but I don't know the details. Does the notmuch CLI not use the 'Delivered-To' header for this? /p ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [RFC] Split notmuch_database_close into two functions
Justus Winter <4win...@informatik.uni-hamburg.de> writes: > I propose to split the function notmuch_database_close into > notmuch_database_close and notmuch_database_destroy so that long > running processes like alot can close the database while still using > data obtained from queries to that database. > > I've updated the tools, the go, ruby and python bindings to use > notmuch_database_destroy instead of notmuch_database_close to destroy > database objects. This looks like a good idea. grep _destroy *.c outputs plenty of other matches so this is not a new term here. I wonder what (backward) compability issues there are, though. In message id:"1332291311-28954-2-git-send-email-4win...@informatik.uni-hamburg.de" there was typo in comment: notmuch_database_destroyed ? > > Cheers, > Justus Tomi ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] vim: fix regex after "notmuch show" output change
Jakob writes: > The new field "excluded" was added to the output and made this regex fail. > --- Is this regexp part below good ? > +... match:\([0-9]*\) excluded:\([[0-9]*\) filename:\(.*\)$', ... ( --> excluded:\([[0-9]*\) <-- ) Otherwise lookg good (I think). Tomi > vim/plugin/notmuch.vim |5 +++-- > 1 files changed, 3 insertions(+), 2 deletions(-) > > diff --git a/vim/plugin/notmuch.vim b/vim/plugin/notmuch.vim > index 21985c7..92e1b50 100644 > --- a/vim/plugin/notmuch.vim > +++ b/vim/plugin/notmuch.vim > @@ -48,7 +48,7 @@ let s:notmuch_defaults = { > \ 'g:notmuch_show_part_end_regexp': 'part}' >, > \ 'g:notmuch_show_marker_regexp':' > \\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$', > \ > -\ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) > depth:\([0-9]*\) match:\([0-9]*\) filename:\(.*\)$', > +\ 'g:notmuch_show_message_parse_regexp': '\(id:[^ ]*\) > depth:\([0-9]*\) match:\([0-9]*\) excluded:\([[0-9]*\) filename:\(.*\)$', > \ 'g:notmuch_show_tags_regexp': '(\([^)]*\))$' > , > \ > \ 'g:notmuch_show_signature_regexp': '^\(-- \?\|_\+\)$' > , > @@ -870,7 +870,8 @@ function! s:NM_cmd_show_parse(inlines) > let msg['id'] = m[1] > let msg['depth'] = m[2] > let msg['match'] = m[3] > -let msg['filename'] = m[4] > +let msg['excluded'] = m[4] > +let msg['filename'] = m[5] > endif > > let in_message = 1 > -- > 1.7.9.1 > > ___ > notmuch mailing list > notmuch@notmuchmail.org > http://notmuchmail.org/mailman/listinfo/notmuch ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch