]> code.delx.au - offlineimap/blob - offlineimap/repository/IMAP.py
944ca8f69dd64b9f8a7f8a9002ab12b570e81868
[offlineimap] / offlineimap / repository / IMAP.py
1 # IMAP repository support
2 # Copyright (C) 2002 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 Base import BaseRepository
20 from offlineimap import folder, imaputil, imapserver
21 from offlineimap.folder.UIDMaps import MappedIMAPFolder
22 from offlineimap.threadutil import ExitNotifyThread
23 import re, types, os
24 from threading import *
25
26 class IMAPRepository(BaseRepository):
27 def __init__(self, reposname, account):
28 """Initialize an IMAPRepository object."""
29 BaseRepository.__init__(self, reposname, account)
30 self.imapserver = imapserver.ConfigedIMAPServer(self)
31 self.folders = None
32 self.nametrans = lambda foldername: foldername
33 self.folderfilter = lambda foldername: 1
34 self.folderincludes = []
35 self.foldersort = cmp
36 localeval = self.localeval
37 if self.config.has_option(self.getsection(), 'nametrans'):
38 self.nametrans = localeval.eval(self.getconf('nametrans'),
39 {'re': re})
40 if self.config.has_option(self.getsection(), 'folderfilter'):
41 self.folderfilter = localeval.eval(self.getconf('folderfilter'),
42 {'re': re})
43 if self.config.has_option(self.getsection(), 'folderincludes'):
44 self.folderincludes = localeval.eval(self.getconf('folderincludes'),
45 {'re': re})
46 if self.config.has_option(self.getsection(), 'foldersort'):
47 self.foldersort = localeval.eval(self.getconf('foldersort'),
48 {'re': re})
49
50 def startkeepalive(self):
51 keepalivetime = self.getkeepalive()
52 if not keepalivetime: return
53 self.kaevent = Event()
54 self.kathread = ExitNotifyThread(target = self.imapserver.keepalive,
55 name = "Keep alive " + self.getname(),
56 args = (keepalivetime, self.kaevent))
57 self.kathread.setDaemon(1)
58 self.kathread.start()
59
60 def stopkeepalive(self, abrupt = 0):
61 if not hasattr(self, 'kaevent'):
62 # Keepalive is not active.
63 return
64
65 self.kaevent.set()
66 if not abrupt:
67 self.kathread.join()
68 del self.kathread
69 del self.kaevent
70
71 def holdordropconnections(self):
72 if not self.getholdconnectionopen():
73 self.dropconnections()
74
75 def dropconnections(self):
76 self.imapserver.close()
77
78 def getholdconnectionopen(self):
79 return self.getconfboolean("holdconnectionopen", 0)
80
81 def getkeepalive(self):
82 return self.getconfint("keepalive", 0)
83
84 def getsep(self):
85 return self.imapserver.delim
86
87 def gethost(self):
88 host = None
89 localeval = self.localeval
90
91 if self.config.has_option(self.getsection(), 'remotehosteval'):
92 host = self.getconf('remotehosteval')
93 if host != None:
94 return localeval.eval(host)
95
96 host = self.getconf('remotehost')
97 if host != None:
98 return host
99
100 def getuser(self):
101 user = None
102 localeval = self.localeval
103
104 if self.config.has_option(self.getsection(), 'remoteusereval'):
105 user = self.getconf('remoteusereval')
106 if user != None:
107 return localeval.eval(user)
108
109 user = self.getconf('remoteuser')
110 if user != None:
111 return user
112
113 def getport(self):
114 return self.getconfint('remoteport', None)
115
116 def getssl(self):
117 return self.getconfboolean('ssl', 0)
118
119 def getpreauthtunnel(self):
120 return self.getconf('preauthtunnel', None)
121
122 def getreference(self):
123 return self.getconf('reference', '""')
124
125 def getmaxconnections(self):
126 return self.getconfint('maxconnections', 1)
127
128 def getexpunge(self):
129 return self.getconfboolean('expunge', 1)
130
131 def getpassword(self):
132 passwd = None
133 localeval = self.localeval
134
135 if self.config.has_option(self.getsection(), 'remotepasseval'):
136 passwd = self.getconf('remotepasseval')
137 if passwd != None:
138 return localeval.eval(passwd)
139
140 password = self.getconf('remotepass', None)
141 if password != None:
142 return password
143 passfile = self.getconf('remotepassfile', None)
144 if passfile != None:
145 fd = open(os.path.expanduser(passfile))
146 password = fd.readline().strip()
147 fd.close()
148 return password
149 return None
150
151 def getfolder(self, foldername):
152 return self.getfoldertype()(self.imapserver, foldername,
153 self.nametrans(foldername),
154 self.accountname, self)
155
156 def getfoldertype(self):
157 return folder.IMAP.IMAPFolder
158
159 def getfolders(self):
160 if self.folders != None:
161 return self.folders
162 retval = []
163 imapobj = self.imapserver.acquireconnection()
164 try:
165 listresult = imapobj.list(directory = self.imapserver.reference)[1]
166 finally:
167 self.imapserver.releaseconnection(imapobj)
168 for string in listresult:
169 if string == None or \
170 (type(string) == types.StringType and string == ''):
171 # Bug in imaplib: empty strings in results from
172 # literals.
173 continue
174 flags, delim, name = imaputil.imapsplit(string)
175 flaglist = [x.lower() for x in imaputil.flagsplit(flags)]
176 if '\\noselect' in flaglist:
177 continue
178 foldername = imaputil.dequote(name)
179 if not self.folderfilter(foldername):
180 continue
181 retval.append(self.getfoldertype()(self.imapserver, foldername,
182 self.nametrans(foldername),
183 self.accountname, self))
184 if len(self.folderincludes):
185 imapobj = self.imapserver.acquireconnection()
186 try:
187 for foldername in self.folderincludes:
188 try:
189 imapobj.select(foldername, readonly = 1)
190 except ValueError:
191 continue
192 retval.append(self.getfoldertype()(self.imapserver,
193 foldername,
194 self.nametrans(foldername),
195 self.accountname, self))
196 finally:
197 self.imapserver.releaseconnection(imapobj)
198
199 retval.sort(lambda x, y: self.foldersort(x.getvisiblename(), y.getvisiblename()))
200 self.folders = retval
201 return retval
202
203 def makefolder(self, foldername):
204 #if self.getreference() != '""':
205 # newname = self.getreference() + self.getsep() + foldername
206 #else:
207 # newname = foldername
208 newname = foldername
209 imapobj = self.imapserver.acquireconnection()
210 try:
211 result = imapobj.create(newname)
212 if result[0] != 'OK':
213 raise RuntimeError, "Repository %s could not create folder %s: %s" % (self.getname(), foldername, str(result))
214 finally:
215 self.imapserver.releaseconnection(imapobj)
216
217 class MappedIMAPRepository(IMAPRepository):
218 def getfoldertype(self):
219 return MappedIMAPFolder