#!/usr/bin/python

## biff-notify : v0.1

## http://devsec.org/software/misc/biff-notify

## about:
##  - monitor a list of Maildirs for new messages, and tell
##    the Gnome notification-daemon to pop up a message when
##    a new message arrives
##
## example usage:
##  biff-notify ~/.Maildir/
##
## changelog:
##  - 2009-03-12 : v0.1 : initial release
##
## - Thor Kooda
##   2009-03-12


import os
import re
import sys
import time
from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
from rfc822 import Message
import pynotify


def bail( str, err = 1 ):
    print >>sys.stderr, str
    sys.exit( err )


class PTmp( ProcessEvent ):
    def process_IN_MOVED_TO( self, event ):
        global count
        global icons_from
        global icons_subject
        if event.is_dir != False:
            return
        
        ## open ..
        path_msg = os.path.join( event.path, event.name )
        try:
            fp = open( path_msg, "r" )
        except:
            print >>sys.stderr, "error: could not open: '%s'" % path_msg
            return
        
        ## parse ..
        m = Message(fp)
        str_date = time.strftime( "%I:%M %p", m.getdate( "Date" ) )
        str_from_name, str_from_address = m.getaddr( "From" )
        if str_from_name == "":
            str_from_name = str_from_address
        str_to_names = ""
        list = m.getaddrlist( "To" )
        for realname, mailaddr in list:
            if str_to_names != "":
                str_to_names += ", "
            if realname != "":
                str_to_names += realname
            else:
                str_to_names += mailaddr
        str_subject = m.getheader( "Subject" ) or ""
        fp.close()
        
        ## print ..
        str_dir = "[ %s ]" % os.path.basename( os.path.dirname( event.path ) )
        if len(sys.argv) > 2:
            print str_dir
        print "From:", str_from_name
        print "To:", str_to_names
        print "Subject:", str_subject
        print
        
        count += 1
        title = "%s @ %s (#%d)" % ( str_from_name, str_date, count )
        body = ""
        if len(sys.argv) > 2:
            body += "%s\n" % str_dir
        body += "To: %s\nSubject: %s" % ( str_to_names, str_subject )
        icon = "mail-message-new"
        
        ## possibly change icon ..
        for r in icons_subject:
            if re.match( r, str_subject, re.I ):
                icon = icons_subject[ r ]
        for r in icons_from:
            if re.match( r, str_from_address, re.I ):
                icon = icons_from[ r ]
        
        ## notify ..
        pynotify.init( "biff-notify" )
        n = pynotify.Notification( title, body, icon )
        n.set_urgency( pynotify.URGENCY_NORMAL )
        n.set_timeout( pynotify.EXPIRES_NEVER )
        n.show()


icons_subject = {
    "^fwd:": "mail-forward",
    "^re:": "mail-reply-sender",
    ".*other subject": "edit-paste",
    }

icons_from = {
    "root@example\.com": "media-record",
    "postmaster@example\.com": "dialog-warning",
    ".*@.*\.net": "dialog-warning",
    "jdoe@": "document-new",
    }

# other possibly decent icons:
# "mail-forward"
# "mail-mark-not-junk"
# "mail-message-new"
# "mail-reply-all"
# "mail-reply-sender"
# "mail-send-receive"
# "contact-new"
# "bookmark-new"
# "document-new"
# "edit-copy"
 
count = 0
watches = []

if __name__ == '__main__':
    if len(sys.argv) < 2:
        bail( "usage: %s <maildir|mbox> [maildir|mbox ...]" % sys.argv[0], 2 )
    
    ## init ..
    wm = WatchManager()
    notifier = Notifier( wm, PTmp() )
    
    for arg in sys.argv[1:]:
        new = os.path.join( arg, "new" )
        if not os.path.isdir( new ):
            continue
        wdd = wm.add_watch( new, EventsCodes.IN_MOVED_TO, rec=True )
        print >>sys.stderr, "watching: %s" % arg
    
    ## loop ..
    while True:
        try:
            notifier.process_events()
            if notifier.check_events():
                notifier.read_events()
        except KeyboardInterrupt:
            notifier.stop()
            break

