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
	 John Goerzen
					John Goerzen