From 6aec7a76b9e70544a93b092c50d167c3e63548ee Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 19 Dec 2017 14:08:50 -0500 Subject: [PATCH] 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 fe09b330..a1ae14fc 100644 --- a/bindings/python/notmuch/database.py +++ b/bindings/python/notmuch/database.py @@ -29,6 +29,7 @@ from .globals import ( NotmuchConfigListP, NotmuchDatabaseP, NotmuchDirectoryP, + NotmuchIndexoptsP, NotmuchMessageP, NotmuchTagsP, ) @@ -73,6 +74,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)] @@ -401,13 +405,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 @@ -428,6 +444,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 @@ -458,7 +491,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 b33e10d3..97413996 100644 --- a/bindings/python/notmuch/globals.py +++ b/bindings/python/notmuch/globals.py @@ -93,3 +93,8 @@ NotmuchFilenamesP = POINTER(NotmuchFilenamesS) class NotmuchConfigListS(Structure): pass NotmuchConfigListP = POINTER(NotmuchConfigListS) + + +class NotmuchIndexoptsS(Structure): + pass +NotmuchIndexoptsP = POINTER(NotmuchIndexoptsS) diff --git a/test/T390-python.sh b/test/T390-python.sh index 312d61e8..9f71ce3c 100755 --- a/test/T390-python.sh +++ b/test/T390-python.sh @@ -5,6 +5,7 @@ test_description="python bindings" test_require_external_prereq ${NOTMUCH_PYTHON} add_email_corpus +add_gnupg_home test_begin_subtest "compare thread ids" test_python < "$fname" +From: test_suite@notmuchmail.org +To: test_suite@notmuchmail.org +Subject: encrypted message +Date: Sat, 01 Jan 2000 12:00:00 +0000 +Message-ID: +MIME-Version: 1.0 +Content-Type: multipart/encrypted; boundary="=-=-="; + protocol="application/pgp-encrypted" + +--=-=-= +Content-Type: application/pgp-encrypted + +Version: 1 + +--=-=-= +Content-Type: application/octet-stream + +$(printf 'Content-Type: text/plain\n\nThis is the sekrit message\n' | gpg --no-tty --batch --quiet --trust-model=always --encrypt --armor --recipient test_suite@notmuchmail.org) +--=-=-=-- +EOF + +test_begin_subtest "index message with decryption" +test_python < EXPECTED +test_expect_equal_file EXPECTED OUTPUT + test_done -- 2.43.0