]>
code.delx.au - offlineimap/blob - offlineimap/repository/Maildir.py
1 # Maildir repository support
2 # Copyright (C) 2002 John Goerzen
3 # <jgoerzen@complete.org>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 from Base
import BaseRepository
20 from offlineimap
import folder
, imaputil
21 from offlineimap
. ui
import UIBase
22 from mailbox
import Maildir
26 class MaildirRepository ( BaseRepository
):
27 def __init__ ( self
, reposname
, account
):
28 """Initialize a MaildirRepository object. Takes a path name
29 to the directory holding all the Maildir directories."""
30 BaseRepository
.__ init
__ ( self
, reposname
, account
)
32 self
. root
= self
. getlocalroot ()
34 self
. ui
= UIBase
. getglobalui ()
35 self
. debug ( "MaildirRepository initialized, sep is " + repr ( self
. getsep ()))
36 self
. folder_atimes
= []
38 def _append_folder_atimes ( self
, foldername
):
39 p
= os
. path
. join ( self
. root
, foldername
)
40 new
= os
. path
. join ( p
, 'new' )
41 cur
= os
. path
. join ( p
, 'cur' )
42 f
= p
, os
. stat ( new
)[ ST_ATIME
], os
. stat ( cur
)[ ST_ATIME
]
43 self
. folder_atimes
. append ( f
)
45 def restore_folder_atimes ( self
):
46 if not self
. folder_atimes
:
49 for f
in self
. folder_atimes
:
50 t
= f
[ 1 ], os
. stat ( os
. path
. join ( f
[ 0 ], 'new' ))[ ST_MTIME
]
51 os
. utime ( os
. path
. join ( f
[ 0 ], 'new' ), t
)
52 t
= f
[ 2 ], os
. stat ( os
. path
. join ( f
[ 0 ], 'cur' ))[ ST_MTIME
]
53 os
. utime ( os
. path
. join ( f
[ 0 ], 'cur' ), t
)
55 def getlocalroot ( self
):
56 return os
. path
. expanduser ( self
. getconf ( 'localfolders' ))
59 self
. ui
. debug ( 'maildir' , msg
)
62 return self
. getconf ( 'sep' , '.' ). strip ()
64 def makefolder ( self
, foldername
):
65 self
. debug ( "makefolder called with arg " + repr ( foldername
))
66 # Do the chdir thing so the call to makedirs does not make the
67 # self.root directory (we'd prefer to raise an error in that case),
68 # but will make the (relative) paths underneath it. Need to use
69 # makedirs to support a / separator.
70 if self
. getsep () == '/' :
71 for invalid
in [ 'new' , 'cur' , 'tmp' , 'offlineimap.uidvalidity' ]:
72 for component
in foldername
. split ( '/' ):
73 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'."
75 assert foldername
. find ( './' ) == - 1 , "Folder names may not contain ../"
76 assert not foldername
. startswith ( '/' ), "Folder names may not begin with /"
81 # If we're using hierarchical folders, it's possible that sub-folders
82 # may be created before higher-up ones. If this is the case,
83 # makedirs will fail because the higher-up dir already exists.
84 # So, check to see if this is indeed the case.
86 if ( self
. getsep () == '/' or self
. getconfboolean ( 'existsok' , 0 )) \
87 and os
. path
. isdir ( foldername
):
88 self
. debug ( "makefolder: %s already is a directory" % foldername
)
89 # Already exists. Sanity-check that it's not a Maildir.
90 for subdir
in [ 'cur' , 'new' , 'tmp' ]:
91 assert not os
. path
. isdir ( os
. path
. join ( foldername
, subdir
)), \
92 "Tried to create folder %s but it already had dir %s " % \
95 self
. debug ( "makefolder: calling makedirs %s " % foldername
)
96 os
. makedirs ( foldername
, 0700 )
97 self
. debug ( "makefolder: creating cur, new, tmp" )
98 for subdir
in [ 'cur' , 'new' , 'tmp' ]:
99 os
. mkdir ( os
. path
. join ( foldername
, subdir
), 0700 )
100 # Invalidate the cache
104 def deletefolder ( self
, foldername
):
105 self
. ui
. warn ( "NOT YET IMPLEMENTED: DELETE FOLDER %s " % foldername
)
107 def getfolder ( self
, foldername
):
108 if self
. config
. has_option ( 'Repository ' + self
. name
, 'restoreatime' ) and self
. config
. getboolean ( 'Repository ' + self
. name
, 'restoreatime' ):
109 self
._ append
_ folder
_ atimes
( foldername
)
110 return folder
. Maildir
. MaildirFolder ( self
. root
, foldername
,
111 self
. getsep (), self
, self
. accountname
)
113 def _getfolders_scandir ( self
, root
, extension
= None ):
114 self
. debug ( "_GETFOLDERS_SCANDIR STARTING. root = %s , extension = %s " \
116 # extension willl only be non-None when called recursively when
117 # getsep() returns '/'.
120 # Configure the full path to this repository -- "toppath"
122 if extension
== None :
125 toppath
= os
. path
. join ( root
, extension
)
127 self
. debug ( " toppath = %s " % toppath
)
129 # Iterate over directories in top.
130 for dirname
in os
. listdir ( toppath
) + [ '.' ]:
131 self
. debug ( " *** top of loop" )
132 self
. debug ( " dirname = %s " % dirname
)
133 if dirname
in [ 'cur' , 'new' , 'tmp' , 'offlineimap.uidvalidity' ]:
134 self
. debug ( " skipping this dir (Maildir special)" )
135 # Bypass special files.
137 fullname
= os
. path
. join ( toppath
, dirname
)
138 self
. debug ( " fullname = %s " % fullname
)
139 if not os
. path
. isdir ( fullname
):
140 self
. debug ( " skipping this entry (not a directory)" )
141 # Not a directory -- not a folder.
144 if extension
!= None :
145 foldername
= os
. path
. join ( extension
, dirname
)
146 if ( os
. path
. isdir ( os
. path
. join ( fullname
, 'cur' )) and
147 os
. path
. isdir ( os
. path
. join ( fullname
, 'new' )) and
148 os
. path
. isdir ( os
. path
. join ( fullname
, 'tmp' ))):
149 # This directory has maildir stuff -- process
150 self
. debug ( " This is a maildir folder." )
152 self
. debug ( " foldername = %s " % foldername
)
154 if self
. config
. has_option ( 'Repository ' + self
. name
, 'restoreatime' ) and self
. config
. getboolean ( 'Repository ' + self
. name
, 'restoreatime' ):
155 self
._ append
_ folder
_ atimes
( foldername
)
156 retval
. append ( folder
. Maildir
. MaildirFolder ( self
. root
, foldername
,
157 self
. getsep (), self
, self
. accountname
))
158 if self
. getsep () == '/' and dirname
!= '.' :
159 # Check sub-directories for folders.
160 retval
. extend ( self
._ getfolders
_ scandir
( root
, foldername
))
161 self
. debug ( "_GETFOLDERS_SCANDIR RETURNING %s " % \
162 repr ([ x
. getname () for x
in retval
]))
165 def getfolders ( self
):
166 if self
. folders
== None :
167 self
. folders
= self
._ getfolders
_ scandir
( self
. root
)