Commit Graph

47 Commits

Author SHA1 Message Date
Sebastian Spaeth
d2f8504757 Fix getuidvalidity crash (UIDVALIDITY returning None)
Rename getuidvalidity -> get_uidvalidity and cache the IMAP result.

1) Start modernizing our function names using more underscores
2) IMAPs implementation of get_uidvalidity was removing the UIDVALIDITY result
   from the imaplib2 result stack, so subsequent calls would return "None".
   As various functions can invoke this, this led to some errors that we
   avoid by caching the current UIDVALIDITY value in the Folder instance.

There are more simplifications and improvements to be made.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-19 12:09:37 +01:00
Sebastian Spaeth
6e9e256946 Ignore lower-case custom Maildir flags
Do not read in custom maildir flags, or we would try to sync them over
the wire. The next step will be to merge flag writes with existing
custom flags, so we don't lose information.

The long term goal will be to attempt to sync flags to the other side,
of course.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-07 22:00:45 +01:00
Sebastian Spaeth
d549cbdac9 Fix code comment on flag stripping
Fix code comment that we preserve custom dovecot flags. We discard them.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-07 21:34:57 +01:00
Sebastian Spaeth
0b85a34fc7 Maildir: flagmatchre --> re_flagmatch
Overlooked a variable renaming when merging in a branch.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-07 13:10:41 +01:00
Sebastian Spaeth
78a37f27ef WIP, revamp how we treat top-level dirs
Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-06 19:08:48 +01:00
Sebastian Spaeth
ff50585007 Folder-Maildir.savemessageflags(): Only parse file name if flags changed
Rather than always parsing the filename, we only need to do so if the flags
have actually changed, otherwise we can keep the filename.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-06 19:08:48 +01:00
Sebastian Spaeth
de537dc09c Implement change_message_uid
Previously, assigning a new UID to a mapped IMAP or Maildir repository
was done by loading the "local" item, saving it under a new UID and
deleting the old one. This involved lots of disk activity for nothing
more than an effective file rename in Maildirs, and lots of network
usage in the MappedUID cases.

We do this on every upload from a local to a remote item, so that can
potentially be quite expensive. This patch lets backends that support it
(Maildir, MappedUID) efficiently rename the file rather than having to
read the mail content, write it out as a new file and delete the old
file. This speeds up uploads from Maildir and the MappedUID server.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-06 19:08:48 +01:00
Sebastian Spaeth
09ce56c594 Factor out creating a Maildir message filename
Various functions (such as change_message_uid) will want to construct
maildir filenames, so factor out the code into a helper.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-06 19:08:48 +01:00
Sebastian Spaeth
6fe808338c Refactor parsing out maildirs filename components
Create a helper function that retrieves the UID, folder MD5, and Flags from
a message filename.

We need these items when we simply want to rename (=new UID) a Maildir
message file later. The new function can give us these components.

Rework, so we cache the calculation of the folder's md5 value once, it
never changes and we call it a lot.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-06 19:08:45 +01:00
Sebastian Spaeth
d5666ce91d Don't create invalid maildir names with lower case maildir flags
If someone had a custom :2,a flag, adding a new flag would lead to the
invalid maildir filename ...a:2,... due to regex deficiencies not coping
with this. Fix this so we alway produce valid maildir names.

Note that custom flags are still problematic: as the syncing to the
remote IMAP server will fail, the next sync will assume that they have
been removed from the remote IMAP side and they will be removed from the
local Maildir then. We will need to think about how to handle this. At
least, with this patch we won't lose standard flags and won't produce
invalid maildir names.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-06 13:05:08 +01:00
Sebastian Spaeth
64f5e557bc Fix (harmless) regex flaw when determining maildir flags
The regex for catching Maildir message flags was
self.infosep + '.*2,([A-Z]+)' (infosep being ':').

The .* is bogus, as there is nothing between the : and the 2, per
maildir name specification, so remove that unneeded piece.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2012-01-05 14:39:09 +01:00
Sebastian Spaeth
32ca20d0da Folder.Maildir: No need to store 'uid' in messagelist dict.
The Message UID is already the key to self.messagelist, so we have that
information. It is redundant to save the UID again as
self.messagelist[uid]{'uid': uid} and we never made use of the
information anyway.

