1 from Plugins.Plugin import PluginDescriptor
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 from socket import gaierror
11 from Screens.Setup import SetupSummary
12 from Screens.Screen import Screen
13 from Screens.MessageBox import MessageBox
14 from Components.ActionMap import ActionMap
15 from Components.config import config, getConfigListEntry, ConfigSubsection, \
16 ConfigText, ConfigPassword, ConfigYesNo
17 from Components.ConfigList import ConfigListScreen
18 from Components.Sources.StaticText import StaticText
20 config.plugins.growlee = ConfigSubsection()
21 config.plugins.growlee.enable_incoming = ConfigYesNo(default=False)
22 config.plugins.growlee.enable_outgoing = ConfigYesNo(default=False)
23 config.plugins.growlee.address = ConfigText(fixed_size=False)
24 config.plugins.growlee.password = ConfigPassword()
26 NOTIFICATIONID = 'GrowleeReceivedNotification'
28 class GrowleeConfiguration(Screen, ConfigListScreen):
29 def __init__(self, session):
30 Screen.__init__(self, session)
31 self.skinName = [ "GrowleeConfiguration", "Setup" ]
34 self["key_red"] = StaticText(_("Cancel"))
35 self["key_green"] = StaticText(_("OK"))
38 self.setup_title = "Growlee Configuration"
39 self.onChangedEntry = []
42 self["actions"] = ActionMap(["SetupActions"],
44 "cancel": self.keyCancel,
49 ConfigListScreen.__init__(
52 getConfigListEntry(_("Receive Notifications?"), config.plugins.growlee.enable_incoming),
53 getConfigListEntry(_("Send Notifications?"), config.plugins.growlee.enable_outgoing),
54 getConfigListEntry(_("Address"), config.plugins.growlee.address),
55 getConfigListEntry(_("Password"), config.plugins.growlee.password),
58 on_change=self.changed
65 for x in self.onChangedEntry:
68 def getCurrentEntry(self):
69 return self["config"].getCurrent()[0]
71 def getCurrentValue(self):
72 return str(self["config"].getCurrent()[1].getText())
74 def createSummary(self):
78 if self["config"].isChanged():
81 def maybeConnect(*args, **kwargs):
82 if config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value:
84 port = reactor.listenUDP(GROWL_UDP_PORT, growlProtocolOneWrapper)
86 d = port.stopListening()
88 d.addCallback(maybeConnect).addErrback(emergencyDisable)
91 elif config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value:
92 port = reactor.listenUDP(GROWL_UDP_PORT, growlProtocolOneWrapper)
97 def configuration(session, **kwargs):
98 session.open(GrowleeConfiguration)
100 def emergencyDisable(*args, **kwargs):
106 if gotNotification in Notifications.notificationAdded:
107 Notifications.notificationAdded.remove(gotNotification)
108 Notifications.AddPopup(
109 _("Network error.\nDisabling Growlee!"),
110 MessageBox.TYPE_ERROR,
114 class GrowlProtocolOneWrapper(DatagramProtocol):
115 def startProtocol(self):
116 if config.plugins.growlee.enable_outgoing.value:
117 addr = (config.plugins.growlee.address.value, GROWL_UDP_PORT)
118 p = GrowlRegistrationPacket(password=config.plugins.growlee.password.value)
121 self.transport.write(p.payload(), addr)
125 def sendNotification(self, *args, **kwargs):
126 if not self.transport or not config.plugins.growlee.enable_outgoing.value:
129 addr = (config.plugins.growlee.address.value, GROWL_UDP_PORT)
130 p = GrowlNotificationPacket(*args, **kwargs)
132 self.transport.write(p.payload(), addr)
136 def datagramReceived(self, data, addr):
138 if Len < 16 or not config.plugins.growlee.enable_incoming.value:
142 password = config.plugins.growlee.password.value
143 checksum = md5_constructor()
144 checksum.update(data[:-16])
146 checksum.update(password)
147 if digest != checksum.digest():
151 if data[1] == '\x01':
152 nlen, tlen, dlen, alen = unpack("!HHHH",str(data[4:12]))
153 notification, title, description = unpack(("%ds%ds%ds") % (nlen, tlen, dlen), data[12:Len-alen-16])
155 Notifications.AddNotificationWithID(
158 text = title + '\n' + description,
159 type = MessageBox.TYPE_INFO,
161 close_on_any_key = True,
164 # TODO: do we want to handle register packets? :-)
166 growlProtocolOneWrapper = GrowlProtocolOneWrapper()
169 def gotNotification():
170 notifications = Notifications.notifications
172 _, screen, args, kwargs, id = notifications[-1]
173 if screen is MessageBox and id != NOTIFICATIONID:
176 description = kwargs["text"]
178 description = args[0]
179 description = description.decode('utf-8')
181 growlProtocolOneWrapper.sendNotification(title="Dreambox", description=description, password=config.plugins.growlee.password.value)
183 def autostart(**kwargs):
184 if config.plugins.growlee.enable_incoming.value or config.plugins.growlee.enable_outgoing.value:
186 port = reactor.listenUDP(GROWL_UDP_PORT, growlProtocolOneWrapper)
188 # NOTE: we need to be the first one to be notified since other listeners
189 # may remove the notifications from the list for good
190 Notifications.notificationAdded.insert(0, gotNotification)
192 def Plugins(**kwargs):
195 where=PluginDescriptor.WHERE_SESSIONSTART,
200 description=_("Configure Growlee"),
201 where=PluginDescriptor.WHERE_PLUGINMENU,