#!/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 Growler(AbstractConsumer):
- def __init__(self):
+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
- print repr(s)
d = dict([(ss[0], len(ss) > 2 and ss[2] or None) for ss in s])
if d['tzcspew'] == 'message':
zclass = d['class'].lower()
zop = d['opcode'].lower()
zsender = d['sender'].lower()
zauth = d['auth'].lower() == 'yes'
- ztime = ':'.join(d['time'].split(' ')[3].split(':')[0:2])
+ ztime = "%02d:%02d" % time.strptime(d['time'])[3:5]
zmessage = d['message']
- id = '%s/\n%s/\n%s\n %s' % (zclass, zinstance, zsender, ztime)
+ 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, zmessage[0])
- message = '%s' % zmessage[1]
+ header = '%s (%s)' % (id, len(zmessage) > 0 and zmessage[0] or zsender)
+ message = '%s' % (len(zmessage) > 1 and zmessage[1] or '')
else:
return
- g = os.popen("growlnotify -a MacZephyr -n zephyr -d '%s' -t '%s'" % (id, header), 'w')
- g.write(message)
- g.close()
+ 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):
- if len(argv) < 2:
- print """barn-growl v.0.0.1
+ 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
-Usage:
-barn-growl USERNAME"""
- return 0
+ 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
- username = argv[1]
- principal = username
- if principal.find("@") == -1:
- principal += '@ATHENA.MIT.EDU'
- bash = "/bin/bash -lc \"kdo %s ssh %s@linerva.mit.edu 'tzc -si'\" 2>/dev/null </dev/null" % (principal, username)
- p = os.popen(bash)
- r = sexpr.SExprReader(Growler())
+ 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)
- while 1:
- [i,o,e] = select.select([p], [], [], 5)
- if i: s = p.read(1024)
- else: s = ''
+ try:
+ while 1:
+ [i,o,e] = select.select([p], [], [], 5)
+ if i: s = p.read(1024)
+ else: s = ''
- if s != '':
- r.feed(s)
+ if s != '':
+ r.feed(s)
+ except KeyboardInterrupt:
+ pass
return 0
if __name__ == "__main__":