[PATCH] emacs: Add customization group for replying

2012-07-26 Thread Michal Sojka
When one wants to customize the format of reply message, there nothing
to tell the user how to do it.  Without knowing that construction of
reply buffer is actually implemented in the message package, it seems
that replying cannot be customized.

Because I was getting annoyed by the empty line the between citation
line and the quoted message, I figured out that changing this is fairly
easy when one knows what to customize.

This patch adds notmuch-reply customization group that that contains
references to the relevant customization options. The new group is easy
to find as it is shown as a result of running M-x customize-group RET
notmuch RET.
---
 emacs/notmuch-lib.el |   11 +++
 1 file changed, 11 insertions(+)

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 30db58f..47d9e0c 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -45,6 +45,17 @@
   Showing messages and threads.
   :group 'notmuch)
 
+(defgroup notmuch-reply
+  '((message-citation-line-function custom-variable)
+(message-citation-line-format custom-variable)
+(message-insertion custom-group))
+  Replying to messages.
+
+Replying in notmuch can be customized in `Message insertion'
+group. However, the most important options from that group are
+also included here.
+  :group 'notmuch)
+
 (defgroup notmuch-send nil
   Sending messages from Notmuch.
   :group 'notmuch)
-- 
1.7.10

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH] emacs: functions to import sender or recipient into BBDB

2012-07-26 Thread Daniel Bergey
From a show buffer, bbdb/notmuch-snarf-from imports the sender into
bbdb.  bbdb/notmuch-snarf-to attempts to import all recipients.  BBDB
displays a buffer with each contact; C-g displays the next contact, or
returns to the notmuch-show buffer.

Both functions assume that email contacts are seperated by commas.  If a
comma is included in a name, it will try to make two separate
contacts.
---
This is my first notmuch patch.  Comments very welcome.

 emacs/notmuch-show.el |   28 
 1 file changed, 28 insertions(+)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 6335d45..3bc1da0 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1895,6 +1895,34 @@ the user (see 
`notmuch-show-stash-mlarchive-link-alist').
   (button-get button :notmuch-filename)
   (button-get button :notmuch-content-type)))
 
