diff options
-rw-r--r-- | CUSTOMIZE.md | 3 | ||||
-rw-r--r-- | alot/account.py | 60 | ||||
-rw-r--r-- | alot/commands/envelope.py | 8 | ||||
-rw-r--r-- | alot/db.py | 17 | ||||
-rwxr-xr-x | alot/init.py | 6 |
5 files changed, 72 insertions, 22 deletions
diff --git a/CUSTOMIZE.md b/CUSTOMIZE.md index 14e646b0..febcf14f 100644 --- a/CUSTOMIZE.md +++ b/CUSTOMIZE.md @@ -60,6 +60,9 @@ Here's a full list of the interpreted keywords in account sections: # where to store outgoing mail sent_box = maildir:///home/you/mail//Sent + # how to tag sent mails [default: sent]. seperate multiple tags with ','. + sent_tags = sent + # file to append before sending signature = ~/your_vcard_for_this_account.vcs # signature file's name as it appears in outgoing mails diff --git a/alot/account.py b/alot/account.py index 6eb9f099..71398c22 100644 --- a/alot/account.py +++ b/alot/account.py @@ -4,12 +4,14 @@ import time import re import email import os +import glob import shlex from ConfigParser import SafeConfigParser from urlparse import urlparse import helper +class SendingMailFailed(RuntimeError): pass class Account(object): """ @@ -38,10 +40,11 @@ class Account(object): abook = None """addressbook (:class:`AddressBook`) managing this accounts contacts""" - def __init__(self, address=None, aliases=None, realname=None, gpg_key=None, - signature=None, signature_filename=None, sent_box=None, - draft_box=None, abook=None): - + def __init__(self, dbman, address=None, aliases=None, realname=None, + gpg_key=None, signature=None, signature_filename=None, + sent_box=None, sent_tags=['sent'], draft_box=None, + draft_tags=['draft'], abook=None): + self.dbman = dbman self.address = address self.abook = abook self.aliases = [] @@ -65,6 +68,7 @@ class Account(object): self.sent_box = mailbox.Babyl(mburl.path) elif mburl.scheme == 'mmdf': self.sent_box = mailbox.MMDF(mburl.path) + self.sent_tags = sent_tags self.draft_box = None if draft_box: @@ -79,8 +83,9 @@ class Account(object): self.draft_box = mailbox.Babyl(mburl.path) elif mburl.scheme == 'mmdf': self.draft_box = mailbox.MMDF(mburl.path) + self.draft_tags = draft_tags - def store_mail(self, mbx, mail): + def store_mail(self, mbx, mail, tags = None): """ stores given mail in mailbox. If mailbox is maildir, set the S-flag. @@ -88,6 +93,8 @@ class Account(object): :type mbx: :class:`mailbox.Mailbox` :param mail: the mail to store :type mail: :class:`email.message.Message` or str + :param tags: if given, add the mail to the notmuch index and tag it + :type tags: list of str """ mbx.lock() if isinstance(mbx, mailbox.Maildir): @@ -95,17 +102,26 @@ class Account(object): msg.set_flags('S') else: msg = mailbox.Message(mail) - mbx.add(mail) + message_id = mbx.add(mail) mbx.flush() mbx.unlock() + if isinstance(mbx, mailbox.Maildir) and tags != None: + # this is a dirty hack to get the path to the newly added file + # I wish the mailbox module were more helpful... + path = glob.glob(os.path.join(mbx._path, '*', message_id + '*'))[0] + + message = self.dbman.add_message(path) + message.add_tags(tags) + self.dbman.flush() + def store_sent_mail(self, mail): """ stores mail (:class:`email.message.Message` or str) in send-store if :attr:`sent_box` is set. """ if self.sent_box is not None: - self.store_mail(self.sent_box, mail) + self.store_mail(self.sent_box, mail, self.sent_tags) def store_draft_mail(self, mail): """ @@ -113,7 +129,7 @@ class Account(object): :attr:`draft_box` is set. """ if self.draft_box is not None: - self.store_mail(self.sent_box, mail) + self.store_mail(self.sent_box, mail, self.draft_tags) def send_mail(self, mail): """ @@ -121,8 +137,7 @@ class Account(object): :param mail: the mail to send :type mail: :class:`email.message.Message` or string - :returns: None if successful and a string with the reason - for failure otherwise. + :raises: :class:`alot.account.SendingMailFailed` if an error occured """ return 'not implemented' @@ -130,12 +145,14 @@ class Account(object): class SendmailAccount(Account): """:class:`Account` that pipes a message to a `sendmail` shell command for sending""" - def __init__(self, cmd, **kwargs): + def __init__(self, dbman, cmd, **kwargs): """ + :param dbman: the database manager instance + :type dbman: :class:`~alot.db.DBManager` :param cmd: sendmail command to use for this account :type cmd: str """ - Account.__init__(self, **kwargs) + super(SendmailAccount, self).__init__(dbman, **kwargs) self.cmd = cmd def send_mail(self, mail): @@ -143,9 +160,8 @@ class SendmailAccount(Account): cmdlist = shlex.split(self.cmd.encode('utf-8', errors='ignore')) out, err, retval = helper.call_cmd(cmdlist, stdin=mail.as_string()) if err: - return err + '. sendmail_cmd set to: %s' % self.cmd + raise SendingMailFailed('%s. sendmail_cmd set to: %s' % (err, self.cmd)) self.store_sent_mail(mail) - return None class AccountManager(object): @@ -165,14 +181,19 @@ class AccountManager(object): 'abook_command', 'abook_regexp', 'sent_box', - 'draft_box'] + 'sent_tags', + 'draft_box', + 'draft_tags'] manditory = ['realname', 'address'] + parse_lists = ['sent_tags', 'draft_tags'] accountmap = {} accounts = [] ordered_addresses = [] - def __init__(self, config): + def __init__(self, dbman, config): """ + :param dbman: the database manager instance + :type dbman: :class:`~alot.db.DBManager` :param config: the config object to read account information from :type config: :class:`~alot.settings.AlotConfigParser`. """ @@ -195,14 +216,17 @@ class AccountManager(object): to_set = self.manditory for o in options: - args[o] = config.get(s, o) + if o not in self.parse_lists: + args[o] = config.get(s, o) + else: + args[o] = config.getstringlist(s, o) if o in to_set: to_set.remove(o) # removes obligation if not to_set: # all manditory fields were present sender_type = args.pop('type', 'sendmail') if sender_type == 'sendmail': cmd = args.pop('sendmail_command', 'sendmail') - newacc = (SendmailAccount(cmd, **args)) + newacc = (SendmailAccount(dbman, cmd, **args)) self.accountmap[newacc.address] = newacc self.accounts.append(newacc) for alias in newacc.aliases: diff --git a/alot/commands/envelope.py b/alot/commands/envelope.py index 21b6aa26..5e54b63f 100644 --- a/alot/commands/envelope.py +++ b/alot/commands/envelope.py @@ -8,6 +8,7 @@ from twisted.internet.defer import inlineCallbacks import threading import datetime +from alot.account import SendingMailFailed from alot import buffers from alot import commands from alot.commands import Command, registerCommand @@ -129,7 +130,12 @@ class SendCommand(Command): def thread_code(): mail = envelope.construct_mail() - os.write(write_fd, account.send_mail(mail) or 'success') + try: + account.send_mail(mail) + except SendingMailFailed as e: + os.write(write_fd, unicode(e)) + else: + os.write(write_fd, 'success') thread = threading.Thread(target=thread_code) thread.start() @@ -249,6 +249,23 @@ class DBManager(object): db = Database(path=self.path, mode=mode) return db.create_query(querystring) + def add_message(self, path): + """ + Adds a file to the notmuch index. + + :param path: path to the file + :type path: str + :returns: the message object corresponding the added message + :rtype: :class:`alot.message.Message` + """ + db = Database(path=self.path, mode=Database.MODE.READ_WRITE) + try: + message, status = db.add_message(path, + sync_maildir_flags=True) + except NotmuchError as e: + raise DatabaseError(unicode(e)) + + return Message(self, message) class Thread(object): """ diff --git a/alot/init.py b/alot/init.py index 064eaf2e..8f5665e3 100755 --- a/alot/init.py +++ b/alot/init.py @@ -128,12 +128,12 @@ def main(): logger = logging.getLogger() #logger.debug(commands.COMMANDS) - #accountman - aman = AccountManager(settings.config) - # get ourselves a database manager dbman = DBManager(path=args['mailindex-path'], ro=args['read-only']) + #accountman + aman = AccountManager(dbman, settings.config) + # get initial searchstring try: if args.subCommand == 'search': |