work around some weird utf-8 related crash
[enigma2-plugins.git] / growlee / src / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2
3 from Tools import Notifications
4 from netgrowl import GrowlRegistrationPacket, GrowlNotificationPacket, \
5                 GROWL_UDP_PORT, md5_constructor
6 from twisted.internet.protocol import DatagramProtocol
7 from twisted.internet import reactor
8 from struct import unpack
9
10 from Screens.Setup import SetupSummary
11 from Screens.Screen import Screen
12 from Screens.MessageBox import MessageBox
13 from Components.ActionMap import ActionMap
14 from Components.config import config, getConfigListEntry, ConfigSubsection, \
15                 ConfigText, ConfigPassword, ConfigYesNo
16 from Components.ConfigList import ConfigListScreen
17
18 config.plugins.growlee = ConfigSubsection()
19 config.plugins.growlee.enable_incoming = ConfigYesNo(default=False)
20 config.plugins.growlee.enable_outgoing = ConfigYesNo(default=False)
21 config.plugins.growlee.address = ConfigText(fixed_size=False)
22 config.plugins.growlee.password = ConfigPassword()
23
24 class GrowleeConfiguration(Screen, ConfigListScreen):
25         skin = """<screen title="Growlee Configuration" position="75,155" size="565,280">
26                 <widget name="config" position="5,5" size="555,100" scrollbarMode="showOnDemand" />
27         </screen>"""
28
29         def __init__(self, session):
30                 Screen.__init__(self, session)
31
32                 # Summary
33                 self.setup_title = "Growlee Configuration"
34                 self.onChangedEntry = []
35
36                 # Define Actions
37                 self["actions"] = ActionMap(["SetupActions"],
38                         {
39                                 "cancel": self.keySave,
40                         }
41                 )
42
43                 ConfigListScreen.__init__(
44                         self,
45                         [
46                                 getConfigListEntry(_("Receive Notifications?"), config.plugins.growlee.enable_incoming),
47                                 getConfigListEntry(_("Send Notifications?"), config.plugins.growlee.enable_outgoing),
48                                 getConfigListEntry(_("Address"), config.plugins.growlee.address),
49                                 getConfigListEntry(_("Password"), config.plugins.growlee.password),
50                         ],
51                         session=session,
52                         on_change=self.changed
53                 )
54
55                 # Trigger change
56                 self.changed()
57
58         def changed(self):
59                 for x in self.onChangedEntry:
60                         try:
61                                 x()
62                         except:
63                                 pass
64
65         def getCurrentEntry(self):
66                 return self["config"].getCurrent()[0]
67
68         def getCurrentValue(self):
69                 return str(self["config"].getCurrent()[1].getText())
70
71         def createSummary(self):
72                 return SetupSummary
73
74         def keySave(self):
75                 if self["config"].isChanged():
76                         global port
77                         if port:
78                                 port.stopListening()
79
80                         if config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value:
81                                 port = reactor.listenUDP(GROWL_UDP_PORT, growlProtocolOneWrapper)
82
83                 self.saveAll()
84                 self.close()
85
86 def configuration(session, **kwargs):
87         session.open(GrowleeConfiguration)
88
89 class GrowlProtocolOneWrapper(DatagramProtocol):
90         def startProtocol(self):
91                 if config.plugins.growlee.enable_outgoing.value:
92                         addr = (config.plugins.growlee.address.value, GROWL_UDP_PORT)
93                         p = GrowlRegistrationPacket(password=config.plugins.growlee.password.value)
94                         p.addNotification()
95                         self.transport.write(p.payload(), addr)
96
97         def sendNotification(self, *args, **kwargs):
98                 if not self.transport or not config.plugins.growlee.enable_outgoing.value:
99                         return
100
101                 addr = (config.plugins.growlee.address.value, GROWL_UDP_PORT)
102                 p = GrowlNotificationPacket(*args, **kwargs)
103                 self.transport.write(p.payload(), addr)
104
105         def datagramReceived(self, data, addr):
106                 Len = len(data)
107                 if Len < 16 or not config.plugins.growlee.enable_incoming.value:
108                         return
109
110                 digest = data[-16:]
111                 password = config.plugins.growlee.password.value
112                 checksum = md5_constructor()
113                 checksum.update(data[:-16])
114                 if password:
115                         checksum.update(password)
116                 if digest != checksum.digest():
117                         return
118
119                 # notify packet
120                 if data[1] == '\x01':
121                         nlen, tlen, dlen, alen = unpack("!HHHH",str(data[4:12]))
122                         notification, title, description = unpack(("%ds%ds%ds") % (nlen, tlen, dlen), data[12:Len-alen-16])
123
124                         # XXX: we should add a proper fix :-)
125                         Notifications.notificationAdded.remove(gotNotification)
126                         Notifications.AddPopup(
127                                 title + '\n' + description,
128                                 MessageBox.TYPE_INFO,
129                                 5
130                         )
131                         Notifications.notificationAdded.insert(0, gotNotification)
132
133                 # TODO: do we want to handle register packets? :-)
134
135 growlProtocolOneWrapper = GrowlProtocolOneWrapper()
136 port = None
137
138 def gotNotification():
139         notifications = Notifications.notifications
140         if notifications:
141                 _, screen, args, kwargs, _ = notifications[-1]
142                 if screen is MessageBox:
143
144                         if "text" in kwargs:
145                                 description = kwargs["text"]
146                         else:
147                                 description = args[0]
148                         description = description.decode('utf-8')
149
150                         growlProtocolOneWrapper.sendNotification(title="Dreambox", description=description, password=config.plugins.growlee.password.value)
151
152 def autostart(**kwargs):
153         if config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value:
154                 global port
155                 port = reactor.listenUDP(GROWL_UDP_PORT, growlProtocolOneWrapper)
156
157         # NOTE: we need to be the first one to be notified since other listeners
158         # may remove the notifications from the list for good
159         Notifications.notificationAdded.insert(0, gotNotification)
160
161 def Plugins(**kwargs):
162         return [
163                 PluginDescriptor(
164                         where=PluginDescriptor.WHERE_SESSIONSTART,
165                         fnc=autostart,
166                 ),
167                 PluginDescriptor(
168                         name="Growlee",
169                         description=_("Configure Growlee"), 
170                         where=PluginDescriptor.WHERE_PLUGINMENU,
171                         fnc=configuration,
172                 ),
173         ]
174