diff --git a/scripts/procmail-to-dispatch.py b/scripts/procmail-to-dispatch.py new file mode 100644 index 0000000..3c6b036 --- /dev/null +++ b/scripts/procmail-to-dispatch.py @@ -0,0 +1,121 @@ +""" +procmail-to-dispatch.py --- use dr.botzo's Dispatch to send mail notifications + +""" + +import argparse +import getpass +import glob +import logging +import os +import re +import sys +import time +import xmlrpc.client + +# set up some basic logging +logger = logging.getLogger() +handler = logging.StreamHandler(sys.stdout) +logger.addHandler(handler) +logger.setLevel(logging.DEBUG) + +# set up config flags +parser = argparse.ArgumentParser() +parser.add_argument('-f', '--filename') +parser.add_argument('-k', '--key') +parser.add_argument('-l', '--location') +parser.add_argument('-u', '--user') +args = parser.parse_args() + +if (args.filename == None or args.key == None or args.user == None or + args.location == None): + print("script needs -f/--filename (location of .procmailrc.log) -k/--key (dispatch key to use) " + "-l/--location (url to connect to) -u/--user (user to authenticate to XML-RPC as)") + sys.exit(2) + +password = getpass.getpass("password for {0:s}: ".format(args.user)) + +drbotzo = xmlrpc.client.ServerProxy("https://{0:s}:{1:s}@{2:s}".format(args.user, password, args.location)) +if 'dispatch' not in drbotzo.system.listMethods(): + print("remote dr.botzo instance doesn't seem to implement 'dispatch'!") + sys.exit(2) + +file = open(args.filename, 'r') + +folderre = re.compile("^ Folder: (\S+)\s+\d+$") +senderre = re.compile("^From: (.*)$") +subjectre = re.compile("^Subject: (.*)$") + +# start file at the end +st_results = os.stat(args.filename) +st_size = st_results[6] +file.seek(st_size) + +def get_mail_items(filename): + sender = None + subject = None + + for num, line in enumerate(open(filename)): + if senderre.search(line): + match = senderre.search(line) + sender = match.group(1) + if subjectre.search(line): + match = subjectre.search(line) + subject = match.group(1) + + if sender and subject: + return (sender, subject) + + if sender: + return (sender, "[no subject]") + +while 1: + try: + filename = None + + where = file.tell() + line = file.readline() + if not line: + time.sleep(1) + file.seek(where) + else: + if folderre.search(line): + sender = None + subject = None + + match = folderre.search(line) + filename = match.group(1) + + # ignore /dev/null, of course + if filename == "/dev/null": + logger.debug("skipping message forwarded to /dev/null") + continue + + # ignore Spam + if filename.find(".Spam") > 0: + logger.debug("skipping spam '{0:s}'".format(filename)) + continue + + # try opening the actual path. this is a bit racey + logger.debug("trying to open '{0:s}'".format(filename)) + if os.path.isfile(filename): + logger.debug("opening '{0:s}'".format(filename)) + (sender, subject) = get_mail_items(filename) + else: + # ok... maybe something already moved it into cur. in addition + # they probably added flags at the end + filepattern = filename.replace("/new", "/cur") + "*" + for globhit in glob.glob(filepattern): + logger.debug("trying to open '{0:s}'".format(globhit)) + if os.path.isfile(globhit): + logger.debug("opening '{0:s}'".format(globhit)) + (sender, subject) = get_mail_items(globhit) + + if sender and subject: + logger.debug("notifying: '{0:s}' from {1:s}".format(subject, sender)) + drbotzo.dispatch(args.key, "'{0:s}' from {1:s}".format(subject, sender)) + except UnicodeDecodeError as e: + logger.error("Error: " + str(e) + ", skipping") + pass + +# vi:tabstop=4:expandtab:autoindent