Updated pbkdf2.py to the newest upstream version
[cnetworkmanager.git] / cnetworkmanager
blobd40b757e0cbccd50b45d4dc6b46c84dd591ed141
1 #! /usr/bin/python
2 # cnetworkmanager: Command Line Interface for NetworkManager
3 # by: http://en.opensuse.org/User:Mvidner
4 # license: http://www.gnu.org/licenses/gpl-2.0.html or later
6 VERSION = "0.8.3"
7 print "cnetworkmanager %s - Command Line Interface for NetworkManager" % VERSION
9 norpm = False
10 import sys
11 # find other modules in our prefix, if specified
12 if len(sys.argv) > 2 and sys.argv[1] == "--prefix":
13 prefix = sys.argv[2]
14 sys.argv[1:] = sys.argv[3:]
15 sys.path.append(prefix + "/share/cnetworkmanager");
17 import os
18 import string
19 import re
20 import time
21 import uuid
22 import math
23 import hashlib
24 import pbkdf2
25 from binascii import hexlify
26 import ConfigParser # knm config
27 from optparse import OptionParser
28 try:
29 import dbus
30 import dbus.service
31 import _dbus_bindings
32 except:
33 print "Install python-1-dbus.rpm or or python-dbus.rpm or python-dbus.deb"
34 norpm = True
35 import xml.dom.minidom
36 try:
37 import gobject
38 except:
39 # todo - only if loop wanted
40 print "Install python-gobject2.rpm or pygobject2.rpm or python-gobject.deb"
41 norpm = True
42 # python-gnome.rpm has gconf for nm-applet...
43 if norpm:
44 sys.exit(1)
46 from dbus.mainloop.glib import DBusGMainLoop
47 DBusGMainLoop(set_as_default=True)
49 LOOP = False
51 bus = dbus.SystemBus()
53 # FOOC = connection (service) string
54 # FOOI = interface string
55 # fooo = object
56 # fooi = interface
57 # foopi = property interface
58 NMC = 'org.freedesktop.NetworkManager'
59 NMI = NMC
60 PI = 'org.freedesktop.DBus.Properties'
61 SSC = "org.freedesktop.NetworkManagerSystemSettings"
62 USC = "org.freedesktop.NetworkManagerUserSettings"
63 NMIC = "org.freedesktop.NetworkManagerInfo"
65 def introspect(obj):
66 ii = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
67 print ii.Introspect()
69 class cNM:
70 # TODO: pull them from introspection.xml
71 NM_STATE = ["UNKNOWN", "ASLEEP", "CONNECTING", "CONNECTED", "DISCONNECTED",]
73 def __init__(self, opath):
74 self.opath = opath
75 self.nmo = bus.get_object(NMC, self.opath)
76 self.nmi = dbus.Interface(self.nmo, NMI)
77 self.nmpi = dbus.Interface(self.nmo, PI)
79 def Api(self):
80 return "common"
82 def Dump0(self):
83 "Dumps its own info (not owned objects)."
84 pass
86 def Dump(self):
87 self.Dump0()
88 if options.dev:
89 for device in self.Devices():
90 device.Dump()
92 if options.actcon:
93 print "Active Connections"
94 aconns = self.ActiveConnections()
95 for aconn in aconns:
96 aconn.Dump()
98 def ListNets(self):
99 print "Wifi Networks:"
100 for dev in self.Devices():
101 dev.ListNets()
103 def reply_handler(self, opath):
104 print "Connected:", opath
106 def err_handler(self, *args):
107 print "ERR:", args
109 def silent_handler(self, *args):
110 pass
111 print "BOO!:", args
113 def quitter_handler(self, *args):
114 # exit the loop that runs only because of us
115 print "padla"
116 sys.exit(0)
119 def make_nm(opath):
120 "Detects NM version and chooses appropriate class"
122 nmo = bus.get_object(NMC, opath)
123 nmi = dbus.Interface(nmo, NMI)
124 try:
125 dummy = nmi.getDevices()
126 return cNM_06(opath)
127 except dbus.exceptions.DBusException:
128 return cNM_07(opath)
130 class cNM_06(cNM):
131 def Api(self):
132 return "06"
134 def SetWifiEnabled(self, v):
135 # TODO: async call, catch the state signal and exit
136 # weird: synchronous call works, but times out
137 # asynchronous call does not work
138 self.nmi.setWirelessEnabled(v,
139 reply_handler=self.quitter_handler,
140 error_handler=self.quitter_handler)
141 global LOOP
142 LOOP = True
144 def SetOnline(self, v):
145 if v:
146 self.nmi.wake(True,
147 reply_handler=self.quitter_handler,
148 error_handler=self.quitter_handler)
149 else:
150 self.nmi.sleep(True,
151 reply_handler=self.quitter_handler,
152 error_handler=self.quitter_handler)
153 global LOOP
154 LOOP = True
156 def Dump0(self):
157 print "State:", self.NM_STATE[self.nmi.state()]
158 we = self.nmi.getWirelessEnabled()
159 if isinstance(we, tuple):
160 print "Wifi enabled:", bool(we[0])
161 print "Wifi HW enabled:", bool(we[1])
162 else:
163 print "Wifi enabled:", bool(we)
165 try:
166 dup = self.nmi.getDialup()
167 print "Dialup:", dup
168 except dbus.exceptions.DBusException, e:
169 #if e.get_dbus_name() == "org.freedesktop.NetworkManager.NoDialup":
170 # pass
171 #else:
172 print e
174 def Devices(self):
175 opaths = self.nmi.getDevices()
176 return map(cDevice_06, opaths)
178 def ActiveConnections(self):
179 return [] # at most one active connection, FIXME find it
181 def reply_handler(self):
182 print "Connection requested"
184 def err_handler(self, *args):
185 print "ERR:", args
187 def ActivateConnection(self, conn, device, ap):
188 # passing *_handler makes the call asynchronous
189 self.nmi.setActiveDevice(device.opath, ssid_str(conn.Ssid()),
190 reply_handler=self.reply_handler,
191 error_handler=self.err_handler,
194 class cNM_07(cNM):
195 def Api(self):
196 return "07"
198 def SetWifiEnabled(self, v):
199 self.nmpi.Set(NMI, "WirelessEnabled", v)
201 def SetOnline(self, v):
202 self.nmi.Sleep(not v)
204 def Dump0(self):
205 print "State:", self.NM_STATE[self.nmpi.Get(NMI, "State")]
206 print "Wifi enabled:", self.nmpi.Get(NMI, "WirelessEnabled")
207 print "Wifi HW enabled:", self.nmpi.Get(NMI, "WirelessHardwareEnabled")
209 def Devices(self):
210 opaths = self.nmi.GetDevices()
211 return map(cDevice_07, opaths)
213 def ActiveConnections(self):
214 aconns = self.nmpi.Get(NMI, "ActiveConnections")
215 return map(cActiveConnection, aconns)
217 def ActivateConnection(self, conn, device, ap):
218 # passing *_handler makes the call asynchronous
219 self.nmi.ActivateConnection(USC,
220 conn.__dbus_object_path__,
221 device.opath,
222 ap.opath,
223 reply_handler=self.reply_handler,
224 error_handler=self.err_handler,
228 class cActiveConnection:
229 def __init__(self, opath):
230 self.opath = opath
232 def Dump(self):
233 print self.opath
234 co = bus.get_object(NMC, self.opath)
235 copi = dbus.Interface(co, PI)
236 for P in ["ServiceName", "Connection", "SpecificObject",]:
237 print " %s: %s" % (P, copi.Get(NMI, P))
238 devs = copi.Get(NMI, "Devices")
239 print " Devices:"
240 for dev in devs:
241 print " ", dev
243 def bitmask_str(map, value):
244 ret = []
245 for mask in sorted(map.keys()):
246 if value & mask: ret.append(map[mask])
247 return ",".join(ret)
250 class cDevice:
251 def __init__(self, opath):
252 self.opath = opath
253 self.devo = bus.get_object(NMC, self.opath)
254 self.devi = dbus.Interface(self.devo, NMI + ".Device")
255 self.devpi = dbus.Interface(self.devo, PI)
256 self.dt = None
257 self.DeviceType0()
259 DEVICE_TYPE = ["UNKNOWN", "802_3_ETHERNET", "802_11_WIRELESS",
260 "GSM", "CDMA",] #OLPC: 3 is MESH
262 def DeviceType(self):
263 return self.DEVICE_TYPE[self.DeviceType0()]
265 def ip_str(self, i32):
266 ret = []
267 ret.append("%d" % (i32 % 256))
268 i32 /= 256
269 ret.append("%d" % (i32 % 256))
270 i32 /= 256
271 ret.append("%d" % (i32 % 256))
272 i32 /= 256
273 ret.append("%d" % (i32 % 256))
274 i32 /= 256
275 return ".".join(ret)
277 def DumpIp4Config(self, opath):
278 print " Ip4Config:", opath
279 o = bus.get_object(NMC, opath)
280 pi = dbus.Interface(o, PI)
281 try:
282 for P in ["Address", "Netmask", "Broadcast", "Gateway",]: # beta2?
283 print " %s: %s" % (P, self.ip_str(pi.Get(NMI, P)))
284 except:
285 print " Addresses:"
286 addrs = pi.Get(NMI, "Addresses")
287 for addr in addrs:
288 print " %s/%s via %s" % tuple(map(self.ip_str, addr))
289 nss = pi.Get(NMI, "Nameservers")
290 print " Nameservers:", " ".join(map(self.ip_str, nss))
291 doms = pi.Get(NMI, "Domains")
292 print " Domains:", " ".join(doms)
294 NM_DEVICE_CAP = {1: "NM_SUPPORTED", 2: "CARRIER_DETECT", 4: "SCANNING", }
297 def Dump(self):
298 print "Device:", self.opath
301 IW_MODE = ["AUTO", "ADHOC", "INFRA", "MASTER",
302 "REPEAT", "SECOND", "MONITOR",]
304 def APs(self):
305 return []
307 def ListNets(self):
308 for ap in self.APs():
309 ap.ListNets()
311 # mixin
312 class cDeviceEth:
313 pass
315 class cDevice_06(cDevice):
316 def DeviceType0(self):
317 if self.dt is None:
318 self.dt = self.devi.getProperties()[2]
319 if self.dt == 1:
320 self.__class__ = cDeviceEth_06
321 elif self.dt == 2:
322 self.__class__ = cDeviceWifi_06
323 return self.dt
325 NM_ACT_STAGE = [
326 "UNKNOWN", "DEVICE_PREPARE", "DEVICE_CONFIG", "NEED_USER_KEY",
327 "IP_CONFIG_START", "IP_CONFIG_GET", "IP_CONFIG_COMMIT",
328 "ACTIVATED", "FAILED", "CANCELLED", ]
330 def Dump(self):
331 cDevice.Dump(self)
332 print " Driver:", self.devi.getDriver()
333 props = self.devi.getProperties() # osusb ussss sssii biuus as
334 print " Self:", props[0] # o
335 print " Interface:", props[1] # s
336 print " Type:", self.DEVICE_TYPE[props[2]] # u
337 print " UDI:", props[3] # s
338 print " Active:", bool(props[4]) # b
339 print " Activation Stage:", self.NM_ACT_STAGE[props[5]] # u
340 print " IP:", props[6] # s
341 print " Mask:", props[7] # s
342 print " Bcast:", props[8] # s
343 print " HwAddress:", props[9] # s
344 print " GW:", props[10] # s
345 print " NS1:", props[11] # s
346 print " NS2:", props[12] # s
347 self.DumpMore()
349 def DumpMore(self):
350 print " (unknown device type, not dumping more)"
352 class cDeviceEth_06(cDevice_06, cDeviceEth):
353 def DumpMore(self):
354 props = self.devi.getProperties() # osusb ussss sssii biuus as
355 print " Link Active:", bool(props[15]) # b
356 print " Speed:", props[16] # i
357 print " Generic Capabilities:", bitmask_str(self.NM_DEVICE_CAP, props[17]) # u
359 class cDeviceWifi_06(cDevice_06):
360 NM_802_11_CAP = {
361 0x00000001: "PROTO_NONE",
362 0x00000002: "PROTO_WEP",
363 0x00000004: "PROTO_WPA",
364 0x00000008: "PROTO_WPA2",
365 0x00000010: "RESERVED1",
366 0x00000020: "RESERVED2",
367 0x00000040: "KEY_MGMT_PSK",
368 0x00000080: "KEY_MGMT_802_1X",
369 0x00000100: "RESERVED3",
370 0x00000200: "RESERVED4",
371 0x00000400: "RESERVED5",
372 0x00000800: "RESERVED6",
373 0x00001000: "CIPHER_WEP40",
374 0x00002000: "CIPHER_WEP104",
375 0x00004000: "CIPHER_TKIP",
376 0x00008000: "CIPHER_CCMP",
379 def APs(self):
380 self.wdevi = dbus.Interface(self.devo, NMI + ".Device.Wireless")
381 aps = self.devi.getProperties()[20]
382 return map(cAP_06, aps)
384 def DumpMore(self):
385 props = self.devi.getProperties() # osusb ussss sssii biuus as
386 print " Mode:", self.IW_MODE[props[13]] # i
387 print " Strength:", props[14] # i
388 print " Link Active:", bool(props[15]) # b
389 print " Speed:", props[16] # i
390 print " Generic Capabilities:", bitmask_str(self.NM_DEVICE_CAP, props[17]) # u
391 print " Capabilities:", bitmask_str(self.NM_802_11_CAP, props[18]) # u
392 print " Current net:", props[19] # s
393 nets = props[20] # as
394 print " Seen nets:", " ".join(nets)
395 if options.ap:
396 print " Access Points"
397 for ap in self.APs():
398 ap.Dump()
400 class cDevice_07(cDevice):
401 def DeviceType0(self):
402 if self.dt is None:
403 self.dt = self.devpi.Get(NMI, "DeviceType")
404 if self.dt == 1:
405 self.__class__ = cDeviceEth_07
406 elif self.dt == 2:
407 self.__class__ = cDeviceWifi_07
408 return self.dt
410 NM_DEVICE_STATE = [
411 "UNKNOWN", "UNMANAGED", "UNAVAILABLE", "DISCONNECTED", "PREPARE",
412 "CONFIG", "NEED_AUTH", "IP_CONFIG", "ACTIVATED", "FAILED",]
414 def Dump(self):
415 cDevice.Dump(self)
417 # "Ip4Config", only for NM_DEVICE_STATE_ACTIVATED
418 for P in ["Udi", "Interface", "Driver",]:
419 print " %s: %s" % (P, self.devpi.Get(NMI, P))
420 addr = self.devpi.Get(NMI, "Ip4Address")
421 print " Ip4Address:", self.ip_str(addr)
422 caps = self.devpi.Get(NMI, "Capabilities")
423 print " Capabilities:", bitmask_str(self.NM_DEVICE_CAP, caps)
424 state = self.NM_DEVICE_STATE[self.devpi.Get(NMI, "State")]
425 print " Dev State:", state
426 if state == "ACTIVATED":
427 self.DumpIp4Config(self.devpi.Get(NMI, "Ip4Config"))
429 dt = self.DeviceType()
430 print " Dev Type:", dt
431 self.DumpMore()
433 class cDeviceEth_07(cDevice_07, cDeviceEth):
434 def DumpMore(self):
435 for P in ["HwAddress", "Speed", "Carrier"]:
436 print " %s: %s" % (P, self.devpi.Get(NMI, P))
438 class cDeviceWifi_07(cDevice_07):
439 NM_802_11_DEVICE_CAP = {1:"CIPHER_WEP40", 2:"CIPHER_WEP104",
440 4:"CIPHER_TKIP", 8:"CIPHER_CCMP",
441 16:"WPA", 32:"RSN",}
443 def APs(self):
444 self.wdevi = dbus.Interface(self.devo, NMI + ".Device.Wireless")
445 aps = self.wdevi.GetAccessPoints()
446 return map(cAP_07, aps)
448 def DumpMore(self):
449 print " Dev Mode:", self.IW_MODE[self.devpi.Get(NMI, "Mode")]
450 wcaps = self.devpi.Get(NMI, "WirelessCapabilities")
451 print " Wifi Capabilities:", bitmask_str(self.NM_802_11_DEVICE_CAP, wcaps)
452 for P in ["HwAddress", "Bitrate", "ActiveAccessPoint"]:
453 print " %s: %s" % (P, self.devpi.Get(NMI, P))
454 if options.ap:
455 print " Access Points"
456 for ap in self.APs():
457 ap.Dump()
459 """An AP found around us"""
460 class cAP:
461 def __init__(self, opath):
462 self.opath = opath
463 self.apo = bus.get_object(NMC, self.opath)
464 self.appi = dbus.Interface(self.apo, PI)
465 # for _06
466 self.devi = dbus.Interface(self.apo, NMI + ".Devices")
468 NM_802_11_AP_FLAGS = {1: "PRIVACY",}
470 NM_802_11_AP_SEC = {
471 1: "PAIR_WEP40", 2: "PAIR_WEP104", 4: "PAIR_TKIP", 8: "PAIR_CCMP",
472 16: "GROUP_WEP40", 32: "GROUP_WEP104", 64: "GROUP_TKIP",
473 128: "GROUP_CCMP", 256: "KEY_MGMT_PSK", 512: "KEY_MGMT_802_1X",}
475 def ListNets(self, marker = " "):
476 # TODO *mark current
477 mbr = self.Mbr() / 1024 # 07 1000, 06 1024?
478 priv_s = self.PrivS()
479 print "%s%3d: %s (%dMb%s)" % (marker, self.Strength(), self.Ssid(), mbr, priv_s)
481 class cAP_06(cAP):
482 def Mbr(self, props=None):
483 if props is None:
484 props = self.devi.getProperties()
485 return props[5]
488 def PrivS(self):
489 props = self.devi.getProperties()
490 caps_s = bitmask_str(cDeviceWifi_06.NM_802_11_CAP, props[7]) + ","
491 priv_s = ""
492 if caps_s.find("PROTO_WEP,") != -1:
493 priv_s += " WEP"
494 if caps_s.find("PROTO_WPA,") != -1:
495 priv_s += " WPA"
496 if caps_s.find("PROTO_WPA2,") != -1:
497 priv_s += " WPA2"
498 if caps_s.find("KEY_MGMT_802_1X,") != -1:
499 priv_s += " Enterprise"
500 return priv_s
502 def Strength(self, props=None):
503 if props is None:
504 props = self.devi.getProperties()
505 return props[3]
507 def Ssid(self, props=None):
508 if props is None:
509 props = self.devi.getProperties()
510 return props[1]
513 def Dump(self):
514 props = self.devi.getProperties() # ossid iiib
515 print " Self:", props[0]
516 print " Ssid:", self.Ssid(props)
517 print " HwAddress:", props[2]
518 print " Strength:", self.Strength(props)
519 print " Frequency:", props[4]
520 print " MaxBitrate:", self.Mbr(props)
521 print " AP Mode:", cDevice.IW_MODE[props[6]]
522 print " Capabilities:", bitmask_str(cDeviceWifi_06.NM_802_11_CAP, props[7])
523 print " Broadcast:", props[8]
525 def ssid_str(array):
526 s = ""
527 for b in array:
528 s = s + ("%c" % b)
529 return s
531 def opath_validchar(c):
532 # _ is also escaped even though it is valid
533 return \
534 string.ascii_letters.find(c) != -1 or \
535 string.digits.find(c) != -1
537 def opath_escape(s):
538 r = ""
539 for c in s:
540 # TODO find a more elegant way
541 if not opath_validchar(c):
542 # "-" -> "_2d_"
543 c = "_%2x_" % ord(c)
544 r = r + c
545 return r
547 def opath_unescape(s):
548 # "2d" -> "-"
549 unhex = lambda xx: chr(eval("0x"+xx))
550 # all "_2d_" -> "-"
551 return re.sub("_.._", lambda p: unhex(p.group()[1:3]), s)
553 class cAP_07(cAP):
554 def Mbr(self):
555 return self.appi.Get(NMI, "MaxBitrate")
557 def PrivS(self):
558 priv = self.appi.Get(NMI, "Flags") != 0
559 wpa = self.appi.Get(NMI, "WpaFlags") != 0
560 wpa2 = self.appi.Get(NMI, "RsnFlags") != 0
561 priv_s = ""
562 if priv:
563 if not wpa and not wpa2:
564 priv_s = priv_s + " WEP"
565 if wpa:
566 priv_s = priv_s + " WPA"
567 if wpa2:
568 priv_s = priv_s + " WPA2"
569 return priv_s
571 def Strength(self):
572 return int(self.appi.Get(NMI, "Strength"))
574 def Ssid(self):
575 return ssid_str(self.appi.Get(NMI, "Ssid"))
577 def Dump(self):
578 print " AP:", self.opath
579 print " Ssid:", self.Ssid()
580 for P in ["Frequency", "HwAddress", "MaxBitrate",]:
581 print " %s: %s" % (P, self.appi.Get(NMI, P))
582 print " Strength:", self.Strength()
583 print " AP Mode:", cDevice.IW_MODE[self.appi.Get(NMI, "Mode")]
584 print " AP Flags:", bitmask_str(self.NM_802_11_AP_FLAGS,
585 self.appi.Get(NMI, "Flags"))
586 print " AP WPA Flags:", bitmask_str(self.NM_802_11_AP_SEC,
587 self.appi.Get(NMI, "WpaFlags"))
588 print " AP RSN Flags:", bitmask_str(self.NM_802_11_AP_SEC,
589 self.appi.Get(NMI, "RsnFlags"))
591 # this is the client side of the applet; see also UserSettings
592 class cApplet:
593 def __init__(self, svc, opath):
594 self.svc = svc
595 self.opath = opath
596 self.so = bus.get_object(self.svc, self.opath)
597 self.si = dbus.Interface(self.so, 'org.freedesktop.NetworkManagerSettings')
599 def isSystem(self):
600 return self.svc == SSC;
602 def Dump(self):
603 for conn in self.Connections():
604 conn.Dump()
605 if self.isSystem():
606 self.DumpSystem()
608 def DumpSystem(self):
609 sspi = dbus.Interface(self.so, PI)
610 print "Unmanaged Devices"
611 umds = sspi.Get(NMI, "UnmanagedDevices")
612 for umd in umds:
613 print " ", umd
614 # dump_settings_conn(svc, conn) umd?
617 def myConnection(self, opath):
618 return cConnection(self.svc, opath)
620 def Connections(self):
621 opaths = self.si.ListConnections()
622 return map(self.myConnection, opaths)
624 NETWORK_TYPE_ALLOWED = 1
625 class cApplet_06(cApplet):
626 def __init__(self, svc, opath):
627 self.svc = svc
628 self.opath = opath
629 self.io = bus.get_object(self.svc, self.opath)
630 self.ii = dbus.Interface(self.io, 'org.freedesktop.NetworkManagerInfo')
632 def isSystem(self):
633 return False;
635 def myConnection(self, opath):
636 return cConnection_06(self, opath)
638 # TODO also VPN conns
639 def Connections(self):
640 names = self.ii.getNetworks(NETWORK_TYPE_ALLOWED)
641 return map(self.myConnection, names)
643 class cConnection:
644 def __init__(self, svc, opath):
645 self.svc = svc
646 self.opath = opath
647 self.co = bus.get_object(self.svc, self.opath)
648 self.ci = dbus.Interface(self.co, 'org.freedesktop.NetworkManagerSettings.Connection')
650 def Dump(self):
651 print "Conn:", self.opath
652 settings = self.Settings()
653 settings.Dump()
655 si = dbus.Interface(self.co, 'org.freedesktop.NetworkManagerSettings.Connection.Secrets')
656 security = settings.Security()
657 if security != "":
658 print " SECRETS:", security
659 try:
660 # TODO merge them
661 secrets = cSettings(si.GetSecrets(security,[],False))
662 secrets.Dump()
663 except dbus.exceptions.DBusException, e:
664 print e
665 print " FIXME figure out 802-1x secrets"
667 def Settings(self):
668 return cSettings(self.ci.GetSettings())
670 def dump_time(unixtime):
671 return time.asctime(time.localtime(unixtime))
673 class cConnection_06:
674 def __init__(self, applet, id):
675 self.id = id
676 self.applet = applet
678 def Dump(self):
679 print "Conn:", self.id
681 np = self.applet.ii.getNetworkProperties(self.id, NETWORK_TYPE_ALLOWED)
682 ssid = np[0]
683 print " ssid:", ssid
684 print " time:", dump_time(np[1])
685 print " trusted:", bool(np[2])
686 print " bssids:", ", ".join(np[3])
687 enctype = np[4]
688 print " we_cipher:", enctype
689 if enctype != 1:
690 print " secret:", np[5]
691 if enctype == 16:
692 print " wep_auth_algorithm:", np[6]
693 elif enctype == 0:
694 print " wpa_psk_key_mgt:", np[6]
695 print " wpa_psk_wpa_version:", np[7]
697 return # nm-applet will not tell kfn anyway
698 devp = "/org/freedesktop/NetworkManager/Devices/ath0" #FIXME
699 netp = devp + "/Networks/" + opath_escape(self.id)
700 attempt = 1
701 newkey = False
702 kfn = self.applet.ii.getKeyForNetwork(devp, netp, ssid, attempt, newkey)
703 print " kfn:", kfn
706 # 06
707 NM_AUTH_TYPE_WPA_PSK_AUTO = 0x00000000
708 NM_AUTH_TYPE_NONE = 0x00000001
709 NM_AUTH_TYPE_WEP40 = 0x00000002
710 NM_AUTH_TYPE_WPA_PSK_TKIP = 0x00000004
711 NM_AUTH_TYPE_WPA_PSK_CCMP = 0x00000008
712 NM_AUTH_TYPE_WEP104 = 0x00000010
713 NM_AUTH_TYPE_WPA_EAP = 0x00000020
714 NM_AUTH_TYPE_LEAP = 0x00000040
716 IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
717 IW_AUTH_ALG_SHARED_KEY = 0x00000002
718 IW_AUTH_ALG_LEAP = 0x00000004
720 class cSettings:
721 def __init__(self, conmap):
722 #print "INIT", conmap
723 self.conmap = conmap
725 def Type(self):
726 return self.conmap["connection"]["type"]
728 def ID(self):
729 return self.conmap["connection"]["id"]
731 def Ssid(self):
732 try:
733 return self.conmap["802-11-wireless"]["ssid"]
734 except KeyError:
735 pass
736 # probably 802-3-ethernet
737 return ""
739 def Timestamp(self):
740 try:
741 return self.conmap["connection"]["timestamp"]
742 except KeyError:
743 return 0
745 def Trusted(self):
746 # false by default
747 return False
749 def SeenBssids(self):
750 try:
751 return self.conmap["802-11-wireless"]["seen-bssids"]
752 except KeyError:
753 return []
755 # for 06
756 def WeCipher(self):
757 k = self.Key()
758 if len(k) == 26:
759 return NM_AUTH_TYPE_WEP104
760 elif len(k) == 64:
761 return NM_AUTH_TYPE_WPA_PSK_AUTO
762 elif len(k) == 0:
763 return NM_AUTH_TYPE_NONE
764 print "Defaulting cipher type to none"
765 return NM_AUTH_TYPE_NONE
767 def Key(self):
768 try:
769 return self.conmap["802-11-wireless-security"]["psk"]
770 except KeyError:
771 pass
772 try:
773 return self.conmap["802-11-wireless-security"]["wep-key0"]
774 except KeyError:
775 pass
776 # no key
777 return ""
779 def WepAuthAlgorithm(self):
780 print "FIXME Defaulting WEP auth alg to open"
781 return IW_AUTH_ALG_OPEN_SYSTEM
783 def PskKeyMgt(self):
784 print "FIXME Defaulting PSK key mgmt to 2"
785 return 2
787 def PskWpaVersion(self):
788 print "FIXME Defaulting WPA version to 2"
789 return 2
791 def Security(self):
792 try:
793 return self.conmap[self.Type()]["security"]
794 except KeyError:
795 return ""
797 def isNet(self, net_name):
798 return self.ID() == net_name or self.Ssid() == net_name
800 # FIXME check spec/NM what to censor
801 secrets = dict.fromkeys(["wep-key0", "psk"])
803 def ConMap(self):
804 "For GetSettings: censor secrets."
806 cm = dict()
807 for n1, v1 in self.conmap.iteritems():
808 cm[n1] = dict()
809 for n2, v2 in v1.iteritems():
810 cv2 = v2
811 if self.secrets.has_key(n2):
812 cv2 = ""
813 cm[n1][n2] = cv2
814 return cm
816 def SecMap(self):
817 "For GetSecrets: only secrets."
818 s = self.Security()
819 r = {
820 s: self.conmap[s]
822 print "SECMAP", r
823 return r
825 def Dump(self):
826 for n1, v1 in self.conmap.iteritems():
827 print " ",n1
828 for n2, v2 in v1.iteritems():
829 print " %s: %s" % (n2, v2)
831 def mkconmap_wifi(ssid):
832 return {
833 'connection': {
834 'id': '_cnm_handcrafted_',
835 'uuid': str(uuid.uuid1()), # new in oS 11.1
836 'type': '802-11-wireless',
838 '802-11-wireless': {
839 'ssid': dbus.ByteArray(ssid),
840 'mode': 'infrastructure',
844 def elongate(s, tlen):
845 "repeat string s to target length tlen"
846 if s == "":
847 return ""
848 copies_needed = int(math.ceil(tlen / float(len(s))))
849 return (s * copies_needed)[:tlen]
851 # http://www.mail-archive.com/networkmanager-list@gnome.org/msg07935.html
852 def wep_passphrase_to_hash(p):
853 return hashlib.md5(elongate(p, 64)).hexdigest()
855 def mkconmap_wep_pass(ssid, key):
856 cm = mkconmap_wifi(ssid)
857 cm["802-11-wireless"]["security"] = "802-11-wireless-security"
858 cm["802-11-wireless-security"] = {}
859 cm["802-11-wireless-security"]["key-mgmt"] = "none"
860 cm["802-11-wireless-security"]["wep-tx-keyidx"] = 0
861 cm["802-11-wireless-security"]["wep-key0"] = wep_passphrase_to_hash(key)
862 return cm
864 def mkconmap_wep(ssid, key):
865 cm = mkconmap_wifi(ssid)
866 cm["802-11-wireless"]["security"] = "802-11-wireless-security"
867 cm["802-11-wireless-security"] = {}
868 cm["802-11-wireless-security"]["key-mgmt"] = "none"
869 cm["802-11-wireless-security"]["wep-tx-keyidx"] = 0
870 cm["802-11-wireless-security"]["wep-key0"] = key
871 return cm
873 def mkconmap_psk(ssid, key):
874 cm = mkconmap_wifi(ssid)
875 cm["802-11-wireless"]["security"] = "802-11-wireless-security"
876 cm["802-11-wireless-security"] = {}
877 cm["802-11-wireless-security"]["key-mgmt"] = "wpa-psk"
878 cm["802-11-wireless-security"]["psk"] = key
879 cm["802-11-wireless-security"]["group"] = ["tkip", "ccmp"]
880 cm["802-11-wireless-security"]["pairwise"] = ["tkip", "ccmp"]
881 return cm
884 # server analog of cApplet
885 class UserSettings(dbus.service.Object):
886 # conmaps is a list
887 def __init__(self, opath, conmaps):
888 dbus.service.Object.__init__(self, bus, opath)
889 #print "CONMAPS:", conmaps
890 self.conns = map(self.newCon, conmaps)
892 def addCon(self, conmap):
893 c = self.newCon(conmap)
894 self.conns.append(c)
895 return c
897 counter = 1
898 def newCon(self, conmap):
899 cpath = "/MyConnection/%d" % self.counter
900 self.counter = self.counter + 1
901 c = Connection(cpath, conmap)
902 self.NewConnection(cpath) # announce it
903 return c
905 @dbus.service.method(dbus_interface='org.freedesktop.NetworkManagerSettings',
906 in_signature='', out_signature='ao')
907 def ListConnections(self):
908 return [c.__dbus_object_path__ for c in self.conns]
910 #this is for EMITTING a signal, not receiving it
911 @dbus.service.signal(dbus_interface='org.freedesktop.NetworkManagerSettings',
912 signature='o')
913 def NewConnection(self, opath):
914 pass
915 #print "signalling newconn:", opath
917 def GetByNet(self, net_name):
918 "Returns connection, or None"
919 for c in self.conns:
920 if c.isNet(net_name):
921 return c
922 return None
925 class UserSettings_06(UserSettings):
926 # conmaps is a list
927 def __init__(self, opath, conmaps):
928 dbus.service.Object.__init__(self, bus, opath)
929 #print "CONMAPS:", conmaps
930 self.conns = map(self.newCon, conmaps)
932 counter = 1
933 def newCon(self, conmap):
934 cpath = "/MyConnection/%d" % self.counter
935 self.counter = self.counter + 1
936 c = Connection_06(cpath, conmap)
937 #self.NewConnection(cpath) # announce it
938 return c
940 @dbus.service.method(dbus_interface="org.freedesktop.NetworkManagerInfo",
941 in_signature="i", out_signature='as')
942 def getNetworks(self, i):
943 # FIXME bytearray to str WHERE?
944 #n = [ssid_str(c.Ssid()) for c in self.conns]
945 n = [c.ID() for c in self.conns]
946 print "getNetworks:", n
947 return n
949 @dbus.service.method(dbus_interface="org.freedesktop.NetworkManagerInfo",
950 in_signature="", out_signature='ao') # out??
951 def getVPNConnections(self):
952 return [] # FIXME
954 @dbus.service.method(dbus_interface="org.freedesktop.NetworkManagerInfo",
955 in_signature="si")
956 #out_signature='sibasi') #varies
957 def getNetworkProperties(self, net, type):
958 print "GNP", net
959 # type is 1, NETWORK_TYPE_ALLOWED
960 c = self.GetByNet(net)
961 if c != None:
962 return c.getNetworkProperties()
963 print "Oops, could not getNetworkProperties for " + net
966 @dbus.service.method(dbus_interface="org.freedesktop.NetworkManagerInfo",
967 in_signature="oosib")
968 #out_signature="isi") varies
969 def getKeyForNetwork(self, dev, net, ssid, attempt, newkey):
970 print "GKFN", dev, net, ssid, attempt, bool(newkey)
971 if newkey:
972 m = "Cannot ask for key"
973 print m
974 raise dbus.exceptions.DBusException(m)
976 snet = opath_unescape(net[net.rfind("/")+1 : ]) # only stuff after /
977 c = self.GetByNet(snet)
978 if c != None:
979 return c.getKeyForNetwork()
980 print "Oops, could not getKeyForNetwork " + net
982 @dbus.service.method(dbus_interface="org.freedesktop.NetworkManagerInfo",
983 out_signature='')
984 #in_signature="sbs isi", varies
985 def updateNetworkInfo(self, ssid, automatic, bssid, *security):
986 print "Connected successfully"
987 return
988 print "UNI"
989 print " ssid:", ssid
990 print " automatic:", bool(automatic)
991 print " bssid:", bssid
992 print " security:", security
995 def GetByNet(self, net_name):
996 "Returns connection, or None"
997 for c in self.conns:
998 if c.isNet(net_name):
999 return c
1000 return None
1003 # server analog of cConnection
1004 class Connection(dbus.service.Object):
1005 def __init__(self, opath, conmap):
1006 dbus.service.Object.__init__(self, bus, opath)
1007 self.settings = cSettings(conmap)
1009 @dbus.service.method(dbus_interface='org.freedesktop.NetworkManagerSettings.Connection',
1010 sender_keyword='sender',
1011 in_signature='', out_signature='a{sa{sv}}')
1012 def GetSettings(self, sender):
1013 #print "Getting settings:", self. __dbus_object_path__
1014 # return self.settings.ConMap()
1015 # grr, censoring secrets makes NM complain!?
1016 # bnc#479566#c3: Until I figure out how to make it work with
1017 # censored secrets, only pass the settings to the same user.
1018 sender_uid = bus.get_unix_user(sender)
1019 if sender_uid != 0 and sender_uid != os.geteuid():
1020 e = "User %u is not permitted to read the settings" % sender_uid
1021 print e
1022 raise dbus.exceptions.DBusException(e) # could do NM_SETTINGS_ERROR_* instead
1023 return self.settings.conmap
1025 @dbus.service.method(dbus_interface='org.freedesktop.NetworkManagerSettings.Connection.Secrets',
1026 in_signature='sasb', out_signature='a{sa{sv}}')
1027 def GetSecrets(self, tag, hints, ask):
1028 # FIXME respect args
1029 print "Getting secrets:", self.__dbus_object_path__
1030 return self.settings.SecMap()
1032 @dbus.service.method(dbus_interface='org.freedesktop.NetworkManagerSettings.Connection',
1033 in_signature='', out_signature='s')
1034 def ID(self):
1035 return self.settings.ID()
1037 def Ssid(self):
1038 return self.settings.Ssid()
1040 def isNet(self, net_name):
1041 return self.settings.isNet(net_name)
1043 class Connection_06(Connection):
1044 def __init__(self, opath, conmap):
1045 dbus.service.Object.__init__(self, bus, opath)
1046 #print "C6", conmap
1047 self.settings = cSettings(conmap)
1049 # dbus.service.method
1050 def getNetworkProperties(self):
1051 # essid, timestamp, ?, bssids, we_cipher, ?, ...
1052 # we_cipher=16: i wep_auth_algorithm
1053 # we_cipher=0: i wpa_psk_key_mgt, i wpa_psk_wpa_version
1054 ssid = ssid_str(self.settings.Ssid())
1055 time = self.settings.Timestamp() # last sucessfully connected? seen?
1056 trusted = self.settings.Trusted()
1057 bssids = dbus.Array(self.settings.SeenBssids(), signature="s")
1058 r = [ssid, time, trusted, bssids]
1059 security = self.getKeyForNetwork("fake key")
1060 r.extend(security)
1061 return tuple(r)
1063 # dbus.service.method
1064 def getKeyForNetwork(self, fake="no"):
1065 if fake == "no":
1066 key = self.settings.Key()
1067 else:
1068 key = ""
1070 # security
1071 cip = self.settings.WeCipher()
1072 if cip == NM_AUTH_TYPE_NONE:
1073 security = tuple([cip])
1074 elif cip == NM_AUTH_TYPE_WEP40 or cip == NM_AUTH_TYPE_WEP104:
1075 wep_auth_algorithm = self.settings.WepAuthAlgorithm()
1076 security = (cip, key, wep_auth_algorithm)
1077 elif cip == NM_AUTH_TYPE_WPA_PSK_AUTO or cip == NM_AUTH_TYPE_TKIP or \
1078 cip == NM_AUTH_TYPE_CCMP:
1079 wpa_psk_key_mgt = self.settings.PskKeyMgt()
1080 wpa_psk_wpa_version = self.settings.PskWpaVersion()
1081 security = (cip, key, wpa_psk_key_mgt, wpa_psk_wpa_version)
1082 elif cip == NM_AUTH_TYPE_WPA_EAP:
1083 security = tuple([cip]) # TODO more...
1084 elif cip == NM_AUTH_TYPE_LEAP:
1085 security = tuple([cip]) # TODO more...
1086 return security
1089 class ConfigParserKNM:
1090 "Parse ~/.kde/share/config/knetworkmanagerrc"
1092 def __init__(self):
1093 p = ConfigParser.RawConfigParser()
1094 ok = p.read(os.getenv("HOME") + "/.kde/share/config/knetworkmanagerrc")
1096 self.conmaps_d = {}
1097 for s in p.sections():
1098 path = s.split("_")
1099 #print path
1100 if path[0] in ["ConnectionSetting", "ConnectionSecrets"]:
1101 cid = path[1]
1102 self.conmaps_d.setdefault(cid, {})
1103 part = path[2]
1105 values = {}
1106 for (n, v) in p.items(s):
1107 # WTF, Value_ is transfrmed to value_
1108 if n[:6] == "value_":
1109 n = n[6:]
1110 v = self.ParseValue(v)
1111 values[n] = v
1112 if len(values) != 0: # empty 802-1x confuses NM!?
1113 self.conmaps_d[cid].setdefault(part, {})
1114 self.conmaps_d[cid][part].update(**values)
1115 #print "PARSED", cid, part, values
1117 def ConMaps(self):
1118 return self.conmaps_d.values()
1120 def ParseValue(self, v):
1121 v = eval('"%s"' % v) # unescape backslashes
1122 dom = xml.dom.minidom.parseString(v)
1123 return self.ParseNode(dom.documentElement)
1125 def ParseNode(self, n):
1126 t = n.localName
1127 if t != "list":
1128 v = self.NodeText(n)
1130 if t == "string":
1131 return v
1132 elif t == "byte":
1133 return dbus.Byte(int(v))
1134 elif t == "bool":
1135 return v == "true"
1136 elif t == "int32" or t == "uint32":
1137 return int(v)
1138 elif t == "list":
1139 v = []
1140 c = n.firstChild
1141 while c != None:
1142 if c.localName != None: # whitespace
1143 v.append(self.ParseNode(c))
1144 c = c.nextSibling
1145 return v
1147 def NodeText(self, n):
1148 if n.hasChildNodes():
1149 return n.firstChild.wholeText
1150 else:
1151 return ""
1153 def abbr_signal_handler(*args, **kwargs):
1154 ifc = kwargs["interface"]
1155 sig = kwargs["member"]
1156 opath = kwargs["path"]
1157 line = "SIG %s: %s.%s%s" % (abbrev(opath,"/"), abbrev(ifc,"."), sig, args)
1158 print line
1160 class Monitor:
1161 def __init__(self):
1162 self.amap = {}
1163 bus.add_signal_receiver(self.abbr_signal_handler,
1164 path_keyword="path",
1165 interface_keyword="interface",
1166 member_keyword="member")
1168 def abbr_signal_handler(self, *args, **kwargs):
1169 ifc = kwargs["interface"]
1170 sig = kwargs["member"]
1171 opath = kwargs["path"]
1172 line = "SIG %s: %s.%s%s" % (self.abbrev(opath,"/"),
1173 self.abbrev(ifc,"."),
1174 sig, args)
1175 print line
1177 def abbrev(self, s, sep):
1178 words = s.split(sep)
1179 words = map (self.a1, words)
1180 result = sep.join(words)
1181 if not self.amap.has_key(s):
1182 print "ABBR %s is %s" % (result, s)
1183 self.amap[s] = result
1184 else:
1185 if self.amap[s] != result:
1186 print "ABBR COLLISION %s was %s now %s" % (s, self.amap[s], result)
1187 return result
1189 def a1(self, s):
1190 try:
1191 return s[0]
1192 except:
1193 return ""
1195 # main
1197 op = OptionParser(version="%prog " + VERSION)
1198 op.add_option("-d", "--dev",
1199 action="store_true", default=False,
1200 help="list devices")
1201 op.add_option("-c", "--actcon",
1202 action="store_true", default=False,
1203 help="list active connections")
1204 op.add_option("-u", "--usrcon",
1205 action="store_true", default=False,
1206 help="list user connection settings (can CRASH nm-applet)")
1207 op.add_option("-s", "--syscon",
1208 action="store_true", default=False,
1209 help="list system connection settings")
1210 op.add_option("-a", "--ap",
1211 action="store_true", default=False,
1212 help="list found access points")
1213 op.add_option("-n", "--nets",
1214 action="store_true", default=False,
1215 help="list found wireless networks")
1216 # TODO http://docs.python.org/lib/optparse-adding-new-types.html
1217 op.add_option("-w", "--wifi",
1218 choices=["0","1","off","on","no","yes","false","true"],
1219 metavar="BOOL",
1220 help="enable or disable wireless")
1221 op.add_option("-o", "--online",
1222 choices=["0","1","off","on","no","yes","false","true"],
1223 metavar="BOOL",
1224 help="enable or disable network at all")
1226 op.add_option("-C", "--connect",
1227 help="connect to a wireless network NET (using knetworkmanagerrc or the key options below)",
1228 metavar="NET")
1229 op.add_option("--unprotected",
1230 action="store_true", default=False,
1231 help="network does not require a key")
1232 op.add_option("--wep-hex",
1233 metavar="KEY",
1234 help="use this WEP key of 26 hex digits")
1235 op.add_option("--wep-pass",
1236 metavar="KEY",
1237 help="use this WEP passphrase")
1238 op.add_option("--wpa-psk-hex",
1239 metavar="KEY",
1240 help="use this WPA key of 64 hex digits")
1241 op.add_option("--wpa-pass",
1242 metavar="KEY",
1243 help="use this WPA passphrase")
1244 op.add_option("-m", "--monitor",
1245 action="store_true", default=False,
1246 help="loop to show dbus signals")
1249 (options, args) = op.parse_args()
1251 if options.ap:
1252 options.dev = True
1253 if options.monitor:
1254 LOOP = True
1257 nmp = '/org/freedesktop/NetworkManager'
1258 try:
1259 nm = make_nm(nmp)
1260 except dbus.exceptions.DBusException, e:
1261 print e
1262 print "NetworkManager is not running"
1263 sys.exit(1)
1264 if options.dev or options.actcon:
1265 nm.Dump()
1267 true_choices = ["1", "on", "yes", "true"]
1268 if options.wifi != None:
1269 nm.SetWifiEnabled(options.wifi in true_choices)
1270 if options.online != None:
1271 nm.SetOnline(options.online in true_choices)
1273 if options.nets:
1274 nm.ListNets()
1276 if options.syscon:
1277 print "SYSTEM Connections"
1278 if nm.Api() == "06":
1279 print "Cannot do that with NM 0.6"
1280 else:
1281 ss = cApplet(SSC, '/org/freedesktop/NetworkManagerSettings')
1282 ss.Dump()
1284 if options.usrcon:
1285 print "USER Connections"
1286 try:
1287 if nm.Api() == "06":
1288 us = cApplet_06(NMIC, "/org/freedesktop/NetworkManagerInfo")
1289 else:
1290 us = cApplet(USC, '/org/freedesktop/NetworkManagerSettings')
1291 us.Dump()
1292 except dbus.exceptions.DBusException, e:
1293 print e
1294 #if e.get_dbus_name() == "org.freedesktop.DBus.Error.ServiceUnknown":
1295 print "Applet is not running"
1297 nmo = bus.get_object(NMC, nmp)
1298 nmi = dbus.Interface(nmo, NMI)
1300 def service_pid(name):
1301 DBS = 'org.freedesktop.DBus'
1302 DBI = DBS
1303 dbo = bus.get_object(DBS, '/')
1304 dbi = dbus.Interface(dbo, DBI)
1305 owner = dbi.GetNameOwner(name)
1306 pid = dbi.GetConnectionUnixProcessID(owner)
1307 return pid
1309 # TODO UserSettings_06
1310 if options.connect != None:
1311 if nm.Api() == "06":
1312 name = NMIC
1313 else:
1314 name = USC
1315 brn = bus.request_name(name, _dbus_bindings.NAME_FLAG_DO_NOT_QUEUE)
1316 if brn == _dbus_bindings.REQUEST_NAME_REPLY_EXISTS:
1317 print "Could not provide settings service, another applet is running (pid %s)" % service_pid(name)
1318 sys.exit(1)
1319 cfg = ConfigParserKNM()
1320 if nm.Api() == "06":
1321 us = UserSettings_06("/org/freedesktop/NetworkManagerInfo",
1322 cfg.ConMaps())
1323 else:
1324 us = UserSettings("/org/freedesktop/NetworkManagerSettings",
1325 cfg.ConMaps())
1327 def Connect(wanted_net): # any. or take arg. net is config name or ssid name
1328 # ... in general, look for string in all config data. ssid for wifi, whatever for dialup
1329 # TODO also respect autoconnect
1331 # ActivateConn wants setting device ap; can find device from ap? ap is "specific" for wifi devices
1332 #print "Connection wanted to", wanted_net
1333 found_con = found_ap = found_dev = None
1334 for dev in nm.Devices():
1335 for ap in dev.APs():
1336 if wanted_net == ap.Ssid():
1337 found_ap = ap
1338 found_dev = dev
1339 break # FIXME both loops
1340 found_con = us.GetByNet(wanted_net)
1341 if found_ap == None:
1342 print "No AP found with SSID", wanted_net
1343 return False
1344 if found_con == None:
1345 print "No settings for net %s, assuming no key is needed" % wanted_net
1346 c = mkconmap_wifi(wanted_net)
1347 found_con = us.addCon(c)
1348 nm.ActivateConnection(found_con, found_dev, found_ap) # TODO async
1349 # TODO run loop, exit it when we have serviced the required calls
1350 return True
1352 if options.connect != None:
1353 if options.unprotected:
1354 c = mkconmap_wifi(options.connect)
1355 us.addCon(c)
1356 if options.wep_hex != None:
1357 c = mkconmap_wep(options.connect, options.wep_hex)
1358 us.addCon(c)
1359 if options.wep_pass != None:
1360 c = mkconmap_wep_pass(options.connect, options.wep_pass)
1361 us.addCon(c)
1362 if options.wpa_psk_hex != None:
1363 c = mkconmap_psk(options.connect, options.wpa_psk_hex)
1364 us.addCon(c)
1365 if options.wpa_pass != None:
1366 wpa_psk_hex = hexlify(pbkdf2.pbkdf2(options.wpa_pass, options.connect, 4096, 32))
1367 print "pbkdf2", wpa_psk_hex
1368 c = mkconmap_psk(options.connect, wpa_psk_hex)
1369 us.addCon(c)
1370 if Connect(options.connect):
1371 LOOP = True
1373 if options.monitor:
1374 m = Monitor()
1376 def loop():
1377 loop = gobject.MainLoop()
1378 try:
1379 loop.run()
1380 except:
1381 print "Loop exited"
1383 if LOOP:
1384 loop()