The same thing should be done with the other 2 backends.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-19 10:01:31 +02:00
Sebastian Spaeth
dfdc4d457b Folder.Maildir: Simplify getmessagetime
No need to use os.stat()['st_mtime'] when there is os.path.getmtime()

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-19 09:59:04 +02:00
Sebastian Spaeth
a43677a3e6 Shorten self.infosep assignment
A more pythonic and less verbose way to do the same. Add a comment what the
variable is all about.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-19 09:58:20 +02:00
Sebastian Spaeth
f5366343b9 Fix default Maildir File permissions.
open() and os.open() lead to different file permissions by default, and
while we have not changed the os.open that had been used, some code
changes led to these permissions slipping through. Fix this by setting
the permissions explicitly to 0666 (minus the users umask).

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-19 09:25:48 +02:00
Sebastian Spaeth
ee75e0921f Remove 'config' as parameter from BaseFolder & derivatives
It is possible to get the config parameter from the Repository() which is
set in BaseFolder, so we set self.config there and remove the various
methods and 'config' parameters that are superfluous.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-09-16 12:54:12 +02:00
Sebastian Spaeth
410e2d35e9 Set accountname in BaseFolder, and don't pass it in initialization
We passed in the accountname to all derivatives of BaseFolder, such as
IMAPFolder(...,repository,...,accountname), although it is perfectly
possible to get the accountname from the Repository(). So remove this
unneeded parameter. Each backend had to define getaccountname() (although
the function is hardly used and most accessed .accountname directly).

On the other hand BaseFolder was using getaccountname but it never defined
the function. So make the sane thing, remove all definitions from backends
and define accountname() once in Basefolder. It was made a property and not
just a (public) attribute, so it will show up in our developer
documentation as public API.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-09-16 12:54:12 +02:00
Sebastian Spaeth
c93cd9bb1a BaseFolder(): Save name and repository
As all Folders share these parameters, we can safely handle them in
BaseFolder. This makes sense, as BaseFolder has a getname() function
that returns self.name but nothing actually set self.name.

It also saves a few lines of code.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-09-16 12:54:12 +02:00
Vladimir Marek
9ecac29aaa Maildir relative paths change was not complete
Commit e023f190b0 changed the storing of
file paths in the messagelist variable to be relative paths, but we were
using the full absolute path anyway as we missed one spot.

Adapt this and construct the full file path in the one place where we
need it.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-23 20:56:24 +02:00
Vladimir Marek
df62bb61a5 Create exception when file rename fails
Signed-off-by: Vladimir Marek <vlmarek@volny.cz>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-19 19:02:47 +02:00
Sebastian Spaeth
466ded04d9 Make flags a set rather than a list
As this is essentially what it is, a set of values. This allows as
to do set arithmetics to see, e.g. the intersection of 2 flag sets
rather than clunkily having to do:

for flag in newflags:
  if flag not in oldflags:
    oldflags.append(flag)

Also some more code documenting.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-19 18:56:10 +02:00
Vladimir Marek
6995eeb92e Support maildir for windows
That makes OfflineIMAP to use exclamation mark (!) instead of colon for storing
messages. Such files can be written to windows partitions. But you will probably
loose compatibility with other programs trying to read the same Maildir.

Signed-off-by: Vladimir Marek <vladimir.marek@oracle.com>
Reviewed-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-07-12 21:53:33 +02:00
Sebastian Spaeth
d8026c5308 Simplify Maildir message saving
Previously we were attempting to save out mails according to
 http://www.qmail.org/man/man5/maildir.html in 4 steps:

