Initial checking of "Bonjour" plugin. It takes care of AVAHI/Zercoconf configuration.
authorStephan Reichholf <sreichholf@users.schwerkraft.elitedvb.net>
Mon, 26 Jul 2010 23:05:24 +0000 (23:05 +0000)
committerStephan Reichholf <sreichholf@users.schwerkraft.elitedvb.net>
Mon, 26 Jul 2010 23:05:24 +0000 (23:05 +0000)
Plugins providing network-services can register with this plugin, which will then take care of the proper avahi-configuration.

THIS PLUGIN IS VERY BETA!

Makefile.am
bonjour/CONTROL/control [new file with mode: 0644]
bonjour/Makefile.am [new file with mode: 0644]
bonjour/meta/Makefile.am [new file with mode: 0644]
bonjour/meta/bonjour.jpg [new file with mode: 0644]
bonjour/meta/plugin_bonjour.xml [new file with mode: 0644]
bonjour/src/Bonjour.py [new file with mode: 0644]
bonjour/src/Makefile.am [new file with mode: 0644]
bonjour/src/__init__.py [new file with mode: 0644]
bonjour/src/plugin.py [new file with mode: 0644]
configure.ac

index 0075c7c..c433c7e 100644 (file)
@@ -7,6 +7,7 @@ SUBDIRS = \
        autoresolution \
        autotimer \
        babelzapper \
+       bonjour \
        cdinfo \
        dreamirc \
        dvdbackup \
