"""Implement interface to MH folders.""" from slime_abstract import * import os import mhlib2 mhlib = mhlib2 # kludge until Python accepts my modified mhlib.py import StringIO2 StringIO = StringIO2 default_mh = None def mh_top_folder(): """Return SlimeFolder with top level MH folders.""" global default_mh if not default_mh: default_mh = mhlib.MH() mhroot = SlimeFolder_MHroot(default_mh) mhroot.open() mhroot.rescan_subfolders() if mhroot.list_all_subfolders(): mhroot.close() return mhroot mhroot.close() return None class SlimeFolder_MHroot(SlimeFolder): """Root of all MH folders.""" def __init__(self, mh): SlimeFolder.__init__(self) self._mh = mh self._name = mh.getpath() self._subfolders = [] def open(self): self._is_open = 1 self.rescan_subfolders() def close(self): self._is_open = 0 def commit_changes(self): self._assert_open() def rescan_messages(self): pass def rescan_subfolders(self): self._assert_open() list = [] for name in self._mh.listfolders(): if not os.path.isabs(name): name = os.path.join(self._mh.getpath(), name) new = None for subfolder in self._subfolders: if name == repr(subfolder): new = subfolder break if new is None: new = SlimeFolder_MH(name, self._mh) list.append(new) self._subfolders = list class SlimeFolder_MH(SlimeFolder): """Abstract interface to an MH mail folder.""" def __init__(self, name, mh): SlimeFolder.__init__(self) self.mh = mh self._subfolders = [] self._name = os.path.join(mh.getpath(), name) self.mh_folder = self.mh.openfolder(self._name) self._last_message_scan = 0 def open(self): self._is_open = 1 self._old_numbers = [] def close(self): """Close the folder.""" for msg in self._messages: msg.uncache_headers() self._is_open = 0 def rescan_messages(self): self._assert_open() dirname = self.mh_folder.getfullname() dirmtime = os.stat(dirname)[8] if dirmtime == self._last_message_scan: return self._last_message_scan = dirmtime seq = self.mh_folder.getsequences() if seq.has_key("unseen"): unseen = seq["unseen"] else: unseen = [] numbers = self.mh_folder.listmessages() list = [] for n in numbers: if n in self._old_numbers: for msg in self._messages: if msg._id == n: list.append(msg) break else: msg = SlimeMessage_MH(self, n) if n in unseen: msg.set_status("N") list.append(msg) self._messages = list self._old_numbers = numbers self._threads = [] def rescan_subfolders(self): oldlist = [] for old in self._subfolders: oldlist.append(repr(old)) list = [] for name in self.mh_folder.listsubfolders(): fullname = os.path.join(self.mh.getpath(), name) try: i = oldlist.index(fullname) new = self._subfolders[i] except ValueError: new = SlimeFolder_MH(name, self.mh) list.append(new) self._subfolders = list def add_message(self, file): self._assert_open() f = self.mh_folder n = f.getlast() + 1 f.createmessage(n, file) msg = SlimeMessage_MH(self, n) self._messages.append(msg) self._old_numbers.append(n) return msg def commit_changes(self): if self._dirty: self._assert_open() unseen = [] list = [] for msg in self._messages: if msg.has_status("D"): list.append(msg._id) elif msg.has_status("N"): unseen.append(msg._id) self.mh_folder.removemessages(list) seq = self.mh_folder.getsequences() if seq.has_key("unseen"): unseen.sort() seq["unseen"] = unseen self.mh_folder.putsequences(seq) self._dirty = 0 self.rescan_messages() class SlimeMessage_MH(SlimeMessage): """A SlimeMessage interface to mhlib.Message.""" def __init__(self, folder, id): SlimeMessage.__init__(self, folder) self._msg = None self._id = id def _open(self): self._folder._assert_open() self._open_count = self._open_count + 1 if not self._msg: self._msg = mhlib.Message(self._folder.mh_folder, self._id) # make sure stuff is cached if not self._cached_date: self._cache_headers() def _close(self): self._folder._assert_open() self._open_count = self._open_count - 1 if self._open_count == 0: self._msg = None def change_text(self, file): self._folder._assert_open() if self._open_count != 0: raise Error, "change_text needs closed message" filename = self._folder.mh_folder.getmessagefilename(self._id) newname = filename + '.new' f = open(newname, "w") while 1: buf = file.read(16*1024) if not buf: break f.write(buf) f.close() os.rename(newname, filename) self.uncache_headers() def main(): root = mh_top_folder() if not root: print "no MH root" else: # root.open() # root.rescan_subfolders() # print root.list_all_subfolders() # root.close() foo(root) def foo(folder): folder.open() folder.rescan_subfolders() folder.close() folder.open() folder.rescan_subfolders() print folder for sub in folder.list_all_subfolders(): foo(sub) folder.close() def profile_main(): import time f = mh_top_folder() f.open() f.rescan_subfolders() for sub in f.list_all_subfolders(): if sub.get_nice_name() == "cola-incoming": sub.open() print "computing threads" start = time.time() sub.rescan_messages() sub.list_all_threads() end = time.time() print "threads computed", end - start sub.close() f.close() if __name__ == "__main__": main()