--- /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 2294A6DE09ED\r
+ for <notmuch@notmuchmail.org>; Fri, 8 Jul 2016 03:14:08 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at cworth.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0.041\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0.041 tagged_above=-999 required=5 tests=[AWL=0.041]\r
+ 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 xLj-IHd1uwvi for <notmuch@notmuchmail.org>;\r
+ Fri, 8 Jul 2016 03:14:00 -0700 (PDT)\r
+Received: from che.mayfirst.org (che.mayfirst.org [162.247.75.118])\r
+ by arlo.cworth.org (Postfix) with ESMTP id D41CB6DE0363\r
+ for <notmuch@notmuchmail.org>; Fri, 8 Jul 2016 03:13:12 -0700 (PDT)\r
+Received: from fifthhorseman.net (unknown [88.128.80.54])\r
+ by che.mayfirst.org (Postfix) with ESMTPSA id 02291F99D\r
+ for <notmuch@notmuchmail.org>; Fri, 8 Jul 2016 06:13:11 -0400 (EDT)\r
+Received: by fifthhorseman.net (Postfix, from userid 1000)\r
+ id 8C60420E94; Fri, 8 Jul 2016 11:27:34 +0200 (CEST)\r
+From: Daniel Kahn Gillmor <dkg@fifthhorseman.net>\r
+To: Notmuch Mail <notmuch@notmuchmail.org>\r
+Subject: [PATCH v4 03/16] make shared crypto code behave library-like\r
+Date: Fri, 8 Jul 2016 11:27:14 +0200\r
+Message-Id: <1467970047-8013-4-git-send-email-dkg@fifthhorseman.net>\r
+X-Mailer: git-send-email 2.8.1\r
+In-Reply-To: <1467970047-8013-1-git-send-email-dkg@fifthhorseman.net>\r
+References: <1467970047-8013-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: Fri, 08 Jul 2016 10:14:08 -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 | 89 ++++++++++++++++++++++++++++-----------------------------\r
+ util/crypto.h | 6 ++--\r
+ 5 files changed, 76 insertions(+), 49 deletions(-)\r
+\r
+diff --git a/lib/database.cc b/lib/database.cc\r
+index 3bdbd07..9d6b6f2 100644\r
+--- a/lib/database.cc\r
++++ b/lib/database.cc\r
+@@ -369,6 +369,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 0d667f5..aaed516 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -185,6 +185,23 @@ typedef enum _notmuch_status {\r
+ */\r
+ NOTMUCH_STATUS_ILLEGAL_ARGUMENT,\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 14873ce..717a122 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 48c20bb..cce5cbc 100644\r
+--- a/util/crypto.c\r
++++ b/util/crypto.c\r
+@@ -25,86 +25,86 @@\r
+ \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
++/* Create or pass on a GPG context (GMime 2.6) */\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
+-/* Create a PKCS7 context (GMime 2.6) */\r
+-static notmuch_crypto_context_t *\r
+-create_pkcs7_context (notmuch_crypto_t *crypto)\r
++/* Create or pass on a PKCS7 context (GMime 2.6) */\r
++static notmuch_status_t \r
++get_pkcs7_context (_notmuch_crypto_t *crypto, GMimeCryptoContext **ctx)\r
+ {\r
+- notmuch_crypto_context_t *pkcs7ctx;\r
++ if (ctx == NULL || crypto == NULL)\r
++ return NOTMUCH_STATUS_NULL_POINTER;\r
+ \r
+- if (crypto->pkcs7ctx)\r
+- return crypto->pkcs7ctx;\r
++ if (crypto->pkcs7ctx) {\r
++ *ctx = crypto->pkcs7ctx;\r
++ return NOTMUCH_STATUS_SUCCESS;\r
++ }\r
+ \r
+ /* TODO: GMimePasswordRequestFunc */\r
+- pkcs7ctx = g_mime_pkcs7_context_new (NULL);\r
+- if (! pkcs7ctx) {\r
+- fprintf (stderr, "Failed to construct pkcs7 context.\n");\r
+- return NULL;\r
++ crypto->pkcs7ctx = g_mime_pkcs7_context_new (NULL);\r
++ if (! crypto->pkcs7ctx) {\r
++ return NOTMUCH_STATUS_FAILED_CRYPTO_CONTEXT_CREATION;\r
+ }\r
+- crypto->pkcs7ctx = pkcs7ctx;\r
+ \r
+- g_mime_pkcs7_context_set_always_trust ((GMimePkcs7Context *) pkcs7ctx,\r
++ g_mime_pkcs7_context_set_always_trust ((GMimePkcs7Context *) crypto->pkcs7ctx,\r
+ FALSE);\r
+ \r
+- return crypto->pkcs7ctx;\r
++ *ctx = crypto->pkcs7ctx;\r
++ return NOTMUCH_STATUS_SUCCESS;\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
+ .protocol = "application/pkcs7-signature",\r
+- .get_context = create_pkcs7_context,\r
++ .get_context = get_pkcs7_context,\r
+ },\r
+ {\r
+ .protocol = "application/x-pkcs7-signature",\r
+- .get_context = create_pkcs7_context,\r
++ .get_context = get_pkcs7_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
+@@ -112,15 +112,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 d4a51e8..7cb0a39 100644\r
+--- a/util/crypto.h\r
++++ b/util/crypto.h\r
+@@ -15,8 +15,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.8.1\r
+\r