1 Create a unique filename
2 Do stat(tmp/<filename>). If it found a file, wait 2 sec and go back to 1.
3 Create and write the message to the tmp/<filename>.
4 Link from tmp/* to new/*

(we did step 2 up to 15 times) But as stated by
http://wiki1.dovecot.org/MailboxFormat/Maildir (see section 'Issues with
the specification'), this is a pointless approach, e.g. there are race
issues between stating that the filename does not exist and the actual
moving (when it might exist).

So, we can simplify the steps as suggested in the dovecot wiki and
tighten up our safety at the same time.

One improvement that we do is to open the file, guaranteeing that it did
not exist before in an atomic manner, thus our simplified approach is
really more secure than what we had before.

Also, we throw an OfflineImapError at MESSAGE level when the supposedly
unique filename already exists, so that we can skip this message and
still continue with other messages.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-06-13 16:29:00 +02:00
Sebastian Spaeth
e023f190b0 folder/Maildir: Store only relative filename components
MaildirFolder.messagelist[*]['filename'] was storing the absolute file
paths for all stored emails. While this is convenient, it wastes much
space, as the folder prefix is always the same and it is known to the
MaildirFolder. Just 40 chars in a folder with 100k mails waste >4MB of
space. Adapt the few locations where we need the full path to construct
it dynamically.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-06-12 17:41:13 +02:00
Sebastian Spaeth
c1c200a487 folder/Maildir: cache getfullname() value
We use getfullname() very often (thousands to millions), yet we
dynamically calculate the very same value over and over. Optimize this
by caching the value once and be done with it.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-06-12 17:40:11 +02:00
Sebastian Spaeth
f4081985dc Prettify and use new uidexists() helper function
Make the folder classes use uidexists() more. Add some code
documentation while going through.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-07 13:50:22 +02:00
Sebastian Spaeth
e37441cd19 folder/Maildir: Make use of helper functions
quickchanged() was iterating a lot, make use of some of the helper
functions that had been introduced recently and document the function a
bit better. No functional change.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-04-11 18:57:25 +02:00
Nicolas Sebrecht
44eefae043 cleanup import statements and conform to PEP-8
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-14 21:35:33 +01:00
Sebastian Spaeth
de618d84f3 Save ui as self.ui in folder/Base class
Rather than regetting the ui with UIBase.getglobalui() all the time, we get it once in the base class and let all derivative classes just make use of self.ui rather than refetching the ui all the time, this makes for a bit less code and shorter lines.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-01-05 19:24:00 +01:00
Mike Dawson
cde94e5047 Patch for maxage and maxsize options
Dear All,
Attached is the patch that I have developed to provide maxage and
maxsize options.  You can thus sync only the last x days of messages and
exclude large messages.  All details in the attached git file.

Regards,

-Mike

-- Attached file included as plaintext by Ecartis --
-- File: submit

From 04fead2b46a79675a5b29de6f2b4088b9c9448e5 Mon Sep 17 00:00:00 2001
From: mike <mike@mikelaptop.(none)>
Date: Sun, 16 Aug 2009 17:00:49 +0430
Subject: [PATCH] Patch to provide maxage and maxsize account options to exclude old/large messages

This is designed to make offlineimap even better for low bandwidth connections.

maxage allows you to specify a number of days and only messages within
that range will be considered by offlineimap for the sync.  This can be
useful if you would like to start using offlineimap with a large
existing account and do not want to import large archives of mail.

maxsize allows you to specify the maximum size of a message to consider so
that you can exclude messages with large attachments etc.

In both cases the cachemessagelist function of the folder was modified to ignore
messages that do not meet the criteria.  If the criteria are not specified
then the existing code will be executed the same as before.  If a message
does not meet the criteria it will be as though this message does not exist
- offlineimap will completely ignore it.  It will not have flags updated,
it will not be deleted, it will not be considered at all.

When operating against an IMAP repository a server side search function
is used.  This of course requires support for server side search.

I have tested this with either option, no options etc. against IMAP, Maildir
and Gmail.  I have run variations of this patch here for the last 3 weeks or
so syncing about 4 accounts normally.
2009-08-16 09:27:49 -05:00
John Goerzen
141a23849b Reduce memory usage when scanning Maildirs
Patch from Michal Vitecek
2009-07-07 00:52:00 -05:00
Peter Colberg
3299b2240c Applied patch from Peter Colberg to remove usage of hard linking
Closes: #535160

Bug#535160: offlineimap fails on encfs (FUSE) due to hard linking

Package: offlineimap
Version: 6.0.3
Severity: normal
Tags: patch

Hi,

if the localrepository is stored on an encfs, offlineimap fails as follows:

    OfflineIMAP 6.0.3
    Copyright (C) 2002 - 2008 John Goerzen <jgoerzen@complete.org>
    This software comes with ABSOLUTELY NO WARRANTY; see the file
    COPYING for details.  This is free software, and you are welcome
    to distribute it under the conditions laid out in COPYING.
    ***** Processing account pleione
    Copying folder structure from IMAP to Maildir
    Establishing connection to tunnel:eval `keychain --quiet --eval` && ssh -q mymailhost /usr/sbin/dovecot --exec-mail imap.
    Syncing Drafts: IMAP -> Maildir
    Syncing INBOX: IMAP -> Maildir
    ----------8<----------
    Syncing net: IMAP -> Maildir
    Copy message 360 IMAP[net] -> Maildir[net], LocalStatus[net]
    Syncing personal: IMAP -> Maildir
    Thread 'Copy message 360 from net' terminated with exception:
    Traceback (most recent call last):
      File "/var/lib/python-support/python2.4/offlineimap/threadutil.py", line 149, in run
	Thread.run(self)
      File "threading.py", line 422, in run
	self.__target(*self.__args, **self.__kwargs)
      File "/var/lib/python-support/python2.4/offlineimap/folder/Base.py", line 282, in copymessageto
	newuid = object.savemessage(uid, message, flags, rtime)
      File "/var/lib/python-support/python2.4/offlineimap/folder/Maildir.py", line 198, in savemessage
	os.path.join(tmpdir, messagename))
    OSError: [Errno 1] Operation not permitted

    Last 4 debug messages logged for Copy message 360 from net prior to exception:
    ----------8<----------

As encfs does not support hard linking, the rename of the temporary
message file fails.

This is the only occurrence of hard linking in offlineimap and can be
fixed by using an atomic `os.rename` instead of `os.link`+`os.unlink`.
I have been using the attached patch for more than 1.5 years and have
never again had any problems with offlineimap on encfs.

Regards,
Peter
2009-06-30 00:03:37 -05:00
Paul Hinze
c5886074ee Fix md5 import error
Paul Hinze <paul.t.hinze@gmail.com> on 2008-12-22 at 19:16:
> I did a bit of debugging and asking around in #python and it turns out
> that because Maildir.py uses a conditional import of md5 from either
> hashlib or the md5 module, the md5.new() call is not always correct.
> The attached patch should fix this problem.

Thanks to Daniel Rall for pointing out that the attachment got stripped
off my last message.  Patch follows.

Paul

----

From e01fdfbf62c61c31b514e826e6cc00fb98d88808 Mon Sep 17 00:00:00 2001
From: Paul Hinze <paul.t.hinze@gmail.com>
Date: Mon, 22 Dec 2008 18:42:44 -0600
Subject: [PATCH] Fixing md5 import when hashlib is available

Thanks to habnabit and Rhamphoryncus in #python for help debugging
2009-01-09 15:46:38 -06:00
Loui Chang
c6d95bd471 Import md5 from hashlib if available.
The md5 module is deprecated and hashlib is available
since python 2.5.

Signed-off-by: Loui Chang <louipc.ist@gmail.com>
2008-12-11 00:28:09 -06:00
John Goerzen
0da6bedaa0 Eliminate one more fsync 2008-08-02 15:31:43 -05:00
John Goerzen
fbcb157ca4 Fix syntax error in nofsync support 2008-08-02 15:11:23 -05:00
John Goerzen
2b23657db0 Added ability to disable fsync()
Passed config to LocalStatus and Maildir folders so they can look
up the fsync status
2008-08-02 14:55:08 -05:00
John Goerzen
24cdba3221 Undo 'Fix Maildir race' patch
This was causing OfflineIMAP to hang
2007-10-19 20:29:34 +01:00
John Goerzen
6caaea36e0 Fix Maildir race
fixes deb#439384

From: martin f krafft
Subject: race condition in Maildir writing

The offlineimap Maildir code checks for file existence and then
opens a file. That's open to a race condition. It's better to open
the file and fail if it already exists. The following patch does
this. It catches OSError 17 (file exists) and re-raises all others.
I'll leave it up to you to decide whether this is appropriate.
2007-10-19 01:06:18 +01:00
John Goerzen
3305d8cd4d Daniel Jacobowitz patches
fixes deb#433732

Date: Sun, 30 Sep 2007 13:54:56 -0400
From: Daniel Jacobowitz <drow@false.org>
To: offlineimap@complete.org
Subject: Assorted patches

Here's the result of a lazy Sunday hacking on offlineimap.  Sorry for
not breaking this into multiple patches.  They're mostly logically
independent so just ask if that would make a difference.
First, a new -q (quick) option.  The quick option means to only update
folders that seem to have had significant changes.  For Maildir, any
change to any message UID or flags is significant, because checking
the flags doesn't add a significant cost.  For IMAP, only a change to
the total number of messages or a change in the UID of the most recent
message is significant.  This should catch everything except for
flags changes.

The difference in bandwidth is astonishing: a quick sync takes 80K
instead of 5.3MB, and 28 seconds instead of 90.

There's a configuration variable that lets you say every tenth sync
should update flags, but let all the intervening ones be lighter.


Second, a fix to the UID validity problems many people have been
reporting with Courier.  As discussed in Debian bug #433732, I changed
the UID validity check to use SELECT unless the server complains that
the folder is read-only.  This avoids the Courier bug (see the Debian
log for more details).  This won't fix existing validity errors, you
need to remove the local status and validity files by hand and resync.


Third, some speedups in Maildir checking.  It's still pretty slow
due to a combination of poor performance in os.listdir (never reads
more than 4K of directory entries at a time) and some semaphore that
leads to lots of futex wake operations, but at least this saves
20% or so of the CPU time running offlineimap on a single folder:

Time with quick refresh and md5 in loop: 4.75s user 0.46s system 12%
cpu 41.751 total
Time with quick refresh and md5 out of loop: 4.38s user 0.50s system
14% cpu 34.799 total
Time using string compare to check folder: 4.11s user 0.47s system 13%
cpu 34.788 total


And fourth, some display fixes for Curses.Blinkenlights.  I made
warnings more visible, made the new quick sync message cyan, and
made all not explicitly colored messages grey.  That last one was
really bugging me.  Any time OfflineIMAP printed a warning in
this UI, it had even odds of coming out black on black!


Anyway, I hope these are useful.  I'm happy to revise them if you see
a problem.

-- 
Daniel Jacobowitz
CodeSourcery
2007-10-01 22:20:37 +01:00
Asheesh Laroia
35e7250187 only-write-once-to-cur-or-new.patch
I have tested this and Dovecot no longer beats offlineimap
to the punch. (-:

I achieved that by keeping the renames in tmp/ until it finally does
one last rename in new/ or cur/.
2007-06-13 04:42:15 +01:00
John Goerzen
4f54887265 Improve filesystem flushing semantics
fsync the Maildir file, its final directory when writing a new message.

fsync the localstatus file and its final directory when writing the 
local status cache.

This should reduce duplication in the event of hardware trouble.

fixes #8

see thread at http://lists.complete.org/offlineimap@complete.org/2007/03/threads.html.gz
2007-03-28 21:23:18 +01:00
John Goerzen
aa019172cb Handle rtime being Null when writing to Maildir
fixes #2
debian #401290
2006-12-02 21:54:26 +01:00
John Goerzen
c31f60f8df Update copyright date in Maildir.py 2006-12-02 21:54:15 +01:00
John Goerzen
03488ba81b Sync INTERNALDATE <-> mtime
The attached patch adds syncing the INTERNALDATE of IMAP folders with
the mtime of messages in maildir folders.
I want this to happen, because I'm running a dovecot over the maildirs
synced by offlineimap, and that uses the mtime as the INTERNALDATE.
When using mutt to view messages I generally sort based on the received
date, which for IMAP folders is the INTERNALDATE.

Since this is the first real coding I've done in Python the patch may
need to be cleaned up some, but it's working pretty well for me.  I've
added new messages to each side, and the received date has been
preserved going both ways.
2006-08-22 02:09:36 +01:00
John Goerzen
39a18fef60 Update FSF address 2006-08-12 05:15:55 +01:00
John Goerzen
d839be3c61 Step 2 of SVN to arch tree conversion 2005-04-16 20:33:35 +01:00