diff options
-rw-r--r-- | alot/commands/envelope.py | 32 | ||||
-rw-r--r-- | alot/commands/globals.py | 42 | ||||
-rw-r--r-- | alot/commands/thread.py | 6 | ||||
-rw-r--r-- | alot/commands/utils.py | 5 | ||||
-rw-r--r-- | alot/db/envelope.py | 7 | ||||
-rw-r--r-- | tests/commands/envelope_test.py | 14 | ||||
-rw-r--r-- | tests/commands/global_test.py | 87 | ||||
-rw-r--r-- | tests/commands/utils_tests.py | 10 |
8 files changed, 96 insertions, 107 deletions
diff --git a/alot/commands/envelope.py b/alot/commands/envelope.py index b300125c..2aa15475 100644 --- a/alot/commands/envelope.py +++ b/alot/commands/envelope.py @@ -114,12 +114,14 @@ class SaveCommand(Command): envelope = ui.current_buffer.envelope # determine account to use - try: - account = settings.get_account_by_address( - envelope['From'], return_default=True) - except NoMatchingAccount: - ui.notify('no accounts set.', priority='error') - return + if envelope.account is None: + try: + envelope.account = settings.account_matching_address( + envelope['From'], return_default=True) + except NoMatchingAccount: + ui.notify('no accounts set.', priority='error') + return + account = envelope.account if account.draft_box is None: msg = 'abort: Account for {} has no draft_box' @@ -271,6 +273,7 @@ class SendCommand(Command): await account.send_mail(self.mail) except SendingMailFailed as e: if self.envelope is not None: + self.envelope.account = account self.envelope.sending = False ui.clear_notify([clearme]) logging.error(traceback.format_exc()) @@ -538,13 +541,16 @@ class SignCommand(Command): ui.notify(str(e), priority='error') return else: - try: - acc = settings.get_account_by_address(envelope['From']) - except NoMatchingAccount: - envelope.sign = False - ui.notify('Unable to find a matching account', - priority='error') - return + if envelope.account is None: + try: + envelope.account = settings.get_account_by_address( + envelope['From']) + except NoMatchingAccount: + envelope.sign = False + ui.notify('Unable to find a matching account', + priority='error') + return + acc = envelope.account if not acc.gpg_key: envelope.sign = False msg = 'Account for {} has no gpg key' diff --git a/alot/commands/globals.py b/alot/commands/globals.py index 59722887..8c91ffe5 100644 --- a/alot/commands/globals.py +++ b/alot/commands/globals.py @@ -831,13 +831,21 @@ class ComposeCommand(Command): if self.tags: self.envelope.tags = [t for t in self.tags.split(',') if t] + # find out the right account, if possible yet + account = self.envelope.account + if account is None: + accounts = settings.get_accounts() + if not accounts: + ui.notify('no accounts set.', priority='error') + return + elif len(accounts) == 1: + account = accounts[0] + # get missing From header if 'From' not in self.envelope.headers: - accounts = settings.get_accounts() - if len(accounts) == 1: - a = accounts[0] + if account is not None: fromstring = email.utils.formataddr( - (a.realname, str(a.address))) + (account.realname, str(account.address))) self.envelope.add('From', fromstring) else: cmpl = AccountCompleter() @@ -849,23 +857,17 @@ class ComposeCommand(Command): ui.senderhistory.append(fromaddress) self.envelope.add('From', fromaddress) - # find out the right account - sender = self.envelope.get('From') - name, addr = email.utils.parseaddr(sender) - try: - account = settings.get_account_by_address(addr) - except NoMatchingAccount: - msg = 'Cannot compose mail - no account found for `%s`' % addr - logging.error(msg) - ui.notify(msg, priority='error') - raise CommandCanceled() - + # try to find the account again if account is None: - accounts = settings.get_accounts() - if not accounts: - ui.notify('no accounts set.', priority='error') - return - account = accounts[0] + try: + account = settings.get_account_by_address(fromaddress) + except NoMatchingAccount: + msg = 'Cannot compose mail - no account found for `%s`' % fromaddress + logging.error(msg) + ui.notify(msg, priority='error') + raise CommandCanceled() + if self.envelope.account is None: + self.envelope.account = account # add signature if not self.omit_signature and account.signature: diff --git a/alot/commands/thread.py b/alot/commands/thread.py index 9a0ad474..f68e5405 100644 --- a/alot/commands/thread.py +++ b/alot/commands/thread.py @@ -190,11 +190,12 @@ class ReplyCommand(Command): # set From-header and sending account try: - from_header, _ = determine_sender(mail, 'reply') + from_header, account = determine_sender(mail, 'reply') except AssertionError as e: ui.notify(str(e), priority='error') return envelope.add('From', from_header) + envelope.account = account # set To sender = mail['Reply-To'] or mail['From'] @@ -399,11 +400,12 @@ class ForwardCommand(Command): # set From-header and sending account try: - from_header, _ = determine_sender(mail, 'reply') + from_header, account = determine_sender(mail, 'reply') except AssertionError as e: ui.notify(str(e), priority='error') return envelope.add('From', from_header) + envelope.account = account # continue to compose await ui.apply_command(ComposeCommand(envelope=envelope, diff --git a/alot/commands/utils.py b/alot/commands/utils.py index ace63b03..14ca78af 100644 --- a/alot/commands/utils.py +++ b/alot/commands/utils.py @@ -46,7 +46,10 @@ async def update_keys(ui, envelope, block_error=False, signed_only=False): if 'From' in envelope.headers: try: - acc = settings.get_account_by_address(envelope['From']) + if envelope.account is None: + envelope.account = settings.get_account_by_address( + envelope['From']) + acc = envelope.account if acc.encrypt_to_self: if acc.gpg_key: logging.debug('encrypt to self: %s', acc.gpg_key.fpr) diff --git a/alot/db/envelope.py b/alot/db/envelope.py index 44da6f71..b68e683f 100644 --- a/alot/db/envelope.py +++ b/alot/db/envelope.py @@ -45,11 +45,13 @@ class Envelope(object): """list of :class:`Attachments <alot.db.attachment.Attachment>`""" tags = [] """tags to add after successful sendout""" + account = None + """account to send from""" def __init__( self, template=None, bodytext=None, headers=None, attachments=None, sign=False, sign_key=None, encrypt=False, tags=None, replied=None, - passed=None): + passed=None, account=None): """ :param template: if not None, the envelope will be initialised by :meth:`parsing <parse_template>` this string before @@ -67,6 +69,8 @@ class Envelope(object): :type replied: :class:`~alot.db.message.Message` :param passed: message being passed on :type replied: :class:`~alot.db.message.Message` + :param account: account to send from + :type account: :class:`Account` """ logging.debug('TEMPLATE: %s', template) if template: @@ -88,6 +92,7 @@ class Envelope(object): self.sent_time = None self.modified_since_sent = False self.sending = False # semaphore to avoid accidental double sendout + self.account = account def __str__(self): return "Envelope (%s)\n%s" % (self.headers, self.body) diff --git a/tests/commands/envelope_test.py b/tests/commands/envelope_test.py index 3efce261..b09cddaa 100644 --- a/tests/commands/envelope_test.py +++ b/tests/commands/envelope_test.py @@ -206,11 +206,10 @@ class TestSignCommand(unittest.TestCase): signing key and to sign should be set to false and default. """ env, ui = self._make_ui_mock() + env.account = mock.Mock(gpg_key=None) - with mock.patch('alot.commands.envelope.settings.get_account_by_address', - mock.Mock(return_value=mock.Mock(gpg_key=None))): - cmd = envelope.SignCommand(action='sign', keyid=None) - cmd.apply(ui) + cmd = envelope.SignCommand(action='sign', keyid=None) + cmd.apply(ui) self.assertFalse(env.sign) self.assertEqual(env.sign_key, mock.sentinel.default) @@ -221,11 +220,10 @@ class TestSignCommand(unittest.TestCase): be used. """ env, ui = self._make_ui_mock() + env.account = mock.Mock(gpg_key='sentinel') - with mock.patch('alot.commands.envelope.settings.get_account_by_address', - mock.Mock(return_value=mock.Mock(gpg_key='sentinel'))): - cmd = envelope.SignCommand(action='sign', keyid=None) - cmd.apply(ui) + cmd = envelope.SignCommand(action='sign', keyid=None) + cmd.apply(ui) self.assertTrue(env.sign) self.assertEqual(env.sign_key, 'sentinel') diff --git a/tests/commands/global_test.py b/tests/commands/global_test.py index e5503305..9b026e6a 100644 --- a/tests/commands/global_test.py +++ b/tests/commands/global_test.py @@ -58,21 +58,15 @@ class TestComposeCommand(unittest.TestCase): @utilities.async_test async def test_apply_sign_by_default_okay(self): envelope = self._make_envelope_mock() - account = self._make_account_mock() + envelope.account = self._make_account_mock() cmd = g_commands.ComposeCommand(envelope=envelope) - # This whole mess is required becasue ComposeCommand.apply is waaaaay - # too complicated, it needs to be split into more manageable segments. - with mock.patch('alot.commands.globals.settings.get_account_by_address', - mock.Mock(return_value=account)): - with mock.patch('alot.commands.globals.settings.get_accounts', - mock.Mock(return_value=[account])): - with mock.patch('alot.commands.globals.settings.get_addressbooks', - mock.Mock(side_effect=Stop)): - try: - await cmd.apply(mock.Mock()) - except Stop: - pass + with mock.patch('alot.commands.globals.settings.get_addressbooks', + mock.Mock(side_effect=Stop)): + try: + await cmd.apply(mock.Mock()) + except Stop: + pass self.assertTrue(envelope.sign) self.assertIs(envelope.sign_key, mock.sentinel.gpg_key) @@ -80,21 +74,15 @@ class TestComposeCommand(unittest.TestCase): @utilities.async_test async def test_apply_sign_by_default_false_doesnt_set_key(self): envelope = self._make_envelope_mock() - account = self._make_account_mock(sign_by_default=False) + envelope.account = self._make_account_mock(sign_by_default=False) cmd = g_commands.ComposeCommand(envelope=envelope) - # This whole mess is required becasue ComposeCommand.apply is waaaaay - # too complicated, it needs to be split into more manageable segments. - with mock.patch('alot.commands.globals.settings.get_account_by_address', - mock.Mock(return_value=account)): - with mock.patch('alot.commands.globals.settings.get_accounts', - mock.Mock(return_value=[account])): - with mock.patch('alot.commands.globals.settings.get_addressbooks', - mock.Mock(side_effect=Stop)): - try: - await cmd.apply(mock.Mock()) - except Stop: - pass + with mock.patch('alot.commands.globals.settings.get_addressbooks', + mock.Mock(side_effect=Stop)): + try: + await cmd.apply(mock.Mock()) + except Stop: + pass self.assertFalse(envelope.sign) self.assertIs(envelope.sign_key, None) @@ -102,22 +90,15 @@ class TestComposeCommand(unittest.TestCase): @utilities.async_test async def test_apply_sign_by_default_but_no_key(self): envelope = self._make_envelope_mock() - account = self._make_account_mock(gpg_key=None) + envelope.account = self._make_account_mock(gpg_key=None) cmd = g_commands.ComposeCommand(envelope=envelope) - # This whole mess is required becasue ComposeCommand.apply is waaaaay - # too complicated, it needs to be split into more manageable segments. - with mock.patch('alot.commands.globals.settings.get_account_by_address', - mock.Mock(return_value=account)): - with mock.patch('alot.commands.globals.settings.get_accounts', - mock.Mock(return_value=[account])): - with mock.patch('alot.commands.globals.settings.get_addressbooks', - mock.Mock(side_effect=Stop)): - with self.assertLogs(level=logging.WARNING): - try: - await cmd.apply(mock.Mock()) - except Stop: - pass + with mock.patch('alot.commands.globals.settings.get_addressbooks', + mock.Mock(side_effect=Stop)): + try: + await cmd.apply(mock.Mock()) + except Stop: + pass self.assertFalse(envelope.sign) self.assertIs(envelope.sign_key, None) @@ -138,7 +119,7 @@ class TestComposeCommand(unittest.TestCase): # Crutch to exit the giant `apply` method early. with mock.patch( - 'alot.commands.globals.settings.get_account_by_address', + 'alot.commands.globals.settings.get_accounts', mock.Mock(side_effect=Stop)): try: await cmd.apply(mock.Mock()) @@ -155,23 +136,17 @@ class TestComposeCommand(unittest.TestCase): # issue #1277 envelope = self._make_envelope_mock() del envelope.headers['From'] - account = self._make_account_mock() - account.realname = "foo" - account.address = 1 # maybe this should be a real Address? + envelope.account = self._make_account_mock() + envelope.account.realname = "foo" + envelope.account.address = 1 # maybe this should be a real Address? cmd = g_commands.ComposeCommand(envelope=envelope) - # This whole mess is required becasue ComposeCommand.apply is waaaaay - # too complicated, it needs to be split into more manageable segments. - with mock.patch('alot.commands.globals.settings.get_account_by_address', - mock.Mock(return_value=account)): - with mock.patch('alot.commands.globals.settings.get_accounts', - mock.Mock(return_value=[account])): - with mock.patch('alot.commands.globals.settings.get_addressbooks', - mock.Mock(side_effect=Stop)): - try: - await cmd.apply(mock.Mock()) - except Stop: - pass + with mock.patch('alot.commands.globals.settings.get_addressbooks', + mock.Mock(side_effect=Stop)): + try: + await cmd.apply(mock.Mock()) + except Stop: + pass class TestExternalCommand(unittest.TestCase): diff --git a/tests/commands/utils_tests.py b/tests/commands/utils_tests.py index 639fb1cd..0642ad32 100644 --- a/tests/commands/utils_tests.py +++ b/tests/commands/utils_tests.py @@ -183,9 +183,8 @@ class TestSetEncrypt(unittest.TestCase): envelope['To'] = 'ambig@example.com' gpg_key = crypto.get_key(FPR) account = _Account(encrypt_to_self=True, gpg_key=gpg_key) - with mock.patch('alot.commands.thread.settings.get_account_by_address', - mock.Mock(return_value=account)): - await utils.update_keys(ui, envelope) + envelope.account = account + await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertIn(FPR, envelope.encrypt_keys) self.assertEqual(gpg_key, envelope.encrypt_keys[FPR]) @@ -198,8 +197,7 @@ class TestSetEncrypt(unittest.TestCase): envelope['To'] = 'ambig@example.com' gpg_key = crypto.get_key(FPR) account = _Account(encrypt_to_self=False, gpg_key=gpg_key) - with mock.patch('alot.commands.thread.settings.get_account_by_address', - mock.Mock(return_value=account)): - await utils.update_keys(ui, envelope) + envelope.account = account + await utils.update_keys(ui, envelope) self.assertTrue(envelope.encrypt) self.assertNotIn(FPR, envelope.encrypt_keys) |