Merge remote-tracking branch 'wberrier/master' into master

* wberrier/master:
  prevent an error when no search string is given
  Return partial results if the search takes a long time
  implement caching system for big/slow ldap servers
  make search fields configurable
  Add support for an optional display column
  Fix for python 2.6: add position indexes to format strings
  Add query filter section (in order to pare down results)
  Return results in a format that mutt expects
  fix typo in reference to .rc file
  Add Wade Berrier (me) to author/copyright list
search: `post` and `query` should be Unicode strings

They're being formatted into the Unicode `filterstr`.  Being explicit
here should make the transition to Python 3 less annoying.
search: Move asynchronous result handling inside search()

The result of search() should be an iterable returning entries.  If we
want to use the asynchronous connection.search() and
connection.result(), that's fine, but we should handle the result
unpacking inside search().

One benefit to Wade's new generator approach is that we can start
formatting early entries while we wait for later entries to arrive.
Convert sys.argv to Unicode (using a configurable encoding)

In Python 3, sys.argv is already Unicode, but there's no clean way to
do this automatically in Python 2 [1].  If your system doesn't use
UTF-8 for it's argv encoding, you should set system.argv-encoding in
your ~/.mutt-ldap.rc.  For example, if your system uses UTF-16, try:

  [system]
  argv-encoding = utf-16

[1]: http://bugs.python.org/issue2128
Adapt to Unicode sys.argv
Bump my copyright to 2013 and add Niels de Vos
Decode search results to Unicode and print as Unicode

LDAPv3 strings are encoded in UTF-8 [1], so use that encoding to
decode them in format_columns().  Adjust format_entry() and the main
block to handle the Unicode output from format_columns().

[1]: http://tools.ietf.org/html/rfc2251#section-4.1.2
Restructure around an LDAPConnection class

This keeps us organized and simplifies the connection API (using the
'with' statement).

I also simplified the cache structure to keep all cached entries in a
single pickled dict, to avoid calculating safe filenames for each
query.  The number of queries you make in 14 days will probably not be
large enough for any fan-out efficiencies to be worth the trouble.

I considered using JSON instead of Pickle, but JSON does not support
raw byte strings (e.g. jpegPhoto), and it's not worth encoding
non-text fields using Base64, etc., when Pickle already works.

It would be nice to automatically detect and drop any non text fields,
but that's probably not worth the trouble either...
CachedLDAPConnection: Don't cache fields we don't use

I had previously said:
> It would be nice to automatically detect and drop any non text
> fields, but that's probably not worth the trouble either...

Since the configuration ID is in the cached key, we already know
exactly which fields we need to save in the cache.  Only caching those
fields avoids binary fields and fields with large values (jpegPhoto is
both).  I made the cached fields configurable because the
CachedLDAPConnection instance doesn't know about the fields needed by
format_entry() and format_columns().  If you don't configure the
cached fields, a minimal default is setup in the main block.
Use hyphenated configuration options (instead of underscores)

I like them better ;).
Alphebetize standard library imports
Prefix imported modules with underscores

This cleans up the namespace inside the module, and makes it less
likely that you'll clobber an imported module with a local variable
name.  I also removed imports for modules we no longer use.
CachedLDAPConnection: Add support for cache.longevity-days

Cull entries older than longevity-days (defaults to 14).  This
requires changing the cache values from a list of entries to a dict
with 'time' and 'entries' keys.  Hmm, I should probably add a
reasonable cache versioning scheme...
Add a __version__ (for easier compatibility tracking)
CachedLDAPConnection: Drop the old cache on version missmatch

The expected CachedLDAPConnection._cache_version tracks __version__,
so if you bump __version__, you invalidate the existing cache.  There
shouldn't be anything critical in the cache, and this is safer than
trying to remember to bump an independent _cache_version after major
changes.
CachedLDAPConnection: Convert cache format from Pickle to JSON

Now that we're only storing text fields (via the cache.fields
configuration setting), this is pretty easy to change.
Add logging to stdout (via StreamHandler)

This makes it easy to trace execution and make sure everything is
happening as you think it should.  There's currently no command-line
switch to increase verbosity.  Once we drop support for Python 2.6,
I'll put in an argparse.ArgumentParser.
CachedLDAPConnection: Lazy LDAP connections

This is faster, and it allows us to return cached results even when
the LDAP server is not available (e.g. if your network is down).