]> git.notmuchmail.org Git - notmuch/commitdiff
Merge remote branch 'jukie/vim'
authorCarl Worth <cworth@cworth.org>
Sat, 28 Nov 2009 01:32:50 +0000 (17:32 -0800)
committerCarl Worth <cworth@cworth.org>
Sat, 28 Nov 2009 01:32:50 +0000 (17:32 -0800)
notmuch-new.c
notmuch-reply.c
notmuch.el

index e32b92a51de1b8c0c9bd7797edc84229e8424ff5..ba5bb5ac7b7f202ccbd7831d2105e780fb03eb36 100644 (file)
@@ -149,7 +149,7 @@ add_files_recursive (notmuch_database_t *notmuch,
        /* If this directory hasn't been modified since the last
         * add_files, then we only need to look further for
         * sub-directories. */
-       if (path_mtime <= path_dbtime && entry->d_type != DT_DIR)
+       if (path_mtime <= path_dbtime && entry->d_type == DT_REG)
            continue;
 
        /* Ignore special directories to avoid infinite recursion.
index 65bd356403e210c76b000a6aa6b632d298f81d78..9ca1236b9c1791aec6d0ba88ba250e9773cf0689 100644 (file)
 #include "notmuch-client.h"
 #include "gmime-filter-reply.h"
 
+static const struct {
+    const char *header;
+    const char *fallback;
+    GMimeRecipientType recipient_type;
+} reply_to_map[] = {
+    { "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
+    { "to",         NULL, GMIME_RECIPIENT_TYPE_TO  },
+    { "cc",         NULL, GMIME_RECIPIENT_TYPE_CC  },
+    { "bcc",        NULL, GMIME_RECIPIENT_TYPE_BCC }
+};
+
 static void
 reply_part_content (GMimeObject *part)
 {
@@ -182,58 +193,17 @@ add_recipients_for_string (GMimeMessage *message,
     return add_recipients_for_address_list (message, config, type, list);
 }
 
-int
-notmuch_reply_command (void *ctx, int argc, char *argv[])
+static int
+notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_t *query)
 {
-    notmuch_config_t *config;
-    notmuch_database_t *notmuch;
-    notmuch_query_t *query;
     GMimeMessage *reply;
-    char *query_string;
     notmuch_messages_t *messages;
     notmuch_message_t *message;
-    int ret = 0;
     const char *subject, *recipients, *from_addr = NULL;
     const char *in_reply_to, *orig_references, *references;
     char *reply_headers;
-    struct {
-       const char *header;
-       const char *fallback;
-       GMimeRecipientType recipient_type;
-    } reply_to_map[] = {
-       { "reply-to", "from", GMIME_RECIPIENT_TYPE_TO  },
-       { "to",         NULL, GMIME_RECIPIENT_TYPE_TO  },
-       { "cc",         NULL, GMIME_RECIPIENT_TYPE_CC  },
-       { "bcc",        NULL, GMIME_RECIPIENT_TYPE_BCC }
-    };
     unsigned int i;
 
-    config = notmuch_config_open (ctx, NULL, NULL);
-    if (config == NULL)
-       return 1;
-
-    query_string = query_string_from_args (ctx, argc, argv);
-    if (query_string == NULL) {
-       fprintf (stderr, "Out of memory\n");
-       return 1;
-    }
-
-    if (*query_string == '\0') {
-       fprintf (stderr, "Error: notmuch reply requires at least one search term.\n");
-       return 1;
-    }
-
-    notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
-                                    NOTMUCH_DATABASE_MODE_READ_ONLY);
-    if (notmuch == NULL)
-       return 1;
-
-    query = notmuch_query_create (notmuch, query_string);
-    if (query == NULL) {
-       fprintf (stderr, "Out of memory\n");
-       return 1;
-    }
-
     for (messages = notmuch_query_search_messages (query);
         notmuch_messages_has_more (messages);
         notmuch_messages_advance (messages))
@@ -310,6 +280,145 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 
        notmuch_message_destroy (message);
     }
+    return 0;
+}
+
+/* This format is currently tuned for a git send-email --notmuch hook */
+static int
+notmuch_reply_format_headers_only(void *ctx, notmuch_config_t *config, notmuch_query_t *query)
+{
+    GMimeMessage *reply;
+    notmuch_messages_t *messages;
+    notmuch_message_t *message;
+    const char *recipients, *in_reply_to, *orig_references, *references;
+    char *reply_headers;
+    unsigned int i;
+
+    for (messages = notmuch_query_search_messages (query);
+        notmuch_messages_has_more (messages);
+        notmuch_messages_advance (messages))
+    {
+       message = notmuch_messages_get (messages);
+
+       /* The 0 means we do not want headers in a "pretty" order. */
+       reply = g_mime_message_new (0);
+       if (reply == NULL) {
+           fprintf (stderr, "Out of memory\n");
+           return 1;
+       }
+
+       in_reply_to = talloc_asprintf (ctx, "<%s>",
+                            notmuch_message_get_message_id (message));
+
+        g_mime_object_set_header (GMIME_OBJECT (reply),
+                                 "In-Reply-To", in_reply_to);
+
+
+       orig_references = notmuch_message_get_header (message, "references");
+
+       /* We print In-Reply-To followed by References because git format-patch treats them
+         * specially.  Git does not interpret the other headers specially
+        */
+       references = talloc_asprintf (ctx, "%s%s%s",
+                                     orig_references ? orig_references : "",
+                                     orig_references ? " " : "",
+                                     in_reply_to);
+       g_mime_object_set_header (GMIME_OBJECT (reply),
+                                 "References", references);
+
+       for (i = 0; i < ARRAY_SIZE (reply_to_map); i++) {
+           const char *addr;
+
+           recipients = notmuch_message_get_header (message,
+                                                    reply_to_map[i].header);
+           if ((recipients == NULL || recipients[0] == '\0') && reply_to_map[i].fallback)
+               recipients = notmuch_message_get_header (message,
+                                                        reply_to_map[i].fallback);
+
+           addr = add_recipients_for_string (reply, config,
+                                             reply_to_map[i].recipient_type,
+                                             recipients);
+       }
+
+       g_mime_object_set_header (GMIME_OBJECT (reply), "Bcc",
+                          notmuch_config_get_user_primary_email (config));
+
+       reply_headers = g_mime_object_to_string (GMIME_OBJECT (reply));
+       printf ("%s", reply_headers);
+       free (reply_headers);
+
+       g_object_unref (G_OBJECT (reply));
+       reply = NULL;
+
+       notmuch_message_destroy (message);
+    }
+    return 0;
+}
+
+int
+notmuch_reply_command (void *ctx, int argc, char *argv[])
+{
+    notmuch_config_t *config;
+    notmuch_database_t *notmuch;
+    notmuch_query_t *query;
+    char *opt, *query_string;
+    int i, ret = 0;
+    int (*reply_format_func)(void *ctx, notmuch_config_t *config, notmuch_query_t *query);
+
+    reply_format_func = notmuch_reply_format_default;
+
+    for (i = 0; i < argc && argv[i][0] == '-'; i++) {
+       if (strcmp (argv[i], "--") == 0) {
+           i++;
+           break;
+       }
+        if (STRNCMP_LITERAL (argv[i], "--format=") == 0) {
+           opt = argv[i] + sizeof ("--format=") - 1;
+           if (strcmp (opt, "default") == 0) {
+               reply_format_func = notmuch_reply_format_default;
+           } else if (strcmp (opt, "headers-only") == 0) {
+               reply_format_func = notmuch_reply_format_headers_only;
+           } else {
+               fprintf (stderr, "Invalid value for --format: %s\n", opt);
+               return 1;
+           }
+       } else {
+           fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
+           return 1;
+       }
+    }
+
+    argc -= i;
+    argv += i;
+
+    config = notmuch_config_open (ctx, NULL, NULL);
+    if (config == NULL)
+       return 1;
+
+    query_string = query_string_from_args (ctx, argc, argv);
+    if (query_string == NULL) {
+       fprintf (stderr, "Out of memory\n");
+       return 1;
+    }
+
+    if (*query_string == '\0') {
+       fprintf (stderr, "Error: notmuch reply requires at least one search term.\n");
+       return 1;
+    }
+
+    notmuch = notmuch_database_open (notmuch_config_get_database_path (config),
+                                    NOTMUCH_DATABASE_MODE_READ_ONLY);
+    if (notmuch == NULL)
+       return 1;
+
+    query = notmuch_query_create (notmuch, query_string);
+    if (query == NULL) {
+       fprintf (stderr, "Out of memory\n");
+       return 1;
+    }
+
+    if (reply_format_func (ctx, config, query) != 0)
+       return 1;
 
     notmuch_query_destroy (query);
     notmuch_database_close (notmuch);
index d7c973c30cafe9c08ba937f95b1672abdfb5923c..e9786c0b28885c86e2a62b24f06296bc19ac380e 100644 (file)
@@ -801,6 +801,7 @@ thread from that buffer can be show when done with this one)."
     (define-key map [mouse-1] 'notmuch-search-show-thread)
     (define-key map "+" 'notmuch-search-add-tag)
     (define-key map "-" 'notmuch-search-remove-tag)
+    (define-key map "*" 'notmuch-search-operate-all)
     (define-key map "<" 'beginning-of-buffer)
     (define-key map ">" 'notmuch-search-goto-last-thread)
     (define-key map "=" 'notmuch-search-refresh-view)
@@ -934,15 +935,19 @@ and will also appear in a buffer named \"*Notmuch errors*\"."
        (split-string (buffer-substring beg end))))))
 
 (defun notmuch-search-add-tag (tag)
+  "Add a tag to messages in the current thread matching the
+active query."
   (interactive
    (list (notmuch-select-tag-with-completion "Tag to add: ")))
-  (notmuch-call-notmuch-process "tag" (concat "+" tag) (notmuch-search-find-thread-id))
+  (notmuch-call-notmuch-process "tag" (concat "+" tag) (notmuch-search-find-thread-id) " and " notmuch-search-query-string)
   (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<))))
 
 (defun notmuch-search-remove-tag (tag)
+  "Remove a tag from messages in the current thread matching the
+active query."
   (interactive
    (list (notmuch-select-tag-with-completion "Tag to remove: " (notmuch-search-find-thread-id))))
-  (notmuch-call-notmuch-process "tag" (concat "-" tag) (notmuch-search-find-thread-id))
+  (notmuch-call-notmuch-process "tag" (concat "-" tag) (notmuch-search-find-thread-id) " and " notmuch-search-query-string)
   (notmuch-search-set-tags (delete tag (notmuch-search-get-tags))))
 
 (defun notmuch-search-archive-thread ()
@@ -1001,6 +1006,29 @@ This function advances point to the next line when finished."
                  (set 'more nil))))))
       (delete-process proc))))
 
+(defun notmuch-search-operate-all (action)
+  "Operate on all messages matching the current query.  Any
+number of whitespace separated actions can be given.  Each action
+must have one of the two forms
+
+  +tagname              Add the tag `tagname'
+  -tagname              Remove the tag `tagname'
+
+Each character of the tag name may consist of alphanumeric
+characters as well as `_.+-'.
+"
+  (interactive "sOperation (+add -drop): notmuch tag ")
+  (let ((action-split (split-string action " +")))
+    ;; Perform some validation
+    (let ((words action-split))
+      (when (null words) (error "No operation given"))
+      (while words
+       (unless (string-match-p "^[\+\-][_\+\-\\w]+$" (car words))
+         (error "Action must be of the form `+thistag -that_tag'"))
+       (setq words (cdr words))))
+    (apply 'notmuch-call-notmuch-process "tag"
+          (append action-split (list notmuch-search-query-string) nil))))
+
 (defun notmuch-search (query &optional oldest-first)
   "Run \"notmuch search\" with the given query string and display results."
   (interactive "sNotmuch search: ")