]> code.delx.au - offlineimap/blob - offlineimap/repository/IMAP.py
f0e23e7a6b47574e9047b4528a9707e8a3d06335
[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, netrc
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 netrcentry = netrc.netrc().authentificator(self.gethost())
113 if netrcentry:
114 return netrcentry[0]
115
116 def getport(self):
117 return self.getconfint('remoteport', None)
118
119 def getssl(self):
120 return self.getconfboolean('ssl', 0)
121
122 def getpreauthtunnel(self):
123 return self.getconf('preauthtunnel', None)
124
125 def getreference(self):
126 return self.getconf('reference', '""')
127
128 def getmaxconnections(self):
129 return self.getconfint('maxconnections', 1)
130
131 def getexpunge(self):
132 return self.getconfboolean('expunge', 1)
133
134 def getpassword(self):
135 passwd = None
136 localeval = self.localeval
137
138 if self.config.has_option(self.getsection(), 'remotepasseval'):
139 passwd = self.getconf('remotepasseval')
140 if passwd != None:
141 return localeval.eval(passwd)
142
143 password = self.getconf('remotepass', None)
144 if password != None:
145 return password
146 passfile = self.getconf('remotepassfile', None)
147 if passfile != None:
148 fd = open(os.path.expanduser(passfile))
149 password = fd.readline().strip()
150 fd.close()
151 return password
152 netrcentry = netrc.netrc().authenticators(self.gethost())
153 if netrcentry:
154 user = self.getconf('remoteuser')
155 if user == None or user == netrcentry[0]:
156 return netrcentry[2]
157 return None
158
159 def getfolder(self, foldername):
160 return self.getfoldertype()(self.imapserver, foldername,
161 self.nametrans(foldername),
162 self.accountname, self)
163
164 def getfoldertype(self):
165 return folder.IMAP.IMAPFolder
166
167 def getfolders(self):
168 if self.folders != None:
169 return self.folders
170 retval = []
171 imapobj = self.imapserver.acquireconnection()
172 try:
173 listresult = imapobj.list(directory = self.imapserver.reference)[1]
174 finally:
175 self.imapserver.releaseconnection(imapobj)
176 for string in listresult:
177 if string == None or \
178 (type(string) == types.StringType and string == ''):
179 # Bug in imaplib: empty strings in results from
180 # literals.
181 continue
182 flags, delim, name = imaputil.imapsplit(string)
183 flaglist = [x.lower() for x in imaputil.flagsplit(flags)]
184 if '\\noselect' in flaglist:
185 continue
186 foldername = imaputil.dequote(name)
187 if not self.folderfilter(foldername):
188 continue
189 retval.append(self.getfoldertype()(self.imapserver, foldername,
190 self.nametrans(foldername),
191 self.accountname, self))
192 if len(self.folderincludes):
193 imapobj = self.imapserver.acquireconnection()
194 try:
195 for foldername in self.folderincludes:
196 try:
197 imapobj.select(foldername, readonly = 1)
198 except ValueError:
199 continue
200 retval.append(self.getfoldertype()(self.imapserver,
201 foldername,
202 self.nametrans(foldername),
203 self.accountname, self))
204 finally:
205 self.imapserver.releaseconnection(imapobj)
206
207 retval.sort(lambda x, y: self.foldersort(x.getvisiblename(), y.getvisiblename()))
208 self.folders = retval
209 return retval
210
211 def makefolder(self, foldername):
212 #if self.getreference() != '""':
213 # newname = self.getreference() + self.getsep() + foldername
214 #else:
215 # newname = foldername
216 newname = foldername
217 imapobj = self.imapserver.acquireconnection()
218 try:
219 result = imapobj.create(newname)
220 if result[0] != 'OK':
221 raise RuntimeError, "Repository %s could not create folder %s: %s" % (self.getname(), foldername, str(result))
222 finally:
223 self.imapserver.releaseconnection(imapobj)
224
225 class MappedIMAPRepository(IMAPRepository):
226 def getfoldertype(self):
227 return MappedIMAPFolder