Fixing up the rest of the parsing and IMAP functions, and GMAIL classes as well. Also adding is_debugging() to the UI to allow us to quickly determine if we should build some of the expensive debug objects
This commit is contained in:
parent
5fc08e529b
commit
259bf83607
@ -60,9 +60,9 @@ class BaseFolder:
|
|||||||
policy.default.clone(cte_type='8bit', utf8=True, refold_source='none', linesep='\r\n'),
|
policy.default.clone(cte_type='8bit', utf8=True, refold_source='none', linesep='\r\n'),
|
||||||
}
|
}
|
||||||
# Parsers
|
# Parsers
|
||||||
self.parse = {
|
self.parser = {}
|
||||||
'8bit': BytesParser(policy=p1),
|
for key in self.policy:
|
||||||
}
|
self.parser[key] = BytesParser(policy=self.policy[key])
|
||||||
# Save original name for folderfilter operations.
|
# Save original name for folderfilter operations.
|
||||||
self.ffilter_name = name
|
self.ffilter_name = name
|
||||||
# Top level dir name is always ''.
|
# Top level dir name is always ''.
|
||||||
|
@ -69,10 +69,9 @@ class GmailFolder(IMAPFolder):
|
|||||||
data = self._fetch_from_imap(str(uid), self.retrycount)
|
data = self._fetch_from_imap(str(uid), self.retrycount)
|
||||||
|
|
||||||
# data looks now e.g.
|
# data looks now e.g.
|
||||||
# ['320 (X-GM-LABELS (...) UID 17061 BODY[] {2565}','msgbody....']
|
# ['320 (X-GM-LABELS (...) UID 17061 BODY[] {2565}',<email.message.EmailMessage object>]
|
||||||
# we only asked for one message, and that msg is in data[1].
|
# we only asked for one message, and that msg is in data[1].
|
||||||
# msbody is in [1].
|
msg = data[1]
|
||||||
body = data[1].replace("\r\n", "\n")
|
|
||||||
|
|
||||||
# Embed the labels into the message headers
|
# Embed the labels into the message headers
|
||||||
if self.synclabels:
|
if self.synclabels:
|
||||||
@ -84,19 +83,23 @@ class GmailFolder(IMAPFolder):
|
|||||||
labels = labels - self.ignorelabels
|
labels = labels - self.ignorelabels
|
||||||
labels_str = imaputil.format_labels_string(self.labelsheader, sorted(labels))
|
labels_str = imaputil.format_labels_string(self.labelsheader, sorted(labels))
|
||||||
|
|
||||||
# First remove old label headers that may be in the message content retrieved
|
# First remove old label headers that may be in the message body retrieved
|
||||||
# from gmail Then add a labels header with current gmail labels.
|
# from gmail Then add a labels header with current gmail labels.
|
||||||
body = self.deletemessageheaders(body, self.labelsheader)
|
self.deletemessageheaders(msg, self.labelsheader)
|
||||||
body = self.addmessageheader(body, '\n', self.labelsheader, labels_str)
|
self.addmessageheader(msg, self.labelsheader, labels_str)
|
||||||
|
|
||||||
if len(body) > 200:
|
if self.ui.is_debugging('imap'):
|
||||||
dbg_output = "%s...%s" % (str(body)[:150], str(body)[-50:])
|
# Optimization: don't create the debugging objects unless needed
|
||||||
|
msg_s = msg.as_string(policy=self.policy['8bit-RFC'])
|
||||||
|
if len(msg_s) > 200:
|
||||||
|
dbg_output = "%s...%s" % (msg_s[:150], msg_s[-50:])
|
||||||
else:
|
else:
|
||||||
dbg_output = body
|
dbg_output = msg_s
|
||||||
|
|
||||||
self.ui.debug('imap', "Returned object from fetching %d: '%s'" %
|
self.ui.debug('imap', "Returned object from fetching %d: '%s'" %
|
||||||
(uid, dbg_output))
|
(uid, dbg_output))
|
||||||
return body
|
|
||||||
|
return msg
|
||||||
|
|
||||||
def getmessagelabels(self, uid):
|
def getmessagelabels(self, uid):
|
||||||
if 'labels' in self.messagelist[uid]:
|
if 'labels' in self.messagelist[uid]:
|
||||||
@ -167,7 +170,7 @@ class GmailFolder(IMAPFolder):
|
|||||||
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
||||||
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime}
|
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime}
|
||||||
|
|
||||||
def savemessage(self, uid, content, flags, rtime):
|
def savemessage(self, uid, msg, flags, rtime):
|
||||||
"""Save the message on the Server
|
"""Save the message on the Server
|
||||||
|
|
||||||
This backend always assigns a new uid, so the uid arg is ignored.
|
This backend always assigns a new uid, so the uid arg is ignored.
|
||||||
@ -180,7 +183,7 @@ class GmailFolder(IMAPFolder):
|
|||||||
savemessage is never called in a dryrun mode.
|
savemessage is never called in a dryrun mode.
|
||||||
|
|
||||||
:param uid: Message UID
|
:param uid: Message UID
|
||||||
:param content: Message content
|
:param msg: Message object
|
||||||
:param flags: Message flags
|
:param flags: Message flags
|
||||||
:param rtime: A timestamp to be used as the mail date
|
:param rtime: A timestamp to be used as the mail date
|
||||||
:returns: the UID of the new message as assigned by the server. If the
|
:returns: the UID of the new message as assigned by the server. If the
|
||||||
@ -189,13 +192,13 @@ class GmailFolder(IMAPFolder):
|
|||||||
read-only for example) it will return -1."""
|
read-only for example) it will return -1."""
|
||||||
|
|
||||||
if not self.synclabels:
|
if not self.synclabels:
|
||||||
return super(GmailFolder, self).savemessage(uid, content, flags, rtime)
|
return super(GmailFolder, self).savemessage(uid, msg, flags, rtime)
|
||||||
|
|
||||||
labels = set()
|
labels = set()
|
||||||
for hstr in self.getmessageheaderlist(content, self.labelsheader):
|
for hstr in self.getmessageheaderlist(msg, self.labelsheader):
|
||||||
labels.update(imaputil.labels_from_header(self.labelsheader, hstr))
|
labels.update(imaputil.labels_from_header(self.labelsheader, hstr))
|
||||||
|
|
||||||
ret = super(GmailFolder, self).savemessage(uid, content, flags, rtime)
|
ret = super(GmailFolder, self).savemessage(uid, msg, flags, rtime)
|
||||||
self.savemessagelabels(ret, labels)
|
self.savemessagelabels(ret, labels)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -90,12 +90,12 @@ class GmailMaildirFolder(MaildirFolder):
|
|||||||
if not os.path.exists(filepath):
|
if not os.path.exists(filepath):
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
file = open(filepath, 'rt')
|
fd = open(filepath, 'rb')
|
||||||
content = file.read()
|
msg = self.parser['8bit'].parse(fd)
|
||||||
file.close()
|
fd.close()
|
||||||
|
|
||||||
self.messagelist[uid]['labels'] = set()
|
self.messagelist[uid]['labels'] = set()
|
||||||
for hstr in self.getmessageheaderlist(content, self.labelsheader):
|
for hstr in self.getmessageheaderlist(msg, self.labelsheader):
|
||||||
self.messagelist[uid]['labels'].update(
|
self.messagelist[uid]['labels'].update(
|
||||||
imaputil.labels_from_header(self.labelsheader, hstr))
|
imaputil.labels_from_header(self.labelsheader, hstr))
|
||||||
self.messagelist[uid]['labels_cached'] = True
|
self.messagelist[uid]['labels_cached'] = True
|
||||||
@ -108,7 +108,7 @@ class GmailMaildirFolder(MaildirFolder):
|
|||||||
else:
|
else:
|
||||||
return self.messagelist[uid]['mtime']
|
return self.messagelist[uid]['mtime']
|
||||||
|
|
||||||
def savemessage(self, uid, content, flags, rtime):
|
def savemessage(self, uid, msg, flags, rtime):
|
||||||
"""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
|
||||||
@ -116,14 +116,15 @@ class GmailMaildirFolder(MaildirFolder):
|
|||||||
savemessage is never called in a dryrun mode."""
|
savemessage is never called in a dryrun mode."""
|
||||||
|
|
||||||
if not self.synclabels:
|
if not self.synclabels:
|
||||||
return super(GmailMaildirFolder, self).savemessage(uid, content,
|
return super(GmailMaildirFolder, self).savemessage(uid, msg,
|
||||||
flags, rtime)
|
flags, rtime)
|
||||||
|
|
||||||
labels = set()
|
labels = set()
|
||||||
for hstr in self.getmessageheaderlist(content, self.labelsheader):
|
for hstr in self.getmessageheaderlist(msg, self.labelsheader):
|
||||||
labels.update(imaputil.labels_from_header(self.labelsheader, hstr))
|
labels.update(imaputil.labels_from_header(self.labelsheader, hstr))
|
||||||
|
|
||||||
ret = super(GmailMaildirFolder, self).savemessage(uid, content, flags,
|
# TODO - Not sure why the returned uid is stored early as ret here?
|
||||||
|
ret = super(GmailMaildirFolder, self).savemessage(uid, msg, flags,
|
||||||
rtime)
|
rtime)
|
||||||
|
|
||||||
# Update the mtime and labels.
|
# Update the mtime and labels.
|
||||||
@ -145,12 +146,12 @@ class GmailMaildirFolder(MaildirFolder):
|
|||||||
filename = self.messagelist[uid]['filename']
|
filename = self.messagelist[uid]['filename']
|
||||||
filepath = os.path.join(self.getfullname(), filename)
|
filepath = os.path.join(self.getfullname(), filename)
|
||||||
|
|
||||||
file = open(filepath, 'rt')
|
fd = open(filepath, 'rb')
|
||||||
content = file.read()
|
msg = self.parser['8bit'].parse(fd)
|
||||||
file.close()
|
fd.close()
|
||||||
|
|
||||||
oldlabels = set()
|
oldlabels = set()
|
||||||
for hstr in self.getmessageheaderlist(content, self.labelsheader):
|
for hstr in self.getmessageheaderlist(msg, self.labelsheader):
|
||||||
oldlabels.update(imaputil.labels_from_header(self.labelsheader,
|
oldlabels.update(imaputil.labels_from_header(self.labelsheader,
|
||||||
hstr))
|
hstr))
|
||||||
|
|
||||||
@ -167,15 +168,14 @@ class GmailMaildirFolder(MaildirFolder):
|
|||||||
sorted(labels | ignoredlabels))
|
sorted(labels | ignoredlabels))
|
||||||
|
|
||||||
# First remove old labels header, and then add the new one.
|
# First remove old labels header, and then add the new one.
|
||||||
content = self.deletemessageheaders(content, self.labelsheader)
|
self.deletemessageheaders(msg, self.labelsheader)
|
||||||
content = self.addmessageheader(content, '\n', self.labelsheader,
|
self.addmessageheader(msg, self.labelsheader, labels_str)
|
||||||
labels_str)
|
|
||||||
|
|
||||||
mtime = int(os.stat(filepath).st_mtime)
|
mtime = int(os.stat(filepath).st_mtime)
|
||||||
|
|
||||||
# Write file with new labels to a unique file in tmp.
|
# Write file with new labels to a unique file in tmp.
|
||||||
messagename = self.new_message_filename(uid, set())
|
messagename = self.new_message_filename(uid, set())
|
||||||
tmpname = self.save_to_tmp_file(messagename, content)
|
tmpname = self.save_to_tmp_file(messagename, msg)
|
||||||
tmppath = os.path.join(self.getfullname(), tmpname)
|
tmppath = os.path.join(self.getfullname(), tmpname)
|
||||||
|
|
||||||
# Move to actual location.
|
# Move to actual location.
|
||||||
|
@ -342,19 +342,22 @@ class IMAPFolder(BaseFolder):
|
|||||||
data = self._fetch_from_imap(str(uid), self.retrycount)
|
data = self._fetch_from_imap(str(uid), self.retrycount)
|
||||||
|
|
||||||
# Data looks now e.g.
|
# Data looks now e.g.
|
||||||
# ['320 (17061 BODY[] {2565}','msgbody....']
|
# ['320 (17061 BODY[] {2565}',<email.message.EmailMessage object>]
|
||||||
# Is a list of two elements. Message is at [1]
|
# Is a list of two elements. Message is at [1]
|
||||||
data = data[1].replace(CRLF, "\n")
|
msg = data[1]
|
||||||
|
|
||||||
if len(data) > 200:
|
if self.ui.is_debugging('imap'):
|
||||||
dbg_output = "%s...%s" % (str(data)[:150], str(data)[-50:])
|
# Optimization: don't create the debugging objects unless needed
|
||||||
|
msg_s = msg.as_string(policy=self.policy['8bit-RFC'])
|
||||||
|
if len(msg_s) > 200:
|
||||||
|
dbg_output = "%s...%s" % (msg_s[:150], msg_s[-50:])
|
||||||
else:
|
else:
|
||||||
dbg_output = data
|
dbg_output = msg_s
|
||||||
|
|
||||||
self.ui.debug('imap', "Returned object from fetching %d: '%s'" %
|
self.ui.debug('imap', "Returned object from fetching %d: '%s'" %
|
||||||
(uid, dbg_output))
|
(uid, dbg_output))
|
||||||
|
|
||||||
return data
|
return msg
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def getmessagetime(self, uid):
|
def getmessagetime(self, uid):
|
||||||
@ -679,6 +682,8 @@ class IMAPFolder(BaseFolder):
|
|||||||
(headername, headervalue))
|
(headername, headervalue))
|
||||||
self.addmessageheader(msg, headername, headervalue)
|
self.addmessageheader(msg, headername, headervalue)
|
||||||
|
|
||||||
|
if self.ui.is_debugging('imap'):
|
||||||
|
# Optimization: don't create the debugging objects unless needed
|
||||||
msg_s = msg.as_string(policy=output_policy)
|
msg_s = msg.as_string(policy=output_policy)
|
||||||
if len(msg_s) > 200:
|
if len(msg_s) > 200:
|
||||||
dbg_output = "%s...%s" % (msg_s[:150], msg_s[-50:])
|
dbg_output = "%s...%s" % (msg_s[:150], msg_s[-50:])
|
||||||
@ -830,7 +835,7 @@ class IMAPFolder(BaseFolder):
|
|||||||
"""Fetches data from IMAP server.
|
"""Fetches data from IMAP server.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
- uids: message UIDS
|
- uids: message UIDS (OfflineIMAP3: First UID returned only)
|
||||||
- retry_num: number of retries to make
|
- retry_num: number of retries to make
|
||||||
|
|
||||||
Returns: data obtained by this query."""
|
Returns: data obtained by this query."""
|
||||||
@ -886,9 +891,21 @@ class IMAPFolder(BaseFolder):
|
|||||||
"with UID '%s'" % (self.getrepository(), uids)
|
"with UID '%s'" % (self.getrepository(), uids)
|
||||||
raise OfflineImapError(reason, severity)
|
raise OfflineImapError(reason, severity)
|
||||||
|
|
||||||
# Convert bytes to str
|
# JI: In offlineimap, this function returned a tuple of strings for each
|
||||||
|
# fetched UID, offlineimap3 calls to the imap object return bytes and so
|
||||||
|
# originally a fixed, utf-8 conversion was done and *only* the first
|
||||||
|
# response (d[0]) was returned. Note that this alters the behavior
|
||||||
|
# between code bases. However, it seems like a single UID is the intent
|
||||||
|
# of this function so retaining the modfication here for now.
|
||||||
|
#
|
||||||
|
# TODO: Can we assume the server response containing the meta data is
|
||||||
|
# always 'utf-8' encoded? Assuming yes for now.
|
||||||
|
#
|
||||||
|
# Convert responses, d[0][0], into a 'utf-8' string (from bytes) and
|
||||||
|
# Convert email, d[0][1], into a message object (from bytes)
|
||||||
|
|
||||||
ndata0 = data[0][0].decode('utf-8')
|
ndata0 = data[0][0].decode('utf-8')
|
||||||
ndata1 = data[0][1].decode('utf-8', errors='replace')
|
ndata1 = self.parser['8bit-RFC'].parsebytes(data[0][1])
|
||||||
ndata = [ndata0, ndata1]
|
ndata = [ndata0, ndata1]
|
||||||
|
|
||||||
return ndata
|
return ndata
|
||||||
|
@ -259,7 +259,7 @@ class MaildirFolder(BaseFolder):
|
|||||||
filename = self.messagelist[uid]['filename']
|
filename = self.messagelist[uid]['filename']
|
||||||
filepath = os.path.join(self.getfullname(), filename)
|
filepath = os.path.join(self.getfullname(), filename)
|
||||||
fd = open(filepath, 'rb')
|
fd = open(filepath, 'rb')
|
||||||
retval = self.parse['8bit'](fd)
|
retval = self.parser['8bit'].parse(fd)
|
||||||
fd.close()
|
fd.close()
|
||||||
return retval
|
return retval
|
||||||
|
|
||||||
|
@ -231,6 +231,9 @@ class UIBase:
|
|||||||
else:
|
else:
|
||||||
self.invaliddebug(debugtype)
|
self.invaliddebug(debugtype)
|
||||||
|
|
||||||
|
def is_debugging(self, debugtype):
|
||||||
|
return (debugtype in self.debuglist)
|
||||||
|
|
||||||
def debugging(self, debugtype):
|
def debugging(self, debugtype):
|
||||||
global debugtypes
|
global debugtypes
|
||||||
self.logger.debug("Now debugging for %s: %s" % (debugtype,
|
self.logger.debug("Now debugging for %s: %s" % (debugtype,
|
||||||
|
Loading…
Reference in New Issue
Block a user