]> code.delx.au - offlineimap/blob - offlineimap/folder/LocalStatus.py
8ba5bb88c3f8cea9c92a9b7901eef4614a5e26da
[offlineimap] / offlineimap / folder / LocalStatus.py
1 # Local status cache virtual folder
2 # Copyright (C) 2002 - 2008 John Goerzen
3 # <jgoerzen@complete.org>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 from Base import BaseFolder
20 import os, threading
21
22 magicline = "OFFLINEIMAP LocalStatus CACHE DATA - DO NOT MODIFY - FORMAT 1"
23
24 class LocalStatusFolder(BaseFolder):
25 def __init__(self, root, name, repository, accountname):
26 self.name = name
27 self.root = root
28 self.sep = '.'
29 self.filename = os.path.join(root, name)
30 self.filename = repository.getfolderfilename(name)
31 self.messagelist = None
32 self.repository = repository
33 self.savelock = threading.Lock()
34 self.doautosave = 1
35 self.accountname = accountname
36 BaseFolder.__init__(self)
37
38 def getaccountname(self):
39 return self.accountname
40
41 def storesmessages(self):
42 return 0
43
44 def isnewfolder(self):
45 return not os.path.exists(self.filename)
46
47 def getname(self):
48 return self.name
49
50 def getroot(self):
51 return self.root
52
53 def getsep(self):
54 return self.sep
55
56 def getfullname(self):
57 return self.filename
58
59 def deletemessagelist(self):
60 if not self.isnewfolder():
61 os.unlink(self.filename)
62
63 def cachemessagelist(self):
64 if self.isnewfolder():
65 self.messagelist = {}
66 return
67 file = open(self.filename, "rt")
68 self.messagelist = {}
69 line = file.readline().strip()
70 if not line and not line.read()
71 # The status file is empty - should not have happened,
72 # but somehow did.
73 file.close()
74 return
75 assert(line == magicline)
76 for line in file.xreadlines():
77 line = line.strip()
78 uid, flags = line.split(':')
79 uid = long(uid)
80 flags = [x for x in flags]
81 self.messagelist[uid] = {'uid': uid, 'flags': flags}
82 file.close()
83
84 def autosave(self):
85 if self.doautosave:
86 self.save()
87
88 def save(self):
89 self.savelock.acquire()
90 try:
91 file = open(self.filename + ".tmp", "wt")
92 file.write(magicline + "\n")
93 for msg in self.messagelist.values():
94 flags = msg['flags']
95 flags.sort()
96 flags = ''.join(flags)
97 file.write("%s:%s\n" % (msg['uid'], flags))
98 file.flush()
99 os.fsync(file.fileno())
100 file.close()
101 os.rename(self.filename + ".tmp", self.filename)
102
103 try:
104 fd = os.open(os.path.dirname(self.filename), os.O_RDONLY)
105 os.fsync(fd)
106 os.close(fd)
107 except:
108 pass
109
110 finally:
111 self.savelock.release()
112
113 def getmessagelist(self):
114 return self.messagelist
115
116 def savemessage(self, uid, content, flags, rtime):
117 if uid < 0:
118 # We cannot assign a uid.
119 return uid
120
121 if uid in self.messagelist: # already have it
122 self.savemessageflags(uid, flags)
123 return uid
124
125 self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
126 self.autosave()
127 return uid
128
129 def getmessageflags(self, uid):
130 return self.messagelist[uid]['flags']
131
132 def getmessagetime(self, uid):
133 return self.messagelist[uid]['time']
134
135 def savemessageflags(self, uid, flags):
136 self.messagelist[uid]['flags'] = flags
137 self.autosave()
138
139 def deletemessage(self, uid):
140 if not uid in self.messagelist:
141 return
142 del(self.messagelist[uid])
143 self.autosave()