Re: [PATCH v5 1/5] cli: command line parsing: allow default for keyword options

2012-05-26 Thread Peter Wang
On Sat, 26 May 2012 16:54:50 +0100, Mark Walters  
wrote:
> This changes the parsing for "keyword" options so that if the option
> is specified with no argument the first possible argument is
> chosen. This make it easier to add options to existing boolean
> arguments (the existing --option can default to TRUE).

This has the side-effect of allowing defaults for all keyword options,
right?  I'm not sure that's desirable when the default is non-obvious.

Maybe keyword options which allow an optional argument should have an
explicit entry in the notmuch_keyword_t[] array, e.g. under "" or "default".

> diff --git a/command-line-arguments.c b/command-line-arguments.c
> index 76b185f..d40c7e6 100644
> --- a/command-line-arguments.c
> +++ b/command-line-arguments.c
> @@ -11,10 +11,16 @@
>  */
>  
>  static notmuch_bool_t
> -_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char 
> *arg_str) {
> +_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const 
> char *arg_str) {
>  
>  const notmuch_keyword_t *keywords = arg_desc->keywords;
>  
> +if (next == 0) {
> +/* No keyword given so return first option as default */
> + *((int *)arg_desc->output_var) = keywords->value;
> + return TRUE;
> +}

Indentation.

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


[PATCH 2/2] Makefile.local: added verify-version-news to verify-no-dirty-code deps.

2012-05-26 Thread Tomi Ollila
Added `verify-version-news` to the end of `verify-no-dirty-code`
dependencies so it is part of release testing checks.
---
Tested by executing the following commands:
  make verify-source-tree-and-version
  make verify-source-tree-and-version VERSION=0.13
  make verify-source-tree-and-version VERSION=0.12

 Makefile.local |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 1b34c00..94a3a70 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -187,7 +187,7 @@ release-message:
 verify-source-tree-and-version: verify-no-dirty-code

 .PHONY: verify-no-dirty-code
-verify-no-dirty-code: verify-version-debian verify-version-python 
verify-version-manpage
+verify-no-dirty-code: verify-version-debian verify-version-python 
verify-version-manpage verify-version-news
 ifeq ($(IS_GIT),yes)
@printf "Checking that source tree is clean..."
 ifneq ($(shell git ls-files -m),)
-- 
1.7.1



[PATCH 1/2] Makefile.local: added checks for latest NEWS title

2012-05-26 Thread Tomi Ollila
Added target `verify-version-news` which checks that the first line
in NEWS file has the following properties:
First word is 'Notmuch'
Second "word" matches the current version
Rest of line is in format (201[2-9]-[01][0-9]-[0-3][0-9]
---

Tested by executing the following commands:
  make verify-version-news
  make verify-version-news VERSION=0.13
  make verify-version-news VERSION=0.12

 Makefile.local |   15 +++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 53b4a0d..1b34c00 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -220,6 +220,21 @@ verify-version-python: verify-version-components
 echo "Please edit version and $(PV_FILE) to have consistent 
versions." && false)
@echo "Good."

+.PHONY: verify-version-news
+verify-version-news: verify-version-components
+   @read notmuch version date < NEWS ;\
+   ev=0 ;\
+   echo -n "Checking that this is 'Notmuch' NEWS..." ;\
+   if [ "$$notmuch" = 'Notmuch' ]; then echo 'Good.' ;\
+   else echo 'No.'; ev=1; fi ;\
+   echo -n "Checking that NEWS version is $(VERSION)..." ;\
+   if [ "$$version" = '$(VERSION)' ]; then echo 'Good.' ;\
+   else echo 'No.'; ev=1; fi ;\
+   echo -n "Checking that NEWS date is in correct format..." ;\
+   case $$date in '('201[2-9]-[0-1][0-9]-[0-3][0-9]')') echo 'Good.' ;;\
+   *)   echo 'No.'; ev=1; esac ;\
+   if [ $$ev -ne 0 ]; then echo "Please edit NEWS file to have Notmuch 
header line in correct format."; false; fi
+
 .PHONY: verify-version-components
 verify-version-components:
@echo -n "Checking that $(VERSION) consists only of digits and 
periods..."
-- 
1.7.1



[PATCH v5 5/5] emacs: make elide messages use notmuch-show for omitting messages.

2012-05-26 Thread Mark Walters
Previously the elide messages code got the entire-thread from
notmuch-show.c and then threw away all non-matching messages. This
version calls notmuch-show.c without the --entire-thread flag so
it never receives the non-matching messages in the first place.

