Initial base-0 from arch
This commit is contained in:
		
							
								
								
									
										223
									
								
								offlineimap/folder/UIDMaps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								offlineimap/folder/UIDMaps.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,223 @@
 | 
			
		||||
# Base folder support
 | 
			
		||||
# Copyright (C) 2002 John Goerzen
 | 
			
		||||
# <jgoerzen@complete.org>
 | 
			
		||||
#
 | 
			
		||||
#    This program is free software; you can redistribute it and/or modify
 | 
			
		||||
#    it under the terms of the GNU General Public License as published by
 | 
			
		||||
#    the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
#    (at your option) any later version.
 | 
			
		||||
#
 | 
			
		||||
#    This program is distributed in the hope that it will be useful,
 | 
			
		||||
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
#    GNU General Public License for more details.
 | 
			
		||||
#
 | 
			
		||||
#    You should have received a copy of the GNU General Public License
 | 
			
		||||
#    along with this program; if not, write to the Free Software
 | 
			
		||||
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
			
		||||
 | 
			
		||||
from threading import *
 | 
			
		||||
from offlineimap import threadutil
 | 
			
		||||
from offlineimap.threadutil import InstanceLimitedThread
 | 
			
		||||
from offlineimap.ui import UIBase
 | 
			
		||||
from IMAP import IMAPFolder
 | 
			
		||||
import os.path, re
 | 
			
		||||
 | 
			
		||||
