summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alot/commands/envelope.py32
-rw-r--r--alot/commands/globals.py42
-rw-r--r--alot/commands/thread.py6
-rw-r--r--alot/commands/utils.py5
-rw-r--r--alot/db/envelope.py7
-rw-r--r--tests/commands/envelope_test.py14
-rw-r--r--tests/commands/global_test.py87
-rw-r--r--tests/commands/utils_tests.py10
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)