From 30f484341070ac7905c8f82a1ee85fcc2d964afa Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 11 May 2012 23:09:51 +0200 Subject: add sign_by_default account setting to enable GPG signatures by default, use existing gpg_key setting --- alot/commands/globals.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'alot/commands/globals.py') diff --git a/alot/commands/globals.py b/alot/commands/globals.py index f99aec25..32af400d 100644 --- a/alot/commands/globals.py +++ b/alot/commands/globals.py @@ -594,12 +594,14 @@ class ComposeCommand(Command): select='yes', cancel='no')) == 'no': return + # Figure out whether we should GPG sign messages by default + sender = self.envelope.get('From') + name, addr = email.Utils.parseaddr(sender) + account = settings.get_account_by_address(addr) + self.envelope.apply_account_crypto_settings(account, ui) + # get missing To header if 'To' not in self.envelope.headers: - sender = self.envelope.get('From') - name, addr = email.Utils.parseaddr(sender) - account = settings.get_account_by_address(addr) - allbooks = not settings.get('complete_matching_abook_only') logging.debug(allbooks) if account is not None: -- cgit v1.2.3 From e47ee126ab7572387e7133e4bf34ba0d513878b6 Mon Sep 17 00:00:00 2001 From: Patrick Totzke Date: Sat, 12 May 2012 21:01:56 +0100 Subject: lookup gpg key once during compose .. and not in reply/forward/editnew. This also obsoletes Envelope.apply_account_crypto_settings, which needed a reference to UI for error notifications. --- alot/commands/globals.py | 11 ++++++++++- alot/commands/thread.py | 12 ------------ alot/crypto.py | 3 ++- alot/db/envelope.py | 19 ------------------- 4 files changed, 12 insertions(+), 33 deletions(-) (limited to 'alot/commands/globals.py') diff --git a/alot/commands/globals.py b/alot/commands/globals.py index 32af400d..8fafe2cb 100644 --- a/alot/commands/globals.py +++ b/alot/commands/globals.py @@ -17,12 +17,14 @@ from alot.commands import commandfactory from alot import buffers from alot import widgets from alot import helper +from alot import crypto from alot.db.errors import DatabaseLockedError from alot.completion import ContactsCompleter from alot.completion import AccountCompleter from alot.db.envelope import Envelope from alot import commands from alot.settings import settings +from alot.db.errors import GPGProblem MODE = 'global' @@ -595,10 +597,17 @@ class ComposeCommand(Command): return # Figure out whether we should GPG sign messages by default + # and look up key if so sender = self.envelope.get('From') name, addr = email.Utils.parseaddr(sender) account = settings.get_account_by_address(addr) - self.envelope.apply_account_crypto_settings(account, ui) + self.envelope.sign = account.sign_by_default + try: + key = crypto.CryptoContext().get_key(account.gpg_key) + except GPGProblem, e: + ui.notify(e.message, priority='error') + return + self.envelope.sign_key = key # get missing To header if 'To' not in self.envelope.headers: diff --git a/alot/commands/thread.py b/alot/commands/thread.py index ba6400e2..45734b21 100644 --- a/alot/commands/thread.py +++ b/alot/commands/thread.py @@ -122,10 +122,6 @@ class ReplyCommand(Command): realname, address = recipient_to_from(mail, my_accounts) envelope.add('From', '%s <%s>' % (realname, address)) - # set GPG sign from the account default setting - account = settings.get_account_by_address(address) - envelope.apply_account_crypto_settings(account, ui) - # set To sender = mail['Reply-To'] or mail['From'] recipients = [sender] @@ -236,10 +232,6 @@ class ForwardCommand(Command): realname, address = recipient_to_from(mail, my_accounts) envelope.add('From', '%s <%s>' % (realname, address)) - # set GPG sign from the account default setting - account = settings.get_account_by_address(address) - envelope.apply_account_crypto_settings(account, ui) - # continue to compose ui.apply_command(ComposeCommand(envelope=envelope, spawn=self.force_spawn)) @@ -270,10 +262,6 @@ class EditNewCommand(Command): mailcontent = self.message.accumulate_body() envelope = Envelope(bodytext=mailcontent) - # set GPG sign from the account default setting - account = settings.get_account_by_address(address) - envelope.apply_account_crypto_settings(account, ui) - # copy selected headers to_copy = ['Subject', 'From', 'To', 'Cc', 'Bcc', 'In-Reply-To', 'References'] diff --git a/alot/crypto.py b/alot/crypto.py index b9196590..cf6cdd77 100644 --- a/alot/crypto.py +++ b/alot/crypto.py @@ -88,9 +88,10 @@ class CryptoContext(pyme.core.Context): keys, an exception will be thrown). :param keyid: filter term for the keyring (usually a key ID) + :type keyid: bytestring :rtype: pyme.pygpgme._gpgme_key """ - result = self.op_keylist_start(keyid, 0) + result = self.op_keylist_start(str(keyid), 0) key = self.op_keylist_next() if self.op_keylist_next() is not None: # Deferred import to avoid a circular import dependency diff --git a/alot/db/envelope.py b/alot/db/envelope.py index f75e9dd1..9d8e2599 100644 --- a/alot/db/envelope.py +++ b/alot/db/envelope.py @@ -137,25 +137,6 @@ class Envelope(object): if self.sent_time: self.modified_since_sent = True - def apply_account_crypto_settings(self, account, ui): - """ - initializes sign and sign_key from the account settings. - """ - if account is None: - return - - self.sign = account.sign_by_default - - if account.gpg_key is None: - return - - try: - key = crypto.CryptoContext().get_key(str(account.gpg_key)) - except GPGProblem, e: - ui.notify(e.message, priority='error') - return - self.sign_key = key - def construct_mail(self): """ compiles the information contained in this envelope into a -- cgit v1.2.3 From 8d12c4751d310d7b79bbda6f34c68ef0029873db Mon Sep 17 00:00:00 2001 From: Patrick Totzke Date: Sun, 13 May 2012 11:15:28 +0100 Subject: move alot.db.errors GPGProblem to alot.errors to prevent circular imports and for consistency: This Exception is not related to the database abstraction layer. --- alot/commands/envelope.py | 2 +- alot/commands/globals.py | 2 +- alot/crypto.py | 3 +-- alot/db/envelope.py | 2 +- alot/db/errors.py | 4 ---- alot/errors.py | 3 +++ 6 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 alot/errors.py (limited to 'alot/commands/globals.py') diff --git a/alot/commands/envelope.py b/alot/commands/envelope.py index 26271148..0280b303 100644 --- a/alot/commands/envelope.py +++ b/alot/commands/envelope.py @@ -9,7 +9,7 @@ from twisted.internet.defer import inlineCallbacks import datetime from alot.account import SendingMailFailed -from alot.db.errors import GPGProblem +from alot.errors import GPGProblem from alot import buffers from alot import commands from alot import crypto diff --git a/alot/commands/globals.py b/alot/commands/globals.py index 8fafe2cb..a4f2fdf3 100644 --- a/alot/commands/globals.py +++ b/alot/commands/globals.py @@ -24,7 +24,7 @@ from alot.completion import AccountCompleter from alot.db.envelope import Envelope from alot import commands from alot.settings import settings -from alot.db.errors import GPGProblem +from alot.errors import GPGProblem MODE = 'global' diff --git a/alot/crypto.py b/alot/crypto.py index cf6cdd77..c80fff8f 100644 --- a/alot/crypto.py +++ b/alot/crypto.py @@ -5,6 +5,7 @@ from email.generator import Generator from cStringIO import StringIO import pyme.core import pyme.constants +from alot.errors import GPGProblem def email_as_string(mail): @@ -94,8 +95,6 @@ class CryptoContext(pyme.core.Context): result = self.op_keylist_start(str(keyid), 0) key = self.op_keylist_next() if self.op_keylist_next() is not None: - # Deferred import to avoid a circular import dependency - from alot.db.errors import GPGProblem raise GPGProblem(("More than one key found matching this filter." " Please be more specific (use a key ID like 4AC8EE1D).")) self.op_keylist_end() diff --git a/alot/db/envelope.py b/alot/db/envelope.py index 9d8e2599..3c888311 100644 --- a/alot/db/envelope.py +++ b/alot/db/envelope.py @@ -17,7 +17,7 @@ import logging import alot.helper as helper import alot.crypto as crypto from alot.settings import settings -from alot.db.errors import GPGProblem +from alot.errors import GPGProblem from attachment import Attachment from utils import encode_header diff --git a/alot/db/errors.py b/alot/db/errors.py index 062a0f6c..eb1a56d7 100644 --- a/alot/db/errors.py +++ b/alot/db/errors.py @@ -16,7 +16,3 @@ class NonexistantObjectError(DatabaseError): """requested thread or message does not exist in the index""" pass - -class GPGProblem(Exception): - """A GPG occured while constructing your mail""" - pass diff --git a/alot/errors.py b/alot/errors.py new file mode 100644 index 00000000..29283a45 --- /dev/null +++ b/alot/errors.py @@ -0,0 +1,3 @@ +class GPGProblem(Exception): + """GPG Error""" + pass -- cgit v1.2.3 From 05812e255b0f40c4693114e26e1e57a4e3b8d5fc Mon Sep 17 00:00:00 2001 From: Patrick Totzke Date: Sun, 13 May 2012 11:41:56 +0100 Subject: verify accounts gpg_key upon startup This introduces a custom config check that tests if the given gpg_key value points to a valid private key. If so, the property Account.gpg_key is a pyme.pygpgme._gpgme_key object. --- alot/commands/globals.py | 7 +------ alot/defaults/alot.rc.spec | 2 +- alot/settings/__init__.py | 4 +++- alot/settings/checks.py | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) (limited to 'alot/commands/globals.py') diff --git a/alot/commands/globals.py b/alot/commands/globals.py index a4f2fdf3..8b102de5 100644 --- a/alot/commands/globals.py +++ b/alot/commands/globals.py @@ -602,12 +602,7 @@ class ComposeCommand(Command): name, addr = email.Utils.parseaddr(sender) account = settings.get_account_by_address(addr) self.envelope.sign = account.sign_by_default - try: - key = crypto.CryptoContext().get_key(account.gpg_key) - except GPGProblem, e: - ui.notify(e.message, priority='error') - return - self.envelope.sign_key = key + self.envelope.sign_key = account.gpg_key # get missing To header if 'To' not in self.envelope.headers: diff --git a/alot/defaults/alot.rc.spec b/alot/defaults/alot.rc.spec index 95f776ea..de95ea60 100644 --- a/alot/defaults/alot.rc.spec +++ b/alot/defaults/alot.rc.spec @@ -177,7 +177,7 @@ prompt_suffix = string(default=':') # The GPG key ID you want to use with this account. If unset, alot will # use your default key. - gpg_key = string(default=None) + gpg_key = gpg_key_hint(default=None) # address book for this account [[[abook]]] diff --git a/alot/settings/__init__.py b/alot/settings/__init__.py index f62dfa0d..2a4147a3 100644 --- a/alot/settings/__init__.py +++ b/alot/settings/__init__.py @@ -15,6 +15,7 @@ from alot.addressbooks import MatchSdtoutAddressbook, AbookAddressBook from errors import ConfigError from utils import read_config from checks import mail_container +from checks import gpg_key from theme import Theme DEFAULTSPATH = os.path.join(os.path.dirname(__file__), '..', 'defaults') @@ -53,7 +54,8 @@ class SettingsManager(object): """parse alot's config file from path""" spec = os.path.join(DEFAULTSPATH, 'alot.rc.spec') newconfig = read_config(path, spec, - checks={'mail_container': mail_container}) + checks={'mail_container': mail_container, + 'gpg_key_hint': gpg_key}) self._config.merge(newconfig) hooks_path = os.path.expanduser(self._config.get('hooksfile')) diff --git a/alot/settings/checks.py b/alot/settings/checks.py index 4943daa3..ff1ad3a8 100644 --- a/alot/settings/checks.py +++ b/alot/settings/checks.py @@ -2,6 +2,10 @@ import mailbox import re from urlparse import urlparse from validate import VdtTypeError +from validate import ValidateError + +from alot import crypto +from alot.errors import GPGProblem def mail_container(value): @@ -21,3 +25,17 @@ def mail_container(value): else: raise VdtTypeError(value) return box + + +def gpg_key(value): + """ + test if value points to a known gpg key + and return that key as :class:`pyme.pygpgme._gpgme_key`. + """ + try: + key = crypto.CryptoContext().get_key(value) + if key == None: + raise ValidateError('No key found for hint %s' % value) + return key + except GPGProblem, e: + raise ValidateError(e.message) -- cgit v1.2.3