pmacs3/mode/mbox.py

246 lines
9.1 KiB
Python
Raw Permalink Normal View History

import mailbox, os.path, re, sys
2008-11-10 10:18:08 -05:00
import buffer, default, window
from mode import Fundamental
2008-11-10 19:55:13 -05:00
from mode.mutt import MuttGrammar
from lex import Grammar, PatternRule, RegionRule, PatternMatchRule
2008-11-10 10:18:08 -05:00
from point import Point
from buffer import Buffer
from method import Method, Argument, arg
2009-01-28 16:28:33 -05:00
import util
2008-11-10 10:18:08 -05:00
2009-02-22 23:12:58 -05:00
cont_re = re.compile(r' *\n *| +')
2008-11-10 19:55:13 -05:00
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 ]+'),
]
2008-11-10 10:18:08 -05:00
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")
2008-11-10 10:18:08 -05:00
def name(self): return 'mbox:%s:%s' % (self.base, self.lineno)
2008-11-11 00:10:26 -05:00
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 []
2008-11-10 10:18:08 -05:00
def _get_lines(self):
2009-02-22 23:12:58 -05:00
d = {}
for name in ('delivered-to', 'to', 'from', 'subject', 'date'):
2009-03-10 10:27:20 -04:00
s = self.msg.get(name, '')
2009-02-22 23:12:58 -05:00
d[name] = cont_re.sub(' ', s.replace('\t', ' '))
2008-11-10 19:55:13 -05:00
lines = [
2009-02-22 23:12:58 -05:00
'Delivered-To: ' + d['delivered-to'],
'To: ' + d['to'],
'From: ' + d['from'],
'Subject: ' + d['subject'],
'Date: ' + d['date'],
2008-11-10 19:55:13 -05:00
'',
]
2009-02-22 23:12:58 -05:00
2008-11-11 00:10:26 -05:00
lines.extend(self._get_msg_lines(self.msg))
2008-11-10 19:55:13 -05:00
return lines
2008-11-10 10:18:08 -05:00
def open(self):
self.lines = self._get_lines()
def reload(self):
lines = self._get_lines()
self.set_lines(lines, force=True)
class MboxListBuffer(Buffer):
2008-11-11 00:10:26 -05:00
btype = 'mboxlist'
reverse = True
2009-02-22 23:12:58 -05:00
format = '%(pos)4d %(replied)1.1s %(month)3.3s %(day)2.2s %(fromname)-15.15s %(size)6.6s %(subject)s'
2008-11-11 00:10:26 -05:00
from_re1 = re.compile(r'^ *" *([^"]+) *" *< *(.+) *> *$')
from_re2 = re.compile(r'^ *([^" ].*?) *< *(.+) *> *$')
from_re3 = re.compile(r'^ *([^\'" ]+) *$')
from_re4 = re.compile(r'^ *([^\'" ]+) *\(([^\)]+)\) *$')
2009-03-10 10:53:15 -04:00
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}) ([^ ]+)(?: .*)?$')
2008-11-10 10:18:08 -05:00
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")
2008-11-10 10:18:08 -05:00
def name(self): return 'mbox:%s' % (self.base)
2008-11-11 00:10:26 -05:00
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 'unknown', 'unknown'
def _parse_date(self, msg):
2009-02-22 23:12:58 -05:00
fields = ['', '', '', '', '', '', '', '']
2008-11-11 00:10:26 -05:00
m = self.date_re1.match(msg['date'])
2009-02-22 23:12:58 -05:00
if m:
fields = list(m.groups())
fields[1] = '%02d' % int(fields[1])
return fields
2008-11-11 00:10:26 -05:00
def _create_msg_dict(self, pos, msg):
d = {}
for key in list(msg.keys()):
2008-11-11 00:10:26 -05:00
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', ' ')
2009-02-22 23:12:58 -05:00
d[key] = cont_re.sub(' ', d[key])
2008-11-11 00:10:26 -05:00
return d
2008-11-10 10:18:08 -05:00
def _get_lines(self):
f = open(self.path, 'r')
self.size = len(f.read())
f.close()
2008-11-11 11:29:49 -05:00
if sys.version_info[1] == 4:
2008-11-11 11:29:04 -05:00
fp = open(self.path, 'rb')
self.mbox = mailbox.UnixMailbox(fp)
else:
self.mbox = mailbox.mbox(self.path)
2008-11-10 10:18:08 -05:00
lines = []
pos = 1
2008-11-11 00:10:26 -05:00
msgs = list(self.mbox)
if self.reverse:
msgs.reverse()
for msg in msgs:
d = self._create_msg_dict(pos, msg)
2008-11-10 10:18:08 -05:00
s = self.format % d
2009-02-22 23:12:58 -05:00
lines.append(s.rstrip())
2008-11-10 10:18:08 -05:00
pos += 1
return lines
class MboxRefresh(Method):
def _execute(self, w, **vargs):
w.buffer.reload()
2008-11-11 00:10:26 -05:00
class MboxReadMsg(Method):
2008-11-10 10:18:08 -05:00
def _execute(self, w, **vargs):
2008-11-10 19:55:13 -05:00
b = w.buffer
2008-11-11 00:10:26 -05:00
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])
2008-11-10 19:55:13 -05:00
b.open()
window.Window(b, w.application, height=0, width=0, mode_name='mboxmsg')
w.application.add_buffer(b)
w.application.switch_buffer(b)
2008-11-10 10:18:08 -05:00
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):
2009-01-28 16:28:33 -05:00
path = util.expand_tilde(vargs['mbox'])
path = os.path.abspath(os.path.realpath(path))
b = MboxListBuffer(path)
2008-11-10 10:18:08 -05:00
b.open()
window.Window(b, w.application, height=0, width=0, mode_name='mbox')
w.application.add_buffer(b)
w.application.switch_buffer(b)
2009-02-22 23:12:58 -05:00
class MailListGrammar(Grammar):
rules = [
PatternMatchRule(
r'x', r'^( *)([0-9]+)( )(.)( )(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)( +)([0-9]+)( +)(.{16})( +)([0-9]+)( +)(.+)$',
r'spaces', r'index', r'spaces', r'flag', r'spaces', r'month',
r'spaces', r'day', r'spaces', r'sender', r'spaces', r'size',
r'spaces', r'subject'
2009-03-20 15:41:56 -04:00
),
2009-02-22 23:12:58 -05:00
]
class MboxMsg(Fundamental):
name = 'MboxMsg'
colors = {
2008-11-10 19:55:13 -05:00
'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):
Fundamental.__init__(self, w)
2008-11-10 19:55:13 -05:00
class Mbox(Fundamental):
name = 'Mbox'
grammar = MailListGrammar
actions = [MboxRefresh, MboxOpenPath, MboxReadMsg]
colors = {
2009-02-22 23:12:58 -05:00
'index': ('default', 'default', 'bold'),
'flag': ('yellow', 'default', 'bold'),
'month': ('green', 'default', 'bold'),
'dow': ('green', 'default', 'bold'),
'day': ('green', 'default', 'bold'),
'sender': ('default', 'default', 'bold'),
'size': ('cyan', 'default', 'bold'),
'subject': ('default', 'default', 'bold'),
}
2008-11-10 10:18:08 -05:00
def __init__(self, w):
Fundamental.__init__(self, w)
2008-11-10 10:18:08 -05:00
self.add_bindings('mbox-refresh', ('C-c r',))
2008-11-11 00:10:26 -05:00
self.add_bindings('mbox-read-msg', ('RETURN',))
2008-11-10 10:18:08 -05:00
2008-11-10 19:55:13 -05:00
def install(*args):
Mbox.install(*args)
MboxMsg.install(*args)