diff --git a/bonjour/CONTROL/control b/bonjour/CONTROL/control
new file mode 100644 (file)
index 0000000..acc5e0b
--- /dev/null
@@ -0,0 +1,10 @@
+Package: enigma2-plugin-extensions-bonjour
+Version: 0.1
+Description: Bonjour/avahi-daemon management for your Dreambox
+Section: extra
+Priority: optional
+Maintainer: Stephan Reichholf <stephan@reichholf.net>
+Architecture: noarch
+Homepage: http://enigma2-plugins.schwerkraft.elitedvb.net/
+Depends: enigma2,avahi-daemon
+Source: http://enigma2-plugins.schwerkraft.elitedvb.net/
\ No newline at end of file
diff --git a/bonjour/Makefile.am b/bonjour/Makefile.am
new file mode 100644 (file)
index 0000000..1e238b4
--- /dev/null
@@ -0,0 +1,14 @@
+SUBDIRS = src meta
+
+PWD=$(shell pwd)
+
+ipkg: enigma2-plugin-extensions-bonjour.ipk
+
+enigma2-plugin-extensions-bonjour.ipk:
+       make install DESTDIR=${PWD}/ipkg/INSTALL
+       tar czf ipkg/data.tar.gz -C ipkg/INSTALL/ .
+       echo 2.0 > ipkg/debian-binary
+       tar czf ipkg/control.tar.gz -C CONTROL/ ./control
+       rm -f $@
+       ar q $@ ipkg/control.tar.gz ipkg/debian-binary ipkg/data.tar.gz
+       rm -rf ipkg/
diff --git a/bonjour/meta/Makefile.am b/bonjour/meta/Makefile.am
new file mode 100644 (file)
index 0000000..0a679fb
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = $(datadir)/meta/
+
+dist_install_DATA = plugin_bonjour.xml
+
+EXTRA_DIST = bonjour.jpg
\ No newline at end of file
diff --git a/bonjour/meta/bonjour.jpg b/bonjour/meta/bonjour.jpg
new file mode 100644 (file)
index 0000000..5113b66
Binary files /dev/null and b/bonjour/meta/bonjour.jpg differ
diff --git a/bonjour/meta/plugin_bonjour.xml b/bonjour/meta/plugin_bonjour.xml
new file mode 100644 (file)
index 0000000..87a6539
--- /dev/null
@@ -0,0 +1,24 @@
+<default>
+         <prerequisites>
+                    <tag type="Network" />
+         </prerequisites>
+          <info language="en">
+                    <author>Reichi</author>
+                    <name>Bonjour</name>
+                    <packagename>enigma2-plugin-extensions-bonjour</packagename>
+                    <shortdescription>Bonjour/Avahi control plugin</shortdescription>
+                    <description>Bonjour/Avahi control plugin</description>
+                    <screenshot src="http://www.dreamboxupdate.com/preview/plugin_bonjour.jpg" />                  
+          </info>
+          <info language="de">
+                    <author>Reichi</author>
+                    <name>Bonjour</name>
+                    <packagename>enigma2-plugin-extensions-bonjour</packagename>
+                    <shortdescription>Bonjour/Avahi kontroll plugin</shortdescription>
+                    <description>Bonjour/Avahi kontroll plugin</description>
+                    <screenshot src="http://www.dreamboxupdate.com/preview/plugin_bonjour.jpg" />      
+          </info>
+         <files type="package"> <!-- without version, without .ipk -->
+               <file type="package" name="enigma2-plugin-extensions-bonjour" />
+         </files>
+</default>
diff --git a/bonjour/src/Bonjour.py b/bonjour/src/Bonjour.py
new file mode 100644 (file)
index 0000000..55f60a5
--- /dev/null
@@ -0,0 +1,232 @@
+# -*- coding: utf-8 -*-
+from enigma import eConsoleAppContainer, eTimer
+from xml.etree.cElementTree import parse as cet_parse
+from os import path, listdir
+from os import remove as os_remove
+
+class Bonjour:
+       AVAHI_SERVICES_DIR = '/etc/avahi/services/'
+       AVAHI_START_SCRIPT = '/etc/init.d/avahi-daemon'
+        
+       def __init__(self):     
+               self.services = []              
+               self.files = {} 
+               
+               self.container = eConsoleAppContainer()
+               self.container.appClosed.append(self.cmdFinished)
+               
+               self._timer = eTimer()
+               self._timer.callback.append(self.restartDaemon)
+               self._timerRunning = False
+               
+               self.reloadConfig()
+               
+       def __createServiceConfig(self, service):
+               lines = [
+                               '<?xml version="1.0" standalone="no"?><!--*-nxml-*-->\n',
+                               '<!DOCTYPE service-group SYSTEM "avahi-service.dtd">\n',
+                               '<!-- This file has been created by enigma2-plugin-extensions-bonjour -->\n',                           
+                               '<service-group>\n',
+                               '\t<name replace-wildcards="yes">%s</name>\n' %(service['name']),
+                               '\t<service>\n',
+                               '\t\t<type>%s</type>\n' %(service['type']),
+                               '\t\t<port>%s</port>\n' %(service['port']) 
+                               ]
+               
+               if service['text'] is not None and service['text'] != "":
+                       lines.add('\t\t<text-record>%s</text-record>\n' %(service['text']) )
+               
+               lines.extend([
+                                       '\t</service>\n', 
+                                       '</service-group>\n'
+                                       ])
+               
+               return lines
+       
+       def __writeService(self, service):
+               print "[Bonjour.__writeService] Creating service file '%s'" %(service['file'])  
+               if 'type' in service and 'port' in service and 'file' in service:
+                       filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+                       file = open(filepath, 'w');
+                       file.writelines(self.__createServiceConfig(service))
+                       file.close()
+                       return True
+               
+               print "[Bonjour.__writeService] Cannot create service file '%s'" %(service['file'])             
+               return False
+       
+       def __deleteService(self, protocol):            
+               filepath = "%s%s.service" %(self.AVAHI_SERVICES_DIR, protocol)
+               if path.exists(filepath):
+                       
+                       os_remove(filepath)
+                       return True
+               
+               return False
+                               
+       def __parse(self, file):
+               print "[Bonjour.__parse] parsing %s%s" %(self.AVAHI_SERVICES_DIR, file) 
+               config = cet_parse(self.AVAHI_SERVICES_DIR + file).getroot()
+               
+               name = config.find('name').text
+               
+               service = config.find('service')                
+               type = service.find('type').text
+               port = service.find('port').text
+               text = service.get('text-record')
+               if text is None:
+                       text = ""
+               else: 
+                       text = text.text
+               
+               service = self.buildServiceFull(file, name, type, port, text)           
+               self.registerService(service)
+       
+       def __removeServiceFromList(self, service):     
+               oldservices = self.services
+               self.services = []
+               
+               for s in oldservices:
+                       if s['file'] != service['file']:
+                               self.services.append(s)
+                               self.files[s['file']] = len(self.services) - 1
+               
+               self.files[service['file']] = None
+       
+       
+       def reloadConfig(self):
+               self.services = []
+               self.files = {}
+               if path.exists(self.AVAHI_SERVICES_DIR):
+                       print "[Bonjour.reloadConfig] reloading config"
+                       service_files = filter( lambda x: x.endswith('.service'), listdir(self.AVAHI_SERVICES_DIR) )
+                       for file in service_files:
+                               self.__parse(file)
+               
+               self.registerDefaultServices()
+
+       
+       def registerService(self, service, replace = False):
+               print "[Bonjour.registerService] %s" %service
+               
+               if 'type' in service and 'port' in service and 'file' in service:                                       
+                       if (service['file'] not in self.files) or replace:
+                               filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+                               if not self.__writeService(service):
+                                       return False
+                                       
+                               if replace and service['file'] in self.files:                           
+                                       self.__removeServiceFromList(service)
+                               
+                               
+                               self.services.append(service)
+                               self.files[service['file']] = len(self.services) - 1
+                               
+                               if self._timerRunning:
+                                       self._timer.stop()
+                               
+                               #if no other service is being registered for 15 seconds restart the daemon
+                               self._timer.start(15000)
+                               self._timerRunning = True
+                                                               
+                               return True
+                               
+               else:
+                       print "[Bonjour.registerService] Missing port or type definition in %s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+                       return False    
+       
+       
+       def updateService(self, service):
+               if 'type' in service and 'port' in service and 'file' in service:
+                       
+                       filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+                       if not path.exists(filepath):
+                               print "[Bonjour.updateService] Cannot update non-existent service file '%s'" %(service['file'])
+                               return False
+                       
+                       else:
+                               if not self.__writeService(service):
+                                       print "[Bonjour.updateService] Cannot write service file '%s'" %(service['file'])
+                                       return False
+
+               return True
+       
+       def unregisterService(self, protocol):
+               if self.__deleteService(protocol):
+                       self.reloadConfig()
+               
+       
+       def buildService(self, protocol, port, text="", udp = False):
+               file = "%s.service" %protocol
+               
+               type = "_%s._tcp" %protocol
+               if udp:
+                       type = "_%s._udp" %protocol     
+               
+               name = "%h "
+               name += protocol.upper()
+               
+               return {
+                               'file' : file,
+                               'name' : name,
+                               'type' : type,
+                               'port' : port,
+                               'text' : text
+                               }
+       
+       def buildServiceFull(self, file, name, type, port, text="", udp = False):               
+               return {
+                               'file' : file,
+                               'name' : name,
+                               'type' : type,
+                               'port' : port,
+                               'text' : text
+                               }
+       
+       def registerDefaultServices(self):
+               print "[Bonjour.registerDefaultServices] called"
+               service = self.buildService('ftp', '21')
+               filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+               if not path.exists(filepath):
+                       self.registerService(service)
+                       
+               service = self.buildService('ssh', '22')
+               filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+               if not path.exists(filepath):
+                       self.registerService(service)
+
+               service = self.buildService('sftp-ssh', '22')
+               filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+               if not path.exists(filepath):
+                       self.registerService(service)
+
+               service = self.buildService('smb', '139')
+               filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
+               if not path.exists(filepath):
+                       self.registerService(service)
+       
+       def stopTimer(self):
+               if self._timerRunning:
+                       self._timer.stop()
+               
+       def startDaemon(self):
+               print "[Bonjour.startDaemon] called"            
+               cmd = [self.AVAHI_START_SCRIPT, 'start']
+               self.container.execute(*cmd)
+       
+       def stopDaemon(self):
+               print "[Bonjour.stopDaemon] called"             
+               cmd = [self.AVAHI_START_SCRIPT, 'stop']
+               self.container.execute(*cmd)
+       
+       def restartDaemon(self):
+               print "[Bonjour.restartDaemon] called"
+               self.stopTimer()
+               
+               cmd = [self.AVAHI_START_SCRIPT, 'restart']
+               self.container.execute(*cmd)
+               
+       def cmdFinished(self, data):
+               print "[Bonjour.cmdFinished] %s" %(data)
+                       
+bonjour = Bonjour()
\ No newline at end of file
diff --git a/bonjour/src/Makefile.am b/bonjour/src/Makefile.am
new file mode 100644 (file)
index 0000000..d5f4adb
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = $(LIBDIR)/enigma2/python/Plugins/Extensions/Bonjour
+
+install_PYTHON = __init__.py plugin.py Bonjour.py
diff --git a/bonjour/src/__init__.py b/bonjour/src/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/bonjour/src/plugin.py b/bonjour/src/plugin.py
new file mode 100644 (file)
index 0000000..e2fbc3c
--- /dev/null
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+
+from enigma import eListboxPythonMultiContent, gFont
+
+from Plugins.Plugin import PluginDescriptor
+from Bonjour import bonjour
+
+from Screens.Screen import Screen
+from Components.MenuList import MenuList
+from Components.MultiContent import MultiContentEntryText
+from Components.ActionMap import ActionMap
+
+class BonjourScreen(Screen):   
+       skin = """
+       <screen position="center,center" size="600,400" title="Bonjour" >
+               <widget name="menuList" position="10,10" size="580,380" scrollbarMode="showOnDemand" />
+       </screen>"""
+       
+       def __init__(self, session, services, files):
+               Screen.__init__(self, session)
+               self.session = session
+               self.services = services
+               self.files = files
+               
+               self["menuList"] = MenuList([], content=eListboxPythonMultiContent)
+               self["menuList"].l.setItemHeight(75)
+               self["menuList"].l.setFont(0, gFont("Regular", 20) )
+               self["menuList"].l.setFont(1, gFont("Regular", 16) )
+               
+               self["actions"] = ActionMap(["OkCancelActions"],
+                       {
+                        "ok": self._ok,
+                        "cancel": self._exit,
+                        }, -1)
+               
+               self.onLayoutFinish.append(self.buildMenu)
+               self.onLayoutFinish.append(self.layoutFinished)
+                                                               
+       def layoutFinished(self):
+               print "LAYOUT FINISHED!!"
+               self.setTitle(_("Bonjour: Overview"))
+                                                                               
+       def _ok(self):
+               print "OK OK OK OK"
+               pass
+       
+       def _exit(self):
+               self.close()
+               
+       def buildMenu(self):
+               list = []
+               for key in sorted(self.files):
+                       if self.files[key] != None:
+                               list.append( self.__buildMenuEntry(self.services[self.files[key]]) )
+               
+               self["menuList"].l.setList(list)
+               self["menuList"].setList(list)
+               
+       def __buildMenuEntry(self, service):
+               print "[Bonjour.__buildMenuEntry] service=%s" %service
+               
+               file = "%s" %(service['file'])
+               name = "Name: %s" %(service['name'])
+               type = "Type: %s" %(service['type'].split('.')[0].replace('_',''))
+               prot = "Protocol: %s" %(service['type'].split('.')[1].replace('_',''))
+               port = "Port: %s" %(service['port'])
+               text = "Text: %s" %(service['text'])
+               
+               return [
+                       service,
+                       MultiContentEntryText(pos=(5, 0), size=(185, 30), font=0, text=file),
+                       MultiContentEntryText(pos=(190, 0), size=(385, 30), font=0, text=name),
+                       MultiContentEntryText(pos=(5, 25), size=(150, 30), font=1, text=type),
+                       MultiContentEntryText(pos=(160, 25), size=(150, 30), font=1, text=prot),
+                       MultiContentEntryText(pos=(315, 25), size=(150, 30), font=1, text=port),
+                       MultiContentEntryText(pos=(5, 45), size=(570, 30), font=1, text=text)
+               ]
+               
+def opencontrol(session):
+       bonjour.reloadConfig()
+       session.open(BonjourScreen, bonjour.services, bonjour.files)
+       print "[Bonjour.opencontrol] %s" %(bonjour.files)
+       #TODO GUI-Stuff
+
+       
+def Plugins(**kwargs):
+       return [ PluginDescriptor(
+                                                       name=_("Bonjour"), description=_("Control Bonjour (avahi-daemon)"),
+                                                       where=[PluginDescriptor.WHERE_PLUGINMENU], icon="plugin.png", fnc=opencontrol)
+                       ]
index 6fbcc96..76dff3d 100644 (file)
@@ -63,6 +63,10 @@ babelzapper/etc/Makefile
 babelzapper/meta/Makefile
 babelzapper/src/Makefile
 
+bonjour/Makefile
+bonjour/meta/Makefile
+bonjour/src/Makefile
+
 cdinfo/Makefile
 cdinfo/meta/Makefile
 cdinfo/src/Makefile