def savemessageflags(self, uid, flags): """Change a message's flags to `flags`. Note that this function does not check against dryrun settings, so you need to ensure that it is never called in a dryrun mode.""" imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, [uid], flags) return result = imapobj.uid('store', '%d' % uid, 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert result[0] == 'OK', 'Error with store: ' + '. '.join( result[1]) finally: self.imapserver.releaseconnection(imapobj) result = result[1][0] if not result: self.messagelist[uid]['flags'] = flags else: flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS'] self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
def cachemessagelist(self): if not self.synclabels: return super(GmailFolder, self).cachemessagelist() self.messagelist = {} self.ui.collectingdata(None, self) imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. # # NB: msgsToFetch are sequential numbers, not UID's res_type, response = imapobj.fetch("'%s'" % msgsToFetch, '(FLAGS X-GM-LABELS UID)') if res_type != 'OK': raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. " % \ (self.getrepository(), self) + \ "Server responded '[%s] %s'" % \ (res_type, response), OfflineImapError.ERROR.FOLDER), \ None, exc_info()[2] finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) X-GM-LABELS (\\Inbox \\Favorites) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) m = re.search('\(([^\)]*)\)', options['X-GM-LABELS']) if m: labels = set([ imaputil.dequote(lb) for lb in imaputil.imapsplit(m.group(1)) ]) else: labels = set() labels = labels - self.ignorelabels rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime }
def cachemessagelist(self, min_date=None, min_uid=None): if not self.synclabels: return super(GmailFolder, self).cachemessagelist( min_date=min_date, min_uid=min_uid) self.dropmessagelistcache() self.ui.collectingdata(None, self) imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch( imapobj, min_date=min_date, min_uid=min_uid) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. # # NB: msgsToFetch are sequential numbers, not UID's res_type, response = imapobj.fetch("'%s'"% msgsToFetch, '(FLAGS X-GM-LABELS UID)') if res_type != 'OK': six.reraise(OfflineImapError, OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. "% (self.getrepository(), self) + "Server responded '[%s] %s'"% (res_type, response), OfflineImapError.ERROR.FOLDER), exc_info()[2]) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) X-GM-LABELS (\\Inbox \\Favorites) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] # e.g.: {'X-GM-LABELS': '("Webserver (RW.net)" "\\Inbox" GInbox)', 'FLAGS': '(\\Seen)', 'UID': '275440'} options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = int(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) # e.g.: '("Webserver (RW.net)" "\\Inbox" GInbox)' m = re.search('^[(](.*)[)]', options['X-GM-LABELS']) if m: labels = set([imaputil.dequote(lb) for lb in imaputil.imapsplit(m.group(1))]) else: labels = set() labels = labels - self.ignorelabels rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime}
def cachemessagelist(self, min_date=None, min_uid=None): self.ui.loadmessagelist(self.repository, self) self.dropmessagelistcache() imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj, min_date=min_date, min_uid=min_uid) if not msgsToFetch: return # No messages to sync. # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. fetch_msg = "%s" % msgsToFetch self.ui.debug( 'imap', "calling imaplib2 fetch command: %s %s" % (fetch_msg, '(FLAGS UID INTERNALDATE)')) res_type, response = imapobj.fetch(fetch_msg, '(FLAGS UID INTERNALDATE)') if res_type != 'OK': raise OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % (self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # Looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg. # Discard initial message number. if messagestr is None: continue messagestr = messagestr.decode('utf-8').split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if 'UID' not in options: self.ui.warn('No UID in message with options %s' % str(options), minor=1) else: uid = int(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) keywords = imaputil.flagsimap2keywords(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch( messagestr.encode('utf-8')) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'time': rtime, 'keywords': keywords } self.ui.messagelistloaded(self.repository, self, self.getmessagecount())
def new_message_filename(self, uid, flags=set()): """Creates a new unique Maildir filename :param uid: The UID`None`, or a set of maildir flags :param flags: A set of maildir flags :returns: String containing unique message filename""" timeval, timeseq = gettimeseq() return '%d_%d.%d.%s,U=%d,FMD5=%s%s2,%s' % \ (timeval, timeseq, os.getpid(), socket.gethostname(), uid, self._foldermd5, self.infosep, ''.join(sorted(imaputil.flagsimap2maildir(flags))))
def processmessagesflags(self, operation, uidlist, flags): # XXX: the imapobj.myrights(...) calls dies with an error # report from Gmail server stating that IMAP command # 'MYRIGHTS' is not implemented. So, this # `processmessagesflags` is just a copy from `IMAPFolder`, # with the references to `imapobj.myrights()` deleted This # shouldn't hurt, however, Gmail users always have full # control over all their mailboxes (apparently). if len(uidlist) > 101: # Hack for those IMAP ervers with a limited line length self.processmessagesflags(operation, uidlist[:100], flags) self.processmessagesflags(operation, uidlist[100:], flags) return imapobj = self.imapserver.acquireconnection() try: imapobj.select(self.getfullname()) r = imapobj.uid('store', imaputil.listjoin(uidlist), operation + 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert r[0] == 'OK', 'Error with store: ' + '. '.join(r[1]) r = r[1] finally: self.imapserver.releaseconnection(imapobj) needupdate = copy(uidlist) for result in r: if result == None: # Compensate for servers that don't return anything from # STORE. continue attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1]) if not ('UID' in attributehash and 'FLAGS' in attributehash): # Compensate for servers that don't return a UID attribute. continue flags = attributehash['FLAGS'] uid = long(attributehash['UID']) self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags) try: needupdate.remove(uid) except ValueError: # Let it slide if it's not in the list pass for uid in needupdate: if operation == '+': for flag in flags: if not flag in self.messagelist[uid]['flags']: self.messagelist[uid]['flags'].append(flag) self.messagelist[uid]['flags'].sort() elif operation == '-': for flag in flags: if flag in self.messagelist[uid]['flags']: self.messagelist[uid]['flags'].remove(flag)
def processmessagesflags(self, operation, uidlist, flags): if len(uidlist) > 101: # Hack for those IMAP ervers with a limited line length self.processmessagesflags(operation, uidlist[:100], flags) self.processmessagesflags(operation, uidlist[100:], flags) return imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: UIBase.getglobalui().flagstoreadonly(self, uidlist, flags) return r = imapobj.uid('store', imaputil.listjoin(uidlist), operation + 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert r[0] == 'OK', 'Error with store: ' + '. '.join(r[1]) r = r[1] finally: self.imapserver.releaseconnection(imapobj) # Some IMAP servers do not always return a result. Therefore, # only update the ones that it talks about, and manually fix # the others. needupdate = copy(uidlist) for result in r: if result == None: # Compensate for servers that don't return anything from # STORE. continue attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1]) if not ('UID' in attributehash and 'FLAGS' in attributehash): # Compensate for servers that don't return a UID attribute. continue lflags = attributehash['FLAGS'] uid = long(attributehash['UID']) self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(lflags) try: needupdate.remove(uid) except ValueError: # Let it slide if it's not in the list pass for uid in needupdate: if operation == '+': for flag in flags: if not flag in self.messagelist[uid]['flags']: self.messagelist[uid]['flags'].append(flag) self.messagelist[uid]['flags'].sort() elif operation == '-': for flag in flags: if flag in self.messagelist[uid]['flags']: self.messagelist[uid]['flags'].remove(flag)
def cachemessagelist(self): if not self.synclabels: return super(GmailFolder, self).cachemessagelist() self.ui.collectingdata(None, self) self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. # Note: msgsToFetch are sequential numbers, not UID's res_type, response = imapobj.fetch("'%s'" % msgsToFetch, '(FLAGS X-GM-LABELS UID)') if res_type != 'OK': raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % ( self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) m = re.search('\(([^\)]*)\)', options['X-GM-LABELS']) if m: labels = set([imaputil.dequote(lb) for lb in imaputil.imapsplit(m.group(1))]) else: labels = set() labels = labels - self.ignorelabels rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime}
def cachemessagelist(self): if not self.synclabels: return super(GmailFolder, self).cachemessagelist() self.ui.collectingdata(None, self) self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. data = self._fetch_from_imap(imapobj, "'%s'" % msgsToFetch, '(FLAGS X-GM-LABELS UID)') finally: self.imapserver.releaseconnection(imapobj) for messagestr in data: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) m = re.search('\(([^\)]*)\)', options['X-GM-LABELS']) if m: labels = set([ imaputil.dequote(lb) for lb in imaputil.imapsplit(m.group(1)) ]) else: labels = set() labels = labels - self.ignorelabels rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime }
def processmessagesflags(self, operation, uidlist, flags): if len(uidlist) > 101: # Hack for those IMAP ervers with a limited line length self.processmessagesflags(operation, uidlist[:100], flags) self.processmessagesflags(operation, uidlist[100:], flags) return imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, uidlist, flags) return r = imapobj.uid( "store", imaputil.uid_sequence(uidlist), operation + "FLAGS", imaputil.flagsmaildir2imap(flags) ) assert r[0] == "OK", "Error with store: " + ". ".join(r[1]) r = r[1] finally: self.imapserver.releaseconnection(imapobj) # Some IMAP servers do not always return a result. Therefore, # only update the ones that it talks about, and manually fix # the others. needupdate = list(uidlist) for result in r: if result == None: # Compensate for servers that don't return anything from # STORE. continue attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1]) if not ("UID" in attributehash and "FLAGS" in attributehash): # Compensate for servers that don't return a UID attribute. continue flagstr = attributehash["FLAGS"] uid = long(attributehash["UID"]) self.messagelist[uid]["flags"] = imaputil.flagsimap2maildir(flagstr) try: needupdate.remove(uid) except ValueError: # Let it slide if it's not in the list pass for uid in needupdate: if operation == "+": self.messagelist[uid]["flags"] |= flags elif operation == "-": self.messagelist[uid]["flags"] -= flags
def savemessageflags(self, uid, flags): imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, [uid], flags) return result = imapobj.uid("store", "%d" % uid, "FLAGS", imaputil.flagsmaildir2imap(flags)) assert result[0] == "OK", "Error with store: " + ". ".join(result[1]) finally: self.imapserver.releaseconnection(imapobj) result = result[1][0] if not result: self.messagelist[uid]["flags"] = flags else: flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])["FLAGS"] self.messagelist[uid]["flags"] = imaputil.flagsimap2maildir(flags)
def cachemessagelist(self, min_date=None, min_uid=None): self.ui.loadmessagelist(self.repository, self) self.dropmessagelistcache() imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch( imapobj, min_date=min_date, min_uid=min_uid) if not msgsToFetch: return # No messages to sync. # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. fetch_msg = "'%s'"% msgsToFetch self.ui.debug('imap', "calling imaplib2 fetch command: %s %s"% (fetch_msg, '(FLAGS UID INTERNALDATE)')) res_type, response = imapobj.fetch( fetch_msg, '(FLAGS UID INTERNALDATE)') if res_type != 'OK': raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'"% (self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # Looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg. # Discard initial message number. if messagestr is None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if 'UID' not in options: self.ui.warn('No UID in message with options %s'% str(options), minor=1) else: uid = int(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) keywords = imaputil.flagsimap2keywords(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime, 'keywords': keywords} self.ui.messagelistloaded(self.repository, self, self.getmessagecount())
def __processmessagesflags_real(self, operation, uidlist, flags): imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, uidlist, flags) return response = imapobj.uid('store', imaputil.uid_sequence(uidlist), operation + 'FLAGS', imaputil.flagsmaildir2imap(flags)) if response[0] != 'OK': raise OfflineImapError( 'Error with store: %s' % '. '.join(response[1]), OfflineImapError.ERROR.MESSAGE) response = response[1] finally: self.imapserver.releaseconnection(imapobj) # Some IMAP servers do not always return a result. Therefore, # only update the ones that it talks about, and manually fix # the others. needupdate = list(uidlist) for result in response: if result is None: # Compensate for servers that don't return anything from # STORE. continue attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1]) if not ('UID' in attributehash and 'FLAGS' in attributehash): # Compensate for servers that don't return a UID attribute. continue flagstr = attributehash['FLAGS'] uid = int(attributehash['UID']) self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir( flagstr) try: needupdate.remove(uid) except ValueError: # Let it slide if it's not in the list. pass for uid in needupdate: if operation == '+': self.messagelist[uid]['flags'] |= flags elif operation == '-': self.messagelist[uid]['flags'] -= flags
def __processmessagesflags_real(self, operation, uidlist, flags): imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, uidlist, flags) return response = imapobj.uid('store', imaputil.uid_sequence(uidlist), operation + 'FLAGS', imaputil.flagsmaildir2imap(flags)) if response[0] != 'OK': raise OfflineImapError( 'Error with store: %s'% '. '.join(response[1]), OfflineImapError.ERROR.MESSAGE) response = response[1] finally: self.imapserver.releaseconnection(imapobj) # Some IMAP servers do not always return a result. Therefore, # only update the ones that it talks about, and manually fix # the others. needupdate = list(uidlist) for result in response: if result is None: # Compensate for servers that don't return anything from # STORE. continue attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1]) if not ('UID' in attributehash and 'FLAGS' in attributehash): # Compensate for servers that don't return a UID attribute. continue flagstr = attributehash['FLAGS'] uid = int(attributehash['UID']) self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flagstr) try: needupdate.remove(uid) except ValueError: # Let it slide if it's not in the list. pass for uid in needupdate: if operation == '+': self.messagelist[uid]['flags'] |= flags elif operation == '-': self.messagelist[uid]['flags'] -= flags
def cachemessagelist(self): self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. res_type, response = imapobj.fetch("'%s'" % msgsToFetch, '(FLAGS UID)') if res_type != 'OK': raise OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % (self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'time': rtime }
def savemessageflags(self, uid, flags): imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, [uid], flags) return result = imapobj.uid('store', '%d' % uid, 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert result[0] == 'OK', 'Error with store: ' + '. '.join(r[1]) finally: self.imapserver.releaseconnection(imapobj) result = result[1][0] if not result: self.messagelist[uid]['flags'] = flags else: flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS'] self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
def savemessageflags(self, uid, flags): imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, [uid], flags) return result = imapobj.uid('store', '%d' % uid, 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert result[0] == 'OK', 'Error with store: ' + '. '.join(result[1]) finally: self.imapserver.releaseconnection(imapobj) result = result[1][0] if not result: self.messagelist[uid]['flags'] = flags else: flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS'] self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
def savemessageflags(self, uid, flags): """Sets the specified message's flags to the given set. This function moves the message to the cur or new subdir, depending on the 'S'een flag. Note that this function does not check against dryrun settings, so you need to ensure that it is never called in a dryrun mode.""" oldfilename = self.messagelist[uid]['filename'] dir_prefix, filename = os.path.split(oldfilename) # If a message has been seen, it goes into 'cur' dir_prefix = 'cur' if '\\Seen' in flags else 'new' if flags != self.messagelist[uid]['flags']: # Flags have actually changed, construct new filename Strip # off existing infostring (possibly discarding small letter # flags that dovecot uses TODO) infomatch = self.re_flagmatch.search(filename) if infomatch: filename = filename[:-len(infomatch.group())] #strip off infostr = '%s2,%s' % (self.infosep, ''.join( sorted(imaputil.flagsimap2maildir(flags)))) filename += infostr newfilename = os.path.join(dir_prefix, filename) if (newfilename != oldfilename): try: os.rename(os.path.join(self.getfullname(), oldfilename), os.path.join(self.getfullname(), newfilename)) except OSError as e: raise OfflineImapError( "Can't rename file '%s' to '%s': %s" % (oldfilename, newfilename, e[1]), OfflineImapError.ERROR.FOLDER) self.messagelist[uid]['filename'] = newfilename self.messagelist[uid]['flags'] = flags xattr.set(os.path.join(self.getfullname(), newfilename), 'org.offlineimap.flags', ' '.join(flags), namespace=xattr.NS_USER)
def savemessageflags(self, uid, flags): """Sets the specified message's flags to the given set. This function moves the message to the cur or new subdir, depending on the 'S'een flag. Note that this function does not check against dryrun settings, so you need to ensure that it is never called in a dryrun mode.""" oldfilename = self.messagelist[uid]['filename'] dir_prefix, filename = os.path.split(oldfilename) # If a message has been seen, it goes into 'cur' dir_prefix = 'cur' if '\\Seen' in flags else 'new' if flags != self.messagelist[uid]['flags']: # Flags have actually changed, construct new filename Strip # off existing infostring (possibly discarding small letter # flags that dovecot uses TODO) infomatch = self.re_flagmatch.search(filename) if infomatch: filename = filename[:-len(infomatch.group())] #strip off infostr = '%s2,%s' % (self.infosep, ''.join(sorted(imaputil.flagsimap2maildir(flags)))) filename += infostr newfilename = os.path.join(dir_prefix, filename) if (newfilename != oldfilename): try: os.rename(os.path.join(self.getfullname(), oldfilename), os.path.join(self.getfullname(), newfilename)) except OSError as e: raise OfflineImapError("Can't rename file '%s' to '%s': %s" % ( oldfilename, newfilename, e[1]), OfflineImapError.ERROR.FOLDER) self.messagelist[uid]['filename'] = newfilename self.messagelist[uid]['flags'] = flags xattr.set(os.path.join(self.getfullname(), newfilename), 'org.offlineimap.flags', ' '.join(flags), namespace=xattr.NS_USER)
def cachemessagelist(self): if not self.synclabels: return super(GmailFolder, self).cachemessagelist() self.ui.collectingdata(None, self) self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. data = self._fetch_from_imap(imapobj, "'%s'" % msgsToFetch, '(FLAGS X-GM-LABELS UID)') finally: self.imapserver.releaseconnection(imapobj) for messagestr in data: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) m = re.search('\(([^\)]*)\)', options['X-GM-LABELS']) if m: labels = set([imaputil.dequote(lb) for lb in imaputil.imapsplit(m.group(1))]) else: labels = set() labels = labels - self.ignorelabels rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime}
def savemessageflags(self, uid, flags): """Change a message's flags to `flags`. Note that this function does not check against dryrun settings, so you need to ensure that it is never called in a dryrun mode.""" imapobj = self.imapserver.acquireconnection() try: result = self._store_to_imap(imapobj, str(uid), 'FLAGS', imaputil.flagsmaildir2imap(flags)) except imapobj.readonly: self.ui.flagstoreadonly(self, [uid], flags) return finally: self.imapserver.releaseconnection(imapobj) if not result: self.messagelist[uid]['flags'] = flags else: flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS'] self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
def cachemessagelist(self): self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. res_type, response = imapobj.fetch("'%s'" % msgsToFetch, '(FLAGS UID)') if res_type != 'OK': raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % ( self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
def cachemessagelist(self, min_date=None, min_uid=None): self.ui.loadmessagelist(self.repository, self) self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj, min_date=min_date, min_uid=min_uid) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. res_type, response = imapobj.fetch("'%s'" % msgsToFetch, "(FLAGS UID INTERNALDATE)") if res_type != "OK": raise OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % (self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER, ) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(" ", 1)[1] options = imaputil.flags2hash(messagestr) if not "UID" in options: self.ui.warn("No UID in message with options %s" % str(options), minor=1) else: uid = long(options["UID"]) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options["FLAGS"]) keywords = imaputil.flagsimap2keywords(options["FLAGS"]) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {"uid": uid, "flags": flags, "time": rtime, "keywords": keywords} self.ui.messagelistloaded(self.repository, self, self.getmessagecount())
def savemessageflags(self, uid, flags): """Change a message's flags to `flags`. Note that this function does not check against dryrun settings, so you need to ensure that it is never called in a dryrun mode.""" imapobj = self.imapserver.acquireconnection() try: try: imapobj.select(self.getfullname()) except imapobj.readonly: self.ui.flagstoreadonly(self, [uid], flags) return result = imapobj.uid('store', '%d' % uid, 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert result[0] == 'OK', 'Error with store: ' + '. '.join(result[1]) finally: self.imapserver.releaseconnection(imapobj) result = result[1][0] if not result: self.messagelist[uid]['flags'] = flags else: flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS'] self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
def cachemessagelist(self): imapobj = self.imapserver.acquireconnection() self.messagelist = {} try: # Primes untagged_responses imapobj.select(self.getfullname(), readonly = 1, force = 1) try: # Some mail servers do not return an EXISTS response if # the folder is empty. maxmsgid = long(imapobj.untagged_responses['EXISTS'][0]) except KeyError: return if maxmsgid < 1: # No messages; return return # Now, get the flags and UIDs for these. # We could conceivably get rid of maxmsgid and just say # '1:*' here. response = imapobj.fetch('1:%d' % maxmsgid, '(FLAGS UID INTERNALDATE)')[1] finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # Discard the message number. messagestr = string.split(messagestr, maxsplit = 1)[1] options = imaputil.flags2hash(messagestr) if not options.has_key('UID'): UIBase.getglobalui().warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
def cachemessagelist(self): maxage = self.config.getdefaultint("Account %s" % self.accountname, "maxage", -1) maxsize = self.config.getdefaultint("Account %s" % self.accountname, "maxsize", -1) self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: res_type, imapdata = imapobj.select(self.getfullname(), True, True) if imapdata == [None] or imapdata[0] == '0': # Empty folder, no need to populate message list return # By default examine all UIDs in this folder msgsToFetch = '1:*' if (maxage != -1) | (maxsize != -1): search_cond = "(" if (maxage != -1): #find out what the oldest message is that we should look at oldest_struct = time.gmtime(time.time() - (60 * 60 * 24 * maxage)) if oldest_struct[0] < 1900: raise OfflineImapError( "maxage setting led to year %d. " "Abort syncing." % oldest_struct[0], OfflineImapError.ERROR.REPO) search_cond += "SINCE %02d-%s-%d" % ( oldest_struct[2], MonthNames[oldest_struct[1]], oldest_struct[0]) if (maxsize != -1): if (maxage != -1): # There are two conditions, add space search_cond += " " search_cond += "SMALLER %d" % maxsize search_cond += ")" res_type, res_data = imapobj.search(None, search_cond) if res_type != 'OK': raise OfflineImapError( "SEARCH in folder [%s]%s failed. " "Search string was '%s'. Server responded '[%s] %s'" % (self.getrepository(), self, search_cond, res_type, res_data), OfflineImapError.ERROR.FOLDER) # Result UIDs are seperated by space, coalesce into ranges msgsToFetch = imaputil.uid_sequence(res_data[0].split()) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. res_type, response = imapobj.fetch("'%s'" % msgsToFetch, '(FLAGS UID)') if res_type != 'OK': raise OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % (self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not 'UID' in options: self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'time': rtime }
def cachemessagelist(self): imapobj = self.imapserver.acquireconnection() self.messagelist = {} try: # Primes untagged_responses imaptype, imapdata = imapobj.select(self.getfullname(), readonly=1, force=1) maxage = self.config.getdefaultint("Account " + self.accountname, "maxage", -1) maxsize = self.config.getdefaultint("Account " + self.accountname, "maxsize", -1) if (maxage != -1) | (maxsize != -1): try: search_condition = "(" if (maxage != -1): #find out what the oldest message is that we should look at oldest_time_struct = time.gmtime(time.time() - (60 * 60 * 24 * maxage)) #format this manually - otherwise locales could cause problems monthnames_standard = ["Jan", "Feb", "Mar", "Apr", "May", \ "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"] our_monthname = monthnames_standard[ oldest_time_struct[1] - 1] daystr = "%(day)02d" % {'day': oldest_time_struct[2]} date_search_str = "SINCE " + daystr + "-" + our_monthname \ + "-" + str(oldest_time_struct[0]) search_condition += date_search_str if (maxsize != -1): if (maxage != 1): #There are two conditions - add a space search_condition += " " search_condition += "SMALLER " + self.config.getdefault( "Account " + self.accountname, "maxsize", -1) search_condition += ")" searchresult = imapobj.search(None, search_condition) #result would come back seperated by space - to change into a fetch #statement we need to change space to comma messagesToFetch = searchresult[1][0].replace(" ", ",") except KeyError: return if len(messagesToFetch) < 1: # No messages; return return else: # 1. Some mail servers do not return an EXISTS response # if the folder is empty. 2. ZIMBRA servers can return # multiple EXISTS replies in the form 500, 1000, 1500, # 1623 so check for potentially multiple replies. if imapdata == [None]: return maxmsgid = 0 for msgid in imapdata: maxmsgid = max(long(msgid), maxmsgid) maxmsgid = long(imapdata[0]) messagesToFetch = '1:%d' % maxmsgid if maxmsgid < 1: #no messages; return return # Now, get the flags and UIDs for these. # We could conceivably get rid of maxmsgid and just say # '1:*' here. response = imapobj.fetch(messagesToFetch, '(FLAGS UID)')[1] finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # Discard the message number. messagestr = messagestr.split(' ', 1)[1] options = imaputil.flags2hash(messagestr) if not options.has_key('UID'): self.ui.warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'time': rtime }
def cachemessagelist(self, min_date=None, min_uid=None): if not self.synclabels: return super(GmailFolder, self).cachemessagelist(min_date=min_date, min_uid=min_uid) self.dropmessagelistcache() self.ui.collectingdata(None, self) imapobj = self.imapserver.acquireconnection() try: msgsToFetch = self._msgs_to_fetch(imapobj, min_date=min_date, min_uid=min_uid) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. # # NB: msgsToFetch are sequential numbers, not UID's res_type, response = imapobj.fetch("%s" % msgsToFetch, '(FLAGS X-GM-LABELS UID)') if res_type != 'OK': raise OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. " % (self.getrepository(), self) + "Server responded '[%s] %s'" % (res_type, response), OfflineImapError.ERROR.FOLDER, exc_info()[2]) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) X-GM-LABELS (\\Inbox \\Favorites) UID 4807)' or None if no msg # Discard initial message number. if messagestr is None: continue messagestr = messagestr.decode('utf-8').split(' ', 1)[1] # e.g.: {'X-GM-LABELS': '("Webserver (RW.net)" "\\Inbox" GInbox)', 'FLAGS': '(\\Seen)', 'UID': '275440'} options = imaputil.flags2hash(messagestr) if 'UID' not in options: self.ui.warn('No UID in message with options %s' % str(options), minor=1) else: uid = int(options['UID']) self.messagelist[uid] = self.msglist_item_initializer(uid) flags = imaputil.flagsimap2maildir(options['FLAGS']) # e.g.: '("Webserver (RW.net)" "\\Inbox" GInbox)' m = re.search('^[(](.*)[)]', options['X-GM-LABELS']) if m: labels = set([ imaputil.dequote(lb) for lb in imaputil.imapsplit(m.group(1)) ]) else: labels = set() labels = labels - self.ignorelabels rtime = imaplibutil.Internaldate2epoch(messagestr.encode()) self.messagelist[uid] = { 'uid': uid, 'flags': flags, 'labels': labels, 'time': rtime }
def cachemessagelist(self): imapobj = self.imapserver.acquireconnection() self.messagelist = {} try: # Primes untagged_responses imaptype, imapdata = imapobj.select(self.getfullname(), readonly=1, force=1) maxage = self.config.getdefaultint("Account " + self.accountname, "maxage", -1) maxsize = self.config.getdefaultint("Account " + self.accountname, "maxsize", -1) if (maxage != -1) | (maxsize != -1): try: search_condition = "(" if maxage != -1: # find out what the oldest message is that we should look at oldest_time_struct = time.gmtime(time.time() - (60 * 60 * 24 * maxage)) # format this manually - otherwise locales could cause problems monthnames_standard = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] our_monthname = monthnames_standard[oldest_time_struct[1] - 1] daystr = "%(day)02d" % {"day": oldest_time_struct[2]} date_search_str = "SINCE " + daystr + "-" + our_monthname + "-" + str(oldest_time_struct[0]) search_condition += date_search_str if maxsize != -1: if maxage != -1: # There are two conditions - add a space search_condition += " " search_condition += "SMALLER " + self.config.getdefault( "Account " + self.accountname, "maxsize", -1 ) search_condition += ")" searchresult = imapobj.search(None, search_condition) # result would come back seperated by space - to change into a fetch # statement we need to change space to comma messagesToFetch = searchresult[1][0].replace(" ", ",") except KeyError: return if len(messagesToFetch) < 1: # No messages; return return else: # 1. Some mail servers do not return an EXISTS response # if the folder is empty. 2. ZIMBRA servers can return # multiple EXISTS replies in the form 500, 1000, 1500, # 1623 so check for potentially multiple replies. if imapdata == [None]: return maxmsgid = 0 for msgid in imapdata: maxmsgid = max(long(msgid), maxmsgid) if maxmsgid < 1: # no messages; return return messagesToFetch = "1:%d" % maxmsgid # Now, get the flags and UIDs for these. # We could conceivably get rid of maxmsgid and just say # '1:*' here. response = imapobj.fetch(messagesToFetch, "(FLAGS UID)")[1] finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # Discard the message number. messagestr = messagestr.split(" ", 1)[1] options = imaputil.flags2hash(messagestr) if not options.has_key("UID"): self.ui.warn("No UID in message with options %s" % str(options), minor=1) else: uid = long(options["UID"]) flags = imaputil.flagsimap2maildir(options["FLAGS"]) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {"uid": uid, "flags": flags, "time": rtime}
def cachemessagelist(self): maxage = self.config.getdefaultint("Account %s" % self.accountname, "maxage", -1) maxsize = self.config.getdefaultint("Account %s" % self.accountname, "maxsize", -1) self.messagelist = {} imapobj = self.imapserver.acquireconnection() try: res_type, imapdata = imapobj.select(self.getfullname(), True) if imapdata == [None] or imapdata[0] == "0": # Empty folder, no need to populate message list return # By default examine all UIDs in this folder msgsToFetch = "1:*" if (maxage != -1) | (maxsize != -1): search_cond = "(" if maxage != -1: # find out what the oldest message is that we should look at oldest_struct = time.gmtime(time.time() - (60 * 60 * 24 * maxage)) if oldest_struct[0] < 1900: raise OfflineImapError( "maxage setting led to year %d. " "Abort syncing." % oldest_struct[0], OfflineImapError.ERROR.REPO, ) search_cond += "SINCE %02d-%s-%d" % ( oldest_struct[2], MonthNames[oldest_struct[1]], oldest_struct[0], ) if maxsize != -1: if maxage != -1: # There are two conditions, add space search_cond += " " search_cond += "SMALLER %d" % maxsize search_cond += ")" res_type, res_data = imapobj.search(None, search_cond) if res_type != "OK": raise OfflineImapError( "SEARCH in folder [%s]%s failed. " "Search string was '%s'. Server responded '[%s] %s'" % (self.getrepository(), self, search_cond, res_type, res_data), OfflineImapError.ERROR.FOLDER, ) # Result UIDs are seperated by space, coalesce into ranges msgsToFetch = imaputil.uid_sequence(res_data[0].split()) if not msgsToFetch: return # No messages to sync # Get the flags and UIDs for these. single-quotes prevent # imaplib2 from quoting the sequence. res_type, response = imapobj.fetch("'%s'" % msgsToFetch, "(FLAGS UID)") if res_type != "OK": raise OfflineImapError( "FETCHING UIDs in folder [%s]%s failed. " "Server responded '[%s] %s'" % (self.getrepository(), self, res_type, response), OfflineImapError.ERROR.FOLDER, ) finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # looks like: '1 (FLAGS (\\Seen Old) UID 4807)' or None if no msg # Discard initial message number. if messagestr == None: continue messagestr = messagestr.split(" ", 1)[1] options = imaputil.flags2hash(messagestr) if not options.has_key("UID"): self.ui.warn("No UID in message with options %s" % str(options), minor=1) else: uid = long(options["UID"]) flags = imaputil.flagsimap2maildir(options["FLAGS"]) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {"uid": uid, "flags": flags, "time": rtime}
def test_05_flagsimap2maildir(self): """Test imaputil.flagsimap2maildir()""" res = imaputil.flagsimap2maildir(b'(\\Draft \\Deleted)') self.assertEqual(res, set(b'DT'))
def cachemessagelist(self): imapobj = self.imapserver.acquireconnection() self.messagelist = {} try: # Primes untagged_responses imapobj.select(self.getfullname(), readonly = 1, force = 1) maxage = self.config.getdefaultint("Account " + self.accountname, "maxage", -1) maxsize = self.config.getdefaultint("Account " + self.accountname, "maxsize", -1) if (maxage != -1) | (maxsize != -1): try: search_condition = "("; if(maxage != -1): #find out what the oldest message is that we should look at oldest_time_struct = time.gmtime(time.time() - (60*60*24*maxage)) #format this manually - otherwise locales could cause problems monthnames_standard = ["Jan", "Feb", "Mar", "Apr", "May", \ "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"] our_monthname = monthnames_standard[oldest_time_struct[1]-1] daystr = "%(day)02d" % {'day' : oldest_time_struct[2]} date_search_str = "SINCE " + daystr + "-" + our_monthname \ + "-" + str(oldest_time_struct[0]) search_condition += date_search_str if(maxsize != -1): if(maxage != 1): #There are two conditions - add a space search_condition += " " search_condition += "SMALLER " + self.config.getdefault("Account " + self.accountname, "maxsize", -1) search_condition += ")" searchresult = imapobj.search(None, search_condition) #result would come back seperated by space - to change into a fetch #statement we need to change space to comma messagesToFetch = searchresult[1][0].replace(" ", ",") except KeyError: return if len(messagesToFetch) < 1: # No messages; return return else: try: # Some mail servers do not return an EXISTS response if # the folder is empty. maxmsgid = long(imapobj.untagged_responses['EXISTS'][0]) messagesToFetch = '1:%d' % maxmsgid; except KeyError: return if maxmsgid < 1: #no messages; return return # Now, get the flags and UIDs for these. # We could conceivably get rid of maxmsgid and just say # '1:*' here. response = imapobj.fetch(messagesToFetch, '(FLAGS UID)')[1] finally: self.imapserver.releaseconnection(imapobj) for messagestr in response: # Discard the message number. messagestr = string.split(messagestr, maxsplit = 1)[1] options = imaputil.flags2hash(messagestr) if not options.has_key('UID'): UIBase.getglobalui().warn('No UID in message with options %s' %\ str(options), minor = 1) else: uid = long(options['UID']) flags = imaputil.flagsimap2maildir(options['FLAGS']) rtime = imaplibutil.Internaldate2epoch(messagestr) self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}