-fix typoo in it.po, thx Spaeleus
[enigma2-plugins.git] / networkbrowser / src / NetworkBrowser.py
1 # -*- coding: utf-8 -*-\r
2 # for localized messages\r
3 from __init__ import _\r
4 from enigma import eTimer\r
5 from Screens.Screen import Screen\r
6 from Screens.MessageBox import MessageBox\r
7 from Components.config import config, ConfigText, ConfigPassword, getConfigListEntry, ConfigNothing, ConfigSubsection, ConfigSubList, ConfigSubDict\r
8 from Components.ConfigList import ConfigListScreen\r
9 from Components.Label import Label\r
10 from Components.Pixmap import Pixmap\r
11 from Components.ActionMap import ActionMap\r
12 from Components.Sources.List import List\r
13 from Components.Network import iNetwork\r
14 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE\r
15 from Tools.LoadPixmap import LoadPixmap\r
16 from cPickle import dump, load\r
17 from os import path as os_path, unlink, stat, mkdir,remove\r
18 from time import time\r
19 from stat import ST_MTIME\r
20 \r
21 import netscan\r
22 from MountManager import AutoMountManager\r
23 from AutoMount import iAutoMount\r
24 from MountEdit import AutoMountEdit\r
25 from UserDialog import UserDialog\r
26 \r
27 def write_cache(cache_file, cache_data):\r
28         #Does a cPickle dump\r
29         if not os_path.isdir( os_path.dirname(cache_file) ):\r
30                 try:\r
31                         mkdir( os_path.dirname(cache_file) )\r
32                 except OSError:\r
33                             print os_path.dirname(cache_file), 'is a file'\r
34         fd = open(cache_file, 'w')\r
35         dump(cache_data, fd, -1)\r
36         fd.close()\r
37 \r
38 def valid_cache(cache_file, cache_ttl):\r
39         #See if the cache file exists and is still living\r
40         try:\r
41                 mtime = stat(cache_file)[ST_MTIME]\r
42         except:\r
43                 return 0\r
44         curr_time = time()\r
45         if (curr_time - mtime) > cache_ttl:\r
46                 return 0\r
47         else:\r
48                 return 1\r
49 \r
50 def load_cache(cache_file):\r
51         #Does a cPickle load\r
52         fd = open(cache_file)\r
53         cache_data = load(fd)\r
54         fd.close()\r
55         return cache_data\r
56 \r
57 class NetworkDescriptor:\r
58         def __init__(self, name = "NetworkServer", description = ""):\r
59                 self.name = name\r
60                 self.description = description\r
61 \r
62 class NetworkBrowser(Screen):\r
63         skin = """\r
64                 <screen name="NetworkBrowser" position="90,80" size="560,450" title="Network Neighbourhood">\r
65                         <ePixmap pixmap="skin_default/bottombar.png" position="10,360" size="540,120" zPosition="1" transparent="1" alphatest="on" />\r
66                         <widget source="list" render="Listbox" position="10,10" size="540,350" zPosition="10" scrollbarMode="showOnDemand">\r
67                                 <convert type="TemplatedMultiContent">\r
68                                         {"template": [\r
69                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 0), size = (48, 48), png = 1), # index 1 is the expandable/expanded/verticalline icon\r
70                                                         MultiContentEntryText(pos = (50, 4), size = (420, 26), font=2, flags = RT_HALIGN_LEFT, text = 2), # index 2 is the Hostname\r
71                                                         MultiContentEntryText(pos = (140, 5), size = (320, 25), font=0, flags = RT_HALIGN_LEFT, text = 3), # index 3 is the sharename\r
72                                                         MultiContentEntryText(pos = (140, 26), size = (320, 17), font=1, flags = RT_HALIGN_LEFT, text = 4), # index 4 is the sharedescription\r
73                                                         MultiContentEntryPixmapAlphaTest(pos = (45, 0), size = (48, 48), png = 5), # index 5 is the nfs/cifs icon\r
74                                                         MultiContentEntryPixmapAlphaTest(pos = (90, 0), size = (48, 48), png = 6), # index 6 is the isMounted icon\r
75                                                 ],\r
76                                         "fonts": [gFont("Regular", 20),gFont("Regular", 14),gFont("Regular", 24)],\r
77                                         "itemHeight": 50\r
78                                         }\r
79                                 </convert>\r
80                         </widget>\r
81                         <ePixmap pixmap="skin_default/buttons/button_green.png" position="30,375" zPosition="10" size="15,16" transparent="1" alphatest="on" />\r
82                         <widget name="mounttext" position="50,375" size="250,21" zPosition="10" font="Regular;21" transparent="1" />\r
83                         <widget name="infotext" position="300,375" size="250,21" zPosition="10" font="Regular;21" transparent="1" />\r
84                         <ePixmap pixmap="skin_default/buttons/button_red.png" position="410,415" zPosition="10" size="15,16" transparent="1" alphatest="on" />\r
85                         <widget name="closetext" position="430,415" size="120,21" zPosition="10" font="Regular;21" transparent="1" />\r
86                         <ePixmap pixmap="skin_default/buttons/button_yellow.png" position="30,415" zPosition="10" size="15,16" transparent="1" alphatest="on" />\r
87                         <widget name="rescantext" position="50,415" size="300,21" zPosition="10" font="Regular;21" transparent="1" />\r
88                 </screen>"""\r
89                 \r
90         def __init__(self, session, iface,plugin_path):\r
91                 Screen.__init__(self, session)\r
92                 self.skin_path = plugin_path\r
93                 self.session = session\r
94                 self.iface = iface\r
95                 if self.iface is None:\r
96                         self.iface = 'eth0'\r
97                 self.networklist = None\r
98                 self.device = None\r
99                 self.mounts = None\r
100                 self.expanded = []\r
101                 self.cache_ttl = 604800  #Seconds cache is considered valid, 7 Days should be ok\r
102                 self.cache_file = '/etc/enigma2/networkbrowser.cache' #Path to cache directory          \r
103                 \r
104                 self["closetext"] = Label(_("Close"))\r
105                 self["mounttext"] = Label(_("Mounts management"))\r
106                 self["rescantext"] = Label(_("Rescan network"))\r
107                 self["infotext"] = Label(_("Press OK to mount!"))\r
108                 \r
109                 self["shortcuts"] = ActionMap(["ShortcutActions", "WizardActions"],\r
110                 {\r
111                         "ok": self.go,\r
112                         "back": self.close,\r
113                         "red": self.close,\r
114                         "green": self.keyGreen,\r
115                         "yellow": self.keyYellow,\r
116                 })\r
117                 \r
118                 self.list = []\r
119                 self.statuslist = []\r
120                 self.listindex = 0\r
121                 self["list"] = List(self.list)\r
122                 self["list"].onSelectionChanged.append(self.selectionChanged)\r
123                 \r
124                 self.onLayoutFinish.append(self.startRun)\r
125                 self.onShown.append(self.setWindowTitle)\r
126                 self.onClose.append(self.cleanup)       \r
127                 self.Timer = eTimer()\r
128                 self.Timer.callback.append(self.TimerFire)              \r
129 \r
130         def cleanup(self):\r
131                 del self.Timer\r
132                 iAutoMount.stopMountConsole()\r
133                 iNetwork.stopRestartConsole()\r
134                 iNetwork.stopGetInterfacesConsole()\r
135 \r
136         def startRun(self):\r
137                 self.setStatus('update')\r
138                 self.mounts = iAutoMount.getMountsList()\r
139                 self["infotext"].hide()\r
140                 self.vc = valid_cache(self.cache_file, self.cache_ttl)\r
141                 if self.cache_ttl > 0 and self.vc != 0:\r
142                         self.process_NetworkIPs()\r
143                 else:\r
144                         self.Timer.start(3000)          \r
145                 \r
146         def TimerFire(self):\r
147                 self.Timer.stop()\r
148                 self.process_NetworkIPs()\r
149                 \r
150         def setWindowTitle(self):\r
151                 self.setTitle(_("Browse network neighbourhood"))\r
152                 \r
153         def keyGreen(self):\r
154                 self.session.open(AutoMountManager, None, self.skin_path)\r
155 \r
156         def keyYellow(self):\r
157                 if (os_path.exists(self.cache_file) == True):\r
158                         remove(self.cache_file)\r
159                 self.startRun() \r
160 \r
161         def setStatus(self,status = None):\r
162                 if status:\r
163                         self.statuslist = []\r
164                         if status == 'update':\r
165                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/updating.png"))\r
166                                 self.statuslist.append(( ['info'], statuspng, _("Searching your network. Please wait..."), None, None, None, None  ))\r
167                                 self['list'].setList(self.statuslist)   \r
168                         elif status == 'error':\r
169                                 statuspng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/error.png"))\r
170                                 self.statuslist.append(( ['info'], statuspng, _("No network devices found!"), None, None, None, None  ))\r
171                                 self['list'].setList(self.statuslist)                           \r
172         \r
173         def process_NetworkIPs(self):\r
174                 self.inv_cache = 0\r
175                 self.vc = valid_cache(self.cache_file, self.cache_ttl)\r
176                 if self.cache_ttl > 0 and self.vc != 0:\r
177                         print 'Loading network cache from ',self.cache_file\r
178                         try:\r
179                                 self.networklist = load_cache(self.cache_file)\r
180                         except:\r
181                                 self.inv_cache = 1\r
182                 if self.cache_ttl == 0 or self.inv_cache == 1 or self.vc == 0:\r
183                         print 'Getting fresh network list'\r
184                         self.networklist = self.getNetworkIPs()\r
185                         write_cache(self.cache_file, self.networklist)\r
186                 if len(self.networklist) > 0:\r
187                         self.updateHostsList()\r
188                 else:\r
189                         self.setStatus('error')\r
190                         \r
191         def getNetworkIPs(self):\r
192                 nwlist = []\r
193                 sharelist = []\r
194                 self.IP = iNetwork.getAdapterAttribute(self.iface, "ip")\r
195                 if len(self.IP):\r
196                         strIP = str(self.IP[0]) + "." + str(self.IP[1]) + "." + str(self.IP[2]) + ".0/24"\r
197                         nwlist.append(netscan.netzInfo(strIP))\r
198                 tmplist = nwlist[0]\r
199                 return tmplist\r
200         \r
201         def getNetworkShares(self,hostip,hostname,devicetype):\r
202                 sharelist = []\r
203                 self.sharecache_file = None\r
204                 self.sharecache_file = '/etc/enigma2/' + hostname.strip() + '.cache' #Path to cache directory\r
205                 if os_path.exists(self.sharecache_file):\r
206                         print 'Loading userinfo from ',self.sharecache_file\r
207                         try:\r
208                                 self.hostdata = load_cache(self.sharecache_file)\r
209                                 username = self.hostdata['username']\r
210                                 password = self.hostdata['password']\r
211                         except:\r
212                                 username = "username"\r
213                                 password = "password"\r
214                 else:\r
215                         username = "username"\r
216                         password = "password"\r
217                         \r
218                 if devicetype == 'unix':\r
219                         smblist=netscan.smbShare(hostip,hostname,username,password)\r
220                         for x in smblist:\r
221                                 if len(x) == 6:\r
222                                         if x[3] != 'IPC$':\r
223                                                 sharelist.append(x)\r
224                         nfslist=netscan.nfsShare(hostip,hostname)\r
225                         for x in nfslist:\r
226                                 if len(x) == 6:\r
227                                         sharelist.append(x)\r
228                 else:\r
229                         smblist=netscan.smbShare(hostip,hostname,username,password)\r
230                         for x in smblist:\r
231                                 if len(x) == 6:\r
232                                         if x[3] != 'IPC$':\r
233                                                 sharelist.append(x)                     \r
234                 return sharelist\r
235 \r
236         def updateHostsList(self):\r
237                 self.list = []\r
238                 self.network = {}\r
239                 for x in self.networklist:\r
240                         if not self.network.has_key(x[2]):\r
241                                 self.network[x[2]] = []\r
242                         self.network[x[2]].append((NetworkDescriptor(name = x[1], description = x[2]), x))\r
243                 self.network.keys().sort()\r
244                 for x in self.network.keys():\r
245                         hostentry = self.network[x][0][1]\r
246                         name = hostentry[2] + " ( " +hostentry[1].strip() + " )"\r
247                         print hostentry\r
248                         expandableIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/host.png"))\r
249                         self.list.append(( hostentry, expandableIcon, name, None, None, None, None  ))\r
250                 self["list"].setList(self.list)\r
251                 self["list"].setIndex(self.listindex)\r
252 \r
253         def updateNetworkList(self):\r
254                 self.list = []\r
255                 self.network = {}\r
256                 for x in self.networklist:\r
257                         if not self.network.has_key(x[2]):\r
258                                 self.network[x[2]] = []\r
259                         self.network[x[2]].append((NetworkDescriptor(name = x[1], description = x[2]), x))\r
260                 self.network.keys().sort()\r
261                 for x in self.network.keys():\r
262                         if self.network[x][0][1][3] == '00:00:00:00:00:00':\r
263                                 self.device = 'unix'\r
264                         else:\r
265                                 self.device = 'windows'\r
266                         if x in self.expanded:\r
267                                 networkshares = self.getNetworkShares(x,self.network[x][0][1][1].strip(),self.device)\r
268                                 hostentry = self.network[x][0][1]\r
269                                 name = hostentry[2] + " ( " +hostentry[1].strip() + " )"\r
270                                 expandedIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/host.png"))\r
271                                 self.list.append(( hostentry, expandedIcon, name,  None, None, None, None  ))\r
272                                 for share in networkshares:\r
273                                         self.list.append(self.BuildNetworkShareEntry(share))\r
274                         else: # HOSTLIST - VIEW\r
275                                 hostentry = self.network[x][0][1]\r
276                                 name = hostentry[2] + " ( " +hostentry[1].strip() + " )"\r
277                                 expandableIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/host.png"))\r
278                                 self.list.append(( hostentry, expandableIcon, name,  None, None, None, None  ))\r
279                 self["list"].setList(self.list)\r
280                 self["list"].setIndex(self.listindex)\r
281 \r
282         def BuildNetworkShareEntry(self,share):\r
283                 verticallineIcon = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/verticalLine.png"))\r
284                 sharetype = share[0]\r
285                 localsharename = share[1]\r
286                 sharehost = share[2]\r
287 \r
288                 if sharetype == 'smbShare':\r
289                         sharedir = share[3]\r
290                         sharedescription = share[5]\r
291                 else:\r
292                         sharedir = share[4]\r
293                         sharedescription = share[3]\r
294 \r
295                 if sharetype == 'nfsShare':\r
296                         newpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/i-nfs.png"))\r
297                 else:\r
298                         newpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/i-smb.png"))\r
299 \r
300                 self.isMounted = False\r
301                 for sharename, sharedata in self.mounts.items():\r
302                         if sharedata['ip'] == sharehost:\r
303                                 if sharetype == 'nfsShare' and sharedata['mounttype'] == 'nfs':\r
304                                         if sharedir == sharedata['sharedir']:\r
305                                                 if sharedata["isMounted"] is True:\r
306                                                         self.isMounted = True\r
307                                 if sharetype == 'smbShare' and sharedata['mounttype'] == 'cifs':\r
308                                         if sharedir == sharedata['sharedir']:\r
309                                                 if sharedata["isMounted"] is True:\r
310                                                         self.isMounted = True\r
311                 if self.isMounted is True:\r
312                         isMountedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/ok.png"))\r
313                 else:\r
314                         isMountedpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_PLUGINS, "SystemPlugins/NetworkBrowser/icons/cancel.png"))\r
315                         \r
316                 return((share, verticallineIcon, None, sharedir, sharedescription, newpng, isMountedpng))\r
317 \r
318         def selectionChanged(self):\r
319                 current = self["list"].getCurrent()\r
320                 self.listindex = self["list"].getIndex()\r
321                 print len(current)\r
322                 if current:\r
323                         if current[0][0] in ( "nfsShare", "smbShare"):\r
324                                 self["infotext"].show()\r
325                         else:\r
326                                 self["infotext"].hide()\r
327                 \r
328         def go(self):\r
329                 sel = self["list"].getCurrent()\r
330                 if sel is None:\r
331                         return\r
332                 if len(sel[0]) <= 1:\r
333                         return\r
334                 selectedhost = sel[0][2]\r
335                 selectedhostname = sel[0][1]\r
336 \r
337                 self.hostcache_file = None\r
338                 if sel[0][0] == 'host': # host entry selected\r
339                         if selectedhost in self.expanded:\r
340                                 self.expanded.remove(selectedhost)\r
341                                 self.updateNetworkList()\r
342                         else:\r
343                                 self.hostcache_file = '/etc/enigma2/' + selectedhostname.strip() + '.cache' #Path to cache directory\r
344                                 if os_path.exists(self.hostcache_file):\r
345                                         print 'Loading userinfo cache from ',self.hostcache_file\r
346                                         try:\r
347                                                 self.hostdata = load_cache(self.hostcache_file)\r
348                                                 self.passwordQuestion(False)\r
349                                         except:\r
350                                                 self.session.openWithCallback(self.passwordQuestion, MessageBox, (_("Do you want to enter a username and password for this host?\n") ) )\r
351                                 else:\r
352                                         self.session.openWithCallback(self.passwordQuestion, MessageBox, (_("Do you want to enter a username and password for this host?\n") ) )\r
353                 if sel[0][0] == 'nfsShare': # share entry selected\r
354                         self.openMountEdit(sel[0])\r
355                 if sel[0][0] == 'smbShare': # share entry selected\r
356                         self.openMountEdit(sel[0])\r
357 \r
358         def passwordQuestion(self, ret = False):\r
359                 sel = self["list"].getCurrent()\r
360                 selectedhost = sel[0][2]\r
361                 selectedhostname = sel[0][1]\r
362                 if (ret == True):\r
363                         self.session.openWithCallback(self.UserDialogClosed, UserDialog, self.skin_path, selectedhostname.strip())\r
364                 else:\r
365                         if sel[0][0] == 'host': # host entry selected\r
366                                 if selectedhost in self.expanded:\r
367                                         self.expanded.remove(selectedhost)\r
368                                 else:\r
369                                         self.expanded.append(selectedhost)\r
370                                 self.updateNetworkList()\r
371                         if sel[0][0] == 'nfsShare': # share entry selected\r
372                                 self.openMountEdit(sel[0])\r
373                         if sel[0][0] == 'smbShare': # share entry selected\r
374                                 self.openMountEdit(sel[0])\r
375 \r
376         def UserDialogClosed(self, *ret):\r
377                 if ret is not None and len(ret):\r
378                         self.go()\r
379                         \r
380         def openMountEdit(self, selection):\r
381                 if selection is not None and len(selection):\r
382                         mounts = iAutoMount.getMountsList()\r
383                         if selection[0] == 'nfsShare': # share entry selected\r
384                                 #Initialize blank mount enty\r
385                                 data = { 'isMounted': False, 'active': False, 'ip': False, 'sharename': False, 'sharedir': False, 'username': False, 'password': False, 'mounttype' : False, 'options' : False } \r
386                                 # add data\r
387                                 data['mounttype'] = 'nfs'\r
388                                 data['active'] = True\r
389                                 data['ip'] = selection[2]\r
390                                 data['sharename'] = selection[1]\r
391                                 data['sharedir'] = selection[4]\r
392                                 data['options'] = "rw,nolock"\r
393 \r
394                                 for sharename, sharedata in mounts.items():\r
395                                         if sharedata['ip'] == selection[2] and sharedata['sharedir'] == selection[4]:\r
396                                                 data = sharedata\r
397                                 self.session.openWithCallback(self.MountEditClosed,AutoMountEdit, self.skin_path, data)\r
398                         if selection[0] == 'smbShare': # share entry selected\r
399                                 #Initialize blank mount enty\r
400                                 data = { 'isMounted': False, 'active': False, 'ip': False, 'sharename': False, 'sharedir': False, 'username': False, 'password': False, 'mounttype' : False, 'options' : False } \r
401                                 # add data\r
402                                 data['mounttype'] = 'cifs'\r
403                                 data['active'] = True\r
404                                 data['ip'] = selection[2]\r
405                                 data['sharename'] = selection[1]\r
406                                 data['sharedir'] = selection[3]\r
407                                 data['options'] = "rw"\r
408                                 self.sharecache_file = None\r
409                                 self.sharecache_file = '/etc/enigma2/' + selection[1].strip() + '.cache' #Path to cache directory\r
410                                 if os_path.exists(self.sharecache_file):\r
411                                         print 'Loading userinfo from ',self.sharecache_file\r
412                                         try:\r
413                                                 self.hostdata = load_cache(self.sharecache_file)\r
414                                                 print "self.hostdata", self.hostdata\r
415                                                 data['username'] = self.hostdata['username']\r
416                                                 data['password'] = self.hostdata['password']\r
417                                         except:\r
418                                                 data['username'] = "username"\r
419                                                 data['password'] = "password"\r
420                                 else:\r
421                                         data['username'] = "username"\r
422                                         data['password'] = "password"\r
423 \r
424                                 for sharename, sharedata in mounts.items():\r
425                                         if sharedata['ip'] == selection[2].strip() and sharedata['sharedir'] == selection[3].strip():\r
426                                                 data = sharedata\r
427                                 self.session.openWithCallback(self.MountEditClosed,AutoMountEdit, self.skin_path, data)\r
428 \r
429         def MountEditClosed(self, returnValue = None):\r
430                 if returnValue == None:\r
431                         self.updateNetworkList()\r