+;; bbdb interaction functions, awaiting user keybindings
+
+(defun bbdb/snarf-between-commas ()
+  ; What about names written Surname, First M u...@server.tld?
+  (goto-char (point-min))
+  (let ((comma (point)))
+(while (search-forward , nil end)
+  (bbdb-snarf-region comma (point))
+  (setq comma (point)))
+(bbdb-snarf-region comma (point)) ; last entry
+   ))
+
+(defun bbdb/notmuch-snarf-header (header)
+  (let ((text (notmuch-show-get-header header)))
+(with-temp-buffer
+  (insert text)
+  (bbdb/snarf-between-commas
+
+(defun bbdb/notmuch-snarf-from ()
+  Import the sender of the current message into BBDB
+  (interactive)
+  (bbdb/notmuch-snarf-header :From))
+
+(defun bbdb/notmuch-snarf-to ()
+  Import all recipients of the current message into BBDB
+  (interactive)
+  (bbdb/notmuch-snarf-header :To))
+
 ;;
 
 (provide 'notmuch-show)
-- 
1.7.10.4

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[PATCH 01/18] cli: add stub for insert command

2012-07-26 Thread Peter Wang
This does nothing yet.
---
 Makefile.local   |1 +
 notmuch-client.h |3 +++
 notmuch-insert.c |   27 +++
 notmuch.c|3 +++
 4 files changed, 34 insertions(+), 0 deletions(-)
 create mode 100644 notmuch-insert.c

diff --git a/Makefile.local b/Makefile.local
index 296995d..950f046 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -282,6 +282,7 @@ notmuch_client_srcs =   \
notmuch-config.c\
notmuch-count.c \
notmuch-dump.c  \
+   notmuch-insert.c\
notmuch-new.c   \
notmuch-reply.c \
notmuch-restore.c   \
diff --git a/notmuch-client.h b/notmuch-client.h
index f930798..edbd3ee 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -132,6 +132,9 @@ int
 notmuch_dump_command (void *ctx, int argc, char *argv[]);

 int
+notmuch_insert_command (void *ctx, int argc, char *argv[]);
+
+int
 notmuch_new_command (void *ctx, int argc, char *argv[]);

 int
diff --git a/notmuch-insert.c b/notmuch-insert.c
new file mode 100644
index 000..0e061a0
--- /dev/null
+++ b/notmuch-insert.c
@@ -0,0 +1,27 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright ? 2012 Peter Wang
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Peter Wang 
+ */
+
+#include "notmuch-client.h"
+
+int
+notmuch_insert_command (void *ctx, int argc, char *argv[])
+{
+return 1;
+}
diff --git a/notmuch.c b/notmuch.c
index 477a09c..86239fd 100644
--- a/notmuch.c
+++ b/notmuch.c
@@ -53,6 +53,9 @@ static command_t commands[] = {
 { "new", notmuch_new_command,
   "[options...]",
   "Find and import new messages to the notmuch database." },
+{ "insert", notmuch_insert_command,
+  "[options...] [--] [+|- ...] < message",
+  "Add a new message into the maildir and notmuch database." },
 { "search", notmuch_search_command,
   "[options...]  [...]",
   "Search for messages matching the given search terms." },
-- 
1.7.4.4



[PATCH 02/18] insert: open database

2012-07-26 Thread Peter Wang
Open the notmuch configuration file and database.
---
 notmuch-insert.c |   16 
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 0e061a0..21424cf 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -23,5 +23,21 @@
 int
 notmuch_insert_command (void *ctx, int argc, char *argv[])
 {
+notmuch_config_t *config;
+notmuch_database_t *notmuch;
+const char *db_path;
+
+config = notmuch_config_open (ctx, NULL, NULL);
+if (config == NULL)
+   return 1;
+
+db_path = notmuch_config_get_database_path (config);
+
+if (notmuch_database_open (notmuch_config_get_database_path (config),
+  NOTMUCH_DATABASE_MODE_READ_WRITE, ))
+   return 1;
+
+notmuch_database_destroy (notmuch);
+
 return 1;
 }
-- 
1.7.4.4



[PATCH 03/18] insert: open Maildir tmp file

2012-07-26 Thread Peter Wang
Open a unique file in the Maildir tmp directory.
The new message is not yet copied into the file.
---
 notmuch-insert.c |   80 +-
 1 files changed, 79 insertions(+), 1 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 21424cf..f01a6f2 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -20,12 +20,86 @@

 #include "notmuch-client.h"

+#include 
+#include 
+#include 
+
+static notmuch_bool_t
+safe_gethostname (char *hostname, size_t hostname_size)
+{
+if (gethostname (hostname, hostname_size) == -1) {
+   strncpy (hostname, "unknown", hostname_size);
+}
+hostname[hostname_size - 1] = '\0';
+
+return (strchr (hostname, '/') == NULL);
+}
+
+static int
+maildir_open_tmp (void *ctx, const char *dir, char **tmppath, char **newpath)
+{
+pid_t pid;
+char hostname[256];
+struct timeval tv;
+char *filename;
+int fd = -1;
+
+/* This is the file name format used by Dovecot. */
+pid = getpid ();
+if (! safe_gethostname (hostname, sizeof (hostname))) {
+   fprintf (stderr, "Error: invalid host name.\n");
+   return -1;
+}
+gettimeofday (, NULL);
+filename = talloc_asprintf (ctx, "%ld.M%ldP%d.%s",
+   tv.tv_sec, tv.tv_usec, pid, hostname);
+
+*tmppath = talloc_asprintf (ctx, "%s/tmp/%s", dir, filename);
+
+do {
+   fd = open (*tmppath, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0666);
+} while (fd == -1 && errno == EEXIST);
+
+if (fd != -1) {
+   *newpath = talloc_asprintf (ctx, "%s/new/%s", dir, filename);
+}
+else {
+   fprintf (stderr, "Error: opening %s: %s\n",
+*tmppath, strerror (errno));
+   talloc_free (*tmppath);
+}
+
+talloc_free (filename);
+
+return fd;
+}
+
+static notmuch_bool_t
+insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
+   const char *dir)
+{
+char *tmppath;
+char *newpath;
+int fdout;
+
+fdout = maildir_open_tmp (ctx, dir, , );
+if (fdout < 0) {
+   return FALSE;
+}
+
+close (fdout);
+unlink (tmppath);
+return FALSE;
+}
+
 int
 notmuch_insert_command (void *ctx, int argc, char *argv[])
 {
 notmuch_config_t *config;
 notmuch_database_t *notmuch;
 const char *db_path;
+char *maildir;
+notmuch_bool_t ret;

 config = notmuch_config_open (ctx, NULL, NULL);
 if (config == NULL)
@@ -33,11 +107,15 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])

 db_path = notmuch_config_get_database_path (config);

+maildir = talloc_asprintf (ctx, "%s", db_path);
+
 if (notmuch_database_open (notmuch_config_get_database_path (config),
   NOTMUCH_DATABASE_MODE_READ_WRITE, ))
return 1;

+ret = insert_message (ctx, notmuch, STDIN_FILENO, maildir);
+
 notmuch_database_destroy (notmuch);

-return 1;
+return (ret) ? 0 : 1;
 }
-- 
1.7.4.4



[PATCH 04/18] insert: copy stdin to Maildir tmp file

2012-07-26 Thread Peter Wang
Read the new message from standard input into the Maildir tmp file.
---
 notmuch-insert.c |   51 +--
 1 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index f01a6f2..340f7e4 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -75,21 +75,68 @@ maildir_open_tmp (void *ctx, const char *dir, char 
**tmppath, char **newpath)
 }

 static notmuch_bool_t
+copy_fd_data (int fdin, int fdout)
+{
+char buf[4096];
+char *p;
+ssize_t remain;
+ssize_t written;
+
+for (;;) {
+   remain = read (fdin, buf, sizeof(buf));
+   if (remain == 0)
+   break;
+   if (remain < 0) {
+   if (errno == EINTR)
+   continue;
+   fprintf (stderr, "Error: reading from standard input: %s\n",
+strerror (errno));
+   return FALSE;
+   }
+
+   p = buf;
+   do {
+   written = write (fdout, p, remain);
+   if (written == 0)
+   return FALSE;
+   if (written < 0) {
+   if (errno == EINTR)
+   continue;
+   fprintf (stderr, "Error: writing to temporary file: %s",
+strerror (errno));
+   return FALSE;
+   }
+   p += written;
+   remain -= written;
+   } while (remain > 0);
+}
+
+return TRUE;
+}
+
+static notmuch_bool_t
 insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
const char *dir)
 {
 char *tmppath;
 char *newpath;
 int fdout;
+notmuch_bool_t ret;

 fdout = maildir_open_tmp (ctx, dir, , );
 if (fdout < 0) {
return FALSE;
 }

+ret = copy_fd_data (fdin, fdout);
+
 close (fdout);
-unlink (tmppath);
-return FALSE;
+
+if (!ret) {
+   unlink (tmppath);
+}
+
+return ret;
 }

 int
-- 
1.7.4.4



[PATCH 05/18] insert: move file from Maildir tmp to new

2012-07-26 Thread Peter Wang
Atomically move the new message file from the Maildir 'tmp' directory
to 'new'.
---
 notmuch-insert.c |   18 ++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 340f7e4..bab1fed 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -75,6 +75,20 @@ maildir_open_tmp (void *ctx, const char *dir, char 
**tmppath, char **newpath)
 }

 static notmuch_bool_t
