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
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
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 ( ) ) )
2006-03-02 00:12:29 +01:00
def getrestoreatime ( self ) :
return self . getconfboolean ( ' restoreatime ' , 0 )
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.
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.
2003-04-18 04:18:34 +02:00
if ( self . getsep ( ) == ' / ' or self . getconfboolean ( ' existsok ' , 0 ) ) \
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 ) :
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 )
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