Release new version 2.13.0
[grml-scripts.git] / usr_bin / notifyd.py
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2005-2009 Alexander Bernauer <alex@copton.net>
4 # Copyright (C) 2005-2009 Rico Schiekel <fire@downgra.de>
5 # Copyright (C) 2005-2009 Ulrich Dangel <uli@spamt.net>
6 #
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License
9 # as published by the Free Software Foundation version 2
10 # of the License.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA.
20
21
22 """
23 example of ~/.notifyd.conf:
24 ---------------------------
25
26 import os
27
28 host = "127.0.0.1"
29 port = 8901
30 logfile = os.path.expanduser("~/.event.log")
31 osdparams = "-p bottom  --color=red --delay=4 --age=4 " \
32  "--font=\-\*\-helvetica\-medium\-r\-\*\-\*\-34\-\*\-\*\-\*\-\*\-\*\-\*\-15 " \
33      "--offset=100 --shadow=0 --lines=5 --align=right --indent=100"
34 actions = (
35     (".*", [log], True),
36     ("IRC:&bitlbee:bitlbee", [], False),
37     (".*shutdown.*", [command('sudo shutdown -h now %(msg)s')], False),
38     (".*", [libnotify], False),
39 )
40
41 """
42
43 import os
44 import sys
45 import re
46 import string
47 import socket
48 import logging
49 import getopt
50 import subprocess
51
52 default_hostname = 'localhost'
53 default_port = 1234
54 default_osd_params = osdparams = "-p bottom  --color=red --delay=4 --age=4 " \
55            "--font=\-\*\-helvetica\-medium\-r\-\*\-\*\-34\-\*\-\*\-\*\-\*\-\*\-\*\-15 " \
56             "--offset=100 --shadow=0 --lines=5 --align=right --indent=100"
57 default_logfile = None
58
59
60 def play(sound_file):
61     def play_wrapper(msg):
62         with open(os.devnull, 'w') as devnull:
63             subprocess.Popen(['/usr/bin/aplay', sound_file], stderr=devnull)
64     return play_wrapper
65
66 def execute(command):
67     def command_wrapper(msg):
68         subprocess.call(command % dict(msg = msg))
69     return command_wrapper
70
71 def osd(msg):
72     osdcmd = "/usr/bin/osd_cat"
73     osdpipe = os.popen("%s %s" % (osdcmd, osdparams), 'w')
74     osdpipe.write(msg)
75     osdpipe.close()
76
77 def libnotify(msg):
78     try:
79         import dbus
80     except ImportError:
81         sys.stderr.write('Please install python-dbus\n')
82         raise SystemExit(1)
83
84     bus = dbus.SessionBus()
85     notifyService = bus.get_object("org.freedesktop.Notifications", '/org/freedesktop/Notifications')
86     interface = dbus.Interface(notifyService, 'org.freedesktop.Notifications')
87
88     message, title = (':' + msg).split(':')[::-1][0:2]
89     if not title:
90         title, message = message, title
91     interface.Notify('notify-server', 0, 'notification-message-im', title, message, [], {'x-canonical-append':'allowed'}, -1)
92
93 def log(msg):
94     if logger:
95         logger.info(msg)
96
97 def syntax():
98     print "osd_server.py [options]"
99     print "   options:"
100     print "     -h --help       print this message"
101     print "     -H --host       host of the osd server (def: " + default_hostname + ")"
102     print "     -P --port       port of the osd server (def: " + str(default_port) + ")"
103     print "     -l --log        log file ('-' logs to stdout)"
104
105
106 env = { 'play' : play,
107         'execute' : execute,
108         'osd' : osd,
109         'libnotify' : libnotify,
110         'log' : log,
111         'host' : default_hostname,
112         'port' : default_port,
113         'logfile' : default_logfile,
114         }
115
116 default_actions = (
117     (".*", [log], True),
118     (".*", [libnotify], False),
119 )
120
121
122 default_bind = (default_hostname, default_port)
123
124 try:
125     execfile(os.path.expanduser('~/.notifyd.conf'), {}, env)
126 except IOError:
127     pass
128
129 try:
130     opts, args = getopt.getopt(sys.argv[1:], "hH:P:l:", ["help", "host=", "port=", "log="])
131 except getopt.GetoptError:
132     syntax()
133     sys.exit(2)
134
135 for opt, arg in opts:
136     if opt in ("-h", "--help"):
137         syntax()
138         sys.exit(3)
139     elif opt in ("-H", "--host"):
140         env['host'] = arg
141     elif opt in ("-P", "--port"):
142         env['port'] = int(arg)
143     elif opt in ("-l", "--log"):
144         env['logfile'] = arg
145
146
147 actions = env.get('actions', default_actions)
148 logfile_name = env.get('logfile')
149 logfile_format = env.get('logformat', '%(asctime)s %(message)s')
150 bind_address = (env['host'], env['port'])
151 osd_params = env.get('osdparams', default_osd_params)
152
153 if logfile_name:
154     logger = logging.getLogger('notify_server')
155     lformatter = logging.Formatter(logfile_format)
156     if logfile_name not in ('', '-'):
157         lfh = logging.FileHandler(logfile_name)
158         lfh.setFormatter(lformatter)
159         logger.addHandler(lfh)
160     else:
161         lout = logging.StreamHandler(sys.stdout)
162         lout.setFormatter(lformatter)
163         logger.addHandler(lout)
164     logger.setLevel(logging.INFO)
165 else:
166     logger = None
167
168 l = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
169 l.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
170 l.bind(bind_address)
171 l.listen(5)
172
173 def filter_char(c):
174     return c in string.printable + "äöüßÄÖÜ" and c or '_'
175
176 while 1:
177     try:
178         (con, addr) = l.accept()
179     except:
180         continue
181     data = con.recv(50).strip()
182     con.close()
183
184     log = ''.join(filter_char(c) for c in data)
185
186     for pattern, handlers, cont in actions:
187         if re.match(pattern, log):
188             for handler in handlers:
189                 handler(log)
190             if not cont:
191                 break