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:
		| @@ -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, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Joseph Ishac
					Joseph Ishac