#!/usr/bin/env python """ Subscribes to zephyr via tzc and sends messages to notification drivers (growl or libnotify). """ import sexpr import os import subprocess import fcntl import select import sys from abstfilter import AbstractConsumer import optparse import time class Notifier(AbstractConsumer): def __init__(self, usegrowl, usenotify, useprint): self.usegrowl = usegrowl self.usenotify = usenotify if usenotify: import pynotify pynotify.init("Zephyr") self.pings = {} self.pynotify = pynotify self.useprint = useprint return def feed(self, s): if s is None or type(s) is type(''): return d = dict([(ss[0], len(ss) > 2 and ss[2] or None) for ss in s]) if d['tzcspew'] == 'message': zclass = d['class'].lower() zinstance = d['instance'].lower() zop = d['opcode'].lower() zsender = d['sender'].lower() zauth = d['auth'].lower() == 'yes' ztime = "%02d:%02d" % time.strptime(d['time'])[3:5] zmessage = d['message'] idtuple = (zclass, zinstance, zsender, ztime) id = '%s/\n%s/\n%s\n %s' % idtuple if zop == 'ping': header = '%s (%s)' % (id, zsender) message = '...' elif zop == 'nil': header = '%s (%s)' % (id, len(zmessage) > 0 and zmessage[0] or zsender) message = '%s' % (len(zmessage) > 1 and zmessage[1] or '') else: return if self.useprint: print (id, header) print message if self.usegrowl: growlnotify = ['growlnotify', '-H', 'localhost', '-a', 'MacZephyr', '-n', 'zephyr', '-d', id, '-t', header] g = subprocess.Popen(growlnotify, stdin=subprocess.PIPE) g.stdin.write(message) g.stdin.close() if self.usenotify: if idtuple in self.pings: self.pings[idtuple].update(header, message) self.pings[idtuple].show() else: n = self.pynotify.Notification(header, message) n.show() if zop == 'ping': self.pings[idtuple] = n self.pings = dict(filter(lambda ((c, i, s, time), v): time == idtuple[3], self.pings.items())) def close(self): return def main(argv): parser = optparse.OptionParser(usage = '%prog [-s "username@machine"] (--growl | --notify | --print)', description = __doc__.strip()) parser.add_option('-s', '--ssh', type = 'string', default = None, dest = 'ssh', help = 'optional remote host to run tzc') parser.add_option('-g', '--growl', action = 'store_true', default = False, dest = 'growl', help = 'use growlnotify for output') parser.add_option('-n', '--notify', action = 'store_true', default = False, dest = 'notify', help = 'use notify-send for output') parser.add_option('-p', '--print', action = 'store_true', default = False, dest = 'useprint', help = 'use stdout for output') opts, args = parser.parse_args() usegrowl = opts.growl usenotify = opts.notify useprint = opts.useprint if not usegrowl and not usenotify and not useprint: parser.print_help(sys.stderr) return 1 ssh = opts.ssh if ssh is None: retval = subprocess.call(['which', 'tzc'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if retval: print 'tzc not in path. Please add -s username@machine to specify remote host.' return 1 if ssh is not None: command = "ssh -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes -o GSSAPIKeyExchange=yes %s 'tzc -si'" % ssh else: command = "tzc -si" p = os.popen(command) r = sexpr.SExprReader(Notifier(usegrowl, usenotify, useprint)) flags = fcntl.fcntl(p, fcntl.F_GETFL) fcntl.fcntl(p, fcntl.F_SETFL, flags | os.O_NONBLOCK) try: while 1: [i,o,e] = select.select([p], [], [], 5) if i: s = p.read(1024) else: s = '' if s != '': r.feed(s) except KeyboardInterrupt: pass return 0 if __name__ == "__main__": sys.exit(main(sys.argv))