import commands, dirutil, grp, mailbox, method, mode, os.path, pwd, re, sys import buffer, default, window from mode.mutt import MuttGrammar from lex import Grammar, PatternRule, RegionRule, PatternGroupRule from point import Point from buffer import Buffer from method import Method, Argument, arg class LineGrammar(Grammar): rules = [PatternRule(name=r'data', pattern=r'^.*\n$')] class MailMsgGrammar(Grammar): rules = [ PatternRule(name=r'mail_pgp', pattern=r'^-----BEGIN PGP SIGNED MESSAGE-----\n$'), RegionRule(r'mail_signature', r'^-----BEGIN PGP SIGNATURE-----\n$', LineGrammar, r'^-----END PGP SIGNATURE-----\n$'), PatternRule(name=r'mail_header', pattern=r'^(?:From|To|Cc|Bcc|Subject|Reply-To|In-Reply-To|Delivered-To|Date):'), PatternRule(name=r'mail_quoteb', pattern=r'^ *(?:(?: *>){3})*(?: *>){2}.*$'), PatternRule(name=r'mail_quotea', pattern=r'^ *(?:(?: *>){3})*(?: *>){1}.*$'), PatternRule(name=r'mail_quotec', pattern=r'^ *(?:(?: *>){3})*(?: *>){3}.*$'), PatternRule(name=r'mail_email', pattern=r'(?:^|(?<=[ :]))@\n ]+@(?:[^<>@\.\n ]+\.)*[^<>@\.\n ]+>?'), PatternRule(name=r'mail_url', pattern=r'(?:^|(?<= ))(?:http|https|ftp|sftp|file|smtp|smtps|torrent|news|jabber|irc|telnet)://(?:[^\.\n ]+\.)*[^\.\n ]+'), ] class MboxMsgBuffer(Buffer): btype = 'mboxmsg' def __init__(self, path, lineno, msg): Buffer.__init__(self) self.path = os.path.realpath(path) self.base = os.path.basename(self.path) self.lineno = lineno self.msg = msg def changed(self): return False def readonly(self): return True def path_exists(self): raise Exception def _make_path(self, name): raise Exception def save(self, force=False): raise Exception, "can't save an mbox message" def save_as(self, path): raise Exception, "can't save an mbox message" def name(self): return 'mbox:%s:%s' % (self.base, self.lineno) def _get_msg_lines(self, msg): if msg.is_multipart(): lines = [] for msg2 in msg.get_payload(): lines.extend(self._get_msg_lines(msg2)) return lines elif msg.get_content_type() == 'text/plain': return msg.get_payload().split('\n') else: return [] def _get_lines(self): lines = [ 'Delivered-To: ' + self.msg.get('delivered-to'), 'To: ' + self.msg.get('to'), 'From: ' + self.msg.get('from'), 'Subject: ' + self.msg.get('subject'), 'Date: ' + self.msg.get('date'), '', ] lines.extend(self._get_msg_lines(self.msg)) return lines def open(self): self.lines = self._get_lines() def reload(self): lines = self._get_lines() self.set_lines(lines, force=True) class MboxListBuffer(Buffer): btype = 'mboxlist' reverse = True format = '%(pos)4d %(replied)1.1s %(dow)3.3s %(day)2.2s %(fromname)-15.15s %(size)6.6s %(subject)-43.43s' from_re1 = re.compile(r'^ *" *([^"]+) *" *< *(.+) *> *$') from_re2 = re.compile(r'^ *([^" ].*?) *< *(.+) *> *$') from_re3 = re.compile(r'^ *([^\'" ]+) *$') from_re4 = re.compile(r'^ *([^\'" ]+) *\(([^\)]+)\) *$') date_re1 = re.compile(r'^(Sun|Mon|Tue|Wed|Thu|Fri|Sat), (\d{1,2}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d{2}):(\d{2}):(\d{2}) ([-\+]\d{4})(?: .*)?$') def __init__(self, path): Buffer.__init__(self) self.path = os.path.realpath(path) self.base = os.path.basename(self.path) self.size = 0 def changed(self): return False def readonly(self): return True def path_exists(self): raise Exception def _make_path(self, name): raise Exception def save(self, force=False): raise Exception, "can't save an mbox" def save_as(self, path): raise Exception, "can't save an mbox" def name(self): return 'mbox:%s' % (self.base) def open(self): self.lines = self._get_lines() def reload(self): lines = self._get_lines() self.set_lines(lines, force=True) def _parse_msg_from(self, msg): m = self.from_re1.match(msg['from']) if m: return m.groups() m = self.from_re2.match(msg['from']) if m: return m.groups() m = self.from_re3.match(msg['from']) if m: return m.group(1), m.group(1) m = self.from_re4.match(msg['from']) if m: return m.group(2), m.group(1) #return msg['from'], msg['from'] return 'unknown', 'unknown' def _parse_date(self, msg): m = self.date_re1.match(msg['date']) if m: return m.groups() return ('', '', '', '', '', '', '', '') def _create_msg_dict(self, pos, msg): d = {} for key in msg.keys(): d[key.lower()] = msg[key] d['fromname'], d['fromaddr'] = self._parse_msg_from(msg) d['dow'], d['day'], d['month'], d['year'], \ d['hour'], d['min'], d['sec'], d['tz'] = self._parse_date(msg) if 'A' in msg.get_flags(): d['replied'] = 'r' else: d['replied'] = ' ' d['pos'] = pos d['flags'] = ''.join(msg.get_flags()) d['size'] = len(str(msg)) for key in d: if type(d[key]) == type(''): d[key] = d[key].replace('\t', ' ') return d def _get_lines(self): f = open(self.path, 'r') self.size = len(f.read()) f.close() if sys.version_info == 4: fp = open(self.path, 'rb') self.mbox = mailbox.UnixMailbox(fp) else: self.mbox = mailbox.mbox(self.path) lines = [] pos = 1 msgs = list(self.mbox) if self.reverse: msgs.reverse() for msg in msgs: d = self._create_msg_dict(pos, msg) s = self.format % d lines.append(s) pos += 1 return lines class MboxRefresh(Method): def _execute(self, w, **vargs): w.buffer.reload() class MboxReadMsg(Method): def _execute(self, w, **vargs): b = w.buffer if w.buffer.reverse: i = len(b.mbox) - 1 - w.cursor.y else: i = w.cursor.y b = MboxMsgBuffer(b.path, i, b.mbox[i]) b.open() window.Window(b, w.application, height=0, width=0, mode_name='mboxmsg') w.application.add_buffer(b) w.application.switch_buffer(b) class MboxOpenPath(Method): args = [arg('mbox', dt="path", p="Open Mbox: ", dv=default.path_dirname, ld=True, h="mbox to open")] def _execute(self, w, **vargs): b = MboxListBuffer(vargs['mbox']) b.open() window.Window(b, w.application, height=0, width=0, mode_name='mbox') w.application.add_buffer(b) w.application.switch_buffer(b) class MboxMsg(mode.Fundamental): modename = 'MboxMsg' colors = { 'mail_pgp': ('red', 'default', 'bold'), 'mail_signature.start': ('red', 'default', 'bold'), 'mail_signature.data': ('red', 'default', 'bold'), 'mail_signature.null': ('red', 'default', 'bold'), 'mail_signature.end': ('red', 'default', 'bold'), 'mail_header': ('green', 'default', 'bold'), 'mail_email': ('cyan', 'default', 'bold'), 'mail_url': ('cyan', 'default', 'bold'), 'mail_quotea': ('yellow', 'default', 'bold'), 'mail_quoteb': ('cyan', 'default', 'bold'), 'mail_quotec': ('magenta', 'default', 'bold'), } actions = [] grammar = MailMsgGrammar def __init__(self, w): mode.Fundamental.__init__(self, w) class Mbox(mode.Fundamental): modename = 'Mbox' actions = [MboxRefresh, MboxOpenPath, MboxReadMsg] def __init__(self, w): mode.Fundamental.__init__(self, w) self.add_bindings('mbox-refresh', ('C-c r',)) self.add_bindings('mbox-read-msg', ('RETURN',)) def install(*args): Mbox.install(*args) MboxMsg.install(*args)