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
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.
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
"""
If this function is implemented,
then it should include this code:
if ignorelabels is None:
ignorelabels = set()
"""
raise NotImplementedError
def addmessagelabels(self, uid, labels):

View File

@ -56,7 +56,7 @@ class GmailFolder(IMAPFolder):
# Labels to be left alone
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):
"""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
return ret
def savemessagelabels(self, uid, labels, ignorelabels=set()):
def savemessagelabels(self, uid, labels, ignorelabels=None):
"""Change a message's labels to `labels`.
Note that this function does not check against dryrun settings,
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']
filepath = os.path.join(self.getfullname(), filename)

View File

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

View File

@ -190,13 +190,16 @@ class LocalStatusFolder(BaseFolder):
os.close(fd)
# 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.
See folder/Base for detail. Note that savemessage() does not
check against dryrun settings, so you need to ensure that
savemessage is never called in a dryrun mode."""
if labels is None:
labels = set()
if uid < 0:
# We cannot assign a uid.
return uid

View File

@ -323,13 +323,16 @@ class LocalStatusSQLiteFolder(BaseFolder):
# assert False,"getmessageflags() called on non-existing message"
# 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.
See folder/Base for detail. Note that savemessage() does not
check against dryrun settings, so you need to ensure that
savemessage is never called in a dryrun mode."""
if labels is None:
labels = set()
if uid < 0:
# We cannot assign a uid.
return uid

View File

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

View File

@ -73,16 +73,16 @@ def flagsplit(s):
return imapsplit(s[1:-1])
def __options2hash(list):
"""convert list [1,2,3,4,5,6] to {1:2, 3:4, 5:6}"""
def __options2hash(l_list):
"""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
# measurements seemed to have indicated that the manual variant is
# faster for mosly small lists.
retval = {}
counter = 0
while counter < len(list):
retval[list[counter]] = list[counter + 1]
while counter < len(l_list):
retval[l_list[counter]] = l_list[counter + 1]
counter += 2
__debug("__options2hash returning:", retval)
return retval
@ -435,3 +435,23 @@ def imap4_utf_7(name):
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):
"""
:param account: :class:`Account`
:param regtype: 'remote', 'local', or 'status'"""
:param reqtype: 'remote', 'local', or 'status'"""
if reqtype == 'remote':
name = account.getconf('remoterepository')
@ -81,6 +81,6 @@ class Repository:
executed instead of this stub
:param account: :class:`Account`
:param regtype: 'remote', 'local', or 'status'
:param reqtype: 'remote', 'local', or 'status'
"""
pass

View File

@ -78,17 +78,6 @@ def monitor():
"""An infinite "monitoring" loop watching for finished ExitNotifyThread's.
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