+maildir_move_to_new (const char *tmppath, const char *newpath)
+{
+/* We follow the Dovecot recommendation to simply use rename()
+ * instead of link() and unlink().
+ */
+if (rename (tmppath, newpath) == 0) {
+   return TRUE;
+}
+
+fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));
+return FALSE;
+}
+
+static notmuch_bool_t
 copy_fd_data (int fdin, int fdout)
 {
 char buf[4096];
@@ -132,6 +146,10 @@ insert_message (void *ctx, notmuch_database_t *notmuch, 
int fdin,

 close (fdout);

+if (ret) {
+   ret = maildir_move_to_new (tmppath, newpath);
+}
+
 if (!ret) {
unlink (tmppath);
 }
-- 
1.7.4.4



[PATCH 06/18] insert: add new message to database

2012-07-26 Thread Peter Wang
Add the new message to the notmuch database, renaming the file to encode
notmuch tags as maildir flags.
---
 notmuch-insert.c |   44 
 1 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index bab1fed..dd449bc 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -129,6 +129,42 @@ copy_fd_data (int fdin, int fdout)
 }

 static notmuch_bool_t
+save_database (notmuch_database_t *notmuch, const char *path)
+{
+notmuch_message_t *message;
+notmuch_status_t status;
+
+status = notmuch_database_add_message (notmuch, path, );
+switch (status) {
+case NOTMUCH_STATUS_SUCCESS:
+   break;
+case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:
+   fprintf (stderr, "Warning: duplicate message.\n");
+   break;
+default:
+case NOTMUCH_STATUS_FILE_NOT_EMAIL:
+case NOTMUCH_STATUS_READ_ONLY_DATABASE:
+case NOTMUCH_STATUS_XAPIAN_EXCEPTION:
+case NOTMUCH_STATUS_OUT_OF_MEMORY:
+case NOTMUCH_STATUS_FILE_ERROR:
+case NOTMUCH_STATUS_NULL_POINTER:
+case NOTMUCH_STATUS_TAG_TOO_LONG:
+case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:
+case NOTMUCH_STATUS_UNBALANCED_ATOMIC:
+case NOTMUCH_STATUS_LAST_STATUS:
+   fprintf (stderr, "Error: failed to add `%s' to notmuch database: %s\n",
+path, notmuch_status_to_string (status));
+   return FALSE;
+}
+
+notmuch_message_tags_to_maildir_flags (message);
+
+notmuch_message_destroy (message);
+
+return TRUE;
+}
+
+static notmuch_bool_t
 insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
const char *dir)
 {
@@ -152,6 +188,14 @@ insert_message (void *ctx, notmuch_database_t *notmuch, 
int fdin,

 if (!ret) {
unlink (tmppath);
+   return FALSE;
+}
+
+ret = save_database (notmuch, newpath);
+
+if (!ret) {
+   /* XXX maybe there should be an option to keep the file in maildir? */
+   unlink (newpath);
 }

 return ret;
-- 
1.7.4.4



[PATCH 07/18] insert: add --folder option

2012-07-26 Thread Peter Wang
Allow the new message to be inserted into a folder within the Maildir
hierarchy instead of the top-level folder.
---
 notmuch-insert.c |   21 -
 1 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index dd449bc..6398618 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -207,16 +207,35 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
 notmuch_config_t *config;
 notmuch_database_t *notmuch;
 const char *db_path;
+const char *folder = NULL;
 char *maildir;
+int opt_index;
 notmuch_bool_t ret;

+notmuch_opt_desc_t options[] = {
+   { NOTMUCH_OPT_STRING, , "folder", 0, 0 },
+   { NOTMUCH_OPT_END, 0, 0, 0, 0 }
+};
+
+opt_index = parse_arguments (argc, argv, options, 1);
+
+if (opt_index < 0) {
+   fprintf (stderr, "Error: bad argument to notmuch insert: %s\n",
+argv[-opt_index]);
+   return 1;
+}
+
 config = notmuch_config_open (ctx, NULL, NULL);
 if (config == NULL)
return 1;

 db_path = notmuch_config_get_database_path (config);

-maildir = talloc_asprintf (ctx, "%s", db_path);
+if (folder != NULL) {
+   maildir = talloc_asprintf (ctx, "%s/%s", db_path, folder);
+} else {
+   maildir = talloc_asprintf (ctx, "%s", db_path);
+}

 if (notmuch_database_open (notmuch_config_get_database_path (config),
   NOTMUCH_DATABASE_MODE_READ_WRITE, ))
-- 
1.7.4.4



[PATCH 08/18] insert: check folder name

2012-07-26 Thread Peter Wang
Don't accept folder names containing a ".." component,
to prevent writing outside of the maildir.
---
 notmuch-insert.c |   20 
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 6398618..ee51a87 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -25,6 +25,22 @@
 #include 

 static notmuch_bool_t
+check_folder_name (const char *folder)
+{
+const char *p = folder;
+
+/* Check ".." appears nowhere in the folder name. */
+for (;;) {
+   if ((p[0] == '.') && (p[1] == '.') && (p[2] == '\0' || p[2] == '/'))
+   return FALSE;
+   p = strchr (p, '/');
+   if (!p)
+   return TRUE;
+   p++;
+}
+}
+
+static notmuch_bool_t
 safe_gethostname (char *hostname, size_t hostname_size)
 {
 if (gethostname (hostname, hostname_size) == -1) {
@@ -232,6 +248,10 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
 db_path = notmuch_config_get_database_path (config);

 if (folder != NULL) {
+   if (! check_folder_name (folder)) {
+   fprintf (stderr, "Error: bad folder name: %s\n", folder);
+   return 1;
+   }
maildir = talloc_asprintf (ctx, "%s/%s", db_path, folder);
 } else {
maildir = talloc_asprintf (ctx, "%s", db_path);
-- 
1.7.4.4



[PATCH 09/18] insert: apply default tags to new message

2012-07-26 Thread Peter Wang
Apply the new.tags to messages added by 'insert'.  This mirrors the
behaviour if the message were delivered by a separate tool followed by
'notmuch new'.
---
 notmuch-insert.c |   21 +
 1 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index ee51a87..4fb3ea3 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -145,10 +145,12 @@ copy_fd_data (int fdin, int fdout)
 }

 static notmuch_bool_t
-save_database (notmuch_database_t *notmuch, const char *path)
+save_database (notmuch_database_t *notmuch, const char *path,
+  const char **new_tags)
 {
 notmuch_message_t *message;
 notmuch_status_t status;
+int i;

 status = notmuch_database_add_message (notmuch, path, );
 switch (status) {
@@ -173,6 +175,14 @@ save_database (notmuch_database_t *notmuch, const char 
*path)
return FALSE;
 }

+notmuch_message_freeze (message);
+
+for (i = 0; new_tags[i]; i++) {
+   notmuch_message_add_tag (message, new_tags[i]);
+}
+
+notmuch_message_thaw (message);
+
 notmuch_message_tags_to_maildir_flags (message);

 notmuch_message_destroy (message);
@@ -182,7 +192,7 @@ save_database (notmuch_database_t *notmuch, const char 
*path)

 static notmuch_bool_t
 insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
-   const char *dir)
+   const char *dir, const char **new_tags)
 {
 char *tmppath;
 char *newpath;
@@ -207,7 +217,7 @@ insert_message (void *ctx, notmuch_database_t *notmuch, int 
fdin,
return FALSE;
 }

-ret = save_database (notmuch, newpath);
+ret = save_database (notmuch, newpath, new_tags);

 if (!ret) {
/* XXX maybe there should be an option to keep the file in maildir? */
@@ -223,6 +233,8 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
 notmuch_config_t *config;
 notmuch_database_t *notmuch;
 const char *db_path;
+const char **new_tags;
+size_t new_tags_length;
 const char *folder = NULL;
 char *maildir;
 int opt_index;
@@ -246,6 +258,7 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
return 1;

 db_path = notmuch_config_get_database_path (config);
+new_tags = notmuch_config_get_new_tags (config, _tags_length);

 if (folder != NULL) {
if (! check_folder_name (folder)) {
@@ -261,7 +274,7 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
   NOTMUCH_DATABASE_MODE_READ_WRITE, ))
return 1;

-ret = insert_message (ctx, notmuch, STDIN_FILENO, maildir);
+ret = insert_message (ctx, notmuch, STDIN_FILENO, maildir, new_tags);

 notmuch_database_destroy (notmuch);

-- 
1.7.4.4



[PATCH 10/18] insert: parse command-line tag operations

2012-07-26 Thread Peter Wang
Parse +tag and -tag on the 'insert' command-line.
Issue a warning about ambiguous -tag arguments which don't follow
+tag nor an explicit option list terminator.
---
 notmuch-insert.c |   50 ++
 1 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 4fb3ea3..6db03e3 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -24,6 +24,11 @@
 #include 
 #include 

+typedef struct {
+const char *tag;
+notmuch_bool_t remove;
+} tag_operation_t;
+
 static notmuch_bool_t
 check_folder_name (const char *folder)
 {
@@ -236,8 +241,11 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
 const char **new_tags;
 size_t new_tags_length;
 const char *folder = NULL;
+tag_operation_t *tag_ops;
+int tag_ops_count = 0;
 char *maildir;
 int opt_index;
+notmuch_bool_t warn_tag_rem;
 notmuch_bool_t ret;

 notmuch_opt_desc_t options[] = {
@@ -253,6 +261,48 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
return 1;
 }

+if (opt_index > 0 && strcmp (argv[opt_index - 1], "--") == 0) {
+   warn_tag_rem = FALSE;
+} else {
+   warn_tag_rem = TRUE;
+}
+
+/* Array of tagging operations (add or remove), terminated with an
+ * empty element. */
+tag_ops = talloc_array (ctx, tag_operation_t, argc - opt_index + 1);
+if (tag_ops == NULL) {
+   fprintf (stderr, "Out of memory.\n");
+   return 1;
+}
+
+for (; opt_index < argc; opt_index++) {
+   if (argv[opt_index][0] == '+') {
+   tag_ops[tag_ops_count].tag = argv[opt_index] + 1;
+   tag_ops[tag_ops_count].remove = FALSE;
+   tag_ops_count++;
+   warn_tag_rem = FALSE;
+   } else if (argv[opt_index][0] == '-') {
+   if (warn_tag_rem) {
+   fprintf (stderr,
+"Warning: ambiguous argument treated as tag removal: 
%s\n",
+argv[opt_index]);
+   }
+   tag_ops[tag_ops_count].tag = argv[opt_index] + 1;
+   tag_ops[tag_ops_count].remove = TRUE;
+   tag_ops_count++;
+   } else {
+   break;
+   }
+}
+
+tag_ops[tag_ops_count].tag = NULL;
+
+if (opt_index != argc) {
+   fprintf (stderr, "Error: bad argument to notmuch insert: %s\n",
+argv[opt_index]);
+   return 1;
+}
+
 config = notmuch_config_open (ctx, NULL, NULL);
 if (config == NULL)
return 1;
-- 
1.7.4.4



[PATCH 11/18] insert: apply command-line tag operations

2012-07-26 Thread Peter Wang
Apply the +tag and -tag operations which were specified on the
command-line.
---
 notmuch-insert.c |   18 ++
 1 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 6db03e3..5fd79be 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -151,7 +151,7 @@ copy_fd_data (int fdin, int fdout)

 static notmuch_bool_t
 save_database (notmuch_database_t *notmuch, const char *path,
-  const char **new_tags)
+  const char **new_tags, const tag_operation_t *tag_ops)
 {
 notmuch_message_t *message;
 notmuch_status_t status;
@@ -186,6 +186,14 @@ save_database (notmuch_database_t *notmuch, const char 
*path,
notmuch_message_add_tag (message, new_tags[i]);
 }

+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);

 notmuch_message_tags_to_maildir_flags (message);
@@ -197,7 +205,8 @@ save_database (notmuch_database_t *notmuch, const char 
*path,

 static notmuch_bool_t
 insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,
-   const char *dir, const char **new_tags)
+   const char *dir, const char **new_tags,
+   const tag_operation_t *tag_ops)
 {
 char *tmppath;
 char *newpath;
@@ -222,7 +231,7 @@ insert_message (void *ctx, notmuch_database_t *notmuch, int 
fdin,
return FALSE;
 }

-ret = save_database (notmuch, newpath, new_tags);
+ret = save_database (notmuch, newpath, new_tags, tag_ops);

 if (!ret) {
/* XXX maybe there should be an option to keep the file in maildir? */
@@ -324,7 +333,8 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
   NOTMUCH_DATABASE_MODE_READ_WRITE, ))
return 1;

-ret = insert_message (ctx, notmuch, STDIN_FILENO, maildir, new_tags);
+ret = insert_message (ctx, notmuch, STDIN_FILENO, maildir, new_tags,
+ tag_ops);

 notmuch_database_destroy (notmuch);

-- 
1.7.4.4



[PATCH 12/18] insert: add copyright line from notmuch-deliver

2012-07-26 Thread Peter Wang
The 'insert' implementation was based partly on notmuch-deliver.
---
 notmuch-insert.c |3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index 5fd79be..a69dfe6 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -2,6 +2,9 @@
  *
  * Copyright ? 2012 Peter Wang
  *
+ * Based in part on notmuch-deliver
+ * Copyright ? 2010 Ali Polatel
+ *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation, either version 3 of the License, or
-- 
1.7.4.4



[PATCH 13/18] test: add tests for insert

2012-07-26 Thread Peter Wang
Add tests for new 'insert' command.
---
 test/insert   |   53 +
 test/notmuch-test |1 +
 2 files changed, 54 insertions(+), 0 deletions(-)
 create mode 100755 test/insert

diff --git a/test/insert b/test/insert
new file mode 100755
index 000..3514920
--- /dev/null
+++ b/test/insert
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+test_description='"notmuch insert"'
+. ./test-lib.sh
+
+# Create directories and database before inserting.
+mkdir -p "$MAIL_DIR"/{cur,new,tmp}
+mkdir -p "$MAIL_DIR"/Drafts/{cur,new,tmp}
+notmuch new > /dev/null
+
+# We use generate_message to create the temporary message file.
+# It happens to be in the mail directory already but that is okay.
+
+test_begin_subtest "Insert message, default"
+generate_message \
+"[subject]=\"insert-subject\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message\""
+notmuch insert < "$gen_msg_filename"
+test_expect_equal "`notmuch count subject:insert-subject tag:unread`" "1"
+
+test_begin_subtest "Insert message, add tag"
+generate_message \
+"[subject]=\"insert-subject-addtag\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-addtag\""
+notmuch insert +custom < "$gen_msg_filename"
+test_expect_equal "`notmuch count tag:custom`" "1"
+
+test_begin_subtest "Insert message, add/remove tag"
+generate_message \
+"[subject]=\"insert-subject-addrmtag\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-addrmtag\""
+notmuch insert -- +custom -unread < "$gen_msg_filename"
+test_expect_equal "`notmuch count tag:custom NOT tag:unread`" "1"
+
+test_begin_subtest "Insert message, folder"
+generate_message \
+"[subject]=\"insert-subject-draft\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-draft\""
+notmuch insert --folder=Drafts < "$gen_msg_filename"
+test_expect_equal "`notmuch count folder:Drafts`" "1"
+
+test_begin_subtest "Insert message, folder and tags"
+generate_message \
+"[subject]=\"insert-subject-draft\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-draft\""
+notmuch insert --folder=Drafts -- +draft -unread < "$gen_msg_filename"
+test_expect_equal "`notmuch count folder:Drafts tag:draft NOT tag:unread`" "1"
+
+test_done
diff --git a/test/notmuch-test b/test/notmuch-test
index ea39dfc..b40ba0b 100755
--- a/test/notmuch-test
+++ b/test/notmuch-test
@@ -22,6 +22,7 @@ TESTS="
   config
   new
   count
+  insert
   search
   search-output
   search-by-folder
-- 
1.7.4.4



[PATCH 14/18] man: document 'insert' command

2012-07-26 Thread Peter Wang
Add initial documentation for notmuch insert command.
---
 man/Makefile.local|1 +
 man/man1/notmuch-insert.1 |   50 +
 2 files changed, 51 insertions(+), 0 deletions(-)
 create mode 100644 man/man1/notmuch-insert.1

diff --git a/man/Makefile.local b/man/Makefile.local
index d43a949..f91bfd4 100644
--- a/man/Makefile.local
+++ b/man/Makefile.local
@@ -12,6 +12,7 @@ MAN1 := \
$(dir)/man1/notmuch-count.1 \
$(dir)/man1/notmuch-dump.1 \
$(dir)/man1/notmuch-restore.1 \
+   $(dir)/man1/notmuch-insert.1 \
$(dir)/man1/notmuch-new.1 \
$(dir)/man1/notmuch-reply.1 \
$(dir)/man1/notmuch-search.1 \
diff --git a/man/man1/notmuch-insert.1 b/man/man1/notmuch-insert.1
new file mode 100644
index 000..7d281b5
--- /dev/null
+++ b/man/man1/notmuch-insert.1
@@ -0,0 +1,50 @@
+.TH NOTMUCH-INSERT 1 2012-xx-xx "Notmuch 0.xx"
+.SH NAME
+notmuch-insert \- add a message to the maildir and notmuch database
+.SH SYNOPSIS
+
+.B notmuch insert
+.RI "[" options "]"
+.RI "--"
+.RI "[ +<" tag> "|\-<" tag "> ... ]"
+
+.SH DESCRIPTION
+
+.B notmuch insert
+reads a message from standard input and delivers it to the specified
+maildir folder, then incorporates the message into the notmuch
+database.  It is an alternative to using a separate tool to deliver
+the message then running
+.B notmuch new
+afterwards.
+
+The new message will be tagged with the tags specified by the
+.B new.tags
+configuration option.
+Additional tagging operations may be specified on the command-line.
+Tags prefixed by '+' are added while those prefixed by '\-' are
+removed.  notmuch will warn about ambiguous tag removal arguments
+which may be confused with option arguments.  It is recommended to use
+the option list terminator "--" to avoid ambiguity.
+
+Supported options for
+.B insert
+include
+.RS 4
+.TP 4
+.BI "--folder=<" folder ">"
+
+Deliver the message to the
+.RI Maildir/ folder
+directory, which must already exist.
+The default is to deliver to the top-level directory.
+
+.RE
+.RE
+.SH SEE ALSO
+
+\fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-reply\fR(1),
+\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
+\fBnotmuch-tag\fR(1)
-- 
1.7.4.4



[PATCH 15/18] man: reference notmuch-insert.1

2012-07-26 Thread Peter Wang
Add references to notmuch-insert.1 from other man pages.
---
 man/man1/notmuch-config.1   |4 ++--
 man/man1/notmuch-count.1|4 ++--
 man/man1/notmuch-dump.1 |4 ++--
 man/man1/notmuch-new.1  |4 ++--
 man/man1/notmuch-reply.1|3 ++-
 man/man1/notmuch-restore.1  |3 ++-
 man/man1/notmuch-search.1   |3 ++-
 man/man1/notmuch-show.1 |3 ++-
 man/man1/notmuch-tag.1  |3 ++-
 man/man1/notmuch.1  |3 ++-
 man/man5/notmuch-hooks.5|4 ++--
 man/man7/notmuch-search-terms.7 |3 ++-
 12 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/man/man1/notmuch-config.1 b/man/man1/notmuch-config.1
index 2ee555d..484ccdb 100644
--- a/man/man1/notmuch-config.1
+++ b/man/man1/notmuch-config.1
@@ -152,7 +152,7 @@ use ${HOME}/.notmuch\-config if this variable is not set.
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-count\fR(1), \fBnotmuch-dump\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-reply\fR(1),
-\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
 \fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
 \fBnotmuch-tag\fR(1)
diff --git a/man/man1/notmuch-count.1 b/man/man1/notmuch-count.1
index 8551ab2..f9ba926 100644
--- a/man/man1/notmuch-count.1
+++ b/man/man1/notmuch-count.1
@@ -52,7 +52,7 @@ count (the default) or not.
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-dump\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-reply\fR(1),
-\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
 \fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
 \fBnotmuch-tag\fR(1)
diff --git a/man/man1/notmuch-dump.1 b/man/man1/notmuch-dump.1
index 64abf01..4f219e7 100644
--- a/man/man1/notmuch-dump.1
+++ b/man/man1/notmuch-dump.1
@@ -31,7 +31,7 @@ for details of the supported syntax for .
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1), \fBnotmuch-reply\fR(1),
-\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
 \fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
 \fBnotmuch-tag\fR(1)
diff --git a/man/man1/notmuch-new.1 b/man/man1/notmuch-new.1
index e01f2eb..b5c14f3 100644
--- a/man/man1/notmuch-new.1
+++ b/man/man1/notmuch-new.1
@@ -64,7 +64,7 @@ Prevents hooks from being run.
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-reply\fR(1),
-\fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-insert\fR(1),
+\fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
 \fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
 \fBnotmuch-tag\fR(1)
diff --git a/man/man1/notmuch-reply.1 b/man/man1/notmuch-reply.1
index 5aa86c0..416c796 100644
--- a/man/man1/notmuch-reply.1
+++ b/man/man1/notmuch-reply.1
@@ -96,7 +96,8 @@ replying to multiple messages at once, but the JSON format 
does not.
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
+\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
 \fBnotmuch-restore\fR(1), \fBnotmuch-search\fR(1),
 \fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
 \fBnotmuch-tag\fR(1)
diff --git a/man/man1/notmuch-restore.1 b/man/man1/notmuch-restore.1
index 18281c7..55a902d 100644
--- a/man/man1/notmuch-restore.1
+++ b/man/man1/notmuch-restore.1
@@ -39,7 +39,8 @@ details.
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
+\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
 \fBnotmuch-reply\fR(1), \fBnotmuch-search\fR(1),
 \fBnotmuch-search-terms\fR(7), \fBnotmuch-show\fR(1),
 \fBnotmuch-tag\fR(1)
diff --git a/man/man1/notmuch-search.1 b/man/man1/notmuch-search.1
index b42eb2c..1794a5e 100644
--- a/man/man1/notmuch-search.1
+++ b/man/man1/notmuch-search.1
@@ -128,7 +128,8 @@ is the number of matching non-excluded messages in the 
thread.
 .SH SEE ALSO

 \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),
-\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5), \fBnotmuch-new\fR(1),
+\fBnotmuch-dump\fR(1), \fBnotmuch-hooks\fR(5),
+\fBnotmuch-insert\fR(1), \fBnotmuch-new\fR(1),
 \fBnotmuch-reply\fR(1), \fBnotmuch-restore\fR(1),
 \fBnotmuch-search-terms\fR(7), 

[PATCH 16/18] insert: add --create-folder option

2012-07-26 Thread Peter Wang
Support an option to create a new folder in the maildir.
---
 notmuch-insert.c |   71 ++
 1 files changed, 71 insertions(+), 0 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index a69dfe6..380c520 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -48,6 +48,70 @@ check_folder_name (const char *folder)
 }
 }

