Skip to content

Commit

Permalink
Restructured folder.IMAP code
Browse files Browse the repository at this point in the history
Preparing for a sequence of commits implementing gmail label sync, I have split
some functions so I will be able to change some functionality in folder.Gmail,
with less code repetition.

Also added some functions to folder.base and imaputil I will later need.
  • Loading branch information
aroig committed Nov 10, 2012
1 parent a6c00d4 commit 6ecdfc4
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 120 deletions.
116 changes: 112 additions & 4 deletions offlineimap/folder/Base.py
Expand Up @@ -48,6 +48,11 @@ def __init__(self, name, repository):
self.visiblename = ''
self.config = repository.getconfig()

# Passes for syncmessagesto
self.syncmessagesto_passes = [('copying messages' , self.syncmessagesto_copy),
('deleting messages' , self.syncmessagesto_delete),
('syncing flags' , self.syncmessagesto_flags)]

def getname(self):
"""Returns name"""
return self.name
Expand Down Expand Up @@ -227,6 +232,10 @@ def getmessagetime(self, uid):
"""Return the received time for the specified message."""
raise NotImplementedError

def getmessagemtime(self, uid):
"""Returns the message modification time of the specified message."""
raise NotImplementedError

def getmessageflags(self, uid):
"""Returns the flags for the specified message."""
raise NotImplementedError
Expand Down Expand Up @@ -277,6 +286,58 @@ def deletemessagesflags(self, uidlist, flags):
for uid in uidlist:
self.deletemessageflags(uid, flags)


def getmessagelabels(self, uid):
"""Returns the labels for the specified message."""
raise NotImplementedError

def savemessagelabels(self, uid, labels, ignorelabels=set(), 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."""
raise NotImplementedError

def addmessagelabels(self, uid, labels):
"""Adds the specified labels to the message's labels set. If a given
label is already present, it will not be duplicated.
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode.
:param labels: A set() of labels"""
newlabels = self.getmessagelabels(uid) | labels
self.savemessagelabels(uid, newlabels)

def addmessageslabels(self, uidlist, 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."""
for uid in uidlist:
self.addmessagelabels(uid, labels)

def deletemessagelabels(self, uid, labels):
"""Removes each label given from the message's label set. If a given
label is already removed, no action will be taken for that label.
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
newlabels = self.getmessagelabels(uid) - labels
self.savemessagelabels(uid, newlabels)

def deletemessageslabels(self, uidlist, 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."""
for uid in uidlist:
self.deletemessagelabels(uid, labels)


def change_message_uid(self, uid, new_uid):
"""Change the message from existing uid to new_uid
Expand All @@ -302,6 +363,51 @@ def deletemessages(self, uidlist):
for uid in uidlist:
self.deletemessage(uid)

def message_addheader(self, content, headername, headervalue):
"""Changes the value of headername to headervalue if the header exists,
or adds it if it does not exist"""

self.ui.debug('',
'message_addheader: called to add %s: %s' % (headername,
headervalue))
insertionpoint = content.find("\n\n")
self.ui.debug('', 'message_addheader: insertionpoint = %d' % insertionpoint)
leader = content[0:insertionpoint]
self.ui.debug('', 'message_addheader: leader = %s' % repr(leader))
if insertionpoint == 0 or insertionpoint == -1:
newline = ''
insertionpoint = 0
else:
newline = "\n"

if re.search('^%s:(.*)$' % headername, leader, flags = re.MULTILINE):
leader = re.sub('^%s:(.*)$' % headername, '%s: %s' % (headername, headervalue),
leader, flags = re.MULTILINE)
else:
leader = leader + newline + "%s: %s" % (headername, headervalue)

self.ui.debug('', 'message_addheader: newline = ' + repr(newline))
trailer = content[insertionpoint:]
self.ui.debug('', 'message_addheader: trailer = ' + repr(trailer))
return leader + trailer

def message_getheader(self, content, headername):
"""Gets the value of the header 'headername' in 'content'. Returns None
if can't find the header."""

self.ui.debug('',
'message_getheader: called to get %s' % headername)
insertionpoint = content.find("\n\n")
self.ui.debug('', 'message_getheader: insertionpoint = %d' % insertionpoint)
leader = content[0:insertionpoint]
self.ui.debug('', 'message_getheader: leader = %s' % repr(leader))

m = re.search('^%s:(.*)$' % headername, leader, flags = re.MULTILINE)
if m:
return m.group(1).strip()
else:
return None

def copymessageto(self, uid, dstfolder, statusfolder, register = 1):
"""Copies a message from self to dst if needed, updating the status
Expand Down Expand Up @@ -519,14 +625,16 @@ def syncmessagesto(self, dstfolder, statusfolder):
deleted there), sync the flag change to both dstfolder and
statusfolder.
Pass4: Synchronize label changes (Gmail only)
Compares label mismatches in self with those in statusfolder.
If msg has a valid UID and exists on dstfolder, syncs the labels
to both dstfolder and statusfolder.
: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)]

for (passdesc, action) in passes:
for (passdesc, action) in self.syncmessagesto_passes:
# bail out on CTRL-C or SIGTERM
if offlineimap.accounts.Account.abort_NOW_signal.is_set():
break
Expand Down

0 comments on commit 6ecdfc4

Please sign in to comment.