rev 297 - in offlineimap/head: debian offlineimap offlineimap/ui
[email protected] Fri, 3 Jan 2003 16:57:47 -0600 (CST)
| Newsgroups | gmane.mail.imap.offlineimap.subversion |
|---|---|
| Message-ID | <[email protected]> |
Author: jgoerzen
Date: 2003-01-03 16:57:46 -0600 (Fri, 03 Jan 2003)
New Revision: 297
Added:
offlineimap/head/debian/changelog
offlineimap/head/offlineimap/CustomConfig.py
offlineimap/head/offlineimap/accounts.py
offlineimap/head/offlineimap/test.py
Modified:
offlineimap/head/offlineimap/init.py
offlineimap/head/offlineimap/mbnames.py
offlineimap/head/offlineimap/syncmaster.py
offlineimap/head/offlineimap/threadutil.py
offlineimap/head/offlineimap/ui/Noninteractive.py
offlineimap/head/offlineimap/ui/UIBase.py
offlineimap/head/offlineimap/ui/detector.py
Log:
* Changed to a more account-centric behavior. The refresh time is now
a per-account variable. Implemented new account classes. User
interfaces must now be updated to take advantage of this.
Added: offlineimap/head/debian/changelog
==============================================================================
--- offlineimap/head/debian/changelog (original)
+++ offlineimap/head/debian/changelog Fri Jan 3 16:57:47 2003
@@ -0,0 +1,443 @@
+offlineimap (3.99.6) unstable; urgency=low
+
+ * Beginnings of work to make it work with a threaded Tcl/Tk Tkinter.
+ * Now properly handles folder names that contain parenthesis. Used
+ patch from Kyler Laird in
+ http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=173895.
+ Closes: #173895.
+ * Changed to a more account-centric behavior. The refresh time is now
+ a per-account variable. Implemented new account classes. User
+ interfaces must now be updated to take advantage of this.
+
+ -- John Goerzen <[email protected]> Thu, 2 Jan 2003 13:59:44 -0600
+
+offlineimap (3.99.5) unstable; urgency=low
+
+ * Added ability to disable expunging on the server.
+ * Fixed infinite loop with preauth. Closes: #169514, #171485.
+
+ -- John Goerzen <[email protected]> Tue, 03 Dec 2002 06:22:37 -0600
+
+offlineimap (3.99.4) unstable; urgency=low
+
+ * Fixed setup.py installation instructions.
+ * Added more debugging to the CRAM-MD5 authentication module.
+ * CRAM-MD5 *really* fixed this time. Thanks to MJ for the patch.
+ * Adding missing import os to imapserver.py. Thanks to John Wiegley
+ for catching that.
+
+ -- John Goerzen <[email protected]> Tue, 5 Nov 2002 08:06:45 -0600
+
+offlineimap (3.99.3) unstable; urgency=low
+
+ * Moved password promting into imapserver.py. Passwords are now asked
+ for on-demand and typos will no longer crash the program (the user
+ will be re-prompted). Closes: #162672.
+ * Falls back to plain-text auth if CRAM-MD5 fails. Fixes [complete.org #42]
+ * Fixed CRAM-MD5 auth so it actually works now.
+
+ -- John Goerzen <[email protected]> Mon, 4 Nov 2002 06:16:11 -0600
+
+offlineimap (3.99.2) unstable; urgency=low
+
+ * Further attempts to fix imapsplit problems.
+ * When an exception occurs, OfflineIMAP will attempt to print the last
+ 50 debug messages, whether or not debugging was enabled for this
+ session. This way, even unexpected and non-repeatable errors stand
+ a chance of getting a more detailed log.
+ * Handle uidvalidity file in an atomic fashion. CLoses: #165600.
+ * Supports CRAM-MD5 authentication. Fixes [complete.org #38], and for
+ Debian, Closes: #154165.
+ * Noted CRAM-MD5 support in the "CONFORMING TO" section of the manual.
+ * Certain servers may not always return the UID flag for new messages.
+ This causes an OfflineIMAP exception, though rerunning will fix it.
+ Now, OfflineIMAP will detect the condition and ignore the offending
+ messages (without an exception) until the next sync.
+
+ -- John Goerzen <[email protected]> Sat, 02 Nov 2002 10:23:10 -0600
+
+offlineimap (3.99.1) unstable; urgency=low
+
+ * Fixed some syntax errors in imaputil.py
+ * Fixed a syntax error with mbnames
+
+ -- John Goerzen <[email protected]> Wed, 9 Oct 2002 19:34:37 -0500
+
+offlineimap (3.99.0) unstable; urgency=low
+
+ * The next few releases are adding features and reorganizing
+ code in preparation for 4.0.0.
+ * imaputil.py now logs information with IMAP debugging is enabled.
+ * Added folderfilter capability to mbnames recorder. You can now omit
+ specified folders from the mbnames output.
+ * Added a workaround to imaputil.py to deal with a bug in imaplib.py's
+ tuple when a response contains a literal in certain cases.
+ * Split out the code in bin/offlineimap into offlineimap/init.py.
+ Retaining bin/offlineimap as a skeletal piece only. Contains
+ about three lines of code now. This will make many things
+ easier, including debugging.
+ * Added library version check to bin/offlineimap and
+ offlineimap/init.py.
+ * Moved __main__.ui to functions in UIBase: getglobalui() and
+ setglobalui().
+ * Added license comments to some source files that were missing them.
+ * Moved some code from offlineimap/init.py to new file
+ offlineimap/syncmaster.py to help dileneate between code that
+ performs different functions.
+ * Moved threadexited from offlineimap/init.py to
+ offlineimap/threadutil.py.
+ * offlineimap.py is back to ease the use of OfflineIMAP in single-user
+ installations.
+
+ -- John Goerzen <[email protected]> Mon, 07 Oct 2002 05:08:08 -0500
+
+offlineimap (3.2.8) unstable; urgency=low
+
+ * Added a work-around for some IMAP servers that respond poorly
+ to LIST "" "". It will now do LIST "" "*", for them only.
+
+ -- John Goerzen <[email protected]> Mon, 30 Sep 2002 10:48:01 -0500
+
+offlineimap (3.2.7) unstable; urgency=low
+
+ * Moved executable to bin/offlineimap. This will allow setup.py to
+ properly install it as offlineimap instead of offlineimap.py.
+ * Made sure executables use /usr/bin/env in bangpath.
+ * Font size for Blinkenlights interface is now configurable.
+
+ -- John Goerzen <[email protected]> Thu, 19 Sep 2002 06:46:56 -0500
+
+offlineimap (3.2.6) unstable; urgency=low
+
+ * Changed indentation in debian/control. Closes: #156327.
+ * Removed calls to folder object deletions. None have been implemented
+ anyway.
+ * folder/Maildir.py: unlink throws OSError, not IOError; fixed.
+ Now handles message deleting race condition properly.
+ Closes: #154497.
+
+ -- John Goerzen <[email protected]> Fri, 16 Aug 2002 17:43:19 -0500
+
+offlineimap (3.2.5) unstable; urgency=low
+
+ * Now handles uploading messages without Message-Id headers.
+ Closes: #156022.
+ * Applied patch from Tommi Virtanen that adds two new config file
+ options: pythonfile and foldersort. Fixes [complete.org #29], and
+ for Debian, Closes: #155637.
+ * Added documentation for the above features.
+ * Even more resiliant in the face of invalid Date headers. Closes: #155994.
+
+ -- John Goerzen <[email protected]> Fri, 9 Aug 2002 17:54:01 -0500
+
+offlineimap (3.2.4) unstable; urgency=low
+
+ * When using nested folders, the Maildir repository handler now properly
+ deals with folders that are nested inside "noselect" folders -- ones
+ that do not actually contain messages and are not provided in the
+ server's LIST response. Fixes [complete.org #32] and, for Debian,
+ Closes: #155866.
+
+ -- John Goerzen <[email protected]> Thu, 8 Aug 2002 17:54:44 -0500
+
+offlineimap (3.2.3) unstable; urgency=low
+
+ * -d now takes a parameter: imap or maildir (or both) to specify
+ what type of debugging to do.
+
+ -- John Goerzen <[email protected]> Thu, 8 Aug 2002 10:02:36 -0500
+
+offlineimap (3.2.2) unstable; urgency=low
+
+ * Updated manual to show new Gray color.
+ * Scrolling behavior is better now; sometimes, with fast-scrolling text,
+ the log would stop scrolling.
+ * Better handling of read-only folders. We will now warn if there is
+ a change, but not propogate it. New config variable ignore-readonly
+ can suppress the warnings. This fixes [complete.org #10] and,
+ for Debian, Closes: #154769.
+ * If a given Maildir folder is new, remove the associated local status
+ cache file, if any. That way, there will not be any chance of
+ propogating hordes of deletes and adds based on old status data.
+ * Added support for /-separated Maildirs -- that is, hierarchical
+ Maildir trees. Fixes [complete.org #28] and, for Debian,
+ Closes: #155460.
+ * Preventitive security: Folder names may not contain ./ or start with /.
+
+ -- John Goerzen <[email protected]> Wed, 07 Aug 2002 20:22:25 -0500
+
+offlineimap (3.2.1) unstable; urgency=low
+
+ * There is a new "connecting" event that will appear in all but the
+ Quiet UIs. It has a gray color in Blinkenlights. This event indicates
+ the the program is connecting to a remote server.
+ * Blinkenlights UI log window is now scrolled and has a new
+ config file option "bufferlines" to specify the size of the scroll
+ buffer.
+ * The Blinkenlights window is now non-resizable when the log is disabled.
+ When the log is enabled, the window is resizable, and the changes in
+ size are reflected in the log widget. Therefore, the Bigger Log
+ and Smaller Log items can disappear, and the Log menu now becomes
+ a Show Log or a Hide Log menu option. No sub-menus necessary anymore.
+ This presents a much cleaner feel, more intuitive operation, and
+ faster navigation.
+ * Fix for account name interpolation in dot warning from 3.2.0 from
+ Martijn Pieters.
+ * Backed out check for . in account names for now. Will put it back in
+ when we have a consensus on what exactly to do. Doubt that anyone
+ has a foldername that would conflict with Blinkenlights anyway.
+ * Fix reading the ui.Tk.Blinkenlights bufferlines option.
+
+ -- John Goerzen <[email protected]> Wed, 24 Jul 2002 17:04:04 -0500
+
+offlineimap (3.2.0) unstable; urgency=low
+
+ * New BLINKENLIGHTS interface! Mesmerising, isn't it?
+ * New ui.Tk.Blinkenlights section in offlineimap.conf.
+ * New USER INTERFACES section in the manual.
+ * TTYUI isusable() now checks to see if stdout and stdin are TTYs.
+ * Added build-dependency on python2.2-dev. Closes: #154167.
+
+ -- John Goerzen <[email protected]> Wed, 24 Jul 2002 17:53:20 -0500
+
+offlineimap (3.1.1) unstable; urgency=low
+
+ * Modified imaputil.py and folder/Maildir.py to run faster. Eliminated
+ many regular expressions; pre-compiled many others.
+ * Fixed threadutil's exitnotifyloop to always handle threads in the order
+ they exited, rather than sometimes in the inverse order. This way,
+ make sure to handle thread's exception messages before a thread exited.
+ * Replaced imaplib.py's braindead readline() with a more efficient one.
+ * More optimizations to imaputil and folders for faster operation.
+ * These optimizations, all together, have resulted in OfflineIMAP
+ using approximately half the CPU time of previous versions, fixing
+ [complete.org #6], and... Closes: #153503.
+
+ -- John Goerzen <[email protected]> Wed, 24 Jul 2002 06:53:16 -0500
+
+offlineimap (3.1.0) unstable; urgency=low
+
+ * When uploading messages from a Maildir, now convert \r\n to \n in case
+ the message is stored weirdly. That way, everything is uniform.
+ Fixes [complete.org #11].
+ * Manual: added UW IMAPD example with references from [email protected].
+ * New UI modules: Noninteractive.Basic and Noninteractive.Quiet.
+ Fixes [complete.org #14].
+ * Added per-thread profiling support to aid in debugging.
+
+ -- John Goerzen <[email protected]> Sun, 21 Jul 2002 16:09:42 -0500
+
+offlineimap (3.0.3) unstable; urgency=low
+
+ * No longer throws an exception when updating messages with strange
+ Date headers; will just set IMAP Internaldate to the current date.
+ Closes: #153425.
+ * No longer doubles-up reference names for mailboxes. Closes: #153515.
+ * Noted new bug-tracking system in manual and rebuilt manual files.
+ * Now stores incoming messages in 'cur' instead of 'new' if they have
+ the S flag. Closes: #152482.
+
+ -- John Goerzen <[email protected]> Sun, 21 Jul 2002 13:46:13 -0500
+
+offlineimap (3.0.2) unstable; urgency=low
+
+ * Fixed mailbox name recorder to use localfolder.getvisiblename() rather
+ than remotefolder.getvisiblename()
+ * Fixed remotepassfile option. Closes: #153119. Used 1-line patch from
+ Tommi Virtanen.
+ * Now handles cases of not being able to get UID for an uploaded message
+ more gracefully. This could occur if the server doesn't support
+ SEARCH, can't find the message ID, or finds multiple message IDs.
+ Closes: #153241.
+ * Now source is in Subversion. Make version.py log the Subversion
+ revision number.
+
+ -- John Goerzen <[email protected]> Wed, 15 Jul 2002 06:43:36 -0500
+
+offlineimap (3.0.1) unstable; urgency=low
+
+ * Detabified the source.
+ * Added UI list to the manpage.
+ * Added -o (run only once) option with patch sent in by Martijn Pieters.
+ * Optimized folder/IMAP.py addmessagesflags() with new listjoin() in
+ imaputil. Now, send the server 1:5,7 instead of 1,2,3,4,5,7.
+ * Made folder/Maildir.py/deletemessage() more tolerant if a message
+ asked to be deleted already has been.
+ * In Base.py/copymessageto(), no longer bother calling getmessage()
+ unless a folder's storemessages() returns true. This will also help
+ with syncing to LocalStatus if the user deleted messages in the
+ Maildir since the cachemessagelist() was called.
+
+ -- John Goerzen <[email protected]> Fri, 12 Jul 2002 07:28:24 -0500
+
+offlineimap (3.0.0) unstable; urgency=low
+
+ * Introduced a new graphical user interface written with Tkinter.
+ It features a nice view of multi-threaded displays.
+ * The TTY user interface now also displays thread names.
+ * Program-wide, new threads are given descriptive names to aid in
+ debugging and status messages.
+ * Added new module offlineimap/ui/detect.py that is used to detect
+ which user interface to select for a given session. Its operation
+ is governed by the ui config option and the -u command-line option.
+ * Made IMAP folder addmessagesflags() resiliant to a server refusing
+ to return a full set of new message flags. Closes: #152587.
+ * Completely rewrote documentation. OfflineIMAP now has an
+ exhaustive manpage, which is really a manual. It is also shipped
+ in plain text, HTML, PDF, and PostScript formats.
+ * New command-line options:
+ -1 to force no multi-threaded operation
+ -u to force a particular UI
+ -a to specify which accounts to sync
+ -h to print help
+ -c to specify an alternate config file
+ * Added a workaround for UW IMAP problem wherein the server loses
+ uidvalidity whenever a folder is emptied. Now, the program
+ will not consider it a problem if uidvalidity is lost when a folder
+ and the local status cache are both completely empty, since we do
+ not really need to preserve uidvalidity in that case anyway.
+ Closes: #152079.
+
+ -- John Goerzen <[email protected]> Thu, 11 Jul 2002 22:35:42 -0500
+
+offlineimap (2.0.8) unstable; urgency=low
+
+ * Modified the IMAP folder to use SELECT rather than STATUS more often.
+ Makes the code more robust; handles better with read-only folders;
+ and runs faster, especially for non-threaded useres, where it
+ may eliminate up to 2-3 commands per folder.
+ * Made sure IMAP folder savemessage() does a select. This was a possible
+ bug.
+ * Modified Maildir folder to unlink messages with T flag in
+ cachemessagelist()
+ * My own box now syncs in 3 seconds.
+ * Optimized acquireconnection() to try to give a thread back the
+ connection that it last used, if possible.
+
+ -- John Goerzen <[email protected]> Tue, 9 Jul 2002 23:29:30 -0500
+
+offlineimap (2.0.7) unstable; urgency=low
+
+ * Fixed imaplib.py to work better with read-only folders.
+
+ -- John Goerzen <[email protected]> Tue, 9 Jul 2002 20:24:21 -0500
+
+offlineimap (2.0.6) unstable; urgency=low
+
+ * Added support for holdconnectionopen and keepalive. This feature
+ allows for an IMAP server connection(s) to be held open until
+ the next sync process, permitting faster restart times.
+ * Another try at read-only folder support. This is nasty because I
+ have no way to test it and imaplib's read-only support is weird.
+ * Closing out old bug; fixed in 1.0.2. Closes: #150803.
+ * Optimized algorithm so that a SELECT is never issued for folders
+ that contain no messages.
+
+ -- John Goerzen <[email protected]> Tue, 9 Jul 2002 20:05:24 -0500
+
+offlineimap (2.0.5) unstable; urgency=low
+
+ * Fixed a folderfilter example. Partially fixes #152079.
+ * Added folderincludes capability. Partially fixes #152079.
+ * More fixes for read-only folders.
+
+ -- John Goerzen <[email protected]> Fri, 5 Jul 2002 09:21:52 -0500
+
+offlineimap (2.0.4) unstable; urgency=low
+
+ * Made OfflineIMAP at least rudimentarily compatible with read-only
+ folders. It will still fail if they get modified locally, though.
+ * Flags are handled case-insensitively. Closes: #151993.
+
+ -- John Goerzen <[email protected]> Fri, 5 Jul 2002 09:10:29 -0500
+
+offlineimap (2.0.3) unstable; urgency=low
+
+ * Added support for specifying references. Closes: #151960.
+ * Added -d command-line option to enable imaplib debugging.
+
+ -- John Goerzen <[email protected]> Thu, 4 Jul 2002 20:39:29 -0500
+
+offlineimap (2.0.2) unstable; urgency=low
+
+ * Added support for remotepassfile. Closes: #151943.
+ * Added support for preauth tunnels.
+
+ -- John Goerzen <[email protected]> Thu, 4 Jul 2002 14:46:23 -0500
+
+offlineimap (2.0.1) unstable; urgency=low
+
+ * Fixed a bug with not properly propogating foldersep changes.
+ Now, local folders and status folders properly use the foldersep
+ mechanism. This corrects a problem with Exchange servers.
+ * Wrote a major new thread montiring subsystem, defined a new
+ ExitNotifyThread. Handling of Ctrl-C now occurs within 1 second
+ rather than after the whole program terminates. Exceptions that
+ occur in a thread are now caught by the main thread and marshalled
+ over into the UI side of things for dispatch. The entire program will
+ now abort when one thread dies with an exception.
+
+ -- John Goerzen <[email protected]> Thu, 4 Jul 2002 09:07:06 -0500
+
+offlineimap (2.0.0) unstable; urgency=low
+
+ * This code is now multithreaded. New config file options control the
+ behavior. This can make synchronizing several times faster.
+ * Fixed the STATUS call to be compatible with Exchange.
+ * Added the ability to exclude folders.
+ * If upgrading from 1.0.x, you will need to add maxsyncaccounts to the
+ general section and maxconnections to each account sections.
+ There is also a new folderfilter option.
+ You can find examples of all of these in the new offlineimap.conf
+ example file packaged with the distribution.
+ * The Debian package now properly installs the example offlineimap.conf
+ file.
+ * There is a new mailing list available. To join, send SUBSCRIBE
+ to [email protected]. The posting address is
+ [email protected].
+
+ -- John Goerzen <[email protected]> Wed, 3 Jul 2002 19:21:32 -0500
+
+offlineimap (1.0.4) unstable; urgency=low
+
+ * Deletion of more than one message has been optimized. This could make
+ deleting large numbers of messages far faster -- several orders of
+ magnitude.
+ * Moved more sleep code into ui layer. Fancier sleep actions are now
+ possible. Better handling of Ctrl-C in TTY handler.
+
+ -- John Goerzen <[email protected]> Tue, 2 Jul 2002 19:16:04 -0500
+
+offlineimap (1.0.3) unstable; urgency=low
+
+ * Fixed a bug when a message was deleted on the IMAP side and modified
+ on the local side.
+
+ -- John Goerzen <[email protected]> Mon, 24 Jun 2002 19:08:21 -0500
+
+offlineimap (1.0.2) unstable; urgency=low
+
+ * Made sure that LocalStatus does writing atomically. If the program
+ is interrupted during save(), there will always be a complete copy of
+ either the old or the new data.
+
+ -- John Goerzen <[email protected]> Mon, 24 Jun 2002 06:57:28 -0500
+
+offlineimap (1.0.1) unstable; urgency=low
+
+ * Fixed a bug with writing messages to some IMAP servers. Turns
+ out we need to issue CHECK between APPEND and SEARCH for some.
+ Thanks to Donovan Lange for reporting this bug and helping track it
+ down.
+
+ -- John Goerzen <[email protected]> Fri, 21 Jun 2002 22:03:12 -0500
+
+offlineimap (1.0.0) unstable; urgency=low
+
+ * Initial Release. Closes: #150571.
+
+ -- John Goerzen <[email protected]> Fri, 21 Jun 2002 18:54:56 -0500
+
+Local variables:
+mode: debian-changelog
+End:
Modified: offlineimap/head/offlineimap/syncmaster.py
==============================================================================
--- offlineimap/head/offlineimap/syncmaster.py (original)
+++ offlineimap/head/offlineimap/syncmaster.py Fri Jan 3 16:57:47 2003
@@ -18,187 +18,29 @@
from offlineimap import imaplib, imapserver, repository, folder, mbnames, threadutil, version
from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
+import offlineimap.accounts
+from offlineimap.accounts import SyncableAccount
from offlineimap.ui import UIBase
import re, os, os.path, offlineimap, sys
from ConfigParser import ConfigParser
from threading import *
-def syncaccount(accountname, metadatadir, servers, config,
- localeval, *args):
- ui = UIBase.getglobalui()
- # We don't need an account lock because syncitall() goes through
- # each account once, then waits for all to finish.
- try:
- ui.acct(accountname)
- accountmetadata = os.path.join(metadatadir, accountname)
- if not os.path.exists(accountmetadata):
- os.mkdir(accountmetadata, 0700)
-
- server = None
- if accountname in servers:
- server = servers[accountname]
- else:
- server = imapserver.ConfigedIMAPServer(config, accountname)
- servers[accountname] = server
-
- remoterepos = repository.IMAP.IMAPRepository(config, localeval, accountname, server)
-
- # Connect to the Maildirs.
- localrepos = repository.Maildir.MaildirRepository(os.path.expanduser(config.get(accountname, "localfolders")), accountname, config)
-
- # Connect to the local cache.
- statusrepos = repository.LocalStatus.LocalStatusRepository(accountmetadata)
-
- ui.syncfolders(remoterepos, localrepos)
- remoterepos.syncfoldersto(localrepos)
- ui.acct(accountname)
-
- folderthreads = []
- for remotefolder in remoterepos.getfolders():
- thread = InstanceLimitedThread(\
- instancename = 'FOLDER_' + accountname,
- target = syncfolder,
- name = "Folder sync %s[%s]" % \
- (accountname, remotefolder.getvisiblename()),
- args = (accountname, remoterepos, remotefolder, localrepos,
- statusrepos))
- thread.setDaemon(1)
- thread.start()
- folderthreads.append(thread)
- threadutil.threadsreset(folderthreads)
- if not (config.has_option(accountname, 'holdconnectionopen') and \
- config.getboolean(accountname, 'holdconnectionopen')):
- server.close()
- finally:
- pass
-
-def syncfolder(accountname, remoterepos, remotefolder, localrepos,
- statusrepos):
- ui = UIBase.getglobalui()
- # Load local folder.
- localfolder = localrepos.\
- getfolder(remotefolder.getvisiblename().\
- replace(remoterepos.getsep(), localrepos.getsep()))
- # Write the mailboxes
- mailboxes.append({'accountname': accountname,
- 'foldername': localfolder.getvisiblename()})
- # Load local folder
- ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder)
- ui.loadmessagelist(localrepos, localfolder)
- localfolder.cachemessagelist()
- ui.messagelistloaded(localrepos, localfolder, len(localfolder.getmessagelist().keys()))
-
-
- # Load status folder.
- statusfolder = statusrepos.getfolder(remotefolder.getvisiblename().\
- replace(remoterepos.getsep(),
- statusrepos.getsep()))
- if localfolder.getuidvalidity() == None:
- # This is a new folder, so delete the status cache to be sure
- # we don't have a conflict.
- statusfolder.deletemessagelist()
-
- statusfolder.cachemessagelist()
-
+def syncaccount(threads, config, accountname):
+ account = SyncableAccount(config, accountname)
+ thread = InstanceLimitedThread(instancename = 'ACCOUNTLIMIT',
+ target = account.syncrunner,
+ name = "Account sync %s" % accountname)
+ thread.setDaemon(1)
+ thread.start()
+ threads.add(thread)
- # If either the local or the status folder has messages and
- # there is a UID validity problem, warn and abort.
- # If there are no messages, UW IMAPd loses UIDVALIDITY.
- # But we don't really need it if both local folders are empty.
- # So, in that case, save it off.
- if (len(localfolder.getmessagelist()) or \
- len(statusfolder.getmessagelist())) and \
- not localfolder.isuidvalidityok(remotefolder):
- ui.validityproblem(remotefolder)
- return
- else:
- localfolder.saveuidvalidity(remotefolder.getuidvalidity())
-
- # Load remote folder.
- ui.loadmessagelist(remoterepos, remotefolder)
- remotefolder.cachemessagelist()
- ui.messagelistloaded(remoterepos, remotefolder,
- len(remotefolder.getmessagelist().keys()))
-
-
- #
-
- if not statusfolder.isnewfolder():
- # Delete local copies of remote messages. This way,
- # if a message's flag is modified locally but it has been
- # deleted remotely, we'll delete it locally. Otherwise, we
- # try to modify a deleted message's flags! This step
- # need only be taken if a statusfolder is present; otherwise,
- # there is no action taken *to* the remote repository.
-
- remotefolder.syncmessagesto_delete(localfolder, [localfolder,
- statusfolder])
- ui.syncingmessages(localrepos, localfolder, remoterepos, remotefolder)
- localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder])
-
- # Synchronize remote changes.
- ui.syncingmessages(remoterepos, remotefolder, localrepos, localfolder)
- remotefolder.syncmessagesto(localfolder)
-
- # Make sure the status folder is up-to-date.
- ui.syncingmessages(localrepos, localfolder, statusrepos, statusfolder)
- localfolder.syncmessagesto(statusfolder)
- statusfolder.save()
-
-
-
-def syncitall(accounts, metadatadir, servers, config, localeval):
+def syncitall(accounts, config):
+ currentThread().setExitMessage('SYNC_WITH_TIMER_TERMINATE')
ui = UIBase.getglobalui()
- global mailboxes
- mailboxes = [] # Reset.
- threads = []
+ threads = threadutil.threadlist()
+ offlineimap.accounts.mailboxes = [] # Reset.
for accountname in accounts:
- thread = InstanceLimitedThread(instancename = 'ACCOUNTLIMIT',
- target = syncaccount,
- name = "Account sync %s" % accountname,
- args = (accountname, metadatadir,
- servers, config,
- localeval))
- thread.setDaemon(1)
- thread.start()
- threads.append(thread)
+ syncaccount(threads, config, accountname)
# Wait for the threads to finish.
- threadutil.threadsreset(threads)
- mbnames.genmbnames(config, localeval, mailboxes)
-
-def sync_with_timer(accounts, metadatadir, servers, config,
- localeval):
- ui = UIBase.getglobalui()
- currentThread().setExitMessage('SYNC_WITH_TIMER_TERMINATE')
- syncitall(accounts, metadatadir, servers, config, localeval)
- if config.has_option('general', 'autorefresh'):
- refreshperiod = config.getint('general', 'autorefresh') * 60
- while 1:
- # Set up keep-alives.
- kaevents = {}
- kathreads = {}
- for accountname in accounts:
- if config.has_option(accountname, 'holdconnectionopen') and \
- config.getboolean(accountname, 'holdconnectionopen') and \
- config.has_option(accountname, 'keepalive'):
- event = Event()
- kaevents[accountname] = event
- thread = ExitNotifyThread(target = servers[accountname].keepalive,
- name = "Keep alive " + accountname,
- args = (config.getint(accountname, 'keepalive'), event))
- thread.setDaemon(1)
- thread.start()
- kathreads[accountname] = thread
- if ui.sleep(refreshperiod) == 2:
- # Cancel keep-alives, but don't bother terminating threads
- for event in kaevents.values():
- event.set()
- break
- else:
- # Cancel keep-alives and wait for threads to terminate.
- for event in kaevents.values():
- event.set()
- for thread in kathreads.values():
- thread.join()
- syncitall(accounts, metadatadir, servers, config,
- localeval)
+ threads.reset()
+ mbnames.genmbnames(config, offlineimap.accounts.mailboxes)
Added: offlineimap/head/offlineimap/CustomConfig.py
==============================================================================
--- offlineimap/head/offlineimap/CustomConfig.py (original)
+++ offlineimap/head/offlineimap/CustomConfig.py Fri Jan 3 16:57:47 2003
@@ -0,0 +1,46 @@
+# Copyright (C) 2003 John Goerzen
+# <[email protected]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from ConfigParser import ConfigParser
+from offlineimap.localeval import LocalEval
+import os
+
+class CustomConfigParser(ConfigParser):
+ def getdefault(self, section, option, default, *args, **kwargs):
+ """Same as config.get, but returns the "default" option if there
+ is no such option specified."""
+ if self.has_option(section, option):
+ return apply(self.get, [section, option] + list(args), kwargs)
+ else:
+ return default
+
+ def getmetadatadir(self):
+ metadatadir = os.path.expanduser(self.getdefault("general", "metadata", "~/.offlineimap"))
+ if not os.path.exists(metadatadir):
+ os.mkdir(metadatadir, 0700)
+ return metadatadir
+
+ def getlocaleval(self):
+ if self.has_option("general", "pythonfile"):
+ path = os.path.expanduser(self.get("general", "pythonfile"))
+ else:
+ path = None
+ return LocalEval(path)
+
+ def getaccountlist(self):
+ return [x for x in self.sections() if x != 'general']
+
Modified: offlineimap/head/offlineimap/init.py
==============================================================================
--- offlineimap/head/offlineimap/init.py (original)
+++ offlineimap/head/offlineimap/init.py Fri Jan 3 16:57:47 2003
@@ -21,7 +21,7 @@
from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
from offlineimap.ui import UIBase
import re, os, os.path, offlineimap, sys
-from ConfigParser import ConfigParser
+from offlineimap.CustomConfig import CustomConfigParser
from threading import *
from getopt import getopt
@@ -51,20 +51,14 @@
threadutil.setprofiledir(profiledir)
sys.stderr.write("WARNING: profile mode engaged;\nPotentially large data will be created in " + profiledir + "\n")
- config = ConfigParser()
+ config = CustomConfigParser()
if not os.path.exists(configfilename):
sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
sys.exit(1)
config.read(configfilename)
- if config.has_option("general", "pythonfile"):
- path=os.path.expanduser(config.get("general", "pythonfile"))
- else:
- path=None
- localeval = LocalEval(path)
-
- ui = offlineimap.ui.detector.findUI(config, localeval, options.get('-u'))
+ ui = offlineimap.ui.detector.findUI(config, options.get('-u'))
ui.init_banner()
UIBase.setglobalui(ui)
@@ -74,12 +68,9 @@
if debugtype == 'imap':
imaplib.Debug = 5
- if '-o' in options and config.has_option("general", "autorefresh"):
- config.remove_option("general", "autorefresh")
-
- metadatadir = os.path.expanduser(config.get("general", "metadata"))
- if not os.path.exists(metadatadir):
- os.mkdir(metadatadir, 0700)
+ if '-o' in options:
+ for section in config.getaccountlist():
+ config.remove_option(section, "autorefresh")
accounts = config.get("general", "accounts")
if '-a' in options:
@@ -105,17 +96,11 @@
threadutil.initInstanceLimit(instancename,
config.getint(account, "maxconnections"))
- mailboxes = []
- servers = {}
-
threadutil.initexitnotify()
- t = ExitNotifyThread(target=syncmaster.sync_with_timer,
+ t = ExitNotifyThread(target=syncmaster.syncitall,
name='Sync Runner',
kwargs = {'accounts': accounts,
- 'metadatadir': metadatadir,
- 'servers': servers,
- 'config': config,
- 'localeval': localeval})
+ 'config': config})
t.setDaemon(1)
t.start()
try:
Modified: offlineimap/head/offlineimap/threadutil.py
==============================================================================
--- offlineimap/head/offlineimap/threadutil.py (original)
+++ offlineimap/head/offlineimap/threadutil.py Fri Jan 3 16:57:47 2003
@@ -48,6 +48,42 @@
for thr in threadlist:
thr.join()
+class threadlist:
+ def __init__(self):
+ self.lock = Lock()
+ self.list = []
+
+ def add(self, thread):
+ self.lock.acquire()
+ try:
+ self.list.append(thread)
+ finally:
+ self.lock.release()
+
+ def remove(self, thread):
+ self.lock.acquire()
+ try:
+ self.list.remove(thread)
+ finally:
+ self.lock.release()
+
+ def pop(self):
+ self.lock.acquire()
+ try:
+ if not len(self.list):
+ return None
+ return self.list.pop()
+ finally:
+ self.lock.release()
+
+ def reset(self):
+ while 1:
+ thread = self.pop()
+ if not thread:
+ return
+ thread.join()
+
+
######################################################################
# Exit-notify threads
######################################################################
Added: offlineimap/head/offlineimap/test.py
==============================================================================
--- offlineimap/head/offlineimap/test.py (original)
+++ offlineimap/head/offlineimap/test.py Fri Jan 3 16:57:47 2003
@@ -0,0 +1,17 @@
+#!/usr/bin/python2.2 -i
+import hmac
+def getpassword():
+ return 'tanstaaftanstaaf'
+
+def md5handler(response):
+ challenge = response.strip()
+ print "challenge is", challenge
+ msg = getpassword()
+ reply = hmac.new(challenge, msg)
+ retval = 'tim' + ' ' + \
+ reply.hexdigest()
+ while len(retval) < 64:
+ retval += "\0"
+
+ print "md5handler returning", retval
+ return retval
Added: offlineimap/head/offlineimap/accounts.py
==============================================================================
--- offlineimap/head/offlineimap/accounts.py (original)
+++ offlineimap/head/offlineimap/accounts.py Fri Jan 3 16:57:47 2003
@@ -0,0 +1,211 @@
+# Copyright (C) 2003 John Goerzen
+# <[email protected]>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from offlineimap import imapserver, repository, threadutil
+from offlineimap.ui import UIBase
+from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
+from threading import Event
+import os
+
+mailboxes = []
+
+class Account:
+ def __init__(self, config, name):
+ self.config = config
+ self.name = name
+ self.metadatadir = config.getmetadatadir()
+ self.localeval = config.getlocaleval()
+ self.server = imapserver.ConfigedIMAPServer(config, self.name)
+ self.ui = UIBase.getglobalui()
+ if self.config.has_option(self.name, 'autorefresh'):
+ self.refreshperiod = self.config.getint(self.name, 'autorefresh')
+ else:
+ self.refreshperiod = None
+ self.hold = self.config.has_option(self.name, 'holdconnectionopen') \
+ and self.config.getboolean(self.name, 'holdconnectionopen')
+ if self.config.has_option(self.name, 'keepalive'):
+ self.keepalive = self.config.getint(self.name, 'keepalive')
+ else:
+ self.keepalive = None
+
+ def getconf(self, option, default = None):
+ if default != None:
+ return self.config.get(self.name, option)
+ else:
+ return self.config.getdefault(self.name, option,
+ default)
+
+ def sleeper(self):
+ """Sleep handler. Returns same value as UIBase.sleep:
+ 0 if timeout expired, 1 if there was a request to cancel the timer,
+ and 2 if there is a request to abort the program.
+
+ Also, returns 100 if configured to not sleep at all."""
+
+ if not self.refreshperiod:
+ return 100
+ refreshperiod = self.refreshperiod * 60
+ if self.keepalive:
+ kaevent = Event()
+ kathread = ExitNotifyThread(target = self.server.keepalive,
+ name = "Keep alive " + self.name,
+ args = (self.keepalive, kaevent))
+ kathread.setDaemon(1)
+ kathread.start()
+ sleepresult = self.ui.sleep(refreshperiod)
+ if sleepresult == 2:
+ # Cancel keep-alive, but don't bother terminating threads
+ if self.keepalive:
+ kaevent.set()
+ return sleepresult
+ else:
+ # Cancel keep-alive and wait for thread to terminate.
+ if self.keepalive:
+ kaevent.set()
+ kathread.join()
+ return sleepresult
+
+class AccountSynchronizationMixin:
+ def syncrunner(self):
+ self.ui.acct(self.name)
+ if not self.refreshperiod:
+ self.sync()
+ self.ui.acctdone(self.name)
+ return
+ looping = 1
+ while looping:
+ self.sync()
+ looping = self.sleeper() != 2
+ self.ui.acctdone(self.name)
+
+ def sync(self):
+ # We don't need an account lock because syncitall() goes through
+ # each account once, then waits for all to finish.
+ try:
+ accountmetadata = os.path.join(self.metadatadir, self.name)
+ if not os.path.exists(accountmetadata):
+ os.mkdir(accountmetadata, 0700)
+
+ remoterepos = repository.IMAP.IMAPRepository(self.config,
+ self.localeval,
+ self.name,
+ self.server)
+
+ # Connect to the Maildirs.
+ localrepos = repository.Maildir.MaildirRepository(os.path.expanduser(self.config.get(self.name, "localfolders")), self.name, self.config)
+
+ # Connect to the local cache.
+ statusrepos = repository.LocalStatus.LocalStatusRepository(accountmetadata)
+
+ self.ui.syncfolders(remoterepos, localrepos)
+ remoterepos.syncfoldersto(localrepos)
+
+ folderthreads = []
+ for remotefolder in remoterepos.getfolders():
+ thread = InstanceLimitedThread(\
+ instancename = 'FOLDER_' + self.name,
+ target = syncfolder,
+ name = "Folder sync %s[%s]" % \
+ (self.name, remotefolder.getvisiblename()),
+ args = (self.name, remoterepos, remotefolder, localrepos,
+ statusrepos))
+ thread.setDaemon(1)
+ thread.start()
+ folderthreads.append(thread)
+ threadutil.threadsreset(folderthreads)
+ if not self.hold:
+ server.close()
+ finally:
+ pass
+
+class SyncableAccount(Account, AccountSynchronizationMixin):
+ pass
+
+def syncfolder(accountname, remoterepos, remotefolder, localrepos,
+ statusrepos):
+ global mailboxes
+ ui = UIBase.getglobalui()
+ # Load local folder.
+ localfolder = localrepos.\
+ getfolder(remotefolder.getvisiblename().\
+ replace(remoterepos.getsep(), localrepos.getsep()))
+ # Write the mailboxes
+ mailboxes.append({'accountname': accountname,
+ 'foldername': localfolder.getvisiblename()})
+ # Load local folder
+ ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder)
+ ui.loadmessagelist(localrepos, localfolder)
+ localfolder.cachemessagelist()
+ ui.messagelistloaded(localrepos, localfolder, len(localfolder.getmessagelist().keys()))
+
+
+ # Load status folder.
+ statusfolder = statusrepos.getfolder(remotefolder.getvisiblename().\
+ replace(remoterepos.getsep(),
+ statusrepos.getsep()))
+ if localfolder.getuidvalidity() == None:
+ # This is a new folder, so delete the status cache to be sure
+ # we don't have a conflict.
+ statusfolder.deletemessagelist()
+
+ statusfolder.cachemessagelist()
+
+
+ # If either the local or the status folder has messages and
+ # there is a UID validity problem, warn and abort.
+ # If there are no messages, UW IMAPd loses UIDVALIDITY.
+ # But we don't really need it if both local folders are empty.
+ # So, in that case, save it off.
+ if (len(localfolder.getmessagelist()) or \
+ len(statusfolder.getmessagelist())) and \
+ not localfolder.isuidvalidityok(remotefolder):
+ ui.validityproblem(remotefolder)
+ return
+ else:
+ localfolder.saveuidvalidity(remotefolder.getuidvalidity())
+
+ # Load remote folder.
+ ui.loadmessagelist(remoterepos, remotefolder)
+ remotefolder.cachemessagelist()
+ ui.messagelistloaded(remoterepos, remotefolder,
+ len(remotefolder.getmessagelist().keys()))
+
+
+ #
+
+ if not statusfolder.isnewfolder():
+ # Delete local copies of remote messages. This way,
+ # if a message's flag is modified locally but it has been
+ # deleted remotely, we'll delete it locally. Otherwise, we
+ # try to modify a deleted message's flags! This step
+ # need only be taken if a statusfolder is present; otherwise,
+ # there is no action taken *to* the remote repository.
+
+ remotefolder.syncmessagesto_delete(localfolder, [localfolder,
+ statusfolder])
+ ui.syncingmessages(localrepos, localfolder, remoterepos, remotefolder)
+ localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder])
+
+ # Synchronize remote changes.
+ ui.syncingmessages(remoterepos, remotefolder, localrepos, localfolder)
+ remotefolder.syncmessagesto(localfolder)
+
+ # Make sure the status folder is up-to-date.
+ ui.syncingmessages(localrepos, localfolder, statusrepos, statusfolder)
+ localfolder.syncmessagesto(statusfolder)
+ statusfolder.save()
+
Modified: offlineimap/head/offlineimap/mbnames.py
==============================================================================
--- offlineimap/head/offlineimap/mbnames.py (original)
+++ offlineimap/head/offlineimap/mbnames.py Fri Jan 3 16:57:47 2003
@@ -19,9 +19,10 @@
import os.path
import re # for folderfilter
-def genmbnames(config, localeval, boxlist):
+def genmbnames(config, boxlist):
"""Takes a configparser object and a boxlist, which is a list of hashes
containing 'accountname' and 'foldername' keys."""
+ localeval = config.getlocaleval()
if not config.getboolean("mbnames", "enabled"):
return
file = open(os.path.expanduser(config.get("mbnames", "filename")), "wt")
Modified: offlineimap/head/offlineimap/ui/UIBase.py
==============================================================================
--- offlineimap/head/offlineimap/ui/UIBase.py (original)
+++ offlineimap/head/offlineimap/ui/UIBase.py Fri Jan 3 16:57:47 2003
@@ -140,6 +140,10 @@
if s.verbose >= 0:
s._msg("***** Processing account %s" % accountname)
+ def acctdone(s, accountname):
+ if s.verbose >= 0:
+ s._msg("***** Finished processing account " + accountname)
+
def syncfolders(s, srcrepos, destrepos):
if s.verbose >= 0:
s._msg("Copying folder structure from %s to %s" % \
Modified: offlineimap/head/offlineimap/ui/Noninteractive.py
==============================================================================
--- offlineimap/head/offlineimap/ui/Noninteractive.py (original)
+++ offlineimap/head/offlineimap/ui/Noninteractive.py Fri Jan 3 16:57:47 2003
@@ -20,7 +20,7 @@
from UIBase import UIBase
class Basic(UIBase):
- def getpass(s, accountname, config):
+ def getpass(s, accountname, config, errmsg = None):
raise NotImplementedError, "Prompting for a password is not supported in noninteractive mode."
def _msg(s, msg):
Modified: offlineimap/head/offlineimap/ui/detector.py
==============================================================================
--- offlineimap/head/offlineimap/ui/detector.py (original)
+++ offlineimap/head/offlineimap/ui/detector.py Fri Jan 3 16:57:47 2003
@@ -19,7 +19,7 @@
import offlineimap.ui
import sys
-def findUI(config, localeval, chosenUI=None):
+def findUI(config, chosenUI=None):
uistrlist = ['Tk.Blinkenlights', 'Tk.VerboseUI', 'TTY.TTYUI',
'Noninteractive.Basic', 'Noninteractive.Quiet']
namespace={}
@@ -34,7 +34,7 @@
uistrlist = config.get("general", "ui").replace(" ", "").split(",")
for uistr in uistrlist:
- uimod = getUImod(uistr, localeval, namespace)
+ uimod = getUImod(uistr, config.getlocaleval(), namespace)
if uimod:
uiinstance = uimod(config)
if uiinstance.isusable():