#! /usr/bin/python ## vim: fileencoding=utf-8 """Open Debian BTS mboxes with Mutt, à la /usr/bin/bts show --mbox. A cache of mboxes is kept, and changed mboxes will be merged with existing files instead of replacing them, so that e.g. read-status is preserved for each message. """ import os import re import sys import urllib import mailbox import tempfile import email.Parser MBOX_DIR = os.path.expanduser('~/.mail/y.bug-cache') ## def main(): if len(sys.argv) != 2: print >>sys.stderr, 'Usage: %s ' % (sys.argv[0],) sys.exit(1) bug = re.sub(r'[^0-9]', '', sys.argv[1]) if not re.match(r'\d{4,}$', bug): print >>sys.stderr, \ 'E: %s does not seem a valid number' % (sys.argv[1],) sys.exit(1) path = mbox_update(bug) invoke_mailer(path) ## def mbox_update(bug): """Return a path with an up-to-date copy of the mbox for bug.""" path = os.path.join(MBOX_DIR, bug + '.mbox') if not os.path.exists(path): f = file(path, 'wb') try: retrieve_mbox(bug, f) except: os.unlink(path) raise else: f.close() else: # make a list of Message-Id we have fp1 = file(path, 'ab+') ids1 = [ x.get('Message-Id') for x in mailbox.UnixMailbox(fp1) ] # get remote mbox again fp2 = tempfile.TemporaryFile() retrieve_mbox(bug, fp2) # parse its messages fp2.seek(0) parser = email.Parser.Parser() msgs2 = dict((x['Message-Id'], x) for x in mailbox.UnixMailbox(fp2, parser.parse)) # now append the new ones for msgid in set(msgs2.keys()) - set(ids1): fp1.write('\n' + msgs2[msgid].as_string(unixfrom=True)) return path def retrieve_mbox(bug, fileobj): """Retrieve mbox for bug from bugs.debian.org, writing it to fileobj.""" for line in urllib.urlopen( 'http://bugs.debian.org/cgi-bin/bugreport.cgi?mboxstatus=yes;mboxmaint=yes;mbox=yes;bug=%s' % (bug,)): fileobj.write(line) def invoke_mailer(path): """Exec mutt, opening path.""" os.execlp('mutt', 'mutt', '-f', path) ## if __name__ == '__main__': try: sys.exit(main()) except KeyboardInterrupt: print >>sys.stderr, '\nCancelled.' sys.exit(1)