+static int
+mkdir_parents (void *ctx, const char *path, int mode)
+{
+struct stat st;
+char *pathcopy;
+char *start;
+char *end;
+int ret;
+
+/* First check the common case: directory already exists. */
+if (stat (path, ) == 0) {
+   return (S_ISDIR (st.st_mode)) ? 0 : -1;
+}
+
+pathcopy = talloc_strdup (ctx, path);
+ret = 0;
+
+for (start = pathcopy; *start != '\0'; start = end + 1) {
+   end = strchr (start + 1, '/');
+   if (!end) {
+   ret = mkdir (path, mode);
+   break;
+   }
+   *end = '\0';
+   ret = mkdir (pathcopy, mode);
+   if (ret != 0 && errno != EEXIST) {
+   break;
+   }
+   *end = '/';
+}
+
+talloc_free (pathcopy);
+
+return ret;
+}
+
+static notmuch_bool_t
+maildir_create (void *ctx, const char *dir)
+{
+const int mode = 0755;
+char *subdir;
+char *end;
+
+/* Create 'cur' directory, including parent directories. */
+subdir = talloc_asprintf (ctx, "%s/cur", dir);
+if (mkdir_parents (ctx, subdir, mode) != 0)
+   return FALSE;
+
+end = subdir + strlen (subdir);
+
+/* Create 'new' directory. */
+strcpy (end - 3, "new");
+if (mkdir (subdir, mode) != 0 && errno != EEXIST)
+   return FALSE;
+
+/* Create 'tmp' directory. */
+strcpy (end - 3, "tmp");
+if (mkdir (subdir, mode) != 0 && errno != EEXIST)
+   return FALSE;
+
+talloc_free (subdir);
+return TRUE;
+}
+
 static notmuch_bool_t
 safe_gethostname (char *hostname, size_t hostname_size)
 {
@@ -253,6 +317,7 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
 const char **new_tags;
 size_t new_tags_length;
 const char *folder = NULL;
+notmuch_bool_t create_folder = FALSE;
 tag_operation_t *tag_ops;
 int tag_ops_count = 0;
 char *maildir;
@@ -262,6 +327,7 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_STRING, , "folder", 0, 0 },
+   { NOTMUCH_OPT_BOOLEAN, _folder, "create-folder", 0, 0 },
{ NOTMUCH_OPT_END, 0, 0, 0, 0 }
 };

