Merge pull request #6 from thekix/master

Solves issue #4 and some cleanup
This commit is contained in:
Rodolfo García Peñas (kix) 2020-10-11 23:05:59 +02:00 committed by GitHub
commit 941d69c7b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 53 additions and 24 deletions

View File

@ -524,13 +524,21 @@ class BaseFolder:
raise NotImplementedError raise NotImplementedError
def savemessagelabels(self, uid, labels, ignorelabels=set(), mtime=0): def savemessagelabels(self, uid, labels, ignorelabels=None, mtime=0):
"""Sets the specified message's labels to the given set. """Sets the specified message's labels to the given set.
Note that this function does not check against dryrun settings, Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a so you need to ensure that it is never called in a
dryrun mode.""" dryrun mode."""
"""
If this function is implemented,
then it should include this code:
if ignorelabels is None:
ignorelabels = set()
"""
raise NotImplementedError raise NotImplementedError
def addmessagelabels(self, uid, labels): def addmessagelabels(self, uid, labels):

View File

@ -56,7 +56,7 @@ class GmailFolder(IMAPFolder):
# Labels to be left alone # Labels to be left alone
ignorelabels = self.repository.account.getconf('ignorelabels', '') ignorelabels = self.repository.account.getconf('ignorelabels', '')
self.ignorelabels = set([l for l in re.split(r'\s*,\s*', ignorelabels) if len(l)]) self.ignorelabels = set([v for v in re.split(r'\s*,\s*', ignorelabels) if len(v)])
def getmessage(self, uid): def getmessage(self, uid):
"""Retrieve message with UID from the IMAP server (incl body). Also """Retrieve message with UID from the IMAP server (incl body). Also

View File

@ -133,12 +133,15 @@ class GmailMaildirFolder(MaildirFolder):
self.messagelist[uid]['labels'] = labels self.messagelist[uid]['labels'] = labels
return ret return ret
def savemessagelabels(self, uid, labels, ignorelabels=set()): def savemessagelabels(self, uid, labels, ignorelabels=None):
"""Change a message's labels to `labels`. """Change a message's labels to `labels`.
Note that this function does not check against dryrun settings, Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a dryrun mode.""" so you need to ensure that it is never called in a dryrun mode."""
if ignorelabels is None:
ignorelabels = set()
filename = self.messagelist[uid]['filename'] filename = self.messagelist[uid]['filename']
filepath = os.path.join(self.getfullname(), filename) filepath = os.path.join(self.getfullname(), filename)

View File

@ -91,7 +91,7 @@ class IMAPFolder(BaseFolder):
name = self.getfullname() name = self.getfullname()
if self.repository.account.utf_8_support: if self.repository.account.utf_8_support:
name = imaputil.utf8_IMAP(name) name = imaputil.utf8_IMAP(name)
return name return imaputil.foldername_to_imapname(name)
# Interface from BaseFolder # Interface from BaseFolder
def suggeststhreads(self): def suggeststhreads(self):

View File

@ -190,13 +190,16 @@ class LocalStatusFolder(BaseFolder):
os.close(fd) os.close(fd)
# Interface from BaseFolder # Interface from BaseFolder
def savemessage(self, uid, content, flags, rtime, mtime=0, labels=set()): def savemessage(self, uid, content, flags, rtime, mtime=0, labels=None):
"""Writes a new message, with the specified uid. """Writes a new message, with the specified uid.
See folder/Base for detail. Note that savemessage() does not See folder/Base for detail. Note that savemessage() does not
check against dryrun settings, so you need to ensure that check against dryrun settings, so you need to ensure that
savemessage is never called in a dryrun mode.""" savemessage is never called in a dryrun mode."""
if labels is None:
labels = set()
if uid < 0: if uid < 0:
# We cannot assign a uid. # We cannot assign a uid.
return uid return uid

View File

@ -323,13 +323,16 @@ class LocalStatusSQLiteFolder(BaseFolder):
# assert False,"getmessageflags() called on non-existing message" # assert False,"getmessageflags() called on non-existing message"
# Interface from BaseFolder # Interface from BaseFolder
def savemessage(self, uid, content, flags, rtime, mtime=0, labels=set()): def savemessage(self, uid, content, flags, rtime, mtime=0, labels=None):
"""Writes a new message, with the specified uid. """Writes a new message, with the specified uid.
See folder/Base for detail. Note that savemessage() does not See folder/Base for detail. Note that savemessage() does not
check against dryrun settings, so you need to ensure that check against dryrun settings, so you need to ensure that
savemessage is never called in a dryrun mode.""" savemessage is never called in a dryrun mode."""
if labels is None:
labels = set()
if uid < 0: if uid < 0:
# We cannot assign a uid. # We cannot assign a uid.
return uid return uid

