Fix double release of IMAP connection object

This commit fixes the case when we're invoking releaseconnection()
for a given imapobj twice.

This bug manifests itself as
{{{
ValueError: list.remove(x): x not in list

  File "[...]/offlineimap/folder/IMAP.py", line 615, in savemessage
    self.imapserver.releaseconnection(imapobj)
  File "[...]/offlineimap/imapserver.py", line 130, in releaseconnection
    self.assignedconnections.remove(connection)
}}}

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Introduce dynamic filtering for repository folders

Allow people who want folder filtering to depend on the external
conditions or to make it dynamic for other reasons, to do what
they want.

New repository configuration knob 'dynamic_folderfilter' was
introduced; it defaults to 'False' that matches historical behaviour.

GitHub: #73
Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Fix: Undefined variable 'this' should be 'self'

Pointyhat-to: Eygene Ryabinkin
Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Refactoring: make functions to be private if we can

Make external API of class/module to be smaller, explicitely mark
all internal functions.  Also annotate methods that are implemented
as the part of the parent class interface.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Changed NotImplementedException to NotImplementedError

It seems NotImplementedException does not exist. It must be a relic
from old Python...

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Bugfix: make change_message_uid to update messagelist's filename

This broke code that relied on the filename being up to date in memory
after messages are copied.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Enable compressed connections to the IMAP server

Added the configuration setting usecompression for the IMAP repositories.
When enabled, the data from and to the IMAP server is compressed.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Don't embed CRLF multiple times when saving a message

Since we just do multiple passes for saving the message without
actually modifying its content (apart from header insertion that
is CRLF-clean), we can change line ends to the proper CRLF just
once.

And we can also get message's date only once too.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Add ability to trim some local mail headers

When filterheaders is set to a comma-separated list of headers,
OfflineIMAP removes those headers from messages before uploading them
to the server.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Restructured folder/IMAP code

In preparation for GMail label sync, we had split our some functionality
that will be needed further into their own functions.  This also permitted
the code to look more compact and concise.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Make GmailFolder sync GMail labels

When synclabels config flag is set to "yes" for the GMail repo,
offlineimap fetches the message labels along with the messages, and
embeds them into the body under the header X-Keywords (or whatever
'labelsheader' was set to), as a comma separated list.

It also adds an extra pass to savemessageto, that performs label
synchronization on existing messages from GMail to local, the same way
it is done with flags.

We also introduce GmailMaildir repository that adds functionality to
change message labels.  It keeps track of messages modification time,
so one can quickly detect when the labels may have changed.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Extend handling of GMail labels header

Format headers X-Label and Keywords as a space separated list and all
other ones as comma-separated entities.  This makes OfflineIMAP label
handling to be compatible with some user agents that recognise these
headers.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Adapt plain status folder to gmail labels stuff

  * Implements Status Folder format v2, with a mechanism to upgrade an
    old statusfolder.

  * Do not warn about Gmail and GmailMaildir needing sqlite backend
    anymore.

  * Clean repository.LocalStatus reusing some code from
    folder.LocalStatus.

  * Change field separator in the plaintext file from ':' to '|'. Now
    the local status stores gmail labels. If they contain field
    separator character (formerly ':'), they get messed up. The new
    character '|' is less likely to appear in a label.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Improvements to the SQlite-based local status folder

  * Do not inherit LocalStatusSQLiteFolder class from the plaintext
    one.

  * Use some functions already in BaseFolder in both, plaintext and
    sqlite classes.

  * Add a saveall method. The idea is that saveall dumps the entire
    messagelist to disk, while save only commits the uncommited
    changes. Right now, save is noop for sqlite, and equivalent to
    saveall for plaintext, but it enables to be more clever on when we
    commit to disk in the future.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Add ability to migrate status data across backends

If when we request a LocalStatus folder, the folder has to be created,
we look whether the other backend has data, and if it does we migrate
it to the new backend.

The old backend data is left untouched, so that if you change back say
from sqlite to plaintext, the older data is still there.  That should
not lead to data loss, only a slower sync while the status folder gets
updated.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Imapserver: add missing space to the log message

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
User manual: fix typo, "rebuild" -> "rebuilt"

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Move space to the end of string

... to be aligned with the rest of the code.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
Add support for XDG Base Directory Specification

$XDG_CONFIG_HOME/offlineimap/config will now be tried before
the canonical ~/.offlineimaprc.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
deletemessageheaders(): use passed list of headers to remove

... and not self.filterheaders.  With the current code this change
is no-op (since self.filterheaders is always passed as header_list),
but it is a bug in general.

Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>