@@ -328,6 +394,11 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])
return 1;
}
maildir = talloc_asprintf (ctx, "%s/%s", db_path, folder);
+   if (create_folder && ! maildir_create (ctx, maildir)) {
+   fprintf (stderr, "Error: creating maildir %s: %s\n",
+maildir, strerror (errno));
+   return 1;
+   }
 } else {
maildir = talloc_asprintf (ctx, "%s", db_path);
 }
-- 
1.7.4.4



[PATCH 17/18] man: document insert --create-folder option

2012-07-26 Thread Peter Wang
Document the new option.
---
 man/man1/notmuch-insert.1 |9 -
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/man/man1/notmuch-insert.1 b/man/man1/notmuch-insert.1
index 7d281b5..4bd8a35 100644
--- a/man/man1/notmuch-insert.1
+++ b/man/man1/notmuch-insert.1
@@ -36,10 +36,17 @@ include

 Deliver the message to the
 .RI Maildir/ folder
-directory, which must already exist.
+directory.
 The default is to deliver to the top-level directory.

 .RE
+
+.RS 4
+.TP 4
+.BI "--create-folder"
+
+Try to create the named folder if it does not exist.
+
 .RE
 .SH SEE ALSO

-- 
1.7.4.4



[PATCH 18/18] test: test insert --create-folder

