1 # -*- coding: utf-8 -*-
2 # for localized messages
4 from enigma import eTimer, getDesktop
5 from Screens.Screen import Screen
6 from Screens.MessageBox import MessageBox
7 from Components.Label import Label
8 from Components.ActionMap import ActionMap, NumberActionMap
9 from Components.Sources.List import List
10 from Components.Network import iNetwork
11 from Components.Input import Input
12 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
13 from Tools.LoadPixmap import LoadPixmap
14 from cPickle import dump, load
15 from os import path as os_path, stat, mkdir, remove
17 from stat import ST_MTIME
20 from MountManager import AutoMountManager
21 from AutoMount import iAutoMount
22 from MountEdit import AutoMountEdit
23 from UserDialog import UserDialog
25 def write_cache(cache_file, cache_data):
27 if not os_path.isdir( os_path.dirname(cache_file) ):
29 mkdir( os_path.dirname(cache_file) )
31 print os_path.dirname(cache_file), 'is a file'
32 fd = open(cache_file, 'w')
33 dump(cache_data, fd, -1)
36 def valid_cache(cache_file, cache_ttl):
37 #See if the cache file exists and is still living
39 mtime = stat(cache_file)[ST_MTIME]
43 if (curr_time - mtime) > cache_ttl:
48 def load_cache(cache_file):
55 class NetworkDescriptor:
56 def __init__(self, name = "NetworkServer", description = ""):
58 self.description = description
60 class NetworkBrowser(Screen):
62 <screen name="NetworkBrowser" position="90,80" size="560,450" title="Network Neighbourhood">
63 <ePixmap pixmap="skin_default/bottombar.png" position="10,360" size="540,120" zPosition="1" transparent="1" alphatest="on" />
64 <widget source="list" render="Listbox" position="10,10" size="540,350" zPosition="10" scrollbarMode="showOnDemand">
65 <convert type="TemplatedMultiContent">
67 MultiContentEntryPixmapAlphaTest(pos = (0, 0), size = (48, 48), png = 1), # index 1 is the expandable/expanded/verticalline icon
68 MultiContentEntryText(pos = (50, 4), size = (420, 26), font=2, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the Hostname
69 MultiContentEntryText(pos = (140, 5), size = (320, 25), font=0, flags = RT_HALIGN_LEFT, text = 3), # index 3 is the sharename
70 MultiContentEntryText(pos = (140, 26), size = (320, 17), font=1, flags = RT_HALIGN_LEFT, text = 4), # index 4 is the sharedescription
71 MultiContentEntryPixmapAlphaTest(pos = (45, 0), size = (48, 48), png = 5), # index 5 is the nfs/cifs icon
72 MultiContentEntryPixmapAlphaTest(pos = (90, 0), size = (48, 48), png = 6), # index 6 is the isMounted icon
74 "fonts": [gFont("Regular", 20),gFont("Regular", 14),gFont("Regular", 24)],
79 <ePixmap pixmap="skin_default/buttons/button_green.png" position="30,370" zPosition="10" size="15,16" transparent="1" alphatest="on" />
80 <widget name="mounttext" position="50,370" size="250,21" zPosition="10" font="Regular;21" transparent="1" />
81 <ePixmap pixmap="skin_default/buttons/button_blue.png" position="30,395" zPosition="10" size="15,16" transparent="1" alphatest="on" />
82 <widget name="searchtext" position="50,395" size="150,21" zPosition="10" font="Regular;21" transparent="1" />
83 <widget name="infotext" position="300,375" size="250,21" zPosition="10" font="Regular;21" transparent="1" />
84 <ePixmap pixmap="skin_default/buttons/button_red.png" position="410,420" zPosition="10" size="15,16" transparent="1" alphatest="on" />
85 <widget name="closetext" position="430,420" size="120,21" zPosition="10" font="Regular;21" transparent="1" />
86 <ePixmap pixmap="skin_default/buttons/button_yellow.png" position="30,420" zPosition="10" size="15,16" transparent="1" alphatest="on" />
87 <widget name="rescantext" position="50,420" size="300,21" zPosition="10" font="Regular;21" transparent="1" />
90 def __init__(self, session, iface,plugin_path):
91 Screen.__init__(self, session)
92 self.skin_path = plugin_path
93 self.session = session
95 if self.iface is None:
97 self.networklist = None
101 self.cache_ttl = 604800 #Seconds cache is considered valid, 7 Days should be ok
102 self.cache_file = '/etc/enigma2/networkbrowser.cache' #Path to cache directory
104 self["closetext"] = Label(_("Close"))
105 self["mounttext"] = Label(_("Mounts management"))
106 self["rescantext"] = Label(_("Rescan network"))
107 self["infotext"] = Label(_("Press OK to mount!"))
108 self["searchtext"] = Label(_("Scan IP"))
110 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],
115 "green": self.keyGreen,
116 "yellow": self.keyYellow,
117 "blue": self.keyBlue,
123 self["list"] = List(self.list)
124 self["list"].onSelectionChanged.append(self.selectionChanged)
126 self.onLayoutFinish.append(self.startRun)
127 self.onShown.append(self.setWindowTitle)
128 self.onClose.append(self.cleanup)
129 self.Timer = eTimer()
130 self.Timer.callback.append(self.TimerFire)
134 iAutoMount.stopMountConsole()
135 iNetwork.stopRestartConsole()
136 iNetwork.stopGetInterfacesConsole()
139 self.setStatus('update')
140 self.mounts = iAutoMount.getMountsList()
141 self["infotext"].hide()
142 self.vc = valid_cache(self.cache_file, self.cache_ttl)
143 if self.cache_ttl > 0 and self.vc != 0:
144 self.process_NetworkIPs()
146 self.Timer.start(3000)
150 self.process_NetworkIPs()
152 def setWindowTitle(self):
153 self.setTitle(_("Browse network neighbourhood"))
156 self.session.open(AutoMountManager, None, self.skin_path)
159 if (os_path.exists(self.cache_file) == True):
160 remove(self.cache_file)
164 self.session.openWithCallback(self.scanIPclosed,ScanIP)
166 def scanIPclosed(self,result):
168 print "got IP:",result
171 strIP = str(result) + "/24"
172 nwlist.append(netscan.netzInfo(strIP))
173 self.networklist = nwlist[0]
174 if len(self.networklist) > 0:
175 self.updateHostsList()
177 def setStatus(self,status = None):
180 if status == 'update':
181 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/update.png"))
182 self.statuslist.append(( ['info'], statuspng, _("Searching your network. Please wait..."), None, None, None, None ))
183 self['list'].setList(self.statuslist)
184 elif status == 'error':
185 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/error.png"))
186 self.statuslist.append(( ['info'], statuspng, _("No network devices found!"), None, None, None, None ))
187 self['list'].setList(self.statuslist)
189 def process_NetworkIPs(self):
191 self.vc = valid_cache(self.cache_file, self.cache_ttl)
192 if self.cache_ttl > 0 and self.vc != 0:
193 print 'Loading network cache from ',self.cache_file
195 self.networklist = load_cache(self.cache_file)
198 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:
199 print 'Getting fresh network list'
200 self.networklist = self.getNetworkIPs()
201 write_cache(self.cache_file, self.networklist)
202 if len(self.networklist) > 0:
203 self.updateHostsList()
205 self.setStatus('error')
207 def getNetworkIPs(self):
210 self.IP = iNetwork.getAdapterAttribute(self.iface, "ip")
212 strIP = str(self.IP[0]) + "." + str(self.IP[1]) + "." + str(self.IP[2]) + ".0/24"
213 nwlist.append(netscan.netzInfo(strIP))
217 def getNetworkShares(self,hostip,hostname,devicetype):
219 self.sharecache_file = None
220 self.sharecache_file = '/etc/enigma2/' + hostname.strip() + '.cache' #Path to cache directory
221 if os_path.exists(self.sharecache_file):
222 print 'Loading userinfo from ',self.sharecache_file
224 self.hostdata = load_cache(self.sharecache_file)
225 username = self.hostdata['username']
226 password = self.hostdata['password']
228 username = "username"
229 password = "password"
231 username = "username"
232 password = "password"
234 if devicetype == 'unix':
235 smblist=netscan.smbShare(hostip,hostname,username,password)
240 nfslist=netscan.nfsShare(hostip,hostname)
245 smblist=netscan.smbShare(hostip,hostname,username,password)
252 def updateHostsList(self):
255 for x in self.networklist:
256 if not self.network.has_key(x[2]):
257 self.network[x[2]] = []
258 self.network[x[2]].append((NetworkDescriptor(name = x[1], description = x[2]), x))
260 for x in self.network.keys():
261 hostentry = self.network[x][0][1]
262 name = hostentry[2] + " ( " +hostentry[1].strip() + " )"
263 expandableIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/host.png"))
264 self.list.append(( hostentry, expandableIcon, name, None, None, None, None ))
267 for entry in self.list:
268 entry[0][2]= "%3s.%3s.%3s.%3s" % tuple(entry[0][2].split("."))
269 self.list.sort(key=lambda x: x[0][2])
270 for entry in self.list:
271 entry[0][2]= entry[0][2].replace(" ", "")
272 self["list"].setList(self.list)
273 self["list"].setIndex(self.listindex)
275 def updateNetworkList(self):
278 self.mounts = iAutoMount.getMountsList() # reloading mount list
279 for x in self.networklist:
280 if not self.network.has_key(x[2]):
281 self.network[x[2]] = []
282 self.network[x[2]].append((NetworkDescriptor(name = x[1], description = x[2]), x))
283 self.network.keys().sort()
284 for x in self.network.keys():
285 if self.network[x][0][1][3] == '00:00:00:00:00:00':
288 self.device = 'windows'
289 if x in self.expanded:
290 networkshares = self.getNetworkShares(x,self.network[x][0][1][1].strip(),self.device)
291 hostentry = self.network[x][0][1]
292 name = hostentry[2] + " ( " +hostentry[1].strip() + " )"
293 expandedIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/host.png"))
294 self.list.append(( hostentry, expandedIcon, name, None, None, None, None ))
295 for share in networkshares:
296 self.list.append(self.BuildNetworkShareEntry(share))
297 else: # HOSTLIST - VIEW
298 hostentry = self.network[x][0][1]
299 name = hostentry[2] + " ( " +hostentry[1].strip() + " )"
300 expandableIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/host.png"))
301 self.list.append(( hostentry, expandableIcon, name, None, None, None, None ))
303 for entry in self.list:
304 entry[0][2]= "%3s.%3s.%3s.%3s" % tuple(entry[0][2].split("."))
305 self.list.sort(key=lambda x: x[0][2])
306 for entry in self.list:
307 entry[0][2]= entry[0][2].replace(" ", "")
308 self["list"].setList(self.list)
309 self["list"].setIndex(self.listindex)
311 def BuildNetworkShareEntry(self,share):
312 verticallineIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/verticalLine.png"))
314 localsharename = share[1]
317 if sharetype == 'smbShare':
319 sharedescription = share[5]
322 sharedescription = share[3]
324 if sharetype == 'nfsShare':
325 newpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/i-nfs.png"))
327 newpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/i-smb.png"))
329 self.isMounted = False
330 for sharename, sharedata in self.mounts.items():
331 if sharedata['ip'] == sharehost:
332 if sharetype == 'nfsShare' and sharedata['mounttype'] == 'nfs':
333 if sharedir == sharedata['sharedir']:
334 if sharedata["isMounted"] is True:
335 self.isMounted = True
336 if sharetype == 'smbShare' and sharedata['mounttype'] == 'cifs':
337 if sharedir == sharedata['sharedir']:
338 if sharedata["isMounted"] is True:
339 self.isMounted = True
340 if self.isMounted is True:
341 isMountedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/ok.png"))
343 isMountedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/cancel.png"))
345 return((share, verticallineIcon, None, sharedir, sharedescription, newpng, isMountedpng))
347 def selectionChanged(self):
348 current = self["list"].getCurrent()
349 self.listindex = self["list"].getIndex()
351 if current[0][0] in ("nfsShare", "smbShare"):
352 self["infotext"].show()
354 self["infotext"].hide()
357 sel = self["list"].getCurrent()
362 selectedhost = sel[0][2]
363 selectedhostname = sel[0][1]
365 self.hostcache_file = None
366 if sel[0][0] == 'host': # host entry selected
367 if selectedhost in self.expanded:
368 self.expanded.remove(selectedhost)
369 self.updateNetworkList()
371 self.hostcache_file = '/etc/enigma2/' + selectedhostname.strip() + '.cache' #Path to cache directory
372 if os_path.exists(self.hostcache_file):
373 print 'Loading userinfo cache from ',self.hostcache_file
375 self.hostdata = load_cache(self.hostcache_file)
376 self.passwordQuestion(False)
378 self.session.openWithCallback(self.passwordQuestion, MessageBox, (_("Do you want to enter a username and password for this host?\n") ) )
380 self.session.openWithCallback(self.passwordQuestion, MessageBox, (_("Do you want to enter a username and password for this host?\n") ) )
381 if sel[0][0] == 'nfsShare': # share entry selected
382 self.openMountEdit(sel[0])
383 if sel[0][0] == 'smbShare': # share entry selected
384 self.openMountEdit(sel[0])
386 def passwordQuestion(self, ret = False):
387 sel = self["list"].getCurrent()
388 selectedhost = sel[0][2]
389 selectedhostname = sel[0][1]
391 self.session.openWithCallback(self.UserDialogClosed, UserDialog, self.skin_path, selectedhostname.strip())
393 if sel[0][0] == 'host': # host entry selected
394 if selectedhost in self.expanded:
395 self.expanded.remove(selectedhost)
397 self.expanded.append(selectedhost)
398 self.updateNetworkList()
399 if sel[0][0] == 'nfsShare': # share entry selected
400 self.openMountEdit(sel[0])
401 if sel[0][0] == 'smbShare': # share entry selected
402 self.openMountEdit(sel[0])
404 def UserDialogClosed(self, *ret):
405 if ret is not None and len(ret):
408 def openMountEdit(self, selection):
409 if selection is not None and len(selection):
410 mounts = iAutoMount.getMountsList()
411 if selection[0] == 'nfsShare': # share entry selected
412 #Initialize blank mount enty
413 data = { 'isMounted': False, 'active': False, 'ip': False, 'sharename': False, 'sharedir': False, 'username': False, 'password': False, 'mounttype' : False, 'options' : False }
415 data['mounttype'] = 'nfs'
416 data['active'] = True
417 data['ip'] = selection[2]
418 data['sharename'] = selection[1]
419 data['sharedir'] = selection[4]
420 data['options'] = "rw,nolock"
422 for sharename, sharedata in mounts.items():
423 if sharedata['ip'] == selection[2] and sharedata['sharedir'] == selection[4]:
425 self.session.openWithCallback(self.MountEditClosed,AutoMountEdit, self.skin_path, data)
426 if selection[0] == 'smbShare': # share entry selected
427 #Initialize blank mount enty
428 data = { 'isMounted': False, 'active': False, 'ip': False, 'sharename': False, 'sharedir': False, 'username': False, 'password': False, 'mounttype' : False, 'options' : False }
430 data['mounttype'] = 'cifs'
431 data['active'] = True
432 data['ip'] = selection[2]
433 data['sharename'] = selection[1]
434 data['sharedir'] = selection[3]
435 data['options'] = "rw"
436 self.sharecache_file = None
437 self.sharecache_file = '/etc/enigma2/' + selection[1].strip() + '.cache' #Path to cache directory
438 if os_path.exists(self.sharecache_file):
439 print 'Loading userinfo from ',self.sharecache_file
441 self.hostdata = load_cache(self.sharecache_file)
442 data['username'] = self.hostdata['username']
443 data['password'] = self.hostdata['password']
445 data['username'] = "username"
446 data['password'] = "password"
448 data['username'] = "username"
449 data['password'] = "password"
451 for sharename, sharedata in mounts.items():
452 if sharedata['ip'] == selection[2].strip() and sharedata['sharedir'] == selection[3].strip():
454 self.session.openWithCallback(self.MountEditClosed,AutoMountEdit, self.skin_path, data)
456 def MountEditClosed(self, returnValue = None):
457 if returnValue == None:
458 self.updateNetworkList()
460 class ScanIP(Screen):
462 <screen name="IPKGSource" position="100,100" size="550,80" title="IPKG source" >
463 <widget name="text" position="10,10" size="530,25" font="Regular;20" backgroundColor="background" foregroundColor="#cccccc" />
464 <ePixmap pixmap="skin_default/buttons/red.png" position="10,40" zPosition="2" size="140,40" transparent="1" alphatest="on" />
465 <widget name="closetext" position="20,50" size="140,21" zPosition="10" font="Regular;21" transparent="1" />
466 <ePixmap pixmap="skin_default/buttons/green.png" position="160,40" zPosition="2" size="140,40" transparent="1" alphatest="on" />
467 <widget name="edittext" position="170,50" size="300,21" zPosition="10" font="Regular;21" transparent="1" />
470 def __init__(self, session):
471 Screen.__init__(self, session)
472 self.session = session
476 x= int(desk.size().width())
477 y= int(desk.size().height())
478 #print "[IPKGSource] mainscreen: current desktop size: %dx%d" % (x,y)
480 self["closetext"] = Label(_("Cancel"))
481 self["edittext"] = Label(_("OK"))
484 self["text"] = Input(text, maxSize=False, type=Input.TEXT)
486 self["text"] = Input(text, maxSize=False, visible_width = 55, type=Input.TEXT)
488 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "TextEntryActions", "KeyboardInputActions","ShortcutActions"],
494 "left": self.keyLeft,
495 "right": self.keyRight,
496 "home": self.keyHome,
498 "deleteForward": self.keyDeleteForward,
499 "deleteBackward": self.keyDeleteBackward,
500 "1": self.keyNumberGlobal,
501 "2": self.keyNumberGlobal,
502 "3": self.keyNumberGlobal,
503 "4": self.keyNumberGlobal,
504 "5": self.keyNumberGlobal,
505 "6": self.keyNumberGlobal,
506 "7": self.keyNumberGlobal,
507 "8": self.keyNumberGlobal,
508 "9": self.keyNumberGlobal,
509 "0": self.keyNumberGlobal
512 self.onLayoutFinish.append(self.layoutFinished)
517 def layoutFinished(self):
518 self.setWindowTitle()
521 def setWindowTitle(self):
522 self.setTitle(_("Enter IP to scan..."))
525 text = self["text"].getText()
541 def keyDeleteForward(self):
542 self["text"].delete()
544 def keyDeleteBackward(self):
545 self["text"].deleteBackward()
547 def keyNumberGlobal(self, number):
548 self["text"].number(number)