import mhlib, os, StringIO2 StringIO = StringIO2 from slime_abstract import * from mailbox import UnixMailbox, _Subfile def unix_top_folder(dirname): """Return SlimeFolder with top level Unix folders.""" dirname = os.path.expanduser(dirname) if os.path.isdir(dirname): if not os.path.isfile(os.path.join(dirname, "context")): return SlimeFolder_Unix(dirname) return None class SlimeFolder_Unix(SlimeFolder): """A SlimeFolder interface to ordinary Unix mailbox folders.""" def __init__(self, name): SlimeFolder.__init__(self) if not os.path.isabs(name): name = os.path.join(os.getcwd(), name) self._name = name self._is_dir = 0 def open(self): self._is_open = 1 if os.path.isdir(self._name): self._is_dir = 1 else: self._is_dir = 0 self._fp = open(self._name, 'r+') def close(self): for msg in self._messages: msg.uncache_headers() if not self._is_dir: self._fp = None self._is_open = 0 def rescan_messages(self): self._assert_open() if not self._is_dir: new_messages = [] mb = UnixMailbox(self._fp) while 1: m = mb.next() if not m: break mm = SlimeMessage_Unix(self, m.fp) for msg in self._messages: if mm._checksum == msg._checksum: mm = msg break mm.set_status(mm["status"]) new_messages.append(mm) self._messages = new_messages self._threads = [] def rescan_subfolders(self): self._assert_open() if self._is_dir: list = [] for pathname in os.listdir(self._name): p = os.path.join(self._name, pathname) list.append(SlimeFolder_Unix(p)) self._subfolders = list def add_message(self, file): self._assert_open() dummy = mhlib.Message('NONE', 1, file) self._fp.seek(0,2) start = self._fp.tell() self._fp.write(self._make_separator(dummy)) del dummy file.seek(0,0) while 1: buf = file.read(16*1024) if not buf: break self._fp.write(buf) end = self._fp.tell() subfile = _Subfile(self._fp, start, end) msg = SlimeMessage_Unix(self, subfile) self._messages.append(msg) return msg def commit_changes(self): self._assert_open() if not self._is_dir and self._dirty: newname = self._name + ".new" f = open(newname, "w") for msg in self._messages: if not msg.has_status("D"): f.write(self._make_separator(msg)) f.write(msg.getfulltext()) f.close() os.rename(newname, self._name) self._messages = [] self._dirty = 0 self.open() self.rescan_messages() self.rescan_subfolders() def _make_separator(self, msg): date = msg.getdate("date") if date is None: date = (1970,1,1,0,0,0,3,1,0) mon = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][date[1]] dow = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][date[6]] year = date[0] if year < 1900: year = year + 1900 name, addr = msg.getaddr("from") if not addr: addr = "foo" return "From %s %s %s %2d %2d:%02d:%02d %d\n" % \ (addr, dow, mon, date[2], date[3], date[4], date[5], year) class SlimeMessage_Unix(SlimeMessage): """A SlimeMessage interface to messages in Unix mailbox folders.""" def __init__(self, folder, subfile): SlimeMessage.__init__(self, folder) self._start = subfile.start self._stop = subfile.stop self._checksum = self._start def _open(self): self._folder._assert_open() self._open_count = self._open_count + 1 if not self._msg: self._fp = _Subfile(self._folder._fp, self._start, self._stop) self._msg = mhlib.Message('NONE', 1, self._fp) # 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 self._fp.close() def main(): f = SlimeFolder_Unix(os.path.expanduser("~/mail")) f.open() f.rescan_subfolders() for sub in f.list_all_subfolders(): sub.open() sub.rescan_messages() for msg in sub.list_all_messages()[:2]: print sub._name, msg["subject"] sub.close() print f.close() def profile_main(): import time f = unix_top_folder("~/mail") f.open() f.rescan_subfolders() for sub in f.list_all_subfolders(): if repr(sub) == "/home/liw/mail/yow3": 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()