2012-07-26 Thread Peter Wang
Add tests for the new option.
---
 test/insert |   24 
 1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/test/insert b/test/insert
index 3514920..548da58 100755
--- a/test/insert
+++ b/test/insert
@@ -50,4 +50,28 @@ generate_message \
 notmuch insert --folder=Drafts -- +draft -unread < "$gen_msg_filename"
 test_expect_equal "`notmuch count folder:Drafts tag:draft NOT tag:unread`" "1"

+test_begin_subtest "Insert message, create folder"
+generate_message \
+"[subject]=\"insert-subject-createfolder\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-createfolder\""
+notmuch insert --folder=F --create-folder -- +folder < "$gen_msg_filename"
+test_expect_equal "`notmuch count folder:F tag:folder`" "1"
+
+test_begin_subtest "Insert message, create subfolder"
+generate_message \
+"[subject]=\"insert-subject-createfolder\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-createfolder\""
+notmuch insert --folder=F/G/H/I/J --create-folder -- +folder < 
"$gen_msg_filename"
+test_expect_equal "`notmuch count folder:F/G/H/I/J tag:folder`" "1"
+
+test_begin_subtest "Insert message, create existing subfolder"
+generate_message \
+"[subject]=\"insert-subject-createfolder\"" \
+"[date]=\"Sat, 01 Jan 2000 12:00:00 -\"" \
+"[body]=\"insert-message-createfolder\""
+notmuch insert --folder=F/G/H/I/J --create-folder -- +folder < 
"$gen_msg_filename"
+test_expect_equal "`notmuch count folder:F/G/H/I/J tag:folder`" "2"
+
 test_done
