2002-06-19 08:08:59 +02:00
# Maildir repository support
# Copyright (C) 2002 John Goerzen
# <jgoerzen@complete.org>
#
# 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
2003-04-16 21:23:45 +02:00
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2002-06-19 08:08:59 +02:00
#
# 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
2006-08-12 06:15:55 +02:00
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2002-06-19 08:08:59 +02:00
from Base import BaseRepository
2002-06-21 12:01:10 +02:00
from offlineimap import folder , imaputil
2002-10-07 22:59:02 +02:00
from offlineimap . ui import UIBase
2002-06-19 08:08:59 +02:00
from mailbox import Maildir
import os
New restoreatime patch from Ben Kibbey
From: Ben Kibbey
Subject: Re: Removed restoratime from OfflineIMAP
On Wed, May 03, 2006 at 10:08:35PM -0500, John Goerzen wrote:
> Hi Ben,
>
> Thanks for your restoreatime patch.
>
> However, I have received this bug report:
>
> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=365933
>
> After looking at the problem, here's what's going on.
>
> The person is using IMAP as the local repository as well.
>
> You really need to move the atime save and restore code from accounts.py
> into the repository/Maildir.py. Then, for any new call you add to the
> Maildir repository (that will be called from outside Maildir.py), you
> need to add a corresponding default function to repository/Base.py, and
> also make sure that on folders (such as IMAP) where atime restoration
> makes no sense, no error is generated.
>
> Let me know if that doesn't make sense to you. If you get it fixed, I'd
> be happy to re-apply it to a future version of OfflineIMAP.
>
> -- John Goerzen
>
Attached is a new diff that should work though not really tested
(v4.0.14). In repository/Base.py restore_atime() will call
self.restore_folder_atimes() only if the folder type is Maildir. Let me
know if it has any more problems.
2006-09-06 03:33:07 +02:00
from stat import *
2002-06-19 08:08:59 +02:00
class MaildirRepository ( BaseRepository ) :
2003-04-18 04:18:34 +02:00
def __init__ ( self , reposname , account ) :
2002-06-19 08:08:59 +02:00
""" Initialize a MaildirRepository object. Takes a path name
to the directory holding all the Maildir directories . """
2003-04-18 04:18:34 +02:00
BaseRepository . __init__ ( self , reposname , account )
2002-06-19 08:08:59 +02:00
2003-04-18 04:18:34 +02:00
self . root = self . getlocalroot ( )
2002-06-19 08:08:59 +02:00
self . folders = None
2002-10-07 22:59:02 +02:00
self . ui = UIBase . getglobalui ( )
2002-08-08 22:15:30 +02:00
self . debug ( " MaildirRepository initialized, sep is " + repr ( self . getsep ( ) ) )
New restoreatime patch from Ben Kibbey
From: Ben Kibbey
Subject: Re: Removed restoratime from OfflineIMAP
On Wed, May 03, 2006 at 10:08:35PM -0500, John Goerzen wrote:
> Hi Ben,
>
> Thanks for your restoreatime patch.
>
> However, I have received this bug report:
>
> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=365933
>
> After looking at the problem, here's what's going on.
>
> The person is using IMAP as the local repository as well.
>
> You really need to move the atime save and restore code from accounts.py
> into the repository/Maildir.py. Then, for any new call you add to the
> Maildir repository (that will be called from outside Maildir.py), you
> need to add a corresponding default function to repository/Base.py, and
> also make sure that on folders (such as IMAP) where atime restoration
> makes no sense, no error is generated.
>
> Let me know if that doesn't make sense to you. If you get it fixed, I'd
> be happy to re-apply it to a future version of OfflineIMAP.
>
> -- John Goerzen
>
Attached is a new diff that should work though not really tested
(v4.0.14). In repository/Base.py restore_atime() will call
self.restore_folder_atimes() only if the folder type is Maildir. Let me
know if it has any more problems.
2006-09-06 03:33:07 +02:00
self . folder_atimes = [ ]
2008-03-27 22:19:35 +01:00
# Create the top-level folder if it doesn't exist
if not os . path . isdir ( self . root ) :
os . mkdir ( self . root , 0700 )
New restoreatime patch from Ben Kibbey
From: Ben Kibbey
Subject: Re: Removed restoratime from OfflineIMAP
On Wed, May 03, 2006 at 10:08:35PM -0500, John Goerzen wrote:
> Hi Ben,
>
> Thanks for your restoreatime patch.
>
> However, I have received this bug report:
>
> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=365933
>
> After looking at the problem, here's what's going on.
>
> The person is using IMAP as the local repository as well.
>
> You really need to move the atime save and restore code from accounts.py
> into the repository/Maildir.py. Then, for any new call you add to the
> Maildir repository (that will be called from outside Maildir.py), you
> need to add a corresponding default function to repository/Base.py, and
> also make sure that on folders (such as IMAP) where atime restoration
> makes no sense, no error is generated.
>
> Let me know if that doesn't make sense to you. If you get it fixed, I'd
> be happy to re-apply it to a future version of OfflineIMAP.
>
> -- John Goerzen
>
Attached is a new diff that should work though not really tested
(v4.0.14). In repository/Base.py restore_atime() will call
self.restore_folder_atimes() only if the folder type is Maildir. Let me
know if it has any more problems.
2006-09-06 03:33:07 +02:00
def _append_folder_atimes ( self , foldername ) :
p = os . path . join ( self . root , foldername )
new = os . path . join ( p , ' new ' )
cur = os . path . join ( p , ' cur ' )
f = p , os . stat ( new ) [ ST_ATIME ] , os . stat ( cur ) [ ST_ATIME ]
self . folder_atimes . append ( f )
def restore_folder_atimes ( self ) :
if not self . folder_atimes :
return
for f in self . folder_atimes :
t = f [ 1 ] , os . stat ( os . path . join ( f [ 0 ] , ' new ' ) ) [ ST_MTIME ]
os . utime ( os . path . join ( f [ 0 ] , ' new ' ) , t )
t = f [ 2 ] , os . stat ( os . path . join ( f [ 0 ] , ' cur ' ) ) [ ST_MTIME ]
os . utime ( os . path . join ( f [ 0 ] , ' cur ' ) , t )
2002-08-08 22:15:30 +02:00
2003-04-18 04:18:34 +02:00
def getlocalroot ( self ) :
return os . path . expanduser ( self . getconf ( ' localfolders ' ) )
2002-08-08 22:15:30 +02:00
def debug ( self , msg ) :
self . ui . debug ( ' maildir ' , msg )
2002-06-19 08:08:59 +02:00
2002-06-19 08:16:19 +02:00
def getsep ( self ) :
2003-04-18 04:18:34 +02:00
return self . getconf ( ' sep ' , ' . ' ) . strip ( )
2002-06-20 04:55:24 +02:00
def makefolder ( self , foldername ) :
2002-08-08 22:15:30 +02:00
self . debug ( " makefolder called with arg " + repr ( foldername ) )
2002-08-08 04:40:18 +02:00
# Do the chdir thing so the call to makedirs does not make the
# self.root directory (we'd prefer to raise an error in that case),
# but will make the (relative) paths underneath it. Need to use
# makedirs to support a / separator.
2008-08-02 21:37:55 +02:00
self . debug ( " Is dir? " + repr ( os . path . isdir ( foldername ) ) )
2002-08-08 04:41:52 +02:00
if self . getsep ( ) == ' / ' :
2002-08-08 04:40:18 +02:00
for invalid in [ ' new ' , ' cur ' , ' tmp ' , ' offlineimap.uidvalidity ' ] :
for component in foldername . split ( ' / ' ) :
assert component != invalid , " When using nested folders (/ as a separator in the account config), your folder names may not contain ' new ' , ' cur ' , ' tmp ' , or ' offlineimap.uidvalidity ' . "
2002-08-08 04:44:37 +02:00
2002-08-08 04:45:03 +02:00
assert foldername . find ( ' ./ ' ) == - 1 , " Folder names may not contain ../ "
2002-08-08 04:44:37 +02:00
assert not foldername . startswith ( ' / ' ) , " Folder names may not begin with / "
2002-08-08 05:01:31 +02:00
2002-08-08 04:40:18 +02:00
oldcwd = os . getcwd ( )
os . chdir ( self . root )
2002-08-08 05:01:31 +02:00
# If we're using hierarchical folders, it's possible that sub-folders
# may be created before higher-up ones. If this is the case,
# makedirs will fail because the higher-up dir already exists.
# So, check to see if this is indeed the case.
2008-08-02 21:34:51 +02:00
if ( self . getsep ( ) == ' / ' or self . getconfboolean ( ' existsok ' , 0 ) or foldername == ' . ' ) \
2003-04-18 04:18:34 +02:00
and os . path . isdir ( foldername ) :
2002-08-08 22:15:30 +02:00
self . debug ( " makefolder: %s already is a directory " % foldername )
2002-08-08 05:01:31 +02:00
# Already exists. Sanity-check that it's not a Maildir.
for subdir in [ ' cur ' , ' new ' , ' tmp ' ] :
assert not os . path . isdir ( os . path . join ( foldername , subdir ) ) , \
" Tried to create folder %s but it already had dir %s " % \
( foldername , subdir )
else :
2002-08-08 22:15:30 +02:00
self . debug ( " makefolder: calling makedirs %s " % foldername )
2002-08-08 05:01:31 +02:00
os . makedirs ( foldername , 0700 )
2002-08-08 22:15:30 +02:00
self . debug ( " makefolder: creating cur, new, tmp " )
2002-06-20 04:55:24 +02:00
for subdir in [ ' cur ' , ' new ' , ' tmp ' ] :
2002-08-08 04:44:37 +02:00
os . mkdir ( os . path . join ( foldername , subdir ) , 0700 )
2002-06-21 04:20:42 +02:00
# Invalidate the cache
self . folders = None
2002-08-08 04:40:18 +02:00
os . chdir ( oldcwd )
2002-06-20 04:55:24 +02:00
def deletefolder ( self , foldername ) :
2002-08-08 22:15:30 +02:00
self . ui . warn ( " NOT YET IMPLEMENTED: DELETE FOLDER %s " % foldername )
2002-06-20 04:55:24 +02:00
def getfolder ( self , foldername ) :
New restoreatime patch from Ben Kibbey
From: Ben Kibbey
Subject: Re: Removed restoratime from OfflineIMAP
On Wed, May 03, 2006 at 10:08:35PM -0500, John Goerzen wrote:
> Hi Ben,
>
> Thanks for your restoreatime patch.
>
> However, I have received this bug report:
>
> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=365933
>
> After looking at the problem, here's what's going on.
>
> The person is using IMAP as the local repository as well.
>
> You really need to move the atime save and restore code from accounts.py
> into the repository/Maildir.py. Then, for any new call you add to the
> Maildir repository (that will be called from outside Maildir.py), you
> need to add a corresponding default function to repository/Base.py, and
> also make sure that on folders (such as IMAP) where atime restoration
> makes no sense, no error is generated.
>
> Let me know if that doesn't make sense to you. If you get it fixed, I'd
> be happy to re-apply it to a future version of OfflineIMAP.
>
> -- John Goerzen
>
Attached is a new diff that should work though not really tested
(v4.0.14). In repository/Base.py restore_atime() will call
self.restore_folder_atimes() only if the folder type is Maildir. Let me
know if it has any more problems.
2006-09-06 03:33:07 +02:00
if self . config . has_option ( ' Repository ' + self . name , ' restoreatime ' ) and self . config . getboolean ( ' Repository ' + self . name , ' restoreatime ' ) :
self . _append_folder_atimes ( foldername )
2002-08-08 04:40:18 +02:00
return folder . Maildir . MaildirFolder ( self . root , foldername ,
2003-01-06 00:07:58 +01:00
self . getsep ( ) , self , self . accountname )
2002-06-20 04:55:24 +02:00
2002-08-08 04:57:52 +02:00
def _getfolders_scandir ( self , root , extension = None ) :
2002-08-08 22:15:30 +02:00
self . debug ( " _GETFOLDERS_SCANDIR STARTING. root = %s , extension = %s " \
% ( root , extension ) )
2002-08-08 04:57:52 +02:00
# extension willl only be non-None when called recursively when
# getsep() returns '/'.
2002-06-19 08:08:59 +02:00
retval = [ ]
2002-08-08 04:57:52 +02:00
# Configure the full path to this repository -- "toppath"
if extension == None :
toppath = root
else :
toppath = os . path . join ( root , extension )
2002-08-08 22:15:30 +02:00
self . debug ( " toppath = %s " % toppath )
2002-08-08 04:57:52 +02:00
# Iterate over directories in top.
2003-04-18 09:14:45 +02:00
for dirname in os . listdir ( toppath ) + [ ' . ' ] :
2002-08-08 22:15:30 +02:00
self . debug ( " *** top of loop " )
self . debug ( " dirname = %s " % dirname )
2002-08-08 04:57:52 +02:00
if dirname in [ ' cur ' , ' new ' , ' tmp ' , ' offlineimap.uidvalidity ' ] :
2002-08-08 22:15:30 +02:00
self . debug ( " skipping this dir (Maildir special) " )
2002-08-08 04:57:52 +02:00
# Bypass special files.
continue
fullname = os . path . join ( toppath , dirname )
2002-08-08 22:15:30 +02:00
self . debug ( " fullname = %s " % fullname )
2002-06-19 08:08:59 +02:00
if not os . path . isdir ( fullname ) :
2002-08-08 22:15:30 +02:00
self . debug ( " skipping this entry (not a directory) " )
2002-08-08 04:57:52 +02:00
# Not a directory -- not a folder.
2002-06-19 08:08:59 +02:00
continue
2002-08-09 03:53:57 +02:00
foldername = dirname
if extension != None :
foldername = os . path . join ( extension , dirname )
2002-08-09 03:53:05 +02:00
if ( os . path . isdir ( os . path . join ( fullname , ' cur ' ) ) and
os . path . isdir ( os . path . join ( fullname , ' new ' ) ) and
os . path . isdir ( os . path . join ( fullname , ' tmp ' ) ) ) :
# This directory has maildir stuff -- process
self . debug ( " This is a maildir folder. " )
self . debug ( " foldername = %s " % foldername )
New restoreatime patch from Ben Kibbey
From: Ben Kibbey
Subject: Re: Removed restoratime from OfflineIMAP
On Wed, May 03, 2006 at 10:08:35PM -0500, John Goerzen wrote:
> Hi Ben,
>
> Thanks for your restoreatime patch.
>
> However, I have received this bug report:
>
> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=365933
>
> After looking at the problem, here's what's going on.
>
> The person is using IMAP as the local repository as well.
>
> You really need to move the atime save and restore code from accounts.py
> into the repository/Maildir.py. Then, for any new call you add to the
> Maildir repository (that will be called from outside Maildir.py), you
> need to add a corresponding default function to repository/Base.py, and
> also make sure that on folders (such as IMAP) where atime restoration
> makes no sense, no error is generated.
>
> Let me know if that doesn't make sense to you. If you get it fixed, I'd
> be happy to re-apply it to a future version of OfflineIMAP.
>
> -- John Goerzen
>
Attached is a new diff that should work though not really tested
(v4.0.14). In repository/Base.py restore_atime() will call
self.restore_folder_atimes() only if the folder type is Maildir. Let me
know if it has any more problems.
2006-09-06 03:33:07 +02:00
if self . config . has_option ( ' Repository ' + self . name , ' restoreatime ' ) and self . config . getboolean ( ' Repository ' + self . name , ' restoreatime ' ) :
self . _append_folder_atimes ( foldername )
2002-08-09 03:53:05 +02:00
retval . append ( folder . Maildir . MaildirFolder ( self . root , foldername ,
2003-01-06 00:07:58 +01:00
self . getsep ( ) , self , self . accountname ) )
2003-04-29 23:30:26 +02:00
if self . getsep ( ) == ' / ' and dirname != ' . ' :
2002-08-08 04:57:52 +02:00
# Check sub-directories for folders.
2002-08-08 05:27:55 +02:00
retval . extend ( self . _getfolders_scandir ( root , foldername ) )
2002-08-08 22:18:45 +02:00
self . debug ( " _GETFOLDERS_SCANDIR RETURNING %s " % \
repr ( [ x . getname ( ) for x in retval ] ) )
2002-06-19 08:08:59 +02:00
return retval
2002-08-08 04:57:52 +02:00
def getfolders ( self ) :
if self . folders == None :
self . folders = self . _getfolders_scandir ( self . root )
return self . folders