docker-offlineimap/offlineimap/repository/IMAP.py

306 lines
11 KiB
Python
Raw Normal View History

2002-06-19 06:39:00 +02:00
# IMAP repository support
# Copyright (C) 2002 John Goerzen
# <jgoerzen@complete.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
2002-06-19 06:39:00 +02:00
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
2006-08-12 06:15:55 +02:00
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2002-06-19 06:39:00 +02:00
from offlineimap.repository.Base import BaseRepository
from offlineimap import folder, imaputil, imapserver
from offlineimap.folder.UIDMaps import MappedIMAPFolder
from offlineimap.threadutil import ExitNotifyThread
2008-03-03 09:21:33 +01:00
import re, types, os, netrc, errno
from threading import *
2002-06-19 06:39:00 +02:00
class IMAPRepository(BaseRepository):
def __init__(self, reposname, account):
"""Initialize an IMAPRepository object."""
BaseRepository.__init__(self, reposname, account)
# self.ui is being set by the BaseRepository
self.imapserver = imapserver.ConfigedIMAPServer(self)
self.folders = None
2002-06-21 08:51:21 +02:00
self.nametrans = lambda foldername: foldername
self.folderfilter = lambda foldername: 1
self.folderincludes = []
self.foldersort = cmp
localeval = self.localeval
if self.config.has_option(self.getsection(), 'nametrans'):
self.nametrans = localeval.eval(self.getconf('nametrans'),
{'re': re})
if self.config.has_option(self.getsection(), 'folderfilter'):
self.folderfilter = localeval.eval(self.getconf('folderfilter'),
{'re': re})
if self.config.has_option(self.getsection(), 'folderincludes'):
self.folderincludes = localeval.eval(self.getconf('folderincludes'),
{'re': re})
if self.config.has_option(self.getsection(), 'foldersort'):
self.foldersort = localeval.eval(self.getconf('foldersort'),
{'re': re})
def startkeepalive(self):
keepalivetime = self.getkeepalive()
if not keepalivetime: return
self.kaevent = Event()
self.kathread = ExitNotifyThread(target = self.imapserver.keepalive,
name = "Keep alive " + self.getname(),
args = (keepalivetime, self.kaevent))
self.kathread.setDaemon(1)
self.kathread.start()
def stopkeepalive(self):
if not hasattr(self, 'kaevent'):
# Keepalive is not active.
return
self.kaevent.set()
del self.kathread
del self.kaevent
def holdordropconnections(self):
if not self.getholdconnectionopen():
self.dropconnections()
def dropconnections(self):
self.imapserver.close()
def getholdconnectionopen(self):
return self.getconfboolean("holdconnectionopen", 0)
def getkeepalive(self):
return self.getconfint("keepalive", 0)
2002-06-19 08:16:19 +02:00
def getsep(self):
return self.imapserver.delim
def gethost(self):
2007-07-04 23:00:14 +02:00
host = None
localeval = self.localeval
if self.config.has_option(self.getsection(), 'remotehosteval'):
2007-07-04 23:00:14 +02:00
host = self.getconf('remotehosteval')
if host != None:
return localeval.eval(host)
2007-07-04 23:00:14 +02:00
host = self.getconf('remotehost')
if host != None:
return host
def getuser(self):
2007-07-04 23:00:14 +02:00
user = None
localeval = self.localeval
if self.config.has_option(self.getsection(), 'remoteusereval'):
2007-07-04 23:00:14 +02:00
user = self.getconf('remoteusereval')
if user != None:
return localeval.eval(user)
2007-07-04 23:00:14 +02:00
user = self.getconf('remoteuser')
if user != None:
return user
2008-03-03 09:21:33 +01:00
try:
netrcentry = netrc.netrc().authenticators(self.gethost())
2008-03-03 09:21:33 +01:00
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
else:
if netrcentry:
return netrcentry[0]
try:
netrcentry = netrc.netrc('/etc/netrc').authenticators(self.gethost())
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
else:
if netrcentry:
return netrcentry[0]
def getport(self):
return self.getconfint('remoteport', None)
def getssl(self):
return self.getconfboolean('ssl', 0)
def getsslclientcert(self):
return self.getconf('sslclientcert', None)
def getsslclientkey(self):
return self.getconf('sslclientkey', None)
def getsslcacertfile(self):
"""Return the absolute path of the CA certfile to use, if any"""
cacertfile = self.getconf('sslcacertfile', None)
if cacertfile is None:
return None
cacertfile = os.path.expanduser(cacertfile)
cacertfile = os.path.abspath(cacertfile)
if not os.path.isfile(cacertfile):
raise SyntaxWarning("CA certfile for repository '%s' could "
"not be found. No such file: '%s'" \
% (self.name, cacertfile))
return cacertfile
def getpreauthtunnel(self):
return self.getconf('preauthtunnel', None)
def getreference(self):
return self.getconf('reference', '""')
def getmaxconnections(self):
return self.getconfint('maxconnections', 1)
def getexpunge(self):
return self.getconfboolean('expunge', 1)
def getpassword(self):
"""Return the IMAP password for this repository.
It tries to get passwords in the following order:
1. evaluate Repository 'remotepasseval'
2. read password from Repository 'remotepass'
3. read password from file specified in Repository 'remotepassfile'
4. read password from ~/.netrc
5. read password from /etc/netrc
On success we return the password.
If all strategies fail we return None.
"""
# 1. evaluate Repository 'remotepasseval'
passwd = self.getconf('remotepasseval', None)
if passwd != None:
return self.localeval.eval(passwd)
# 2. read password from Repository 'remotepass'
password = self.getconf('remotepass', None)
if password != None:
return password
# 3. read password from file specified in Repository 'remotepassfile'
passfile = self.getconf('remotepassfile', None)
if passfile != None:
fd = open(os.path.expanduser(passfile))
password = fd.readline().strip()
fd.close()
2007-07-04 23:00:14 +02:00
return password
# 4. read password from ~/.netrc
2008-03-03 09:21:33 +01:00
try:
netrcentry = netrc.netrc().authenticators(self.gethost())
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
else:
if netrcentry:
user = self.getconf('remoteuser')
if user == None or user == netrcentry[0]:
return netrcentry[2]
# 5. read password from /etc/netrc
try:
netrcentry = netrc.netrc('/etc/netrc').authenticators(self.gethost())
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
else:
if netrcentry:
user = self.getconf('remoteuser')
if user == None or user == netrcentry[0]:
return netrcentry[2]
# no strategy yielded a password!
return None
2002-06-20 04:55:24 +02:00
def getfolder(self, foldername):
return self.getfoldertype()(self.imapserver, foldername,
self.nametrans(foldername),
self.accountname, self)
def getfoldertype(self):
return folder.IMAP.IMAPFolder
2002-06-20 04:55:24 +02:00
2007-07-05 06:04:14 +02:00
def connect(self):
imapobj = self.imapserver.acquireconnection()
self.imapserver.releaseconnection(imapobj)
def forgetfolders(self):
self.folders = None
def getfolders(self):
if self.folders != None:
return self.folders
retval = []
imapobj = self.imapserver.acquireconnection()
# check whether to list all folders, or subscribed only
listfunction = imapobj.list
if self.config.has_option(self.getsection(), 'subscribedonly'):
if self.getconf('subscribedonly') == "yes":
listfunction = imapobj.lsub
try:
listresult = listfunction(directory = self.imapserver.reference)[1]
finally:
self.imapserver.releaseconnection(imapobj)
for string in listresult:
if string == None or \
(type(string) == types.StringType and string == ''):
# Bug in imaplib: empty strings in results from
# literals.
continue
flags, delim, name = imaputil.imapsplit(string)
flaglist = [x.lower() for x in imaputil.flagsplit(flags)]
if '\\noselect' in flaglist:
continue
foldername = imaputil.dequote(name)
if not self.folderfilter(foldername):
self.ui.debug('imap',"Filtering out '%s' due to folderfilter" %\
foldername)
continue
retval.append(self.getfoldertype()(self.imapserver, foldername,
self.nametrans(foldername),
self.accountname, self))
if len(self.folderincludes):
imapobj = self.imapserver.acquireconnection()
try:
for foldername in self.folderincludes:
try:
imapobj.select(foldername, readonly = 1)
except ValueError:
continue
retval.append(self.getfoldertype()(self.imapserver,
foldername,
self.nametrans(foldername),
self.accountname, self))
finally:
self.imapserver.releaseconnection(imapobj)
retval.sort(lambda x, y: self.foldersort(x.getvisiblename(), y.getvisiblename()))
self.folders = retval
return retval
def makefolder(self, foldername):
#if self.getreference() != '""':
# newname = self.getreference() + self.getsep() + foldername
#else:
# newname = foldername
newname = foldername
imapobj = self.imapserver.acquireconnection()
try:
result = imapobj.create(newname)
if result[0] != 'OK':
raise RuntimeError, "Repository %s could not create folder %s: %s" % (self.getname(), foldername, str(result))
finally:
self.imapserver.releaseconnection(imapobj)
class MappedIMAPRepository(IMAPRepository):
def getfoldertype(self):
return MappedIMAPFolder