-- 
1.7.4.4



[PATCH 01/18] cli: add stub for insert command

2012-07-26 Thread Peter Wang
On Wed, 25 Jul 2012 10:11:14 -0700, Jameson Graef Rollins  wrote:
> 
> This is an interesting series, but let me play devil's advocate for a
> moment: Why is this functionality needed?  What can this functionality
> do that notmuch new can't?

My mail is stored on a remote server running notmuch.
My email client runs locally, calling notmuch on the server via ssh.

After sending a message, I immediately add that message to the
Maildir/Sent folder and tag it `sent'.  When postponing a message,
I add the message to the Maildir/Drafts folder and tag it `draft'
(excluded by default).

notmuch new doesn't help me get the message into the Maildir in the
first place.  I would also need a second step to tag the messages.
Right now notmuch-deliver serves my purposes, but I would prefer it to
be part of notmuch.

Peter


[PATCH 1/5] emacs: compile and load notmuch-pick.el if present.

2012-07-26 Thread Tomi Ollila
On Thu, Jul 26 2012, Mark Walters  wrote:

> On Wed, 25 Jul 2012, Tomi Ollila  wrote:
>> On Wed, Jul 25 2012, Mark Walters  wrote:
>>
>>> Compile and load notmuch-pick.el if present.
>>>
>>> All the actual setup of pick is done in the function notmuch-pick-init
>>> so we call that in the notmuch init function if it is bound. This
>>> function will setup all extra keybinding etc.
>>
>> Great stuff! See a few thoughts below...
>
> Thanks for these: I think they are all clear improvements.
>
>>
>>> ---
>>>  emacs/Makefile.local |3 ++-
>>>  emacs/notmuch.el |5 +
>>>  2 files changed, 7 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/emacs/Makefile.local b/emacs/Makefile.local
>>> index fb82247..9f4dba6 100644
>>> --- a/emacs/Makefile.local
>>> +++ b/emacs/Makefile.local
>>> @@ -15,7 +15,8 @@ emacs_sources := \
>>> $(dir)/notmuch-crypto.el \
>>> $(dir)/notmuch-tag.el \
>>> $(dir)/coolj.el \
>>> -   $(dir)/notmuch-print.el
>>> +   $(dir)/notmuch-print.el \
>>> +   $(wildcard $(dir)/notmuch-pick.el)
>>
>> I wonder whether having this conditional is good idea. What if
>> someone copies (or (sym)links) notmuch-pick.el there and then
>> compiles and takes to use. Next time he takes clean tree and
>> forgets to do this copying and installs to the same destination.
>> Now there is old notmuch-pick.elc which might be out of sync.
>>
>> I think it would be better to provide a shell script in 
>> notmuch-pick directory which byte-compiles and installs notmuch-pick
>> in case user wants to install/update notmuch-pick. Whenever notmuch-pick
>> is good enough to be shipped inside $(dir) above then the aboce conditional
>> is not needed (at all).
>>
>
> I have now done this: I actually use a Makefile so that I can pick up
> the config from notmuch: in particular the install directory
> for the notmuch-pick.elc file. Does that seem reasonable?

I believe so.. I can say for sure when I see the code -- but anything
that makes the brave user's live in the bleeding edge easier is good.

