cope with inline PGP encrypted messages
Inline PGP encrypted messages are clearly worse than PGP/MIME structured encrypted messages. There are no standards for how they are formed, and they don't offer any structured metadata about how to interpret the bytestream produced by decrypting them. However, some other MUAs and end-user workflows may make creation of inline PGP encrypted messages the only available option for message encryption, and when Notmuch encounters such a message, it should make a reasonable best-effort to render the cleartext to the user. Due to ambiguities in interpretation of signatures on inline messages (e.g. which parts of the message were actually signed? what character encoding should the bytestream be interpreted as), we continue to ignore inline-signed messages entirely, and we do not look at the validity of any signatures that might be found when decrypting inline PGP encrypted messages. We make use here of GMime's optimization function for detecting the presence of inline PGP encrypted content, which is only found in GMime 3.0 or later. This series is currently based n top of the "notmuch show --decrypt=stash" series, which it needs to be able to apply cleanly. If that series proves controversial, i could rebase this patch manually against some earlier commit. If you have applied this series, and you know you have some inline PGP messages already in your message store, you can try to retroactively reindex them with something like: notmuch reindex --decrypt=true BEGIN-PGP-MESSAGE and not tag:encrypted I welcome review and feedback about this series. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 4/5] index: _index_encrypted_mime_part returns success or failure
This change prepares us to know whether or not _index_encrypted_mime_part succeeded or not on a given MIME part. We don't currently make use of the information, but we will in subsequent changes. --- lib/index.cc | 19 +++ 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index e03f5230..29ede685 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -364,7 +364,7 @@ _index_content_type (notmuch_message_t *message, GMimeObject *part) } } -static void +static bool _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, GMimeContentType *content_type, GMimeObject *part); @@ -419,6 +419,8 @@ _index_mime_part (notmuch_message_t *message, _index_content_type (message, g_mime_multipart_get_part (multipart, i)); if (i == GMIME_MULTIPART_ENCRYPTED_CONTENT) { + /* deliberately ignore return value here: if it fails to decrypt, + we have nothing else to try */ _index_encrypted_mime_part(message, indexopts, content_type, part); @@ -519,8 +521,9 @@ _index_mime_part (notmuch_message_t *message, } /* descend (if desired) into the cleartext part of an encrypted MIME - * part while indexing. */ -static void + * part while indexing. Returns true if there was a successful + * decryption, false if there was not.*/ +static bool _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, g_mime_3_unused(GMimeContentType *content_type), @@ -532,7 +535,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, GMimeObject *clear = NULL; if (!indexopts || (notmuch_indexopts_get_decrypt_policy (indexopts) == NOTMUCH_DECRYPT_FALSE)) - return; + return false; notmuch = notmuch_message_get_database (message); @@ -550,7 +553,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, if (status) _notmuch_database_log_append (notmuch, "failed to add index.decryption " "property (%d)\n", status); - return; + return false; } } #endif @@ -560,7 +563,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, clear = _notmuch_crypto_decrypt (, notmuch_indexopts_get_decrypt_policy (indexopts), message, crypto_ctx, encrypted_data, get_sk ? _result : NULL, ); if (!attempted) - return; + return false; if (err || !clear) { if (decrypt_result) g_object_unref (decrypt_result); @@ -576,7 +579,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, if (status) _notmuch_database_log_append (notmuch, "failed to add index.decryption " "property (%d)\n", status); - return; + return false; } if (decrypt_result) { #if HAVE_GMIME_SESSION_KEYS @@ -597,7 +600,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, if (status) _notmuch_database_log (notmuch, "failed to add index.decryption " "property (%d)\n", status); - +return true; } notmuch_status_t -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 3/5] index: tag text parts with inline PGP encryption as "encrypted"
Assuming we have GMime 3.0 (which has efficient detection of inline PGP encrypted blobs) we should be able to mark those messages with the same tag that we mark PGP/MIME and S/MIME encrypted messages. --- lib/index.cc | 6 ++ test/T359-inline-pgp-decryption.sh | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index f144b9fb..e03f5230 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -468,6 +468,12 @@ _index_mime_part (notmuch_message_t *message, return; } +#if (GMIME_MAJOR_VERSION >= 3) +if (GMIME_IS_TEXT_PART (part) && g_mime_part_get_openpgp_data (GMIME_PART (part)) == GMIME_OPENPGP_DATA_ENCRYPTED) { + _notmuch_message_add_term (message, "tag", "encrypted"); +} +#endif + byte_array = g_byte_array_new (); stream = g_mime_stream_mem_new_with_byte_array (byte_array); diff --git a/test/T359-inline-pgp-decryption.sh b/test/T359-inline-pgp-decryption.sh index c0db8eaf..314ca786 100755 --- a/test/T359-inline-pgp-decryption.sh +++ b/test/T359-inline-pgp-decryption.sh @@ -43,7 +43,7 @@ expected=' }, "id": "X", "match": true, - "tags": ["inbox", "unread"], + "tags": ["encrypted", "inbox", "unread"], "timestamp": 946728000 }, [' @@ -74,7 +74,7 @@ expected=' }, "id": "X", "match": false, - "tags": ["inbox", "unread"], + "tags": ["encrypted", "inbox", "unread"], "timestamp": 946728000 }, "reply-headers": { -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/5] crypto: prepare for decryption of inline PGP encrypted messages
Inline PGP encrypted messages are clearly worse than PGP/MIME structured encrypted messages. There are no standards for how they are formed, and they don't offer any structured metadata about how to interpret the bytestream produced by decrypting them. However, some other MUAs and end-user workflows may make creation of inline PGP encrypted messages the only available option for message encryption, and when Notmuch encounters such a message, it should make a reasonable best-effort to render the cleartext to the user. Due to ambiguities in interpretation of signatures on inline messages (e.g. which parts of the message were actually signed? what character encoding should the bytestream be interpreted as), we continue to ignore inline-signed messages entirely, and we do not look at the validity of any signatures that might be found when decrypting inline PGP encrypted messages. We make use here of GMime's optimization function for detecting the presence of inline PGP encrypted content, which is only found in GMime 3.0 or later. This change prepares the internal codebase for decrypting inline encrypted messages, but does not yet actually use the capability. --- lib/index.cc | 6 +++--- mime-node.c | 24 ++-- util/crypto.c | 35 +++ util/crypto.h | 2 +- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index 22ca9ec1..f144b9fb 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -367,7 +367,7 @@ _index_content_type (notmuch_message_t *message, GMimeObject *part) static void _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, GMimeContentType *content_type, - GMimeMultipartEncrypted *part); + GMimeObject *part); /* Callback to generate terms for each mime part of a message. */ static void @@ -421,7 +421,7 @@ _index_mime_part (notmuch_message_t *message, if (i == GMIME_MULTIPART_ENCRYPTED_CONTENT) { _index_encrypted_mime_part(message, indexopts, content_type, - GMIME_MULTIPART_ENCRYPTED (part)); + part); } else { if (i != GMIME_MULTIPART_ENCRYPTED_VERSION) { _notmuch_database_log (notmuch_message_get_database (message), @@ -518,7 +518,7 @@ static void _index_encrypted_mime_part (notmuch_message_t *message, notmuch_indexopts_t *indexopts, g_mime_3_unused(GMimeContentType *content_type), - GMimeMultipartEncrypted *encrypted_data) + GMimeObject *encrypted_data) { notmuch_status_t status; GError *err = NULL; diff --git a/mime-node.c b/mime-node.c index 75b79f98..973133d9 100644 --- a/mime-node.c +++ b/mime-node.c @@ -196,10 +196,10 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, { GError *err = NULL; GMimeDecryptResult *decrypt_result = NULL; -GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part); notmuch_message_t *message = NULL; -if (! node->decrypted_child) { +if (GMIME_IS_PART (part) || /* must be inline */ + (GMIME_IS_MULTIPART_ENCRYPTED (part) && ! node->decrypted_child)) { for (mime_node_t *parent = node; parent; parent = parent->parent) if (parent->envelope_file) { message = parent->envelope_file; @@ -209,7 +209,7 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, node->decrypted_child = _notmuch_crypto_decrypt (>decrypt_attempted, node->ctx->crypto->decrypt, message, -cryptoctx, encrypteddata, _result, ); +cryptoctx, part, _result, ); } if (! node->decrypted_child) { fprintf (stderr, "Failed to decrypt part: %s\n", @@ -217,15 +217,19 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, goto DONE; } -node->decrypt_success = true; -node->verify_attempted = true; if (decrypt_result) { - /* This may be NULL if the part is not signed. */ - node->sig_list = g_mime_decrypt_result_get_signatures (decrypt_result); - if (node->sig_list) { - g_object_ref (node->sig_list); - set_signature_list_destructor (node); + node->decrypt_success = true; + if (GMIME_IS_MULTIPART_ENCRYPTED (part)) { + /* Only check signatures on PGP/MIME messages, not inline + messages. To understand why, see + https://dkg.fifthhorseman.net/notes/inline-pgp-harmful/ */ +
[PATCH 5/5] index: try indexing the cleartext of inline PGP encrypted text parts
Assuming that we're using GMime 3.0 or later, and the user has asked for decryption of some sort, we should go ahead and index the cleartext. --- lib/index.cc | 7 +++ test/T359-inline-pgp-decryption.sh | 7 +++ 2 files changed, 14 insertions(+) diff --git a/lib/index.cc b/lib/index.cc index 29ede685..49f7cfbf 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -473,6 +473,13 @@ _index_mime_part (notmuch_message_t *message, #if (GMIME_MAJOR_VERSION >= 3) if (GMIME_IS_TEXT_PART (part) && g_mime_part_get_openpgp_data (GMIME_PART (part)) == GMIME_OPENPGP_DATA_ENCRYPTED) { _notmuch_message_add_term (message, "tag", "encrypted"); + if (_index_encrypted_mime_part(message, indexopts, + content_type, + part)) + return; + /* if decryption on inline PGP encrypted message fails, we +* should still fall through and try indexing the MIME part +* anyway (this is what we did before inline PGP decryption) */ } #endif diff --git a/test/T359-inline-pgp-decryption.sh b/test/T359-inline-pgp-decryption.sh index 314ca786..66b85d5b 100755 --- a/test/T359-inline-pgp-decryption.sh +++ b/test/T359-inline-pgp-decryption.sh @@ -94,4 +94,11 @@ output=$(notmuch search 'sekrit') expected='' test_expect_equal "$output" "$expected" +test_begin_subtest "reindexing cleartext of inline PGP encrypted message should succeed" +test_subtest_broken_gmime_2 +notmuch reindex --decrypt=true id:inline-pgp-encryp...@testsuite.notmuchmail.org +output=$(notmuch search 'sekrit') +expected='thread:0001 2000-01-01 [1/1] test_su...@notmuchmail.org; inline PGP encrypted message (encrypted inbox unread)' +test_expect_equal "$output" "$expected" + test_done -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/5] cli/{show, reply}: try to decrypt inline PGP encrypted messages
We try this only for leaf parts that are explicitly marked as Content-Type: text/*, since we don't want to accidentally match on any other weird part that happens to contain the magic string, or on the payload child of a multipart/encrypted part. Of course, this only works for GMime 3.0 and later, because of how we're detecting the presence of the OpenPGP inline encrypted blob. --- mime-node.c| 4 ++ test/T359-inline-pgp-decryption.sh | 97 ++ 2 files changed, 101 insertions(+) create mode 100755 test/T359-inline-pgp-decryption.sh diff --git a/mime-node.c b/mime-node.c index 973133d9..3c94bb62 100644 --- a/mime-node.c +++ b/mime-node.c @@ -325,6 +325,10 @@ _mime_node_create (mime_node_t *parent, GMimeObject *part) } else { node_verify (node, part, cryptoctx); } +#if (GMIME_MAJOR_VERSION >= 3) +} else if (GMIME_IS_TEXT_PART (part) && g_mime_part_get_openpgp_data (GMIME_PART (part)) == GMIME_OPENPGP_DATA_ENCRYPTED) { + node_decrypt_and_verify (node, part, cryptoctx); +#endif } return node; diff --git a/test/T359-inline-pgp-decryption.sh b/test/T359-inline-pgp-decryption.sh new file mode 100755 index ..c0db8eaf --- /dev/null +++ b/test/T359-inline-pgp-decryption.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash + +test_description='Decryption of inline PGP messages' +. $(dirname "$0")/test-lib.sh || exit 1 + +## + +add_gnupg_home + +test_begin_subtest "Adding inline PGP encrypted message" +mkdir -p "$MAIL_DIR/cur" +cat < "$MAIL_DIR/cur/inline-pgp-encrypted.eml" +Message-Id: inline-pgp-encryp...@testsuite.notmuchmail.org +Content-Type: text/plain +Subject: inline PGP encrypted message +Date: Sat, 01 Jan 2000 12:00:00 + +From: test_su...@notmuchmail.org +To: test_su...@notmuchmail.org + +$(echo "this is the sekrit message" | gpg --no-tty --batch --quiet --trust-model=always --encrypt --armor --recipient test_su...@notmuchmail.org) +EOF +test_expect_success 'notmuch new' + +test_begin_subtest "inline PGP decryption, --format=json" +test_subtest_broken_gmime_2 +output=$(notmuch show --format=json --decrypt=true id:inline-pgp-encryp...@testsuite.notmuchmail.org \ +| notmuch_json_show_sanitize) +expected=' + [[[{"body": [{ + "content": "this is the sekrit message\n", + "content-type": "text/plain", + "encstatus": [{"status": "good" }], + "id": 1 + }], + "date_relative": "2000-01-01", + "excluded": false, + "filename": ["Y"], + "headers": { + "Date": "Sat, 01 Jan 2000 12:00:00 +", + "From": "test_su...@notmuchmail.org", + "Subject": "inline PGP encrypted message", + "To": "test_su...@notmuchmail.org" + }, + "id": "X", + "match": true, + "tags": ["inbox", "unread"], + "timestamp": 946728000 + }, + [' + +test_expect_equal_json \ +"$output" \ +"$expected" + +test_begin_subtest "inline PGP decryption for reply" +test_subtest_broken_gmime_2 +output=$(notmuch reply --format=json --decrypt=true id:inline-pgp-encryp...@testsuite.notmuchmail.org \ +| notmuch_json_show_sanitize) +expected=' + {"original": {"body": [{ + "content": "this is the sekrit message\n", + "content-type": "text/plain", + "encstatus": [{"status": "good" }], + "id": 1 + }], + "date_relative": "2000-01-01", + "excluded": false, + "filename": ["Y"], + "headers": { + "Date": "Sat, 01 Jan 2000 12:00:00 +", + "From": "test_su...@notmuchmail.org", + "Subject": "inline PGP encrypted message", + "To": "test_su...@notmuchmail.org" + }, + "id": "X", + "match": false, + "tags": ["inbox", "unread"], + "timestamp": 946728000 + }, + "reply-headers": { + "From": "Notmuch Test Suite", + "In-reply-to": " ", + "References": " ", + "Subject": "Re: inline PGP encrypted message" + } +}' + +test_expect_equal_json \ +"$output" \ +"$expected" + +test_begin_subtest "searching for cleartext of inline PGP encrypted message should fail" +output=$(notmuch search 'sekrit') +expected='' +test_expect_equal "$output" "$expected" + +test_done -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v2] cli/reply: make --decrypt take a keyword
On Tue 2017-12-12 01:52:52 -0500, Daniel Kahn Gillmor wrote: > This brings the --decrypt argument to "notmuch reply" into line with > the other --decrypt arguments (in "show", "new", "insert", and > "reindex"). This patch is really just about bringing consistency to > the user interface. v2 of this patch covers: > We also use the recommended form in the emacs MUA when replying, and > update test T350 to match. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v3] cli/show: make --decrypt take a keyword.
On Tue 2017-12-12 01:51:57 -0500, Daniel Kahn Gillmor wrote: > We also expand tab completion for it, update the emacs bindings, and > update T350, T357, and T450 to match. > > Make use of the bool-to-keyword backward-compatibility feature. and now revision 3 of this patch includes transitioning the emacs bindings to use explicit arguments for --decrypt, and covering the rest of the test suite as well. I think it's settled down now. :) --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v3] cli/show: make --decrypt take a keyword.
We also expand tab completion for it, update the emacs bindings, and update T350, T357, and T450 to match. Make use of the bool-to-keyword backward-compatibility feature. --- completion/notmuch-completion.bash | 6 +- doc/man1/notmuch-show.rst | 37 + emacs/notmuch-lib.el | 2 +- emacs/notmuch-query.el | 2 +- notmuch-show.c | 22 +- test/T350-crypto.sh| 12 ++-- test/T357-index-decryption.sh | 6 +++--- test/T450-emacs-show.sh| 2 +- 8 files changed, 47 insertions(+), 42 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index fb093de8..4ab2e5f6 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -517,10 +517,14 @@ _notmuch_show() COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) ) return ;; - --exclude|--body|--decrypt) + --exclude|--body) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; +--decrypt) + COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) ) + return + ;; esac ! $split && diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index 64caa7a6..7d2b38cb 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -115,22 +115,27 @@ Supported options for **show** include supported with --format=json and --format=sexp), and the multipart/signed part will be replaced by the signed data. -``--decrypt`` -Decrypt any MIME encrypted parts found in the selected content -(ie. "multipart/encrypted" parts). Status of the decryption will -be reported (currently only supported with --format=json and ---format=sexp) and on successful decryption the -multipart/encrypted part will be replaced by the decrypted -content. - -If a session key is already known for the message, then it -will be decrypted automatically unless the user explicitly -sets ``--decrypt=false``. - -Decryption expects a functioning **gpg-agent(1)** to provide any -needed credentials. Without one, the decryption will fail. - -Implies --verify. +``--decrypt=(false|auto|true)`` +If ``true``, decrypt any MIME encrypted parts found in the +selected content (i.e. "multipart/encrypted" parts). Status of +the decryption will be reported (currently only supported +with --format=json and --format=sexp) and on successful +decryption the multipart/encrypted part will be replaced by +the decrypted content. + +If ``auto``, and a session key is already known for the +message, then it will be decrypted, but notmuch will not try +to access the user's keys. + +Use ``false`` to avoid even automatic decryption. + +Non-automatic decryption expects a functioning +**gpg-agent(1)** to provide any needed credentials. Without +one, the decryption will fail. + +Note: ``true`` implies --verify. + +Default: ``auto`` ``--exclude=(true|false)`` Specify whether to omit threads only matching diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el index 010be454..a7e02710 100644 --- a/emacs/notmuch-lib.el +++ b/emacs/notmuch-lib.el @@ -593,7 +593,7 @@ the given type." (set-buffer-multibyte nil)) (let ((args `("show" "--format=raw" ,(format "--part=%s" (plist-get part :id)) - ,@(when process-crypto '("--decrypt")) + ,@(when process-crypto '("--decrypt=true")) ,(notmuch-id-to-query (plist-get msg :id (coding-system-for-read (if binaryp 'no-conversion diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el index 592fd8f1..563e4acf 100644 --- a/emacs/notmuch-query.el +++ b/emacs/notmuch-query.el @@ -32,7 +32,7 @@ is a possibly empty forest of replies. " (let ((args '("show" "--format=sexp" "--format-version=4"))) (if notmuch-show-process-crypto - (setq args (append args '("--decrypt" + (setq args (append args '("--decrypt=true" (setq args (append args search-terms)) (apply #'notmuch-call-notmuch-sexp args))) diff --git a/notmuch-show.c b/notmuch-show.c index d5adc370..9871159d 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1085,8 +1085,6 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) bool exclude = true; bool entire_thread_set = false; bool single_message; -bool decrypt = false; -bool decrypt_set = false; notmuch_opt_desc_t options[] = {
[PATCH v2] cli/reply: make --decrypt take a keyword
This brings the --decrypt argument to "notmuch reply" into line with the other --decrypt arguments (in "show", "new", "insert", and "reindex"). This patch is really just about bringing consistency to the user interface. We also use the recommended form in the emacs MUA when replying, and update test T350 to match. --- completion/notmuch-completion.bash | 2 +- doc/man1/notmuch-reply.rst | 34 -- emacs/notmuch-mua.el | 2 +- notmuch-reply.c| 11 ++- test/T350-crypto.sh| 2 +- 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index 4ab2e5f6..a24b8a08 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -351,7 +351,7 @@ _notmuch_reply() return ;; --decrypt) - COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) ) return ;; esac diff --git a/doc/man1/notmuch-reply.rst b/doc/man1/notmuch-reply.rst index ede77930..1b62e075 100644 --- a/doc/man1/notmuch-reply.rst +++ b/doc/man1/notmuch-reply.rst @@ -72,20 +72,26 @@ Supported options for **reply** include in this order, and copy values from the first that contains something other than only the user's addresses. -``--decrypt`` -Decrypt any MIME encrypted parts found in the selected content -(ie. "multipart/encrypted" parts). Status of the decryption will -be reported (currently only supported with --format=json and ---format=sexp) and on successful decryption the -multipart/encrypted part will be replaced by the decrypted -content. - -If a session key is already known for the message, then it -will be decrypted automatically unless the user explicitly -sets ``--decrypt=false``. - -Decryption expects a functioning **gpg-agent(1)** to provide any -needed credentials. Without one, the decryption will likely fail. +``--decrypt=(false|auto|true)`` + +If ``true``, decrypt any MIME encrypted parts found in the +selected content (i.e., "multipart/encrypted" parts). Status +of the decryption will be reported (currently only supported +with --format=json and --format=sexp), and on successful +decryption the multipart/encrypted part will be replaced by +the decrypted content. + +If ``auto``, and a session key is already known for the +message, then it will be decrypted, but notmuch will not try +to access the user's secret keys. + +Use ``false`` to avoid even automatic decryption. + +Non-automatic decryption expects a functioning +**gpg-agent(1)** to provide any needed credentials. Without +one, the decryption will likely fail. + +Default: ``auto`` See **notmuch-search-terms(7)** for details of the supported syntax for . diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index 7a341ebf..59b546a6 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -181,7 +181,7 @@ mutiple parts get a header." reply original) (when process-crypto - (setq args (append args '("--decrypt" + (setq args (append args '("--decrypt=true" (if reply-all (setq args (append args '("--reply-to=all"))) diff --git a/notmuch-reply.c b/notmuch-reply.c index 5cdf642b..75cf7ecb 100644 --- a/notmuch-reply.c +++ b/notmuch-reply.c @@ -704,8 +704,6 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) }; int format = FORMAT_DEFAULT; int reply_all = true; -bool decrypt = false; -bool decrypt_set = false; notmuch_opt_desc_t options[] = { { .opt_keyword = , .name = "format", .keywords = @@ -719,7 +717,12 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) (notmuch_keyword_t []){ { "all", true }, { "sender", false }, { 0, 0 } } }, - { .opt_bool = , .name = "decrypt", .present = _set }, + { .opt_keyword = (int*)(), .name = "decrypt", + .keyword_no_arg_value = "true", .keywords = + (notmuch_keyword_t []){ { "false", NOTMUCH_DECRYPT_FALSE }, + { "auto", NOTMUCH_DECRYPT_AUTO }, + { "true", NOTMUCH_DECRYPT_NOSTASH }, + { 0, 0 } } }, { .opt_inherit = notmuch_shared_options }, { } }; @@ -729,8 +732,6 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; notmuch_process_shared_options (argv[0]); -if (decrypt_set) - params.crypto.decrypt = decrypt ? NOTMUCH_DECRYPT_NOSTASH :
[PATCH] make release archive: common (or no) timestamps
The appended file 'version' has the same timestamp as the files added by `git archive`. The original file name and time stamp are no longer saved to the gzip header in resulting $(PACKAGE)-$(VERSION).tar.gz file. When build environment is close enough to another, this may provide mutually reproducible release archive files. --- The best way to realize improvements in a patch set is to send it >;/ V2 of id:20171211173102.6279-1-tomi.oll...@iki.fi Replaces file touch with --mtime= GNU tar(1) option (diffdiff with V1): : +++ b/Makefile.local : @@ -34,6 +34,5 @@ $(TAR_FILE): : ct=`git --no-pager log -1 --pretty=format:%ct $$ref` ; \ : - touch -d @$$ct version.tmp : tar --owner root --group root --append -f $(TAR_FILE).tmp \ : --transform s_^_$(PACKAGE)-$(VERSION)/_ \ : - --transform 's_.tmp$$__' version.tmp : + --transform 's_.tmp$$__' --mtime=@$$ct version.tmp : rm version.tmp Makefile.local | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile.local b/Makefile.local index 9505b7fee70b..1535c2ae8a7b 100644 --- a/Makefile.local +++ b/Makefile.local @@ -31,11 +31,12 @@ $(TAR_FILE): fi ; \ git archive --format=tar --prefix=$(PACKAGE)-$(VERSION)/ $$ref > $(TAR_FILE).tmp echo $(VERSION) > version.tmp + ct=`git --no-pager log -1 --pretty=format:%ct $$ref` ; \ tar --owner root --group root --append -f $(TAR_FILE).tmp \ --transform s_^_$(PACKAGE)-$(VERSION)/_ \ - --transform 's_.tmp$$__' version.tmp + --transform 's_.tmp$$__' --mtime=@$$ct version.tmp rm version.tmp - gzip < $(TAR_FILE).tmp > $(TAR_FILE) + gzip -n < $(TAR_FILE).tmp > $(TAR_FILE) @echo "Source is ready for release in $(TAR_FILE)" $(SHA256_FILE): $(TAR_FILE) -- 2.13.3 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2] properties: add notmuch_message_count_properties
The user can already do this manually, of course, but (a) it's nice to have a convenience function, and (b) exposing this interface means that someone more clever with a _notmuch_string_map_t than i am can write a more efficient version if they like, and it will just accelerate the users of the convenience function. --- lib/message-property.cc | 25 + lib/notmuch.h | 16 2 files changed, 41 insertions(+) diff --git a/lib/message-property.cc b/lib/message-property.cc index 2e44a386..7894016c 100644 --- a/lib/message-property.cc +++ b/lib/message-property.cc @@ -36,6 +36,31 @@ notmuch_message_get_property (notmuch_message_t *message, const char *key, const return NOTMUCH_STATUS_SUCCESS; } +notmuch_status_t +notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count) +{ +if (! count || ! key || ! message) + return NOTMUCH_STATUS_NULL_POINTER; + +notmuch_string_map_t *map; +map = _notmuch_message_property_map (message); +if (! map) + return NOTMUCH_STATUS_NULL_POINTER; + +notmuch_string_map_iterator_t *matcher = _notmuch_string_map_iterator_create (map, key, true); +if (! matcher) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + +*count = 0; +while (_notmuch_string_map_iterator_valid (matcher)) { + (*count)++; + _notmuch_string_map_iterator_move_to_next (matcher); +} + +_notmuch_string_map_iterator_destroy (matcher); +return NOTMUCH_STATUS_SUCCESS; +} + static notmuch_status_t _notmuch_message_modify_property (notmuch_message_t *message, const char *key, const char *value, bool delete_it) diff --git a/lib/notmuch.h b/lib/notmuch.h index bcf9b68a..141425ee 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -1890,6 +1890,22 @@ typedef struct _notmuch_string_map_iterator notmuch_message_properties_t; notmuch_message_properties_t * notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact); +/** + * Return the number of properties named "key" belonging to the specific message. + * + * @param[in] message The message to examine + * @param[in] key key to count + * @param[out] count The number of matching properties associated with this message. + * + * @returns + * + * NOTMUCH_STATUS_SUCCESS: successful count, possibly some other error. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_status_t +notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count); + /** * Is the given *properties* iterator pointing at a valid (key,value) * pair. -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/5] properties: add notmuch_message_count_properties
The user can already do this manually, of course, but (a) it's nice to have a convenience function, and (b) exposing this interface means that someone more clever with a _notmuch_string_map_t than i am can write a more efficient version if they like, and it will just accelerate the users of the convenience function. --- lib/message-property.cc | 25 + lib/notmuch.h | 15 +++ 2 files changed, 40 insertions(+) diff --git a/lib/message-property.cc b/lib/message-property.cc index 2e44a386..7894016c 100644 --- a/lib/message-property.cc +++ b/lib/message-property.cc @@ -36,6 +36,31 @@ notmuch_message_get_property (notmuch_message_t *message, const char *key, const return NOTMUCH_STATUS_SUCCESS; } +notmuch_status_t +notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count) +{ +if (! count || ! key || ! message) + return NOTMUCH_STATUS_NULL_POINTER; + +notmuch_string_map_t *map; +map = _notmuch_message_property_map (message); +if (! map) + return NOTMUCH_STATUS_NULL_POINTER; + +notmuch_string_map_iterator_t *matcher = _notmuch_string_map_iterator_create (map, key, true); +if (! matcher) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + +*count = 0; +while (_notmuch_string_map_iterator_valid (matcher)) { + (*count)++; + _notmuch_string_map_iterator_move_to_next (matcher); +} + +_notmuch_string_map_iterator_destroy (matcher); +return NOTMUCH_STATUS_SUCCESS; +} + static notmuch_status_t _notmuch_message_modify_property (notmuch_message_t *message, const char *key, const char *value, bool delete_it) diff --git a/lib/notmuch.h b/lib/notmuch.h index bcf9b68a..9e62766b 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -1890,6 +1890,21 @@ typedef struct _notmuch_string_map_iterator notmuch_message_properties_t; notmuch_message_properties_t * notmuch_message_get_properties (notmuch_message_t *message, const char *key, notmuch_bool_t exact); +/** + * Return the number of properties named "key" belonging to the specific message. + * + * @param[in] message The message to examine + * @param[in] key key to count + * + * @returns + * + * NOTMUCH_STATUS_SUCCESS: successful count, possibly some other error. + * + * @since libnotmuch 5.1 (notmuch 0.26) + */ +notmuch_status_t +notmuch_message_count_properties (notmuch_message_t *message, const char *key, unsigned int *count); + /** * Is the given *properties* iterator pointing at a valid (key,value) * pair. -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 4/5] cli/show: reindex when we learned new session keys about a message
If the number of session keys for a given message increased after running "notmuch show" then we just learned something new that might let us do automatic decryption. We should reindex this message using our newfound knowledge. --- notmuch-show.c | 20 1 file changed, 20 insertions(+) diff --git a/notmuch-show.c b/notmuch-show.c index 9871159d..90e45cd9 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -873,6 +873,11 @@ show_message (void *ctx, void *local = talloc_new (ctx); mime_node_t *root, *part; notmuch_status_t status; +unsigned int session_keys = 0; +notmuch_status_t session_key_count_error = NOTMUCH_STATUS_SUCCESS; + +if (params->crypto.decrypt == NOTMUCH_DECRYPT_TRUE) + session_key_count_error = notmuch_message_count_properties (message, "session-key", _keys); status = mime_node_open (local, message, &(params->crypto), ); if (status) @@ -880,6 +885,21 @@ show_message (void *ctx, part = mime_node_seek_dfs (root, (params->part < 0 ? 0 : params->part)); if (part) status = format->part (local, sp, part, indent, params); + +if (params->crypto.decrypt == NOTMUCH_DECRYPT_TRUE && session_key_count_error == NOTMUCH_STATUS_SUCCESS) { + unsigned int new_session_keys = 0; + if (notmuch_message_count_properties (message, "session-key", _session_keys) == NOTMUCH_STATUS_SUCCESS && + new_session_keys > session_keys) { + /* try a quiet re-indexing */ + notmuch_indexopts_t *indexopts = notmuch_database_get_default_indexopts (notmuch_message_get_database (message)); + if (indexopts) { + notmuch_indexopts_set_decrypt_policy (indexopts, NOTMUCH_DECRYPT_AUTO); + status = notmuch_message_reindex (message, indexopts); + if (status) + fprintf (stderr, "Error re-indexing message with --decrypt=stash. (%d) %s\n", status, notmuch_status_to_string (status)); + } + } +} DONE: talloc_free (local); return status; -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 3/5] cli: write session keys to database, if asked to do so
If the decryption policy is NOTMUCH_DECRYPT_TRUE, that means we want to stash session keys in the database. Note that there is currently no way from the command line to set it this way, though, so it is not yet included in the test suite. --- mime-node.c | 24 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/mime-node.c b/mime-node.c index 11df082b..75b79f98 100644 --- a/mime-node.c +++ b/mime-node.c @@ -197,16 +197,18 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, GError *err = NULL; GMimeDecryptResult *decrypt_result = NULL; GMimeMultipartEncrypted *encrypteddata = GMIME_MULTIPART_ENCRYPTED (part); +notmuch_message_t *message = NULL; if (! node->decrypted_child) { - mime_node_t *parent; - for (parent = node; parent; parent = parent->parent) - if (parent->envelope_file) + for (mime_node_t *parent = node; parent; parent = parent->parent) + if (parent->envelope_file) { + message = parent->envelope_file; break; + } node->decrypted_child = _notmuch_crypto_decrypt (>decrypt_attempted, node->ctx->crypto->decrypt, -parent ? parent->envelope_file : NULL, +message, cryptoctx, encrypteddata, _result, ); } if (! node->decrypted_child) { @@ -225,6 +227,20 @@ node_decrypt_and_verify (mime_node_t *node, GMimeObject *part, g_object_ref (node->sig_list); set_signature_list_destructor (node); } + +#if HAVE_GMIME_SESSION_KEYS + if (node->ctx->crypto->decrypt == NOTMUCH_DECRYPT_TRUE && message) { + notmuch_database_t *db = notmuch_message_get_database (message); + const char *sk = g_mime_decrypt_result_get_session_key (decrypt_result); + if (db && sk) { + notmuch_status_t status; + status = notmuch_message_add_property (message, "session-key", sk); + if (status) + fprintf (stderr, "Failed to stash session key in the database (%d) %s\n", +status, notmuch_status_to_string (status)); + } + } +#endif g_object_unref (decrypt_result); } -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 5/5] cli/show: enable --decrypt=stash
Add fancy new feature, which makes "notmuch show" capable of actually indexing messages that it just decrypted. This enables a workflow where messages can come in in the background and be indexed using "--decrypt=auto". But when showing an encrypted message for the first time, it gets automatically indexed. This is something of a departure for "notmuch show" -- in particular, because it requires read/write access to the database. However, this might be a common use case -- people get mail delivered and indexed in the background, but only want access to their secret key to happen when they're directly interacting with notmuch itself. In such a scenario, they couldn't search newly-delivered, encrypted messages, but they could search for them once they've read them. Documentation of this new feature also uses a table form, similar to that found in the description of index.decrypt in notmuch-config(1). A notmuch UI that wants to facilitate this workflow while also offering an interactive search interface might instead make use of these additional commands while the user is at the console: Count received encrypted messages (if > 0, there are some things we haven't yet tried to index, and therefore can't yet search): notmuch count tag:encrypted and \ not property:index.decryption=success and \ not property:index.decryption=failure Reindex those messages: notmuch reindex --try-decrypt=true tag:encrypted and \ not property:index.decryption=success and \ not property:index.decryption=failure --- completion/notmuch-completion.bash | 2 +- doc/man1/notmuch-show.rst | 35 --- notmuch-show.c | 9 +++-- test/T357-index-decryption.sh | 18 ++ 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index a24b8a08..16ae3992 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -522,7 +522,7 @@ _notmuch_show() return ;; --decrypt) - COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "true auto false stash" -- "${cur}" ) ) return ;; esac diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index 7d2b38cb..5fd9876e 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -115,7 +115,7 @@ Supported options for **show** include supported with --format=json and --format=sexp), and the multipart/signed part will be replaced by the signed data. -``--decrypt=(false|auto|true)`` +``--decrypt=(false|auto|true|stash)`` If ``true``, decrypt any MIME encrypted parts found in the selected content (i.e. "multipart/encrypted" parts). Status of the decryption will be reported (currently only supported @@ -123,17 +123,46 @@ Supported options for **show** include decryption the multipart/encrypted part will be replaced by the decrypted content. +``stash`` behaves like ``true``, but upon successful +decryption it will also stash the message's session key in the +database, and index the cleartext of the message, enabling +automatic decryption in the future. + If ``auto``, and a session key is already known for the message, then it will be decrypted, but notmuch will not try to access the user's keys. Use ``false`` to avoid even automatic decryption. -Non-automatic decryption expects a functioning +Non-automatic decryption (``stash`` or ``true``, in the +absence of a stashed session key) expects a functioning **gpg-agent(1)** to provide any needed credentials. Without one, the decryption will fail. -Note: ``true`` implies --verify. +Note: setting either ``true`` or ``stash`` here implies +``--verify``. + +Here is a table that summarizes each of these policies: + +++---+--+--+---+ +|| false | auto | true | stash | +++===+==+==+===+ +| Show cleartext if | | X | X | X | +| session key is | | | | | +| already known | | | | | +++---+--+--+---+ +| Use secret keys to | | | X | X | +| show cleartext | | | | | +++---+--+--+---+ +| Stash any newly| | | | X | +| recovered session keys,| | | | | +| reindexing message if | | | | | +|
notmuch show --decrypt=stash
This series allows "notmuch show" to index the cleartext and stash the session keys of an encrypted message while displaying it. Because it uses a keyword argument to --decrypt for "notmuch show", It needs to be applied *after* the series with the subject: Encourage explicit arguments for --decrypt in "show" and "reply" Background -- The cleartext indexing and session-keys series make working with encrypted e-mail significantly easier in notmuch. However, their underlying assumption is that at the time of message ingestion (and "notmuch new" in particular), the user is likely to have access to their long-term secret keys. In practice, many people using GnuPG today have their secret keys locked behind a passphrase, or on a smartcard, and also run "notmuch new" in some sort of scheduled, backgrounded process. The result is that for users with this workflow, GnuPG prompts for their passphrase (or to trigger their smartcard) at unpredictable times, depending on when their mail delivery happens, and on how many encrypted messages they receive. This is both unfriendly and bad for security (we should not train users to approve random prompts for secret key access when nothing they're doing interactively seems to warrant it). Outline --- For a friendlier experience, some users may prefer incoming encrypted mail to stay in their inbox *without* being decrypted, until they choose to look at it. At the moment that they're looking at it, their MUA is in the foreground and they're interacting with it, so being prompted for their password or smartcard interactively makes sense at that time. This series makes it possible for this interaction to to actually decrypt the message, index it, and stash any session keys the first time the user interacts with the message through "notmuch show". This is not a workflow that every MUA will choose to use (e.g. users whose decryption-capable secret key is already cheaply available without hassling the user at "notmuch new" shouldn't use it), but it is a sensible workflow for some users that notmuch should support. Furthermore, it is a more efficient use of secret key material -- a user that wants to stash session keys of a message, but whose long-term decryption secret key is on a smartcard should only be obliged to trigger the smartcard once per message, ever. Implementation details -- The most controversial part of this series is that it makes "notmuch show" potentially not a read-only operation on the database. This is a tradeoff that the users of this workflow will need to consider, since they are explicitly asking "notmuch show" to potentially modify their index. Note that i've made this R/O-to-R/W switch fairly coarse. If the user requests --decrypt=stash, then "notmuch show" will operate on a read/write database, regardless of whether the message is actually encrypted. I used this coarse approach because i couldn't figure out a safe way to reopen an existing read-only database in read-write mode. If someone more clever with Xapian than me wants to suggest a way to do this in a more fine-grained fashion, i'd welcome patches or pointers. I welcome review and feedback. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/5] lib: expose notmuch_message_get_database()
We've had _notmuch_message_database() internally for a while, and it's useful. It turns out to be useful on the other side of the library interface as well (i'll use it later in this series for "notmuch show"), so we expose it publicly now. --- lib/index.cc| 10 +- lib/message-property.cc | 4 ++-- lib/message.cc | 14 +++--- lib/notmuch-private.h | 2 -- lib/notmuch.h | 8 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/index.cc b/lib/index.cc index 0ad683fa..22ca9ec1 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -385,7 +385,7 @@ _index_mime_part (notmuch_message_t *message, const char *charset; if (! part) { - _notmuch_database_log (_notmuch_message_database (message), + _notmuch_database_log (notmuch_message_get_database (message), "Warning: Not indexing empty mime part.\n"); return; } @@ -411,7 +411,7 @@ _index_mime_part (notmuch_message_t *message, g_mime_multipart_get_part (multipart, i)); continue; } else if (i != GMIME_MULTIPART_SIGNED_CONTENT) { - _notmuch_database_log (_notmuch_message_database (message), + _notmuch_database_log (notmuch_message_get_database (message), "Warning: Unexpected extra parts of multipart/signed. Indexing anyway.\n"); } } @@ -424,7 +424,7 @@ _index_mime_part (notmuch_message_t *message, GMIME_MULTIPART_ENCRYPTED (part)); } else { if (i != GMIME_MULTIPART_ENCRYPTED_VERSION) { - _notmuch_database_log (_notmuch_message_database (message), + _notmuch_database_log (notmuch_message_get_database (message), "Warning: Unexpected extra parts of multipart/encrypted.\n"); } } @@ -447,7 +447,7 @@ _index_mime_part (notmuch_message_t *message, } if (! (GMIME_IS_PART (part))) { - _notmuch_database_log (_notmuch_message_database (message), + _notmuch_database_log (notmuch_message_get_database (message), "Warning: Not indexing unknown mime part: %s.\n", g_type_name (G_OBJECT_TYPE (part))); return; @@ -528,7 +528,7 @@ _index_encrypted_mime_part (notmuch_message_t *message, if (!indexopts || (notmuch_indexopts_get_decrypt_policy (indexopts) == NOTMUCH_DECRYPT_FALSE)) return; -notmuch = _notmuch_message_database (message); +notmuch = notmuch_message_get_database (message); GMimeCryptoContext* crypto_ctx = NULL; #if (GMIME_MAJOR_VERSION < 3) diff --git a/lib/message-property.cc b/lib/message-property.cc index 35eaf3c6..2e44a386 100644 --- a/lib/message-property.cc +++ b/lib/message-property.cc @@ -44,7 +44,7 @@ _notmuch_message_modify_property (notmuch_message_t *message, const char *key, c notmuch_status_t status; char *term = NULL; -status = _notmuch_database_ensure_writable (_notmuch_message_database (message)); +status = _notmuch_database_ensure_writable (notmuch_message_get_database (message)); if (status) return status; @@ -92,7 +92,7 @@ _notmuch_message_remove_all_properties (notmuch_message_t *message, const char * notmuch_status_t status; const char * term_prefix; -status = _notmuch_database_ensure_writable (_notmuch_message_database (message)); +status = _notmuch_database_ensure_writable (notmuch_message_get_database (message)); if (status) return status; diff --git a/lib/message.cc b/lib/message.cc index d5db89b6..0886b22d 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -268,7 +268,7 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch, doc_id = _notmuch_database_generate_doc_id (notmuch); } catch (const Xapian::Error ) { - _notmuch_database_log(_notmuch_message_database (message), "A Xapian exception occurred creating message: %s\n", + _notmuch_database_log(notmuch_message_get_database (message), "A Xapian exception occurred creating message: %s\n", error.get_msg().c_str()); notmuch->exception_reported = true; *status_ret = NOTMUCH_PRIVATE_STATUS_XAPIAN_EXCEPTION; @@ -495,7 +495,7 @@ _notmuch_message_ensure_message_file (notmuch_message_t *message) return; message->message_file = _notmuch_message_file_open_ctx ( - _notmuch_message_database (message), message, filename); + notmuch_message_get_database (message), message, filename); } const char * @@ -525,7 +525,7 @@ notmuch_message_get_header (notmuch_message_t *message, const char *header) return talloc_strdup (message, value.c_str ()); } catch
Re: [PATCH v2] cli/show: make --decrypt take a keyword.
On Mon 2017-12-11 21:33:57 -0500, Daniel Kahn Gillmor wrote: > We also expand tab completion for it, and update T357 to match. > > Make use of the bool-to-keyword backward-compatibility feature. v2 of this patch just removes an unnecessary attempt to open the database read-write. That isn't necessary here, though it will be necessary if we want to enable future versions of "notmuch show" that can also interactively add a message to the index. I removed it from this series so that the interface normalization here (which is valuable whether or not we decide to augment "notmuch show" as described) doesn't get distracted by the change. sorry for the quick revision. --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v2] cli/show: make --decrypt take a keyword.
We also expand tab completion for it, and update T357 to match. Make use of the bool-to-keyword backward-compatibility feature. --- completion/notmuch-completion.bash | 6 +- doc/man1/notmuch-show.rst | 37 + notmuch-show.c | 22 +- test/T357-index-decryption.sh | 6 +++--- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index fb093de8..4ab2e5f6 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -517,10 +517,14 @@ _notmuch_show() COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) ) return ;; - --exclude|--body|--decrypt) + --exclude|--body) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; +--decrypt) + COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) ) + return + ;; esac ! $split && diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index 64caa7a6..7d2b38cb 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -115,22 +115,27 @@ Supported options for **show** include supported with --format=json and --format=sexp), and the multipart/signed part will be replaced by the signed data. -``--decrypt`` -Decrypt any MIME encrypted parts found in the selected content -(ie. "multipart/encrypted" parts). Status of the decryption will -be reported (currently only supported with --format=json and ---format=sexp) and on successful decryption the -multipart/encrypted part will be replaced by the decrypted -content. - -If a session key is already known for the message, then it -will be decrypted automatically unless the user explicitly -sets ``--decrypt=false``. - -Decryption expects a functioning **gpg-agent(1)** to provide any -needed credentials. Without one, the decryption will fail. - -Implies --verify. +``--decrypt=(false|auto|true)`` +If ``true``, decrypt any MIME encrypted parts found in the +selected content (i.e. "multipart/encrypted" parts). Status of +the decryption will be reported (currently only supported +with --format=json and --format=sexp) and on successful +decryption the multipart/encrypted part will be replaced by +the decrypted content. + +If ``auto``, and a session key is already known for the +message, then it will be decrypted, but notmuch will not try +to access the user's keys. + +Use ``false`` to avoid even automatic decryption. + +Non-automatic decryption expects a functioning +**gpg-agent(1)** to provide any needed credentials. Without +one, the decryption will fail. + +Note: ``true`` implies --verify. + +Default: ``auto`` ``--exclude=(true|false)`` Specify whether to omit threads only matching diff --git a/notmuch-show.c b/notmuch-show.c index d5adc370..9871159d 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1085,8 +1085,6 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) bool exclude = true; bool entire_thread_set = false; bool single_message; -bool decrypt = false; -bool decrypt_set = false; notmuch_opt_desc_t options[] = { { .opt_keyword = , .name = "format", .keywords = @@ -1101,7 +1099,12 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) { .opt_bool = _thread, .name = "entire-thread", .present = _thread_set }, { .opt_int = , .name = "part" }, - { .opt_bool = , .name = "decrypt", .present = _set }, + { .opt_keyword = (int*)(), .name = "decrypt", + .keyword_no_arg_value = "true", .keywords = + (notmuch_keyword_t []){ { "false", NOTMUCH_DECRYPT_FALSE }, + { "auto", NOTMUCH_DECRYPT_AUTO }, + { "true", NOTMUCH_DECRYPT_NOSTASH }, + { 0, 0 } } }, { .opt_bool = , .name = "verify" }, { .opt_bool = _body, .name = "body" }, { .opt_bool = _html, .name = "include-html" }, @@ -1115,16 +1118,9 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) notmuch_process_shared_options (argv[0]); -if (decrypt_set) { - if (decrypt) { - /* we do not need or want to ask for session keys */ - params.crypto.decrypt = NOTMUCH_DECRYPT_NOSTASH; - /* decryption implies verification */ - params.crypto.verify = true; - } else { - params.crypto.decrypt = NOTMUCH_DECRYPT_FALSE; - } -} +/* explicit decryption implies verification */ +if (params.crypto.decrypt
Encourage explicit arguments for --decrypt in "show" and "reply"
The notmuch indexing subcommands ("new", "insert", and "reindex") now have a --decrypt option that takes an argument (the decryption policy), since the session-keys patches have landed. But the viewing subcommands ("show" and "reply") have their traditional --decrypt option that (as a boolean) need not take an argument, having --decrypt not present means something different from either --decrypt=true or --decrypt=false. This series allows the user to explicitly choose --decrypt=auto for the viewing subcommands, while allowing people to use the argument-free form (as an alias for --decrypt=true), but warns the user to encourage them to switch to using an explicit argument instead. This is useful normalizing work for the interface, so it's worthwhile on its own. It is also necessary preparation in the event that we decide we want to: * set up a notmuch configuration option that changes the default for --decrypt for the viewing subcommands * allow "notmuch show" to actually index encrypted messages upon their first encounter (e.g., via a new decryption policy, which i'll propose separately) As always, review and feedback welcome! --dkg ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 2/3] cli/show: make --decrypt take a keyword.
We also expand tab completion for it, and update T357 to match. Make use of the bool-to-keyword backward-compatibility feature. --- completion/notmuch-completion.bash | 6 +- doc/man1/notmuch-show.rst | 37 + notmuch-show.c | 27 +-- test/T357-index-decryption.sh | 6 +++--- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index fb093de8..4ab2e5f6 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -517,10 +517,14 @@ _notmuch_show() COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) ) return ;; - --exclude|--body|--decrypt) + --exclude|--body) COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) return ;; +--decrypt) + COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) ) + return + ;; esac ! $split && diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst index 64caa7a6..7d2b38cb 100644 --- a/doc/man1/notmuch-show.rst +++ b/doc/man1/notmuch-show.rst @@ -115,22 +115,27 @@ Supported options for **show** include supported with --format=json and --format=sexp), and the multipart/signed part will be replaced by the signed data. -``--decrypt`` -Decrypt any MIME encrypted parts found in the selected content -(ie. "multipart/encrypted" parts). Status of the decryption will -be reported (currently only supported with --format=json and ---format=sexp) and on successful decryption the -multipart/encrypted part will be replaced by the decrypted -content. - -If a session key is already known for the message, then it -will be decrypted automatically unless the user explicitly -sets ``--decrypt=false``. - -Decryption expects a functioning **gpg-agent(1)** to provide any -needed credentials. Without one, the decryption will fail. - -Implies --verify. +``--decrypt=(false|auto|true)`` +If ``true``, decrypt any MIME encrypted parts found in the +selected content (i.e. "multipart/encrypted" parts). Status of +the decryption will be reported (currently only supported +with --format=json and --format=sexp) and on successful +decryption the multipart/encrypted part will be replaced by +the decrypted content. + +If ``auto``, and a session key is already known for the +message, then it will be decrypted, but notmuch will not try +to access the user's keys. + +Use ``false`` to avoid even automatic decryption. + +Non-automatic decryption expects a functioning +**gpg-agent(1)** to provide any needed credentials. Without +one, the decryption will fail. + +Note: ``true`` implies --verify. + +Default: ``auto`` ``--exclude=(true|false)`` Specify whether to omit threads only matching diff --git a/notmuch-show.c b/notmuch-show.c index d5adc370..ddd3c8c5 100644 --- a/notmuch-show.c +++ b/notmuch-show.c @@ -1085,8 +1085,6 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) bool exclude = true; bool entire_thread_set = false; bool single_message; -bool decrypt = false; -bool decrypt_set = false; notmuch_opt_desc_t options[] = { { .opt_keyword = , .name = "format", .keywords = @@ -1101,7 +1099,12 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) { .opt_bool = _thread, .name = "entire-thread", .present = _thread_set }, { .opt_int = , .name = "part" }, - { .opt_bool = , .name = "decrypt", .present = _set }, + { .opt_keyword = (int*)(), .name = "decrypt", + .keyword_no_arg_value = "true", .keywords = + (notmuch_keyword_t []){ { "false", NOTMUCH_DECRYPT_FALSE }, + { "auto", NOTMUCH_DECRYPT_AUTO }, + { "true", NOTMUCH_DECRYPT_NOSTASH }, + { 0, 0 } } }, { .opt_bool = , .name = "verify" }, { .opt_bool = _body, .name = "body" }, { .opt_bool = _html, .name = "include-html" }, @@ -1115,16 +1118,9 @@ notmuch_show_command (notmuch_config_t *config, int argc, char *argv[]) notmuch_process_shared_options (argv[0]); -if (decrypt_set) { - if (decrypt) { - /* we do not need or want to ask for session keys */ - params.crypto.decrypt = NOTMUCH_DECRYPT_NOSTASH; - /* decryption implies verification */ - params.crypto.verify = true; - } else { - params.crypto.decrypt = NOTMUCH_DECRYPT_FALSE; - } -} +/* explicit decryption implies verification */ +if
[PATCH 3/3] cli/reply: make --decrypt take a keyword
This brings the --decrypt argument to "notmuch reply" into line with the other --decrypt arguments (in "show", "new", "insert", and "reindex"). This patch is really just about bringing consistency to the user interface. --- completion/notmuch-completion.bash | 2 +- doc/man1/notmuch-reply.rst | 34 -- notmuch-reply.c| 11 ++- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash index 4ab2e5f6..a24b8a08 100644 --- a/completion/notmuch-completion.bash +++ b/completion/notmuch-completion.bash @@ -351,7 +351,7 @@ _notmuch_reply() return ;; --decrypt) - COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) ) + COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) ) return ;; esac diff --git a/doc/man1/notmuch-reply.rst b/doc/man1/notmuch-reply.rst index ede77930..1b62e075 100644 --- a/doc/man1/notmuch-reply.rst +++ b/doc/man1/notmuch-reply.rst @@ -72,20 +72,26 @@ Supported options for **reply** include in this order, and copy values from the first that contains something other than only the user's addresses. -``--decrypt`` -Decrypt any MIME encrypted parts found in the selected content -(ie. "multipart/encrypted" parts). Status of the decryption will -be reported (currently only supported with --format=json and ---format=sexp) and on successful decryption the -multipart/encrypted part will be replaced by the decrypted -content. - -If a session key is already known for the message, then it -will be decrypted automatically unless the user explicitly -sets ``--decrypt=false``. - -Decryption expects a functioning **gpg-agent(1)** to provide any -needed credentials. Without one, the decryption will likely fail. +``--decrypt=(false|auto|true)`` + +If ``true``, decrypt any MIME encrypted parts found in the +selected content (i.e., "multipart/encrypted" parts). Status +of the decryption will be reported (currently only supported +with --format=json and --format=sexp), and on successful +decryption the multipart/encrypted part will be replaced by +the decrypted content. + +If ``auto``, and a session key is already known for the +message, then it will be decrypted, but notmuch will not try +to access the user's secret keys. + +Use ``false`` to avoid even automatic decryption. + +Non-automatic decryption expects a functioning +**gpg-agent(1)** to provide any needed credentials. Without +one, the decryption will likely fail. + +Default: ``auto`` See **notmuch-search-terms(7)** for details of the supported syntax for . diff --git a/notmuch-reply.c b/notmuch-reply.c index 5cdf642b..75cf7ecb 100644 --- a/notmuch-reply.c +++ b/notmuch-reply.c @@ -704,8 +704,6 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) }; int format = FORMAT_DEFAULT; int reply_all = true; -bool decrypt = false; -bool decrypt_set = false; notmuch_opt_desc_t options[] = { { .opt_keyword = , .name = "format", .keywords = @@ -719,7 +717,12 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) (notmuch_keyword_t []){ { "all", true }, { "sender", false }, { 0, 0 } } }, - { .opt_bool = , .name = "decrypt", .present = _set }, + { .opt_keyword = (int*)(), .name = "decrypt", + .keyword_no_arg_value = "true", .keywords = + (notmuch_keyword_t []){ { "false", NOTMUCH_DECRYPT_FALSE }, + { "auto", NOTMUCH_DECRYPT_AUTO }, + { "true", NOTMUCH_DECRYPT_NOSTASH }, + { 0, 0 } } }, { .opt_inherit = notmuch_shared_options }, { } }; @@ -729,8 +732,6 @@ notmuch_reply_command (notmuch_config_t *config, int argc, char *argv[]) return EXIT_FAILURE; notmuch_process_shared_options (argv[0]); -if (decrypt_set) - params.crypto.decrypt = decrypt ? NOTMUCH_DECRYPT_NOSTASH : NOTMUCH_DECRYPT_FALSE; notmuch_exit_if_unsupported_format (); -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/3] cli: some keyword options can be supplied with no argument
We might change some notmuch command line tools that used to be booleans into keyword arguments. In that case, there are some legacy tools that will expect to be able to do "notmuch foo --bar" instead of "notmuch foo --bar=baz". This patch makes it possible to support that older API, while providing a warning and an encouragement to upgrade. --- command-line-arguments.c | 59 +++ command-line-arguments.h | 4 +++ test/T410-argument-parsing.sh | 24 ++ test/arg-test.c | 12 - 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/command-line-arguments.c b/command-line-arguments.c index db73ca5e..d0e21693 100644 --- a/command-line-arguments.c +++ b/command-line-arguments.c @@ -4,13 +4,19 @@ #include "error_util.h" #include "command-line-arguments.h" +typedef enum { +OPT_FAILED, /* false */ +OPT_OK, /* good */ +OPT_GIVEBACK, /* pop one of the arguments you thought you were getting off the stack */ +} opt_handled; + /* Search the array of keywords for a given argument, assigning the output variable to the corresponding value. Return false if nothing matches. */ -static bool +static opt_handled _process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) { const notmuch_keyword_t *keywords; @@ -29,16 +35,32 @@ _process_keyword_arg (const notmuch_opt_desc_t *arg_desc, char next, const char else *arg_desc->opt_keyword = keywords->value; - return true; + return OPT_OK; } + +if (arg_desc->opt_keyword && arg_desc->keyword_no_arg_value && next != ':' && next != '=') { + for (keywords = arg_desc->keywords; keywords->name; keywords++) { + if (strcmp (arg_desc->keyword_no_arg_value, keywords->name) != 0) + continue; + + *arg_desc->opt_keyword = keywords->value; + fprintf (stderr, "Warning: No known keyword option given for \"%s\", choosing value \"%s\"." +" Please specify the argument explicitly!\n", arg_desc->name, arg_desc->keyword_no_arg_value); + + return OPT_GIVEBACK; + } + fprintf (stderr, "No matching keyword for option \"%s\" and default value \"%s\" is invalid.\n", arg_str, arg_desc->name); + return OPT_FAILED; +} + if (next != '\0') fprintf (stderr, "Unknown keyword argument \"%s\" for option \"%s\".\n", arg_str, arg_desc->name); else fprintf (stderr, "Option \"%s\" needs a keyword argument.\n", arg_desc->name); -return false; +return OPT_FAILED; } -static bool +static opt_handled _process_boolean_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) { bool value; @@ -48,45 +70,45 @@ _process_boolean_arg (const notmuch_opt_desc_t *arg_desc, char next, const char value = false; } else { fprintf (stderr, "Unknown argument \"%s\" for (boolean) option \"%s\".\n", arg_str, arg_desc->name); - return false; + return OPT_FAILED; } *arg_desc->opt_bool = value; -return true; +return OPT_OK; } -static bool +static opt_handled _process_int_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) { char *endptr; if (next == '\0' || arg_str[0] == '\0') { fprintf (stderr, "Option \"%s\" needs an integer argument.\n", arg_desc->name); - return false; + return OPT_FAILED; } *arg_desc->opt_int = strtol (arg_str, , 10); if (*endptr == '\0') - return true; + return OPT_OK; fprintf (stderr, "Unable to parse argument \"%s\" for option \"%s\" as an integer.\n", arg_str, arg_desc->name); -return false; +return OPT_FAILED; } -static bool +static opt_handled _process_string_arg (const notmuch_opt_desc_t *arg_desc, char next, const char *arg_str) { if (next == '\0') { fprintf (stderr, "Option \"%s\" needs a string argument.\n", arg_desc->name); - return false; + return OPT_FAILED; } if (arg_str[0] == '\0' && ! arg_desc->allow_empty) { fprintf (stderr, "String argument for option \"%s\" must be non-empty.\n", arg_desc->name); - return false; + return OPT_FAILED; } *arg_desc->opt_string = arg_str; -return true; +return OPT_OK; } /* Return number of non-NULL opt_* fields in opt_desc. */ @@ -186,13 +208,15 @@ parse_option (int argc, char **argv, const notmuch_opt_desc_t *options, int opt_ if (next != '=' && next != ':' && next != '\0') continue; + bool incremented = false; if (next == '\0' && next_arg != NULL && ! try->opt_bool) { next = ' '; value = next_arg; + incremented = true; opt_index ++; } - bool opt_status = false; + opt_handled opt_status = OPT_FAILED; if (try->opt_keyword ||
[PATCH] Standards-Version: bumped to 4.1.2 (no changes needed)
--- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index f644695b..bf7eb647 100644 --- a/debian/control +++ b/debian/control @@ -28,7 +28,7 @@ Build-Depends: gpgsm , gnupg , bash-completion (>=1.9.0~) -Standards-Version: 4.1.1 +Standards-Version: 4.1.2 Homepage: https://notmuchmail.org/ Vcs-Git: git://notmuchmail.org/git/notmuch Vcs-Browser: https://git.notmuchmail.org/git/notmuch -- 2.15.1 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH v4] python: add decrypt_policy argument to Database.index_file()
We adopt a pythonic idiom here with an optional argument, rather than exposing the user to the C indexopts object directly. This now includes a simple test to ensure that the decrypt_policy argument works as expected. --- bindings/python/notmuch/database.py | 45 +++-- bindings/python/notmuch/globals.py | 5 + test/T390-python.sh | 39 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py index 1279804a..2a07e346 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -28,6 +28,7 @@ from .globals import ( _str, NotmuchDatabaseP, NotmuchDirectoryP, +NotmuchIndexoptsP, NotmuchMessageP, NotmuchTagsP, ) @@ -72,6 +73,9 @@ class Database(object): MODE = Enum(['READ_ONLY', 'READ_WRITE']) """Constants: Mode in which to open the database""" +DECRYPTION_POLICY = Enum(['FALSE', 'TRUE', 'AUTO', 'NOSTASH']) +"""Constants: policies for decrypting messages during indexing""" + """notmuch_database_get_directory""" _get_directory = nmlib.notmuch_database_get_directory _get_directory.argtypes = [NotmuchDatabaseP, c_char_p, POINTER(NotmuchDirectoryP)] @@ -400,13 +404,25 @@ class Database(object): # return the Directory, init it with the absolute path return Directory(abs_dirpath, dir_p, self) +_get_default_indexopts = nmlib.notmuch_database_get_default_indexopts +_get_default_indexopts.argtypes = [NotmuchDatabaseP] +_get_default_indexopts.restype = NotmuchIndexoptsP + +_indexopts_set_decrypt_policy = nmlib.notmuch_indexopts_set_decrypt_policy +_indexopts_set_decrypt_policy.argtypes = [NotmuchIndexoptsP, c_uint] +_indexopts_set_decrypt_policy.restype = None + +_indexopts_destroy = nmlib.notmuch_indexopts_destroy +_indexopts_destroy.argtypes = [NotmuchIndexoptsP] +_indexopts_destroy.restype = None + _index_file = nmlib.notmuch_database_index_file _index_file.argtypes = [NotmuchDatabaseP, c_char_p, c_void_p, POINTER(NotmuchMessageP)] _index_file.restype = c_uint -def index_file(self, filename, sync_maildir_flags=False): +def index_file(self, filename, sync_maildir_flags=False, decrypt_policy=None): """Adds a new message to the database :param filename: should be a path relative to the path of the @@ -427,6 +443,23 @@ class Database(object): API. You might want to look into the underlying method :meth:`Message.maildir_flags_to_tags`. +:param decrypt_policy: If the message contains any encrypted +parts, and decrypt_policy is set to +:attr:`DECRYPTION_POLICY`.TRUE, notmuch will try to +decrypt the message and index the cleartext, stashing any +discovered session keys. If it is set to +:attr:`DECRYPTION_POLICY`.FALSE, it will never try to +decrypt during indexing. If it is set to +:attr:`DECRYPTION_POLICY`.AUTO, then it will try to use +any stashed session keys it knows about, but will not try +to access the user's secret keys. +:attr:`DECRYPTION_POLICY`.NOSTASH behaves the same as +:attr:`DECRYPTION_POLICY`.TRUE except that no session keys +are stashed in the database. If decrypt_policy is set to +None (the default), then the database itself will decide +whether to decrypt, based on the `index.decrypt` +configuration setting (see notmuch-config(1)). + :returns: On success, we return 1) a :class:`Message` object that can be used for things @@ -457,7 +490,15 @@ class Database(object): """ self._assert_db_is_initialized() msg_p = NotmuchMessageP() -status = self._index_file(self._db, _str(filename), c_void_p(None), byref(msg_p)) +indexopts = c_void_p(None) +if decrypt_policy is not None: +indexopts = self._get_default_indexopts(self._db) +self._indexopts_set_decrypt_policy(indexopts, decrypt_policy) + +status = self._index_file(self._db, _str(filename), indexopts, byref(msg_p)) + +if indexopts: +self._indexopts_destroy(indexopts) if not status in [STATUS.SUCCESS, STATUS.DUPLICATE_MESSAGE_ID]: raise NotmuchError(status) diff --git a/bindings/python/notmuch/globals.py b/bindings/python/notmuch/globals.py index b1eec2cf..71426c84 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -88,3 +88,8 @@ NotmuchDirectoryP = POINTER(NotmuchDirectoryS) class NotmuchFilenamesS(Structure): pass NotmuchFilenamesP = POINTER(NotmuchFilenamesS) + + +class NotmuchIndexoptsS(Structure): +pass
Re: [PATCH 3/4] nmbug: Auto-checkout in clone if it wouldn't clobber
"W. Trevor King"writes: > On Mon, Dec 11, 2017 at 09:10:47AM -0400, David Bremner wrote: >> Not sure what happened to patch 4/4? > > Ah sorry. My local branch has a commit to bump nmbug's internal > version to 0.3 (see my comments in [1]), but I ended up deciding to > punt that until before the next notmuch release (in case other nmbug > changes landed in the meantime) and forgot to update the denominator. > > Based on [2], perhaps it is now time? Or is [3] likely to land before > the freeze? > I think bumping the version is something reasonable to do during the feature freeze. d ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 3/4] nmbug: Auto-checkout in clone if it wouldn't clobber
On Mon, Dec 11, 2017 at 09:10:47AM -0400, David Bremner wrote: > Not sure what happened to patch 4/4? Ah sorry. My local branch has a commit to bump nmbug's internal version to 0.3 (see my comments in [1]), but I ended up deciding to punt that until before the next notmuch release (in case other nmbug changes landed in the meantime) and forgot to update the denominator. Based on [2], perhaps it is now time? Or is [3] likely to land before the freeze? Cheers, Trevor [1]: id:cover.1507675236.git.wk...@tremily.us Subject: [PATCH 0/3] nmbug: Date: Tue, 10 Oct 2017 15:49:48 -0700 [2]: id:87efo222nr@tethera.net Subject: Notmuch 0.26 release schedule Date: Sun, 10 Dec 2017 08:22:32 -0400 [3]: id:4487e001b350aa8e343a1201d869cceca2a03ab6.1508176853.git.wk...@tremily.us Subject: [PATCH] nmbug: Only error for invalid diff lines in tags/ Date: Mon, 16 Oct 2017 11:01:47 -0700 -- This email may be signed or encrypted with GnuPG (http://www.gnupg.org). For more information, see http://en.wikipedia.org/wiki/Pretty_Good_Privacy signature.asc Description: OpenPGP digital signature ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] make release archive: common (or no) timestamps
The appended file 'version' has the same timestamp as the files added by `git archive`. The original file name and time stamp are no longer saved to the gzip header in resulting $(PACKAGE)-$(VERSION).tar.gz file. When build environment is close enough to another, this may provide mutually reproducible release archive files. --- tested somewhat like: $ rm -f test.tar.gz $ make test.tar.gz TAR_FILE=test.tar.gz $ md5sum test.tar.gz 59b22212dd006d24d09acd98cd18570a $ sleep 2 $ rm test.tar.gz $ make test.tar.gz TAR_FILE=test.tar.gz $ md5sum test.tar.gz 59b22212dd006d24d09acd98cd18570a $ rm test.tar.gz ( second try, checksums changed :O .. the reason was git-am'ed content *huh* ;) Makefile.local | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.local b/Makefile.local index 9505b7fee70b..49f83bc3feea 100644 --- a/Makefile.local +++ b/Makefile.local @@ -31,11 +31,13 @@ $(TAR_FILE): fi ; \ git archive --format=tar --prefix=$(PACKAGE)-$(VERSION)/ $$ref > $(TAR_FILE).tmp echo $(VERSION) > version.tmp + ct=`git --no-pager log -1 --pretty=format:%ct $$ref` ; \ + touch -d @$$ct version.tmp tar --owner root --group root --append -f $(TAR_FILE).tmp \ --transform s_^_$(PACKAGE)-$(VERSION)/_ \ --transform 's_.tmp$$__' version.tmp rm version.tmp - gzip < $(TAR_FILE).tmp > $(TAR_FILE) + gzip -n < $(TAR_FILE).tmp > $(TAR_FILE) @echo "Source is ready for release in $(TAR_FILE)" $(SHA256_FILE): $(TAR_FILE) -- 2.13.3 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH] cli/help, completion: added pointers to notmuch-properties(7)
Daniel Kahn Gillmorwrites: > --- > completion/notmuch-completion.bash | 2 +- > notmuch.c | 2 ++ pushed to master d ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 3/4] nmbug: Auto-checkout in clone if it wouldn't clobber
"W. Trevor King"writes: > We currently auto-checkout after pull and merge to make those more > convenient. They're guarded against data-loss with a leading > _insist_committed(). This commit adds the same convenience to clone, > since in most cases users will have no NMBPREFIX-prefixed tags in > their database when they clone. Users that *do* have > NMBPREFIX-prefixed tags will get a warning (and I've bumped the > default log level to warning so folks who don't set --log-level will > see it) like: pushed 1-3 to master. Not sure what happened to patch 4/4? ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch