--- /dev/null
+Return-Path: <dkg@fifthhorseman.net>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by arlo.cworth.org (Postfix) with ESMTP id EB9006DE13FB\r
+ for <notmuch@notmuchmail.org>; Tue, 19 Jan 2016 18:53:18 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -0.023\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-0.023 tagged_above=-999 required=5\r
+ tests=[AWL=-0.023] autolearn=disabled\r
+Received: from arlo.cworth.org ([127.0.0.1])\r
+ by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id ipU96bG_aBQ0 for <notmuch@notmuchmail.org>;\r
+ Tue, 19 Jan 2016 18:53:15 -0800 (PST)\r
+Received: from che.mayfirst.org (che.mayfirst.org [209.234.253.108])\r
+ by arlo.cworth.org (Postfix) with ESMTP id 5C4F36DE1403\r
+ for <notmuch@notmuchmail.org>; Tue, 19 Jan 2016 18:53:15 -0800 (PST)\r
+Received: from fifthhorseman.net (unknown [38.109.115.130])\r
+ by che.mayfirst.org (Postfix) with ESMTPSA id 617FDF986\r
+ for <notmuch@notmuchmail.org>; Tue, 19 Jan 2016 21:53:10 -0500 (EST)\r
+Received: by fifthhorseman.net (Postfix, from userid 1000)\r
+ id D174520229; Tue, 19 Jan 2016 18:53:10 -0800 (PST)\r
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>\r
+To: Notmuch Mail <notmuch@notmuchmail.org>\r
+Subject: [PATCH v2 03/16] make shared crypto code behave library-like\r
+Date: Tue, 19 Jan 2016 21:52:36 -0500\r
+Message-Id: <1453258369-7366-4-git-send-email-dkg@fifthhorseman.net>\r
+X-Mailer: git-send-email 2.7.0.rc3\r
+In-Reply-To: <1453258369-7366-1-git-send-email-dkg@fifthhorseman.net>\r
+References: <1453258369-7366-1-git-send-email-dkg@fifthhorseman.net>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.20\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch/>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Wed, 20 Jan 2016 02:53:19 -0000\r
+\r
+If we're going to reuse the crypto code across both the library and\r
+the client, then it needs to report error states properly and not\r
+write to stderr.\r
+---\r
+ lib/database.cc | 6 ++++++\r
+ lib/notmuch.h | 17 +++++++++++++++++\r
+ mime-node.c | 7 ++++++-\r
+ util/crypto.c | 55 +++++++++++++++++++++++++------------------------------\r
+ util/crypto.h | 6 ++++--\r
+ 5 files changed, 58 insertions(+), 33 deletions(-)\r
+\r
+diff --git a/lib/database.cc b/lib/database.cc\r
+index 3b342f1..0d4dc9b 100644\r
+--- a/lib/database.cc\r
++++ b/lib/database.cc\r
+@@ -349,6 +349,12 @@ notmuch_status_to_string (notmuch_status_t status)\r
+ return "Operation requires a database upgrade";\r
+ case NOTMUCH_STATUS_PATH_ERROR:\r
+ return "Path supplied is illegal for this function";\r
++ case NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL:\r
++ return "Crypto protocol missing, malformed, or unintelligible";\r
++ case NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION:\r
++ return "Crypto engine initialization failure";\r
++ case NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL:\r
++ return "Unknown crypto protocol";\r
+ default:\r
+ case NOTMUCH_STATUS_LAST_STATUS:\r
+ return "Unknown error status value";\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index 310a8b8..00002f1 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -171,6 +171,23 @@ typedef enum _notmuch_status {\r
+ */\r
+ NOTMUCH_STATUS_PATH_ERROR,\r
+ /**\r
++ * A MIME object claimed to have cryptographic protection which\r
++ * notmuch tried to handle, but the protocol was not specified in\r
++ * an intelligible way.\r
++ */\r
++ NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL,\r
++ /**\r
++ * Notmuch attempted to do crypto processing, but could not\r
++ * initialize the engine needed to do so.\r
++ */\r
++ NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION,\r
++ /**\r
++ * A MIME object claimed to have cryptographic protection, and\r
++ * notmuch attempted to process it, but the specific protocol was\r
++ * something that notmuch doesn't know how to handle.\r
++ */\r
++ NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL,\r
++ /**\r
+ * Not an actual status value. Just a way to find out how many\r
+ * valid status values there are.\r
+ */\r
+diff --git a/mime-node.c b/mime-node.c\r
+index a8f5670..59c0da2 100644\r
+--- a/mime-node.c\r
++++ b/mime-node.c\r
+@@ -244,7 +244,12 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part)\r
+ || (GMIME_IS_MULTIPART_SIGNED (part) && node->ctx->crypto->verify)) {\r
+ GMimeContentType *content_type = g_mime_object_get_content_type (part);\r
+ const char *protocol = g_mime_content_type_get_parameter (content_type, "protocol");\r
+- cryptoctx = _notmuch_crypto_get_gmime_context (node->ctx->crypto, protocol);\r
++ notmuch_status_t status;\r
++ status = _notmuch_crypto_get_gmime_ctx_for_protocol (node->ctx->crypto,\r
++ protocol, &cryptoctx);\r
++ if (status) /* this is a warning, not an error */\r
++ fprintf (stderr, "Warning: %s (%s).\n", notmuch_status_to_string (status),\r
++ protocol ? protocol : "(NULL)");\r
+ }\r
+ \r
+ /* Handle PGP/MIME parts */\r
+diff --git a/util/crypto.c b/util/crypto.c\r
+index 1712347..c18c82c 100644\r
+--- a/util/crypto.c\r
++++ b/util/crypto.c\r
+@@ -26,55 +26,53 @@\r
+ #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))\r
+ \r
+ /* Create a GPG context (GMime 2.6) */\r
+-static GMimeCryptoContext*\r
+-create_gpg_context (_notmuch_crypto_t *crypto)\r
++static notmuch_status_t\r
++get_gpg_context (_notmuch_crypto_t *crypto, GMimeCryptoContext **ctx)\r
+ {\r
+- GMimeCryptoContext *gpgctx;\r
++ if (ctx == NULL || crypto == NULL)\r
++ return NOTMUCH_STATUS_NULL_POINTER;\r
+ \r
+ if (crypto->gpgctx) {\r
+- return crypto->gpgctx;\r
++ *ctx = crypto->gpgctx;\r
++ return NOTMUCH_STATUS_SUCCESS;\r
+ }\r
+ \r
+ /* TODO: GMimePasswordRequestFunc */\r
+- gpgctx = g_mime_gpg_context_new (NULL, crypto->gpgpath ? crypto->gpgpath : "gpg");\r
+- if (! gpgctx) {\r
+- fprintf (stderr, "Failed to construct gpg context.\n");\r
+- return NULL;\r
++ crypto->gpgctx = g_mime_gpg_context_new (NULL, crypto->gpgpath ? crypto->gpgpath : "gpg");\r
++ if (! crypto->gpgctx) {\r
++ return NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION;\r
+ }\r
+- crypto->gpgctx = gpgctx;\r
+ \r
+- g_mime_gpg_context_set_use_agent ((GMimeGpgContext *) gpgctx, TRUE);\r
+- g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) gpgctx, FALSE);\r
++ g_mime_gpg_context_set_use_agent ((GMimeGpgContext *) crypto->gpgctx, TRUE);\r
++ g_mime_gpg_context_set_always_trust ((GMimeGpgContext *) crypto->gpgctx, FALSE);\r
+ \r
+- return crypto->gpgctx;\r
++ *ctx = crypto->gpgctx;\r
++ return NOTMUCH_STATUS_SUCCESS;\r
+ }\r
+ \r
+ static const struct {\r
+ const char *protocol;\r
+- GMimeCryptoContext *(*get_context) (_notmuch_crypto_t *crypto);\r
++ notmuch_status_t (*get_context) (_notmuch_crypto_t *crypto, GMimeCryptoContext **ctx);\r
+ } protocols[] = {\r
+ {\r
+ .protocol = "application/pgp-signature",\r
+- .get_context = create_gpg_context,\r
++ .get_context = get_gpg_context,\r
+ },\r
+ {\r
+ .protocol = "application/pgp-encrypted",\r
+- .get_context = create_gpg_context,\r
++ .get_context = get_gpg_context,\r
+ },\r
+ };\r
+ \r
+ /* for the specified protocol return the context pointer (initializing\r
+ * if needed) */\r
+-GMimeCryptoContext *\r
+-_notmuch_crypto_get_gmime_context (_notmuch_crypto_t *crypto, const char *protocol)\r
++notmuch_status_t\r
++_notmuch_crypto_get_gmime_ctx_for_protocol (_notmuch_crypto_t *crypto,\r
++ const char *protocol,\r
++ GMimeCryptoContext **ctx)\r
+ {\r
+- GMimeCryptoContext *cryptoctx = NULL;\r
+- size_t i;\r
+-\r
+- if (! protocol) {\r
+- fprintf (stderr, "Cryptographic protocol is empty.\n");\r
+- return cryptoctx;\r
+- }\r
++ if (! protocol)\r
++ return NOTMUCH_STATUS_MALFORMED_CRYPTO_PROTOCOL;\r
+ \r
+ /* As per RFC 1847 section 2.1: "the [protocol] value token is\r
+ * comprised of the type and sub-type tokens of the Content-Type".\r
+@@ -82,15 +80,12 @@ _notmuch_crypto_get_gmime_context (_notmuch_crypto_t *crypto, const char *protoc\r
+ * parameter names as defined in this document are\r
+ * case-insensitive." Thus, we use strcasecmp for the protocol.\r
+ */\r
+- for (i = 0; i < ARRAY_SIZE (protocols); i++) {\r
++ for (size_t i = 0; i < ARRAY_SIZE (protocols); i++) {\r
+ if (strcasecmp (protocol, protocols[i].protocol) == 0)\r
+- return protocols[i].get_context (crypto);\r
++ return protocols[i].get_context (crypto, ctx);\r
+ }\r
+ \r
+- fprintf (stderr, "Unknown or unsupported cryptographic protocol %s.\n",\r
+- protocol);\r
+-\r
+- return NULL;\r
++ return NOTMUCH_STATUS_UNKNOWN_CRYPTO_PROTOCOL;\r
+ }\r
+ \r
+ void\r
+diff --git a/util/crypto.h b/util/crypto.h\r
+index 0e65472..92357b4 100644\r
+--- a/util/crypto.h\r
++++ b/util/crypto.h\r
+@@ -12,8 +12,10 @@ typedef struct _notmuch_crypto {\r
+ } _notmuch_crypto_t;\r
+ \r
+ \r
+-GMimeCryptoContext *\r
+-_notmuch_crypto_get_gmime_context (_notmuch_crypto_t *crypto, const char *protocol);\r
++notmuch_status_t\r
++_notmuch_crypto_get_gmime_ctx_for_protocol (_notmuch_crypto_t *crypto,\r
++ const char *protocol,\r
++ GMimeCryptoContext **ctx);\r
+ \r
+ void\r
+ _notmuch_crypto_cleanup (_notmuch_crypto_t *crypto);\r
+-- \r
+2.7.0.rc3\r
+\r