>
>>>  emacs_images := \
>>> $(srcdir)/$(dir)/notmuch-logo.png
>>> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
>>> index fd1836f..4f3da4f 100644
>>> --- a/emacs/notmuch.el
>>> +++ b/emacs/notmuch.el
>>> @@ -59,6 +59,9 @@
>>>  (require 'notmuch-maildir-fcc)
>>>  (require 'notmuch-message)
>>>  
>>> +;; Load notmuch-pick if available (but do not error if not present).
>>> +(load "notmuch-pick" t)
>>> +
>>>  (defcustom notmuch-search-result-format
>>>`(("date" . "%12s ")
>>>  ("count" . "%-7s ")
>>> @@ -1088,6 +1091,8 @@ current search results AND that are tagged with the 
>>> given tag."
>>>  (defun notmuch ()
>>>"Run notmuch and display saved searches, known tags, etc."
>>>(interactive)
>>> +  (when (fboundp 'notmuch-pick-init)
>>> +(notmuch-pick-init))
>>>(notmuch-hello))
>>
>> Instead of this could notmuch-pick.el contain:
>>
>> In the beginning:
>>
>> (require 'notmuch-hello)
>> (require 'notmuch-show)
>> (require 'notmuch) ;; XXX ATM, as notmuch-search-mode-map is defined here
>>
>> And, at the end, before (provide 'notmuch-pick), execute the lines
>> what currenty are contained in (notmuch-pick-init).
>>
>> Then, those who want to start using notmuch-pick at this time
>> can (just) write the following in their .emacs:
>>
>> (require 'notmuch)
>> (require 'notmuch-pick)
>
> This works very nicely. And if we want a transitional period the
> notmuch-pick could be in (dir) but not loaded automatically.

Yes.

>
> Many thanks for the excellent suggestions.

Np. Thank you.

> Mark

Tomi


[PATCH 01/13] test: Uniformly canonicalize actual and expected JSON

2012-07-26 Thread Tomi Ollila
On Wed, Jul 25 2012, Austin Clements  wrote:

> Previously, we used a variety of ad-hoc canonicalizations for JSON
> output in the test suite, but were ultimately very sensitive to JSON
> irrelevancies such as whitespace.  This introduces a new test
> comparison function, test_expect_equal_json, that first pretty-prints
> *both* the actual and expected JSON and the compares the result.
>
> The current implementation of this simply uses Python's json.tool to
> perform pretty-printing (with a fallback to the identity function if
> parsing fails).  However, since the interface it introduces is
> semantically high-level, we could swap in other mechanisms in the
> future, such as another pretty-printer or something that does not
> re-order object keys (if we decide that we care about that).


The whole series looks good to me and was easy to read through.
The use of Python json.tool is pretty reasonable; It is shipped in
Python 2.6+ (For example perl does not ship json components by default,
making it more complicated to set up for this purpose). If that is too
"much", then we could also use tr -d '[:space:]' as an intermediate
solution (but that eats whitespace in quoted content too...)

I'll be afk for a few days then I test this... 

Tomi


[PATCH] emacs: Add customization group for replying

2012-07-26 Thread Michal Sojka
When one wants to customize the format of reply message, there nothing
to tell the user how to do it.  Without knowing that construction of
reply buffer is actually implemented in the message package, it seems
that replying cannot be customized.

Because I was getting annoyed by the empty line the between citation
line and the quoted message, I figured out that changing this is fairly
easy when one knows what to customize.

This patch adds notmuch-reply customization group that that contains
references to the relevant customization options. The new group is easy
to find as it is shown as a result of running "M-x customize-group RET
notmuch RET".
---
 emacs/notmuch-lib.el |   11 +++
 1 file changed, 11 insertions(+)

diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 30db58f..47d9e0c 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -45,6 +45,17 @@
   "Showing messages and threads."
   :group 'notmuch)

+(defgroup notmuch-reply
+  '((message-citation-line-function custom-variable)
+(message-citation-line-format custom-variable)
+(message-insertion custom-group))
+  "Replying to messages.
+
+Replying in notmuch can be customized in `Message insertion'
+group. However, the most important options from that group are
+also included here."
+  :group 'notmuch)
+
 (defgroup notmuch-send nil
   "Sending messages from Notmuch."
   :group 'notmuch)
-- 
1.7.10



[PATCH] emacs: functions to import sender or recipient into BBDB

2012-07-26 Thread Daniel Bergey
>From a show buffer, bbdb/notmuch-snarf-from imports the sender into
bbdb.  bbdb/notmuch-snarf-to attempts to import all recipients.  BBDB
displays a buffer with each contact; C-g displays the next contact, or
returns to the notmuch-show buffer.

Both functions assume that email contacts are seperated by commas.  If a
comma is included in a name, it will try to make two separate
contacts.
---
This is my first notmuch patch.  Comments very welcome.

 emacs/notmuch-show.el |   28 
 1 file changed, 28 insertions(+)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 6335d45..3bc1da0 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1895,6 +1895,34 @@ the user (see 
`notmuch-show-stash-mlarchive-link-alist')."
   (button-get button :notmuch-filename)
   (button-get button :notmuch-content-type)))

+;; bbdb interaction functions, awaiting user keybindings
+
+(defun bbdb/snarf-between-commas ()
+  ; What about names written "Surname, First M" ?
+  (goto-char (point-min))
+  (let ((comma (point)))
+(while (search-forward "," nil "end")
+  (bbdb-snarf-region comma (point))
+  (setq comma (point)))
+(bbdb-snarf-region comma (point)) ; last entry
+   ))
+
+(defun bbdb/notmuch-snarf-header (header)
+  (let ((text (notmuch-show-get-header header)))
+(with-temp-buffer
+  (insert text)
+  (bbdb/snarf-between-commas
+
+(defun bbdb/notmuch-snarf-from ()
+  "Import the sender of the current message into BBDB"
+  (interactive)
+  (bbdb/notmuch-snarf-header :From))
+
+(defun bbdb/notmuch-snarf-to ()
+  "Import all recipients of the current message into BBDB"
+  (interactive)
+  (bbdb/notmuch-snarf-header :To))
+
 ;;

 (provide 'notmuch-show)
-- 
1.7.10.4