View File

@ -270,7 +270,7 @@ class MaildirFolder(BaseFolder):
filepath = os.path.join(self.getfullname(), filename) filepath = os.path.join(self.getfullname(), filename)
return os.path.getmtime(filepath) return os.path.getmtime(filepath)
def new_message_filename(self, uid, flags=set(), date=None): def new_message_filename(self, uid, flags=None, date=None):
"""Creates a new unique Maildir filename """Creates a new unique Maildir filename
:param uid: The UID`None`, or a set of maildir flags :param uid: The UID`None`, or a set of maildir flags
@ -278,6 +278,9 @@ class MaildirFolder(BaseFolder):
:param flags: (optional) Date :param flags: (optional) Date
:returns: String containing unique message filename""" :returns: String containing unique message filename"""
if flags is None:
flags = set()
timeval, timeseq = _gettimeseq(date) timeval, timeseq = _gettimeseq(date)
uniq_name = '%d_%d.%d.%s,U=%d,FMD5=%s%s2,%s' % \ uniq_name = '%d_%d.%d.%s,U=%d,FMD5=%s%s2,%s' % \
(timeval, timeseq, os.getpid(), socket.gethostname(), (timeval, timeseq, os.getpid(), socket.gethostname(),

View File

@ -73,16 +73,16 @@ def flagsplit(s):
return imapsplit(s[1:-1]) return imapsplit(s[1:-1])
def __options2hash(list): def __options2hash(l_list):
"""convert list [1,2,3,4,5,6] to {1:2, 3:4, 5:6}""" """convert l_list [1,2,3,4,5,6] to {1:2, 3:4, 5:6}"""
# effectively this does dict(zip(l[::2],l[1::2])), however # effectively this does dict(zip(l[::2],l[1::2])), however
# measurements seemed to have indicated that the manual variant is # measurements seemed to have indicated that the manual variant is
# faster for mosly small lists. # faster for mosly small lists.
retval = {} retval = {}
counter = 0 counter = 0
while counter < len(list): while counter < len(l_list):
retval[list[counter]] = list[counter + 1] retval[l_list[counter]] = l_list[counter + 1]
counter += 2 counter += 2
__debug("__options2hash returning:", retval) __debug("__options2hash returning:", retval)
return retval return retval
@ -435,3 +435,23 @@ def imap4_utf_7(name):
codecs.register(imap4_utf_7) codecs.register(imap4_utf_7)
def foldername_to_imapname(folder_name):
"""
This function returns the folder_name ready to send to the
IMAP server. It tests if the folder_name has special characters
Then, quote it.
Args:
folder_name: Folder's name
Returns: The folder_name quoted if needed
"""
# If name includes some of these characters, quote it
atom_specials = [' ', '/', '(', ')', '{', '}']
if any((c in atom_specials) for c in folder_name):
folder_name = '"' + folder_name + '"'
return folder_name

View File

@ -32,7 +32,7 @@ class Repository:
def __new__(cls, account, reqtype): def __new__(cls, account, reqtype):
""" """
:param account: :class:`Account` :param account: :class:`Account`
:param regtype: 'remote', 'local', or 'status'""" :param reqtype: 'remote', 'local', or 'status'"""
if reqtype == 'remote': if reqtype == 'remote':
name = account.getconf('remoterepository') name = account.getconf('remoterepository')
@ -81,6 +81,6 @@ class Repository:
executed instead of this stub executed instead of this stub
:param account: :class:`Account` :param account: :class:`Account`
:param regtype: 'remote', 'local', or 'status' :param reqtype: 'remote', 'local', or 'status'
""" """
pass pass

View File

@ -78,17 +78,6 @@ def monitor():
"""An infinite "monitoring" loop watching for finished ExitNotifyThread's. """An infinite "monitoring" loop watching for finished ExitNotifyThread's.
This one is supposed to run in the main thread. This one is supposed to run in the main thread.
:param callback: the function to call when a thread terminated. That
function is called with a single argument -- the
ExitNotifyThread that has terminated. The monitor will
not continue to monitor for other threads until
'callback' returns, so if it intends to perform long
calculations, it should start a new thread itself -- but
NOT an ExitNotifyThread, or else an infinite loop
may result.
Furthermore, the monitor will hold the lock all the
while the other thread is waiting.
:type callback: a callable function
""" """
global exitedThreads global exitedThreads