]>
code.delx.au - offlineimap/blob - offlineimap/repository/IMAP.py
1 # IMAP 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
, imapserver
21 from offlineimap
.folder
.UIDMaps
import MappedIMAPFolder
22 from offlineimap
.threadutil
import ExitNotifyThread
23 import re
, types
, os
, netrc
, errno
24 from threading
import *
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
)
32 self
.nametrans
= lambda foldername
: foldername
33 self
.folderfilter
= lambda foldername
: 1
34 self
.folderincludes
= []
36 localeval
= self
.localeval
37 if self
.config
.has_option(self
.getsection(), 'nametrans'):
38 self
.nametrans
= localeval
.eval(self
.getconf('nametrans'),
40 if self
.config
.has_option(self
.getsection(), 'folderfilter'):
41 self
.folderfilter
= localeval
.eval(self
.getconf('folderfilter'),
43 if self
.config
.has_option(self
.getsection(), 'folderincludes'):
44 self
.folderincludes
= localeval
.eval(self
.getconf('folderincludes'),
46 if self
.config
.has_option(self
.getsection(), 'foldersort'):
47 self
.foldersort
= localeval
.eval(self
.getconf('foldersort'),
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)
60 def stopkeepalive(self
, abrupt
= 0):
61 if not hasattr(self
, 'kaevent'):
62 # Keepalive is not active.
71 def holdordropconnections(self
):
72 if not self
.getholdconnectionopen():
73 self
.dropconnections()
75 def dropconnections(self
):
76 self
.imapserver
.close()
78 def getholdconnectionopen(self
):
79 return self
.getconfboolean("holdconnectionopen", 0)
81 def getkeepalive(self
):
82 return self
.getconfint("keepalive", 0)
85 return self
.imapserver
.delim
89 localeval
= self
.localeval
91 if self
.config
.has_option(self
.getsection(), 'remotehosteval'):
92 host
= self
.getconf('remotehosteval')
94 return localeval
.eval(host
)
96 host
= self
.getconf('remotehost')
102 localeval
= self
.localeval
104 if self
.config
.has_option(self
.getsection(), 'remoteusereval'):
105 user
= self
.getconf('remoteusereval')
107 return localeval
.eval(user
)
109 user
= self
.getconf('remoteuser')
113 netrcentry
= netrc
.netrc().authentificator(self
.gethost())
114 except IOError, inst
:
115 if inst
.errno
!= errno
.ENOENT
:
122 return self
.getconfint('remoteport', None)
125 return self
.getconfboolean('ssl', 0)
127 def getpreauthtunnel(self
):
128 return self
.getconf('preauthtunnel', None)
130 def getreference(self
):
131 return self
.getconf('reference', '""')
133 def getmaxconnections(self
):
134 return self
.getconfint('maxconnections', 1)
136 def getexpunge(self
):
137 return self
.getconfboolean('expunge', 1)
139 def getpassword(self
):
141 localeval
= self
.localeval
143 if self
.config
.has_option(self
.getsection(), 'remotepasseval'):
144 passwd
= self
.getconf('remotepasseval')
146 return localeval
.eval(passwd
)
148 password
= self
.getconf('remotepass', None)
151 passfile
= self
.getconf('remotepassfile', None)
153 fd
= open(os
.path
.expanduser(passfile
))
154 password
= fd
.readline().strip()
158 netrcentry
= netrc
.netrc().authenticators(self
.gethost())
159 except IOError, inst
:
160 if inst
.errno
!= errno
.ENOENT
:
164 user
= self
.getconf('remoteuser')
165 if user
== None or user
== netrcentry
[0]:
169 def getfolder(self
, foldername
):
170 return self
.getfoldertype()(self
.imapserver
, foldername
,
171 self
.nametrans(foldername
),
172 self
.accountname
, self
)
174 def getfoldertype(self
):
175 return folder
.IMAP
.IMAPFolder
177 def getfolders(self
):
178 if self
.folders
!= None:
181 imapobj
= self
.imapserver
.acquireconnection()
183 listresult
= imapobj
.list(directory
= self
.imapserver
.reference
)[1]
185 self
.imapserver
.releaseconnection(imapobj
)
186 for string
in listresult
:
187 if string
== None or \
188 (type(string
) == types
.StringType
and string
== ''):
189 # Bug in imaplib: empty strings in results from
192 flags
, delim
, name
= imaputil
.imapsplit(string
)
193 flaglist
= [x
.lower() for x
in imaputil
.flagsplit(flags
)]
194 if '\\noselect' in flaglist
:
196 foldername
= imaputil
.dequote(name
)
197 if not self
.folderfilter(foldername
):
199 retval
.append(self
.getfoldertype()(self
.imapserver
, foldername
,
200 self
.nametrans(foldername
),
201 self
.accountname
, self
))
202 if len(self
.folderincludes
):
203 imapobj
= self
.imapserver
.acquireconnection()
205 for foldername
in self
.folderincludes
:
207 imapobj
.select(foldername
, readonly
= 1)
210 retval
.append(self
.getfoldertype()(self
.imapserver
,
212 self
.nametrans(foldername
),
213 self
.accountname
, self
))
215 self
.imapserver
.releaseconnection(imapobj
)
217 retval
.sort(lambda x
, y
: self
.foldersort(x
.getvisiblename(), y
.getvisiblename()))
218 self
.folders
= retval
221 def makefolder(self
, foldername
):
222 #if self.getreference() != '""':
223 # newname = self.getreference() + self.getsep() + foldername
225 # newname = foldername
227 imapobj
= self
.imapserver
.acquireconnection()
229 result
= imapobj
.create(newname
)
230 if result
[0] != 'OK':
231 raise RuntimeError, "Repository %s could not create folder %s: %s" % (self
.getname(), foldername
, str(result
))
233 self
.imapserver
.releaseconnection(imapobj
)
235 class MappedIMAPRepository(IMAPRepository
):
236 def getfoldertype(self
):
237 return MappedIMAPFolder