class MappingFolderMixIn:
 | 
			
		||||
    def _initmapping(self):
 | 
			
		||||
        self.maplock = Lock()
 | 
			
		||||
        (self.diskr2l, self.diskl2r) = self._loadmaps()
 | 
			
		||||
        self._mb = self.__class__.__bases__[1]
 | 
			
		||||
 | 
			
		||||
    def _getmapfilename(self):
 | 
			
		||||
        return os.path.join(self.repository.getmapdir(),
 | 
			
		||||
                            self.getfolderbasename())
 | 
			
		||||
        
 | 
			
		||||
    def _loadmaps(self):
 | 
			
		||||
        self.maplock.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            mapfilename = self._getmapfilename()
 | 
			
		||||
            if not os.path.exists(mapfilename):
 | 
			
		||||
                return ({}, {})
 | 
			
		||||
            file = open(mapfilename, 'rt')
 | 
			
		||||
            r2l = {}
 | 
			
		||||
            l2r = {}
 | 
			
		||||
            while 1:
 | 
			
		||||
                line = file.readline()
 | 
			
		||||
                if not len(line):
 | 
			
		||||
                    break
 | 
			
		||||
                line = line.strip()
 | 
			
		||||
                (str1, str2) = line.split(':')
 | 
			
		||||
                loc = long(str1)
 | 
			
		||||
                rem = long(str2)
 | 
			
		||||
                r2l[rem] = loc
 | 
			
		||||
                l2r[loc] = rem
 | 
			
		||||
            return (r2l, l2r)
 | 
			
		||||
        finally:
 | 
			
		||||
            self.maplock.release()
 | 
			
		||||
 | 
			
		||||
    def _savemaps(self, dolock = 1):
 | 
			
		||||
        mapfilename = self._getmapfilename()
 | 
			
		||||
        if dolock: self.maplock.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            file = open(mapfilename + ".tmp", 'wt')
 | 
			
		||||
            for (key, value) in self.diskl2r.iteritems():
 | 
			
		||||
                file.write("%d:%d\n" % (key, value))
 | 
			
		||||
            file.close()
 | 
			
		||||
            os.rename(mapfilename + '.tmp', mapfilename)
 | 
			
		||||
        finally:
 | 
			
		||||
            if dolock: self.maplock.release()
 | 
			
		||||
 | 
			
		||||
    def _uidlist(self, mapping, items):
 | 
			
		||||
        return [mapping[x] for x in items]
 | 
			
		||||
 | 
			
		||||
    def cachemessagelist(self):
 | 
			
		||||
        self._mb.cachemessagelist(self)
 | 
			
		||||
        reallist = self._mb.getmessagelist(self)
 | 
			
		||||
 | 
			
		||||
        self.maplock.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            # OK.  Now we've got a nice list.  First, delete things from the
 | 
			
		||||
            # summary that have been deleted from the folder.
 | 
			
		||||
 | 
			
		||||
            for luid in self.diskl2r.keys():
 | 
			
		||||
                if not reallist.has_key(luid):
 | 
			
		||||
                    ruid = self.diskl2r[luid]
 | 
			
		||||
                    del self.diskr2l[ruid]
 | 
			
		||||
                    del self.diskl2r[luid]
 | 
			
		||||
 | 
			
		||||
            # Now, assign negative UIDs to local items.
 | 
			
		||||
            self._savemaps(dolock = 0)
 | 
			
		||||
            nextneg = -1
 | 
			
		||||
 | 
			
		||||
            self.r2l = self.diskr2l.copy()
 | 
			
		||||
            self.l2r = self.diskl2r.copy()
 | 
			
		||||
 | 
			
		||||
            for luid in reallist.keys():
 | 
			
		||||
                if not self.l2r.has_key(luid):
 | 
			
		||||
                    ruid = nextneg
 | 
			
		||||
                    nextneg -= 1
 | 
			
		||||
                    self.l2r[luid] = ruid
 | 
			
		||||
                    self.r2l[ruid] = luid
 | 
			
		||||
        finally:
 | 
			
		||||
            self.maplock.release()
 | 
			
		||||
 | 
			
		||||
    def getmessagelist(self):
 | 
			
		||||
        """Gets the current message list.
 | 
			
		||||
        You must call cachemessagelist() before calling this function!"""
 | 
			
		||||
 | 
			
		||||
        retval = {}
 | 
			
		||||
        localhash = self._mb.getmessagelist(self)
 | 
			
		||||
        self.maplock.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            for key, value in localhash.items():
 | 
			
		||||
                try:
 | 
			
		||||
                    key = self.l2r[key]
 | 
			
		||||
                except KeyError:
 | 
			
		||||
                    # Sometimes, the IMAP backend may put in a new message,
 | 
			
		||||
                    # then this function acquires the lock before the system
 | 
			
		||||
                    # has the chance to note it in the mapping.  In that case,
 | 
			
		||||
                    # just ignore it.
 | 
			
		||||
                    continue
 | 
			
		||||
                value = value.copy()
 | 
			
		||||
                value['uid'] = self.l2r[value['uid']]
 | 
			
		||||
                retval[key] = value
 | 
			
		||||
            return retval
 | 
			
		||||
        finally:
 | 
			
		||||
            self.maplock.release()
 | 
			
		||||
 | 
			
		||||
    def getmessage(self, uid):
 | 
			
		||||
        """Returns the content of the specified message."""
 | 
			
		||||
        return self._mb.getmessage(self, self.r2l[uid])
 | 
			
		||||
 | 
			
		||||
    def savemessage(self, uid, content, flags):
 | 
			
		||||
        """Writes a new message, with the specified uid.
 | 
			
		||||
        If the uid is < 0, the backend should assign a new uid and return it.
 | 
			
		||||
 | 
			
		||||
        If the backend cannot assign a new uid, it returns the uid passed in
 | 
			
		||||
        WITHOUT saving the message.
 | 
			
		||||
 | 
			
		||||
        If the backend CAN assign a new uid, but cannot find out what this UID
 | 
			
		||||
        is (as is the case with many IMAP servers), it returns 0 but DOES save
 | 
			
		||||
        the message.
 | 
			
		||||
        
 | 
			
		||||
        IMAP backend should be the only one that can assign a new uid.
 | 
			
		||||
 | 
			
		||||
        If the uid is > 0, the backend should set the uid to this, if it can.
 | 
			
		||||
        If it cannot set the uid to that, it will save it anyway.
 | 
			
		||||
        It will return the uid assigned in any case.
 | 
			
		||||
        """
 | 
			
		||||
        if uid < 0:
 | 
			
		||||
            # We cannot assign a new uid.
 | 
			
		||||
            return uid
 | 
			
		||||
        if uid in self.r2l:
 | 
			
		||||
            self.savemessageflags(uid, flags)
 | 
			
		||||
            return uid
 | 
			
		||||
        newluid = self._mb.savemessage(self, -1, content, flags)
 | 
			
		||||
        if newluid < 1:
 | 
			
		||||
            raise ValueError, "Backend could not find uid for message"
 | 
			
		||||
        self.maplock.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            self.diskl2r[newluid] = uid
 | 
			
		||||
            self.diskr2l[uid] = newluid
 | 
			
		||||
            self.l2r[newluid] = uid
 | 
			
		||||
            self.r2l[uid] = newluid
 | 
			
		||||
            self._savemaps(dolock = 0)
 | 
			
		||||
        finally:
 | 
			
		||||
            self.maplock.release()
 | 
			
		||||
 | 
			
		||||
    def getmessageflags(self, uid):
 | 
			
		||||
        return self._mb.getmessageflags(self, self.r2l[uid])
 | 
			
		||||
 | 
			
		||||
    def savemessageflags(self, uid, flags):
 | 
			
		||||
        self._mb.savemessageflags(self, self.r2l[uid], flags)
 | 
			
		||||
 | 
			
		||||
    def addmessageflags(self, uid, flags):
 | 
			
		||||
        self._mb.addmessageflags(self, self.r2l[uid], flags)
 | 
			
		||||
 | 
			
		||||
    def addmessagesflags(self, uidlist, flags):
 | 
			
		||||
        self._mb.addmessagesflags(self, self._uidlist(self.r2l, uidlist),
 | 
			
		||||
                                  flags)
 | 
			
		||||
 | 
			
		||||
    def _mapped_delete(self, uidlist):
 | 
			
		||||
        self.maplock.acquire()
 | 
			
		||||
        try:
 | 
			
		||||
            needssave = 0
 | 
			
		||||
            for ruid in uidlist:
 | 
			
		||||
                luid = self.r2l[ruid]
 | 
			
		||||
                del self.r2l[ruid]
 | 
			
		||||
                del self.l2r[luid]
 | 
			
		||||
                if ruid > 0:
 | 
			
		||||
                    del self.diskr2l[ruid]
 | 
			
		||||
                    del self.diskl2r[luid]
 | 
			
		||||
                    needssave = 1
 | 
			
		||||
            if needssave:
 | 
			
		||||
                self._savemaps(dolock = 0)
 | 
			
		||||
        finally:
 | 
			
		||||
            self.maplock.release()
 | 
			
		||||
 | 
			
		||||
    def deletemessageflags(self, uid, flags):
 | 
			
		||||
        self._mb.deletemessageflags(self, self.r2l[uid], flags)
 | 
			
		||||
 | 
			
		||||
    def deletemessagesflags(self, uidlist, flags):
 | 
			
		||||
        self._mb.deletemessagesflags(self, self._uidlist(self.r2l, uidlist),
 | 
			
		||||
                                     flags)
 | 
			
		||||
 | 
			
		||||
    def deletemessage(self, uid):
 | 
			
		||||
        self._mb.deletemessage(self, self.r2l[uid])
 | 
			
		||||
        self._mapped_delete([uid])
 | 
			
		||||
 | 
			
		||||
    def deletemessages(self, uidlist):
 | 
			
		||||
        self._mb.deletemessages(self, self._uidlist(self.r2l, uidlist))
 | 
			
		||||
        self._mapped_delete(uidlist)
 | 
			
		||||
 | 
			
		||||
    #def syncmessagesto_neguid_msg(self, uid, dest, applyto, register = 1):
 | 
			
		||||
    # does not need changes because it calls functions that make the changes   
 | 
			
		||||
    # same goes for all other sync messages types.
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
# Define a class for local part of IMAP.
 | 
			
		||||
class MappedIMAPFolder(MappingFolderMixIn, IMAPFolder):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
	apply(IMAPFolder.__init__, (self,) + args, kwargs)
 | 
			
		||||
        self._initmapping()
 | 
			
		||||
		Reference in New Issue
	
	Block a user