Merge remote-tracking branch 'origin/acid-burn/virtualkeyboard'
[vuplus_dvbapp] / lib / python / Plugins / SystemPlugins / WirelessLan / plugin.py
1 from enigma import eTimer, eTPM, eEnv
2 from Screens.Screen import Screen
3 from Components.ActionMap import ActionMap, NumberActionMap
4 from Components.Pixmap import Pixmap,MultiPixmap
5 from Components.Label import Label
6 from Components.Sources.StaticText import StaticText
7 from Components.Sources.List import List
8 from Components.MenuList import MenuList
9 from Components.config import config, getConfigListEntry, ConfigYesNo, NoSave, ConfigSubsection, ConfigText, ConfigSelection, ConfigPassword
10 from Components.ConfigList import ConfigListScreen
11 from Components.Network import iNetwork
12 from Components.Console import Console
13 from Plugins.Plugin import PluginDescriptor
14 from os import system, path as os_path, listdir
15 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
16 from Tools.LoadPixmap import LoadPixmap
17 from Tools.HardwareInfo import HardwareInfo
18 from Wlan import iWlan, wpaSupplicant, iStatus, getWlanConfigName
19 import hashlib
20 from time import time
21 from os import urandom, system
22 from re import escape as re_escape
23
24 plugin_path = eEnv.resolve("${libdir}/enigma2/python/Plugins/SystemPlugins/WirelessLan")
25
26
27 list = []
28 list.append("Unencrypted")
29 list.append("WEP")
30 list.append("WPA")
31 list.append("WPA/WPA2")
32 list.append("WPA2")
33
34 weplist = []
35 weplist.append("ASCII")
36 weplist.append("HEX")
37
38 config.plugins.wlan = ConfigSubsection()
39 config.plugins.wlan.essid = NoSave(ConfigText(default = "", fixed_size = False))
40 config.plugins.wlan.hiddenessid = NoSave(ConfigYesNo(default = False))
41 config.plugins.wlan.encryption = NoSave(ConfigSelection(list, default = "WPA2"))
42 config.plugins.wlan.wepkeytype = NoSave(ConfigSelection(weplist, default = "ASCII"))
43 config.plugins.wlan.psk = NoSave(ConfigPassword(default = "", fixed_size = False))
44
45
46
47 class WlanStatus(Screen):
48         skin = """
49                 <screen name="WlanStatus" position="center,center" size="560,400" title="Wireless Network State" >
50                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
51                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
52
53                         <widget source="LabelBSSID" render="Label" position="10,60" size="200,25" valign="left" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
54                         <widget source="LabelESSID" render="Label" position="10,100" size="200,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
55                         <widget source="LabelQuality" render="Label" position="10,140" size="200,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
56                         <widget source="LabelSignal" render="Label" position="10,180" size="200,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
57                         <widget source="LabelBitrate" render="Label" position="10,220" size="200,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
58                         <widget source="LabelEnc" render="Label" position="10,260" size="200,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
59                         <widget source="BSSID" render="Label" position="220,60" size="330,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
60                         <widget source="ESSID" render="Label" position="220,100" size="330,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
61                         <widget source="quality" render="Label" position="220,140" size="330,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
62                         <widget source="signal" render="Label" position="220,180" size="330,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
63                         <widget source="bitrate" render="Label" position="220,220" size="330,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
64                         <widget source="enc" render="Label" position="220,260" size="330,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
65         
66                         <ePixmap pixmap="skin_default/div-h.png" position="0,350" zPosition="1" size="560,2" />         
67                         <widget source="IFtext" render="Label" position="10,355" size="120,21" zPosition="10" font="Regular;20" halign="left" backgroundColor="#25062748" transparent="1" />
68                         <widget source="IF" render="Label" position="120,355" size="400,21" zPosition="10" font="Regular;20" halign="left" backgroundColor="#25062748" transparent="1" />
69                         <widget source="Statustext" render="Label" position="10,375" size="115,21" zPosition="10" font="Regular;20" halign="left" backgroundColor="#25062748" transparent="1"/>
70                         <widget name="statuspic" pixmaps="skin_default/buttons/button_green.png,skin_default/buttons/button_green_off.png" position="130,380" zPosition="10" size="15,16" transparent="1" alphatest="on"/>
71                 </screen>"""
72         
73         def __init__(self, session, iface):
74                 Screen.__init__(self, session)
75                 self.session = session
76                 self.iface = iface
77                                     
78                 self["LabelBSSID"] = StaticText(_('Accesspoint:'))
79                 self["LabelESSID"] = StaticText(_('SSID:'))
80                 self["LabelQuality"] = StaticText(_('Link Quality:'))
81                 self["LabelSignal"] = StaticText(_('Signal Strength:'))
82                 self["LabelBitrate"] = StaticText(_('Bitrate:'))
83                 self["LabelEnc"] = StaticText(_('Encryption:'))
84                         
85                 self["BSSID"] = StaticText()
86                 self["ESSID"] = StaticText()
87                 self["quality"] = StaticText()
88                 self["signal"] = StaticText()
89                 self["bitrate"] = StaticText()
90                 self["enc"] = StaticText()
91
92                 self["IFtext"] = StaticText()
93                 self["IF"] = StaticText()
94                 self["Statustext"] = StaticText()
95                 self["statuspic"] = MultiPixmap()
96                 self["statuspic"].hide()
97                 self["key_red"] = StaticText(_("Close"))
98
99                 self.resetList()
100                 self.updateStatusbar()
101                 
102                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "EPGSelectActions", "ShortcutActions"],
103                 {
104                         "ok": self.exit,
105                         "back": self.exit,
106                         "red": self.exit,
107                 }, -1)
108                 self.timer = eTimer()
109                 self.timer.timeout.get().append(self.resetList) 
110                 self.onShown.append(lambda: self.timer.start(8000))
111                 self.onLayoutFinish.append(self.layoutFinished)
112                 self.onClose.append(self.cleanup)
113
114         def cleanup(self):
115                 iStatus.stopWlanConsole()
116                 
117         def layoutFinished(self):
118                 self.setTitle(_("Wireless network state"))
119                 
120         def resetList(self):
121                 iStatus.getDataForInterface(self.iface,self.getInfoCB)
122                 
123         def getInfoCB(self,data,status):
124                 if data is not None:
125                         if data is True:
126                                 if status is not None:
127                                         if status[self.iface]["essid"] == "off":
128                                                 essid = _("No Connection")
129                                         else:
130                                                 essid = status[self.iface]["essid"]
131                                         if status[self.iface]["accesspoint"] == "Not-Associated":
132                                                 accesspoint = _("Not-Associated")
133                                                 essid = _("No Connection")
134                                         else:
135                                                 accesspoint = status[self.iface]["accesspoint"]
136                                         if self.has_key("BSSID"):
137                                                 self["BSSID"].setText(accesspoint)
138                                         if self.has_key("ESSID"):
139                                                 self["ESSID"].setText(essid)
140
141                                         quality = status[self.iface]["quality"]
142                                         if self.has_key("quality"):
143                                                 self["quality"].setText(quality)
144                                                 
145                                         if status[self.iface]["bitrate"] == '0':
146                                                 bitrate = _("Unsupported")
147                                         else:
148                                                 bitrate = str(status[self.iface]["bitrate"]) + " Mb/s"
149                                         if self.has_key("bitrate"):
150                                                 self["bitrate"].setText(bitrate)                                        
151                                         
152                                         signal = status[self.iface]["signal"]
153                                         if self.has_key("signal"):
154                                                 self["signal"].setText(signal)
155
156                                         if status[self.iface]["encryption"] == "off":
157                                                 if accesspoint == "Not-Associated":
158                                                         encryption = _("Disabled")
159                                                 else:
160                                                         encryption = _("Unsupported")
161                                         else:
162                                                 encryption = _("Enabled")
163                                         if self.has_key("enc"):
164                                                 self["enc"].setText(encryption)
165                                         self.updateStatusLink(status)
166
167         def exit(self):
168                 self.timer.stop()
169                 self.close(True)
170
171         def updateStatusbar(self):
172                 wait_txt = _("Please wait...")
173                 self["BSSID"].setText(wait_txt)
174                 self["ESSID"].setText(wait_txt)
175                 self["quality"].setText(wait_txt)
176                 self["signal"].setText(wait_txt)
177                 self["bitrate"].setText(wait_txt)
178                 self["enc"].setText(wait_txt)
179                 self["IFtext"].setText(_("Network:"))
180                 self["IF"].setText(iNetwork.getFriendlyAdapterName(self.iface))
181                 self["Statustext"].setText(_("Link:"))
182
183         def updateStatusLink(self,status):
184                 if status is not None:
185                         if status[self.iface]["essid"] == "off" or status[self.iface]["accesspoint"] == "Not-Associated" or status[self.iface]["accesspoint"] == False:
186                                 self["statuspic"].setPixmapNum(1)
187                         else:
188                                 self["statuspic"].setPixmapNum(0)
189                         self["statuspic"].show()                
190
191
192 class WlanScan(Screen):
193         skin = """
194                 <screen name="WlanScan" position="center,center" size="560,400" title="Choose a Wireless Network" >
195                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
196                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
197                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
198                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
199                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
200                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
201                         <widget source="list" render="Listbox" position="5,40" size="550,300" scrollbarMode="showOnDemand">
202                                 <convert type="TemplatedMultiContent">
203                                         {"template": [
204                                                         MultiContentEntryText(pos = (0, 0), size = (550, 30), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the essid
205                                                         MultiContentEntryText(pos = (0, 30), size = (175, 20), font=1, flags = RT_HALIGN_LEFT, text = 5), # index 5 is the interface
206                                                         MultiContentEntryText(pos = (175, 30), size = (175, 20), font=1, flags = RT_HALIGN_LEFT, text = 4), # index 0 is the encryption
207                                                         MultiContentEntryText(pos = (350, 0), size = (200, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 0 is the signal
208                                                         MultiContentEntryText(pos = (350, 30), size = (200, 20), font=1, flags = RT_HALIGN_LEFT, text = 3), # index 0 is the maxrate
209                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 52), size = (550, 2), png = 6), # index 6 is the div pixmap
210                                                 ],
211                                         "fonts": [gFont("Regular", 28),gFont("Regular", 18)],
212                                         "itemHeight": 54
213                                         }
214                                 </convert>
215                         </widget>
216                         <ePixmap pixmap="skin_default/div-h.png" position="0,340" zPosition="1" size="560,2" />         
217                         <widget source="info" render="Label" position="0,350" size="560,50" font="Regular;24" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
218                 </screen>"""
219
220         def __init__(self, session, iface):
221                 Screen.__init__(self, session)
222                 self.session = session
223                 self.iface = iface
224                 self.skin_path = plugin_path
225                 self.oldInterfaceState = iNetwork.getAdapterAttribute(self.iface, "up")
226                 self.APList = None
227                 self.newAPList = None
228                 self.WlanList = None
229                 self.cleanList = None
230                 self.oldlist = {}
231                 self.listLength = None
232                 self.rescanTimer = eTimer()
233                 self.rescanTimer.callback.append(self.rescanTimerFired)
234                 
235                 self["info"] = StaticText()
236                 
237                 self.list = []
238                 self["list"] = List(self.list)
239                 
240                 self["key_red"] = StaticText(_("Close"))
241                 self["key_green"] = StaticText(_("Connect"))
242                 self["key_yellow"] = StaticText()
243                         
244                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "EPGSelectActions"],
245                 {
246                         "ok": self.select,
247                         "back": self.cancel,
248                 }, -1)
249                 
250                 self["shortcuts"] = ActionMap(["ShortcutActions"],
251                 {
252                         "red": self.cancel,
253                         "green": self.select,
254                 })
255                 iWlan.setInterface(self.iface)
256                 self.w = iWlan.getInterface()
257                 self.onLayoutFinish.append(self.layoutFinished)
258                 self.getAccessPoints(refresh = False)
259                 
260         def layoutFinished(self):
261                 self.setTitle(_("Choose a wireless network"))
262         
263         def select(self):
264                 cur = self["list"].getCurrent()
265                 if cur is not None:
266                         iWlan.stopGetNetworkList()
267                         self.rescanTimer.stop()
268                         del self.rescanTimer
269                         if cur[0] is not None:
270                                 self.close(cur[0])
271                         else:
272                                 self.close(None)
273                 else:
274                         iWlan.stopGetNetworkList()
275                         self.rescanTimer.stop()
276                         del self.rescanTimer
277                         self.close(None)
278         
279         def cancel(self):
280                 iWlan.stopGetNetworkList()
281                 self.rescanTimer.stop()
282                 del self.rescanTimer
283                 self.close(None)
284
285         def rescanTimerFired(self):
286                 self.rescanTimer.stop()
287                 self.updateAPList()
288
289         def buildEntryComponent(self, essid, bssid, encrypted, iface, maxrate, signal):
290                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
291                 encryption = encrypted and _("Yes") or _("No")
292                 return((essid, bssid, _("Signal: ") + str(signal), _("Max. Bitrate: ") + str(maxrate), _("Encrypted: ") + encryption, _("Interface: ") + str(iface), divpng))
293
294         def updateAPList(self):
295                 newList = []
296                 newList = self.getAccessPoints(refresh = True)  
297                 self.newAPList = []
298                 tmpList = []
299                 newListIndex = None
300                 currentListEntry = None
301                 currentListIndex = None
302
303                 for ap in self.oldlist.keys():
304                         data = self.oldlist[ap]['data']
305                         if data is not None:
306                                 tmpList.append(data)
307
308                 if len(tmpList):
309                         for entry in tmpList:
310                                 self.newAPList.append(self.buildEntryComponent( entry[0], entry[1], entry[2], entry[3], entry[4], entry[5] ))
311         
312                         currentListEntry = self["list"].getCurrent()
313                         if currentListEntry is not None:
314                                 idx = 0
315                                 for entry in self.newAPList:
316                                         if entry[0] == currentListEntry[0]:
317                                                 newListIndex = idx
318                                         idx +=1
319                         self['list'].setList(self.newAPList)
320                         if newListIndex is not None:
321                                 self["list"].setIndex(newListIndex)
322                         self["list"].updateList(self.newAPList)
323                         self.listLength = len(self.newAPList)
324                         self.buildWlanList()
325                         self.setInfo()
326
327         def getAccessPoints(self, refresh = False):
328                 self.APList = []
329                 self.cleanList = []
330                 aps = iWlan.getNetworkList()
331                 if aps is not None:
332                         print "[WirelessLan.py] got Accespoints!"
333                         tmpList = []
334                         compList = []
335                         for ap in aps:
336                                 a = aps[ap]
337                                 if a['active']:
338                                         tmpList.append( (a['essid'], a['bssid']) )
339                                         compList.append( (a['essid'], a['bssid'], a['encrypted'], a['iface'], a['maxrate'], a['signal']) )
340
341                         for entry in tmpList:
342                                 if entry[0] == "":
343                                         for compentry in compList:
344                                                 if compentry[1] == entry[1]:
345                                                         compList.remove(compentry)
346                         for entry in compList:
347                                 self.cleanList.append( ( entry[0], entry[1], entry[2], entry[3], entry[4], entry[5] ) )
348                                 if not self.oldlist.has_key(entry[0]):
349                                         self.oldlist[entry[0]] = { 'data': entry }
350                                 else:
351                                         self.oldlist[entry[0]]['data'] = entry
352                 
353                 for entry in self.cleanList:
354                         self.APList.append(self.buildEntryComponent( entry[0], entry[1], entry[2], entry[3], entry[4], entry[5] ))
355                 
356                 if refresh is False:
357                         self['list'].setList(self.APList)
358                 self.listLength = len(self.APList)
359                 self.setInfo()
360                 self.rescanTimer.start(5000)
361                 return self.cleanList
362
363         def setInfo(self):
364                 length = self.getLength()
365                 if length == 0:
366                         self["info"].setText(_("No wireless networks found! Searching..."))
367                 elif length == 1:
368                         self["info"].setText(_("1 wireless network found!"))
369                 else:
370                         self["info"].setText(str(length)+_(" wireless networks found!"))
371
372         def buildWlanList(self):
373                 self.WlanList = []
374                 for entry in self['list'].list:
375                         self.WlanList.append( (entry[0], entry[0]) )
376
377         def getLength(self):
378                 return self.listLength          
379
380         def getWlanList(self):
381                 if self.WlanList is None:
382                         self.buildWlanList()
383                 return self.WlanList
384
385
386 def bin2long(s):
387         return reduce( lambda x,y:(x<<8L)+y, map(ord, s))
388
389 def long2bin(l):
390         res = ""
391         for byte in range(128):
392                 res += chr((l >> (1024 - (byte + 1) * 8)) & 0xff)
393         return res
394
395 def rsa_pub1024(src, mod):
396         return long2bin(pow(bin2long(src), 65537, bin2long(mod)))
397         
398 def decrypt_block(src, mod):
399         if len(src) != 128 and len(src) != 202:
400                 return None
401         dest = rsa_pub1024(src[:128], mod)
402         hash = hashlib.sha1(dest[1:107])
403         if len(src) == 202:
404                 hash.update(src[131:192])       
405         result = hash.digest()
406         if result == dest[107:127]:
407                 return dest
408         return None
409
410 def validate_certificate(cert, key):
411         buf = decrypt_block(cert[8:], key) 
412         if buf is None:
413                 return None
414         return buf[36:107] + cert[139:196]
415
416 def get_random():
417         try:
418                 xor = lambda a,b: ''.join(chr(ord(c)^ord(d)) for c,d in zip(a,b*100))
419                 random = urandom(8)
420                 x = str(time())[-8:]
421                 result = xor(random, x)
422                                 
423                 return result
424         except:
425                 return None
426
427 def WlanStatusScreenMain(session, iface):
428         session.open(WlanStatus, iface)
429
430 def callFunction(iface):
431         iWlan.setInterface(iface)
432         i = iWlan.getWirelessInterfaces()
433         if i:
434                 if iface in i or iNetwork.isWirelessInterface(iface):
435                         return WlanStatusScreenMain
436                 return None
437         return None
438
439 def configStrings(iface):
440         try:
441                 device = open("/proc/stb/info/model", "r").readline().strip()
442         except:
443                 device = ""     
444         if device != "dm7025":
445                 rootkey = ['\x9f', '|', '\xe4', 'G', '\xc9', '\xb4', '\xf4', '#', '&', '\xce', '\xb3', '\xfe', '\xda', '\xc9', 'U', '`', '\xd8', '\x8c', 's', 'o', '\x90', '\x9b', '\\', 'b', '\xc0', '\x89', '\xd1', '\x8c', '\x9e', 'J', 'T', '\xc5', 'X', '\xa1', '\xb8', '\x13', '5', 'E', '\x02', '\xc9', '\xb2', '\xe6', 't', '\x89', '\xde', '\xcd', '\x9d', '\x11', '\xdd', '\xc7', '\xf4', '\xe4', '\xe4', '\xbc', '\xdb', '\x9c', '\xea', '}', '\xad', '\xda', 't', 'r', '\x9b', '\xdc', '\xbc', '\x18', '3', '\xe7', '\xaf', '|', '\xae', '\x0c', '\xe3', '\xb5', '\x84', '\x8d', '\r', '\x8d', '\x9d', '2', '\xd0', '\xce', '\xd5', 'q', '\t', '\x84', 'c', '\xa8', ')', '\x99', '\xdc', '<', '"', 'x', '\xe8', '\x87', '\x8f', '\x02', ';', 'S', 'm', '\xd5', '\xf0', '\xa3', '_', '\xb7', 'T', '\t', '\xde', '\xa7', '\xf1', '\xc9', '\xae', '\x8a', '\xd7', '\xd2', '\xcf', '\xb2', '.', '\x13', '\xfb', '\xac', 'j', '\xdf', '\xb1', '\x1d', ':', '?']
446                 etpm = eTPM()
447                 l2cert = etpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
448                 if l2cert is None:
449                         return
450                 l2key = validate_certificate(l2cert, rootkey)
451                 if l2key is None:
452                         return
453                 l3cert = etpm.getCert(eTPM.TPMD_DT_LEVEL3_CERT)
454                 if l3cert is None:
455                         return
456                 l3key = validate_certificate(l3cert, l2key)
457                 if l3key is None:
458                         return
459                 rnd = get_random()
460                 if rnd is None:
461                         return
462                 val = etpm.challenge(rnd)
463                 result = decrypt_block(val, l3key)
464         if device == "dm7025" or result[80:88] == rnd:
465                 driver = iNetwork.detectWlanModule(iface)
466         else:
467                 driver = 'dreambox'
468         print 'Using "%s" as wpa-supplicant driver' % (driver)
469         ret = ""
470         if driver == 'madwifi' and config.plugins.wlan.hiddenessid.value:
471                 ret += "\tpre-up iwconfig " + iface + " essid \"" + re_escape(config.plugins.wlan.essid.value) + "\" || true\n"
472         ret += "\tpre-up wpa_supplicant -i" + iface + " -c" + getWlanConfigName(iface) + " -B -dd -D" + driver + " || true\n"
473         ret += "\tpre-down wpa_cli -i" + iface + " terminate || true\n"
474         return ret
475
476 def Plugins(**kwargs):
477         return PluginDescriptor(name=_("Wireless LAN"), description=_("Connect to a Wireless Network"), where = PluginDescriptor.WHERE_NETWORKSETUP, needsRestart = False, fnc={"ifaceSupported": callFunction, "configStrings": configStrings, "WlanPluginEntry": lambda x: "Wireless Network Configuartion..."})