Initial checking of "Bonjour" plugin. It takes care of AVAHI/Zercoconf configuration.
[enigma2-plugins.git] / bonjour / src / Bonjour.py
1 # -*- coding: utf-8 -*-
2 from enigma import eConsoleAppContainer, eTimer
3 from xml.etree.cElementTree import parse as cet_parse
4 from os import path, listdir
5 from os import remove as os_remove
6
7 class Bonjour:
8         AVAHI_SERVICES_DIR = '/etc/avahi/services/'
9         AVAHI_START_SCRIPT = '/etc/init.d/avahi-daemon'
10          
11         def __init__(self):     
12                 self.services = []              
13                 self.files = {} 
14                 
15                 self.container = eConsoleAppContainer()
16                 self.container.appClosed.append(self.cmdFinished)
17                 
18                 self._timer = eTimer()
19                 self._timer.callback.append(self.restartDaemon)
20                 self._timerRunning = False
21                 
22                 self.reloadConfig()
23                 
24         def __createServiceConfig(self, service):
25                 lines = [
26                                 '<?xml version="1.0" standalone="no"?><!--*-nxml-*-->\n',
27                                 '<!DOCTYPE service-group SYSTEM "avahi-service.dtd">\n',
28                                 '<!-- This file has been created by enigma2-plugin-extensions-bonjour -->\n',                           
29                                 '<service-group>\n',
30                                 '\t<name replace-wildcards="yes">%s</name>\n' %(service['name']),
31                                 '\t<service>\n',
32                                 '\t\t<type>%s</type>\n' %(service['type']),
33                                 '\t\t<port>%s</port>\n' %(service['port']) 
34                                 ]
35                 
36                 if service['text'] is not None and service['text'] != "":
37                         lines.add('\t\t<text-record>%s</text-record>\n' %(service['text']) )
38                 
39                 lines.extend([
40                                         '\t</service>\n', 
41                                         '</service-group>\n'
42                                         ])
43                 
44                 return lines
45         
46         def __writeService(self, service):
47                 print "[Bonjour.__writeService] Creating service file '%s'" %(service['file'])  
48                 if 'type' in service and 'port' in service and 'file' in service:
49                         filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
50                         file = open(filepath, 'w');
51                         file.writelines(self.__createServiceConfig(service))
52                         file.close()
53                         return True
54                 
55                 print "[Bonjour.__writeService] Cannot create service file '%s'" %(service['file'])             
56                 return False
57         
58         def __deleteService(self, protocol):            
59                 filepath = "%s%s.service" %(self.AVAHI_SERVICES_DIR, protocol)
60                 if path.exists(filepath):
61                         
62                         os_remove(filepath)
63                         return True
64                 
65                 return False
66                                 
67         def __parse(self, file):
68                 print "[Bonjour.__parse] parsing %s%s" %(self.AVAHI_SERVICES_DIR, file) 
69                 config = cet_parse(self.AVAHI_SERVICES_DIR + file).getroot()
70                 
71                 name = config.find('name').text
72                 
73                 service = config.find('service')                
74                 type = service.find('type').text
75                 port = service.find('port').text
76                 text = service.get('text-record')
77                 if text is None:
78                         text = ""
79                 else: 
80                         text = text.text
81                 
82                 service = self.buildServiceFull(file, name, type, port, text)           
83                 self.registerService(service)
84         
85         def __removeServiceFromList(self, service):     
86                 oldservices = self.services
87                 self.services = []
88                 
89                 for s in oldservices:
90                         if s['file'] != service['file']:
91                                 self.services.append(s)
92                                 self.files[s['file']] = len(self.services) - 1
93                 
94                 self.files[service['file']] = None
95         
96         
97         def reloadConfig(self):
98                 self.services = []
99                 self.files = {}
100                 if path.exists(self.AVAHI_SERVICES_DIR):
101                         print "[Bonjour.reloadConfig] reloading config"
102                         service_files = filter( lambda x: x.endswith('.service'), listdir(self.AVAHI_SERVICES_DIR) )
103                         for file in service_files:
104                                 self.__parse(file)
105                 
106                 self.registerDefaultServices()
107
108         
109         def registerService(self, service, replace = False):
110                 print "[Bonjour.registerService] %s" %service
111                 
112                 if 'type' in service and 'port' in service and 'file' in service:                                       
113                         if (service['file'] not in self.files) or replace:
114                                 filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
115                                 if not self.__writeService(service):
116                                         return False
117                                         
118                                 if replace and service['file'] in self.files:                           
119                                         self.__removeServiceFromList(service)
120                                 
121                                 
122                                 self.services.append(service)
123                                 self.files[service['file']] = len(self.services) - 1
124                                 
125                                 if self._timerRunning:
126                                         self._timer.stop()
127                                 
128                                 #if no other service is being registered for 15 seconds restart the daemon
129                                 self._timer.start(15000)
130                                 self._timerRunning = True
131                                                                 
132                                 return True
133                                 
134                 else:
135                         print "[Bonjour.registerService] Missing port or type definition in %s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
136                         return False    
137         
138         
139         def updateService(self, service):
140                 if 'type' in service and 'port' in service and 'file' in service:
141                         
142                         filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
143                         if not path.exists(filepath):
144                                 print "[Bonjour.updateService] Cannot update non-existent service file '%s'" %(service['file'])
145                                 return False
146                         
147                         else:
148                                 if not self.__writeService(service):
149                                         print "[Bonjour.updateService] Cannot write service file '%s'" %(service['file'])
150                                         return False
151
152                 return True
153         
154         def unregisterService(self, protocol):
155                 if self.__deleteService(protocol):
156                         self.reloadConfig()
157                 
158         
159         def buildService(self, protocol, port, text="", udp = False):
160                 file = "%s.service" %protocol
161                 
162                 type = "_%s._tcp" %protocol
163                 if udp:
164                         type = "_%s._udp" %protocol     
165                 
166                 name = "%h "
167                 name += protocol.upper()
168                 
169                 return {
170                                 'file' : file,
171                                 'name' : name,
172                                 'type' : type,
173                                 'port' : port,
174                                 'text' : text
175                                 }
176         
177         def buildServiceFull(self, file, name, type, port, text="", udp = False):               
178                 return {
179                                 'file' : file,
180                                 'name' : name,
181                                 'type' : type,
182                                 'port' : port,
183                                 'text' : text
184                                 }
185         
186         def registerDefaultServices(self):
187                 print "[Bonjour.registerDefaultServices] called"
188                 service = self.buildService('ftp', '21')
189                 filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
190                 if not path.exists(filepath):
191                         self.registerService(service)
192                         
193                 service = self.buildService('ssh', '22')
194                 filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
195                 if not path.exists(filepath):
196                         self.registerService(service)
197
198                 service = self.buildService('sftp-ssh', '22')
199                 filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
200                 if not path.exists(filepath):
201                         self.registerService(service)
202
203                 service = self.buildService('smb', '139')
204                 filepath = "%s%s" %(self.AVAHI_SERVICES_DIR, service['file'])
205                 if not path.exists(filepath):
206                         self.registerService(service)
207         
208         def stopTimer(self):
209                 if self._timerRunning:
210                         self._timer.stop()
211                 
212         def startDaemon(self):
213                 print "[Bonjour.startDaemon] called"            
214                 cmd = [self.AVAHI_START_SCRIPT, 'start']
215                 self.container.execute(*cmd)
216         
217         def stopDaemon(self):
218                 print "[Bonjour.stopDaemon] called"             
219                 cmd = [self.AVAHI_START_SCRIPT, 'stop']
220                 self.container.execute(*cmd)
221         
222         def restartDaemon(self):
223                 print "[Bonjour.restartDaemon] called"
224                 self.stopTimer()
225                 
226                 cmd = [self.AVAHI_START_SCRIPT, 'restart']
227                 self.container.execute(*cmd)
228                 
229         def cmdFinished(self, data):
230                 print "[Bonjour.cmdFinished] %s" %(data)
231                         
232 bonjour = Bonjour()