X-Git-Url: http://git.tremily.us/?p=mutt-ldap.git;a=blobdiff_plain;f=mutt_ldap.py;h=c63c04e5e73abde5507ebc3b01c8580a5a4561fd;hp=efab29b3583e1973c47dfeac4d3447efeeb17a6c;hb=HEAD;hpb=4a8efa546541b78660aa67000a871c0dc2eb2c2e diff --git a/mutt_ldap.py b/mutt_ldap.py index efab29b..c63c04e 100755 --- a/mutt_ldap.py +++ b/mutt_ldap.py @@ -19,17 +19,27 @@ "LDAP address searches for Mutt" +import codecs as _codecs import ConfigParser as _configparser import hashlib as _hashlib import json as _json +import locale as _locale import logging as _logging import os.path as _os_path +import os as _os import pickle as _pickle +import sys as _sys import time as _time import ldap as _ldap import ldap.sasl as _ldap_sasl +_xdg_import_error = None +try: + import xdg.BaseDirectory as _xdg_basedirectory +except ImportError as _xdg_import_error: + _xdg_basedirectory = None + __version__ = '0.1' @@ -38,7 +48,89 @@ LOG = _logging.getLogger('mutt-ldap') LOG.addHandler(_logging.StreamHandler()) LOG.setLevel(_logging.ERROR) -CONFIG = _configparser.SafeConfigParser() + +class Config (_configparser.SafeConfigParser): + def load(self): + config_paths = self._get_config_paths() + LOG.info(u'load configuration from {0}'.format(config_paths)) + read_config_paths = self.read(config_paths) + self._setup_defaults() + LOG.info(u'loaded configuration from {0}'.format(read_config_paths)) + + def get_connection_class(self): + if self.getboolean('cache', 'enable'): + return CachedLDAPConnection + else: + return LDAPConnection + + def _setup_defaults(self): + "Setup dynamic default values" + self._setup_encoding_defaults() + self._setup_cache_defaults() + + def _setup_encoding_defaults(self): + default_encoding = _locale.getpreferredencoding(do_setlocale=True) + for key in ['output-encoding', 'argv-encoding']: + self.set( + 'system', key, + self.get('system', key, raw=True) or default_encoding) + + # HACK: convert sys.std{out,err} to Unicode (not needed in Python 3) + output_encoding = self.get('system', 'output-encoding') + _sys.stdout = _codecs.getwriter(output_encoding)(_sys.stdout) + _sys.stderr = _codecs.getwriter(output_encoding)(_sys.stderr) + + # HACK: convert sys.argv to Unicode (not needed in Python 3) + argv_encoding = self.get('system', 'argv-encoding') + _sys.argv = [unicode(arg, argv_encoding) for arg in _sys.argv] + + def _setup_cache_defaults(self): + if not self.get('cache', 'path'): + self.set('cache', 'path', self._get_cache_path()) + if not self.get('cache', 'fields'): + # setup a reasonable default + fields = ['mail', 'cn', 'displayName'] # used by format_entry() + optional_column = self.get('results', 'optional-column') + if optional_column: + fields.append(optional_column) + self.set('cache', 'fields', ' '.join(fields)) + + def _get_config_paths(self): + "Get configuration file paths" + if _xdg_basedirectory: + paths = list(reversed(list( + _xdg_basedirectory.load_config_paths('')))) + if not paths: # setup something for a useful log message + paths.append(_xdg_basedirectory.save_config_path('')) + else: + self._log_xdg_import_error() + paths = [_os_path.expanduser(_os_path.join('~', '.config'))] + return [_os_path.join(path, 'mutt-ldap.cfg') for path in paths] + + def _get_cache_path(self): + "Get the cache file path" + + # Some versions of pyxdg don't have save_cache_path (0.20 and older) + # See: https://bugs.freedesktop.org/show_bug.cgi?id=26458 + if _xdg_basedirectory and 'save_cache_path' in dir(_xdg_basedirectory): + path = _xdg_basedirectory.save_cache_path('') + else: + self._log_xdg_import_error() + path = _os_path.expanduser(_os_path.join('~', '.cache')) + if not _os_path.isdir(path): + _os.makedirs(path) + return _os_path.join(path, 'mutt-ldap.json') + + def _log_xdg_import_error(self): + global _xdg_import_error + if _xdg_import_error: + LOG.warning(u'could not import xdg.BaseDirectory ' + u'or lacking necessary support') + LOG.warning(_xdg_import_error) + _xdg_import_error = None + + +CONFIG = Config() CONFIG.add_section('connection') CONFIG.set('connection', 'server', 'domaincontroller.yourdomain.com') CONFIG.set('connection', 'port', '389') # set to 636 for default over SSL @@ -56,9 +148,9 @@ CONFIG.add_section('results') CONFIG.set('results', 'optional-column', '') # mutt can display one optional column CONFIG.add_section('cache') CONFIG.set('cache', 'enable', 'yes') # enable caching by default -CONFIG.set('cache', 'path', '~/.mutt-ldap.cache') # cache results here +CONFIG.set('cache', 'path', '') # cache results here, defaults to XDG CONFIG.set('cache', 'fields', '') # fields to cache (if empty, setup in the main block) -CONFIG.set('cache', 'longevity-days', '14') # TODO: cache results for 14 days by default +CONFIG.set('cache', 'longevity-days', '14') # Days before cache entries are invalidated CONFIG.add_section('system') # HACK: Python 2.x support, see http://bugs.python.org/issue13329#msg147475 CONFIG.set('system', 'output-encoding', '') # match .muttrc's $charset @@ -264,28 +356,7 @@ def format_entry(entry): if __name__ == '__main__': - import codecs as _codecs - import locale as _locale - import sys as _sys - - read_configfiles = CONFIG.read(_os_path.expanduser('~/.mutt-ldap.rc')) - - default_encoding = _locale.getpreferredencoding(do_setlocale=True) - for key in ['output-encoding', 'argv-encoding']: - CONFIG.set( - 'system', key, - CONFIG.get('system', key, raw=True) or default_encoding) - - # HACK: convert sys.std{out,err} to Unicode (not needed in Python 3) - output_encoding = CONFIG.get('system', 'output-encoding') - _sys.stdout = _codecs.getwriter(output_encoding)(_sys.stdout) - _sys.stderr = _codecs.getwriter(output_encoding)(_sys.stderr) - - # HACK: convert sys.argv to Unicode (not needed in Python 3) - argv_encoding = CONFIG.get('system', 'argv-encoding') - _sys.argv = [unicode(arg, argv_encoding) for arg in _sys.argv] - - LOG.info(u'loaded configuration from {0}'.format(read_configfiles)) + CONFIG.load() if len(_sys.argv) < 2: LOG.error(u'{0}: no search string given'.format(_sys.argv[0])) @@ -293,18 +364,7 @@ if __name__ == '__main__': query = u' '.join(_sys.argv[1:]) - if CONFIG.getboolean('cache', 'enable'): - connection_class = CachedLDAPConnection - if not CONFIG.get('cache', 'fields'): - # setup a reasonable default - fields = ['mail', 'cn', 'displayName'] # used by format_entry() - optional_column = CONFIG.get('results', 'optional-column') - if optional_column: - fields.append(optional_column) - CONFIG.set('cache', 'fields', ' '.join(fields)) - else: - connection_class = LDAPConnection - + connection_class = CONFIG.get_connection_class() addresses = [] with connection_class() as connection: entries = connection.search(query=query)