Syslog.py: add type -1 to SEVERITYMAP
[enigma2-plugins.git] / growlee / src / Syslog.py
1 from __future__ import print_function
2
3 from twisted.internet.protocol import DatagramProtocol
4 from twisted.internet import reactor
5 from twisted.internet import reactor
6 from time import strftime, strptime, localtime
7 from os import uname
8
9 from Screens.MessageBox import MessageBox
10 from Tools import Notifications
11
12 from GrowleeConnection import emergencyDisable
13 from . import NOTIFICATIONID
14
15 SYSLOG_UDP_PORT = 514
16
17 FACILITY = {
18         'kern': 0, 'user': 1, 'mail': 2, 'daemon': 3,
19         'auth': 4, 'syslog': 5, 'lpr': 6, 'news': 7,
20         'uucp': 8, 'cron': 9, 'authpriv': 10, 'ftp': 11,
21         'local0': 16, 'local1': 17, 'local2': 18, 'local3': 19,
22         'local4': 20, 'local5': 21, 'local6': 22, 'local7': 23,
23 }
24
25 SEVERITY = {
26         'emerg': 0, 'alert':1, 'crit': 2, 'err': 3,
27         'warning': 4, 'notice': 5, 'info': 6, 'debug': 7
28 }
29
30 try:
31         dict.iteritems
32         reverse = lambda map: dict((v,k) for k,v in map.iteritems())
33 except AttributeError:
34         reverse = lambda map: dict((v,k) for k,v in map.items())
35
36 SEVERITYMAP = {
37         -1: SEVERITY['info'],
38         MessageBox.TYPE_YESNO: SEVERITY['debug'],
39         MessageBox.TYPE_INFO: SEVERITY['info'],
40         MessageBox.TYPE_WARNING: SEVERITY['warning'],
41         MessageBox.TYPE_ERROR: SEVERITY['err'],
42 }
43
44 class SyslogNetworkProtocol(DatagramProtocol):
45         addr = None
46         def __init__(self, host):
47                 self.host = host
48
49         def gotIP(self, ip):
50                 self.addr = (ip, SYSLOG_UDP_PORT)
51
52         def noIP(self, error):
53                 print("--------------------------------", error)
54                 emergencyDisable()
55
56         def startProtocol(self):
57                 reactor.resolve(self.host.address.value).addCallback(self.gotIP).addErrback(self.noIP)
58
59         def sendNotification(self, title='No title.', description='No message.', priority=0):
60                 if not self.transport or not self.addr or not self.host.enable_outgoing.value:
61                         return
62
63                 ltime = localtime()
64                 day = strftime("%d", ltime)
65                 if day[0] == "0":
66                         day = " " + day[1:]
67                 value = strftime("%b %%s %H:%M:%S", ltime)
68                 timestamp = value % (day,)
69                 payload = "<%d>%s %s growlee: (%s) %s" % (FACILITY['local0'] * 8 + SEVERITYMAP[priority], timestamp, uname()[1], title, description.replace('\n', ' '),)
70                 # TODO: better way to stay within the 1024 char-limit (e.g. ignore title, multiple packets, ...)
71                 #if len(payload) > 1024:
72                 #       payload = payload[:1024]
73                 self.transport.write(payload, self.addr)
74
75         def datagramReceived(self, data, addr):
76                 if not self.host.enable_incoming.value:
77                         return
78
79                 Len = len(data)
80                 # NOTE: since we're capable of handling longer messages, lets just do so
81                 # even if they do not comply to the protocol
82                 #if Len > 1024: # invalid according to rfc
83                 #       return
84
85                 # read prio field
86                 prio, data = data.split('>', 1)
87                 prio = int(prio[1:])
88                 facility, severity = divmod(prio, 8) # just the ids
89                 #facility = reverse(FACILITY)[facility]
90                 type = reverse(SEVERITYMAP).get(severity, MessageBox.TYPE_ERROR)
91
92                 # parse remaining header
93                 try:
94                         # try to parse timestamp to determine validity
95                         timestamp = strptime(data[:15], '%b %d %H:%M:%S')
96                 except ValueError:
97                         message = data
98                 else:
99                         hostname, body = data[16:].split(' ', 1)
100                         # NOTE: we could re-process timestamp to get a customized display format,
101                         # but lets just keep this for now
102                         message = hostname + ' @ ' + data[:15] + ': ' + body
103
104                 Notifications.AddNotificationWithID(
105                         NOTIFICATIONID,
106                         MessageBox,
107                         text = message,
108                         type = type,
109                         timeout = 10, # XXX: un-hardcode timeout?
110                         close_on_any_key = True,
111                 )
112
113 class SyslogAbstraction:
114         def __init__(self, host):
115                 self.syslog = SyslogNetworkProtocol(host)
116                 listeningPort = SYSLOG_UDP_PORT if host.enable_incoming.value else 0
117                 self.serverPort = reactor.listenUDP(listeningPort, self.syslog)
118
119         def sendNotification(self, title='No title.', description='No description.', priority=-1, timeout=-1):
120                 self.syslog.sendNotification(title=title, description=description, priority=priority)
121
122         def stop(self):
123                 return self.serverPort.stopListening()