]> code.delx.au - offlineimap/blob - offlineimap/repository/Base.py
ed07b572b87872e3749a9e3ee0eddae90d7cfde1
[offlineimap] / offlineimap / repository / Base.py
1 # Base repository support
2 # Copyright (C) 2002-2007 John Goerzen
3 # <jgoerzen@complete.org>
4 #
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.
9 #
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.
14 #
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
18
19 from offlineimap import CustomConfig
20 import os.path
21
22 def LoadRepository(name, account, reqtype):
23 from offlineimap.repository.Gmail import GmailRepository
24 from offlineimap.repository.IMAP import IMAPRepository, MappedIMAPRepository
25 from offlineimap.repository.Maildir import MaildirRepository
26 if reqtype == 'remote':
27 # For now, we don't support Maildirs on the remote side.
28 typemap = {'IMAP': IMAPRepository,
29 'Gmail': GmailRepository}
30 elif reqtype == 'local':
31 typemap = {'IMAP': MappedIMAPRepository,
32 'Maildir': MaildirRepository}
33 else:
34 raise ValueError, "Request type %s not supported" % reqtype
35 config = account.getconfig()
36 repostype = config.get('Repository ' + name, 'type').strip()
37 return typemap[repostype](name, account)
38
39 class BaseRepository(CustomConfig.ConfigHelperMixin):
40 def __init__(self, reposname, account):
41 self.account = account
42 self.config = account.getconfig()
43 self.name = reposname
44 self.localeval = account.getlocaleval()
45 self.accountname = self.account.getname()
46 self.uiddir = os.path.join(self.config.getmetadatadir(), 'Repository-' + self.name)
47 if not os.path.exists(self.uiddir):
48 os.mkdir(self.uiddir, 0700)
49 self.mapdir = os.path.join(self.uiddir, 'UIDMapping')
50 if not os.path.exists(self.mapdir):
51 os.mkdir(self.mapdir, 0700)
52 self.uiddir = os.path.join(self.uiddir, 'FolderValidity')
53 if not os.path.exists(self.uiddir):
54 os.mkdir(self.uiddir, 0700)
55
56 # The 'restoreatime' config parameter only applies to local Maildir
57 # mailboxes.
58 def restore_atime(self):
59 if self.config.get('Repository ' + self.name, 'type').strip() != \
60 'Maildir':
61 return
62
63 if not self.config.has_option('Repository ' + self.name, 'restoreatime') or not self.config.getboolean('Repository ' + self.name, 'restoreatime'):
64 return
65
66 return self.restore_folder_atimes()
67
68 def connect(self):
69 """Establish a connection to the remote, if necessary. This exists
70 so that IMAP connections can all be established up front, gathering
71 passwords as needed. It was added in order to support the
72 error recovery -- we need to connect first outside of the error
73 trap in order to validate the password, and that's the point of
74 this function."""
75 pass
76
77 def holdordropconnections(self):
78 pass
79
80 def dropconnections(self):
81 pass
82
83 def getaccount(self):
84 return self.account
85
86 def getname(self):
87 return self.name
88
89 def getuiddir(self):
90 return self.uiddir
91
92 def getmapdir(self):
93 return self.mapdir
94
95 def getaccountname(self):
96 return self.accountname
97
98 def getsection(self):
99 return 'Repository ' + self.name
100
101 def getconfig(self):
102 return self.config
103
104 def getlocaleval(self):
105 return self.account.getlocaleval()
106
107 def getfolders(self):
108 """Returns a list of ALL folders on this server."""
109 return []
110
111 def forgetfolders(self):
112 """Forgets the cached list of folders, if any. Useful to run
113 after a sync run."""
114 pass
115
116 def getsep(self):
117 raise NotImplementedError
118
119 def makefolder(self, foldername):
120 raise NotImplementedError
121
122 def deletefolder(self, foldername):
123 raise NotImplementedError
124
125 def getfolder(self, foldername):
126 raise NotImplementedError
127
128 def syncfoldersto(self, dest, copyfolders):
129 """Syncs the folders in this repository to those in dest.
130 It does NOT sync the contents of those folders.
131
132 For every time dest.makefolder() is called, also call makefolder()
133 on each folder in copyfolders."""
134 src = self
135 srcfolders = src.getfolders()
136 destfolders = dest.getfolders()
137
138 # Create hashes with the names, but convert the source folders
139 # to the dest folder's sep.
140
141 srchash = {}
142 for folder in srcfolders:
143 srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \
144 folder
145 desthash = {}
146 for folder in destfolders:
147 desthash[folder.getvisiblename()] = folder
148
149 #
150 # Find new folders.
151 #
152
153 for key in srchash.keys():
154 if not key in desthash:
155 dest.makefolder(key)
156 for copyfolder in copyfolders:
157 copyfolder.makefolder(key.replace(dest.getsep(), copyfolder.getsep()))
158
159 #
160 # Find deleted folders.
161 #
162 # We don't delete folders right now.
163
164 #for key in desthash.keys():
165 # if not key in srchash:
166 # dest.deletefolder(key)
167
168 ##### Keepalive
169
170 def startkeepalive(self):
171 """The default implementation will do nothing."""
172 pass
173
174 def stopkeepalive(self, abrupt = 0):
175 """Stop keep alive. If abrupt is 1, stop it but don't bother waiting
176 for the threads to terminate."""
177 pass
178