This makes it substantially faster.
---
 emacs/notmuch-show.el |   18 ++
 1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index d318430..9cc68be 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -958,9 +958,9 @@ message at DEPTH in the current thread."
   "Insert the message tree TREE at depth DEPTH in the current thread."
   (let ((msg (car tree))
(replies (cadr tree)))
-(if (or (not notmuch-show-elide-non-matching-messages)
-   (plist-get msg :match))
-   (notmuch-show-insert-msg msg depth))
+;; We test whether there is a message or just some replies.
+(when msg
+  (notmuch-show-insert-msg msg depth))
 (notmuch-show-insert-thread replies (1+ depth

 (defun notmuch-show-insert-thread (thread depth)
@@ -1041,16 +1041,18 @@ function is used."
 (args (if notmuch-show-query-context
   (append (list "\'") basic-args
   (list "and (" notmuch-show-query-context ")\'"))
-(append (list "\'") basic-args (list "\'")
-   (notmuch-show-insert-forest (notmuch-query-get-threads
-(cons "--exclude=false" args)))
+(append (list "\'") basic-args (list "\'"
+(cli-args (cons "--exclude=false"
+(when notmuch-show-elide-non-matching-messages
+  (list "--entire-thread=false")
+
+   (notmuch-show-insert-forest (notmuch-query-get-threads (append cli-args 
args)))
;; If the query context reduced the results to nothing, run
;; the basic query.
(when (and (eq (buffer-size) 0)
   notmuch-show-query-context)
  (notmuch-show-insert-forest
-  (notmuch-query-get-threads
-   (cons "--exclude=false" basic-args)
+  (notmuch-query-get-threads (append cli-args basic-args)

   (jit-lock-register #'notmuch-show-buttonise-links)

-- 
1.7.9.1



[PATCH v5 4/5] Update devel/schemata for --entire-thread=false

2012-05-26 Thread Mark Walters
Also remove the Json --entire-thread item from devel/TODO.
---
 devel/TODO |2 --
 devel/schemata |2 +-
 2 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/devel/TODO b/devel/TODO
index 7b750af..eb757af 100644
--- a/devel/TODO
+++ b/devel/TODO
@@ -92,8 +92,6 @@ and email address in the From: line. We could also then 
easily support
 "notmuch compose --from " to support getting at alternate
 email addresses.

-Fix the --format=json option to not imply --entire-thread.
-
 Implement "notmuch search --exclude-threads=" to allow
 for excluding muted threads, (and any other negative, thread-based
 filtering that the user wants to do).
diff --git a/devel/schemata b/devel/schemata
index 977cea7..8fcab8e 100644
--- a/devel/schemata
+++ b/devel/schemata
@@ -32,7 +32,7 @@ thread = [thread_node*]

 # A message and its replies (show_messages)
 thread_node = [
-message?, # present if --entire-thread or matched
+message?, # null if not matched and not --entire-thread
 [thread_node*]# children of message
 ]

-- 
1.7.9.1



[PATCH v5 3/5] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread Mark Walters
The --entire-thread option in notmuch-show.c defaults to true when
format=json. Previously there was no way to turn this off. This patch
makes it respect --entire-thread=false.

To do this the patch moves the --entire-thread option to be a keyword
option using the new command line parsing to allow the existing
--entire-thread syntax to keep working.
---
 notmuch-show.c |   25 +++--
 1 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 97da5cc..207093a 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -981,6 +981,12 @@ enum {
 NOTMUCH_FORMAT_RAW
 };

+enum {
+ENTIRE_THREAD_DEFAULT,
+ENTIRE_THREAD_TRUE,
+ENTIRE_THREAD_FALSE,
+};
+
 /* The following is to allow future options to be added more easily */
 enum {
 EXCLUDE_TRUE,
@@ -1000,6 +1006,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
 notmuch_bool_t verify = FALSE;
 int exclude = EXCLUDE_TRUE;
+int entire_thread = ENTIRE_THREAD_DEFAULT;

 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1012,8 +1019,11 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
   (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
   { "false", EXCLUDE_FALSE },
   { 0, 0 } } },
+{ NOTMUCH_OPT_KEYWORD, &entire_thread, "entire-thread", 't',
+  (notmuch_keyword_t []){ { "true", ENTIRE_THREAD_TRUE },
+  { "false", ENTIRE_THREAD_FALSE },
+  { 0, 0 } } },
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
-   { NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
{ 0, 0, 0, 0, 0 }
@@ -1036,7 +1046,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 switch (format_sel) {
 case NOTMUCH_FORMAT_JSON:
format = &format_json;
-   params.entire_thread = TRUE;
+   /* JSON defaults to entire-thread TRUE */
+   if (entire_thread == ENTIRE_THREAD_DEFAULT)
+   entire_thread = ENTIRE_THREAD_TRUE;
break;
 case NOTMUCH_FORMAT_TEXT:
format = &format_text;
@@ -1058,6 +1070,15 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
params.raw = TRUE;
break;
 }
+/* Default is entire-thread = FALSE except for format=json which
+ * is dealt with above. */
+if (entire_thread == ENTIRE_THREAD_DEFAULT)
+   entire_thread = ENTIRE_THREAD_FALSE;
+
+if (entire_thread == ENTIRE_THREAD_TRUE)
+   params.entire_thread = TRUE;
+else
+   params.entire_thread = FALSE;

 if (params.decrypt || verify) {
 #ifdef GMIME_ATLEAST_26
-- 
1.7.9.1



[PATCH v5 2/5] cli: Let json output "null" messages for non --entire-thread

2012-05-26 Thread Mark Walters
All formats except Json can output empty messages for non
entire-thread, but in Json format we output "null" to keep the other
elements (e.g. the replies to the omitted message) in the correct
place.
---
 notmuch-client.h |1 +
 notmuch-show.c   |   20 
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 19b7f01..08540a7 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -72,6 +72,7 @@ typedef struct notmuch_show_format {
  const struct notmuch_show_params *params);
 const char *message_set_sep;
 const char *message_set_end;
+const char *null_message;
 } notmuch_show_format_t;

 typedef struct notmuch_show_params {
diff --git a/notmuch-show.c b/notmuch-show.c
index 95427d4..97da5cc 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -37,7 +37,8 @@ static const notmuch_show_format_t format_json = {
 .message_set_start = "[",
 .part = format_part_json_entry,
 .message_set_sep = ", ",
-.message_set_end = "]"
+.message_set_end = "]",
+.null_message = "null"
 };

 static notmuch_status_t
@@ -800,6 +801,15 @@ format_part_raw (unused (const void *ctx), mime_node_t 
*node,
 }

 static notmuch_status_t
+show_null_message (const notmuch_show_format_t *format)
+{
+/* Output a null message. Currently empty for all formats except Json */
+if (format->null_message)
+   printf ("%s", format->null_message);
+return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
 show_message (void *ctx,
  const notmuch_show_format_t *format,
  notmuch_message_t *message,
@@ -862,11 +872,13 @@ show_messages (void *ctx,
if (status && !res)
res = status;
next_indent = indent + 1;
-
-   if (!status && format->message_set_sep)
-   fputs (format->message_set_sep, stdout);
+   } else {
+   status = show_null_message (format);
}

+   if (!status && format->message_set_sep)
+   fputs (format->message_set_sep, stdout);
+
status = show_messages (ctx,
format,
notmuch_message_get_replies (message),
-- 
1.7.9.1



[PATCH v5 1/5] cli: command line parsing: allow default for keyword options

2012-05-26 Thread Mark Walters
This changes the parsing for "keyword" options so that if the option
is specified with no argument the first possible argument is
chosen. This make it easier to add options to existing boolean
arguments (the existing --option can default to TRUE).
---
 command-line-arguments.c |   13 ++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/command-line-arguments.c b/command-line-arguments.c
index 76b185f..d40c7e6 100644
--- a/command-line-arguments.c
+++ b/command-line-arguments.c
@@ -11,10 +11,16 @@
 */

 static notmuch_bool_t
-_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char *arg_str) 
{
+_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const 
char *arg_str) {

 const notmuch_keyword_t *keywords = arg_desc->keywords;

+if (next == 0) {
+/* No keyword given so return first option as default */
+   *((int *)arg_desc->output_var) = keywords->value;
+   return TRUE;
+}
+
 while (keywords->name) {
if (strcmp (arg_str, keywords->name) == 0) {
if (arg_desc->output_var) {
@@ -99,7 +105,8 @@ parse_option (const char *arg,
 */
if (next != '=' && next != ':' && next != 0) return FALSE;
if (next == 0) {
-   if (try->opt_type != NOTMUCH_OPT_BOOLEAN)
+   if (try->opt_type != NOTMUCH_OPT_BOOLEAN &&
+   try->opt_type != NOTMUCH_OPT_KEYWORD)
return FALSE;
} else {
if (value[0] == 0) return FALSE;
@@ -110,7 +117,7 @@ parse_option (const char *arg,

switch (try->opt_type) {
case NOTMUCH_OPT_KEYWORD:
-   return _process_keyword_arg (try, value);
+   return _process_keyword_arg (try, next, value);
break;
case NOTMUCH_OPT_BOOLEAN:
return _process_boolean_arg (try, next, value);
-- 
1.7.9.1



[PATCH v5 0/5] Allow JSON to use non-entire thread, and use for elide

2012-05-26 Thread Mark Walters
This is version 5 of this patch series: version 4 is at
id:"1335258675-29439-1-git-send-email-markwalters1009 at gmail.com".

This version changes the way the command-line parser deals with
keywords so that specifying --option without an = returns
the first option. This means that boolean options can easily have
extra options added without breaking the existing syntax.

Patch 3/5 takes advantage of this new feature to implement the  
--entire-thread option to notmuch-show in a non-hacky way.

Best wishes 

Mark


Mark Walters (5):
  cli: command line parsing: allow default for keyword options
  cli: Let json output "null" messages for non --entire-thread
  cli: make --entire-thread=false work for format=json.
  Update devel/schemata for --entire-thread=false
  emacs: make elide messages use notmuch-show for omitting messages.

 command-line-arguments.c |   13 ++---
 devel/TODO   |2 --
 devel/schemata   |2 +-
 emacs/notmuch-show.el|   18 ++
 notmuch-client.h |1 +
 notmuch-show.c   |   45 +++--
 6 files changed, 61 insertions(+), 20 deletions(-)

-- 
1.7.9.1



[PATCH 1/2] Makefile.local: added checks for latest NEWS title

2012-05-26 Thread David Bremner
Tomi Ollila  writes:

> Added target `verify-version-news` which checks that the first line
> in NEWS file has the following properties:
> First word is 'Notmuch'
> Second "word" matches the current version
> Rest of line is in format (201[2-9]-[01][0-9]-[0-3][0-9]

I appreciate the effort, but I wonder if it is worth complicating the
build system further? I'm willing to be swayed either way.

d


[PATCH 03/10] Fix compilation of smtp-dummy on FreeBSD

2012-05-26 Thread Jani Nikula
On May 25, 2012 4:44 PM, "Mike Kelly"  wrote:
>
> ---
>  test/smtp-dummy.c |5 -
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/test/smtp-dummy.c b/test/smtp-dummy.c
> index 3801a5e..aa82fa1 100644
> --- a/test/smtp-dummy.c
> +++ b/test/smtp-dummy.c
> @@ -33,11 +33,14 @@
>  * have been warned.
>  */
>
> +#define _GNU_SOURCE /* for getline */

First of all, thanks for sharing your work.

Independent of this patch, I've been thinking about defining _GNU_SOURCE in
the makefile. I don't think it's very elegant to #define it everywhere. It
would also pave the way towards building with -pedantic (and possibly
-std=c99) in a portable way. For example, the compat test code #defines
_GNU_SOURCE while the actual code does not, which I think is an error.

I'll look into this after the weekend (unless you beat me to it).

BR,
Jani.

>  #include 
>  #include 
>  #include 
>  #include 
> -#include 
> +#include 
> +#include 
> +#include 
>  #include 
>  #include 
>
> --
> 1.7.10.2
>
> ___
> notmuch mailing list
> notmuch at notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
-- next part --
An HTML attachment was scrubbed...
URL: 
<http://notmuchmail.org/pipermail/notmuch/attachments/20120526/2226a245/attachment.html>


[PATCH 06/10] Fix test/count on FreeBSD

2012-05-26 Thread Peter Wang
On Fri, 25 May 2012 09:43:27 -0400, Mike Kelly  wrote:
> FreeBSD's `wc -l` includes some white space in front of the number, so
> trim it off.
> ---
>  test/count |8 
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/test/count b/test/count
> index 300b171..618dbb9 100755
> --- a/test/count
> +++ b/test/count
> @@ -8,22 +8,22 @@ SEARCH="\"*\""
>  
>  test_begin_subtest "message count is the default for notmuch count"
>  test_expect_equal \
> -"`notmuch search --output=messages ${SEARCH} | wc -l`" \
> +"`notmuch search --output=messages ${SEARCH} | wc -l |sed 
> 's/^[[:space:]]*//'`" \
>  "`notmuch count ${SEARCH}`"

You could perform a proper integer comparison like:

test_expect_success "message count is the default for notmuch count" '
test "`notmuch search --output=messages ${SEARCH} | wc -l`" \
 -eq "`notmuch count ${SEARCH}`"
'

Peter


[PATCH v4 2/4] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread Peter Wang
On Tue, 24 Apr 2012 10:11:13 +0100, Mark Walters  
wrote:
> The --entire-thread option in notmuch-show.c defaults to true when
> format=json. Previously there was no way to turn this off. This patch
> makes it respect --entire-thread=false.
> 
> The one subtlety is that we initialise a notmuch_bool_t to -1 to
> indicate that the option parsing has not set it. This allows the code
> to distinguish between the option being omitted from the command line,
> and the option being set to false on the command line.
> ---
>  notmuch-show.c |   16 ++--
>  1 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/notmuch-show.c b/notmuch-show.c
> index 0d21f1a..48551bb 100644
> --- a/notmuch-show.c
> +++ b/notmuch-show.c
> @@ -996,7 +996,13 @@ notmuch_show_command (void *ctx, unused (int argc), 
> unused (char *argv[]))
>  char *query_string;
>  int opt_index, ret;
>  const notmuch_show_format_t *format = &format_text;
> -notmuch_show_params_t params = { .part = -1, .omit_excluded = TRUE };
> +
> +/* We abuse the notmuch_bool_t variable params.entire-thread by
> + * setting it to -1 to denote that the command line parsing has
> + * not set it. We ensure it is set to TRUE or FALSE before passing
> + * it to any other function.*/
> +notmuch_show_params_t params = { .part = -1, .entire_thread = -1 };
> +
>  int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
>  notmuch_bool_t verify = FALSE;
>  int exclude = EXCLUDE_TRUE;

Hi Mark,

As an alternative to the abuse, could you just treat it as with exclude,
using an enum with three values (TRUE|FALSE|DEFAULT)?
Then set params.entire_thread afterwards.

Peter


[PATCH v5 6/7] cli: new crypto verify flag to handle verification

2012-05-26 Thread Jameson Graef Rollins
Use this flag rather than depend on the existence of an initialized
gpgctx, to determine whether we should verify a multipart/signed.  We
will be moving to create the ctx lazily, so we don't want to depend on
it being previously initialized if it's not needed.
---
 mime-node.c  |5 ++---
 notmuch-client.h |8 
 notmuch-reply.c  |1 +
 notmuch-show.c   |   14 +++---
 4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index a838224..73e28c5 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -183,8 +183,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 }
 
 /* Handle PGP/MIME parts */
-if (GMIME_IS_MULTIPART_ENCRYPTED (part)
-   && node->ctx->crypto->gpgctx && node->ctx->crypto->decrypt) {
+if (GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 4, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
@@ -218,7 +217,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 (err ? err->message : "no error explanation given"));
}
}
-} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->gpgctx) {
+} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 5, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
diff --git a/notmuch-client.h b/notmuch-client.h
index 962c747..0f29a83 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -79,6 +79,7 @@ typedef struct notmuch_show_format {
 
 typedef struct notmuch_crypto {
 notmuch_crypto_context_t* gpgctx;
+notmuch_bool_t verify;
 notmuch_bool_t decrypt;
 } notmuch_crypto_t;
 
@@ -350,10 +351,9 @@ struct mime_node {
 };
 
 /* Construct a new MIME node pointing to the root message part of
- * message.  If crypto->gpgctx is non-NULL, it will be used to verify
- * signatures on any child parts.  If crypto->decrypt is true, then
- * crypto.gpgctx will additionally be used to decrypt any encrypted
- * child parts.
+ * message. If crypto->verify is true, signed child parts will be
+ * verified. If crypto->decrypt is true, encrypted child parts will be
+ * decrypted.
  *
  * Return value:
  *
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 6f368c9..1ab3db9 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -707,6 +707,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 notmuch_show_params_t params = {
.part = -1,
.crypto = {
+   .verify = FALSE,
.decrypt = FALSE
}
 };
diff --git a/notmuch-show.c b/notmuch-show.c
index fb5e9b6..3c06792 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -987,11 +987,11 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
.part = -1,
.omit_excluded = TRUE,
.crypto = {
+   .verify = FALSE,
.decrypt = FALSE
}
 };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
-notmuch_bool_t verify = FALSE;
 int exclude = EXCLUDE_TRUE;
 
 notmuch_opt_desc_t options[] = {
@@ -1008,7 +1008,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.decrypt, "decrypt", 'd', 0 },
-   { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.verify, "verify", 'v', 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -1018,6 +1018,10 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
return 1;
 }
 
+/* decryption implies verification */
+if (params.crypto.decrypt)
+   params.crypto.verify = TRUE;
+
 if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
/* if part was requested and format was not specified, use format=raw */
if (params.part >= 0)
@@ -1052,7 +1056,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
break;
 }
 
-if (params.crypto.decrypt || verify) {
+if (params.crypto.decrypt || params.crypto.verify) {
 #ifdef GMIME_ATLEAST_26
/* TODO: GMimePasswordRequestFunc */
params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg");
@@ -1063,6 +1067,10 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
if (params.crypto.gpgctx) {
g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.crypto.gpgctx, FALSE);
} else {
+   /* If we fail to create the gpgctx set the verify and
+* decrypt flags to FALSE so we don't try to do any
+* further verification or decryption 

[PATCH v5 2/7] cli: new crypto structure to store crypto contexts and parameters, and functions to support it

2012-05-26 Thread Jameson Graef Rollins
This new structure, notmuch_crypto_t, keeps all relevant crypto
contexts and parameters together, and will make it easier to pass the
stuff around and clean it up.  The name of the crypto context inside
this new struct will change, to reflect that it is actually a GPG
context, which is a sub type of Crypto context.  There are other types
of Crypto contexts (Pkcs7 in particular, which we hope to support) so
we want to be clear.

The new crypto.c contains functions to return the proper context from
the struct for a given protocol (and initialize it if needed), and to
cleanup a struct by releasing the crypto contexts.
---
 Makefile.local   |1 +
 crypto.c |   71 ++
 notmuch-client.h |   11 +
 3 files changed, 83 insertions(+)
 create mode 100644 crypto.c

diff --git a/Makefile.local b/Makefile.local
index 53b4a0d..a890df2 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -292,6 +292,7 @@ notmuch_client_srcs =   \
notmuch-time.c  \
query-string.c  \
mime-node.c \
+   crypto.c\
json.c
 
 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
diff --git a/crypto.c b/crypto.c
new file mode 100644
index 000..fbe5aeb
--- /dev/null
+++ b/crypto.c
@@ -0,0 +1,71 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright © 2012 Jameson Rollins
+ *
+ * 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/ .
+ *
+ * Authors: Jameson Rollins 
+ */
+
+#include "notmuch-client.h"
+
+/* for the specified protocol return the context pointer (initializing
+ * if needed) */
+notmuch_crypto_context_t *
+notmuch_crypto_get_context (notmuch_crypto_t *crypto, const char *protocol)
+{
+notmuch_crypto_context_t *cryptoctx = NULL;
+
+/* As per RFC 1847 section 2.1: "the [protocol] value token is
+ * comprised of the type and sub-type tokens of the Content-Type".
+ * As per RFC 1521 section 2: "Content-Type values, subtypes, and
+ * parameter names as defined in this document are
+ * case-insensitive."  Thus, we use strcasecmp for the protocol.
+ */
+if ((strcasecmp (protocol, "application/pgp-signature") == 0)
+   || (strcasecmp (protocol, "application/pgp-encrypted") == 0)) {
+   if (!crypto->gpgctx) {
+#ifdef GMIME_ATLEAST_26
+   /* TODO: GMimePasswordRequestFunc */
+   crypto->gpgctx = g_mime_gpg_context_new (NULL, "gpg");
+#else
+   GMimeSession* session = g_object_new (g_mime_session_get_type(), 
NULL);
+   crypto->gpgctx = g_mime_gpg_context_new (session, "gpg");
+   g_object_unref (session);
+#endif
+   if (crypto->gpgctx) {
+   g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
crypto->gpgctx, FALSE);
+   } else {
+   fprintf (stderr, "Failed to construct gpg context.\n");
+   }
+   }
+   cryptoctx = crypto->gpgctx;
+
+} else {
+   fprintf (stderr, "Unknown or unsupported cryptographic protocol.\n");
+}
+
+return cryptoctx;
+}
+
+int
+notmuch_crypto_cleanup (notmuch_crypto_t *crypto)
+{
+if (crypto->gpgctx) {
+   g_object_unref (crypto->gpgctx);
+   crypto->gpgctx = NULL;
+}
+
+return 0;
+}
diff --git a/notmuch-client.h b/notmuch-client.h
index d377b04..6664075 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -77,6 +77,11 @@ typedef struct notmuch_show_format {
 const char *message_set_end;
 } notmuch_show_format_t;
 
+typedef struct notmuch_crypto {
+notmuch_crypto_context_t* gpgctx;
+notmuch_bool_t decrypt;
+} notmuch_crypto_t;
+
 typedef struct notmuch_show_params {
 notmuch_bool_t entire_thread;
 notmuch_bool_t omit_excluded;
@@ -112,6 +117,12 @@ chomp_newline (char *str)
str[strlen(str)-1] = '\0';
 }
 
+notmuch_crypto_context_t *
+notmuch_crypto_get_context (notmuch_crypto_t *crypto, const char *protocol);
+
+int
+notmuch_crypto_cleanup (notmuch_crypto_t *crypto);
+
 int
 notmuch_count_command (void *ctx, int argc, char *argv[]);
 
-- 
1.7.10

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


[PATCH v5 4/7] cli: modify mime_node_open to take new crypto struct as argument

2012-05-26 Thread Jameson Graef Rollins
This simplifies the interface considerably.
---
 mime-node.c  |7 +++
 notmuch-client.h |   10 +-
 notmuch-reply.c  |6 ++
 notmuch-show.c   |3 +--
 4 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index a5645e5..67f4b16 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -57,8 +57,7 @@ _mime_node_context_free (mime_node_context_t *res)
 
 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-   notmuch_crypto_context_t *cryptoctx,
-   notmuch_bool_t decrypt, mime_node_t **root_out)
+   notmuch_crypto_t *crypto, mime_node_t **root_out)
 {
 const char *filename = notmuch_message_get_filename (message);
 mime_node_context_t *mctx;
@@ -110,8 +109,8 @@ mime_node_open (const void *ctx, notmuch_message_t *message,
goto DONE;
 }
 
-mctx->cryptoctx = cryptoctx;
-mctx->decrypt = decrypt;
+mctx->cryptoctx = crypto->gpgctx;
+mctx->decrypt = crypto->decrypt;
 
 /* Create the root node */
 root->part = GMIME_OBJECT (mctx->mime_message);
diff --git a/notmuch-client.h b/notmuch-client.h
index ead7fbd..962c747 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -350,9 +350,10 @@ struct mime_node {
 };
 
 /* Construct a new MIME node pointing to the root message part of
- * message.  If cryptoctx is non-NULL, it will be used to verify
- * signatures on any child parts.  If decrypt is true, then cryptoctx
- * will additionally be used to decrypt any encrypted child parts.
+ * message.  If crypto->gpgctx is non-NULL, it will be used to verify
+ * signatures on any child parts.  If crypto->decrypt is true, then
+ * crypto.gpgctx will additionally be used to decrypt any encrypted
+ * child parts.
  *
  * Return value:
  *
@@ -364,8 +365,7 @@ struct mime_node {
  */
 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-   notmuch_crypto_context_t *cryptoctx,
-   notmuch_bool_t decrypt, mime_node_t **node_out);
+   notmuch_crypto_t *crypto, mime_node_t **node_out);
 
 /* Return a new MIME node for the requested child part of parent.
  * parent will be used as the talloc context for the returned child
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 11f269f..6f368c9 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -575,8 +575,7 @@ notmuch_reply_format_default(void *ctx,
g_object_unref (G_OBJECT (reply));
reply = NULL;
 
-   if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
-   &root) == NOTMUCH_STATUS_SUCCESS) {
+   if (mime_node_open (ctx, message, &(params->crypto), &root) == 
NOTMUCH_STATUS_SUCCESS) {
format_part_reply (root);
talloc_free (root);
}
@@ -605,8 +604,7 @@ notmuch_reply_format_json(void *ctx,
 
 messages = notmuch_query_search_messages (query);
 message = notmuch_messages_get (messages);
-if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
-   &node) != NOTMUCH_STATUS_SUCCESS)
+if (mime_node_open (ctx, message, &(params->crypto), &node) != 
NOTMUCH_STATUS_SUCCESS)
return 1;
 
 reply = create_reply_message (ctx, config, message, reply_all);
diff --git a/notmuch-show.c b/notmuch-show.c
index cc509a6..fb5e9b6 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -810,8 +810,7 @@ show_message (void *ctx,
 mime_node_t *root, *part;
 notmuch_status_t status;
 
-status = mime_node_open (local, message, params->crypto.gpgctx,
-params->crypto.decrypt, &root);
+status = mime_node_open (local, message, &(params->crypto), &root);
 if (status)
goto DONE;
 part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
-- 
1.7.10

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


[PATCH v5 7/7] cli: use new notmuch_crypto_get_context in mime-node.c

2012-05-26 Thread Jameson Graef Rollins
This has the affect of lazily creating the crypto contexts only when
needed.  This removes code duplication from notmuch-show and
notmuch-reply, and should speed up these functions considerably if the
crypto flags are provided but the messages don't have any
cryptographic parts.
---
 mime-node.c  |   20 ++--
 notmuch-client.h |3 ++-
 notmuch-reply.c  |   19 ---
 notmuch-show.c   |   23 ---
 4 files changed, 16 insertions(+), 49 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index 73e28c5..97e8b48 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -150,6 +150,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 {
 mime_node_t *node = talloc_zero (parent, mime_node_t);
 GError *err = NULL;
+notmuch_crypto_context_t *cryptoctx = NULL;
 
 /* Set basic node properties */
 node->part = part;
@@ -182,8 +183,15 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
return NULL;
 }
 
+if ((GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt)
+   || (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify)) {
+   GMimeContentType *content_type = g_mime_object_get_content_type (part);
+   const char *protocol = g_mime_content_type_get_parameter (content_type, 
"protocol");
+   cryptoctx = notmuch_crypto_get_context (node->ctx->crypto, protocol);
+}
+
 /* Handle PGP/MIME parts */
-if (GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt) {
+if (GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt && 
cryptoctx) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 4, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
@@ -196,10 +204,10 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 #ifdef GMIME_ATLEAST_26
GMimeDecryptResult *decrypt_result = NULL;
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->crypto->gpgctx, &decrypt_result, 
&err);
+   (encrypteddata, cryptoctx, &decrypt_result, &err);
 #else
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->crypto->gpgctx, &err);
+   (encrypteddata, cryptoctx, &err);
 #endif
if (node->decrypted_child) {
node->decrypt_success = node->verify_attempted = TRUE;
@@ -217,7 +225,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 (err ? err->message : "no error explanation given"));
}
}
-} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify) {
+} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify 
&& cryptoctx) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 5, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
@@ -226,7 +234,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
} else {
 #ifdef GMIME_ATLEAST_26
node->sig_list = g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
+   (GMIME_MULTIPART_SIGNED (part), cryptoctx, &err);
node->verify_attempted = TRUE;
 
if (!node->sig_list)
@@ -242,7 +250,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 * In GMime 2.6, they're both non-const, so we'll be able
 * to clean up this asymmetry. */
GMimeSignatureValidity *sig_validity = 
g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
+   (GMIME_MULTIPART_SIGNED (part), cryptoctx, &err);
node->verify_attempted = TRUE;
node->sig_validity = sig_validity;
if (sig_validity) {
diff --git a/notmuch-client.h b/notmuch-client.h
index 0f29a83..9b63eae 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -353,7 +353,8 @@ struct mime_node {
 /* Construct a new MIME node pointing to the root message part of
  * message. If crypto->verify is true, signed child parts will be
  * verified. If crypto->decrypt is true, encrypted child parts will be
- * decrypted.
+ * decrypted.  If crypto->gpgctx is NULL, it will be lazily
+ * initialized.
  *
  * Return value:
  *
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 1ab3db9..3a038ed 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -741,25 +741,6 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 else
reply_format_func = notmuch_reply_format_default;
 
-if (params.crypto.decrypt) {
-#ifdef GMIME_ATLEAST_26
-   /* TODO: GMimePasswordRequestFunc */
-   params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg");
-#else
-   GMimeSession* session = g_object

[PATCH v5 0/7] cli: improved crypto internals

2012-05-26 Thread Jameson Graef Rollins
I'm not going to claim this is the last version, but I think it
addresses the remaining comments.  I implemented Austin's of
introducing a new type to handle the gmime 2.4/2.6 context
incompatibility.

jamie.

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


[PATCH v5 5/7] cli: modify mime_node_context to use the new crypto struct

2012-05-26 Thread Jameson Graef Rollins
This simplifies some more interfaces.
---
 mime-node.c |   18 --
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index 67f4b16..a838224 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -33,8 +33,7 @@ typedef struct mime_node_context {
 GMimeMessage *mime_message;
 
 /* Context provided by the caller. */
-notmuch_crypto_context_t *cryptoctx;
-notmuch_bool_t decrypt;
+notmuch_crypto_t *crypto;
 } mime_node_context_t;
 
 static int
@@ -109,8 +108,7 @@ mime_node_open (const void *ctx, notmuch_message_t *message,
goto DONE;
 }
 
-mctx->cryptoctx = crypto->gpgctx;
-mctx->decrypt = crypto->decrypt;
+mctx->crypto = crypto;
 
 /* Create the root node */
 root->part = GMIME_OBJECT (mctx->mime_message);
@@ -186,7 +184,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 
 /* Handle PGP/MIME parts */
 if (GMIME_IS_MULTIPART_ENCRYPTED (part)
-   && node->ctx->cryptoctx && node->ctx->decrypt) {
+   && node->ctx->crypto->gpgctx && node->ctx->crypto->decrypt) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 4, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
@@ -199,10 +197,10 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 #ifdef GMIME_ATLEAST_26
GMimeDecryptResult *decrypt_result = NULL;
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->cryptoctx, &decrypt_result, &err);
+   (encrypteddata, node->ctx->crypto->gpgctx, &decrypt_result, 
&err);
 #else
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->cryptoctx, &err);
+   (encrypteddata, node->ctx->crypto->gpgctx, &err);
 #endif
if (node->decrypted_child) {
node->decrypt_success = node->verify_attempted = TRUE;
@@ -220,7 +218,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 (err ? err->message : "no error explanation given"));
}
}
-} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->cryptoctx) {
+} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->gpgctx) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 5, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
@@ -229,7 +227,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
} else {
 #ifdef GMIME_ATLEAST_26
node->sig_list = g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->cryptoctx, &err);
+   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
node->verify_attempted = TRUE;
 
if (!node->sig_list)
@@ -245,7 +243,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 * In GMime 2.6, they're both non-const, so we'll be able
 * to clean up this asymmetry. */
GMimeSignatureValidity *sig_validity = 
g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->cryptoctx, &err);
+   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
node->verify_attempted = TRUE;
node->sig_validity = sig_validity;
if (sig_validity) {
-- 
1.7.10

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


[PATCH v5 3/7] cli: modify show and reply to use new crypto struct

2012-05-26 Thread Jameson Graef Rollins
notmuch_show_params_t is modified to use the new notmuch_crypto_t, and
notmuch-show and notmuch-reply are modified accordingly.
---
 notmuch-client.h |3 +--
 notmuch-reply.c  |   29 -
 notmuch-show.c   |   30 +-
 3 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 6664075..ead7fbd 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -87,8 +87,7 @@ typedef struct notmuch_show_params {
 notmuch_bool_t omit_excluded;
 notmuch_bool_t raw;
 int part;
-notmuch_crypto_context_t* cryptoctx;
-notmuch_bool_t decrypt;
+notmuch_crypto_t crypto;
 } notmuch_show_params_t;
 
 /* There's no point in continuing when we've detected that we've done
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 0f92a2e..11f269f 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -575,7 +575,7 @@ notmuch_reply_format_default(void *ctx,
g_object_unref (G_OBJECT (reply));
reply = NULL;
 
-   if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,
+   if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
&root) == NOTMUCH_STATUS_SUCCESS) {
format_part_reply (root);
talloc_free (root);
@@ -605,7 +605,7 @@ notmuch_reply_format_json(void *ctx,
 
 messages = notmuch_query_search_messages (query);
 message = notmuch_messages_get (messages);
-if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,
+if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
&node) != NOTMUCH_STATUS_SUCCESS)
return 1;
 
@@ -706,7 +706,12 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 char *query_string;
 int opt_index, ret = 0;
 int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
reply_all);
-notmuch_show_params_t params = { .part = -1 };
+notmuch_show_params_t params = {
+   .part = -1,
+   .crypto = {
+   .decrypt = FALSE
+   }
+};
 int format = FORMAT_DEFAULT;
 int reply_all = TRUE;
 
@@ -720,7 +725,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  (notmuch_keyword_t []){ { "all", TRUE },
  { "sender", FALSE },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.decrypt, "decrypt", 'd', 0 },
{ 0, 0, 0, 0, 0 }
 };
 
@@ -737,18 +742,18 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 else
reply_format_func = notmuch_reply_format_default;
 
-if (params.decrypt) {
+if (params.crypto.decrypt) {
 #ifdef GMIME_ATLEAST_26
/* TODO: GMimePasswordRequestFunc */
-   params.cryptoctx = g_mime_gpg_context_new (NULL, "gpg");
+   params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg");
 #else
GMimeSession* session = g_object_new (g_mime_session_get_type(), NULL);
-   params.cryptoctx = g_mime_gpg_context_new (session, "gpg");
+   params.crypto.gpgctx = g_mime_gpg_context_new (session, "gpg");
 #endif
-   if (params.cryptoctx) {
-   g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.cryptoctx, FALSE);
+   if (params.crypto.gpgctx) {
+   g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.crypto.gpgctx, FALSE);
} else {
-   params.decrypt = FALSE;
+   params.crypto.decrypt = FALSE;
fprintf (stderr, "Failed to construct gpg context.\n");
}
 #ifndef GMIME_ATLEAST_26
@@ -784,11 +789,9 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 if (reply_format_func (ctx, config, query, ¶ms, reply_all) != 0)
return 1;
 
+notmuch_crypto_cleanup (¶ms.crypto);
 notmuch_query_destroy (query);
 notmuch_database_destroy (notmuch);
 
-if (params.cryptoctx)
-   g_object_unref(params.cryptoctx);
-
 return ret;
 }
diff --git a/notmuch-show.c b/notmuch-show.c
index 95427d4..cc509a6 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -810,8 +810,8 @@ show_message (void *ctx,
 mime_node_t *root, *part;
 notmuch_status_t status;
 
-status = mime_node_open (local, message, params->cryptoctx,
-params->decrypt, &root);
+status = mime_node_open (local, message, params->crypto.gpgctx,
+params->crypto.decrypt, &root);
 if (status)
goto DONE;
 part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
@@ -984,7 +984,13 @@ notmuch_show_command (void *ctx, unused (int argc), unused 
(char *argv[]))
 char *query_string;
 int opt_index, ret;
 const notmuch_show_format_t *format = &format_text;
-notmuch_show_params_t params = { .part = -1, .om

[PATCH v5 1/7] cli: use new typedef to deal with gmime 2.4/2.6 context incompatibility

2012-05-26 Thread Jameson Graef Rollins
gmime 2.4 defines GMimeCipherContext, while 2.6 defines
GMimeCryptoContext.  typedef them both to notmuch_crypto_context_t to
cover this discrepancy and remove a bunch of #ifdefs.
---
 mime-node.c  |   12 ++--
 notmuch-client.h |   15 +--
 2 files changed, 7 insertions(+), 20 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index a95bdab..a5645e5 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -33,11 +33,7 @@ typedef struct mime_node_context {
 GMimeMessage *mime_message;
 
 /* Context provided by the caller. */
-#ifdef GMIME_ATLEAST_26
-GMimeCryptoContext *cryptoctx;
-#else
-GMimeCipherContext *cryptoctx;
-#endif
+notmuch_crypto_context_t *cryptoctx;
 notmuch_bool_t decrypt;
 } mime_node_context_t;
 
@@ -61,11 +57,7 @@ _mime_node_context_free (mime_node_context_t *res)
 
 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-#ifdef GMIME_ATLEAST_26
-   GMimeCryptoContext *cryptoctx,
-#else
-   GMimeCipherContext *cryptoctx,
-#endif
+   notmuch_crypto_context_t *cryptoctx,
notmuch_bool_t decrypt, mime_node_t **root_out)
 {
 const char *filename = notmuch_message_get_filename (message);
diff --git a/notmuch-client.h b/notmuch-client.h
index 19b7f01..d377b04 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -36,6 +36,9 @@
  * these to check the version number. */
 #ifdef GMIME_MAJOR_VERSION
 #define GMIME_ATLEAST_26
+typedef GMimeCryptoContext notmuch_crypto_context_t;
+#else
+typedef GMimeCipherContext notmuch_crypto_context_t;
 #endif
 
 #include "notmuch.h"
@@ -79,11 +82,7 @@ typedef struct notmuch_show_params {
 notmuch_bool_t omit_excluded;
 notmuch_bool_t raw;
 int part;
-#ifdef GMIME_ATLEAST_26
-GMimeCryptoContext* cryptoctx;
-#else
-GMimeCipherContext* cryptoctx;
-#endif
+notmuch_crypto_context_t* cryptoctx;
 notmuch_bool_t decrypt;
 } notmuch_show_params_t;
 
@@ -355,11 +354,7 @@ struct mime_node {
  */
 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-#ifdef GMIME_ATLEAST_26
-   GMimeCryptoContext *cryptoctx,
-#else
-   GMimeCipherContext *cryptoctx,
-#endif
+   notmuch_crypto_context_t *cryptoctx,
notmuch_bool_t decrypt, mime_node_t **node_out);
 
 /* Return a new MIME node for the requested child part of parent.
-- 
1.7.10

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


[PATCH v5 7/7] cli: use new notmuch_crypto_get_context in mime-node.c

2012-05-26 Thread Jameson Graef Rollins
This has the affect of lazily creating the crypto contexts only when
needed.  This removes code duplication from notmuch-show and
notmuch-reply, and should speed up these functions considerably if the
crypto flags are provided but the messages don't have any
cryptographic parts.
---
 mime-node.c  |   20 ++--
 notmuch-client.h |3 ++-
 notmuch-reply.c  |   19 ---
 notmuch-show.c   |   23 ---
 4 files changed, 16 insertions(+), 49 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index 73e28c5..97e8b48 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -150,6 +150,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 {
 mime_node_t *node = talloc_zero (parent, mime_node_t);
 GError *err = NULL;
+notmuch_crypto_context_t *cryptoctx = NULL;

 /* Set basic node properties */
 node->part = part;
@@ -182,8 +183,15 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
return NULL;
 }

+if ((GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt)
+   || (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify)) {
+   GMimeContentType *content_type = g_mime_object_get_content_type (part);
+   const char *protocol = g_mime_content_type_get_parameter (content_type, 
"protocol");
+   cryptoctx = notmuch_crypto_get_context (node->ctx->crypto, protocol);
+}
+
 /* Handle PGP/MIME parts */
-if (GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt) {
+if (GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt && 
cryptoctx) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 4, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
@@ -196,10 +204,10 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 #ifdef GMIME_ATLEAST_26
GMimeDecryptResult *decrypt_result = NULL;
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->crypto->gpgctx, &decrypt_result, 
&err);
+   (encrypteddata, cryptoctx, &decrypt_result, &err);
 #else
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->crypto->gpgctx, &err);
+   (encrypteddata, cryptoctx, &err);
 #endif
if (node->decrypted_child) {
node->decrypt_success = node->verify_attempted = TRUE;
@@ -217,7 +225,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 (err ? err->message : "no error explanation given"));
}
}
-} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify) {
+} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify 
&& cryptoctx) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 5, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
@@ -226,7 +234,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
} else {
 #ifdef GMIME_ATLEAST_26
node->sig_list = g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
+   (GMIME_MULTIPART_SIGNED (part), cryptoctx, &err);
node->verify_attempted = TRUE;

if (!node->sig_list)
@@ -242,7 +250,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 * In GMime 2.6, they're both non-const, so we'll be able
 * to clean up this asymmetry. */
GMimeSignatureValidity *sig_validity = 
g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
+   (GMIME_MULTIPART_SIGNED (part), cryptoctx, &err);
node->verify_attempted = TRUE;
node->sig_validity = sig_validity;
if (sig_validity) {
diff --git a/notmuch-client.h b/notmuch-client.h
index 0f29a83..9b63eae 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -353,7 +353,8 @@ struct mime_node {
 /* Construct a new MIME node pointing to the root message part of
  * message. If crypto->verify is true, signed child parts will be
  * verified. If crypto->decrypt is true, encrypted child parts will be
- * decrypted.
+ * decrypted.  If crypto->gpgctx is NULL, it will be lazily
+ * initialized.
  *
  * Return value:
  *
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 1ab3db9..3a038ed 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -741,25 +741,6 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 else
reply_format_func = notmuch_reply_format_default;

-if (params.crypto.decrypt) {
-#ifdef GMIME_ATLEAST_26
-   /* TODO: GMimePasswordRequestFunc */
-   params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg");
-#else
-   GMimeSession* session = g_object_new

[PATCH v5 6/7] cli: new crypto verify flag to handle verification

2012-05-26 Thread Jameson Graef Rollins
Use this flag rather than depend on the existence of an initialized
gpgctx, to determine whether we should verify a multipart/signed.  We
will be moving to create the ctx lazily, so we don't want to depend on
it being previously initialized if it's not needed.
---
 mime-node.c  |5 ++---
 notmuch-client.h |8 
 notmuch-reply.c  |1 +
 notmuch-show.c   |   14 +++---
 4 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index a838224..73e28c5 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -183,8 +183,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 }

 /* Handle PGP/MIME parts */
-if (GMIME_IS_MULTIPART_ENCRYPTED (part)
-   && node->ctx->crypto->gpgctx && node->ctx->crypto->decrypt) {
+if (GMIME_IS_MULTIPART_ENCRYPTED (part) && node->ctx->crypto->decrypt) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 4, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
@@ -218,7 +217,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 (err ? err->message : "no error explanation given"));
}
}
-} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->gpgctx) {
+} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 5, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
diff --git a/notmuch-client.h b/notmuch-client.h
index 962c747..0f29a83 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -79,6 +79,7 @@ typedef struct notmuch_show_format {

 typedef struct notmuch_crypto {
 notmuch_crypto_context_t* gpgctx;
+notmuch_bool_t verify;
 notmuch_bool_t decrypt;
 } notmuch_crypto_t;

@@ -350,10 +351,9 @@ struct mime_node {
 };

 /* Construct a new MIME node pointing to the root message part of
- * message.  If crypto->gpgctx is non-NULL, it will be used to verify
- * signatures on any child parts.  If crypto->decrypt is true, then
- * crypto.gpgctx will additionally be used to decrypt any encrypted
- * child parts.
+ * message. If crypto->verify is true, signed child parts will be
+ * verified. If crypto->decrypt is true, encrypted child parts will be
+ * decrypted.
  *
  * Return value:
  *
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 6f368c9..1ab3db9 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -707,6 +707,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 notmuch_show_params_t params = {
.part = -1,
.crypto = {
+   .verify = FALSE,
.decrypt = FALSE
}
 };
diff --git a/notmuch-show.c b/notmuch-show.c
index fb5e9b6..3c06792 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -987,11 +987,11 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
.part = -1,
.omit_excluded = TRUE,
.crypto = {
+   .verify = FALSE,
.decrypt = FALSE
}
 };
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
-notmuch_bool_t verify = FALSE;
 int exclude = EXCLUDE_TRUE;

 notmuch_opt_desc_t options[] = {
@@ -1008,7 +1008,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.decrypt, "decrypt", 'd', 0 },
-   { NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.verify, "verify", 'v', 0 },
{ 0, 0, 0, 0, 0 }
 };

@@ -1018,6 +1018,10 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
return 1;
 }

+/* decryption implies verification */
+if (params.crypto.decrypt)
+   params.crypto.verify = TRUE;
+
 if (format_sel == NOTMUCH_FORMAT_NOT_SPECIFIED) {
/* if part was requested and format was not specified, use format=raw */
if (params.part >= 0)
@@ -1052,7 +1056,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
break;
 }

-if (params.crypto.decrypt || verify) {
+if (params.crypto.decrypt || params.crypto.verify) {
 #ifdef GMIME_ATLEAST_26
/* TODO: GMimePasswordRequestFunc */
params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg");
@@ -1063,6 +1067,10 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
if (params.crypto.gpgctx) {
g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.crypto.gpgctx, FALSE);
} else {
+   /* If we fail to create the gpgctx set the verify and
+* decrypt flags to FALSE so we don't try to do any
+* further verification or decryption */
+

[PATCH v5 5/7] cli: modify mime_node_context to use the new crypto struct

2012-05-26 Thread Jameson Graef Rollins
This simplifies some more interfaces.
---
 mime-node.c |   18 --
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index 67f4b16..a838224 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -33,8 +33,7 @@ typedef struct mime_node_context {
 GMimeMessage *mime_message;

 /* Context provided by the caller. */
-notmuch_crypto_context_t *cryptoctx;
-notmuch_bool_t decrypt;
+notmuch_crypto_t *crypto;
 } mime_node_context_t;

 static int
@@ -109,8 +108,7 @@ mime_node_open (const void *ctx, notmuch_message_t *message,
goto DONE;
 }

-mctx->cryptoctx = crypto->gpgctx;
-mctx->decrypt = crypto->decrypt;
+mctx->crypto = crypto;

 /* Create the root node */
 root->part = GMIME_OBJECT (mctx->mime_message);
@@ -186,7 +184,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)

 /* Handle PGP/MIME parts */
 if (GMIME_IS_MULTIPART_ENCRYPTED (part)
-   && node->ctx->cryptoctx && node->ctx->decrypt) {
+   && node->ctx->crypto->gpgctx && node->ctx->crypto->decrypt) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 4, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/encrypted "
@@ -199,10 +197,10 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 #ifdef GMIME_ATLEAST_26
GMimeDecryptResult *decrypt_result = NULL;
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->cryptoctx, &decrypt_result, &err);
+   (encrypteddata, node->ctx->crypto->gpgctx, &decrypt_result, 
&err);
 #else
node->decrypted_child = g_mime_multipart_encrypted_decrypt
-   (encrypteddata, node->ctx->cryptoctx, &err);
+   (encrypteddata, node->ctx->crypto->gpgctx, &err);
 #endif
if (node->decrypted_child) {
node->decrypt_success = node->verify_attempted = TRUE;
@@ -220,7 +218,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 (err ? err->message : "no error explanation given"));
}
}
-} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->cryptoctx) {
+} else if (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->gpgctx) {
if (node->nchildren != 2) {
/* this violates RFC 3156 section 5, so we won't bother with it. */
fprintf (stderr, "Error: %d part(s) for a multipart/signed message "
@@ -229,7 +227,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
} else {
 #ifdef GMIME_ATLEAST_26
node->sig_list = g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->cryptoctx, &err);
+   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
node->verify_attempted = TRUE;

if (!node->sig_list)
@@ -245,7 +243,7 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)
 * In GMime 2.6, they're both non-const, so we'll be able
 * to clean up this asymmetry. */
GMimeSignatureValidity *sig_validity = 
g_mime_multipart_signed_verify
-   (GMIME_MULTIPART_SIGNED (part), node->ctx->cryptoctx, &err);
+   (GMIME_MULTIPART_SIGNED (part), node->ctx->crypto->gpgctx, 
&err);
node->verify_attempted = TRUE;
node->sig_validity = sig_validity;
if (sig_validity) {
-- 
1.7.10



[PATCH v5 4/7] cli: modify mime_node_open to take new crypto struct as argument

2012-05-26 Thread Jameson Graef Rollins
This simplifies the interface considerably.
---
 mime-node.c  |7 +++
 notmuch-client.h |   10 +-
 notmuch-reply.c  |6 ++
 notmuch-show.c   |3 +--
 4 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index a5645e5..67f4b16 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -57,8 +57,7 @@ _mime_node_context_free (mime_node_context_t *res)

 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-   notmuch_crypto_context_t *cryptoctx,
-   notmuch_bool_t decrypt, mime_node_t **root_out)
+   notmuch_crypto_t *crypto, mime_node_t **root_out)
 {
 const char *filename = notmuch_message_get_filename (message);
 mime_node_context_t *mctx;
@@ -110,8 +109,8 @@ mime_node_open (const void *ctx, notmuch_message_t *message,
goto DONE;
 }

-mctx->cryptoctx = cryptoctx;
-mctx->decrypt = decrypt;
+mctx->cryptoctx = crypto->gpgctx;
+mctx->decrypt = crypto->decrypt;

 /* Create the root node */
 root->part = GMIME_OBJECT (mctx->mime_message);
diff --git a/notmuch-client.h b/notmuch-client.h
index ead7fbd..962c747 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -350,9 +350,10 @@ struct mime_node {
 };

 /* Construct a new MIME node pointing to the root message part of
- * message.  If cryptoctx is non-NULL, it will be used to verify
- * signatures on any child parts.  If decrypt is true, then cryptoctx
- * will additionally be used to decrypt any encrypted child parts.
+ * message.  If crypto->gpgctx is non-NULL, it will be used to verify
+ * signatures on any child parts.  If crypto->decrypt is true, then
+ * crypto.gpgctx will additionally be used to decrypt any encrypted
+ * child parts.
  *
  * Return value:
  *
@@ -364,8 +365,7 @@ struct mime_node {
  */
 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-   notmuch_crypto_context_t *cryptoctx,
-   notmuch_bool_t decrypt, mime_node_t **node_out);
+   notmuch_crypto_t *crypto, mime_node_t **node_out);

 /* Return a new MIME node for the requested child part of parent.
  * parent will be used as the talloc context for the returned child
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 11f269f..6f368c9 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -575,8 +575,7 @@ notmuch_reply_format_default(void *ctx,
g_object_unref (G_OBJECT (reply));
reply = NULL;

-   if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
-   &root) == NOTMUCH_STATUS_SUCCESS) {
+   if (mime_node_open (ctx, message, &(params->crypto), &root) == 
NOTMUCH_STATUS_SUCCESS) {
format_part_reply (root);
talloc_free (root);
}
@@ -605,8 +604,7 @@ notmuch_reply_format_json(void *ctx,

 messages = notmuch_query_search_messages (query);
 message = notmuch_messages_get (messages);
-if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
-   &node) != NOTMUCH_STATUS_SUCCESS)
+if (mime_node_open (ctx, message, &(params->crypto), &node) != 
NOTMUCH_STATUS_SUCCESS)
return 1;

 reply = create_reply_message (ctx, config, message, reply_all);
diff --git a/notmuch-show.c b/notmuch-show.c
index cc509a6..fb5e9b6 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -810,8 +810,7 @@ show_message (void *ctx,
 mime_node_t *root, *part;
 notmuch_status_t status;

-status = mime_node_open (local, message, params->crypto.gpgctx,
-params->crypto.decrypt, &root);
+status = mime_node_open (local, message, &(params->crypto), &root);
 if (status)
goto DONE;
 part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
-- 
1.7.10



[PATCH v5 3/7] cli: modify show and reply to use new crypto struct

2012-05-26 Thread Jameson Graef Rollins
notmuch_show_params_t is modified to use the new notmuch_crypto_t, and
notmuch-show and notmuch-reply are modified accordingly.
---
 notmuch-client.h |3 +--
 notmuch-reply.c  |   29 -
 notmuch-show.c   |   30 +-
 3 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 6664075..ead7fbd 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -87,8 +87,7 @@ typedef struct notmuch_show_params {
 notmuch_bool_t omit_excluded;
 notmuch_bool_t raw;
 int part;
-notmuch_crypto_context_t* cryptoctx;
-notmuch_bool_t decrypt;
+notmuch_crypto_t crypto;
 } notmuch_show_params_t;

 /* There's no point in continuing when we've detected that we've done
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 0f92a2e..11f269f 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -575,7 +575,7 @@ notmuch_reply_format_default(void *ctx,
g_object_unref (G_OBJECT (reply));
reply = NULL;

-   if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,
+   if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
&root) == NOTMUCH_STATUS_SUCCESS) {
format_part_reply (root);
talloc_free (root);
@@ -605,7 +605,7 @@ notmuch_reply_format_json(void *ctx,

 messages = notmuch_query_search_messages (query);
 message = notmuch_messages_get (messages);
-if (mime_node_open (ctx, message, params->cryptoctx, params->decrypt,
+if (mime_node_open (ctx, message, params->crypto.gpgctx, 
params->crypto.decrypt,
&node) != NOTMUCH_STATUS_SUCCESS)
return 1;

@@ -706,7 +706,12 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 char *query_string;
 int opt_index, ret = 0;
 int (*reply_format_func)(void *ctx, notmuch_config_t *config, 
notmuch_query_t *query, notmuch_show_params_t *params, notmuch_bool_t 
reply_all);
-notmuch_show_params_t params = { .part = -1 };
+notmuch_show_params_t params = {
+   .part = -1,
+   .crypto = {
+   .decrypt = FALSE
+   }
+};
 int format = FORMAT_DEFAULT;
 int reply_all = TRUE;

@@ -720,7 +725,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  (notmuch_keyword_t []){ { "all", TRUE },
  { "sender", FALSE },
  { 0, 0 } } },
-   { NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
+   { NOTMUCH_OPT_BOOLEAN, ¶ms.crypto.decrypt, "decrypt", 'd', 0 },
{ 0, 0, 0, 0, 0 }
 };

@@ -737,18 +742,18 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 else
reply_format_func = notmuch_reply_format_default;

-if (params.decrypt) {
+if (params.crypto.decrypt) {
 #ifdef GMIME_ATLEAST_26
/* TODO: GMimePasswordRequestFunc */
-   params.cryptoctx = g_mime_gpg_context_new (NULL, "gpg");
+   params.crypto.gpgctx = g_mime_gpg_context_new (NULL, "gpg");
 #else
GMimeSession* session = g_object_new (g_mime_session_get_type(), NULL);
-   params.cryptoctx = g_mime_gpg_context_new (session, "gpg");
+   params.crypto.gpgctx = g_mime_gpg_context_new (session, "gpg");
 #endif
-   if (params.cryptoctx) {
-   g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.cryptoctx, FALSE);
+   if (params.crypto.gpgctx) {
+   g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
params.crypto.gpgctx, FALSE);
} else {
-   params.decrypt = FALSE;
+   params.crypto.decrypt = FALSE;
fprintf (stderr, "Failed to construct gpg context.\n");
}
 #ifndef GMIME_ATLEAST_26
@@ -784,11 +789,9 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
 if (reply_format_func (ctx, config, query, ¶ms, reply_all) != 0)
return 1;

+notmuch_crypto_cleanup (¶ms.crypto);
 notmuch_query_destroy (query);
 notmuch_database_destroy (notmuch);

-if (params.cryptoctx)
-   g_object_unref(params.cryptoctx);
-
 return ret;
 }
diff --git a/notmuch-show.c b/notmuch-show.c
index 95427d4..cc509a6 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -810,8 +810,8 @@ show_message (void *ctx,
 mime_node_t *root, *part;
 notmuch_status_t status;

-status = mime_node_open (local, message, params->cryptoctx,
-params->decrypt, &root);
+status = mime_node_open (local, message, params->crypto.gpgctx,
+params->crypto.decrypt, &root);
 if (status)
goto DONE;
 part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part));
@@ -984,7 +984,13 @@ notmuch_show_command (void *ctx, unused (int argc), unused 
(char *argv[]))
 char *query_string;
 int opt_index, ret;
 const notmuch_show_format_t *format = &format_text;
-notmuch_show_params_t params = { .part = -1, .omit_exclude

[PATCH v5 2/7] cli: new crypto structure to store crypto contexts and parameters, and functions to support it

2012-05-26 Thread Jameson Graef Rollins
This new structure, notmuch_crypto_t, keeps all relevant crypto
contexts and parameters together, and will make it easier to pass the
stuff around and clean it up.  The name of the crypto context inside
this new struct will change, to reflect that it is actually a GPG
context, which is a sub type of Crypto context.  There are other types
of Crypto contexts (Pkcs7 in particular, which we hope to support) so
we want to be clear.

The new crypto.c contains functions to return the proper context from
the struct for a given protocol (and initialize it if needed), and to
cleanup a struct by releasing the crypto contexts.
---
 Makefile.local   |1 +
 crypto.c |   71 ++
 notmuch-client.h |   11 +
 3 files changed, 83 insertions(+)
 create mode 100644 crypto.c

diff --git a/Makefile.local b/Makefile.local
index 53b4a0d..a890df2 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -292,6 +292,7 @@ notmuch_client_srcs =   \
notmuch-time.c  \
query-string.c  \
mime-node.c \
+   crypto.c\
json.c

 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
diff --git a/crypto.c b/crypto.c
new file mode 100644
index 000..fbe5aeb
--- /dev/null
+++ b/crypto.c
@@ -0,0 +1,71 @@
+/* notmuch - Not much of an email program, (just index and search)
+ *
+ * Copyright ? 2012 Jameson Rollins
+ *
+ * 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/ .
+ *
+ * Authors: Jameson Rollins 
+ */
+
+#include "notmuch-client.h"
+
+/* for the specified protocol return the context pointer (initializing
+ * if needed) */
+notmuch_crypto_context_t *
+notmuch_crypto_get_context (notmuch_crypto_t *crypto, const char *protocol)
+{
+notmuch_crypto_context_t *cryptoctx = NULL;
+
+/* As per RFC 1847 section 2.1: "the [protocol] value token is
+ * comprised of the type and sub-type tokens of the Content-Type".
+ * As per RFC 1521 section 2: "Content-Type values, subtypes, and
+ * parameter names as defined in this document are
+ * case-insensitive."  Thus, we use strcasecmp for the protocol.
+ */
+if ((strcasecmp (protocol, "application/pgp-signature") == 0)
+   || (strcasecmp (protocol, "application/pgp-encrypted") == 0)) {
+   if (!crypto->gpgctx) {
+#ifdef GMIME_ATLEAST_26
+   /* TODO: GMimePasswordRequestFunc */
+   crypto->gpgctx = g_mime_gpg_context_new (NULL, "gpg");
+#else
+   GMimeSession* session = g_object_new (g_mime_session_get_type(), 
NULL);
+   crypto->gpgctx = g_mime_gpg_context_new (session, "gpg");
+   g_object_unref (session);
+#endif
+   if (crypto->gpgctx) {
+   g_mime_gpg_context_set_always_trust ((GMimeGpgContext*) 
crypto->gpgctx, FALSE);
+   } else {
+   fprintf (stderr, "Failed to construct gpg context.\n");
+   }
+   }
+   cryptoctx = crypto->gpgctx;
+
+} else {
+   fprintf (stderr, "Unknown or unsupported cryptographic protocol.\n");
+}
+
+return cryptoctx;
+}
+
+int
+notmuch_crypto_cleanup (notmuch_crypto_t *crypto)
+{
+if (crypto->gpgctx) {
+   g_object_unref (crypto->gpgctx);
+   crypto->gpgctx = NULL;
+}
+
+return 0;
+}
diff --git a/notmuch-client.h b/notmuch-client.h
index d377b04..6664075 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -77,6 +77,11 @@ typedef struct notmuch_show_format {
 const char *message_set_end;
 } notmuch_show_format_t;

+typedef struct notmuch_crypto {
+notmuch_crypto_context_t* gpgctx;
+notmuch_bool_t decrypt;
+} notmuch_crypto_t;
+
 typedef struct notmuch_show_params {
 notmuch_bool_t entire_thread;
 notmuch_bool_t omit_excluded;
@@ -112,6 +117,12 @@ chomp_newline (char *str)
str[strlen(str)-1] = '\0';
 }

+notmuch_crypto_context_t *
+notmuch_crypto_get_context (notmuch_crypto_t *crypto, const char *protocol);
+
+int
+notmuch_crypto_cleanup (notmuch_crypto_t *crypto);
+
 int
 notmuch_count_command (void *ctx, int argc, char *argv[]);

-- 
1.7.10



[PATCH v5 1/7] cli: use new typedef to deal with gmime 2.4/2.6 context incompatibility

2012-05-26 Thread Jameson Graef Rollins
gmime 2.4 defines GMimeCipherContext, while 2.6 defines
GMimeCryptoContext.  typedef them both to notmuch_crypto_context_t to
cover this discrepancy and remove a bunch of #ifdefs.
---
 mime-node.c  |   12 ++--
 notmuch-client.h |   15 +--
 2 files changed, 7 insertions(+), 20 deletions(-)

diff --git a/mime-node.c b/mime-node.c
index a95bdab..a5645e5 100644
--- a/mime-node.c
+++ b/mime-node.c
@@ -33,11 +33,7 @@ typedef struct mime_node_context {
 GMimeMessage *mime_message;

 /* Context provided by the caller. */
-#ifdef GMIME_ATLEAST_26
-GMimeCryptoContext *cryptoctx;
-#else
-GMimeCipherContext *cryptoctx;
-#endif
+notmuch_crypto_context_t *cryptoctx;
 notmuch_bool_t decrypt;
 } mime_node_context_t;

@@ -61,11 +57,7 @@ _mime_node_context_free (mime_node_context_t *res)

 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-#ifdef GMIME_ATLEAST_26
-   GMimeCryptoContext *cryptoctx,
-#else
-   GMimeCipherContext *cryptoctx,
-#endif
+   notmuch_crypto_context_t *cryptoctx,
notmuch_bool_t decrypt, mime_node_t **root_out)
 {
 const char *filename = notmuch_message_get_filename (message);
diff --git a/notmuch-client.h b/notmuch-client.h
index 19b7f01..d377b04 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -36,6 +36,9 @@
  * these to check the version number. */
 #ifdef GMIME_MAJOR_VERSION
 #define GMIME_ATLEAST_26
+typedef GMimeCryptoContext notmuch_crypto_context_t;
+#else
+typedef GMimeCipherContext notmuch_crypto_context_t;
 #endif

 #include "notmuch.h"
@@ -79,11 +82,7 @@ typedef struct notmuch_show_params {
 notmuch_bool_t omit_excluded;
 notmuch_bool_t raw;
 int part;
-#ifdef GMIME_ATLEAST_26
-GMimeCryptoContext* cryptoctx;
-#else
-GMimeCipherContext* cryptoctx;
-#endif
+notmuch_crypto_context_t* cryptoctx;
 notmuch_bool_t decrypt;
 } notmuch_show_params_t;

@@ -355,11 +354,7 @@ struct mime_node {
  */
 notmuch_status_t
 mime_node_open (const void *ctx, notmuch_message_t *message,
-#ifdef GMIME_ATLEAST_26
-   GMimeCryptoContext *cryptoctx,
-#else
-   GMimeCipherContext *cryptoctx,
-#endif
+   notmuch_crypto_context_t *cryptoctx,
notmuch_bool_t decrypt, mime_node_t **node_out);

 /* Return a new MIME node for the requested child part of parent.
-- 
1.7.10



[PATCH v5 0/7] cli: improved crypto internals

2012-05-26 Thread Jameson Graef Rollins
I'm not going to claim this is the last version, but I think it
addresses the remaining comments.  I implemented Austin's of
introducing a new type to handle the gmime 2.4/2.6 context
incompatibility.

jamie.



[PATCH v4 2/4] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread David Bremner
Mark Walters  writes:

> On Sat, 26 May 2012, Peter Wang  wrote:
>> On Tue, 24 Apr 2012 10:11:13 +0100, Mark Walters > gmail.com> wrote:
>
> It is easy to change the keyword parsing code to allow this: I include a
> first draft of such a patch below. This would allow the solution you
> suggest and thus avoid the hack/abuse.  What do people think?
>

It didn't carefully review it, but it looks sane enough at a quick
glance.

d


Re: [PATCH 1/2] Makefile.local: added checks for latest NEWS title

2012-05-26 Thread David Bremner
Tomi Ollila  writes:

> Added target `verify-version-news` which checks that the first line
> in NEWS file has the following properties:
> First word is 'Notmuch'
> Second "word" matches the current version
> Rest of line is in format (201[2-9]-[01][0-9]-[0-3][0-9]

I appreciate the effort, but I wonder if it is worth complicating the
build system further? I'm willing to be swayed either way.

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


[PATCH v4 2/4] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread Mark Walters

On Sat, 26 May 2012, Peter Wang  wrote:
> On Tue, 24 Apr 2012 10:11:13 +0100, Mark Walters  gmail.com> wrote:
>> The --entire-thread option in notmuch-show.c defaults to true when
>> format=json. Previously there was no way to turn this off. This patch
>> makes it respect --entire-thread=false.
>> 
>> The one subtlety is that we initialise a notmuch_bool_t to -1 to
>> indicate that the option parsing has not set it. This allows the code
>> to distinguish between the option being omitted from the command line,
>> and the option being set to false on the command line.
>> ---
>>  notmuch-show.c |   16 ++--
>>  1 files changed, 14 insertions(+), 2 deletions(-)
>> 
>> diff --git a/notmuch-show.c b/notmuch-show.c
>> index 0d21f1a..48551bb 100644
>> --- a/notmuch-show.c
>> +++ b/notmuch-show.c
>> @@ -996,7 +996,13 @@ notmuch_show_command (void *ctx, unused (int argc), 
>> unused (char *argv[]))
>>  char *query_string;
>>  int opt_index, ret;
>>  const notmuch_show_format_t *format = &format_text;
>> -notmuch_show_params_t params = { .part = -1, .omit_excluded = TRUE };
>> +
>> +/* We abuse the notmuch_bool_t variable params.entire-thread by
>> + * setting it to -1 to denote that the command line parsing has
>> + * not set it. We ensure it is set to TRUE or FALSE before passing
>> + * it to any other function.*/
>> +notmuch_show_params_t params = { .part = -1, .entire_thread = -1 };
>> +
>>  int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
>>  notmuch_bool_t verify = FALSE;
>>  int exclude = EXCLUDE_TRUE;
>
> Hi Mark,
>
> As an alternative to the abuse, could you just treat it as with exclude,
> using an enum with three values (TRUE|FALSE|DEFAULT)?
> Then set params.entire_thread afterwards.

The reason I haven't done this is that the current command line parser
does not allow keyword options to take default values: in other words
--entire-thread without an "=" would not be allowed.

It is easy to change the keyword parsing code to allow this: I include a
first draft of such a patch below. This would allow the solution you
suggest and thus avoid the hack/abuse.  What do people think?

Best wishes

Mark


---
 command-line-arguments.c |   13 ++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/command-line-arguments.c b/command-line-arguments.c
index 76b185f..d40c7e6 100644
--- a/command-line-arguments.c
+++ b/command-line-arguments.c
@@ -11,10 +11,16 @@
 */

 static notmuch_bool_t
-_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char *arg_str) 
{
+_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const 
char *arg_str) {

 const notmuch_keyword_t *keywords = arg_desc->keywords;

+if (next == 0) {
+/* No keyword given so return first option as default */
+   *((int *)arg_desc->output_var) = keywords->value;
+   return TRUE;
+}
+
 while (keywords->name) {
if (strcmp (arg_str, keywords->name) == 0) {
if (arg_desc->output_var) {
@@ -99,7 +105,8 @@ parse_option (const char *arg,
 */
if (next != '=' && next != ':' && next != 0) return FALSE;
if (next == 0) {
-   if (try->opt_type != NOTMUCH_OPT_BOOLEAN)
+   if (try->opt_type != NOTMUCH_OPT_BOOLEAN &&
+   try->opt_type != NOTMUCH_OPT_KEYWORD)
return FALSE;
} else {
if (value[0] == 0) return FALSE;
@@ -110,7 +117,7 @@ parse_option (const char *arg,

switch (try->opt_type) {
case NOTMUCH_OPT_KEYWORD:
-   return _process_keyword_arg (try, value);
+   return _process_keyword_arg (try, next, value);
break;
case NOTMUCH_OPT_BOOLEAN:
return _process_boolean_arg (try, next, value);
-- 
1.7.9.1



[PATCH v5 5/5] emacs: make elide messages use notmuch-show for omitting messages.

2012-05-26 Thread Mark Walters
Previously the elide messages code got the entire-thread from
notmuch-show.c and then threw away all non-matching messages. This
version calls notmuch-show.c without the --entire-thread flag so
it never receives the non-matching messages in the first place.

This makes it substantially faster.
---
 emacs/notmuch-show.el |   18 ++
 1 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index d318430..9cc68be 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -958,9 +958,9 @@ message at DEPTH in the current thread."
   "Insert the message tree TREE at depth DEPTH in the current thread."
   (let ((msg (car tree))
(replies (cadr tree)))
-(if (or (not notmuch-show-elide-non-matching-messages)
-   (plist-get msg :match))
-   (notmuch-show-insert-msg msg depth))
+;; We test whether there is a message or just some replies.
+(when msg
+  (notmuch-show-insert-msg msg depth))
 (notmuch-show-insert-thread replies (1+ depth
 
 (defun notmuch-show-insert-thread (thread depth)
@@ -1041,16 +1041,18 @@ function is used."
 (args (if notmuch-show-query-context
   (append (list "\'") basic-args
   (list "and (" notmuch-show-query-context ")\'"))
-(append (list "\'") basic-args (list "\'")
-   (notmuch-show-insert-forest (notmuch-query-get-threads
-(cons "--exclude=false" args)))
+(append (list "\'") basic-args (list "\'"
+(cli-args (cons "--exclude=false"
+(when notmuch-show-elide-non-matching-messages
+  (list "--entire-thread=false")
+
+   (notmuch-show-insert-forest (notmuch-query-get-threads (append cli-args 
args)))
;; If the query context reduced the results to nothing, run
;; the basic query.
(when (and (eq (buffer-size) 0)
   notmuch-show-query-context)
  (notmuch-show-insert-forest
-  (notmuch-query-get-threads
-   (cons "--exclude=false" basic-args)
+  (notmuch-query-get-threads (append cli-args basic-args)
 
   (jit-lock-register #'notmuch-show-buttonise-links)
 
-- 
1.7.9.1

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


[PATCH v5 3/5] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread Mark Walters
The --entire-thread option in notmuch-show.c defaults to true when
format=json. Previously there was no way to turn this off. This patch
makes it respect --entire-thread=false.

To do this the patch moves the --entire-thread option to be a keyword
option using the new command line parsing to allow the existing
--entire-thread syntax to keep working.
---
 notmuch-show.c |   25 +++--
 1 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/notmuch-show.c b/notmuch-show.c
index 97da5cc..207093a 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -981,6 +981,12 @@ enum {
 NOTMUCH_FORMAT_RAW
 };
 
+enum {
+ENTIRE_THREAD_DEFAULT,
+ENTIRE_THREAD_TRUE,
+ENTIRE_THREAD_FALSE,
+};
+
 /* The following is to allow future options to be added more easily */
 enum {
 EXCLUDE_TRUE,
@@ -1000,6 +1006,7 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
 notmuch_bool_t verify = FALSE;
 int exclude = EXCLUDE_TRUE;
+int entire_thread = ENTIRE_THREAD_DEFAULT;
 
 notmuch_opt_desc_t options[] = {
{ NOTMUCH_OPT_KEYWORD, &format_sel, "format", 'f',
@@ -1012,8 +1019,11 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
   (notmuch_keyword_t []){ { "true", EXCLUDE_TRUE },
   { "false", EXCLUDE_FALSE },
   { 0, 0 } } },
+{ NOTMUCH_OPT_KEYWORD, &entire_thread, "entire-thread", 't',
+  (notmuch_keyword_t []){ { "true", ENTIRE_THREAD_TRUE },
+  { "false", ENTIRE_THREAD_FALSE },
+  { 0, 0 } } },
{ NOTMUCH_OPT_INT, ¶ms.part, "part", 'p', 0 },
-   { NOTMUCH_OPT_BOOLEAN, ¶ms.entire_thread, "entire-thread", 't', 0 },
{ NOTMUCH_OPT_BOOLEAN, ¶ms.decrypt, "decrypt", 'd', 0 },
{ NOTMUCH_OPT_BOOLEAN, &verify, "verify", 'v', 0 },
{ 0, 0, 0, 0, 0 }
@@ -1036,7 +1046,9 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
 switch (format_sel) {
 case NOTMUCH_FORMAT_JSON:
format = &format_json;
-   params.entire_thread = TRUE;
+   /* JSON defaults to entire-thread TRUE */
+   if (entire_thread == ENTIRE_THREAD_DEFAULT)
+   entire_thread = ENTIRE_THREAD_TRUE;
break;
 case NOTMUCH_FORMAT_TEXT:
format = &format_text;
@@ -1058,6 +1070,15 @@ notmuch_show_command (void *ctx, unused (int argc), 
unused (char *argv[]))
params.raw = TRUE;
break;
 }
+/* Default is entire-thread = FALSE except for format=json which
+ * is dealt with above. */
+if (entire_thread == ENTIRE_THREAD_DEFAULT)
+   entire_thread = ENTIRE_THREAD_FALSE;
+
+if (entire_thread == ENTIRE_THREAD_TRUE)
+   params.entire_thread = TRUE;
+else
+   params.entire_thread = FALSE;
 
 if (params.decrypt || verify) {
 #ifdef GMIME_ATLEAST_26
-- 
1.7.9.1

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


[PATCH v5 4/5] Update devel/schemata for --entire-thread=false

2012-05-26 Thread Mark Walters
Also remove the Json --entire-thread item from devel/TODO.
---
 devel/TODO |2 --
 devel/schemata |2 +-
 2 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/devel/TODO b/devel/TODO
index 7b750af..eb757af 100644
--- a/devel/TODO
+++ b/devel/TODO
@@ -92,8 +92,6 @@ and email address in the From: line. We could also then 
easily support
 "notmuch compose --from " to support getting at alternate
 email addresses.
 
-Fix the --format=json option to not imply --entire-thread.
-
 Implement "notmuch search --exclude-threads=" to allow
 for excluding muted threads, (and any other negative, thread-based
 filtering that the user wants to do).
diff --git a/devel/schemata b/devel/schemata
index 977cea7..8fcab8e 100644
--- a/devel/schemata
+++ b/devel/schemata
@@ -32,7 +32,7 @@ thread = [thread_node*]
 
 # A message and its replies (show_messages)
 thread_node = [
-message?, # present if --entire-thread or matched
+message?, # null if not matched and not --entire-thread
 [thread_node*]# children of message
 ]
 
-- 
1.7.9.1

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


[PATCH v5 1/5] cli: command line parsing: allow default for keyword options

2012-05-26 Thread Mark Walters
This changes the parsing for "keyword" options so that if the option
is specified with no argument the first possible argument is
chosen. This make it easier to add options to existing boolean
arguments (the existing --option can default to TRUE).
---
 command-line-arguments.c |   13 ++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/command-line-arguments.c b/command-line-arguments.c
index 76b185f..d40c7e6 100644
--- a/command-line-arguments.c
+++ b/command-line-arguments.c
@@ -11,10 +11,16 @@
 */
 
 static notmuch_bool_t
-_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char *arg_str) 
{
+_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const 
char *arg_str) {
 
 const notmuch_keyword_t *keywords = arg_desc->keywords;
 
+if (next == 0) {
+/* No keyword given so return first option as default */
+   *((int *)arg_desc->output_var) = keywords->value;
+   return TRUE;
+}
+
 while (keywords->name) {
if (strcmp (arg_str, keywords->name) == 0) {
if (arg_desc->output_var) {
@@ -99,7 +105,8 @@ parse_option (const char *arg,
 */
if (next != '=' && next != ':' && next != 0) return FALSE;
if (next == 0) {
-   if (try->opt_type != NOTMUCH_OPT_BOOLEAN)
+   if (try->opt_type != NOTMUCH_OPT_BOOLEAN &&
+   try->opt_type != NOTMUCH_OPT_KEYWORD)
return FALSE;
} else {
if (value[0] == 0) return FALSE;
@@ -110,7 +117,7 @@ parse_option (const char *arg,
 
switch (try->opt_type) {
case NOTMUCH_OPT_KEYWORD:
-   return _process_keyword_arg (try, value);
+   return _process_keyword_arg (try, next, value);
break;
case NOTMUCH_OPT_BOOLEAN:
return _process_boolean_arg (try, next, value);
-- 
1.7.9.1

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


[PATCH v5 2/5] cli: Let json output "null" messages for non --entire-thread

2012-05-26 Thread Mark Walters
All formats except Json can output empty messages for non
entire-thread, but in Json format we output "null" to keep the other
elements (e.g. the replies to the omitted message) in the correct
place.
---
 notmuch-client.h |1 +
 notmuch-show.c   |   20 
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/notmuch-client.h b/notmuch-client.h
index 19b7f01..08540a7 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -72,6 +72,7 @@ typedef struct notmuch_show_format {
  const struct notmuch_show_params *params);
 const char *message_set_sep;
 const char *message_set_end;
+const char *null_message;
 } notmuch_show_format_t;
 
 typedef struct notmuch_show_params {
diff --git a/notmuch-show.c b/notmuch-show.c
index 95427d4..97da5cc 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -37,7 +37,8 @@ static const notmuch_show_format_t format_json = {
 .message_set_start = "[",
 .part = format_part_json_entry,
 .message_set_sep = ", ",
-.message_set_end = "]"
+.message_set_end = "]",
+.null_message = "null"
 };
 
 static notmuch_status_t
@@ -800,6 +801,15 @@ format_part_raw (unused (const void *ctx), mime_node_t 
*node,
 }
 
 static notmuch_status_t
+show_null_message (const notmuch_show_format_t *format)
+{
+/* Output a null message. Currently empty for all formats except Json */
+if (format->null_message)
+   printf ("%s", format->null_message);
+return NOTMUCH_STATUS_SUCCESS;
+}
+
+static notmuch_status_t
 show_message (void *ctx,
  const notmuch_show_format_t *format,
  notmuch_message_t *message,
@@ -862,11 +872,13 @@ show_messages (void *ctx,
if (status && !res)
res = status;
next_indent = indent + 1;
-
-   if (!status && format->message_set_sep)
-   fputs (format->message_set_sep, stdout);
+   } else {
+   status = show_null_message (format);
}
 
+   if (!status && format->message_set_sep)
+   fputs (format->message_set_sep, stdout);
+
status = show_messages (ctx,
format,
notmuch_message_get_replies (message),
-- 
1.7.9.1

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


[PATCH v5 0/5] Allow JSON to use non-entire thread, and use for elide

2012-05-26 Thread Mark Walters
This is version 5 of this patch series: version 4 is at
id:"1335258675-29439-1-git-send-email-markwalters1...@gmail.com".

This version changes the way the command-line parser deals with
keywords so that specifying --option without an = returns
the first option. This means that boolean options can easily have
extra options added without breaking the existing syntax.

Patch 3/5 takes advantage of this new feature to implement the  
--entire-thread option to notmuch-show in a non-hacky way.

Best wishes 

Mark


Mark Walters (5):
  cli: command line parsing: allow default for keyword options
  cli: Let json output "null" messages for non --entire-thread
  cli: make --entire-thread=false work for format=json.
  Update devel/schemata for --entire-thread=false
  emacs: make elide messages use notmuch-show for omitting messages.

 command-line-arguments.c |   13 ++---
 devel/TODO   |2 --
 devel/schemata   |2 +-
 emacs/notmuch-show.el|   18 ++
 notmuch-client.h |1 +
 notmuch-show.c   |   45 +++--
 6 files changed, 61 insertions(+), 20 deletions(-)

-- 
1.7.9.1

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


[PATCH 2/2] Makefile.local: added verify-version-news to verify-no-dirty-code deps.

2012-05-26 Thread Tomi Ollila
Added `verify-version-news` to the end of `verify-no-dirty-code`
dependencies so it is part of release testing checks.
---
Tested by executing the following commands:
  make verify-source-tree-and-version
  make verify-source-tree-and-version VERSION=0.13
  make verify-source-tree-and-version VERSION=0.12

 Makefile.local |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 1b34c00..94a3a70 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -187,7 +187,7 @@ release-message:
 verify-source-tree-and-version: verify-no-dirty-code
 
 .PHONY: verify-no-dirty-code
-verify-no-dirty-code: verify-version-debian verify-version-python 
verify-version-manpage
+verify-no-dirty-code: verify-version-debian verify-version-python 
verify-version-manpage verify-version-news
 ifeq ($(IS_GIT),yes)
@printf "Checking that source tree is clean..."
 ifneq ($(shell git ls-files -m),)
-- 
1.7.1

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


[PATCH 1/2] Makefile.local: added checks for latest NEWS title

2012-05-26 Thread Tomi Ollila
Added target `verify-version-news` which checks that the first line
in NEWS file has the following properties:
First word is 'Notmuch'
Second "word" matches the current version
Rest of line is in format (201[2-9]-[01][0-9]-[0-3][0-9]
---

Tested by executing the following commands:
  make verify-version-news
  make verify-version-news VERSION=0.13
  make verify-version-news VERSION=0.12

 Makefile.local |   15 +++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/Makefile.local b/Makefile.local
index 53b4a0d..1b34c00 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -220,6 +220,21 @@ verify-version-python: verify-version-components
 echo "Please edit version and $(PV_FILE) to have consistent 
versions." && false)
@echo "Good."
 
+.PHONY: verify-version-news
+verify-version-news: verify-version-components
+   @read notmuch version date < NEWS ;\
+   ev=0 ;\
+   echo -n "Checking that this is 'Notmuch' NEWS..." ;\
+   if [ "$$notmuch" = 'Notmuch' ]; then echo 'Good.' ;\
+   else echo 'No.'; ev=1; fi ;\
+   echo -n "Checking that NEWS version is $(VERSION)..." ;\
+   if [ "$$version" = '$(VERSION)' ]; then echo 'Good.' ;\
+   else echo 'No.'; ev=1; fi ;\
+   echo -n "Checking that NEWS date is in correct format..." ;\
+   case $$date in '('201[2-9]-[0-1][0-9]-[0-3][0-9]')') echo 'Good.' ;;\
+   *)   echo 'No.'; ev=1; esac ;\
+   if [ $$ev -ne 0 ]; then echo "Please edit NEWS file to have Notmuch 
header line in correct format."; false; fi
+
 .PHONY: verify-version-components
 verify-version-components:
@echo -n "Checking that $(VERSION) consists only of digits and 
periods..."
-- 
1.7.1

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


Re: [PATCH v4 2/4] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread David Bremner
Mark Walters  writes:

> On Sat, 26 May 2012, Peter Wang  wrote:
>> On Tue, 24 Apr 2012 10:11:13 +0100, Mark Walters  
>> wrote:
>
> It is easy to change the keyword parsing code to allow this: I include a
> first draft of such a patch below. This would allow the solution you
> suggest and thus avoid the hack/abuse.  What do people think?
>

It didn't carefully review it, but it looks sane enough at a quick
glance.

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


FreeBSD Support Patches

2012-05-26 Thread Dmitry Kurochkin
Mike Kelly  writes:

> On Fri, May 25, 2012 at 10:15 AM, Dmitry Kurochkin
>  wrote:
>> Why do we need to explicitly declare Emacs dependency for tests? ?There
>> should be no need for it. ?We have "implicit" dependencies which are
>> declared once (see test_declare_external_prereq calls at the end of
>> test-lib.sh) and are automatically handled when a test tries to use a
>> missing binary. ?Explicit dependencies are hard to maintain (e.g. your
>> patch adds explicit emacs dependency for crypto test but misses gpg).
>> With rare exceptions we should not use explicit dependencies.
>
> Because not every test actually has those implicit dependencies. For
> example, some of the crypto tests depend upon emacs_deliver_message
> working correctly for subsequents tests. Those emacs_deliver_message
> tests are skipped, but not the ones after it that try to do something
> with that injected message.
>
> For the emacs-* test files, there are some tests that act the same
> way.

These subtests do not directly depend on Emacs.  They depend on other
subtests.  Currently, we do not support such dependencies.  But what you
propose is not the solution.  We have two options here: make all
subtests independent or introduce proper subtests dependencies.  The
former might require many changes to existing tests and may be hard to
enforce.  The latter is not trivial as well but is doable.  I planned to
implement subtests dependencies but never really got to it (and I do not
think I will anytime soon).

> However, it is also a minor speed improvement to say that,
> obviously, none of the emacs tests are going to work, so just don't
> bother.
>

I do not think maintaining an explicit list of dependencies worth a
minor speed improvement.

Given all above, I understand that your patches fix a common problem in
a simple way.  And it does not look like we would get proper solution
anytime soon.  So I am ok with these patches with two comments:

  * Provide a proper commit message to explain the issue in more detail.

  * Add an XXX comment for each explicit dependency, something like:

// XXX: Workaround for subtests that depend on other subtests (and,
// hence, indirectly depend on emacs).  Should be removed when we
// have proper subtests dependencies.

Regards,
  Dmitry

> -- 
> Mike Kelly


Re: [PATCH 03/10] Fix compilation of smtp-dummy on FreeBSD

2012-05-26 Thread Jani Nikula
On May 25, 2012 4:44 PM, "Mike Kelly"  wrote:
>
> ---
>  test/smtp-dummy.c |5 -
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/test/smtp-dummy.c b/test/smtp-dummy.c
> index 3801a5e..aa82fa1 100644
> --- a/test/smtp-dummy.c
> +++ b/test/smtp-dummy.c
> @@ -33,11 +33,14 @@
>  * have been warned.
>  */
>
> +#define _GNU_SOURCE /* for getline */

First of all, thanks for sharing your work.

Independent of this patch, I've been thinking about defining _GNU_SOURCE in
the makefile. I don't think it's very elegant to #define it everywhere. It
would also pave the way towards building with -pedantic (and possibly
-std=c99) in a portable way. For example, the compat test code #defines
_GNU_SOURCE while the actual code does not, which I think is an error.

I'll look into this after the weekend (unless you beat me to it).

BR,
Jani.

>  #include 
>  #include 
>  #include 
>  #include 
> -#include 
> +#include 
> +#include 
> +#include 
>  #include 
>  #include 
>
> --
> 1.7.10.2
>
> ___
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [PATCH v4 2/4] cli: make --entire-thread=false work for format=json.

2012-05-26 Thread Mark Walters

On Sat, 26 May 2012, Peter Wang  wrote:
> On Tue, 24 Apr 2012 10:11:13 +0100, Mark Walters  
> wrote:
>> The --entire-thread option in notmuch-show.c defaults to true when
>> format=json. Previously there was no way to turn this off. This patch
>> makes it respect --entire-thread=false.
>> 
>> The one subtlety is that we initialise a notmuch_bool_t to -1 to
>> indicate that the option parsing has not set it. This allows the code
>> to distinguish between the option being omitted from the command line,
>> and the option being set to false on the command line.
>> ---
>>  notmuch-show.c |   16 ++--
>>  1 files changed, 14 insertions(+), 2 deletions(-)
>> 
>> diff --git a/notmuch-show.c b/notmuch-show.c
>> index 0d21f1a..48551bb 100644
>> --- a/notmuch-show.c
>> +++ b/notmuch-show.c
>> @@ -996,7 +996,13 @@ notmuch_show_command (void *ctx, unused (int argc), 
>> unused (char *argv[]))
>>  char *query_string;
>>  int opt_index, ret;
>>  const notmuch_show_format_t *format = &format_text;
>> -notmuch_show_params_t params = { .part = -1, .omit_excluded = TRUE };
>> +
>> +/* We abuse the notmuch_bool_t variable params.entire-thread by
>> + * setting it to -1 to denote that the command line parsing has
>> + * not set it. We ensure it is set to TRUE or FALSE before passing
>> + * it to any other function.*/
>> +notmuch_show_params_t params = { .part = -1, .entire_thread = -1 };
>> +
>>  int format_sel = NOTMUCH_FORMAT_NOT_SPECIFIED;
>>  notmuch_bool_t verify = FALSE;
>>  int exclude = EXCLUDE_TRUE;
>
> Hi Mark,
>
> As an alternative to the abuse, could you just treat it as with exclude,
> using an enum with three values (TRUE|FALSE|DEFAULT)?
> Then set params.entire_thread afterwards.

The reason I haven't done this is that the current command line parser
does not allow keyword options to take default values: in other words
--entire-thread without an "=" would not be allowed.

It is easy to change the keyword parsing code to allow this: I include a
first draft of such a patch below. This would allow the solution you
suggest and thus avoid the hack/abuse.  What do people think?

Best wishes

Mark


---
 command-line-arguments.c |   13 ++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/command-line-arguments.c b/command-line-arguments.c
index 76b185f..d40c7e6 100644
--- a/command-line-arguments.c
+++ b/command-line-arguments.c
@@ -11,10 +11,16 @@
 */
 
 static notmuch_bool_t
-_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, const char *arg_str) 
{
+_process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const 
char *arg_str) {
 
 const notmuch_keyword_t *keywords = arg_desc->keywords;
 
+if (next == 0) {
+/* No keyword given so return first option as default */
+   *((int *)arg_desc->output_var) = keywords->value;
+   return TRUE;
+}
+
 while (keywords->name) {
if (strcmp (arg_str, keywords->name) == 0) {
if (arg_desc->output_var) {
@@ -99,7 +105,8 @@ parse_option (const char *arg,
 */
if (next != '=' && next != ':' && next != 0) return FALSE;
if (next == 0) {
-   if (try->opt_type != NOTMUCH_OPT_BOOLEAN)
+   if (try->opt_type != NOTMUCH_OPT_BOOLEAN &&
+   try->opt_type != NOTMUCH_OPT_KEYWORD)
return FALSE;
} else {
if (value[0] == 0) return FALSE;
@@ -110,7 +117,7 @@ parse_option (const char *arg,
 
switch (try->opt_type) {
case NOTMUCH_OPT_KEYWORD:
-   return _process_keyword_arg (try, value);
+   return _process_keyword_arg (try, next, value);
break;
case NOTMUCH_OPT_BOOLEAN:
return _process_boolean_arg (try, next, value);
-- 
1.7.9.1

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