Refactoring: make functions to be private if we can
Make external API of class/module to be smaller, explicitely mark all internal functions. Also annotate methods that are implemented as the part of the parent class interface. Signed-off-by: Eygene Ryabinkin <rea@codelabs.ru>
This commit is contained in:
@ -96,6 +96,22 @@ class BaseFolder(object):
|
||||
false otherwise. Probably only IMAP will return true."""
|
||||
return 0
|
||||
|
||||
def waitforthread(self):
|
||||
"""Implements method that waits for thread to be usable.
|
||||
Should be implemented only for folders that suggest threads."""
|
||||
raise NotImplementedException
|
||||
|
||||
# XXX: we may need someting like supports_quickstatus() to check
|
||||
# XXX: if user specifies 'quick' flag for folder that doesn't
|
||||
# XXX: support quick status queries, so one believes that quick
|
||||
# XXX: status checks will be done, but it won't really be so.
|
||||
def quickchanged(self, statusfolder):
|
||||
""" Runs quick check for folder changes and returns changed
|
||||
status: True -- changed, False -- not changed.
|
||||
:param statusfolder: keeps track of the last known folder state.
|
||||
"""
|
||||
return True
|
||||
|
||||
def getcopyinstancelimit(self):
|
||||
"""For threading folders, returns the instancelimitname for
|
||||
InstanceLimitedThreads."""
|
||||
@ -328,7 +344,7 @@ class BaseFolder(object):
|
||||
for uid in uidlist:
|
||||
self.deletemessage(uid)
|
||||
|
||||
def copymessageto(self, uid, dstfolder, statusfolder, register = 1):
|
||||
def __copymessageto(self, uid, dstfolder, statusfolder, register = 1):
|
||||
"""Copies a message from self to dst if needed, updating the status
|
||||
|
||||
Note that this function does not check against dryrun settings,
|
||||
@ -403,14 +419,14 @@ class BaseFolder(object):
|
||||
(uid, self.accountname))
|
||||
raise #raise on unknown errors, so we can fix those
|
||||
|
||||
def syncmessagesto_copy(self, dstfolder, statusfolder):
|
||||
def __syncmessagesto_copy(self, dstfolder, statusfolder):
|
||||
"""Pass1: Copy locally existing messages not on the other side
|
||||
|
||||
This will copy messages to dstfolder that exist locally but are
|
||||
not in the statusfolder yet. The strategy is:
|
||||
|
||||
1) Look for messages present in self but not in statusfolder.
|
||||
2) invoke copymessageto() on those which:
|
||||
2) invoke __copymessageto() on those which:
|
||||
- If dstfolder doesn't have it yet, add them to dstfolder.
|
||||
- Update statusfolder
|
||||
|
||||
@ -431,23 +447,23 @@ class BaseFolder(object):
|
||||
if offlineimap.accounts.Account.abort_NOW_signal.is_set():
|
||||
break
|
||||
self.ui.copyingmessage(uid, num+1, num_to_copy, self, dstfolder)
|
||||
# exceptions are caught in copymessageto()
|
||||
# exceptions are caught in __copymessageto()
|
||||
if self.suggeststhreads() and not globals.options.singlethreading:
|
||||
self.waitforthread()
|
||||
thread = threadutil.InstanceLimitedThread(\
|
||||
self.getcopyinstancelimit(),
|
||||
target = self.copymessageto,
|
||||
target = self.__copymessageto,
|
||||
name = "Copy message from %s:%s" % (self.repository, self),
|
||||
args = (uid, dstfolder, statusfolder))
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
else:
|
||||
self.copymessageto(uid, dstfolder, statusfolder,
|
||||
self.__copymessageto(uid, dstfolder, statusfolder,
|
||||
register = 0)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
def syncmessagesto_delete(self, dstfolder, statusfolder):
|
||||
def __syncmessagesto_delete(self, dstfolder, statusfolder):
|
||||
"""Pass 2: Remove locally deleted messages on dst
|
||||
|
||||
Get all UIDS in statusfolder but not self. These are messages
|
||||
@ -468,7 +484,7 @@ class BaseFolder(object):
|
||||
for folder in [statusfolder, dstfolder]:
|
||||
folder.deletemessages(deletelist)
|
||||
|
||||
def syncmessagesto_flags(self, dstfolder, statusfolder):
|
||||
def __syncmessagesto_flags(self, dstfolder, statusfolder):
|
||||
"""Pass 3: Flag synchronization
|
||||
|
||||
Compare flag mismatches in self with those in statusfolder. If
|
||||
@ -551,9 +567,9 @@ class BaseFolder(object):
|
||||
:param dstfolder: Folderinstance to sync the msgs to.
|
||||
:param statusfolder: LocalStatus instance to sync against.
|
||||
"""
|
||||
passes = [('copying messages' , self.syncmessagesto_copy),
|
||||
('deleting messages' , self.syncmessagesto_delete),
|
||||
('syncing flags' , self.syncmessagesto_flags)]
|
||||
passes = [('copying messages' , self.__syncmessagesto_copy),
|
||||
('deleting messages' , self.__syncmessagesto_delete),
|
||||
('syncing flags' , self.__syncmessagesto_flags)]
|
||||
|
||||
for (passdesc, action) in passes:
|
||||
# bail out on CTRL-C or SIGTERM
|
||||
|
@ -38,7 +38,7 @@ class IMAPFolder(BaseFolder):
|
||||
self.randomgenerator = random.Random()
|
||||
#self.ui is set in BaseFolder
|
||||
|
||||
def selectro(self, imapobj, force = False):
|
||||
def __selectro(self, imapobj, force = False):
|
||||
"""Select this folder when we do not need write access.
|
||||
|
||||
Prefer SELECT to EXAMINE if we can, since some servers
|
||||
@ -52,15 +52,19 @@ class IMAPFolder(BaseFolder):
|
||||
except imapobj.readonly:
|
||||
imapobj.select(self.getfullname(), readonly = True, force = force)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def suggeststhreads(self):
|
||||
return not globals.options.singlethreading
|
||||
|
||||
# Interface from BaseFolder
|
||||
def waitforthread(self):
|
||||
self.imapserver.connectionwait()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getcopyinstancelimit(self):
|
||||
return 'MSGCOPY_' + self.repository.getname()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def get_uidvalidity(self):
|
||||
"""Retrieve the current connections UIDVALIDITY value
|
||||
|
||||
@ -72,7 +76,7 @@ class IMAPFolder(BaseFolder):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
# SELECT (if not already done) and get current UIDVALIDITY
|
||||
self.selectro(imapobj)
|
||||
self.__selectro(imapobj)
|
||||
typ, uidval = imapobj.response('UIDVALIDITY')
|
||||
assert uidval != [None] and uidval != None, \
|
||||
"response('UIDVALIDITY') returned [None]!"
|
||||
@ -81,6 +85,7 @@ class IMAPFolder(BaseFolder):
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def quickchanged(self, statusfolder):
|
||||
# An IMAP folder has definitely changed if the number of
|
||||
# messages or the UID of the last message have changed. Otherwise
|
||||
@ -118,6 +123,7 @@ class IMAPFolder(BaseFolder):
|
||||
return True
|
||||
return False
|
||||
|
||||
# Interface from BaseFolder
|
||||
def cachemessagelist(self):
|
||||
maxage = self.config.getdefaultint("Account %s" % self.accountname,
|
||||
"maxage", -1)
|
||||
@ -199,9 +205,11 @@ class IMAPFolder(BaseFolder):
|
||||
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessage(self, uid):
|
||||
"""Retrieve message with UID from the IMAP server (incl body)
|
||||
|
||||
@ -253,13 +261,15 @@ class IMAPFolder(BaseFolder):
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
return data
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagetime(self, uid):
|
||||
return self.messagelist[uid]['time']
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessageflags(self, uid):
|
||||
return self.messagelist[uid]['flags']
|
||||
|
||||
def generate_randomheader(self, content):
|
||||
def __generate_randomheader(self, content):
|
||||
"""Returns a unique X-OfflineIMAP header
|
||||
|
||||
Generate an 'X-OfflineIMAP' mail header which contains a random
|
||||
@ -286,28 +296,28 @@ class IMAPFolder(BaseFolder):
|
||||
return (headername, headervalue)
|
||||
|
||||
|
||||
def savemessage_addheader(self, content, headername, headervalue):
|
||||
def __savemessage_addheader(self, content, headername, headervalue):
|
||||
self.ui.debug('imap',
|
||||
'savemessage_addheader: called to add %s: %s' % (headername,
|
||||
'__savemessage_addheader: called to add %s: %s' % (headername,
|
||||
headervalue))
|
||||
insertionpoint = content.find("\r\n\r\n")
|
||||
self.ui.debug('imap', 'savemessage_addheader: insertionpoint = %d' % insertionpoint)
|
||||
self.ui.debug('imap', '__savemessage_addheader: insertionpoint = %d' % insertionpoint)
|
||||
leader = content[0:insertionpoint]
|
||||
self.ui.debug('imap', 'savemessage_addheader: leader = %s' % repr(leader))
|
||||
self.ui.debug('imap', '__savemessage_addheader: leader = %s' % repr(leader))
|
||||
if insertionpoint == 0 or insertionpoint == -1:
|
||||
newline = ''
|
||||
insertionpoint = 0
|
||||
else:
|
||||
newline = "\r\n"
|
||||
newline += "%s: %s" % (headername, headervalue)
|
||||
self.ui.debug('imap', 'savemessage_addheader: newline = ' + repr(newline))
|
||||
self.ui.debug('imap', '__savemessage_addheader: newline = ' + repr(newline))
|
||||
trailer = content[insertionpoint:]
|
||||
self.ui.debug('imap', 'savemessage_addheader: trailer = ' + repr(trailer))
|
||||
self.ui.debug('imap', '__savemessage_addheader: trailer = ' + repr(trailer))
|
||||
return leader + newline + trailer
|
||||
|
||||
|
||||
def savemessage_searchforheader(self, imapobj, headername, headervalue):
|
||||
self.ui.debug('imap', 'savemessage_searchforheader called for %s: %s' % \
|
||||
def __savemessage_searchforheader(self, imapobj, headername, headervalue):
|
||||
self.ui.debug('imap', '__savemessage_searchforheader called for %s: %s' % \
|
||||
(headername, headervalue))
|
||||
# Now find the UID it got.
|
||||
headervalue = imapobj._quote(headervalue)
|
||||
@ -315,16 +325,16 @@ class IMAPFolder(BaseFolder):
|
||||
matchinguids = imapobj.uid('search', 'HEADER', headername, headervalue)[1][0]
|
||||
except imapobj.error as err:
|
||||
# IMAP server doesn't implement search or had a problem.
|
||||
self.ui.debug('imap', "savemessage_searchforheader: got IMAP error '%s' while attempting to UID SEARCH for message with header %s" % (err, headername))
|
||||
self.ui.debug('imap', "__savemessage_searchforheader: got IMAP error '%s' while attempting to UID SEARCH for message with header %s" % (err, headername))
|
||||
return 0
|
||||
self.ui.debug('imap', 'savemessage_searchforheader got initial matchinguids: ' + repr(matchinguids))
|
||||
self.ui.debug('imap', '__savemessage_searchforheader got initial matchinguids: ' + repr(matchinguids))
|
||||
|
||||
if matchinguids == '':
|
||||
self.ui.debug('imap', "savemessage_searchforheader: UID SEARCH for message with header %s yielded no results" % headername)
|
||||
self.ui.debug('imap', "__savemessage_searchforheader: UID SEARCH for message with header %s yielded no results" % headername)
|
||||
return 0
|
||||
|
||||
matchinguids = matchinguids.split(' ')
|
||||
self.ui.debug('imap', 'savemessage_searchforheader: matchinguids now ' + \
|
||||
self.ui.debug('imap', '__savemessage_searchforheader: matchinguids now ' + \
|
||||
repr(matchinguids))
|
||||
if len(matchinguids) != 1 or matchinguids[0] == None:
|
||||
raise ValueError("While attempting to find UID for message with "
|
||||
@ -332,7 +342,7 @@ class IMAPFolder(BaseFolder):
|
||||
(headername, str(matchinguids)))
|
||||
return long(matchinguids[0])
|
||||
|
||||
def savemessage_fetchheaders(self, imapobj, headername, headervalue):
|
||||
def __savemessage_fetchheaders(self, imapobj, headername, headervalue):
|
||||
""" We fetch all new mail headers and search for the right
|
||||
X-OfflineImap line by hand. The response from the server has form:
|
||||
(
|
||||
@ -355,7 +365,7 @@ class IMAPFolder(BaseFolder):
|
||||
|
||||
Returns UID when found, 0 when not found.
|
||||
"""
|
||||
self.ui.debug('imap', 'savemessage_fetchheaders called for %s: %s' % \
|
||||
self.ui.debug('imap', '__savemessage_fetchheaders called for %s: %s' % \
|
||||
(headername, headervalue))
|
||||
|
||||
# run "fetch X:* rfc822.header"
|
||||
@ -401,7 +411,7 @@ class IMAPFolder(BaseFolder):
|
||||
|
||||
return 0
|
||||
|
||||
def getmessageinternaldate(self, content, rtime=None):
|
||||
def __getmessageinternaldate(self, content, rtime=None):
|
||||
"""Parses mail and returns an INTERNALDATE string
|
||||
|
||||
It will use information in the following order, falling back as an attempt fails:
|
||||
@ -474,6 +484,7 @@ class IMAPFolder(BaseFolder):
|
||||
|
||||
return internaldate
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessage(self, uid, content, flags, rtime):
|
||||
"""Save the message on the Server
|
||||
|
||||
@ -511,16 +522,16 @@ class IMAPFolder(BaseFolder):
|
||||
use_uidplus = 'UIDPLUS' in imapobj.capabilities
|
||||
|
||||
# get the date of the message, so we can pass it to the server.
|
||||
date = self.getmessageinternaldate(content, rtime)
|
||||
date = self.__getmessageinternaldate(content, rtime)
|
||||
content = re.sub("(?<!\r)\n", "\r\n", content)
|
||||
|
||||
if not use_uidplus:
|
||||
# insert a random unique header that we can fetch later
|
||||
(headername, headervalue) = self.generate_randomheader(
|
||||
(headername, headervalue) = self.__generate_randomheader(
|
||||
content)
|
||||
self.ui.debug('imap', 'savemessage: header is: %s: %s' %\
|
||||
(headername, headervalue))
|
||||
content = self.savemessage_addheader(content, headername,
|
||||
content = self.__savemessage_addheader(content, headername,
|
||||
headervalue)
|
||||
if len(content)>200:
|
||||
dbg_output = "%s...%s" % (content[:150], content[-50:])
|
||||
@ -605,14 +616,14 @@ class IMAPFolder(BaseFolder):
|
||||
"'%s'" % str(resp))
|
||||
else:
|
||||
# we don't support UIDPLUS
|
||||
uid = self.savemessage_searchforheader(imapobj, headername,
|
||||
uid = self.__savemessage_searchforheader(imapobj, headername,
|
||||
headervalue)
|
||||
# See docs for savemessage in Base.py for explanation
|
||||
# of this and other return values
|
||||
if uid == 0:
|
||||
self.ui.debug('imap', 'savemessage: attempt to get new UID '
|
||||
'UID failed. Search headers manually.')
|
||||
uid = self.savemessage_fetchheaders(imapobj, headername,
|
||||
uid = self.__savemessage_fetchheaders(imapobj, headername,
|
||||
headervalue)
|
||||
self.ui.warn('imap', "savemessage: Searching mails for new "
|
||||
"Message-ID failed. Could not determine new UID.")
|
||||
@ -625,6 +636,7 @@ class IMAPFolder(BaseFolder):
|
||||
self.ui.debug('imap', 'savemessage: returning new UID %d' % uid)
|
||||
return uid
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessageflags(self, uid, flags):
|
||||
"""Change a message's flags to `flags`.
|
||||
|
||||
@ -650,29 +662,34 @@ class IMAPFolder(BaseFolder):
|
||||
flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS']
|
||||
self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def addmessageflags(self, uid, flags):
|
||||
self.addmessagesflags([uid], flags)
|
||||
|
||||
def addmessagesflags_noconvert(self, uidlist, flags):
|
||||
self.processmessagesflags('+', uidlist, flags)
|
||||
def __addmessagesflags_noconvert(self, uidlist, flags):
|
||||
self.__processmessagesflags('+', uidlist, flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def addmessagesflags(self, uidlist, flags):
|
||||
"""This is here for the sake of UIDMaps.py -- deletemessages must
|
||||
add flags and get a converted UID, and if we don't have noconvert,
|
||||
then UIDMaps will try to convert it twice."""
|
||||
self.addmessagesflags_noconvert(uidlist, flags)
|
||||
self.__addmessagesflags_noconvert(uidlist, flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessageflags(self, uid, flags):
|
||||
self.deletemessagesflags([uid], flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessagesflags(self, uidlist, flags):
|
||||
self.processmessagesflags('-', uidlist, flags)
|
||||
self.__processmessagesflags('-', uidlist, flags)
|
||||
|
||||
def processmessagesflags(self, operation, uidlist, flags):
|
||||
def __processmessagesflags(self, operation, uidlist, flags):
|
||||
# XXX: should really iterate over batches of 100 UIDs
|
||||
if len(uidlist) > 101:
|
||||
# Hack for those IMAP ervers with a limited line length
|
||||
self.processmessagesflags(operation, uidlist[:100], flags)
|
||||
self.processmessagesflags(operation, uidlist[100:], flags)
|
||||
# Hack for those IMAP servers with a limited line length
|
||||
self.__processmessagesflags(operation, uidlist[:100], flags)
|
||||
self.__processmessagesflags(operation, uidlist[100:], flags)
|
||||
return
|
||||
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
@ -716,6 +733,7 @@ class IMAPFolder(BaseFolder):
|
||||
elif operation == '-':
|
||||
self.messagelist[uid]['flags'] -= flags
|
||||
|
||||
# Interface from BaseFolder
|
||||
def change_message_uid(self, uid, new_uid):
|
||||
"""Change the message from existing uid to new_uid
|
||||
|
||||
@ -724,19 +742,21 @@ class IMAPFolder(BaseFolder):
|
||||
'%d to %d' % (uid, new_uid),
|
||||
OfflineImapError.ERROR.MESSAGE)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessage(self, uid):
|
||||
self.deletemessages_noconvert([uid])
|
||||
self.__deletemessages_noconvert([uid])
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessages(self, uidlist):
|
||||
self.deletemessages_noconvert(uidlist)
|
||||
self.__deletemessages_noconvert(uidlist)
|
||||
|
||||
def deletemessages_noconvert(self, uidlist):
|
||||
def __deletemessages_noconvert(self, uidlist):
|
||||
# Weed out ones not in self.messagelist
|
||||
uidlist = [uid for uid in uidlist if self.uidexists(uid)]
|
||||
if not len(uidlist):
|
||||
return
|
||||
|
||||
self.addmessagesflags_noconvert(uidlist, set('T'))
|
||||
self.__addmessagesflags_noconvert(uidlist, set('T'))
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
try:
|
||||
@ -750,5 +770,3 @@ class IMAPFolder(BaseFolder):
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
for uid in uidlist:
|
||||
del self.messagelist[uid]
|
||||
|
||||
|
||||
|
@ -33,21 +33,26 @@ class LocalStatusFolder(BaseFolder):
|
||||
False)
|
||||
"""Should we perform fsyncs as often as possible?"""
|
||||
|
||||
# Interface from BaseFolder
|
||||
def storesmessages(self):
|
||||
return 0
|
||||
|
||||
def isnewfolder(self):
|
||||
return not os.path.exists(self.filename)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getname(self):
|
||||
return self.name
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getroot(self):
|
||||
return self.repository.root
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getsep(self):
|
||||
return self.sep
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getfullname(self):
|
||||
return self.filename
|
||||
|
||||
@ -55,6 +60,7 @@ class LocalStatusFolder(BaseFolder):
|
||||
if not self.isnewfolder():
|
||||
os.unlink(self.filename)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def cachemessagelist(self):
|
||||
if self.isnewfolder():
|
||||
self.messagelist = {}
|
||||
@ -103,9 +109,11 @@ class LocalStatusFolder(BaseFolder):
|
||||
os.fsync(fd)
|
||||
os.close(fd)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessage(self, uid, content, flags, rtime):
|
||||
"""Writes a new message, with the specified uid.
|
||||
|
||||
@ -124,19 +132,24 @@ class LocalStatusFolder(BaseFolder):
|
||||
self.save()
|
||||
return uid
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessageflags(self, uid):
|
||||
return self.messagelist[uid]['flags']
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagetime(self, uid):
|
||||
return self.messagelist[uid]['time']
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessageflags(self, uid, flags):
|
||||
self.messagelist[uid]['flags'] = flags
|
||||
self.save()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessage(self, uid):
|
||||
self.deletemessages([uid])
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessages(self, uidlist):
|
||||
# Weed out ones not in self.messagelist
|
||||
uidlist = [uid for uid in uidlist if uid in self.messagelist]
|
||||
|
@ -62,14 +62,14 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
cursor = self.connection.execute("SELECT value from metadata WHERE key='db_version'")
|
||||
except sqlite.DatabaseError:
|
||||
#db file missing or corrupt, recreate it.
|
||||
self.upgrade_db(0)
|
||||
self.__upgrade_db(0)
|
||||
else:
|
||||
# fetch db version and upgrade if needed
|
||||
version = int(cursor.fetchone()[0])
|
||||
if version < LocalStatusSQLiteFolder.cur_version:
|
||||
self.upgrade_db(version)
|
||||
self.__upgrade_db(version)
|
||||
|
||||
def sql_write(self, sql, vars=None, executemany=False):
|
||||
def __sql_write(self, sql, vars=None, executemany=False):
|
||||
"""Execute some SQL, retrying if the db was locked.
|
||||
|
||||
:param sql: the SQL string passed to execute()
|
||||
@ -106,7 +106,7 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
self._dblock.release()
|
||||
return cursor
|
||||
|
||||
def upgrade_db(self, from_ver):
|
||||
def __upgrade_db(self, from_ver):
|
||||
"""Upgrade the sqlite format from version 'from_ver' to current"""
|
||||
|
||||
if hasattr(self, 'connection'):
|
||||
@ -116,7 +116,7 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
|
||||
if from_ver == 0:
|
||||
# from_ver==0: no db existent: plain text migration?
|
||||
self.create_db()
|
||||
self.__create_db()
|
||||
# below was derived from repository.getfolderfilename() logic
|
||||
plaintextfilename = os.path.join(
|
||||
self.repository.account.getaccountmeta(),
|
||||
@ -144,7 +144,7 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
# if from_ver <= 1: ... #upgrade from 1 to 2
|
||||
# if from_ver <= 2: ... #upgrade from 2 to 3
|
||||
|
||||
def create_db(self):
|
||||
def __create_db(self):
|
||||
"""Create a new db file"""
|
||||
self.ui._msg('Creating new Local Status db for %s:%s' \
|
||||
% (self.repository, self))
|
||||
@ -158,16 +158,19 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
""")
|
||||
self.connection.commit()
|
||||
|
||||
# Interface from LocalStatusFolder
|
||||
def isnewfolder(self):
|
||||
# testing the existence of the db file won't work. It is created
|
||||
# as soon as this class instance was intitiated. So say it is a
|
||||
# new folder when there are no messages at all recorded in it.
|
||||
return self.getmessagecount() > 0
|
||||
|
||||
# Interface from LocalStatusFolder
|
||||
def deletemessagelist(self):
|
||||
"""delete all messages in the db"""
|
||||
self.sql_write('DELETE FROM status')
|
||||
self.__sql_write('DELETE FROM status')
|
||||
|
||||
# Interface from BaseFolder
|
||||
def cachemessagelist(self):
|
||||
self.messagelist = {}
|
||||
cursor = self.connection.execute('SELECT id,flags from status')
|
||||
@ -175,6 +178,7 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
flags = set(row[1])
|
||||
self.messagelist[row[0]] = {'uid': row[0], 'flags': flags}
|
||||
|
||||
# Interface from LocalStatusFolder
|
||||
def save(self):
|
||||
#Noop in this backend
|
||||
pass
|
||||
@ -215,6 +219,7 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
# return flags
|
||||
# assert False,"getmessageflags() called on non-existing message"
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessage(self, uid, content, flags, rtime):
|
||||
"""Writes a new message, with the specified uid.
|
||||
|
||||
@ -231,21 +236,24 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
|
||||
flags = ''.join(sorted(flags))
|
||||
self.sql_write('INSERT INTO status (id,flags) VALUES (?,?)',
|
||||
self.__sql_write('INSERT INTO status (id,flags) VALUES (?,?)',
|
||||
(uid,flags))
|
||||
return uid
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessageflags(self, uid, flags):
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
||||
flags = ''.join(sorted(flags))
|
||||
self.sql_write('UPDATE status SET flags=? WHERE id=?',(flags,uid))
|
||||
self.__sql_write('UPDATE status SET flags=? WHERE id=?',(flags,uid))
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessage(self, uid):
|
||||
if not uid in self.messagelist:
|
||||
return
|
||||
self.sql_write('DELETE FROM status WHERE id=?', (uid, ))
|
||||
self.__sql_write('DELETE FROM status WHERE id=?', (uid, ))
|
||||
del(self.messagelist[uid])
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessages(self, uidlist):
|
||||
"""Delete list of UIDs from status cache
|
||||
|
||||
@ -257,6 +265,6 @@ class LocalStatusSQLiteFolder(LocalStatusFolder):
|
||||
if not len(uidlist):
|
||||
return
|
||||
# arg2 needs to be an iterable of 1-tuples [(1,),(2,),...]
|
||||
self.sql_write('DELETE FROM status WHERE id=?', zip(uidlist, ), True)
|
||||
self.__sql_write('DELETE FROM status WHERE id=?', zip(uidlist, ), True)
|
||||
for uid in uidlist:
|
||||
del(self.messagelist[uid])
|
||||
|
@ -43,7 +43,7 @@ timeseq = 0
|
||||
lasttime = 0
|
||||
timelock = Lock()
|
||||
|
||||
def gettimeseq():
|
||||
def _gettimeseq():
|
||||
global lasttime, timeseq, timelock
|
||||
timelock.acquire()
|
||||
try:
|
||||
@ -79,10 +79,12 @@ class MaildirFolder(BaseFolder):
|
||||
# Cache the full folder path, as we use getfullname() very often
|
||||
self._fullname = os.path.join(self.getroot(), self.getname())
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getfullname(self):
|
||||
"""Return the absolute file path to the Maildir folder (sans cur|new)"""
|
||||
return self._fullname
|
||||
|
||||
# Interface from BaseFolder
|
||||
def get_uidvalidity(self):
|
||||
"""Retrieve the current connections UIDVALIDITY value
|
||||
|
||||
@ -191,6 +193,7 @@ class MaildirFolder(BaseFolder):
|
||||
retval[uid] = {'flags': flags, 'filename': filepath}
|
||||
return retval
|
||||
|
||||
# Interface from BaseFolder
|
||||
def quickchanged(self, statusfolder):
|
||||
"""Returns True if the Maildir has changed"""
|
||||
self.cachemessagelist()
|
||||
@ -204,13 +207,16 @@ class MaildirFolder(BaseFolder):
|
||||
return True
|
||||
return False #Nope, nothing changed
|
||||
|
||||
# Interface from BaseFolder
|
||||
def cachemessagelist(self):
|
||||
if self.messagelist is None:
|
||||
self.messagelist = self._scanfolder()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessage(self, uid):
|
||||
"""Return the content of the message"""
|
||||
filename = self.messagelist[uid]['filename']
|
||||
@ -222,22 +228,24 @@ class MaildirFolder(BaseFolder):
|
||||
# read it as text?
|
||||
return retval.replace("\r\n", "\n")
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagetime(self, uid):
|
||||
filename = self.messagelist[uid]['filename']
|
||||
filepath = os.path.join(self.getfullname(), filename)
|
||||
return os.path.getmtime(filepath)
|
||||
|
||||
def new_message_filename(self, uid, flags=set()):
|
||||
def __new_message_filename(self, uid, flags=set()):
|
||||
"""Creates a new unique Maildir filename
|
||||
|
||||
:param uid: The UID`None`, or a set of maildir flags
|
||||
:param flags: A set of maildir flags
|
||||
:returns: String containing unique message filename"""
|
||||
timeval, timeseq = gettimeseq()
|
||||
timeval, timeseq = _gettimeseq()
|
||||
return '%d_%d.%d.%s,U=%d,FMD5=%s%s2,%s' % \
|
||||
(timeval, timeseq, os.getpid(), socket.gethostname(),
|
||||
uid, self._foldermd5, self.infosep, ''.join(sorted(flags)))
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessage(self, uid, content, flags, rtime):
|
||||
"""Writes a new message, with the specified uid.
|
||||
|
||||
@ -259,7 +267,7 @@ class MaildirFolder(BaseFolder):
|
||||
# Otherwise, save the message in tmp/ and then call savemessageflags()
|
||||
# to give it a permanent home.
|
||||
tmpdir = os.path.join(self.getfullname(), 'tmp')
|
||||
messagename = self.new_message_filename(uid, flags)
|
||||
messagename = self.__new_message_filename(uid, flags)
|
||||
# open file and write it out
|
||||
try:
|
||||
fd = os.open(os.path.join(tmpdir, messagename),
|
||||
@ -291,9 +299,11 @@ class MaildirFolder(BaseFolder):
|
||||
self.ui.debug('maildir', 'savemessage: returning uid %d' % uid)
|
||||
return uid
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessageflags(self, uid):
|
||||
return self.messagelist[uid]['flags']
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessageflags(self, uid, flags):
|
||||
"""Sets the specified message's flags to the given set.
|
||||
|
||||
@ -331,6 +341,7 @@ class MaildirFolder(BaseFolder):
|
||||
self.messagelist[uid]['flags'] = flags
|
||||
self.messagelist[uid]['filename'] = newfilename
|
||||
|
||||
# Interface from BaseFolder
|
||||
def change_message_uid(self, uid, new_uid):
|
||||
"""Change the message from existing uid to new_uid
|
||||
|
||||
@ -345,12 +356,13 @@ class MaildirFolder(BaseFolder):
|
||||
oldfilename = self.messagelist[uid]['filename']
|
||||
dir_prefix, filename = os.path.split(oldfilename)
|
||||
flags = self.getmessageflags(uid)
|
||||
filename = self.new_message_filename(new_uid, flags)
|
||||
filename = self.__new_message_filename(new_uid, flags)
|
||||
os.rename(os.path.join(self.getfullname(), oldfilename),
|
||||
os.path.join(self.getfullname(), dir_prefix, filename))
|
||||
self.messagelist[new_uid] = self.messagelist[uid]
|
||||
del self.messagelist[uid]
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessage(self, uid):
|
||||
"""Unlinks a message file from the Maildir.
|
||||
|
||||
@ -375,4 +387,3 @@ class MaildirFolder(BaseFolder):
|
||||
os.unlink(filepath)
|
||||
# Yep -- return.
|
||||
del(self.messagelist[uid])
|
||||
|
||||
|
@ -91,6 +91,7 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
"iling list.".format(e.args[0], self),
|
||||
OfflineImapError.ERROR.MESSAGE)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def cachemessagelist(self):
|
||||
self._mb.cachemessagelist()
|
||||
reallist = self._mb.getmessagelist()
|
||||
@ -122,12 +123,14 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
finally:
|
||||
self.maplock.release()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def uidexists(self, ruid):
|
||||
"""Checks if the (remote) UID exists in this Folder"""
|
||||
# This implementation overrides the one in BaseFolder, as it is
|
||||
# much more efficient for the mapped case.
|
||||
return ruid in self.r2l
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessageuidlist(self):
|
||||
"""Gets a list of (remote) UIDs.
|
||||
You may have to call cachemessagelist() before calling this function!"""
|
||||
@ -135,6 +138,7 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
# much more efficient for the mapped case.
|
||||
return self.r2l.keys()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagecount(self):
|
||||
"""Gets the number of messages in this folder.
|
||||
You may have to call cachemessagelist() before calling this function!"""
|
||||
@ -142,6 +146,7 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
# much more efficient for the mapped case.
|
||||
return len(self.r2l)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagelist(self):
|
||||
"""Gets the current message list. This function's implementation
|
||||
is quite expensive for the mapped UID case. You must call
|
||||
@ -167,10 +172,12 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
finally:
|
||||
self.maplock.release()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessage(self, uid):
|
||||
"""Returns the content of the specified message."""
|
||||
return self._mb.getmessage(self.r2l[uid])
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessage(self, uid, content, flags, rtime):
|
||||
"""Writes a new message, with the specified uid.
|
||||
|
||||
@ -216,12 +223,15 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
self.maplock.release()
|
||||
return uid
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessageflags(self, uid):
|
||||
return self._mb.getmessageflags(self.r2l[uid])
|
||||
|
||||
# Interface from BaseFolder
|
||||
def getmessagetime(self, uid):
|
||||
return None
|
||||
|
||||
# Interface from BaseFolder
|
||||
def savemessageflags(self, uid, flags):
|
||||
"""
|
||||
|
||||
@ -230,13 +240,16 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
dryrun mode."""
|
||||
self._mb.savemessageflags(self.r2l[uid], flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def addmessageflags(self, uid, flags):
|
||||
self._mb.addmessageflags(self.r2l[uid], flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def addmessagesflags(self, uidlist, flags):
|
||||
self._mb.addmessagesflags(self._uidlist(self.r2l, uidlist),
|
||||
flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def change_message_uid(self, ruid, new_ruid):
|
||||
"""Change the message from existing ruid to new_ruid
|
||||
|
||||
@ -279,17 +292,21 @@ class MappedIMAPFolder(IMAPFolder):
|
||||
finally:
|
||||
self.maplock.release()
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessageflags(self, uid, flags):
|
||||
self._mb.deletemessageflags(self.r2l[uid], flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessagesflags(self, uidlist, flags):
|
||||
self._mb.deletemessagesflags(self._uidlist(self.r2l, uidlist),
|
||||
flags)
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessage(self, uid):
|
||||
self._mb.deletemessage(self.r2l[uid])
|
||||
self._mapped_delete([uid])
|
||||
|
||||
# Interface from BaseFolder
|
||||
def deletemessages(self, uidlist):
|
||||
self._mb.deletemessages(self._uidlist(self.r2l, uidlist))
|
||||
self._mapped_delete(uidlist)
|
||||
|
Reference in New Issue
Block a user