diff options
author | Patrick Totzke <patricktotzke@gmail.com> | 2015-04-10 09:29:47 +0100 |
---|---|---|
committer | Patrick Totzke <patricktotzke@gmail.com> | 2015-04-15 13:05:13 +0100 |
commit | 2f064af42d4735649d361cbda640353ca08289fd (patch) | |
tree | 4e399c030eb1750d0e1848ffac24dc2cebc775c0 /alot | |
parent | 7b1aee9f1625fafa6cf899239a1207a51b825682 (diff) |
refactor addressbook code
Diffstat (limited to 'alot')
-rw-r--r-- | alot/account.py | 2 | ||||
-rw-r--r-- | alot/addressbook/__init__.py | 38 | ||||
-rw-r--r-- | alot/addressbook/abook.py | 31 | ||||
-rw-r--r-- | alot/addressbook/external.py | 56 | ||||
-rw-r--r-- | alot/addressbooks.py | 115 | ||||
-rw-r--r-- | alot/completion.py | 2 | ||||
-rw-r--r-- | alot/settings/manager.py | 3 |
7 files changed, 129 insertions, 118 deletions
diff --git a/alot/account.py b/alot/account.py index 0c4abfbe..4a62f0b4 100644 --- a/alot/account.py +++ b/alot/account.py @@ -44,7 +44,7 @@ class Account(object): signature_as_attachment = None """attach signature file instead of appending its content to body text""" abook = None - """addressbook (:class:`addressbooks.AddressBook`) + """addressbook (:class:`addressbook.AddressBook`) managing this accounts contacts""" def __init__(self, address=None, aliases=None, realname=None, diff --git a/alot/addressbook/__init__.py b/alot/addressbook/__init__.py new file mode 100644 index 00000000..f649b523 --- /dev/null +++ b/alot/addressbook/__init__.py @@ -0,0 +1,38 @@ +# Copyright (C) 2011-2015 Patrick Totzke <patricktotzke@gmail.com> +# This file is released under the GNU GPL, version 3 or a later revision. +# For further details see the COPYING file +import re + + +class AddressbookError(Exception): + pass + + +class AddressBook(object): + """can look up email addresses and realnames for contacts. + + .. note:: + + This is an abstract class that leaves :meth:`get_contacts` + unspecified. See :class:`AbookAddressBook` and + :class:`MatchSdtoutAddressbook` for implementations. + """ + def __init__(self, ignorecase=True): + self.reflags = re.IGNORECASE if ignorecase else 0 + + def get_contacts(self): + """list all contacts tuples in this abook as (name, email) tuples""" + return [] + + def lookup(self, query=''): + """looks up all contacts where name or address match query""" + res = [] + query = '.*%s.*' % query + for name, email in self.get_contacts(): + try: + if re.match(query, name, self.reflags) or \ + re.match(query, email, self.reflags): + res.append((name, email)) + except: + pass + return res diff --git a/alot/addressbook/abook.py b/alot/addressbook/abook.py new file mode 100644 index 00000000..c71f485c --- /dev/null +++ b/alot/addressbook/abook.py @@ -0,0 +1,31 @@ +# Copyright (C) 2011-2015 Patrick Totzke <patricktotzke@gmail.com> +# This file is released under the GNU GPL, version 3 or a later revision. +# For further details see the COPYING file + +import os +from . import AddressBook +from ..settings.utils import read_config + + +class AbookAddressBook(AddressBook): + """:class:`AddressBook` that parses abook's config/database files""" + def __init__(self, path='~/.abook/addressbook', **kwargs): + """ + :param path: path to theme file + :type path: str + """ + AddressBook.__init__(self, **kwargs) + DEFAULTSPATH = os.path.join(os.path.dirname(__file__), 'defaults') + self._spec = os.path.join(DEFAULTSPATH, 'abook_contacts.spec') + path = os.path.expanduser(path) + self._config = read_config(path, self._spec) + del(self._config['format']) + + def get_contacts(self): + c = self._config + res = [] + for id in c.sections: + for email in c[id]['email']: + if email: + res.append((c[id]['name'], email)) + return res diff --git a/alot/addressbook/external.py b/alot/addressbook/external.py new file mode 100644 index 00000000..21096d23 --- /dev/null +++ b/alot/addressbook/external.py @@ -0,0 +1,56 @@ +# Copyright (C) 2011-2015 Patrick Totzke <patricktotzke@gmail.com> +# This file is released under the GNU GPL, version 3 or a later revision. +# For further details see the COPYING file +import re + +from ..helper import call_cmd +from ..helper import split_commandstring +from . import AddressBook, AddressbookError + + +class MatchSdtoutAddressbook(AddressBook): + """:class:`AddressBook` that parses a shell command's output for lookups""" + + def __init__(self, command, match=None, **kwargs): + """ + :param command: lookup command + :type command: str + :param match: regular expression used to match contacts in `commands` + output to stdout. Must define subparts named "email" and + "name". Defaults to + :regexp:`^(?P<email>[^@]+@[^\t]+)\t+(?P<name>[^\t]+)`. + :type match: str + """ + AddressBook.__init__(self, **kwargs) + self.command = command + if not match: + self.match = '^(?P<email>[^@]+@[^\t]+)\t+(?P<name>[^\t]+)' + else: + self.match = match + + def get_contacts(self): + return self.lookup('\'\'') + + def lookup(self, prefix): + cmdlist = split_commandstring(self.command) + resultstring, errmsg, retval = call_cmd(cmdlist + [prefix]) + if retval != 0: + msg = 'abook command "%s" returned with ' % self.command + msg += 'return code %d' % retval + if errmsg: + msg += ':\n%s' % errmsg + raise AddressbookError(msg) + + if not resultstring: + return [] + lines = resultstring.splitlines() + res = [] + for l in lines: + m = re.match(self.match, l, self.reflags) + if m: + info = m.groupdict() + if 'email' and 'name' in info: + email = info['email'].strip() + name = info['name'] + res.append((name, email)) + return res diff --git a/alot/addressbooks.py b/alot/addressbooks.py deleted file mode 100644 index 890eb0e3..00000000 --- a/alot/addressbooks.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2011-2012 Patrick Totzke <patricktotzke@gmail.com> -# This file is released under the GNU GPL, version 3 or a later revision. -# For further details see the COPYING file -import re -import os - -from alot.settings.utils import read_config -from helper import call_cmd -from alot.helper import split_commandstring - - -class AddressbookError(Exception): - pass - - -class AddressBook(object): - """can look up email addresses and realnames for contacts. - - .. note:: - - This is an abstract class that leaves :meth:`get_contacts` - unspecified. See :class:`AbookAddressBook` and - :class:`MatchSdtoutAddressbook` for implementations. - """ - def __init__(self, ignorecase=True): - self.reflags = re.IGNORECASE if ignorecase else 0 - - def get_contacts(self): - """list all contacts tuples in this abook as (name, email) tuples""" - return [] - - def lookup(self, query=''): - """looks up all contacts where name or address match query""" - res = [] - query = '.*%s.*' % query - for name, email in self.get_contacts(): - try: - if re.match(query, name, self.reflags) or \ - re.match(query, email, self.reflags): - res.append((name, email)) - except: - pass - return res - - -class AbookAddressBook(AddressBook): - """:class:`AddressBook` that parses abook's config/database files""" - def __init__(self, path='~/.abook/addressbook', **kwargs): - """ - :param path: path to theme file - :type path: str - """ - AddressBook.__init__(self, **kwargs) - DEFAULTSPATH = os.path.join(os.path.dirname(__file__), 'defaults') - self._spec = os.path.join(DEFAULTSPATH, 'abook_contacts.spec') - path = os.path.expanduser(path) - self._config = read_config(path, self._spec) - del(self._config['format']) - - def get_contacts(self): - c = self._config - res = [] - for id in c.sections: - for email in c[id]['email']: - if email: - res.append((c[id]['name'], email)) - return res - - -class MatchSdtoutAddressbook(AddressBook): - """:class:`AddressBook` that parses a shell command's output for lookups""" - - def __init__(self, command, match=None, **kwargs): - """ - :param command: lookup command - :type command: str - :param match: regular expression used to match contacts in `commands` - output to stdout. Must define subparts named "email" and - "name". Defaults to - :regexp:`^(?P<email>[^@]+@[^\t]+)\t+(?P<name>[^\t]+)`. - :type match: str - """ - AddressBook.__init__(self, **kwargs) - self.command = command - if not match: - self.match = '^(?P<email>[^@]+@[^\t]+)\t+(?P<name>[^\t]+)' - else: - self.match = match - - def get_contacts(self): - return self.lookup('\'\'') - - def lookup(self, prefix): - cmdlist = split_commandstring(self.command) - resultstring, errmsg, retval = call_cmd(cmdlist + [prefix]) - if retval != 0: - msg = 'abook command "%s" returned with ' % self.command - msg += 'return code %d' % retval - if errmsg: - msg += ':\n%s' % errmsg - raise AddressbookError(msg) - - if not resultstring: - return [] - lines = resultstring.splitlines() - res = [] - for l in lines: - m = re.match(self.match, l, self.reflags) - if m: - info = m.groupdict() - if 'email' and 'name' in info: - email = info['email'].strip() - name = info['name'] - res.append((name, email)) - return res diff --git a/alot/completion.py b/alot/completion.py index 75d50e0c..300592b3 100644 --- a/alot/completion.py +++ b/alot/completion.py @@ -13,7 +13,7 @@ from alot.buffers import EnvelopeBuffer from alot.settings import settings from alot.utils.booleanaction import BooleanAction from alot.helper import split_commandline -from alot.addressbooks import AddressbookError +from alot.addressbook import AddressbookError from errors import CompletionError diff --git a/alot/settings/manager.py b/alot/settings/manager.py index 66c8e355..1b5a274a 100644 --- a/alot/settings/manager.py +++ b/alot/settings/manager.py @@ -9,7 +9,8 @@ import logging from configobj import ConfigObj, Section from alot.account import SendmailAccount -from alot.addressbooks import MatchSdtoutAddressbook, AbookAddressBook +from alot.addressbook.abook import AbookAddressBook +from alot.addressbook.external import MatchSdtoutAddressbook from alot.helper import pretty_datetime, string_decode from errors import ConfigError |