915f209e9b98fed635662e16510d983801512011
[vuplus_dvbapp] / lib / python / Plugins / Extensions / SatipClient / plugin.py
1 from Screens.Screen import Screen
2 from Components.ConfigList import ConfigListScreen
3 from Components.config import config, ConfigSubsection, ConfigSelection, getConfigListEntry
4 from Components.ActionMap import ActionMap
5 from Screens.MessageBox import MessageBox
6 from Components.Sources.StaticText import StaticText
7 from Plugins.Plugin import PluginDescriptor
8 from Tools.Directories import fileExists
9
10 from Components.MenuList import MenuList
11 from Components.Sources.List import List
12
13 from enigma import eTimer
14 from Screens.Standby import TryQuitMainloop
15 from Components.Network import iNetwork
16
17 from Tools.LoadPixmap import LoadPixmap
18 from Tools.Directories import pathExists, fileExists, resolveFilename, SCOPE_CURRENT_SKIN
19
20 import xml.etree.cElementTree
21 from twisted.internet import reactor, task
22 from twisted.internet.protocol import DatagramProtocol
23
24 import glob
25 import os
26 import httplib
27
28 import copy
29
30 from Components.config import config, ConfigSubList, ConfigSelection, ConfigElement
31
32 def isEmpty(x):
33                 return len(x) == 0
34
35 def getVtunerList():
36         data = []
37         for x in glob.glob('/dev/misc/vtuner*'):
38                 x = x.strip('/dev/misc/vtuner')
39                 data.append(x)
40         data.sort()
41         return data
42
43 VTUNER_IDX_LIST = getVtunerList()
44
45 SSDP_ADDR = '239.255.255.250'
46 SSDP_PORT = 1900
47 MAN = "ssdp:discover"
48 MX = 2
49 ST = "urn:ses-com:device:SatIPServer:1"
50 MS = 'M-SEARCH * HTTP/1.1\r\nHOST: %s:%d\r\nMAN: "%s"\r\nMX: %d\r\nST: %s\r\n\r\n' % (SSDP_ADDR, SSDP_PORT, MAN, MX, ST)
51
52 class SSDPServerDiscovery(DatagramProtocol):
53         def __init__(self, callback, iface = None):
54                 self.callback = callback
55                 self.port = None
56
57         def send_msearch(self, iface):
58                 if not iface:
59                         return
60
61                 self.port = reactor.listenUDP(0, self, interface=iface)
62                 if self.port is not None:
63                         print "Sending M-SEARCH..."
64                         self.port.write(MS, (SSDP_ADDR, SSDP_PORT))
65
66         def stop_msearch(self):
67                 if self.port is not None:
68                         self.port.stopListening()
69
70         def datagramReceived(self, datagram, address):
71 #               print "Received: (from %r)" % (address,)
72 #               print "%s" % (datagram )
73                 self.callback(datagram)
74
75         def stop(self):
76                 pass
77
78 SATIPSERVERDATA = {}
79
80 DEVICE_ATTR = [ 
81 'friendlyName',
82 'manufacturer',
83 'manufacturerURL',
84 'modelDescription',
85 'modelName',
86 'modelNumber',
87 'modelURL',
88 'serialNumber',
89 'presentationURL'
90 ]
91
92 discoveryTimeoutMS = 2000;
93
94 class SATIPDiscovery:
95         def __init__(self):
96                 self.discoveryStartTimer = eTimer()
97                 self.discoveryStartTimer.callback.append(self.DiscoveryStart)
98
99                 self.discoveryStopTimer = eTimer()
100                 self.discoveryStopTimer.callback.append(self.DiscoveryStop)
101
102                 self.ssdp = SSDPServerDiscovery(self.dataReceive)
103                 self.updateCallback = []
104
105         def formatAddr(self, address):
106                 if not address:
107                         return None
108
109                 return "%d.%d.%d.%d"%(address[0],address[1],address[2],address[3])
110
111         def getEthernetAddr(self):
112                 return self.formatAddr(iNetwork.getAdapterAttribute("eth0", "ip") )
113
114         def DiscoveryTimerStart(self):
115                 self.discoveryStartTimer.start(10, True)
116
117         def DiscoveryStart(self, stop_timeout = discoveryTimeoutMS):
118                 self.discoveryStopTimer.stop()
119                 self.ssdp.stop_msearch()
120                 
121 #               print "Discovery Start!"
122                 self.ssdp.send_msearch(self.getEthernetAddr())
123                 self.discoveryStopTimer.start(stop_timeout, True)
124
125         def DiscoveryStop(self):
126 #               print "Discovery Stop!"
127                 self.ssdp.stop_msearch()
128
129                 for x in self.updateCallback:
130                         x()
131
132         def dataReceive(self, data):
133 #               print "dataReceive:\n", data
134 #               print "\n"
135                 serverData = self.dataParse(data)
136                 if serverData.has_key('LOCATION'):
137                         self.xmlParse(serverData['LOCATION'])
138
139         def dataParse(self, data):
140                 serverData = {}
141                 for line in data.splitlines():
142 #                       print "[*] line : ", line
143                         if line.find(':') != -1:
144                                 (attr, value) = line.split(':', 1)
145                                 attr = attr.strip().upper()
146                                 if not serverData.has_key(attr):
147                                         serverData[attr] = value.strip()
148
149 #               for (key, value) in serverData.items():
150 #                       print "[%s] %s" % (key, value)
151 #               print "\n"
152                 return serverData
153
154         def xmlParse(self, location):
155                 def findChild(parent, tag, namespace):
156                         return parent.find('{%s}%s' % (namespace, tag))
157
158                 def getAttr(root, parent, tag, namespace):
159                         try:
160                                 pElem = findChild(root, parent, namespace)
161                                 if pElem is not None:
162                                         child = findChild(pElem, tag, namespace)
163                                         if child is not None:
164                                                 return child.text
165                         except:
166                                 pass
167
168                         return None
169
170                 def getAttrN2(root, parent, tag, namespace_1 , namespace_2):
171                         try:
172                                 pElem = findChild(root, parent, namespace_1)
173                                 if pElem is not None:
174                                         child = findChild(pElem, tag, namespace_2)
175                                         if child is not None:
176                                                 return child.text
177                         except:
178                                 pass
179
180                         return None
181
182                 def dumpData():
183                         print "\n######## SATIPSERVERDATA ########"
184                         for (k, v) in SATIPSERVERDATA.items():
185 #                               prestr = "[%s]" % k
186                                 prestr = ""
187                                 for (k2, v2) in v.items():
188                                         prestr2 = prestr + "[%s]" % k2
189                                         if not isinstance(v2, dict):
190                                                 print "%s %s" % (prestr2, v2)
191                                                 continue
192                                         for (k3, v3) in v2.items():
193                                                 prestr3 = prestr2 + "[%s]" % k3
194                                                 print "%s %s" % (prestr3, v3)
195                         print ""
196
197                 print "[SATIPClient] Parsing %s" % location
198
199                 address = ""
200                 port = None
201                 request = ""
202
203                 try:
204                         location = location.strip().split("http://")[1]
205                         AAA = location.find(':')
206                         BBB = location.find('/')
207
208                         address = location[:AAA]
209                         port = int(location[AAA+1 : BBB])
210                         request = location[BBB:]
211 #                       print "address : ", address
212 #                       print "port: " , port
213 #                       print "request : ", request
214
215                         conn = httplib.HTTPConnection(address, port)
216                         conn.request("GET", request)
217                         res = conn.getresponse()
218                 except Exception, ErrMsg:
219                         print "http request error %s" % ErrMsg
220                         return -1
221
222                 if res.status != 200 or res.reason !="OK":
223                         print "response error"
224                         return -1
225
226                 data = res.read()
227                 conn.close()
228
229                 # parseing xml data
230                 root = xml.etree.cElementTree.fromstring(data)
231
232                 xmlns_dev = "urn:schemas-upnp-org:device-1-0"
233                 xmlns_satip = "urn:ses-com:satip"
234
235                 udn = getAttr(root, 'device', 'UDN', xmlns_dev)
236                 if udn is None:
237                         return -1;
238
239                 uuid = udn.strip('uuid:')
240                 SATIPSERVERDATA[uuid] = {}
241
242                 SATIPSERVERDATA[uuid]['ipaddress'] = address
243
244                 pTag = 'device'
245                 SATIPSERVERDATA[uuid][pTag] = {}
246                 for tag in DEVICE_ATTR:
247                         SATIPSERVERDATA[uuid][pTag][tag] = getAttr(root, pTag, tag, xmlns_dev)
248
249                 tagList = ['X_SATIPCAP']
250                 for tag in tagList:
251                         SATIPSERVERDATA[uuid][pTag][tag] = getAttrN2(root, pTag, tag, xmlns_dev, xmlns_satip)
252
253                 pTag = 'specVersion'
254                 SATIPSERVERDATA[uuid][pTag] = {}
255                 tagList = ['major', 'minor']
256                 for tag in tagList:
257                         SATIPSERVERDATA[uuid][pTag][tag] = getAttr(root, pTag, tag, xmlns_dev)
258
259 #               dumpData()
260
261         def isEmptyServerData(self):
262                 return isEmpty(SATIPSERVERDATA)
263
264         def getServerData(self):
265                 return SATIPSERVERDATA
266
267         def getServerKeys(self):
268                 return SATIPSERVERDATA.keys()
269
270         def getServerInfo(self, uuid, attr):
271                 if attr in ["ipaddress"]:
272                         return SATIPSERVERDATA[uuid][attr]
273
274                 elif attr in DEVICE_ATTR + ['X_SATIPCAP']:
275                         return SATIPSERVERDATA[uuid]["device"][attr]
276
277                 elif attr in ['major', 'minor']:
278                         return SATIPSERVERDATA[uuid]["specVersion"][attr]
279                 else:
280                         return "Unknown"
281
282         def getServerDescFromIP(self, ip):
283                 for (uuid, data) in SATIPSERVERDATA.items():
284                         if data.get('ipaddress') == ip:
285                                 return data['device'].get('modelName')
286                 return 'Unknown'
287
288         def getUUIDFromIP(self, ip):
289                 for (uuid, data) in SATIPSERVERDATA.items():
290                         if data.get('ipaddress') == ip:
291                                 return uuid
292                 return None
293
294 satipdiscovery = SATIPDiscovery()
295 SATIP_CONF_CHANGED = False
296
297 class SATIPTuner(Screen, ConfigListScreen):
298         skin =  """
299                 <screen position="center,center" size="590,370">
300                         <ePixmap pixmap="skin_default/buttons/red.png" position="40,0" size="140,40" alphatest="on" />
301                         <ePixmap pixmap="skin_default/buttons/green.png" position="230,0" size="140,40" alphatest="on" />
302                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="420,0" size="140,40" alphatest="on" />
303                         <widget source="key_red" render="Label" position="40,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
304                         <widget source="key_green" render="Label" position="230,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
305                         <widget source="key_yellow" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" foregroundColor="#ffffff" transparent="1" />
306                         <widget name="config" zPosition="2" position="20,70" size="550,50" scrollbarMode="showOnDemand" transparent="1" />
307                         <widget source="description" render="Label" position="20,120" size="550,210" font="Regular;20" halign="left" valign="center" />
308                         <widget source="choices" render="Label" position="20,330" size="550,40" font="Regular;20" halign="center" valign="center" />
309                 </screen>
310         """
311         def __init__(self, session, vtuner_idx, vtuner_uuid, vtuner_type, current_satipConfig):
312                 Screen.__init__(self, session)
313                 self.setTitle(_("SAT>IP Client Tuner Setup"))
314                 self.skin = SATIPTuner.skin
315                 self.session = session
316                 self.vtuner_idx = vtuner_idx
317                 self.vtuner_uuid = vtuner_uuid
318                 self.vtuner_type = vtuner_type
319                 self.current_satipConfig = current_satipConfig
320
321                 self["key_red"] = StaticText(_("Cancel"))
322                 self["key_green"] = StaticText(_("Ok"))
323                 self["key_yellow"] = StaticText(_("Discover"))
324                 self["description"] = StaticText(_("Starting..."))
325                 self["choices"] = StaticText(_(" "))
326
327                 self["shortcuts"] = ActionMap(["SATIPCliActions" ],
328                 {
329                         "ok": self.keySave,
330                         "cancel": self.keyCancel,
331                         "red": self.keyCancel,
332                         "green": self.keySave,
333                         "yellow" : self.DiscoveryStart,
334                 }, -2)
335
336                 self.list = []
337                 ConfigListScreen.__init__(self, self.list, session = self.session)
338                 self.satipconfig = ConfigSubsection()
339                 self.satipconfig.server = None
340
341                 if not self.discoveryEnd in satipdiscovery.updateCallback:
342                         satipdiscovery.updateCallback.append(self.discoveryEnd)
343
344                 self.onClose.append(self.OnClose)
345
346                 if satipdiscovery.isEmptyServerData():
347                         self.onLayoutFinish.append(self.DiscoveryStart)
348                 else:
349                         self.createServerConfig()
350                         self.createSetup()
351
352         def OnClose(self):
353                 if self.discoveryEnd in satipdiscovery.updateCallback:
354                         satipdiscovery.updateCallback.remove(self.discoveryEnd)
355
356                 satipdiscovery.DiscoveryStop()
357
358         def DiscoveryStart(self):
359                 self["shortcuts"].setEnabled(False)
360                 self["config_actions"].setEnabled(False)
361                 self["description"].setText(_("SAT>IP server discovering for %d seconds..." % (discoveryTimeoutMS / 1000)))
362                 satipdiscovery.DiscoveryStart()
363
364         def discoveryEnd(self):
365                 self["shortcuts"].setEnabled(True)
366                 self["config_actions"].setEnabled(True)
367                 if not satipdiscovery.isEmptyServerData():
368                         self.createServerConfig()
369                         self.createSetup()
370                 else:
371                         self["description"].setText(_("SAT>IP server is not detected."))
372
373         def createServerConfig(self):
374                 if satipdiscovery.isEmptyServerData():
375                         return
376
377                 server_choices = []
378
379                 server_default = None
380                 for uuid in satipdiscovery.getServerKeys():
381                         description = satipdiscovery.getServerInfo(uuid, "modelName")
382                         server_choices.append( (uuid, description) )
383                         if self.vtuner_uuid == uuid:
384                                 server_default = uuid
385
386                 if server_default is None:
387                         server_default = server_choices[0][0]
388
389                 self.satipconfig.server = ConfigSelection(default = server_default, choices = server_choices )
390
391         def createSetup(self):
392                 if self.satipconfig.server is None:
393                         return
394
395                 self.list = []
396                 self.server_entry = getConfigListEntry(_("SAT>IP Server : "), self.satipconfig.server)
397                 self.list.append( self.server_entry )
398
399                 self.createTypeConfig(self.satipconfig.server.value)
400                 self.type_entry = getConfigListEntry(_("SAT>IP Tuner Type : "), self.satipconfig.tunertype)
401                 self.list.append( self.type_entry )
402
403                 self["config"].list = self.list
404                 self["config"].l.setList(self.list)
405
406                 if not self.showChoices in self["config"].onSelectionChanged:
407                         self["config"].onSelectionChanged.append(self.showChoices)
408
409                 self.selectionChanged()
410
411         def createTypeConfig(self, uuid):
412                 # type_choices = [ ("DVB-S", _("DVB-S")), ("DVB-C", _("DVB-C")), ("DVB-T", _("DVB-T"))]
413                 type_choices = []
414                 type_default = None
415                 capability = self.getCapability(uuid)
416
417                 for (t, n) in capability.items():
418                         if n != 0:
419                                 type_choices.append( (t, _(t)) )
420                                 if self.vtuner_type == t:
421                                         type_default = t
422
423                 if isEmpty(type_choices):
424                         type_choices = [ ("DVB-S", _("DVB-S")) ]
425
426                 self.satipconfig.tunertype = ConfigSelection(default = type_default, choices = type_choices )
427
428         def selectionChanged(self):
429                 if self.satipconfig.server is None:
430                         return
431
432                 uuid = self.satipconfig.server.value
433
434 #               ipaddress = satipdiscovery.getServerInfo(uuid, "ipaddress")
435                 modelDescription = satipdiscovery.getServerInfo(uuid, "modelDescription")
436                 manufacturer = satipdiscovery.getServerInfo(uuid, "manufacturer")
437 #               specversion = "%s.%s" % (satipdiscovery.getServerInfo(uuid, "major"), satipdiscovery.getServerInfo(uuid, "minor"))
438                 modelURL = satipdiscovery.getServerInfo(uuid, "modelURL")
439                 presentationURL = satipdiscovery.getServerInfo(uuid, "presentationURL")
440 #               satipcap = satipdiscovery.getServerInfo(uuid, "X_SATIPCAP")
441 #               serialNumber = satipdiscovery.getServerInfo(uuid, "serialNumber")
442
443                 capability = self.getCapability(uuid)
444                 satipcap_list = []
445                 for (t, n) in capability.items():
446                         if n != 0:
447                                 satipcap_list.append("%d x %s" % (n, t))
448
449                 satipcap = ",".join(satipcap_list)
450
451                 description = ""
452                 description += "Description : %s\n" % modelDescription
453                 description += "Manufacture : %s\n" % manufacturer 
454                 description += "Model URL : %s\n" % modelURL
455                 description += "Presentation URL : %s\n" % presentationURL
456                 description += "UUID : %s\n" % uuid             
457                 description += "SAT>IP Capavility : %s" % satipcap
458                 
459                 self["description"].setText(description)
460
461         def showChoices(self):
462                 currentConfig = self["config"].getCurrent()[1]
463                 text_list = []
464                 for choice in currentConfig.choices.choices:
465                         text_list.append(choice[1])
466
467                 text = ",".join(text_list)
468
469                 self["choices"].setText("Choices : \n%s" % (text))
470
471         def getCapability(self, uuid):
472                 capability = { 'DVB-S' : 0, 'DVB-C' : 0, 'DVB-T' : 0}
473                 data = satipdiscovery.getServerInfo(uuid, "X_SATIPCAP")
474                 for x in data.split(','):
475                         if x.upper().find("DVBS") != -1:
476                                 capability['DVB-S'] = int(x.split('-')[1])
477                         elif x.upper().find("DVBC") != -1:
478                                 capability['DVB-C'] = int(x.split('-')[1])
479                         elif x.upper().find("DVBT") != -1:
480                                 capability['DVB-T'] = int(x.split('-')[1])
481
482                 return capability
483
484         def checkTunerCapacity(self, uuid, tunertype):
485                 capability = self.getCapability(uuid)
486                 t_cap = capability[tunertype]
487
488                 t_count = 0
489
490                 for idx in VTUNER_IDX_LIST:
491                         if self.vtuner_idx == idx:
492                                 continue
493
494                         vtuner = self.current_satipConfig[int(idx)]
495                         if vtuner["vtuner_type"] == "satip_client" and vtuner["uuid"] == uuid and vtuner["tuner_type"] == tunertype:
496 #                               print "[checkTunerCapacity] tuner %d use type %s" % (int(idx), tunertype)
497                                 t_count += 1
498
499 #               print "[checkTunerCapacity] capability : ", capability
500 #               print "[checkTunerCapacity] t_cap : %d, t_count %d" % (t_cap, t_count)
501
502                 if int(t_cap) > t_count:
503                         return True
504
505                 return False
506
507         def keyLeft(self):
508                 ConfigListScreen.keyLeft(self)
509                 if self["config"].getCurrent() == self.server_entry:
510                         self.createSetup()
511                 self.selectionChanged()
512
513         def keyRight(self):
514                 ConfigListScreen.keyRight(self)
515                 if self["config"].getCurrent() == self.server_entry:
516                         self.createSetup()
517                 self.selectionChanged()
518
519         def keySave(self):
520                 if self.satipconfig.server is None:
521                         self.keyCancel()
522                         return
523
524                 uuid = self.satipconfig.server.value
525                 tunertype = self.satipconfig.tunertype.value
526
527                 if not self.checkTunerCapacity(uuid, tunertype):
528                         self.session.open(MessageBox, _("Server capacity is fulled."), MessageBox.TYPE_ERROR)
529
530                 else:
531                         data = {}
532                         data['idx'] = self.vtuner_idx
533                         data['ip'] = satipdiscovery.getServerInfo(uuid, 'ipaddress');
534                         data['desc'] = satipdiscovery.getServerInfo(uuid, "modelName")
535                         data['tuner_type'] = tunertype
536                         data['uuid'] = uuid
537
538                         self.close(data)
539
540         def keyCancel(self):
541                 self.close()
542
543 SATIP_CONFFILE = "/etc/vtuner.conf"
544 class SATIPClient(Screen):
545         skin = """
546                 <screen position="center,center" size="590,370">
547                         <ePixmap pixmap="skin_default/buttons/red.png" position="20,0" size="140,40" alphatest="on" />
548                         <ePixmap pixmap="skin_default/buttons/green.png" position="160,0" size="140,40" alphatest="on" />
549                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="300,0" size="140,40" alphatest="on" />
550                         <ePixmap pixmap="skin_default/buttons/blue.png" position="440,0" size="140,40" alphatest="on" />
551
552                         <widget source="key_red" render="Label" position="20,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#9f1313" transparent="1" />
553                         <widget source="key_green" render="Label" position="160,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#1f771f" transparent="1" />
554                         <widget source="key_yellow" render="Label" position="300,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#a08500" transparent="1" />
555                         <widget source="key_blue" render="Label" position="440,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" foregroundColor="#ffffff" backgroundColor="#18188b" transparent="1" />
556
557                         <widget source="vtunerList" render="Listbox" position="30,60" size="540,272" scrollbarMode="showOnDemand">
558                                 <convert type="TemplatedMultiContent">
559                                 {"templates":
560                                         {"default": (68,[
561                                                         MultiContentEntryText(pos = (20, 0), size = (180, 28), font=0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 0),
562                                                         MultiContentEntryText(pos = (50, 28), size = (140, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 1),
563                                                         MultiContentEntryText(pos = (210, 28), size = (140, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 2),
564                                                         MultiContentEntryText(pos = (370, 28), size = (140, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 3),
565                                                         MultiContentEntryText(pos = (50, 48), size = (490, 20), font=1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER, text = 4),
566                                                         
567                                                         
568                                         ]),
569                                         },
570                                         "fonts": [gFont("Regular", 24),gFont("Regular", 16)],
571                                         "itemHeight": 68
572                                 }
573                                 </convert>
574                         </widget>
575                         <widget source="description" render="Label" position="0,340" size="590,30" font="Regular;20" halign="center" valign="center" />
576                 </screen>
577         """
578         def __init__(self, session):
579                 Screen.__init__(self, session)
580                 self.setTitle(_("SAT>IP Client Setup"))
581                 self.skin = SATIPClient.skin
582                 self.session = session
583
584                 self["key_red"] = StaticText(_("Cancel"))
585                 self["key_green"] = StaticText(_("Save"))
586                 self["key_yellow"] = StaticText(_("Setup"))
587                 self["key_blue"] = StaticText(_("Disable"))
588                 self["description"] = StaticText(_("Select tuner and press setup key (Yellow)"))
589
590                 self.configList = []
591                 self["vtunerList"] = List(self.configList)
592
593                 self["shortcuts"] = ActionMap(["SATIPCliActions" ],
594                 {
595                         "ok": self.keySetup,
596                         "cancel": self.keyCancel,
597                         "red": self.keyCancel,
598                         "green": self.KeySave,
599                         "yellow": self.keySetup,
600                         "blue": self.keyDisable,
601                 }, -2)
602
603                 self.vtunerIndex = VTUNER_IDX_LIST
604                 self.vtunerConfig = self.loadConfig()
605                 self.sortVtunerConfig()
606                 self.old_vtunerConfig = copy.deepcopy(self.vtunerConfig)
607                 self.createSetup()
608
609         def isChanged(self):
610                 for vtuner_idx in self.vtunerIndex:
611                         vtuner = self.vtunerConfig[int(vtuner_idx)]
612                         old_vtuner = self.old_vtunerConfig[int(vtuner_idx)]
613                         if vtuner['vtuner_type'] != old_vtuner['vtuner_type']:
614                                 return True
615
616                         elif vtuner['vtuner_type'] == "satip_client":
617                                 for key in sorted(vtuner):
618                                         if vtuner[key] != old_vtuner[key]:
619                                                 return True
620                 return False
621
622         def KeySave(self):
623                 if self.isChanged():
624                         msg = "You should now reboot your STB to change SAT>IP Configuration.\n\nReboot now ?\n\n"
625                         self.session.openWithCallback(self.keySaveCB, MessageBox, (_(msg) ) )
626
627                 else:
628                         self.close()
629
630         def keySaveCB(self, res):
631                 if res:
632                         self.saveConfig()
633                         self.doReboot()
634
635         def doReboot(self):
636                 self.session.open(TryQuitMainloop, 2)
637
638         def cancelConfirm(self, result):
639                 if not result:
640                         return
641
642                 self.close()
643
644         def keyCancel(self):
645                 if self.isChanged():
646                         self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?"))
647                 else:
648                         self.close()
649
650         def createSetup(self):
651 #               print "vtunerIndex : ", self.vtunerIndex
652 #               print "vtunerConfig : ", self.vtunerConfig
653                 self.configList = []
654                 for vtuner_idx in self.vtunerIndex:
655                         vtuner = self.vtunerConfig[int(vtuner_idx)]
656
657                         if vtuner['vtuner_type'] == "satip_client":
658                                 entry = (
659                                 "VIRTUAL TUNER %s" % vtuner_idx,
660                                 "TYPE : %s" % vtuner['vtuner_type'].replace('_',' ').upper(),
661                                 "IP : %s" % vtuner['ipaddr'],
662                                 "TUNER TYPE : %s" % vtuner['tuner_type'],
663                                 "SAT>IP SERVER : %s" % vtuner['desc'],
664                                 vtuner_idx,
665                                 vtuner['tuner_type'],
666                                 vtuner['uuid'],
667                                 )
668
669                         else:
670                                 entry = (
671                                 "VIRTUAL TUNER %s" % vtuner_idx,
672                                 "TYPE : %s" % vtuner['vtuner_type'].replace('_',' ').upper(),
673                                 "",
674                                 "",
675                                 "",
676                                 vtuner_idx,
677                                 "",
678                                 "",
679                                 )
680
681                         self.configList.append(entry)
682 #               self.configList.sort()
683                 self["vtunerList"].setList(self.configList)
684
685         def keyDisable(self):
686                 idx = self["vtunerList"].getCurrent()[5]
687
688                 self.vtunerConfig[int(idx)] = copy.deepcopy(self.old_vtunerConfig[int(idx)])
689                 if self.vtunerConfig[int(idx)] and self.vtunerConfig[int(idx)]['vtuner_type'] == "satip_client":
690                         self.vtunerConfig[int(idx)] = {'vtuner_type':"usb_tuner"}
691
692                 self.sortVtunerConfig()
693                 self.createSetup()
694
695         def keySetup(self):
696                 vtuner_idx = self["vtunerList"].getCurrent()[5]
697                 vtuner_type = self["vtunerList"].getCurrent()[6]
698                 vtuner_uuid = self["vtunerList"].getCurrent()[7]
699                 self.session.openWithCallback(self.SATIPTunerCB, SATIPTuner, vtuner_idx, vtuner_uuid, vtuner_type, self.vtunerConfig)
700
701         def SATIPTunerCB(self, data = None):
702                 if data is not None:
703                         self.setConfig(data)
704
705         def setConfig(self, data):
706                 if data['uuid'] is not None:
707                         vtuner = self.vtunerConfig[int(data['idx'])]
708                         vtuner['vtuner_type'] = "satip_client"
709                         vtuner['ipaddr'] = data['ip']
710                         vtuner['desc'] = data['desc']
711                         vtuner['uuid'] = data['uuid']
712                         vtuner['tuner_type'] = data['tuner_type']
713
714                 self.sortVtunerConfig()
715                 self.createSetup()
716 #               else:
717 #                       self.keyDisable()
718
719         def sortVtunerConfig(self):
720                 self.vtunerConfig.sort(reverse=True)
721
722         def saveConfig(self):
723                 data = ""
724
725                 for idx in self.vtunerIndex:
726                         conf = self.vtunerConfig[int(idx)]
727                         if not conf:
728                                 continue
729
730 #                       print "conf : ", conf
731
732                         attr = []
733                         for k in sorted(conf):
734                                 attr.append("%s:%s" % (k, conf[k]))
735
736                         data += idx + '=' + ",".join(attr)+"\n"
737
738                 if data:
739                         fd = open(SATIP_CONFFILE, 'w')
740                         fd.write(data)
741                         fd.close()
742
743         def loadConfig(self):
744                 vtunerConfig = []
745
746                 for idx in self.vtunerIndex:
747                         vtunerConfig.append({'vtuner_type':"usb_tuner"})
748
749                 if os.access(SATIP_CONFFILE, os.R_OK):
750                         fd = open(SATIP_CONFFILE)
751                         confData = fd.read()
752                         fd.close()
753
754                         if confData:
755                                 for line in confData.splitlines():
756                                         if len(line) == 0 or line[0] == '#':
757                                                 continue
758
759
760                                         data = line.split('=')
761                                         if len(data) != 2:
762                                                 continue
763                                         idx = data[0]
764
765                                         try:
766                                                 vtunerConfig[int(idx)]
767                                         except:
768                                                 continue
769
770                                         data = data[1].split(',')
771                                         if len(data) != 5:
772                                                 continue
773
774                                         for x in data:
775                                                 s = x.split(':')
776                                                 if len(s) != 2:
777                                                         continue
778
779                                                 attr = s[0]
780                                                 value = s[1]
781                                                 vtunerConfig[int(idx)][attr] = value
782
783                 return vtunerConfig
784
785 def main(session, **kwargs):
786         session.open(SATIPClient)
787
788 def Plugins(**kwargs):
789         pList = []
790         pList.append( PluginDescriptor(name=_("SAT>IP Client"), description=_("SAT>IP Client attached to vtuner."), where = PluginDescriptor.WHERE_PLUGINMENU, needsRestart = False, fnc=main) )
791         return pList