Ticket #29: nm07-support.patch

File nm07-support.patch, 170.7 KB (added by erikos, 14 years ago)

suprt of wireless connections with NM 0.7 (this drops NM 0.6 support)

  • data/Makefile.am

    diff --git a/data/Makefile.am b/data/Makefile.am
    index cdf9dc5..8800ad8 100644
    a b GTKRC_FILES = \ 
    2222xsessionsdir = $(datadir)/xsessions
    2323xsessions_DATA = sugar.desktop
    2424
     25nmservicedir = $(sysconfdir)/dbus-1/system.d/
     26nmservice_DATA = nm-user-settings.conf
     27
    2528mime_xml_in_files = sugar.xml.in
    2629mime_xml_files = $(mime_xml_in_files:.xml.in=.xml)
    2730@INTLTOOL_XML_RULE@
    if ENABLE_UPDATE_MIMEDB 
    4346        fi
    4447endif
    4548
    46 EXTRA_DIST = $(sugar_DATA) $(xsessions_DATA) $(mime_xml_in_files) em.py gtkrc.em
     49EXTRA_DIST = $(sugar_DATA) $(xsessions_DATA) $(nmservice_DATA) $(mime_xml_in_files) em.py gtkrc.em
    4750CLEANFILES = $(GTKRC_FILES) $(mime_xml_files)
  • new file data/nm-user-settings.conf

    diff --git a/data/nm-user-settings.conf b/data/nm-user-settings.conf
    new file mode 100644
    index 0000000..af7c642
    - +  
     1<!DOCTYPE busconfig PUBLIC
     2 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
     3 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
     4<busconfig>
     5        <policy user="root">
     6                <allow own="org.freedesktop.NetworkManagerUserSettings"/>
     7
     8                <allow send_destination="org.freedesktop.NetworkManagerUserSettings"/>
     9                <allow send_interface="org.freedesktop.NetworkManagerSettings"/>
     10
     11                <!-- Only root can get secrets -->
     12                <allow send_interface="org.freedesktop.NetworkManagerSettings.Secrets"/>
     13        </policy>
     14        <policy at_console="true">
     15                <allow own="org.freedesktop.NetworkManagerUserSettings"/>
     16
     17                <allow send_destination="org.freedesktop.NetworkManagerUserSettings"/>
     18                <allow send_interface="org.freedesktop.NetworkManagerSettings"/>
     19
     20                <!-- Only root can get secrets -->
     21                <deny send_interface="org.freedesktop.NetworkManagerSettings.Secrets"/>
     22        </policy>
     23        <policy context="default">
     24                <deny own="org.freedesktop.NetworkManagerUserSettings"/>
     25
     26                <allow send_destination="org.freedesktop.NetworkManagerUserSettings"/>
     27                <allow send_interface="org.freedesktop.NetworkManagerSettings"/>
     28                <!-- Only root can get secrets -->
     29                <deny send_interface="org.freedesktop.NetworkManagerSettings.Secrets"/>
     30        </policy>
     31
     32        <limit name="max_replies_per_connection">512</limit>
     33</busconfig>
     34
  • src/hardware/Makefile.am

    diff --git a/src/hardware/Makefile.am b/src/hardware/Makefile.am
    index 8cd9c77..f589d42 100644
    a b sugardir = $(pkgdatadir)/shell/hardware 
    22sugar_PYTHON =                          \
    33        __init__.py                     \
    44        hardwaremanager.py              \
    5         keydialog.py                    \
    6         nmclient.py                     \
    7         nminfo.py                       \
    85        schoolserver.py
    9 
    10 dbusservicedir = $(sysconfdir)/dbus-1/system.d/
    11 dbusservice_DATA = NetworkManagerInfo.conf
    12 
    13 EXTRA_DIST = $(dbusservice_DATA)
  • deleted file src/hardware/NetworkManagerInfo.conf

    diff --git a/src/hardware/NetworkManagerInfo.conf b/src/hardware/NetworkManagerInfo.conf
    deleted file mode 100644
    index 4fb8270..0000000
    + -  
    1 <!DOCTYPE busconfig PUBLIC
    2  "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
    3  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
    4 <busconfig>
    5         <policy user="root">
    6                 <allow own="org.freedesktop.NetworkManagerInfo"/>
    7 
    8                 <allow send_destination="org.freedesktop.NetworkManagerInfo"/>
    9                 <allow send_interface="org.freedesktop.NetworkManagerInfo"/>
    10         </policy>
    11         <policy at_console="true">
    12                 <allow own="org.freedesktop.NetworkManagerInfo"/>
    13 
    14                 <allow send_destination="org.freedesktop.NetworkManagerInfo"/>
    15                 <allow send_interface="org.freedesktop.NetworkManagerInfo"/>
    16         </policy>
    17         <policy context="default">
    18                 <deny own="org.freedesktop.NetworkManagerInfo"/>
    19 
    20                 <deny send_destination="org.freedesktop.NetworkManagerInfo"/>
    21                 <deny send_interface="org.freedesktop.NetworkManagerInfo"/>
    22         </policy>
    23 
    24         <limit name="max_replies_per_connection">512</limit>
    25 </busconfig>
    26 
  • src/hardware/hardwaremanager.py

    diff --git a/src/hardware/hardwaremanager.py b/src/hardware/hardwaremanager.py
    index c4f9f75..2e5a16b 100644
    a b import logging 
    1919import dbus
    2020import gobject
    2121
    22 from hardware.nmclient import NMClient
    2322from sugar.profile import get_profile
    2423from sugar import env
    2524from sugar import _sugarext
    class HardwareManager(gobject.GObject): 
    111110def get_manager():
    112111    return _manager
    113112
    114 def get_network_manager():
    115     return _network_manager
    116 
    117113_manager = HardwareManager()
    118114
    119 try:
    120     _network_manager = NMClient()
    121 except dbus.DBusException, e:
    122     _network_manager = None
    123     logging.info('Network manager service not found.')
  • deleted file src/hardware/keydialog.py

    diff --git a/src/hardware/keydialog.py b/src/hardware/keydialog.py
    deleted file mode 100644
    index 88a551f..0000000
    + -  
    1 # vi: ts=4 ai noet
    2 #
    3 # Copyright (C) 2006-2007 Red Hat, Inc.
    4 #
    5 # This program is free software; you can redistribute it and/or modify
    6 # it under the terms of the GNU General Public License as published by
    7 # the Free Software Foundation; either version 2 of the License, or
    8 # (at your option) any later version.
    9 #
    10 # This program is distributed in the hope that it will be useful,
    11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13 # GNU General Public License for more details.
    14 #
    15 # You should have received a copy of the GNU General Public License
    16 # along with this program; if not, write to the Free Software
    17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19 import md5
    20 from gettext import gettext as _
    21 
    22 import gtk
    23 
    24 IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
    25 IW_AUTH_ALG_SHARED_KEY  = 0x00000002
    26 
    27 IW_AUTH_WPA_VERSION_DISABLED = 0x00000001
    28 IW_AUTH_WPA_VERSION_WPA      = 0x00000002
    29 IW_AUTH_WPA_VERSION_WPA2     = 0x00000004
    30 
    31 NM_802_11_CAP_NONE            = 0x00000000
    32 NM_802_11_CAP_PROTO_NONE      = 0x00000001
    33 NM_802_11_CAP_PROTO_WEP       = 0x00000002
    34 NM_802_11_CAP_PROTO_WPA       = 0x00000004
    35 NM_802_11_CAP_PROTO_WPA2      = 0x00000008
    36 NM_802_11_CAP_KEY_MGMT_PSK    = 0x00000040
    37 NM_802_11_CAP_KEY_MGMT_802_1X = 0x00000080
    38 NM_802_11_CAP_CIPHER_WEP40    = 0x00001000
    39 NM_802_11_CAP_CIPHER_WEP104   = 0x00002000
    40 NM_802_11_CAP_CIPHER_TKIP     = 0x00004000
    41 NM_802_11_CAP_CIPHER_CCMP     = 0x00008000
    42 
    43 NM_AUTH_TYPE_WPA_PSK_AUTO = 0x00000000
    44 IW_AUTH_CIPHER_NONE   = 0x00000001
    45 IW_AUTH_CIPHER_WEP40  = 0x00000002
    46 IW_AUTH_CIPHER_TKIP   = 0x00000004
    47 IW_AUTH_CIPHER_CCMP   = 0x00000008
    48 IW_AUTH_CIPHER_WEP104 = 0x00000010
    49 
    50 IW_AUTH_KEY_MGMT_802_1X = 0x1
    51 IW_AUTH_KEY_MGMT_PSK    = 0x2
    52 
    53 def string_is_hex(key):
    54     is_hex = True
    55     for c in key:
    56         if not 'a' <= c.lower() <= 'f' and not '0' <= c <= '9':
    57             is_hex = False
    58     return is_hex
    59 
    60 def string_is_ascii(string):
    61     try:
    62         string.encode('ascii')
    63         return True
    64     except UnicodeEncodeError:
    65         return False
    66 
    67 def string_to_hex(passphrase):
    68     key = ''
    69     for c in passphrase:
    70         key += '%02x' % ord(c)
    71     return key
    72 
    73 def hash_passphrase(passphrase):
    74     # passphrase must have a length of 64
    75     if len(passphrase) > 64:
    76         passphrase = passphrase[:64]
    77     elif len(passphrase) < 64:
    78         while len(passphrase) < 64:
    79             passphrase += passphrase[:64 - len(passphrase)]
    80     passphrase = md5.new(passphrase).digest()
    81     return string_to_hex(passphrase)[:26]
    82 
    83 class KeyDialog(gtk.Dialog):
    84     def __init__(self, net, async_cb, async_err_cb):
    85         gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
    86         self.set_title("Wireless Key Required")
    87 
    88         self._net = net
    89         self._async_cb = async_cb
    90         self._async_err_cb = async_err_cb
    91         self._entry = None
    92 
    93         self.set_has_separator(False)       
    94 
    95         label = gtk.Label("A wireless encryption key is required for\n" \
    96                           " the wireless network '%s'." % net.get_ssid())
    97         self.vbox.pack_start(label)
    98 
    99         self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
    100                          gtk.STOCK_OK, gtk.RESPONSE_OK)
    101         self.set_default_response(gtk.RESPONSE_OK)
    102         self.set_has_separator(True)
    103 
    104     def add_key_entry(self):
    105         self._entry = gtk.Entry()
    106         #self._entry.props.visibility = False
    107         self._entry.connect('changed', self._update_response_sensitivity)
    108         self._entry.connect('activate', self._entry_activate_cb)
    109         self.vbox.pack_start(self._entry)
    110         self.vbox.set_spacing(6)
    111         self.vbox.show_all()
    112 
    113         self._update_response_sensitivity()
    114         self._entry.grab_focus()
    115 
    116     def _entry_activate_cb(self, entry):
    117         self.response(gtk.RESPONSE_OK)
    118 
    119     def create_security(self):
    120         raise NotImplementedError
    121 
    122     def get_network(self):
    123         return self._net
    124 
    125     def get_callbacks(self):
    126         return (self._async_cb, self._async_err_cb)
    127 
    128 WEP_PASSPHRASE = 1
    129 WEP_HEX = 2
    130 WEP_ASCII = 3
    131 
    132 class WEPKeyDialog(KeyDialog):
    133     def __init__(self, net, async_cb, async_err_cb):
    134         KeyDialog.__init__(self, net, async_cb, async_err_cb)
    135 
    136         # WEP key type
    137         self.key_store = gtk.ListStore(str, int)
    138         self.key_store.append(["Passphrase (128-bit)", WEP_PASSPHRASE])
    139         self.key_store.append(["Hex (40/128-bit)", WEP_HEX])
    140         self.key_store.append(["ASCII (40/128-bit)", WEP_ASCII])
    141 
    142         self.key_combo = gtk.ComboBox(self.key_store)
    143         cell = gtk.CellRendererText()
    144         self.key_combo.pack_start(cell, True)
    145         self.key_combo.add_attribute(cell, 'text', 0)
    146         self.key_combo.set_active(0)
    147         self.key_combo.connect('changed', self._key_combo_changed_cb)
    148 
    149         hbox = gtk.HBox()
    150         hbox.pack_start(gtk.Label(_("Key Type:")))
    151         hbox.pack_start(self.key_combo)
    152         hbox.show_all()
    153         self.vbox.pack_start(hbox)
    154 
    155         # Key entry field
    156         self.add_key_entry()
    157 
    158         # WEP authentication mode
    159         self.auth_store = gtk.ListStore(str, int)
    160         self.auth_store.append(["Open System", IW_AUTH_ALG_OPEN_SYSTEM])
    161         self.auth_store.append(["Shared Key", IW_AUTH_ALG_SHARED_KEY])
    162 
    163         self.auth_combo = gtk.ComboBox(self.auth_store)
    164         cell = gtk.CellRendererText()
    165         self.auth_combo.pack_start(cell, True)
    166         self.auth_combo.add_attribute(cell, 'text', 0)
    167         self.auth_combo.set_active(0)
    168 
    169         hbox = gtk.HBox()
    170         hbox.pack_start(gtk.Label(_("Authentication Type:")))
    171         hbox.pack_start(self.auth_combo)
    172         hbox.show_all()
    173 
    174         self.vbox.pack_start(hbox)
    175 
    176     def _key_combo_changed_cb(self, widget):
    177         self._update_response_sensitivity()
    178 
    179     def _get_security(self):
    180         key = self._entry.get_text()
    181 
    182         it = self.key_combo.get_active_iter()
    183         (key_type, ) = self.key_store.get(it, 1)
    184 
    185         if key_type == WEP_PASSPHRASE:
    186             key = hash_passphrase(key)
    187         elif key_type == WEP_ASCII:
    188             key = string_to_hex(key)
    189 
    190         it = self.auth_combo.get_active_iter()
    191         (auth_alg, ) = self.auth_store.get(it, 1)
    192 
    193         we_cipher = None
    194         if len(key) == 26:
    195             we_cipher = IW_AUTH_CIPHER_WEP104
    196         elif len(key) == 10:
    197             we_cipher = IW_AUTH_CIPHER_WEP40
    198 
    199         return (we_cipher, key, auth_alg)
    200 
    201     def print_security(self):
    202         (we_cipher, key, auth_alg) = self._get_security()
    203         print "Cipher: %d" % we_cipher
    204         print "Key: %s" % key
    205         print "Auth: %d" % auth_alg
    206 
    207     def create_security(self):
    208         (we_cipher, key, auth_alg) = self._get_security()
    209         from nminfo import Security
    210         return Security.new_from_args(we_cipher, (key, auth_alg))
    211 
    212     def _update_response_sensitivity(self, ignored=None):
    213         key = self._entry.get_text()
    214         it = self.key_combo.get_active_iter()
    215         (key_type, ) = self.key_store.get(it, 1)
    216 
    217         valid = False
    218         if key_type == WEP_PASSPHRASE:
    219             # As the md5 passphrase can be of any length and has no indicator,
    220             # we cannot check for the validity of the input.
    221             if len(key) > 0:
    222                 valid = True
    223         elif key_type == WEP_ASCII:
    224             if len(key) == 5 or len(key) == 13:
    225                 valid = string_is_ascii(key)
    226         elif key_type == WEP_HEX:
    227             if len(key) == 10 or len(key) == 26:
    228                 valid = string_is_hex(key)
    229 
    230         self.set_response_sensitive(gtk.RESPONSE_OK, valid)
    231 
    232 class WPAKeyDialog(KeyDialog):
    233     def __init__(self, net, async_cb, async_err_cb):
    234         KeyDialog.__init__(self, net, async_cb, async_err_cb)
    235         self.add_key_entry()
    236 
    237         self.store = gtk.ListStore(str, int)
    238         self.store.append(["Automatic", NM_AUTH_TYPE_WPA_PSK_AUTO])
    239         if net.get_caps() & NM_802_11_CAP_CIPHER_CCMP:
    240             self.store.append(["AES-CCMP", IW_AUTH_CIPHER_CCMP])
    241         if net.get_caps() & NM_802_11_CAP_CIPHER_TKIP:
    242             self.store.append(["TKIP", IW_AUTH_CIPHER_TKIP])
    243 
    244         self.combo = gtk.ComboBox(self.store)
    245         cell = gtk.CellRendererText()
    246         self.combo.pack_start(cell, True)
    247         self.combo.add_attribute(cell, 'text', 0)
    248         self.combo.set_active(0)
    249 
    250         self.hbox = gtk.HBox()
    251         self.hbox.pack_start(gtk.Label(_("Encryption Type:")))
    252         self.hbox.pack_start(self.combo)
    253         self.hbox.show_all()
    254 
    255         self.vbox.pack_start(self.hbox)
    256 
    257     def _get_security(self):
    258         ssid = self.get_network().get_ssid()
    259         key = self._entry.get_text()
    260         is_hex = string_is_hex(key)
    261 
    262         real_key = None
    263         if len(key) == 64 and is_hex:
    264             # Hex key
    265             real_key = key
    266         elif len(key) >= 8 and len(key) <= 63:
    267             # passphrase
    268             from subprocess import Popen, PIPE
    269             p = Popen(['/usr/sbin/wpa_passphrase', ssid, key], stdout=PIPE)
    270             for line in p.stdout:
    271                 if line.strip().startswith("psk="):
    272                     real_key = line.strip()[4:]
    273             if p.wait() != 0:
    274                 raise RuntimeError("Error hashing passphrase")
    275             if real_key and len(real_key) != 64:
    276                 real_key = None
    277 
    278         if not real_key:
    279             raise RuntimeError("Invalid key")
    280 
    281         it = self.combo.get_active_iter()
    282         (we_cipher, ) = self.store.get(it, 1)
    283 
    284         wpa_ver = IW_AUTH_WPA_VERSION_WPA
    285         caps = self.get_network().get_caps()
    286         if caps & NM_802_11_CAP_PROTO_WPA2:
    287             wpa_ver = IW_AUTH_WPA_VERSION_WPA2
    288 
    289         return (we_cipher, real_key, wpa_ver)
    290 
    291     def print_security(self):
    292         (we_cipher, key, wpa_ver) = self._get_security()
    293         print "Cipher: %d" % we_cipher
    294         print "Key: %s" % key
    295         print "WPA Ver: %d" % wpa_ver
    296 
    297     def create_security(self):
    298         (we_cipher, key, wpa_ver) = self._get_security()
    299         from nminfo import Security
    300         return Security.new_from_args(we_cipher,
    301                                       (key, wpa_ver, IW_AUTH_KEY_MGMT_PSK))
    302 
    303     def _update_response_sensitivity(self, ignored=None):
    304         key = self._entry.get_text()
    305         is_hex = string_is_hex(key)
    306 
    307         valid = False
    308         if len(key) == 64 and is_hex:
    309             # hex key
    310             valid = True
    311         elif len(key) >= 8 and len(key) <= 63:
    312             # passphrase
    313             valid = True
    314         self.set_response_sensitive(gtk.RESPONSE_OK, valid)
    315         return False
    316 
    317 def new_key_dialog(net, async_cb, async_err_cb):
    318     caps = net.get_caps()
    319     if (caps & NM_802_11_CAP_CIPHER_TKIP or caps & NM_802_11_CAP_CIPHER_CCMP) \
    320             and (caps & NM_802_11_CAP_PROTO_WPA or \
    321                 caps & NM_802_11_CAP_PROTO_WPA2):
    322         return WPAKeyDialog(net, async_cb, async_err_cb)
    323     elif (caps & NM_802_11_CAP_CIPHER_WEP40 or \
    324             caps & NM_802_11_CAP_CIPHER_WEP104) and \
    325             (caps & NM_802_11_CAP_PROTO_WEP):
    326         return WEPKeyDialog(net, async_cb, async_err_cb)
    327     else:
    328         raise RuntimeError("Unhandled network capabilities %x" % caps)
    329 
    330 
    331 
    332 class FakeNet(object):
    333     def get_ssid(self):
    334         return "olpcwpa"
    335 
    336     def get_caps(self):
    337         return NM_802_11_CAP_CIPHER_CCMP | NM_802_11_CAP_CIPHER_TKIP | \
    338                 NM_802_11_CAP_PROTO_WPA
    339 
    340 def response_cb(widget, response_id):
    341     if response_id == gtk.RESPONSE_OK:
    342         print dialog.print_security()
    343     else:
    344         print "canceled"
    345     widget.hide()
    346     widget.destroy()
    347 
    348 
    349 if __name__ == "__main__":
    350     fake_net = FakeNet()
    351     dialog = new_key_dialog(fake_net, None, None)
    352     dialog.connect("response", response_cb)
    353     dialog.run()
    354 
  • deleted file src/hardware/nmclient.py

    diff --git a/src/hardware/nmclient.py b/src/hardware/nmclient.py
    deleted file mode 100644
    index c517391..0000000
    + -  
    1 #
    2 # Copyright (C) 2006-2007 Red Hat, Inc.
    3 #
    4 # This program is free software; you can redistribute it and/or modify
    5 # it under the terms of the GNU General Public License as published by
    6 # the Free Software Foundation; either version 2 of the License, or
    7 # (at your option) any later version.
    8 #
    9 # This program is distributed in the hope that it will be useful,
    10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12 # GNU General Public License for more details.
    13 #
    14 # You should have received a copy of the GNU General Public License
    15 # along with this program; if not, write to the Free Software
    16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17 
    18 import logging
    19 
    20 import dbus
    21 import dbus.glib
    22 import dbus.decorators
    23 import gobject
    24 
    25 from hardware import nminfo
    26 from sugar.graphics import xocolor
    27 
    28 IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
    29 IW_AUTH_ALG_SHARED_KEY  = 0x00000002
    30 
    31 NM_DEVICE_STAGE_STRINGS = ("Unknown",
    32                            "Prepare",
    33                            "Config",
    34                            "Need Users Key",
    35                            "IP Config",
    36                            "IP Config Get",
    37                            "IP Config Commit",
    38                            "Activated",
    39                            "Failed",
    40                            "Canceled"
    41                            )
    42 
    43 NM_SERVICE = 'org.freedesktop.NetworkManager'
    44 NM_IFACE = 'org.freedesktop.NetworkManager'
    45 NM_IFACE_DEVICES = 'org.freedesktop.NetworkManager.Devices'
    46 NM_PATH = '/org/freedesktop/NetworkManager'
    47 
    48 DEVICE_TYPE_UNKNOWN = 0
    49 DEVICE_TYPE_802_3_ETHERNET = 1
    50 DEVICE_TYPE_802_11_WIRELESS = 2
    51 DEVICE_TYPE_802_11_MESH_OLPC = 3
    52 
    53 NM_DEVICE_CAP_NONE = 0x00000000
    54 NM_DEVICE_CAP_NM_SUPPORTED = 0x00000001
    55 NM_DEVICE_CAP_CARRIER_DETECT = 0x00000002
    56 NM_DEVICE_CAP_WIRELESS_SCAN = 0x00000004
    57 
    58 sys_bus = dbus.SystemBus()
    59 
    60 NM_802_11_CAP_NONE            = 0x00000000
    61 NM_802_11_CAP_PROTO_NONE      = 0x00000001
    62 NM_802_11_CAP_PROTO_WEP       = 0x00000002
    63 NM_802_11_CAP_PROTO_WPA       = 0x00000004
    64 NM_802_11_CAP_PROTO_WPA2      = 0x00000008
    65 NM_802_11_CAP_KEY_MGMT_PSK    = 0x00000040
    66 NM_802_11_CAP_KEY_MGMT_802_1X = 0x00000080
    67 NM_802_11_CAP_CIPHER_WEP40    = 0x00001000
    68 NM_802_11_CAP_CIPHER_WEP104   = 0x00002000
    69 NM_802_11_CAP_CIPHER_TKIP     = 0x00004000
    70 NM_802_11_CAP_CIPHER_CCMP     = 0x00008000
    71 
    72 NETWORK_STATE_CONNECTING   = 0
    73 NETWORK_STATE_CONNECTED    = 1
    74 NETWORK_STATE_NOTCONNECTED = 2
    75 
    76 DEVICE_STATE_ACTIVATING = 0
    77 DEVICE_STATE_ACTIVATED  = 1
    78 DEVICE_STATE_INACTIVE   = 2
    79 
    80 IW_MODE_ADHOC = 1
    81 IW_MODE_INFRA = 2
    82 
    83 class Network(gobject.GObject):
    84     __gsignals__ = {
    85         'initialized'     : (gobject.SIGNAL_RUN_FIRST,
    86                              gobject.TYPE_NONE, ([gobject.TYPE_BOOLEAN])),
    87         'strength-changed': (gobject.SIGNAL_RUN_FIRST,
    88                              gobject.TYPE_NONE, ([])),
    89         'state-changed'   : (gobject.SIGNAL_RUN_FIRST,
    90                              gobject.TYPE_NONE, ([]))
    91     }
    92 
    93     def __init__(self, client, op):
    94         gobject.GObject.__init__(self)
    95         self._client = client
    96         self._op = op
    97         self._ssid = None
    98         self._mode = None
    99         self._strength = 0
    100         self._caps = 0
    101         self._valid = False
    102         self._favorite = False
    103         self._state = NETWORK_STATE_NOTCONNECTED
    104 
    105         obj = sys_bus.get_object(NM_SERVICE, self._op)
    106         net = dbus.Interface(obj, NM_IFACE_DEVICES)
    107         net.getProperties(reply_handler=self._update_reply_cb,
    108                 error_handler=self._update_error_cb)
    109 
    110     def _update_reply_cb(self, *props):
    111         self._ssid = props[1]
    112         self._strength = props[3]
    113         self._mode = props[6]
    114         self._caps = props[7]
    115         if self._caps & NM_802_11_CAP_PROTO_WPA or \
    116                 self._caps & NM_802_11_CAP_PROTO_WPA2:
    117             if not (self._caps & NM_802_11_CAP_KEY_MGMT_PSK):
    118                 # 802.1x is not supported at this time
    119                 logging.debug("Net(%s): ssid '%s' dropping because 802.1x" \
    120                               "is unsupported" % (self._op, self._ssid))
    121                 self._valid = False
    122                 self.emit('initialized', self._valid)
    123                 return
    124         if self._mode != IW_MODE_INFRA:
    125             # Don't show Ad-Hoc networks; they usually don't DHCP and therefore
    126             # won't work well here.  This also works around the bug where
    127             # we show our own mesh SSID on the Mesh view when in mesh mode
    128             logging.debug("Net(%s): ssid '%s' is adhoc; not showing" %
    129                           (self._op, self._ssid))
    130             self._valid = False
    131             self.emit('initialized', self._valid)
    132             return
    133 
    134         fav_nets = []
    135         if self._client.nminfo:
    136             fav_nets = self._client.nminfo.get_networks(
    137                     nminfo.NETWORK_TYPE_ALLOWED)
    138         if self._ssid in fav_nets:
    139             self._favorite = True
    140 
    141         self._valid = True
    142         logging.debug("Net(%s): caps 0x%X" % (self._ssid, self._caps))
    143         self.emit('initialized', self._valid)
    144 
    145     def _update_error_cb(self, err):
    146         logging.debug("Net(%s): failed to update. (%s)" % (self._op, err))
    147         self._valid = False
    148         self.emit('initialized', self._valid)
    149 
    150     def get_colors(self):
    151         import sha
    152         sh = sha.new()
    153         data = self._ssid + hex(self._caps) + hex(self._mode)
    154         sh.update(data)
    155         h = hash(sh.digest())
    156         idx = h % len(xocolor.colors)
    157         # stroke, fill
    158         return (xocolor.colors[idx][0], xocolor.colors[idx][1])
    159 
    160     def get_ssid(self):
    161         return self._ssid
    162 
    163     def get_caps(self):
    164         return self._caps
    165 
    166     def get_mode(self):
    167         return self._mode
    168 
    169     def get_state(self):
    170         return self._state
    171 
    172     def set_state(self, state):
    173         if state == self._state:
    174             return
    175         self._state = state
    176         if self._valid:
    177             self.emit('state-changed')
    178 
    179     def get_op(self):
    180         return self._op
    181 
    182     def get_strength(self):
    183         return self._strength
    184 
    185     def set_strength(self, strength):
    186         if strength == self._strength:
    187             return
    188         self._strength = strength
    189         if self._valid:
    190             self.emit('strength-changed')
    191 
    192     def is_valid(self):
    193         return self._valid
    194 
    195     def is_favorite(self):
    196         return self._favorite
    197 
    198 class Device(gobject.GObject):
    199     __gsignals__ = {
    200         'initialized':              (gobject.SIGNAL_RUN_FIRST,
    201                                      gobject.TYPE_NONE, ([])),
    202         'init-failed':              (gobject.SIGNAL_RUN_FIRST,
    203                                      gobject.TYPE_NONE, ([])),
    204         'ssid-changed':             (gobject.SIGNAL_RUN_FIRST,
    205                                      gobject.TYPE_NONE, ([])),
    206         'strength-changed':         (gobject.SIGNAL_RUN_FIRST,
    207                                      gobject.TYPE_NONE, ([])),
    208         'state-changed':            (gobject.SIGNAL_RUN_FIRST,
    209                                      gobject.TYPE_NONE, ([])),
    210         'activation-stage-changed': (gobject.SIGNAL_RUN_FIRST,
    211                                      gobject.TYPE_NONE, ([])),
    212         'network-appeared':         (gobject.SIGNAL_RUN_FIRST,
    213                                      gobject.TYPE_NONE,
    214                                      ([gobject.TYPE_PYOBJECT])),
    215         'network-disappeared':      (gobject.SIGNAL_RUN_FIRST,
    216                                      gobject.TYPE_NONE,
    217                                      ([gobject.TYPE_PYOBJECT])),
    218         'ip-changed':               (gobject.SIGNAL_RUN_FIRST,
    219                                      gobject.TYPE_NONE, ([])),
    220     }
    221 
    222     def __init__(self, client, op):
    223         gobject.GObject.__init__(self)
    224         self._client = client
    225         self._op = op
    226         self._iface = None
    227         self._type = DEVICE_TYPE_UNKNOWN
    228         self._udi = None
    229         self._active = False
    230         self._act_stage = 0
    231         self._strength = 0
    232         self._freq = 0.0
    233         self._link = False
    234         self._valid = False
    235         self._networks = {}
    236         self._caps = 0
    237         self._state = DEVICE_STATE_INACTIVE
    238         self._active_network = None
    239         self._active_net_sigid = 0
    240         self._ip_address = None
    241 
    242         obj = sys_bus.get_object(NM_SERVICE, self._op)
    243         self.dev = dbus.Interface(obj, NM_IFACE_DEVICES)
    244         self.dev.getProperties(reply_handler=self._update_reply_cb,
    245                 error_handler=self._update_error_cb)
    246 
    247     def _is_activating(self):
    248         if self._active and self._act_stage >= 1 and self._act_stage <= 6:
    249             return True
    250         return False
    251 
    252     def _is_activated(self):
    253         if self._active and self._act_stage == 7:
    254             return True
    255         return False
    256 
    257     # 6248: remove for NM0.7; http://dev.laptop.org/ticket/6248#comment:2
    258     def _getproperties_for_ip_only_reply_cb(self, *props):
    259         current_ip = props[6]
    260         if current_ip != self._ip_address:
    261             self._ip_address = current_ip
    262             if self._valid:
    263                 self.emit('ip-changed')
    264 
    265     # 6248: remove for NM0.7; http://dev.laptop.org/ticket/6248#comment:2
    266     def _getproperties_for_ip_only_error_cb(self, err):
    267         logging.warning("Device(%s): failed to update. (%s)" % (self._op, err))
    268 
    269     def _update_reply_cb(self, *props):
    270         self._iface = props[1]
    271         self._type = props[2]
    272         self._udi = props[3]
    273         self._active = props[4]
    274         self._act_stage = props[5]
    275         self._link = props[15]
    276         self._caps = props[17]
    277 
    278         if self._type == DEVICE_TYPE_802_11_WIRELESS:
    279             old_strength = self._strength
    280             self._strength = props[14]
    281             if self._strength != old_strength:
    282                 if self._valid:
    283                     self.emit('strength-changed')
    284             self._update_networks(props[20], props[19])
    285         elif self._type ==  DEVICE_TYPE_802_11_MESH_OLPC:
    286             old_strength = self._strength
    287             self._strength = props[14]
    288             if self._strength != old_strength:
    289                 if self._valid:
    290                     self.emit('strength-changed')
    291 
    292         self._valid = True
    293 
    294         # 6248: remove for NM0.7; http://dev.laptop.org/ticket/6248#comment:2
    295         if props[6] != self._ip_address:
    296             self._ip_address = props[6]
    297             self.emit('ip-changed')
    298 
    299         if self._is_activating():
    300             self.set_state(DEVICE_STATE_ACTIVATING)
    301         elif self._is_activated():
    302             self.set_state(DEVICE_STATE_ACTIVATED)
    303         else:
    304             self.set_state(DEVICE_STATE_INACTIVE)
    305 
    306         self.emit('initialized')
    307 
    308     def _update_networks(self, net_ops, active_op):
    309         for op in net_ops:
    310             net = Network(self._client, op)
    311             self._networks[op] = net
    312             net.connect('initialized', lambda *args:
    313                         self._net_initialized_cb(active_op, *args))
    314 
    315     def _update_error_cb(self, err):
    316         logging.debug("Device(%s): failed to update. (%s)" % (self._op, err))
    317         self._valid = False
    318         self.emit('init-failed')
    319 
    320     def _net_initialized_cb(self, active_op, net, valid):
    321         net_op = net.get_op()
    322         if not self._networks.has_key(net_op):
    323             return
    324 
    325         if not valid:
    326             # init failure
    327             del self._networks[net_op]
    328             return
    329 
    330         # init success
    331         if self._valid:
    332             self.emit('network-appeared', net)
    333         if active_op and net_op == active_op:
    334             self.set_active_network(net)
    335 
    336     def get_op(self):
    337         return self._op
    338 
    339     def get_networks(self):
    340         ret = []
    341         for net in self._networks.values():
    342             if net.is_valid():
    343                 ret.append(net)
    344         return ret
    345 
    346     def get_network(self, op):
    347         if self._networks.has_key(op) and self._networks[op].is_valid():
    348             return self._networks[op]
    349         return None
    350 
    351     def get_network_ops(self):
    352         ret = []
    353         for net in self._networks.values():
    354             if net.is_valid():
    355                 ret.append(net.get_op())
    356         return ret
    357 
    358     def get_mesh_step(self):
    359         if self._type !=  DEVICE_TYPE_802_11_MESH_OLPC:
    360             raise RuntimeError("Only valid for mesh devices")
    361         try:
    362             step = self.dev.getMeshStep(timeout=3)
    363         except dbus.DBusException:
    364             step = 0
    365         return step
    366 
    367     def get_frequency(self):
    368         try:
    369             freq = self.dev.getFrequency(timeout=3)
    370         except dbus.DBusException:
    371             freq = 0.0
    372         # Hz -> GHz
    373         self._freq = freq / 1000000000.0
    374         return self._freq
    375 
    376     def get_ip_address(self):
    377         return self._ip_address
    378 
    379     def get_strength(self):
    380         return self._strength
    381 
    382     def set_strength(self, strength):
    383         if strength == self._strength:
    384             return False
    385 
    386         if strength >= 0 and strength <= 100:
    387             self._strength = strength
    388         else:
    389             self._strength = 0
    390 
    391         if self._valid:
    392             self.emit('strength-changed')
    393 
    394     def network_appeared(self, network):
    395         # NM may emit NetworkAppeared messages before the initialization-time
    396         # getProperties call completes. This means that we are in danger of
    397         # instantiating the "appeared" network here, and then instantiating
    398         # the same network later on when getProperties completes
    399         # (_update_reply_cb calls _update_networks).
    400         # We avoid this race by confirming that getProperties has completed
    401         # before listening to any NetworkAppeared messages. We assume that
    402         # any networks that get reported as appeared in this race window
    403         # will be included in the getProperties response.
    404         if not self._valid:
    405             return
    406 
    407         if self._networks.has_key(network):
    408             return
    409         net = Network(self._client, network)
    410         self._networks[network] = net
    411         net.connect('initialized', lambda *args:
    412                     self._net_initialized_cb(None, *args))
    413 
    414     def network_disappeared(self, network):
    415         if not self._networks.has_key(network):
    416             return
    417 
    418         if self._valid:
    419             self.emit('network-disappeared', self._networks[network])
    420 
    421         del self._networks[network]
    422 
    423     def set_active_network(self, network):
    424         if self._active_network == network:
    425             return
    426 
    427         # Make sure the old one doesn't get a stuck state
    428         if self._active_network:
    429             self._active_network.set_state(NETWORK_STATE_NOTCONNECTED)
    430             self._active_network.disconnect(self._active_net_sigid)
    431 
    432         self._active_network = network
    433 
    434         if self._active_network:
    435             self._active_net_sigid = self._active_network.connect(
    436                     "initialized", self._active_net_initialized)
    437 
    438         # don't emit ssid-changed for networks that are not yet valid
    439         if self._valid:
    440             if self._active_network and self._active_network.is_valid():
    441                 self.emit('ssid-changed')
    442             elif not self._active_network:
    443                 self.emit('ssid-changed')
    444 
    445     def _active_net_initialized(self, net, user_data=None):
    446         if self._active_network and self._active_network.is_valid():
    447             self.emit('ssid-changed')
    448 
    449     def _get_active_net_cb(self, state, net_op):
    450         if not self._networks.has_key(net_op):
    451             self.set_active_network(None)
    452             return
    453 
    454         self.set_active_network(self._networks[net_op])
    455 
    456         _device_to_network_state = {
    457             DEVICE_STATE_ACTIVATING : NETWORK_STATE_CONNECTING,
    458             DEVICE_STATE_ACTIVATED  : NETWORK_STATE_CONNECTED,
    459             DEVICE_STATE_INACTIVE   : NETWORK_STATE_NOTCONNECTED
    460         }
    461 
    462         network_state = _device_to_network_state[state]
    463         self._active_network.set_state(network_state)
    464 
    465     def _get_active_net_error_cb(self, err):
    466         logging.debug("Couldn't get active network: %s" % err)
    467         self.set_active_network(None)
    468 
    469     def get_state(self):
    470         return self._state
    471 
    472     def set_state(self, state):
    473         if state == self._state:
    474             return
    475 
    476         if state == DEVICE_STATE_INACTIVE:
    477             self._act_stage = 0
    478 
    479         self._state = state
    480         if self._valid:
    481             self.emit('state-changed')
    482 
    483         if self._type == DEVICE_TYPE_802_11_WIRELESS:
    484             if state == DEVICE_STATE_INACTIVE:
    485                 self.set_active_network(None)
    486             else:
    487                 self.dev.getActiveNetwork(
    488                     reply_handler=lambda *args:
    489                     self._get_active_net_cb(state, *args),
    490                     error_handler=self._get_active_net_error_cb)
    491 
    492         if state == DEVICE_STATE_ACTIVATED:
    493             # 6248: reimplement for NM0.7
    494             #       see http://dev.laptop.org/ticket/6248#comment:2
    495             self.dev.getProperties(
    496                 reply_handler=self._getproperties_for_ip_only_reply_cb,
    497                 error_handler=self._getproperties_for_ip_only_error_cb)
    498 
    499     def set_activation_stage(self, stage):
    500         if stage == self._act_stage:
    501             return
    502         self._act_stage = stage
    503         if self._valid:
    504             self.emit('activation-stage-changed')
    505 
    506             # 6248: reimplement for NM0.7
    507             #       see http://dev.laptop.org/ticket/6248#comment:2
    508             self.dev.getProperties(
    509                 reply_handler=self._getproperties_for_ip_only_reply_cb,
    510                 error_handler=self._getproperties_for_ip_only_error_cb)
    511 
    512     def get_activation_stage(self):
    513         return self._act_stage
    514 
    515     def get_ssid(self):
    516         if self._active_network and self._active_network.is_valid():
    517             return self._active_network.get_ssid()
    518         elif not self._active_network:
    519             return None
    520 
    521     def get_active_network(self):
    522         return self._active_network
    523 
    524     def get_type(self):
    525         return self._type
    526 
    527     def is_valid(self):
    528         return self._valid
    529 
    530     def set_carrier(self, on):
    531         self._link = on
    532 
    533     def get_capabilities(self):
    534         return self._caps
    535 
    536 class NMClient(gobject.GObject):
    537     __gsignals__ = {
    538         'device-added'     : (gobject.SIGNAL_RUN_FIRST,
    539                               gobject.TYPE_NONE,
    540                              ([gobject.TYPE_PYOBJECT])),
    541         'device-activated' : (gobject.SIGNAL_RUN_FIRST,
    542                               gobject.TYPE_NONE,
    543                              ([gobject.TYPE_PYOBJECT])),
    544         'device-activating': (gobject.SIGNAL_RUN_FIRST,
    545                               gobject.TYPE_NONE,
    546                              ([gobject.TYPE_PYOBJECT])),
    547         'device-removed'   : (gobject.SIGNAL_RUN_FIRST,
    548                               gobject.TYPE_NONE,
    549                              ([gobject.TYPE_PYOBJECT]))
    550     }
    551 
    552     def __init__(self):
    553         gobject.GObject.__init__(self)
    554 
    555         self.nminfo = None
    556         self._nm_present = False
    557         self._nm_proxy = None
    558         self._nm_obj = None
    559         self._sig_handlers = None
    560         self._update_timer = 0
    561         self._devices = {}
    562 
    563         self.nminfo = nminfo.NMInfo(self)
    564        
    565         self._setup_dbus()
    566         if self._nm_present:
    567             self._get_initial_devices()
    568 
    569     def get_devices(self):
    570         return self._devices.values()
    571 
    572     def _get_initial_devices_reply_cb(self, ops):
    573         for op in ops:
    574             self._add_device(op)
    575 
    576     def _dev_initialized_cb(self, dev):
    577         self.emit('device-added', dev)
    578 
    579     def _dev_init_failed_cb(self, dev):
    580         # Device failed to initialize, likely due to dbus errors or something
    581         op = dev.get_op()
    582         self._remove_device(op)
    583 
    584     def _get_initial_devices_error_cb(self, err):
    585         logging.debug("Error updating devices (%s)" % err)
    586 
    587     def _get_initial_devices(self):
    588         self._nm_obj.getDevices(
    589             reply_handler=self._get_initial_devices_reply_cb,
    590             error_handler=self._get_initial_devices_error_cb)
    591 
    592     def _add_device(self, dev_op):
    593         if self._devices.has_key(dev_op):
    594             return
    595         dev = Device(self, dev_op)
    596         self._devices[dev_op] = dev
    597         dev.connect('init-failed', self._dev_init_failed_cb)
    598         dev.connect('initialized', self._dev_initialized_cb)
    599         dev.connect('state-changed', self._dev_state_changed_cb)
    600 
    601     def _remove_device(self, dev_op):
    602         if not self._devices.has_key(dev_op):
    603             return
    604         dev = self._devices[dev_op]
    605         if dev.is_valid():
    606             self.emit('device-removed', dev)
    607         del self._devices[dev_op]
    608 
    609     def _dev_state_changed_cb(self, dev):
    610         op = dev.get_op()
    611         if not self._devices.has_key(op) or not dev.is_valid():
    612             return
    613         if dev.get_state() == DEVICE_STATE_ACTIVATING:
    614             self.emit('device-activating', dev)
    615         elif dev.get_state() == DEVICE_STATE_ACTIVATED:
    616             self.emit('device-activated', dev)
    617 
    618     def get_device(self, dev_op):
    619         if not self._devices.has_key(dev_op):
    620             return None
    621         return self._devices[dev_op]
    622 
    623     def _setup_dbus(self):
    624         self._sig_handlers = {
    625             'StateChange': self.state_changed_sig_handler,
    626             'DeviceAdded': self.device_added_sig_handler,
    627             'DeviceRemoved': self.device_removed_sig_handler,
    628             'DeviceActivationStage': self.device_activation_stage_sig_handler,
    629             'DeviceActivating': self.device_activating_sig_handler,
    630             'DeviceNowActive': self.device_now_active_sig_handler,
    631             'DeviceNoLongerActive': self.device_no_longer_active_sig_handler,
    632             'DeviceActivationFailed': \
    633                 self.device_activation_failed_sig_handler,
    634             'DeviceCarrierOn': self.device_carrier_on_sig_handler,
    635             'DeviceCarrierOff': self.device_carrier_off_sig_handler,
    636             'DeviceStrengthChanged': \
    637                 self.wireless_device_strength_changed_sig_handler,
    638             'WirelessNetworkAppeared': \
    639                 self.wireless_network_appeared_sig_handler,
    640             'WirelessNetworkDisappeared': \
    641                 self.wireless_network_disappeared_sig_handler,
    642             'WirelessNetworkStrengthChanged': \
    643                 self.wireless_network_strength_changed_sig_handler
    644         }
    645 
    646         try:
    647             self._nm_proxy = sys_bus.get_object(NM_SERVICE, NM_PATH,
    648                                                 follow_name_owner_changes=True)
    649             self._nm_obj = dbus.Interface(self._nm_proxy, NM_IFACE)
    650         except dbus.DBusException, e:
    651             logging.debug("Could not connect to NetworkManager: %s" % e)
    652             self._nm_present = False
    653             return
    654 
    655         sys_bus.add_signal_receiver(self.name_owner_changed_sig_handler,
    656                                          signal_name="NameOwnerChanged",
    657                                          dbus_interface="org.freedesktop.DBus")
    658 
    659         for (signal, handler) in self._sig_handlers.items():
    660             sys_bus.add_signal_receiver(handler, signal_name=signal,
    661                                         dbus_interface=NM_IFACE)
    662 
    663         # Find out whether or not NMI is running
    664         try:
    665             bus_object = sys_bus.get_object('org.freedesktop.DBus',
    666                                             '/org/freedesktop/DBus')
    667             name_ = bus_object.GetNameOwner( \
    668                     "org.freedesktop.NetworkManagerInfo",
    669                     dbus_interface='org.freedesktop.DBus')
    670             self._nm_present = True
    671         except dbus.DBusException:
    672             self._nm_present = False
    673 
    674     def set_active_device(self, device, network=None,
    675                           mesh_freq=None, mesh_start=None):
    676         ssid = ""
    677         if network:
    678             ssid = network.get_ssid()
    679         if device.get_type() == DEVICE_TYPE_802_11_MESH_OLPC:
    680             if mesh_freq or mesh_start:
    681                 if mesh_freq and not mesh_start:
    682                     self._nm_obj.setActiveDevice(device.get_op(),
    683                                                  dbus.Double(mesh_freq))
    684                 elif mesh_start and not mesh_freq:
    685                     self._nm_obj.setActiveDevice(device.get_op(),
    686                                                  dbus.Double(0.0),
    687                                                  dbus.UInt32(mesh_start))
    688                 else:
    689                     self._nm_obj.setActiveDevice(device.get_op(),
    690                                                  dbus.Double(mesh_freq),
    691                                                  dbus.UInt32(mesh_start))
    692             else:
    693                 self._nm_obj.setActiveDevice(device.get_op())
    694         else:
    695             self._nm_obj.setActiveDevice(device.get_op(), ssid)
    696 
    697     def state_changed_sig_handler(self, new_state):
    698         logging.debug('NM State Changed to %d' % new_state)
    699 
    700     def device_activation_stage_sig_handler(self, device, stage):
    701         logging.debug('Device Activation Stage "%s" for device %s'
    702                       % (NM_DEVICE_STAGE_STRINGS[stage], device))
    703         if not self._devices.has_key(device):
    704             logging.debug('DeviceActivationStage, device %s does not exist'
    705                           % (device))
    706             return
    707         self._devices[device].set_activation_stage(stage)
    708 
    709     def device_activating_sig_handler(self, device):
    710         logging.debug('DeviceActivating for %s' % (device))
    711         if not self._devices.has_key(device):
    712             logging.debug('DeviceActivating, device %s does not exist'
    713                           % (device))
    714             return
    715         self._devices[device].set_state(DEVICE_STATE_ACTIVATING)
    716 
    717     def device_now_active_sig_handler(self, device, ssid=None):
    718         logging.debug('DeviceNowActive for %s' % (device))
    719         if not self._devices.has_key(device):
    720             logging.debug('DeviceNowActive, device %s does not exist'
    721                           % (device))
    722             return
    723         self._devices[device].set_state(DEVICE_STATE_ACTIVATED)
    724 
    725     def device_no_longer_active_sig_handler(self, device):
    726         logging.debug('DeviceNoLongerActive for %s' % (device))
    727         if not self._devices.has_key(device):
    728             logging.debug('DeviceNoLongerActive, device %s does not exist'
    729                           % (device))
    730             return
    731         self._devices[device].set_state(DEVICE_STATE_INACTIVE)
    732 
    733     def device_activation_failed_sig_handler(self, device, ssid=None):
    734         logging.debug('DeviceActivationFailed for %s' % (device))
    735         if not self._devices.has_key(device):
    736             logging.debug('DeviceActivationFailed, device %s does not exist'
    737                           % (device))
    738             return
    739         self._devices[device].set_state(DEVICE_STATE_INACTIVE)
    740 
    741     def name_owner_changed_sig_handler(self, name, old, new):
    742         if name != NM_SERVICE:
    743             return
    744         if (old and len(old)) and (not new and not len(new)):
    745             # NM went away
    746             self._nm_present = False
    747             devs = self._devices.keys()
    748             for op in devs:
    749                 self._remove_device(op)
    750             self._devices = {}
    751         elif (not old and not len(old)) and (new and len(new)):
    752             # NM started up
    753             self._nm_present = True
    754             self._get_initial_devices()
    755 
    756     def device_added_sig_handler(self, device):
    757         logging.debug('DeviceAdded for %s' % (device))
    758         self._add_device(device)
    759 
    760     def device_removed_sig_handler(self, device):
    761         logging.debug('DeviceRemoved for %s' % (device))
    762         self._remove_device(device)
    763 
    764     def wireless_network_appeared_sig_handler(self, device, network):
    765         if not self._devices.has_key(device):
    766             return
    767         self._devices[device].network_appeared(network)
    768 
    769     def wireless_network_disappeared_sig_handler(self, device, network):
    770         if not self._devices.has_key(device):
    771             return
    772         self._devices[device].network_disappeared(network)
    773 
    774     def wireless_device_strength_changed_sig_handler(self, device, strength):
    775         if not self._devices.has_key(device):
    776             return
    777         self._devices[device].set_strength(strength)
    778 
    779     def wireless_network_strength_changed_sig_handler(self, device,
    780                                                       network, strength):
    781         if not self._devices.has_key(device):
    782             return
    783         net = self._devices[device].get_network(network)
    784         if net:
    785             net.set_strength(strength)
    786 
    787     def device_carrier_on_sig_handler(self, device):
    788         if not self._devices.has_key(device):
    789             return
    790         self._devices[device].set_carrier(True)
    791 
    792     def device_carrier_off_sig_handler(self, device):
    793         if not self._devices.has_key(device):
    794             return
    795         self._devices[device].set_carrier(False)
  • deleted file src/hardware/nminfo.py

    diff --git a/src/hardware/nminfo.py b/src/hardware/nminfo.py
    deleted file mode 100644
    index 9f427e0..0000000
    + -  
    1 # vi: ts=4 ai noet
    2 #
    3 # Copyright (C) 2006-2007 Red Hat, Inc.
    4 #
    5 # This program is free software; you can redistribute it and/or modify
    6 # it under the terms of the GNU General Public License as published by
    7 # the Free Software Foundation; either version 2 of the License, or
    8 # (at your option) any later version.
    9 #
    10 # This program is distributed in the hope that it will be useful,
    11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13 # GNU General Public License for more details.
    14 #
    15 # You should have received a copy of the GNU General Public License
    16 # along with this program; if not, write to the Free Software
    17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19 import dbus
    20 import dbus.service
    21 import time
    22 import os
    23 import binascii
    24 import ConfigParser
    25 import logging
    26 
    27 import nmclient
    28 import keydialog
    29 import gtk
    30 from sugar import env
    31 
    32 IW_AUTH_KEY_MGMT_802_1X = 0x1
    33 IW_AUTH_KEY_MGMT_PSK = 0x2
    34 
    35 IW_AUTH_WPA_VERSION_DISABLED = 0x00000001
    36 IW_AUTH_WPA_VERSION_WPA      = 0x00000002
    37 IW_AUTH_WPA_VERSION_WPA2     = 0x00000004
    38 
    39 NM_AUTH_TYPE_WPA_PSK_AUTO = 0x00000000
    40 IW_AUTH_CIPHER_NONE   = 0x00000001
    41 IW_AUTH_CIPHER_WEP40  = 0x00000002
    42 IW_AUTH_CIPHER_TKIP   = 0x00000004
    43 IW_AUTH_CIPHER_CCMP   = 0x00000008
    44 IW_AUTH_CIPHER_WEP104 = 0x00000010
    45 
    46 IW_AUTH_ALG_OPEN_SYSTEM = 0x00000001
    47 IW_AUTH_ALG_SHARED_KEY  = 0x00000002
    48 
    49 NM_INFO_IFACE = 'org.freedesktop.NetworkManagerInfo'
    50 NM_INFO_PATH = '/org/freedesktop/NetworkManagerInfo'
    51 
    52 
    53 class NoNetworks(dbus.DBusException):
    54     def __init__(self):
    55         dbus.DBusException.__init__(self)
    56         self._dbus_error_name = NM_INFO_IFACE + '.NoNetworks'
    57 
    58 class CanceledKeyRequestError(dbus.DBusException):
    59     def __init__(self):
    60         dbus.DBusException.__init__(self)
    61         self._dbus_error_name = NM_INFO_IFACE + '.CanceledError'
    62 
    63 
    64 class NetworkInvalidError(Exception):
    65     pass
    66 
    67 
    68 class NMConfig(ConfigParser.ConfigParser):
    69     def get_bool(self, section, name):
    70         opt = self.get(section, name)
    71         if type(opt) == str:
    72             if opt.lower() == 'yes' or opt.lower() == 'true':
    73                 return True
    74             elif opt.lower() == 'no' or opt.lower() == 'false':
    75                 return False
    76         raise ValueError("Invalid format for %s/%s.  Should be one of" \
    77                          " [yes, no, true, false]." % (section, name))
    78 
    79     def get_list(self, section, name):
    80         opt = self.get(section, name)
    81         if type(opt) != str or not len(opt):
    82             return []
    83         try:
    84             return opt.split()
    85         except Exception:
    86             raise ValueError("Invalid format for %s/%s.  Should be a" \
    87                              " space-separate list." % (section, name))
    88 
    89     def get_int(self, section, name):
    90         opt = self.get(section, name)
    91         try:
    92             return int(opt)
    93         except ValueError:
    94             raise ValueError("Invalid format for %s/%s.  Should be a" \
    95                              " valid integer." % (section, name))
    96 
    97     def get_float(self, section, name):
    98         opt = self.get(section, name)
    99         try:
    100             return float(opt)
    101         except ValueError:
    102             raise ValueError("Invalid format for %s/%s.  Should be a" \
    103                              " valid float." % (section, name))
    104 
    105 
    106 NETWORK_TYPE_UNKNOWN = 0
    107 NETWORK_TYPE_ALLOWED = 1
    108 NETWORK_TYPE_INVALID = 2
    109 
    110 
    111 class Security(object):
    112     def __init__(self, we_cipher):
    113         self._we_cipher = we_cipher
    114         self._key = None
    115         self._auth_alg = None
    116 
    117     def read_from_config(self, cfg, name):
    118         pass
    119 
    120     def read_from_args(self, args):
    121         pass
    122 
    123     def new_from_config(cfg, name):
    124         security = None
    125         we_cipher = cfg.get_int(name, "we_cipher")
    126         if we_cipher == IW_AUTH_CIPHER_NONE:
    127             security = Security(we_cipher)
    128         elif we_cipher == IW_AUTH_CIPHER_WEP40 or \
    129                         we_cipher == IW_AUTH_CIPHER_WEP104:
    130             security = WEPSecurity(we_cipher)
    131         elif we_cipher == NM_AUTH_TYPE_WPA_PSK_AUTO or \
    132                         we_cipher == IW_AUTH_CIPHER_CCMP or \
    133                         we_cipher == IW_AUTH_CIPHER_TKIP:
    134             security = WPASecurity(we_cipher)
    135         else:
    136             raise ValueError("Unsupported security combo")
    137         security.read_from_config(cfg, name)
    138         return security
    139     new_from_config = staticmethod(new_from_config)
    140 
    141     def new_from_args(we_cipher, args):
    142         security = None
    143         try:
    144             if we_cipher == IW_AUTH_CIPHER_NONE:
    145                 security = Security(we_cipher)
    146             elif we_cipher == IW_AUTH_CIPHER_WEP40 or \
    147                             we_cipher == IW_AUTH_CIPHER_WEP104:
    148                 security = WEPSecurity(we_cipher)
    149             elif we_cipher == NM_AUTH_TYPE_WPA_PSK_AUTO or \
    150                             we_cipher == IW_AUTH_CIPHER_CCMP or \
    151                             we_cipher == IW_AUTH_CIPHER_TKIP:
    152                 security = WPASecurity(we_cipher)
    153             else:
    154                 raise ValueError("Unsupported security combo")
    155             security.read_from_args(args)
    156         except ValueError, e:
    157             logging.debug("Error reading security information: %s" % e)
    158             del security
    159             return None
    160         return security
    161     new_from_args = staticmethod(new_from_args)
    162 
    163     def get_properties(self):
    164         return [dbus.Int32(self._we_cipher)]
    165 
    166     def write_to_config(self, section, config):
    167         config.set(section, "we_cipher", self._we_cipher)
    168 
    169 
    170 class WEPSecurity(Security):
    171     def read_from_args(self, args):
    172         if len(args) != 2:
    173             raise ValueError("not enough arguments")
    174         key = args[0]
    175         auth_alg = args[1]
    176         if isinstance(key, unicode):
    177             key = key.encode()
    178         if not isinstance(key, str):
    179             raise ValueError("wrong argument type for key")
    180         if not isinstance(auth_alg, int):
    181             raise ValueError("wrong argument type for auth_alg")
    182         self._key = key
    183         self._auth_alg = auth_alg
    184 
    185     def read_from_config(self, cfg, name):
    186         # Key should be a hex encoded string
    187         self._key = cfg.get(name, "key")
    188         if self._we_cipher == IW_AUTH_CIPHER_WEP40 and len(self._key) != 10:
    189             raise ValueError("Key length not right for 40-bit WEP")
    190         if self._we_cipher == IW_AUTH_CIPHER_WEP104 and len(self._key) != 26:
    191             raise ValueError("Key length not right for 104-bit WEP")
    192 
    193         try:
    194             binascii.a2b_hex(self._key)
    195         except TypeError:
    196             raise ValueError("Key was not a hexadecimal string.")
    197            
    198         self._auth_alg = cfg.get_int(name, "auth_alg")
    199         if self._auth_alg != IW_AUTH_ALG_OPEN_SYSTEM and \
    200                 self._auth_alg != IW_AUTH_ALG_SHARED_KEY:
    201             raise ValueError("Invalid authentication algorithm %d"
    202                              % self._auth_alg)
    203 
    204     def get_properties(self):
    205         args = Security.get_properties(self)
    206         args.append(dbus.String(self._key))
    207         args.append(dbus.Int32(self._auth_alg))
    208         return args
    209 
    210     def write_to_config(self, section, config):
    211         Security.write_to_config(self, section, config)
    212         config.set(section, "key", self._key)
    213         config.set(section, "auth_alg", self._auth_alg)
    214 
    215 class WPASecurity(Security):
    216     def __init__(self, we_cipher):
    217         Security.__init__(self, we_cipher)
    218         self._wpa_ver = None
    219         self._key_mgmt = None
    220 
    221     def read_from_args(self, args):
    222         if len(args) != 3:
    223             raise ValueError("not enough arguments")
    224         key = args[0]
    225         if isinstance(key, unicode):
    226             key = key.encode()
    227         if not isinstance(key, str):
    228             raise ValueError("wrong argument type for key")
    229 
    230         wpa_ver = args[1]
    231         if not isinstance(wpa_ver, int):
    232             raise ValueError("wrong argument type for WPA version")
    233 
    234         key_mgmt = args[2]
    235         if not isinstance(key_mgmt, int):
    236             raise ValueError("wrong argument type for WPA key management")
    237         if not key_mgmt & IW_AUTH_KEY_MGMT_PSK:
    238             raise ValueError("Key management types other than" \
    239                              " PSK are not supported")
    240 
    241         self._key = key
    242         self._wpa_ver = wpa_ver
    243         self._key_mgmt = key_mgmt
    244 
    245     def read_from_config(self, cfg, name):
    246         # Key should be a hex encoded string
    247         self._key = cfg.get(name, "key")
    248         if len(self._key) != 64:
    249             raise ValueError("Key length not right for WPA-PSK")
    250 
    251         try:
    252             binascii.a2b_hex(self._key)
    253         except TypeError:
    254             raise ValueError("Key was not a hexadecimal string.")
    255            
    256         self._wpa_ver = cfg.get_int(name, "wpa_ver")
    257         if self._wpa_ver != IW_AUTH_WPA_VERSION_WPA and \
    258                 self._wpa_ver != IW_AUTH_WPA_VERSION_WPA2:
    259             raise ValueError("Invalid WPA version %d" % self._wpa_ver)
    260 
    261         self._key_mgmt = cfg.get_int(name, "key_mgmt")
    262         if not self._key_mgmt & IW_AUTH_KEY_MGMT_PSK:
    263             raise ValueError("Invalid WPA key management option %d"
    264                              % self._key_mgmt)
    265 
    266     def get_properties(self):
    267         args = Security.get_properties(self)
    268         args.append(dbus.String(self._key))
    269         args.append(dbus.Int32(self._wpa_ver))
    270         args.append(dbus.Int32(self._key_mgmt))
    271         return args
    272 
    273     def write_to_config(self, section, config):
    274         Security.write_to_config(self, section, config)
    275         config.set(section, "key", self._key)
    276         config.set(section, "wpa_ver", self._wpa_ver)
    277         config.set(section, "key_mgmt", self._key_mgmt)
    278 
    279 
    280 class Network:
    281     def __init__(self, ssid):
    282         self.ssid = ssid
    283         self.timestamp = int(time.time())
    284         self.bssids = []
    285         self.we_cipher = 0
    286         self._security = None
    287 
    288     def get_properties(self):
    289         bssid_list = dbus.Array([], signature="s")
    290         for item in self.bssids:
    291             bssid_list.append(dbus.String(item))
    292         args = [dbus.String(self.ssid), dbus.Int32(self.timestamp),
    293                 dbus.Boolean(True), bssid_list]
    294         args += self._security.get_properties()
    295         return tuple(args)
    296 
    297     def get_security(self):
    298         return self._security.get_properties()
    299 
    300     def set_security(self, security):
    301         self._security = security
    302 
    303     def read_from_args(self, auto, bssid, we_cipher, args):
    304         if auto == False:
    305             self.timestamp = int(time.time())
    306         if not bssid in self.bssids:
    307             self.bssids.append(bssid)
    308 
    309         self._security = Security.new_from_args(we_cipher, args)
    310         if not self._security:
    311             raise NetworkInvalidError("Invalid security information")
    312 
    313     def read_from_config(self, config):
    314         try:
    315             self.timestamp = config.get_int(self.ssid, "timestamp")
    316         except (ConfigParser.NoOptionError, ValueError), e:
    317             raise NetworkInvalidError(e)
    318 
    319         try:
    320             self._security = Security.new_from_config(config, self.ssid)
    321         except Exception, e:
    322             raise NetworkInvalidError(e)
    323 
    324         # The following don't need to be present
    325         try:
    326             self.bssids = config.get_list(self.ssid, "bssids")
    327         except (ConfigParser.NoOptionError, ValueError), e:
    328             logging.debug("Error reading bssids: %s" % e)
    329 
    330     def write_to_config(self, config):
    331         try:
    332             config.add_section(self.ssid)
    333             config.set(self.ssid, "timestamp", self.timestamp)
    334             if len(self.bssids) > 0:
    335                 opt = " "
    336                 opt = opt.join(self.bssids)
    337                 config.set(self.ssid, "bssids", opt)
    338             self._security.write_to_config(self.ssid, config)
    339         except Exception, e:
    340             logging.debug("Error writing '%s': %s" % (self.ssid, e))
    341 
    342 
    343 class NotFoundError(dbus.DBusException):
    344     pass
    345 class UnsupportedError(dbus.DBusException):
    346     pass
    347 
    348 class NMInfoDBusServiceHelper(dbus.service.Object):
    349     def __init__(self, parent):
    350         self._parent = parent
    351         bus = dbus.SystemBus()
    352 
    353         # If NMI is already around, don't grab the NMI service
    354         bus_object = bus.get_object('org.freedesktop.DBus',
    355                                     '/org/freedesktop/DBus')
    356         name = None
    357         try:
    358             name = bus_object.GetNameOwner( \
    359                     "org.freedesktop.NetworkManagerInfo",
    360                     dbus_interface='org.freedesktop.DBus')
    361         except dbus.DBusException:
    362             logging.debug("Error getting owner of NMI")
    363         if name:
    364             logging.info("NMI service already owned by %s, won't claim it."
    365                           % name)
    366 
    367         bus_name = dbus.service.BusName(NM_INFO_IFACE, bus=bus)
    368         dbus.service.Object.__init__(self, bus_name, NM_INFO_PATH)
    369 
    370     @dbus.service.method(NM_INFO_IFACE, in_signature='i', out_signature='as')
    371     def getNetworks(self, net_type):
    372         ssids = self._parent.get_networks(net_type)
    373         if len(ssids) > 0:
    374             return dbus.Array(ssids)
    375 
    376         raise NoNetworks()
    377 
    378     @dbus.service.method(NM_INFO_IFACE, in_signature='si',
    379                          async_callbacks=('async_cb', 'async_err_cb'))
    380     def getNetworkProperties(self, ssid, net_type, async_cb, async_err_cb):
    381         self._parent.get_network_properties(ssid, net_type,
    382                                             async_cb, async_err_cb)
    383 
    384     @dbus.service.method(NM_INFO_IFACE)
    385     def updateNetworkInfo(self, ssid, bauto, bssid, cipher, *args):
    386         self._parent.update_network_info(ssid, bauto, bssid, cipher, args)
    387 
    388     @dbus.service.method(NM_INFO_IFACE,
    389                          async_callbacks=('async_cb', 'async_err_cb'))
    390     def getKeyForNetwork(self, dev_path, net_path, ssid, attempt,
    391                          new_key, async_cb, async_err_cb):
    392         self._parent.get_key_for_network(dev_path, net_path, ssid,
    393                 attempt, new_key, async_cb, async_err_cb)
    394 
    395     @dbus.service.method(NM_INFO_IFACE)
    396     def cancelGetKeyForNetwork(self):
    397         self._parent.cancel_get_key_for_network()
    398 
    399 class NMInfo(object):
    400     def __init__(self, client):
    401         profile_path = env.get_profile_path()
    402         self._cfg_file = os.path.join(profile_path, "nm", "networks.cfg")
    403         self._nmclient = client
    404         self._allowed_networks = self._read_config()
    405         self._dbus_helper = NMInfoDBusServiceHelper(self)
    406         self._key_dialog = None
    407 
    408     def save_config(self):
    409         self._write_config(self._allowed_networks)
    410 
    411     def _read_config(self):
    412         if not os.path.exists(os.path.dirname(self._cfg_file)):
    413             os.makedirs(os.path.dirname(self._cfg_file), 0755)
    414         if not os.path.exists(self._cfg_file):
    415             self._write_config({})
    416             return {}
    417 
    418         config = NMConfig()
    419         config.read(self._cfg_file)
    420         networks = {}
    421         for name in config.sections():
    422             try:
    423                 net = Network(name)
    424                 net.read_from_config(config)
    425                 networks[name] = net
    426             except Exception, e:
    427                 logging.error("Error when processing config for" \
    428                               " the network %s: %r" % (name, e))
    429 
    430         del config
    431         return networks
    432 
    433     def _write_config(self, networks):
    434         fp = open(self._cfg_file, 'w')
    435         config = NMConfig()
    436         for net in networks.values():
    437             net.write_to_config(config)
    438         config.write(fp)
    439         fp.close()
    440         del config
    441 
    442     def get_networks(self, net_type):
    443         if net_type != NETWORK_TYPE_ALLOWED:
    444             raise ValueError("Bad network type")
    445         nets = []
    446         for net in self._allowed_networks.values():
    447             nets.append(net.ssid)
    448         logging.debug("Returning networks: %s" % nets)
    449         return nets
    450 
    451     def get_network_properties(self, ssid, net_type, async_cb, async_err_cb):
    452         if not isinstance(ssid, unicode):
    453             async_err_cb(ValueError("Invalid arguments; ssid must be unicode."))
    454         if net_type != NETWORK_TYPE_ALLOWED:
    455             async_err_cb(ValueError("Bad network type"))
    456         if not self._allowed_networks.has_key(ssid):
    457             async_err_cb(NotFoundError("Network '%s' not found." % ssid))
    458         network = self._allowed_networks[ssid]
    459         props = network.get_properties()
    460 
    461         # DBus workaround: the normal method return handler wraps
    462         # the returned arguments in a tuple and then converts that to a
    463         # struct, but NetworkManager expects a plain list of arguments.
    464         # It turns out that the async callback method return code _doesn't_
    465         # wrap the returned arguments in a tuple, so as a workaround use
    466         # the async callback stuff here even though we're not doing it
    467         # asynchronously.
    468         async_cb(*props)
    469 
    470     def update_network_info(self, ssid, auto, bssid, we_cipher, args):
    471         if not isinstance(ssid, unicode):
    472             raise ValueError("Invalid arguments; ssid must be unicode.")
    473         if self._allowed_networks.has_key(ssid):
    474             del self._allowed_networks[ssid]
    475         net = Network(ssid)
    476         try:
    477             net.read_from_args(auto, bssid, we_cipher, args)
    478             logging.debug("Updated network information for '%s'." % ssid)
    479             self._allowed_networks[ssid] = net
    480             self.save_config()
    481         except NetworkInvalidError, e:
    482             logging.debug("Error updating network information: %s" % e)
    483             del net
    484 
    485     def get_key_for_network(self, dev_op, net_op, ssid, attempt,
    486                             new_key, async_cb, async_err_cb):
    487         if not isinstance(ssid, unicode):
    488             raise ValueError("Invalid arguments; ssid must be unicode.")
    489         if self._allowed_networks.has_key(ssid) and not new_key:
    490             # We've got the info already
    491             net = self._allowed_networks[ssid]
    492             async_cb(tuple(net.get_security()))
    493             return
    494 
    495         # Otherwise, ask the user for it
    496         net = None
    497         dev = self._nmclient.get_device(dev_op)
    498         if not dev:
    499             async_err_cb(NotFoundError("Device was unknown."))
    500             return
    501 
    502         if dev.get_type() == nmclient.DEVICE_TYPE_802_3_ETHERNET:
    503             # We don't support wired 802.1x yet...
    504             async_err_cb(UnsupportedError("Device type is unsupported by NMI."))
    505             return
    506 
    507         net = dev.get_network(net_op)
    508         if not net:
    509             async_err_cb(NotFoundError("Network was unknown."))
    510             return
    511 
    512         self._key_dialog = keydialog.new_key_dialog(net, async_cb, async_err_cb)
    513         self._key_dialog.connect("response", self._key_dialog_response_cb)
    514         self._key_dialog.connect("destroy", self._key_dialog_destroy_cb)
    515         self._key_dialog.show_all()
    516 
    517     def _key_dialog_destroy_cb(self, widget, data=None):
    518         if widget != self._key_dialog:
    519             return
    520         self._key_dialog_response_cb(widget, gtk.RESPONSE_CANCEL)
    521 
    522     def _key_dialog_response_cb(self, widget, response_id):
    523         if widget != self._key_dialog:
    524             return
    525 
    526         (async_cb, async_err_cb) = self._key_dialog.get_callbacks()
    527         security = None
    528         if response_id == gtk.RESPONSE_OK:
    529             security = self._key_dialog.create_security()
    530         self._key_dialog = None
    531         widget.destroy()
    532 
    533         if response_id in [gtk.RESPONSE_CANCEL, gtk.RESPONSE_NONE]:
    534             # key dialog dialog was canceled; send the error back to NM
    535             async_err_cb(CanceledKeyRequestError())
    536         elif response_id == gtk.RESPONSE_OK:
    537             if not security:
    538                 raise RuntimeError("Invalid security arguments.")
    539             props = security.get_properties()
    540             a = tuple(props)
    541             async_cb(*a)
    542         else:
    543             raise RuntimeError("Unhandled key dialog response %d" % response_id)
    544 
    545     def cancel_get_key_for_network(self):
    546         # Close the wireless key dialog and just have it return
    547         # with the 'canceled' argument set to true
    548         if not self._key_dialog:
    549             return
    550         self._key_dialog_destroy_cb(self._key_dialog)
    551 
    552     # this method is invoked directly in-process (not by DBus).
    553     def delete_all_networks(self):
    554         self._allowed_networks = {}
    555         self.save_config()
    556 
  • src/model/Makefile.am

    diff --git a/src/model/Makefile.am b/src/model/Makefile.am
    index 0b7d14c..c89ce47 100644
    a b SUBDIRS = devices 
    33sugardir = $(pkgdatadir)/shell/model
    44sugar_PYTHON =                  \
    55        __init__.py             \
    6         accesspointmodel.py     \
    76        BuddyModel.py           \
    87        Friends.py              \
    98        Invites.py              \
    109        Owner.py                \
    11         MeshModel.py            \
    1210        shellmodel.py           \
    1311        homeactivity.py         \
    14         homemodel.py
     12        homemodel.py            \
     13        network.py              \
     14        neighborhood.py
  • deleted file src/model/MeshModel.py

    diff --git a/src/model/MeshModel.py b/src/model/MeshModel.py
    deleted file mode 100644
    index fa33035..0000000
    + -  
    1 # Copyright (C) 2006-2007 Red Hat, Inc.
    2 #
    3 # This program is free software; you can redistribute it and/or modify
    4 # it under the terms of the GNU General Public License as published by
    5 # the Free Software Foundation; either version 2 of the License, or
    6 # (at your option) any later version.
    7 #
    8 # This program is distributed in the hope that it will be useful,
    9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11 # GNU General Public License for more details.
    12 #
    13 # You should have received a copy of the GNU General Public License
    14 # along with this program; if not, write to the Free Software
    15 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    16 
    17 import gobject
    18 
    19 from sugar.graphics.xocolor import XoColor
    20 from sugar.presence import presenceservice
    21 from sugar import activity
    22 
    23 from model.BuddyModel import BuddyModel
    24 from model.accesspointmodel import AccessPointModel
    25 from hardware import hardwaremanager
    26 from hardware import nmclient
    27 
    28 class ActivityModel:
    29     def __init__(self, act, bundle):
    30         self.activity = act
    31         self.bundle = bundle
    32 
    33     def get_id(self):
    34         return self.activity.props.id
    35        
    36     def get_icon_name(self):
    37         return self.bundle.icon
    38    
    39     def get_color(self):
    40         return XoColor(self.activity.props.color)
    41 
    42     def get_bundle_id(self):
    43         return self.bundle.bundle_id
    44 
    45 class MeshModel(gobject.GObject):
    46     __gsignals__ = {
    47         'activity-added':       (gobject.SIGNAL_RUN_FIRST,
    48                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    49         'activity-removed':     (gobject.SIGNAL_RUN_FIRST,
    50                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    51         'buddy-added':          (gobject.SIGNAL_RUN_FIRST,
    52                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    53         'buddy-moved':          (gobject.SIGNAL_RUN_FIRST,
    54                                  gobject.TYPE_NONE,
    55                                 ([gobject.TYPE_PYOBJECT,
    56                                   gobject.TYPE_PYOBJECT])),
    57         'buddy-removed':        (gobject.SIGNAL_RUN_FIRST,
    58                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    59         'access-point-added':   (gobject.SIGNAL_RUN_FIRST,
    60                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    61         'access-point-removed': (gobject.SIGNAL_RUN_FIRST,
    62                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    63         'mesh-added':           (gobject.SIGNAL_RUN_FIRST,
    64                                  gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
    65         'mesh-removed':         (gobject.SIGNAL_RUN_FIRST,
    66                                  gobject.TYPE_NONE, ([]))
    67     }
    68 
    69     def __init__(self):
    70         gobject.GObject.__init__(self)
    71 
    72         self._activities = {}
    73         self._buddies = {}
    74         self._access_points = {}
    75         self._mesh = None
    76 
    77         self._pservice = presenceservice.get_instance()
    78         self._pservice.connect("activity-appeared",
    79                                self._activity_appeared_cb)
    80         self._pservice.connect('activity-disappeared',
    81                                self._activity_disappeared_cb)
    82         self._pservice.connect("buddy-appeared",
    83                                self._buddy_appeared_cb)
    84         self._pservice.connect("buddy-disappeared",
    85                                self._buddy_disappeared_cb)
    86 
    87         # Add any buddies the PS knows about already
    88         self._pservice.get_buddies_async(reply_handler=self._get_buddies_cb)
    89 
    90         self._pservice.get_activities_async(
    91                 reply_handler=self._get_activities_cb)
    92 
    93         network_manager = hardwaremanager.get_network_manager()
    94         if network_manager:
    95             for nm_device in network_manager.get_devices():
    96                 self._add_network_device(nm_device)
    97             network_manager.connect('device-added',
    98                                     self._nm_device_added_cb)
    99             network_manager.connect('device-removed',
    100                                     self._nm_device_removed_cb)
    101 
    102     def _get_buddies_cb(self, buddy_list):
    103         for buddy in buddy_list:
    104             self._buddy_appeared_cb(self._pservice, buddy)
    105 
    106     def _get_activities_cb(self, activity_list):
    107         for act in activity_list:
    108             self._check_activity(act)
    109 
    110     def _nm_device_added_cb(self, manager, nm_device):
    111         self._add_network_device(nm_device)
    112 
    113     def _nm_device_removed_cb(self, manager, nm_device):
    114         self._remove_network_device(nm_device)
    115 
    116     def _nm_network_appeared_cb(self, nm_device, nm_network):
    117         self._add_access_point(nm_device, nm_network)
    118 
    119     def _nm_network_disappeared_cb(self, nm_device, nm_network):
    120         if self._access_points.has_key(nm_network.get_op()):
    121             ap = self._access_points[nm_network.get_op()]
    122             self._remove_access_point(ap)
    123 
    124     def _add_network_device(self, nm_device):
    125         dtype = nm_device.get_type()
    126         if dtype == nmclient.DEVICE_TYPE_802_11_WIRELESS:
    127             for nm_network in nm_device.get_networks():
    128                 self._add_access_point(nm_device, nm_network)
    129 
    130             nm_device.connect('network-appeared',
    131                               self._nm_network_appeared_cb)
    132             nm_device.connect('network-disappeared',
    133                               self._nm_network_disappeared_cb)
    134         elif dtype == nmclient.DEVICE_TYPE_802_11_MESH_OLPC:
    135             self._mesh = nm_device
    136             self.emit('mesh-added', self._mesh)
    137 
    138     def _remove_network_device(self, nm_device):
    139         if nm_device == self._mesh:
    140             self._mesh = None
    141             self.emit('mesh-removed')
    142         elif nm_device.get_type() == nmclient.DEVICE_TYPE_802_11_WIRELESS:
    143             aplist = self._access_points.values()
    144             for ap in aplist:
    145                 if ap.get_nm_device() == nm_device:
    146                     self._remove_access_point(ap)
    147 
    148     def _add_access_point(self, nm_device, nm_network):
    149         model = AccessPointModel(nm_device, nm_network)
    150         self._access_points[model.get_id()] = model
    151         self.emit('access-point-added', model)
    152 
    153     def _remove_access_point(self, ap):
    154         if not self._access_points.has_key(ap.get_id()):
    155             return
    156         self.emit('access-point-removed', ap)
    157         del self._access_points[ap.get_id()]
    158 
    159     def get_mesh(self):
    160         return self._mesh
    161 
    162     def get_access_points(self):
    163         return self._access_points.values()
    164 
    165     def get_activities(self):
    166         return self._activities.values()
    167 
    168     def get_buddies(self):
    169         return self._buddies.values()
    170 
    171     def _buddy_activity_changed_cb(self, model, cur_activity):
    172         if not self._buddies.has_key(model.get_key()):
    173             return
    174         if cur_activity and self._activities.has_key(cur_activity.props.id):
    175             activity_model = self._activities[cur_activity.props.id]
    176             self.emit('buddy-moved', model, activity_model)
    177         else:
    178             self.emit('buddy-moved', model, None)
    179 
    180     def _buddy_appeared_cb(self, pservice, buddy):
    181         if self._buddies.has_key(buddy.props.key):
    182             return
    183 
    184         model = BuddyModel(buddy=buddy)
    185         model.connect('current-activity-changed',
    186                       self._buddy_activity_changed_cb)
    187         self._buddies[buddy.props.key] = model
    188         self.emit('buddy-added', model)
    189 
    190         cur_activity = buddy.props.current_activity
    191         if cur_activity:
    192             self._buddy_activity_changed_cb(model, cur_activity)
    193 
    194     def _buddy_disappeared_cb(self, pservice, buddy):
    195         if not self._buddies.has_key(buddy.props.key):
    196             return
    197         self.emit('buddy-removed', self._buddies[buddy.props.key])
    198         del self._buddies[buddy.props.key]
    199 
    200     def _activity_appeared_cb(self, pservice, act):
    201         self._check_activity(act)
    202 
    203     def _check_activity(self, presence_activity):
    204         registry = activity.get_registry()
    205         bundle = registry.get_activity(presence_activity.props.type)
    206         if not bundle:
    207             return
    208         if self.has_activity(presence_activity.props.id):
    209             return
    210         self.add_activity(bundle, presence_activity)
    211 
    212     def has_activity(self, activity_id):
    213         return self._activities.has_key(activity_id)
    214 
    215     def get_activity(self, activity_id):
    216         if self.has_activity(activity_id):
    217             return self._activities[activity_id]
    218         else:
    219             return None
    220 
    221     def add_activity(self, bundle, act):
    222         model = ActivityModel(act, bundle)
    223         self._activities[model.get_id()] = model
    224         self.emit('activity-added', model)
    225 
    226         for buddy in self._pservice.get_buddies():
    227             cur_activity = buddy.props.current_activity
    228             key = buddy.props.key
    229             if cur_activity == activity and self._buddies.has_key(key):
    230                 buddy_model = self._buddies[key]
    231                 self.emit('buddy-moved', buddy_model, model)
    232 
    233     def _activity_disappeared_cb(self, pservice, act):
    234         if self._activities.has_key(act.props.id):
    235             activity_model = self._activities[act.props.id]
    236             self.emit('activity-removed', activity_model)
    237             del self._activities[act.props.id]
  • deleted file src/model/accesspointmodel.py

    diff --git a/src/model/accesspointmodel.py b/src/model/accesspointmodel.py
    deleted file mode 100644
    index f464f75..0000000
    + -  
    1 # Copyright (C) 2006-2007 Red Hat, Inc.
    2 #
    3 # This program is free software; you can redistribute it and/or modify
    4 # it under the terms of the GNU General Public License as published by
    5 # the Free Software Foundation; either version 2 of the License, or
    6 # (at your option) any later version.
    7 #
    8 # This program is distributed in the hope that it will be useful,
    9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11 # GNU General Public License for more details.
    12 #
    13 # You should have received a copy of the GNU General Public License
    14 # along with this program; if not, write to the Free Software
    15 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    16 
    17 import gobject
    18 
    19 from hardware import nmclient
    20 
    21 STATE_CONNECTING   = 0
    22 STATE_CONNECTED    = 1
    23 STATE_NOTCONNECTED = 2
    24 
    25 _nm_state_to_state = {
    26     nmclient.NETWORK_STATE_CONNECTED    : STATE_CONNECTED,
    27     nmclient.NETWORK_STATE_CONNECTING   : STATE_CONNECTING,
    28     nmclient.NETWORK_STATE_NOTCONNECTED : STATE_NOTCONNECTED
    29 }
    30 
    31 class AccessPointModel(gobject.GObject):
    32     __gproperties__ = {
    33         'name'     : (str, None, None, None,
    34                       gobject.PARAM_READABLE),
    35         'strength' : (int, None, None, 0, 100, 0,
    36                       gobject.PARAM_READABLE),
    37         'state'    : (int, None, None, STATE_CONNECTING,
    38                       STATE_NOTCONNECTED, 0, gobject.PARAM_READABLE),
    39         'capabilities' : (int, None, None, 0, 0x7FFFFFFF, 0,
    40                       gobject.PARAM_READABLE),
    41         'mode'     : (int, None, None, 0, 6, 0, gobject.PARAM_READABLE)
    42     }
    43 
    44     def __init__(self, nm_device, nm_network):
    45         gobject.GObject.__init__(self)
    46         self._nm_network = nm_network
    47         self._nm_device = nm_device
    48 
    49         self._nm_network.connect('strength-changed',
    50                                  self._strength_changed_cb)
    51         self._nm_network.connect('state-changed',
    52                                  self._state_changed_cb)
    53 
    54     def _strength_changed_cb(self, nm_network):
    55         self.notify('strength')
    56 
    57     def _state_changed_cb(self, nm_network):
    58         self.notify('state')
    59 
    60     def get_id(self):
    61         return self._nm_network.get_op()
    62 
    63     def get_nm_device(self):
    64         return self._nm_device
    65 
    66     def get_nm_network(self):
    67         return self._nm_network
    68 
    69     def do_get_property(self, pspec):
    70         if pspec.name == 'strength':
    71             return self._nm_network.get_strength()
    72         elif pspec.name == 'name':
    73             return self._nm_network.get_ssid()
    74         elif pspec.name == 'state':
    75             nm_state = self._nm_network.get_state()
    76             return _nm_state_to_state[nm_state]
    77         elif pspec.name == 'capabilities':
    78             return self._nm_network.get_caps()
    79         elif pspec.name == 'mode':
    80             return self._nm_network.get_mode()
  • src/model/devices/device.py

    diff --git a/src/model/devices/device.py b/src/model/devices/device.py
    index 3273da9..6a62088 100644
    a b  
    1616# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1717
    1818import gobject
    19 from hardware import nmclient
    2019
    2120from sugar import util
    2221
    23 STATE_ACTIVATING = 0
    24 STATE_ACTIVATED  = 1
    25 STATE_INACTIVE   = 2
    26 
    27 nm_state_to_state = {
    28     nmclient.DEVICE_STATE_ACTIVATING : STATE_ACTIVATING,
    29     nmclient.DEVICE_STATE_ACTIVATED  : STATE_ACTIVATED,
    30     nmclient.DEVICE_STATE_INACTIVE   : STATE_INACTIVE
    31 }
    32 
    3322class Device(gobject.GObject):
    3423    def __init__(self, device_id=None):
    3524        gobject.GObject.__init__(self)
  • src/model/devices/devicesmodel.py

    diff --git a/src/model/devices/devicesmodel.py b/src/model/devices/devicesmodel.py
    index f328109..aa9446c 100644
    a b import logging 
    1919import gobject
    2020import dbus
    2121
    22 from model.devices import device
    2322from model.devices.network import wireless
    24 from model.devices.network import mesh
    2523from model.devices import battery
    2624from model.devices import speaker
    27 from hardware import hardwaremanager
    28 from hardware import nmclient
     25from model import network
     26
     27_NM_SERVICE = 'org.freedesktop.NetworkManager'
     28_NM_IFACE = 'org.freedesktop.NetworkManager'
     29_NM_PATH = '/org/freedesktop/NetworkManager'
     30_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
    2931
    3032class DevicesModel(gobject.GObject):
    3133    __gsignals__ = {
    class DevicesModel(gobject.GObject): 
    3941   
    4042    def __init__(self):
    4143        gobject.GObject.__init__(self)
     44        self._bus = dbus.SystemBus()
     45        self._netmgr = None
    4246
    4347        self._devices = {}
    4448        self._sigids = {}
    class DevicesModel(gobject.GObject): 
    6266            self.add_device(battery.Device(udi))
    6367
    6468    def _observe_network_manager(self):
    65         network_manager = hardwaremanager.get_network_manager()
    66         if not network_manager:
     69        try:
     70            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     71            self._netmgr = dbus.Interface(obj, _NM_IFACE)
     72        except dbus.DBusException:
     73            logging.debug('%s service not available', _NM_SERVICE)
    6774            return
    6875
    69         for dev in network_manager.get_devices():
    70             self._check_network_device(dev)
    71 
    72         network_manager.connect('device-added',
    73                                 self._network_device_added_cb)
    74         network_manager.connect('device-activating',
    75                                 self._network_device_activating_cb)
    76         network_manager.connect('device-activated',
    77                                 self._network_device_activated_cb)
    78         network_manager.connect('device-removed',
    79                                 self._network_device_removed_cb)
    80 
    81     def _network_device_added_cb(self, network_manager, nm_device):
    82         state = nm_device.get_state()
    83         if state == nmclient.DEVICE_STATE_ACTIVATING \
    84                 or state == nmclient.DEVICE_STATE_ACTIVATED:
    85             self._check_network_device(nm_device)
    86 
    87     def _network_device_activating_cb(self, network_manager, nm_device):
    88         self._check_network_device(nm_device)
    89 
    90     def _network_device_activated_cb(self, network_manager, nm_device):
    91         pass
    92 
    93     def _network_device_removed_cb(self, network_manager, nm_device):
    94         if self._devices.has_key(str(nm_device.get_op())):
    95             self.remove_device(self._get_network_device(nm_device))
    96 
    97     def _check_network_device(self, nm_device):
    98         if not nm_device.is_valid():
    99             logging.debug("Device %s not valid" % nm_device.get_op())
    100             return
     76        self._netmgr.GetDevices(reply_handler=self.__get_devices_reply_cb,
     77                                error_handler=self.__get_devices_error_cb)
    10178
    102         dtype = nm_device.get_type()
    103         if dtype == nmclient.DEVICE_TYPE_802_11_WIRELESS \
    104            or dtype == nmclient.DEVICE_TYPE_802_11_MESH_OLPC:
    105             self._add_network_device(nm_device)
     79        self._bus.add_signal_receiver(self.__device_added_cb,
     80                                      signal_name='DeviceAdded',
     81                                      dbus_interface=_NM_IFACE)
     82        self._bus.add_signal_receiver(self.__device_removed_cb,
     83                                      signal_name='DeviceRemoved',
     84                                      dbus_interface=_NM_IFACE)
    10685
    107     def _get_network_device(self, nm_device):
    108         return self._devices[str(nm_device.get_op())]
     86    def __get_devices_reply_cb(self, devices_o):
     87        for dev_o in devices_o:
     88            self._check_device(dev_o)
    10989
    110     def _network_device_state_changed_cb(self, dev, param):
    111         if dev.props.state == device.STATE_INACTIVE:
    112             self.remove_device(dev)
     90    def __get_devices_error_cb(self, err):
     91        logging.error('Failed to get devices: %s', err)
    11392
    114     def _add_network_device(self, nm_device):
    115         if self._devices.has_key(str(nm_device.get_op())):
    116             logging.debug("Tried to add device %s twice" % nm_device.get_op())
    117             return
     93    def _check_device(self, device_o):
     94        nm_device = self._bus.get_object(_NM_SERVICE, device_o)
     95        props = dbus.Interface(nm_device, 'org.freedesktop.DBus.Properties')
     96
     97        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
     98        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
     99            device = wireless.Device(nm_device)
     100            self.add_device(device)
     101
     102    def __device_added_cb(self, device_o):
     103        self._check_device(device_o)
    118104
    119         dtype = nm_device.get_type()
    120         if dtype == nmclient.DEVICE_TYPE_802_11_WIRELESS:
    121             dev = wireless.Device(nm_device)
    122             self.add_device(dev)
    123             sigid = dev.connect('notify::state',
    124                                 self._network_device_state_changed_cb)
    125             self._sigids[dev] = sigid
    126         if dtype == nmclient.DEVICE_TYPE_802_11_MESH_OLPC:
    127             dev = mesh.Device(nm_device)
    128             self.add_device(dev)
    129             sigid = dev.connect('notify::state',
    130                                 self._network_device_state_changed_cb)
    131             self._sigids[dev] = sigid
     105    def __device_removed_cb(self, device_o):
     106        if device_o in self._devices:
     107            device = self._devices[device_o]
     108            self.remove_device(device)
    132109
    133110    def __iter__(self):
    134111        return iter(self._devices.values())
    class DevicesModel(gobject.GObject): 
    139116
    140117    def remove_device(self, dev):
    141118        self.emit('device-disappeared', self._devices[dev.get_id()])
    142         dev.disconnect(self._sigids[dev])
    143         del self._sigids[dev]
     119        if dev in self._sigids:
     120            dev.disconnect(self._sigids[dev])
     121            del self._sigids[dev]
    144122        del self._devices[dev.get_id()]
  • src/model/devices/network/wireless.py

    diff --git a/src/model/devices/network/wireless.py b/src/model/devices/network/wireless.py
    index b2efb49..e8b64ff 100644
    a b  
    1515# along with this program; if not, write to the Free Software
    1616# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1717
    18 import gobject
    19 
    2018from model.devices import device
    2119
    22 def freq_to_channel(freq):
    23     ftoc = { 2.412: 1, 2.417: 2, 2.422: 3, 2.427: 4,
    24              2.432: 5, 2.437: 6, 2.442: 7, 2.447: 8,
    25              2.452: 9, 2.457: 10, 2.462: 11, 2.467: 12,
    26              2.472: 13
    27              }
    28     return ftoc[freq]
    29 
    30 def channel_to_freq(channel):
    31     ctof = { 1: 2.412, 2: 2.417, 3: 2.422, 4: 2.427,
    32              5: 2.432, 6: 2.437, 7: 2.442, 8: 2.447,
    33              9: 2.452, 10: 2.457, 11: 2.462, 12: 2.467,
    34              13: 2.472
    35              }
    36     return ctof[channel]
    37 
    3820class Device(device.Device):
    39     __gproperties__ = {
    40         'name'     : (str, None, None, None,
    41                       gobject.PARAM_READABLE),
    42         'strength' : (int, None, None, 0, 100, 0,
    43                       gobject.PARAM_READABLE),
    44         'state'    : (int, None, None, device.STATE_ACTIVATING,
    45                       device.STATE_INACTIVE, 0, gobject.PARAM_READABLE),
    46         'frequency': (float, None, None, 0.0, 9999.99, 0.0,
    47                       gobject.PARAM_READABLE),
    48         'ip-address' : (str, None, None, None, gobject.PARAM_READABLE),
    49     }
    50 
    5121    def __init__(self, nm_device):
    5222        device.Device.__init__(self)
    53         self._nm_device = nm_device
    54 
    55         self._nm_device.connect('strength-changed',
    56                                 self._strength_changed_cb)
    57         self._nm_device.connect('ssid-changed',
    58                                 self._ssid_changed_cb)
    59         self._nm_device.connect('state-changed',
    60                                 self._state_changed_cb)
    61         self._nm_device.connect('ip-changed', self._ip_changed_cb)
    62 
    63     def _strength_changed_cb(self, nm_device):
    64         self.notify('strength')
    65 
    66     def _ssid_changed_cb(self, nm_device):
    67         self.notify('name')
    68 
    69     def _state_changed_cb(self, nm_device):
    70         self.notify('state')
    71 
    72     def _ip_changed_cb(self, nm_device):
    73         self.notify('ip-address')
    74 
    75     def do_get_property(self, pspec):
    76         if pspec.name == 'strength':
    77             return self._nm_device.get_strength()
    78         elif pspec.name == 'name':
    79             import logging
    80             logging.debug('wireless.Device.props.name: %s' %
    81                     self._nm_device.get_ssid())
    82             return self._nm_device.get_ssid()
    83         elif pspec.name == 'state':
    84             nm_state = self._nm_device.get_state()
    85             return device.nm_state_to_state[nm_state]
    86         elif pspec.name == 'frequency':
    87             return self._nm_device.get_frequency()
    88         elif pspec.name == 'ip-address':
    89             return self._nm_device.get_ip_address()
     23        self.nm_device = nm_device
    9024
    9125    def get_type(self):
    9226        return 'network.wireless'
    9327
    9428    def get_id(self):
    95         return str(self._nm_device.get_op())
    96 
    97     def get_active_network_colors(self):
    98         net = self._nm_device.get_active_network()
    99         if not net:
    100             return (None, None)
    101         return net.get_colors()
     29        return str(self.nm_device.object_path)
    10230
  • new file src/model/neighborhood.py

    diff --git a/src/model/neighborhood.py b/src/model/neighborhood.py
    new file mode 100644
    index 0000000..0a09a62
    - +  
     1# Copyright (C) 2006-2007 Red Hat, Inc.
     2#
     3# This program is free software; you can redistribute it and/or modify
     4# it under the terms of the GNU General Public License as published by
     5# the Free Software Foundation; either version 2 of the License, or
     6# (at your option) any later version.
     7#
     8# This program is distributed in the hope that it will be useful,
     9# but WITHOUT ANY WARRANTY; without even the implied warranty of
     10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11# GNU General Public License for more details.
     12#
     13# You should have received a copy of the GNU General Public License
     14# along with this program; if not, write to the Free Software
     15# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     16
     17import gobject
     18
     19from sugar.graphics.xocolor import XoColor
     20from sugar.presence import presenceservice
     21from sugar import activity
     22
     23from model.BuddyModel import BuddyModel
     24
     25class ActivityModel:
     26    def __init__(self, act, bundle):
     27        self.activity = act
     28        self.bundle = bundle
     29
     30    def get_id(self):
     31        return self.activity.props.id
     32       
     33    def get_icon_name(self):
     34        return self.bundle.icon
     35   
     36    def get_color(self):
     37        return XoColor(self.activity.props.color)
     38
     39    def get_bundle_id(self):
     40        return self.bundle.bundle_id
     41
     42class Neighborhood(gobject.GObject):
     43    __gsignals__ = {
     44        'activity-added':       (gobject.SIGNAL_RUN_FIRST,
     45                                 gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
     46        'activity-removed':     (gobject.SIGNAL_RUN_FIRST,
     47                                 gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
     48        'buddy-added':          (gobject.SIGNAL_RUN_FIRST,
     49                                 gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])),
     50        'buddy-moved':          (gobject.SIGNAL_RUN_FIRST,
     51                                 gobject.TYPE_NONE,
     52                                ([gobject.TYPE_PYOBJECT,
     53                                  gobject.TYPE_PYOBJECT])),
     54        'buddy-removed':        (gobject.SIGNAL_RUN_FIRST,
     55                                 gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT]))
     56    }
     57
     58    def __init__(self):
     59        gobject.GObject.__init__(self)
     60
     61        self._activities = {}
     62        self._buddies = {}
     63
     64        self._pservice = presenceservice.get_instance()
     65        self._pservice.connect("activity-appeared",
     66                               self._activity_appeared_cb)
     67        self._pservice.connect('activity-disappeared',
     68                               self._activity_disappeared_cb)
     69        self._pservice.connect("buddy-appeared",
     70                               self._buddy_appeared_cb)
     71        self._pservice.connect("buddy-disappeared",
     72                               self._buddy_disappeared_cb)
     73
     74        # Add any buddies the PS knows about already
     75        self._pservice.get_buddies_async(reply_handler=self._get_buddies_cb)
     76
     77        self._pservice.get_activities_async(
     78                reply_handler=self._get_activities_cb)
     79
     80    def _get_buddies_cb(self, buddy_list):
     81        for buddy in buddy_list:
     82            self._buddy_appeared_cb(self._pservice, buddy)
     83
     84    def _get_activities_cb(self, activity_list):
     85        for act in activity_list:
     86            self._check_activity(act)
     87
     88    def get_activities(self):
     89        return self._activities.values()
     90
     91    def get_buddies(self):
     92        return self._buddies.values()
     93
     94    def _buddy_activity_changed_cb(self, model, cur_activity):
     95        if not self._buddies.has_key(model.get_key()):
     96            return
     97        if cur_activity and self._activities.has_key(cur_activity.props.id):
     98            activity_model = self._activities[cur_activity.props.id]
     99            self.emit('buddy-moved', model, activity_model)
     100        else:
     101            self.emit('buddy-moved', model, None)
     102
     103    def _buddy_appeared_cb(self, pservice, buddy):
     104        if self._buddies.has_key(buddy.props.key):
     105            return
     106
     107        model = BuddyModel(buddy=buddy)
     108        model.connect('current-activity-changed',
     109                      self._buddy_activity_changed_cb)
     110        self._buddies[buddy.props.key] = model
     111        self.emit('buddy-added', model)
     112
     113        cur_activity = buddy.props.current_activity
     114        if cur_activity:
     115            self._buddy_activity_changed_cb(model, cur_activity)
     116
     117    def _buddy_disappeared_cb(self, pservice, buddy):
     118        if not self._buddies.has_key(buddy.props.key):
     119            return
     120        self.emit('buddy-removed', self._buddies[buddy.props.key])
     121        del self._buddies[buddy.props.key]
     122
     123    def _activity_appeared_cb(self, pservice, act):
     124        self._check_activity(act)
     125
     126    def _check_activity(self, presence_activity):
     127        registry = activity.get_registry()
     128        bundle = registry.get_activity(presence_activity.props.type)
     129        if not bundle:
     130            return
     131        if self.has_activity(presence_activity.props.id):
     132            return
     133        self.add_activity(bundle, presence_activity)
     134
     135    def has_activity(self, activity_id):
     136        return self._activities.has_key(activity_id)
     137
     138    def get_activity(self, activity_id):
     139        if self.has_activity(activity_id):
     140            return self._activities[activity_id]
     141        else:
     142            return None
     143
     144    def add_activity(self, bundle, act):
     145        model = ActivityModel(act, bundle)
     146        self._activities[model.get_id()] = model
     147        self.emit('activity-added', model)
     148
     149        for buddy in self._pservice.get_buddies():
     150            cur_activity = buddy.props.current_activity
     151            key = buddy.props.key
     152            if cur_activity == activity and self._buddies.has_key(key):
     153                buddy_model = self._buddies[key]
     154                self.emit('buddy-moved', buddy_model, model)
     155
     156    def _activity_disappeared_cb(self, pservice, act):
     157        if self._activities.has_key(act.props.id):
     158            activity_model = self._activities[act.props.id]
     159            self.emit('activity-removed', activity_model)
     160            del self._activities[act.props.id]
     161
     162_model = None
     163
     164def get_model():
     165    global _model
     166    if _model is None:
     167        _model = Neighborhood()
     168    return _model
  • new file src/model/network.py

    diff --git a/src/model/network.py b/src/model/network.py
    new file mode 100644
    index 0000000..d793deb
    - +  
     1# Copyright (C) 2008 Red Hat, Inc.
     2#
     3# This program is free software; you can redistribute it and/or modify
     4# it under the terms of the GNU General Public License as published by
     5# the Free Software Foundation; either version 2 of the License, or
     6# (at your option) any later version.
     7#
     8# This program is distributed in the hope that it will be useful,
     9# but WITHOUT ANY WARRANTY; without even the implied warranty of
     10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11# GNU General Public License for more details.
     12#
     13# You should have received a copy of the GNU General Public License
     14# along with this program; if not, write to the Free Software
     15# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     16
     17import logging
     18import os
     19
     20import dbus
     21import ConfigParser
     22
     23from sugar import dispatch
     24from sugar import env
     25
     26DEVICE_TYPE_802_11_WIRELESS = 2
     27
     28DEVICE_STATE_UNKNOWN = 0
     29DEVICE_STATE_UNMANAGED = 1
     30DEVICE_STATE_UNAVAILABLE = 2
     31DEVICE_STATE_DISCONNECTED = 3
     32DEVICE_STATE_PREPARE = 4
     33DEVICE_STATE_CONFIG = 5
     34DEVICE_STATE_NEED_AUTH = 6
     35DEVICE_STATE_IP_CONFIG = 7
     36DEVICE_STATE_ACTIVATED = 8
     37DEVICE_STATE_FAILED = 9
     38
     39NM_802_11_AP_FLAGS_NONE = 0x00000000
     40NM_802_11_AP_FLAGS_PRIVACY = 0x00000001
     41
     42NM_802_11_AP_SEC_NONE = 0x00000000
     43NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001
     44NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002
     45NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004
     46NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008
     47NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010
     48NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020
     49NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040
     50NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080
     51NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100
     52NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200
     53
     54NM_802_11_MODE_UNKNOWN = 0
     55NM_802_11_MODE_ADHOC = 1
     56NM_802_11_MODE_INFRA = 2
     57
     58NM_802_11_DEVICE_CAP_NONE = 0x00000000
     59NM_802_11_DEVICE_CAP_CIPHER_WEP40 = 0x00000001
     60NM_802_11_DEVICE_CAP_CIPHER_WEP104 = 0x00000002
     61NM_802_11_DEVICE_CAP_CIPHER_TKIP = 0x00000004
     62NM_802_11_DEVICE_CAP_CIPHER_CCMP = 0x00000008
     63NM_802_11_DEVICE_CAP_WPA = 0x00000010
     64NM_802_11_DEVICE_CAP_RSN = 0x00000020
     65
     66SETTINGS_SERVICE = 'org.freedesktop.NetworkManagerUserSettings'
     67
     68NM_SETTINGS_PATH = '/org/freedesktop/NetworkManagerSettings'
     69NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManagerSettings'
     70NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection'
     71NM_SECRETS_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection.Secrets'
     72
     73_nm_settings = None
     74_conn_counter = 0
     75
     76class WirelessSecurity(object):
     77    def __init__(self):
     78        self.key_mgmt = None
     79        self.proto = None
     80        self.group = None
     81        self.pairwise = None
     82
     83    def get_dict(self):
     84        wireless_security = {}
     85
     86        if self.key_mgmt is not None:
     87            wireless_security['key-mgmt'] = self.key_mgmt
     88        if self.proto is not None:
     89            wireless_security['proto'] = self.proto
     90        if self.pairwise is not None:
     91            wireless_security['pairwise'] = self.pairwise
     92        if self.group is not None:
     93            wireless_security['group'] = self.group
     94
     95        return wireless_security
     96
     97class Wireless(object):
     98    def __init__(self):
     99        self.ssid = None
     100
     101    def get_dict(self):
     102        return {'ssid': self.ssid}
     103
     104class Connection(object):
     105    def __init__(self):
     106        self.id = None
     107        self.uuid = None
     108        self.type = None
     109
     110    def get_dict(self):
     111        return {'id': self.id,
     112                'uuid': self.uuid,
     113                'type': self.type}
     114
     115class Settings(object):
     116    def __init__(self):
     117        self.connection = Connection()
     118        self.wireless = Wireless()
     119        self.wireless_security = None
     120
     121    def get_dict(self):
     122        settings = {}
     123        settings['connection'] = self.connection.get_dict()
     124        settings['802-11-wireless'] = self.wireless.get_dict()
     125        if self.wireless_security is not None:
     126            settings['802-11-wireless-security'] = \
     127                self.wireless_security.get_dict()
     128        return settings
     129
     130class Secrets(object):
     131    def __init__(self):
     132        self.wep_key = None
     133        self.psk = None
     134        self.auth_alg = None
     135
     136    def get_dict(self):
     137        secrets = {}
     138
     139        if self.wep_key is not None:
     140            secrets['wep-key0'] = self.wep_key
     141        if self.psk is not None:
     142            secrets['psk'] = self.psk
     143        if self.auth_alg is not None:
     144            secrets['auth-alg'] = self.auth_alg
     145
     146        return {'802-11-wireless-security': secrets}
     147
     148class NMSettings(dbus.service.Object):
     149    def __init__(self):
     150        bus = dbus.SystemBus()
     151        bus_name = dbus.service.BusName(SETTINGS_SERVICE, bus=bus)
     152        dbus.service.Object.__init__(self, bus_name, NM_SETTINGS_PATH)
     153
     154        self.connections = {}
     155        self.secrets_request = dispatch.Signal()
     156
     157    @dbus.service.method(dbus_interface=NM_SETTINGS_IFACE,
     158                         in_signature='', out_signature='ao')
     159    def ListConnections(self):
     160        return self.connections.values()
     161
     162    @dbus.service.signal(NM_SETTINGS_IFACE, signature='o')
     163    def NewConnection(self, connection_path):
     164        pass
     165
     166    def add_connection(self, ssid, conn):
     167        self.connections[ssid] = conn
     168        conn.secrets_request.connect(self.__secrets_request_cb)
     169        self.NewConnection(conn.path)
     170
     171    def __secrets_request_cb(self, sender, **kwargs):
     172        self.secrets_request.send(self, connection=sender,
     173                                  response=kwargs['response'])
     174
     175class SecretsResponse(object):
     176    ''' Intermediate object to report the secrets from the dialog
     177    back to the connection object and which will inform NM
     178    '''
     179    def __init__(self, connection, reply_cb, error_cb):
     180        self._connection = connection
     181        self._reply_cb = reply_cb
     182        self._error_cb = error_cb
     183
     184    def set_secrets(self, secrets):
     185        self._connection.set_secrets(secrets)
     186        self._reply_cb(secrets.get_dict())
     187
     188    def set_error(self, error):
     189        self._error_cb(error)
     190
     191class NMSettingsConnection(dbus.service.Object):
     192    def __init__(self, path, settings, secrets):
     193        bus = dbus.SystemBus()
     194        bus_name = dbus.service.BusName(SETTINGS_SERVICE, bus=bus)
     195        dbus.service.Object.__init__(self, bus_name, path)
     196
     197        self.path = path
     198        self.secrets_request = dispatch.Signal()
     199
     200        self._settings = settings
     201        self._secrets = secrets
     202
     203    def set_secrets(self, secrets):
     204        self._secrets = secrets
     205        self.save()
     206
     207    def save(self):
     208        profile_path = env.get_profile_path()
     209        config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
     210
     211        config = ConfigParser.ConfigParser()
     212        try:
     213            try:
     214                if not config.read(config_path):
     215                    logging.error('Error reading the nm config file')
     216                    return
     217            except ConfigParser.ParsingError, e:
     218                logging.error('Error reading the nm config file: %s' % e)
     219                return
     220            identifier = self._settings.connection.id
     221
     222            if identifier not in config.sections():
     223                config.add_section(identifier)
     224            config.set(identifier, 'type', self._settings.connection.type)
     225            config.set(identifier, 'ssid', self._settings.wireless.ssid)
     226            config.set(identifier, 'uuid', self._settings.connection.uuid)
     227
     228            if self._settings.wireless_security is not None:
     229                if self._settings.wireless_security.key_mgmt is not None:
     230                    config.set(identifier, 'key-mgmt',
     231                               self._settings.wireless_security.key_mgmt)
     232                if self._settings.wireless_security.proto is not None:
     233                    config.set(identifier, 'proto',
     234                               self._settings.wireless_security.proto)
     235                if self._settings.wireless_security.pairwise is not None:
     236                    config.set(identifier, 'pairwise',
     237                               self._settings.wireless_security.pairwise)
     238                if self._settings.wireless_security.group is not None:
     239                    config.set(identifier, 'group',
     240                               self._settings.wireless_security.group)
     241            if self._secrets is not None:
     242                if self._settings.wireless_security.key_mgmt == 'none':
     243                    config.set(identifier, 'key', self._secrets.wep_key)
     244                    config.set(identifier, 'auth-alg', self._secrets.auth_alg)
     245                elif self._settings.wireless_security.key_mgmt == 'wpa-psk':
     246                    config.set(identifier, 'key', self._secrets.psk)
     247        except ConfigParser.Error, e:
     248            logging.error('Error constructing %s: %s' % (identifier, e))
     249        else:
     250            f = open(config_path, 'w')
     251            try:
     252                config.write(f)
     253            except ConfigParser.Error, e:
     254                logging.error('Can not write %s error: %s' % (config_path, e))
     255            f.close()
     256
     257    @dbus.service.method(dbus_interface=NM_CONNECTION_IFACE,
     258                         in_signature='', out_signature='a{sa{sv}}')
     259    def GetSettings(self):
     260        return self._settings.get_dict()
     261
     262    @dbus.service.method(dbus_interface=NM_SECRETS_IFACE,
     263                         async_callbacks=('reply', 'error'),
     264                         in_signature='sasb', out_signature='a{sa{sv}}')
     265    def GetSecrets(self, setting_name, hints, request_new, reply, error):
     266        logging.debug('Secrets requested for connection %s request_new=%s'
     267                      % (self.path, request_new))
     268
     269        if request_new or self._secrets is None:
     270            # request_new is for example the case when the pw on the AP changes
     271            response = SecretsResponse(self, reply, error)
     272            try:
     273                self.secrets_request.send(self, response=response)
     274            except Exception, e:
     275                logging.error('Error requesting the secrets via dialog: %s' % e)
     276        else:
     277            reply(self._secrets.get_dict())
     278
     279def get_settings():
     280    global _nm_settings
     281    if _nm_settings is None:
     282        try:
     283            _nm_settings = NMSettings()
     284        except dbus.DBusException, e:
     285            logging.error('Cannot create the UserSettings service %s.', e)
     286        load_connections()
     287    return _nm_settings
     288
     289def find_connection(ssid):
     290    connections = get_settings().connections
     291    if ssid in connections:
     292        return connections[ssid]
     293    else:
     294        return None
     295
     296def add_connection(ssid, settings, secrets=None):
     297    global _conn_counter
     298
     299    path = NM_SETTINGS_PATH + '/' + str(_conn_counter)
     300    _conn_counter += 1
     301
     302    conn = NMSettingsConnection(path, settings, secrets)
     303    _nm_settings.add_connection(ssid, conn)
     304    return conn
     305
     306def load_connections():
     307    profile_path = env.get_profile_path()
     308    config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
     309
     310    config = ConfigParser.ConfigParser()
     311
     312    if not os.path.exists(config_path):
     313        if not os.path.exists(os.path.dirname(config_path)):
     314            os.makedirs(os.path.dirname(config_path), 0755)
     315        f = open(config_path, 'w')
     316        config.write(f)
     317        f.close()
     318
     319    try:
     320        if not config.read(config_path):
     321            logging.error('Error reading the nm config file')
     322            return
     323    except ConfigParser.ParsingError, e:
     324        logging.error('Error reading the nm config file: %s' % e)
     325        return
     326
     327    for section in config.sections():
     328        try:
     329            settings = Settings()
     330            settings.connection.id = section
     331            ssid = config.get(section, 'ssid')
     332            settings.wireless.ssid = dbus.ByteArray(ssid)
     333            uuid = config.get(section, 'uuid')
     334            settings.connection.uuid = uuid
     335            nmtype = config.get(section, 'type')
     336            settings.connection.type = nmtype
     337
     338            secrets = None
     339            if config.has_option(section, 'key-mgmt'):
     340                secrets = Secrets()
     341                settings.wireless_security = WirelessSecurity()
     342                mgmt = config.get(section, 'key-mgmt')
     343                settings.wireless_security.key_mgmt = mgmt
     344                key = config.get(section, 'key')
     345                if mgmt == 'none':
     346                    secrets.wep_key = key
     347                    auth_alg = config.get(section, 'auth-alg')
     348                    secrets.auth_alg = auth_alg
     349                elif mgmt == 'wpa-psk':
     350                    secrets.psk = key
     351                    if config.has_option(section, 'proto'):
     352                        value = config.get(section, 'proto')
     353                        settings.wireless_security.proto = value
     354                    if config.has_option(section, 'group'):
     355                        value = config.get(section, 'group')
     356                        settings.wireless_security.group = value
     357                    if config.has_option(section, 'pairwise'):
     358                        value = config.get(section, 'pairwise')
     359                        settings.wireless_security.pairwise = value
     360        except ConfigParser.Error, e:
     361            logging.error('Error reading section: %s' % e)
     362        else:
     363            add_connection(ssid, settings, secrets)
  • src/model/shellmodel.py

    diff --git a/src/model/shellmodel.py b/src/model/shellmodel.py
    index d1d8db8..7e786be 100644
    a b import gobject 
    1919
    2020from sugar.presence import presenceservice
    2121from model.Friends import Friends
    22 from model.MeshModel import MeshModel
    2322from model.homemodel import HomeModel
    2423from model.Owner import ShellOwner
    2524from model.devices.devicesmodel import DevicesModel
    class ShellModel(gobject.GObject): 
    4847        self._owner = ShellOwner()
    4948
    5049        self._friends = Friends()
    51         self._mesh = MeshModel()
    5250        self._home = HomeModel()
    5351        self._devices = DevicesModel()
    5452
    class ShellModel(gobject.GObject): 
    7068        if pspec.name == 'zoom-level':
    7169            return self.get_zoom_level()               
    7270
    73     def get_mesh(self):
    74         return self._mesh
    75 
    7671    def get_friends(self):
    7772        return self._friends
    7873
  • src/view/devices/network/wireless.py

    diff --git a/src/view/devices/network/wireless.py b/src/view/devices/network/wireless.py
    index 5bef0bb..a9cf22b 100644
    a b  
    1616# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1717
    1818from gettext import gettext as _
     19import logging
     20import sha
    1921
    2022import gtk
     23import dbus
    2124
    2225from sugar.graphics.icon import get_icon_state
    2326from sugar.graphics import style
    2427from sugar.graphics.palette import Palette
    2528from sugar.graphics.toolbutton import ToolButton
    26 from sugar.graphics.xocolor import XoColor
     29from sugar.graphics import xocolor
    2730
    28 from model.devices.network import wireless
    29 from model.devices import device
    30 from hardware import hardwaremanager
    31 from hardware import nmclient
     31from model import network
    3232from view.frame.frameinvoker import FrameWidgetInvoker
    3333from view.pulsingicon import PulsingIcon
    3434
    _ICON_NAME = 'network-wireless' 
    3636
    3737IP_ADDRESS_TEXT_TEMPLATE = _("IP address: %s")
    3838
    39 class DeviceView(ToolButton):
    40 
    41     FRAME_POSITION_RELATIVE = 300
    42 
    43     def __init__(self, model):
    44         ToolButton.__init__(self)
    45         self._model = model
    46 
    47         self._icon = PulsingIcon()
    48         self._icon.props.icon_name = _ICON_NAME
    49         pulse_color = XoColor("%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
    50                                          style.COLOR_TRANSPARENT.get_svg()))
    51         self._icon.props.pulse_color = pulse_color
    52         self._icon.props.base_color = pulse_color   # only temporarily
    53         self._inactive_color = XoColor("%s,%s" % (
    54                 style.COLOR_INACTIVE_STROKE.get_html(),
    55                 style.COLOR_INACTIVE_FILL.get_html()))
    56 
    57         meshdev = None
    58         network_manager = hardwaremanager.get_network_manager()
    59         for dev in network_manager.get_devices():
    60             if dev.get_type() == nmclient.DEVICE_TYPE_802_11_MESH_OLPC:
    61                 meshdev = dev
    62                 break
    63 
    64         self._counter = 0
    65         self.palette = WirelessPalette(self._get_palette_primary_text(),
    66                                        meshdev)
    67         self.set_palette(self.palette)
    68         self.palette.props.invoker = FrameWidgetInvoker(self)
    69         self.palette.set_group_id('frame')
    70         self.palette.set_frequency(self._model.props.frequency)
    71 
    72         model.connect('notify::name', self._name_changed_cb)
    73         model.connect('notify::ip-address', self._ip_address_changed_cb)
    74         model.connect('notify::strength', self._strength_changed_cb)
    75         model.connect('notify::state', self._state_changed_cb)
    76 
    77         self._update_icon()
    78         self._update_state()
    79         self._update_ip_address()
    80 
    81         self.set_icon_widget(self._icon)
    82         self._icon.show()
    83 
    84     def _get_palette_primary_text(self):
    85         if self._model.props.state == device.STATE_INACTIVE:
    86             return _("Disconnected")
    87         return self._model.props.name
    88 
    89     def _strength_changed_cb(self, model, pspec):
    90         self._update_icon()
    91         # Only update frequency periodically
    92         if self._counter % 4 == 0:
    93             self.palette.set_frequency(self._model.props.frequency)
    94         self._counter += 1
    95 
    96     def _ip_address_changed_cb(self, model, pspec):
    97         self._update_ip_address()
    98 
    99     def _name_changed_cb(self, model, pspec):
    100         self.palette.set_primary_text(self._get_palette_primary_text())
    101         self._update_state()
    102 
    103     def _state_changed_cb(self, model, pspec):
    104         self._update_icon()
    105         self._update_state()
    106         self.palette.set_primary_text(self._get_palette_primary_text())
    107 
    108     def _update_icon(self):
    109         # keep this code in sync with view/home/MeshBox.py
    110         strength = self._model.props.strength
    111         if self._model.props.state == device.STATE_INACTIVE:
    112             strength = 0
    113         if self._model.props.state == device.STATE_ACTIVATED:
    114             icon_name = '%s-connected' % _ICON_NAME
    115         else:
    116             icon_name = _ICON_NAME
    117         icon_name = get_icon_state(icon_name, strength)
    118         if icon_name:
    119             self._icon.props.icon_name = icon_name
    120 
    121     def _update_state(self):
    122         # FIXME Change icon colors once we have real icons
    123         state = self._model.props.state
    124         self._icon.props.pulsing = state == device.STATE_ACTIVATING
    125         if state == device.STATE_ACTIVATING:
    126             fill = style.COLOR_INACTIVE_FILL.get_svg()
    127             stroke = style.COLOR_INACTIVE_STROKE.get_svg()
    128         elif state == device.STATE_ACTIVATED:
    129             (stroke, fill) = self._model.get_active_network_colors()
    130         elif state == device.STATE_INACTIVE:
    131             fill = style.COLOR_INACTIVE_FILL.get_svg()
    132             stroke = style.COLOR_INACTIVE_STROKE.get_svg()
    133         self._icon.props.base_color = XoColor("%s,%s" % (stroke, fill))
    134 
    135     def _update_ip_address(self):
    136         self.palette.set_ip_address(self._model.props.ip_address)
     39_NM_SERVICE = 'org.freedesktop.NetworkManager'
     40_NM_IFACE = 'org.freedesktop.NetworkManager'
     41_NM_PATH = '/org/freedesktop/NetworkManager'
     42_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
     43_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
     44_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
     45_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
     46
     47_NM_DEVICE_STATE_UNKNOWN = 0
     48_NM_DEVICE_STATE_UNMANAGED = 1
     49_NM_DEVICE_STATE_UNAVAILABLE = 2
     50_NM_DEVICE_STATE_DISCONNECTED = 3
     51_NM_DEVICE_STATE_PREPARE = 4
     52_NM_DEVICE_STATE_CONFIG = 5
     53_NM_DEVICE_STATE_NEED_AUTH = 6
     54_NM_DEVICE_STATE_IP_CONFIG = 7
     55_NM_DEVICE_STATE_ACTIVATED = 8
     56_NM_DEVICE_STATE_FAILED = 9
     57
     58def freq_to_channel(freq):
     59    ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4,
     60             2432: 5, 2437: 6, 2442: 7, 2447: 8,
     61             2452: 9, 2457: 10, 2462: 11, 2467: 12,
     62             2472: 13}
     63    return ftoc[freq]
    13764
    13865class WirelessPalette(Palette):
    139     def __init__(self, primary_text, meshdev):
    140         Palette.__init__(self, primary_text, menu_after_content=True)
    141         self._meshdev = meshdev
     66    def __init__(self, primary_text, device_view):
     67        Palette.__init__(self, label=primary_text)
     68
     69        self._device_view = device_view
     70        self._disconnect_item = None
    14271
    14372        self._chan_label = gtk.Label()
    14473        self._chan_label.props.xalign = 0.0
    class WirelessPalette(Palette): 
    14675
    14776        self._ip_address_label = gtk.Label()
    14877
    149         vbox = gtk.VBox()
     78        self._info = gtk.VBox()
    15079
    15180        def _padded(child, xalign=0, yalign=0.5):
    15281            padder = gtk.Alignment(xalign=xalign, yalign=yalign,
    class WirelessPalette(Palette): 
    15887            padder.add(child)
    15988            return padder
    16089
    161         vbox.pack_start(_padded(self._chan_label))
    162         vbox.pack_start(_padded(self._ip_address_label))
    163         vbox.show_all()
     90        self._info.pack_start(_padded(self._chan_label))
     91        self._info.pack_start(_padded(self._ip_address_label))
     92        self._info.show_all()
     93
     94        self._disconnect_item = gtk.MenuItem(_('Disconnect...'))
     95        self._disconnect_item.connect('activate', self._disconnect_activate_cb)
     96        self.menu.append(self._disconnect_item)
     97
     98        self.disconnected()
    16499
    165         if meshdev:
    166             disconnect_item = gtk.MenuItem(_('Disconnect...'))
    167             disconnect_item.connect('activate', self._disconnect_activate_cb)
    168             self.menu.append(disconnect_item)
    169             disconnect_item.show()
     100    def connecting(self):
     101        self.props.secondary_text = _('Connecting...')
    170102
    171         self.set_content(vbox)
     103    def connected(self, frequency, iaddress):
     104        self.set_content(self._info)
     105        self.props.secondary_text = _('Connected')
     106        self._set_channel(frequency)
     107        self._set_ip_address(iaddress)
     108        self._disconnect_item.show()
     109
     110    def disconnected(self):
     111        self.props.primary_text = ''
     112        self.props.secondary_text = _('Not connected')
     113        self.set_content(None)
     114        self._disconnect_item.hide()
    172115
    173116    def _disconnect_activate_cb(self, menuitem):
    174         # Disconnection for an AP means activating the default mesh device
    175         network_manager = hardwaremanager.get_network_manager()
    176         if network_manager and self._meshdev:
    177             network_manager.set_active_device(self._meshdev)
     117        self._device_view.deactivate_connection()
     118
     119    def _inet_ntoa(self, iaddress):
     120        address = ['%s' % ((iaddress >> i) % 256) for i in [0, 8, 16, 24]]
     121        return ".".join(address)
    178122
    179     def set_frequency(self, freq):
     123    def _set_channel(self, freq):
    180124        try:
    181             chan = wireless.freq_to_channel(freq)
     125            chan = freq_to_channel(freq)
    182126        except KeyError:
    183127            chan = 0
    184128        self._chan_label.set_text("%s: %d" % (_("Channel"), chan))
    185129
    186     def set_ip_address(self, ip_address):
    187         if ip_address is not None and ip_address != "0.0.0.0":
    188             ip_address_text = IP_ADDRESS_TEXT_TEMPLATE % ip_address
     130    def _set_ip_address(self, ip_address):
     131        if ip_address is not None:
     132            ip_address_text = IP_ADDRESS_TEXT_TEMPLATE % \
     133                self._inet_ntoa(ip_address)
    189134        else:
    190135            ip_address_text = ""
    191136        self._ip_address_label.set_text(ip_address_text)
     137
     138
     139class DeviceView(ToolButton):
     140
     141    FRAME_POSITION_RELATIVE = 300
     142
     143    def __init__(self, device):
     144        ToolButton.__init__(self)
     145
     146        self._bus = dbus.SystemBus()
     147        self._device = device.nm_device
     148        self._flags = 0
     149        self._name = ''
     150        self._strength = 0
     151        self._frequency = 0
     152        self._device_state = None
     153        self._color = None
     154        self._active_ap_op = None
     155
     156        self._icon = PulsingIcon()
     157        self._icon.props.icon_name = get_icon_state(_ICON_NAME, 0)
     158        self._inactive_color = xocolor.XoColor( \
     159            "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
     160                       style.COLOR_TRANSPARENT.get_svg()))
     161        self._icon.props.pulse_color = self._inactive_color
     162        self._icon.props.base_color = self._inactive_color
     163
     164        self.set_icon_widget(self._icon)
     165        self._icon.show()
     166
     167        self._palette = WirelessPalette(self._name, self)
     168        self.set_palette(self._palette)
     169        self._palette.props.invoker = FrameWidgetInvoker(self)
     170        self._palette.set_group_id('frame')
     171
     172        self._device.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
     173                         reply_handler=self.__get_active_ap_reply_cb,
     174                         error_handler=self.__get_active_ap_error_cb)
     175
     176        self._bus.add_signal_receiver(self.__state_changed_cb,
     177                                      signal_name='StateChanged',
     178                                      path=self._device.object_path,
     179                                      dbus_interface=_NM_DEVICE_IFACE)
     180
     181    def disconnect(self):
     182        self._bus.remove_signal_receiver(self.__state_changed_cb,
     183                                         signal_name='StateChanged',
     184                                         path=self._device.object_path,
     185                                         dbus_interface=_NM_DEVICE_IFACE)
     186
     187    def __get_active_ap_reply_cb(self, active_ap_op):
     188        if self._active_ap_op != active_ap_op:
     189            if self._active_ap_op is not None:
     190                self._bus.remove_signal_receiver(
     191                    self.__ap_properties_changed_cb,
     192                    signal_name='PropertiesChanged',
     193                    path=self._active_ap_op,
     194                    dbus_interface=_NM_ACCESSPOINT_IFACE)
     195            if active_ap_op == '/':
     196                self._active_ap_op = None
     197                return
     198            self._active_ap_op = active_ap_op
     199            active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op)
     200            props = dbus.Interface(active_ap, 'org.freedesktop.DBus.Properties')
     201
     202            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
     203                         reply_handler=self.__get_all_props_reply_cb,
     204                         error_handler=self.__get_all_props_error_cb)
     205
     206            self._bus.add_signal_receiver(self.__ap_properties_changed_cb,
     207                                          signal_name='PropertiesChanged',
     208                                          path=self._active_ap_op,
     209                                          dbus_interface=_NM_ACCESSPOINT_IFACE)
     210
     211    def __get_active_ap_error_cb(self, err):
     212        logging.debug('Error getting the active access point: %s', err)
     213
     214    def __state_changed_cb(self, new_state, old_state, reason):
     215        self._device_state = new_state
     216        self._update_state()
     217
     218        self._device.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
     219                         reply_handler=self.__get_active_ap_reply_cb,
     220                         error_handler=self.__get_active_ap_error_cb)
     221
     222    def __ap_properties_changed_cb(self, properties):
     223        self._update_properties(properties)
     224
     225    def _update_properties(self, properties):
     226        if 'Ssid' in properties:
     227            self._name = properties['Ssid']
     228        if 'Strength' in properties:
     229            self._strength = properties['Strength']
     230        if 'Flags' in properties:
     231            self._flags = properties['Flags']
     232        if 'Frequency' in properties:
     233            self._frequency = properties['Frequency']
     234
     235        sh = sha.new()
     236        data = self._name + hex(self._flags)
     237        sh.update(data)
     238        h = hash(sh.digest())
     239        idx = h % len(xocolor.colors)
     240
     241        self._color = xocolor.XoColor('%s,%s' % (xocolor.colors[idx][0],
     242                                                 xocolor.colors[idx][1]))
     243        self._update()
     244
     245    def __get_all_props_reply_cb(self, properties):
     246        self._update_properties(properties)
     247
     248    def __get_all_props_error_cb(self, err):
     249        logging.debug('Error getting the access point properties: %s', err)
     250
     251    def _update(self):
     252        if self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
     253            self._icon.props.badge_name = "emblem-locked"
     254        else:
     255            self._icon.props.badge_name = None
     256
     257        self._palette.props.primary_text = self._name
     258
     259        self._update_state()
     260        self._update_color()
     261
     262    def _update_state(self):
     263        if self._active_ap_op is not None:
     264            state = self._device_state
     265        else:
     266            state = network.DEVICE_STATE_UNKNOWN
     267
     268        if state == network.DEVICE_STATE_ACTIVATED:
     269            icon_name = '%s-connected' % _ICON_NAME
     270        else:
     271            icon_name = _ICON_NAME
     272
     273        icon_name = get_icon_state(icon_name, self._strength)
     274        if icon_name:
     275            self._icon.props.icon_name = icon_name
     276
     277        if state == network.DEVICE_STATE_PREPARE or \
     278           state == network.DEVICE_STATE_CONFIG or \
     279           state == network.DEVICE_STATE_NEED_AUTH or \
     280           state == network.DEVICE_STATE_IP_CONFIG:
     281            self._palette.connecting()
     282            self._icon.props.pulsing = True
     283        elif state == network.DEVICE_STATE_ACTIVATED:
     284            props = dbus.Interface(self._device,
     285                                   'org.freedesktop.DBus.Properties')
     286            address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
     287            self._palette.connected(self._frequency, address)
     288            self._icon.props.pulsing = False
     289        else:
     290            self._palette.disconnected()
     291            self._icon.props.pulsing = False
     292            self._icon.props.base_color = self._inactive_color
     293            self._icon.props.badge_name = None
     294            self._name = ''
     295
     296    def _update_color(self):
     297        self._icon.props.base_color = self._color
     298
     299    def deactivate_connection(self):
     300        if self._active_ap_op is not None:
     301            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     302            netmgr = dbus.Interface(obj, _NM_IFACE)
     303            netmgr_props = dbus.Interface(
     304                netmgr, 'org.freedesktop.DBus.Properties')
     305            active_connections_o = netmgr_props.Get(_NM_IFACE,
     306                                                    'ActiveConnections')
     307
     308            for conn_o in active_connections_o:
     309                obj = self._bus.get_object(_NM_IFACE, conn_o)
     310                props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     311                ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
     312                if ap_op == self._active_ap_op:
     313                    netmgr.DeactivateConnection(conn_o)
     314                    break
  • src/view/home/Makefile.am

    diff --git a/src/view/home/Makefile.am b/src/view/home/Makefile.am
    index b323589..9e4a754 100644
    a b sugar_PYTHON = \ 
    77        grid.py                 \
    88        FriendView.py           \
    99        FriendsBox.py           \
     10        keydialog.py            \
    1011        HomeBox.py              \
    1112        HomeWindow.py           \
    1213        MeshBox.py              \
  • src/view/home/MeshBox.py

    diff --git a/src/view/home/MeshBox.py b/src/view/home/MeshBox.py
    index 8cf8af6..568e1b9 100644
    a b  
    1616
    1717from gettext import gettext as _
    1818import logging
     19import sha
    1920
     21import dbus
    2022import hippo
    2123import gobject
    2224import gtk
    2325
    2426from sugar.graphics.icon import CanvasIcon, Icon
    2527from sugar.graphics.xocolor import XoColor
     28from sugar.graphics import xocolor
    2629from sugar.graphics import style
    2730from sugar.graphics.icon import get_icon_state
    2831from sugar.graphics import palette
    2932from sugar.graphics import iconentry
    3033from sugar.graphics.menuitem import MenuItem
    31 from sugar import profile
     34from sugar.util import unique_id
    3235
    33 from model import accesspointmodel
    34 from model.devices.network import wireless
    35 from model import shellmodel
    36 from hardware import hardwaremanager
    37 from hardware import nmclient
     36from model import neighborhood
    3837from view.BuddyIcon import BuddyIcon
    3938from view.pulsingicon import CanvasPulsingIcon
    4039from view.home.snowflakelayout import SnowflakeLayout
    4140from view.home.spreadlayout import SpreadLayout
     41from view.home import keydialog
     42from model import network
     43from model.network import Settings
     44from model.network import WirelessSecurity
    4245import view.Shell
    4346
    44 from hardware.nmclient import NM_802_11_CAP_PROTO_WEP, \
    45     NM_802_11_CAP_PROTO_WPA, NM_802_11_CAP_PROTO_WPA2
    46 
     47_NM_SERVICE = 'org.freedesktop.NetworkManager'
     48_NM_IFACE = 'org.freedesktop.NetworkManager'
     49_NM_PATH = '/org/freedesktop/NetworkManager'
     50_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
     51_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
     52_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
     53_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
    4754
    4855_ICON_NAME = 'network-wireless'
    4956
    5057class AccessPointView(CanvasPulsingIcon):
    51     def __init__(self, model, mesh_device=None):
     58    def __init__(self, device, model):
    5259        CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE,
    5360                                   cache=True)
     61        self._bus = dbus.SystemBus()
     62        self._device = device
    5463        self._model = model
    55         self._meshdev = mesh_device
     64        self._palette_icon = None
    5665        self._disconnect_item = None
    5766        self._connect_item = None
    5867        self._greyed_out = False
     68        self._name = ''
     69        self._strength = 0
     70        self._flags = 0
     71        self._wpa_flags = 0
     72        self._rsn_flags = 0
     73        self._mode = 0
     74        self._device_caps = 0
     75        self._device_state = None
     76        self._connection = None
     77        self._active = True
     78        self._color = None
    5979
    6080        self.connect('activated', self._activate_cb)
    6181
    62         model.connect('notify::strength', self._strength_changed_cb)
    63         model.connect('notify::name', self._name_changed_cb)
    64         model.connect('notify::state', self._state_changed_cb)
    65 
    6682        pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
    6783                                         style.COLOR_TRANSPARENT.get_svg()))
    6884        self.props.pulse_color = pulse_color
    6985
    70         # Update badge
    71         caps = model.props.capabilities
    72         if model.get_nm_network().is_favorite():
    73             self.props.badge_name = "emblem-favorite"
    74         elif (caps & NM_802_11_CAP_PROTO_WEP) or \
    75                 (caps & NM_802_11_CAP_PROTO_WPA) or \
    76                 (caps & NM_802_11_CAP_PROTO_WPA2):
    77             self.props.badge_name = "emblem-locked"
    78 
    7986        self._palette = self._create_palette()
    8087        self.set_palette(self._palette)
    8188
    82         self._update_icon()
    83         self._update_name()
    84         self._update_state()
     89        model_props = dbus.Interface(model, 'org.freedesktop.DBus.Properties')
     90        model_props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
     91                           reply_handler=self.__get_all_props_reply_cb,
     92                           error_handler=self.__get_all_props_error_cb)
     93
     94        self._bus.add_signal_receiver(self.__ap_properties_changed_cb,
     95                                      signal_name='PropertiesChanged',
     96                                      path=model.object_path,
     97                                      dbus_interface=_NM_ACCESSPOINT_IFACE)
     98
     99        self._device.Get(_NM_DEVICE_IFACE, 'State',
     100                         reply_handler=self.__get_device_state_reply_cb,
     101                         error_handler=self.__get_device_state_error_cb)
     102        self._device.Get(_NM_WIRELESS_IFACE, 'WirelessCapabilities',
     103                         reply_handler=self.__get_device_caps_reply_cb,
     104                         error_handler=self.__get_device_caps_error_cb)
     105        self._device.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
     106                         reply_handler=self.__get_active_ap_reply_cb,
     107                         error_handler=self.__get_active_ap_error_cb)
     108
     109        self._bus.add_signal_receiver(self.__device_state_changed_cb,
     110                                      signal_name='StateChanged',
     111                                      path=device.object_path,
     112                                      dbus_interface=_NM_DEVICE_IFACE)
     113        self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
     114                                      signal_name='PropertiesChanged',
     115                                      path=device.object_path,
     116                                      dbus_interface=_NM_WIRELESS_IFACE)
    85117
    86118    def _create_palette(self):
    87         icon_name = get_icon_state(_ICON_NAME, self._model.props.strength)
    88         palette_icon = Icon(icon_name=icon_name,
    89                             icon_size=style.STANDARD_ICON_SIZE,
    90                             badge_name=self.props.badge_name)
    91         ap_color = self._model.get_nm_network().get_colors()
    92         palette_icon.props.xo_color = XoColor('%s,%s' % ap_color)
     119        icon_name = get_icon_state(_ICON_NAME, self._strength)
     120        self._palette_icon = Icon(icon_name=icon_name,
     121                                  icon_size=style.STANDARD_ICON_SIZE,
     122                                  badge_name=self.props.badge_name)
    93123                                             
    94         p = palette.Palette(primary_text=self._model.props.name,
    95                             icon=palette_icon)
     124        p = palette.Palette(primary_text=self._name,
     125                            icon=self._palette_icon)
    96126
    97127        self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
    98128        self._connect_item.connect('activate', self._activate_cb)
    99129        p.menu.append(self._connect_item)
    100130
    101         # Only show disconnect when there's a mesh device, because mesh takes
    102         # priority over the normal wireless device. NM doesn't have a
    103         # "disconnect" method for a device either (for various reasons)
    104         # so this doesn't have a good mapping
    105         if self._meshdev:
    106             self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
    107             self._disconnect_item.connect('activate',
    108                                           self._disconnect_activate_cb)
    109             p.menu.append(self._disconnect_item)
     131        self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
     132        self._disconnect_item.connect('activate',
     133                                        self._disconnect_activate_cb)
     134        p.menu.append(self._disconnect_item)
    110135
    111136        return p
    112137
    113     def _disconnect_activate_cb(self, menuitem):
    114         # Disconnection for an AP means activating the default mesh device
    115         network_manager = hardwaremanager.get_network_manager()
    116         if network_manager and self._meshdev:
    117             network_manager.set_active_device(self._meshdev)
    118             self._palette.props.secondary_text = _('Disconnecting...')
    119             self.props.pulsing = False
     138    def __device_state_changed_cb(self, new_state, old_state, reason):
     139        self._device_state = new_state
     140        self._update_state()
     141
     142    def __ap_properties_changed_cb(self, properties):
     143        self._update_properties(properties)
     144
     145    def __wireless_properties_changed_cb(self, properties):
     146        if 'ActiveAccessPoint' in properties:
     147            ap = properties['ActiveAccessPoint']
     148            self._active = (ap == self._model.object_path)
     149            self._update_state()
     150
     151    def _update_properties(self, properties):
     152        if 'Ssid' in properties:
     153            self._name = properties['Ssid']
     154        if 'Strength' in properties:
     155            self._strength = properties['Strength']
     156        if 'Flags' in properties:
     157            self._flags = properties['Flags']
     158        if 'WpaFlags' in properties:
     159            self._wpa_flags = properties['WpaFlags']
     160        if 'RsnFlags' in properties:
     161            self._rsn_flags = properties['RsnFlags']
     162        if 'Mode' in properties:
     163            self._mode = properties['Mode']
     164
     165        sh = sha.new()
     166        data = self._name + hex(self._flags)
     167        sh.update(data)
     168        h = hash(sh.digest())
     169        idx = h % len(xocolor.colors)
     170
     171        self._color = XoColor('%s,%s' % (xocolor.colors[idx][0],
     172                                         xocolor.colors[idx][1]))
     173
     174        self._update()
     175
     176    def __get_active_ap_reply_cb(self, ap):
     177        self._active = (ap == self._model.object_path)
     178        self._update_state()
     179
     180    def __get_active_ap_error_cb(self, err):
     181        logging.debug('Error getting the active access point: %s', err)
     182
     183    def __get_device_caps_reply_cb(self, caps):
     184        self._device_caps = caps
    120185
    121     def _strength_changed_cb(self, model, pspec):
    122         self._update_icon()
     186    def __get_device_caps_error_cb(self, err):
     187        logging.debug('Error getting the wireless device properties: %s', err)
    123188
    124     def _name_changed_cb(self, model, pspec):
    125         self._update_name()
     189    def __get_device_state_reply_cb(self, state):
     190        self._device_state = state
     191        self._update()
     192
     193    def __get_device_state_error_cb(self, err):
     194        logging.debug('Error getting the access point properties: %s', err)
     195
     196    def __get_all_props_reply_cb(self, properties):
     197        self._update_properties(properties)
     198
     199    def __get_all_props_error_cb(self, err):
     200        logging.debug('Error getting the access point properties: %s', err)
     201
     202    def _update(self):
     203        if self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
     204            self.props.badge_name = "emblem-locked"
     205            self._palette_icon.props.badge_name = "emblem-locked"
     206        else:
     207            self.props.badge_name = None
     208            self._palette_icon.props.badge_name = None
     209
     210        self._palette.props.primary_text = self._name
    126211
    127     def _state_changed_cb(self, model, pspec):
    128         self._update_icon()
    129212        self._update_state()
     213        self._update_color()
    130214
    131     def _activate_cb(self, icon):
    132         network_manager = hardwaremanager.get_network_manager()
    133         if network_manager:
    134             device = self._model.get_nm_device()
    135             network = self._model.get_nm_network()
    136             network_manager.set_active_device(device, network)
    137 
    138     def _update_name(self):
    139         self._palette.props.primary_text = self._model.props.name
    140 
    141     def _update_icon(self):
    142         # keep this code in sync with view/devices/network/wireless.py
    143         strength = self._model.props.strength
    144         if self._model.props.state == accesspointmodel.STATE_CONNECTED:
     215    def _update_state(self):
     216        if self._active:
     217            state = self._device_state
     218        else:
     219            state = network.DEVICE_STATE_UNKNOWN
     220
     221        if state == network.DEVICE_STATE_ACTIVATED:
    145222            icon_name = '%s-connected' % _ICON_NAME
    146223        else:
    147224            icon_name = _ICON_NAME
    148         icon_name = get_icon_state(icon_name, strength)
     225
     226        icon_name = get_icon_state(icon_name, self._strength)
    149227        if icon_name:
    150228            self.props.icon_name = icon_name
    151229            icon = self._palette.props.icon
    152230            icon.props.icon_name = icon_name
    153231
    154     def _update_state(self):
    155         if self._model.props.state == accesspointmodel.STATE_CONNECTING:
     232        if state == network.DEVICE_STATE_PREPARE or \
     233           state == network.DEVICE_STATE_CONFIG or \
     234           state == network.DEVICE_STATE_NEED_AUTH or \
     235           state == network.DEVICE_STATE_IP_CONFIG:
    156236            if self._disconnect_item:
    157237                self._disconnect_item.show()
    158238            self._connect_item.hide()
    159239            self._palette.props.secondary_text = _('Connecting...')
    160240            self.props.pulsing = True
    161         elif self._model.props.state == accesspointmodel.STATE_CONNECTED:
     241        elif state == network.DEVICE_STATE_ACTIVATED:
    162242            if self._disconnect_item:
    163243                self._disconnect_item.show()
    164244            self._connect_item.hide()
    165             # TODO: show the channel number
    166245            self._palette.props.secondary_text = _('Connected')
    167246            self.props.pulsing = False
    168         elif self._model.props.state == accesspointmodel.STATE_NOTCONNECTED:
     247        else:
    169248            if self._disconnect_item:
    170249                self._disconnect_item.hide()
    171250            self._connect_item.show()
    172             # TODO: show the channel number
    173251            self._palette.props.secondary_text = None
    174252            self.props.pulsing = False
    175253
     254    def _update_color(self):       
    176255        if self._greyed_out:
    177256            self.props.pulsing = False
    178257            self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
    179258        else:
    180             self.props.base_color = XoColor('%s,%s' % \
    181                     self._model.get_nm_network().get_colors())
    182 
    183     def set_filter(self, query):
    184         self._greyed_out = self._model.props.name.lower().find(query) == -1
    185         self._update_state()
    186 
    187 _MESH_ICON_NAME = 'network-mesh'
    188 
    189 class MeshDeviceView(CanvasPulsingIcon):
    190     def __init__(self, nm_device, channel):
    191         if not channel in [1, 6, 11]:
    192             raise ValueError("Invalid channel %d" % channel)
    193 
    194         CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE,
    195                              icon_name=_MESH_ICON_NAME, cache=True)
    196 
    197         self._nm_device = nm_device
    198         self.channel = channel
    199         self.props.badge_name = "badge-channel-%d" % self.channel
    200         self._greyed_out = False
     259            self.props.base_color = self._color
    201260
    202         self._disconnect_item = None
    203         self._palette = self._create_palette()
    204         self.set_palette(self._palette)
     261        self._palette_icon.props.xo_color = self._color
    205262
    206         pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
    207                                          style.COLOR_TRANSPARENT.get_svg()))
    208         self.props.pulse_color = pulse_color
     263    def _disconnect_activate_cb(self, item):
     264        pass
    209265
    210         self.connect('activated', self._activate_cb)
    211266
    212         self._nm_device.connect('state-changed', self._state_changed_cb)
    213         self._nm_device.connect('activation-stage-changed',
    214                                 self._state_changed_cb)
    215         self._update_state()
     267    def _add_ciphers_from_flags(self, flags, pairwise):
     268        ciphers = []
     269        if pairwise:
     270            if flags & network.NM_802_11_AP_SEC_PAIR_TKIP:
     271                ciphers.append("tkip")
     272            if flags & network.NM_802_11_AP_SEC_PAIR_CCMP:
     273                ciphers.append("ccmp")
     274        else:
     275            if flags & network.NM_802_11_AP_SEC_GROUP_WEP40:
     276                ciphers.append("wep40")
     277            if flags & network.NM_802_11_AP_SEC_GROUP_WEP104:
     278                ciphers.append("wep104")
     279            if flags & network.NM_802_11_AP_SEC_GROUP_TKIP:
     280                ciphers.append("tkip")
     281            if flags & network.NM_802_11_AP_SEC_GROUP_CCMP:
     282                ciphers.append("ccmp")
     283        return ciphers
     284
     285    def _get_security(self):
     286        if not (self._flags & network.NM_802_11_AP_FLAGS_PRIVACY) and \
     287                (self._wpa_flags == network.NM_802_11_AP_SEC_NONE) and \
     288                (self._rsn_flags == network.NM_802_11_AP_SEC_NONE):
     289            # No security
     290            return None
     291
     292        if (self._flags & network.NM_802_11_AP_FLAGS_PRIVACY) and \
     293                (self._wpa_flags == network.NM_802_11_AP_SEC_NONE) and \
     294                (self._rsn_flags == network.NM_802_11_AP_SEC_NONE):
     295            # Static WEP, Dynamic WEP, or LEAP
     296            wireless_security = WirelessSecurity()
     297            wireless_security.key_mgmt = 'none'
     298            return wireless_security
     299
     300        if (self._mode != network.NM_802_11_MODE_INFRA):
     301            # Stuff after this point requires infrastructure
     302            logging.error('The infrastructure mode is not supoorted'
     303                          ' by your wireless device.')
     304            return None
     305
     306        if (self._rsn_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) and \
     307                (self._device_caps & network.NM_802_11_DEVICE_CAP_RSN):
     308            # WPA2 PSK first
     309            pairwise = self._add_ciphers_from_flags(self._rsn_flags, True)
     310            group = self._add_ciphers_from_flags(self._rsn_flags, False)
     311            wireless_security = WirelessSecurity()
     312            wireless_security.key_mgmt = 'wpa-psk'
     313            wireless_security.proto = 'rsn'
     314            wireless_security.pairwise = pairwise
     315            wireless_security.group = group
     316            return wireless_security
     317
     318        if (self._wpa_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) and \
     319                (self._device_caps & network.NM_802_11_DEVICE_CAP_WPA):
     320            # WPA PSK
     321            pairwise = self._add_ciphers_from_flags(self._wpa_flags, True)
     322            group = self._add_ciphers_from_flags(self._wpa_flags, False)
     323            wireless_security = WirelessSecurity()
     324            wireless_security.key_mgmt = 'wpa-psk'
     325            wireless_security.proto = 'wpa'
     326            wireless_security.pairwise = pairwise
     327            wireless_security.group = group
     328            return wireless_security
    216329
    217     def _create_palette(self):
    218         p = palette.Palette(_("Mesh Network") + " " + str(self.channel),
    219                             menu_after_content=True)
     330    def _activate_cb(self, icon):
     331        connection = network.find_connection(self._name)
     332        if connection is None:
     333            settings = Settings()           
     334            settings.connection.id = 'Auto ' + self._name
     335            settings.connection.uuid = unique_id()
     336            settings.connection.type = '802-11-wireless'
     337            settings.wireless.ssid = self._name
    220338
    221         self._disconnect_item = gtk.MenuItem(_('Disconnect...'))
    222         self._disconnect_item.connect('activate', self._disconnect_activate_cb)
    223         p.menu.append(self._disconnect_item)
     339            wireless_security = self._get_security()
     340            settings.wireless_security = wireless_security
    224341
    225         state = self._nm_device.get_state()
    226         chan = wireless.freq_to_channel(self._nm_device.get_frequency())
    227         if state == nmclient.DEVICE_STATE_ACTIVATED and chan == self.channel:
    228             self._disconnect_item.show()
    229         return p
     342            connection = network.add_connection(self._name, settings)
    230343
    231     def _disconnect_activate_cb(self, menuitem):
    232         network_manager = hardwaremanager.get_network_manager()
    233         if network_manager:
    234             network_manager.set_active_device(self._nm_device)
     344            if wireless_security is None:
     345                self._connection = connection
    235346
    236     def _activate_cb(self, icon):
    237         network_manager = hardwaremanager.get_network_manager()
    238         if network_manager:
    239             freq = wireless.channel_to_freq(self.channel)
    240             network_manager.set_active_device(self._nm_device, mesh_freq=freq)
     347        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     348        netmgr = dbus.Interface(obj, _NM_IFACE)
    241349
    242     def _state_changed_cb(self, model):
    243         self._update_state()
     350        netmgr.ActivateConnection(network.SETTINGS_SERVICE, connection.path,
     351                                  self._device.object_path,
     352                                  self._model.object_path,
     353                                  reply_handler=self.__activate_reply_cb,
     354                                  error_handler=self.__activate_error_cb)
    244355
    245     def _update_state(self):
    246         state = self._nm_device.get_state()
    247         chan = wireless.freq_to_channel(self._nm_device.get_frequency())
    248         if state == nmclient.DEVICE_STATE_ACTIVATING and chan == self.channel:
    249             self._disconnect_item.hide()
    250             self.props.pulsing = True
    251         elif state == nmclient.DEVICE_STATE_ACTIVATED and chan == self.channel:
    252             self._disconnect_item.show()
    253             self.props.pulsing = False
    254         elif state == nmclient.DEVICE_STATE_INACTIVE or chan != self.channel:
    255             self._disconnect_item.hide()
    256             self.props.pulsing = False
     356    def __activate_reply_cb(self, connection):
     357        if self._connection:
     358            self._connection.save()
     359        logging.debug('Connection activated: %s', connection)
    257360
    258         if self._greyed_out:
    259             self.props.pulsing = False
    260             self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
    261         else:
    262             self.props.base_color = profile.get_color()
     361    def __activate_error_cb(self, err):
     362        logging.debug('Failed to activate connection: %s', err)
    263363
    264364    def set_filter(self, query):
    265         self._greyed_out = (query != '')
     365        self._greyed_out = self._name.lower().find(query) == -1
    266366        self._update_state()
     367        self._update_color()
     368
     369    def create_keydialog(self, response):
     370        keydialog.create(self._name, self._flags, self._wpa_flags,
     371                         self._rsn_flags, self._device_caps, response)
     372
     373    def disconnect(self):
     374        self._bus.remove_signal_receiver(self.__ap_properties_changed_cb,
     375                                         signal_name='PropertiesChanged',
     376                                         path=self._model.object_path,
     377                                         dbus_interface=_NM_ACCESSPOINT_IFACE)
     378
     379        self._bus.remove_signal_receiver(self.__device_state_changed_cb,
     380                                         signal_name='StateChanged',
     381                                         path=self._device.object_path,
     382                                         dbus_interface=_NM_DEVICE_IFACE)
     383        self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
     384                                         signal_name='PropertiesChanged',
     385                                         path=self._device.object_path,
     386                                         dbus_interface=_NM_WIRELESS_IFACE)
    267387
    268388class ActivityView(hippo.CanvasBox):
    269389    def __init__(self, model):
    class ActivityView(hippo.CanvasBox): 
    364484        self._update_palette()
    365485
    366486    def _joined_changed_cb(self, widget, event):
    367         logging.debug('ActivityView._joined_changed_cb: AAAA!!!!')
     487        logging.debug('ActivityView._joined_changed_cb')
    368488
    369489_AUTOSEARCH_TIMEOUT = 1000
    370490
    class MeshToolbar(gtk.Toolbar): 
    436556        self.search_entry.activate()
    437557        return False
    438558
     559class DeviceObserver(object):
     560    def __init__(self, box, device):
     561        self._box = box
     562        self._bus = dbus.SystemBus()
     563        self._device = device
     564
     565        wireless = dbus.Interface(self._device, _NM_WIRELESS_IFACE)
     566        wireless.GetAccessPoints(reply_handler=self._get_access_points_reply_cb,
     567                                 error_handler=self._get_access_points_error_cb)
     568
     569        self._bus.add_signal_receiver(self.__access_point_added_cb,
     570                                      signal_name='AccessPointAdded',
     571                                      path=device.object_path,
     572                                      dbus_interface=_NM_WIRELESS_IFACE)
     573        self._bus.add_signal_receiver(self.__access_point_removed_cb,
     574                                      signal_name='AccessPointRemoved',
     575                                      path=device.object_path,
     576                                      dbus_interface=_NM_WIRELESS_IFACE)
     577
     578    def _get_access_points_reply_cb(self, access_points_o):
     579        for ap_o in access_points_o:
     580            ap = self._bus.get_object(_NM_SERVICE, ap_o)
     581            self._box.add_access_point(self._device, ap)
     582
     583    def _get_access_points_error_cb(self, err):
     584        logging.error('Failed to get access points: %s', err)
     585
     586    def __access_point_added_cb(self, access_point_o):
     587        ap = self._bus.get_object(_NM_SERVICE, access_point_o)
     588        self._box.add_access_point(self._device, ap)
     589
     590    def __access_point_removed_cb(self, access_point_o):
     591        self._box.remove_access_point(access_point_o)
     592
     593    def disconnect(self):
     594        self._bus.remove_signal_receiver(self.__access_point_added_cb,
     595                                         signal_name='AccessPointAdded',
     596                                         path=self._device.object_path,
     597                                         dbus_interface=_NM_WIRELESS_IFACE)
     598        self._bus.remove_signal_receiver(self.__access_point_removed_cb,
     599                                         signal_name='AccessPointRemoved',
     600                                         path=self._device.object_path,
     601                                         dbus_interface=_NM_WIRELESS_IFACE)
     602
     603class NetworkManagerObserver(object):
     604    def __init__(self, box):
     605        self._box = box
     606        self._bus = dbus.SystemBus()
     607        self._devices = {}
     608        self._netmgr = None
     609
     610    def listen(self):
     611        try:
     612            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     613            self._netmgr = dbus.Interface(obj, _NM_IFACE)
     614        except dbus.DBusException:
     615            logging.debug('%s service not available', _NM_SERVICE)
     616            return
     617
     618        self._netmgr.GetDevices(reply_handler=self.__get_devices_reply_cb,
     619                                error_handler=self.__get_devices_error_cb)
     620
     621        self._bus.add_signal_receiver(self.__device_added_cb,
     622                                      signal_name='DeviceAdded',
     623                                      dbus_interface=_NM_IFACE)
     624        self._bus.add_signal_receiver(self.__device_removed_cb,
     625                                      signal_name='DeviceRemoved',
     626                                      dbus_interface=_NM_IFACE)
     627
     628        settings = network.get_settings()
     629        if settings is not None:
     630            settings.secrets_request.connect(self.__secrets_request_cb)
     631
     632    def __secrets_request_cb(self, **kwargs):
     633        # FIXME It would be better to do all of this async, but I cannot think
     634        # of a good way to. NM could really use some love here.
     635
     636        netmgr_props = dbus.Interface(
     637                            self._netmgr, 'org.freedesktop.DBus.Properties')
     638        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
     639
     640        for conn_o in active_connections_o:
     641            obj = self._bus.get_object(_NM_IFACE, conn_o)
     642            props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
     643            ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
     644
     645            ap_view = self._box.access_points[ap_o]
     646            ap_view.create_keydialog(kwargs['response'])
     647
     648    def __get_devices_reply_cb(self, devices_o):
     649        for dev_o in devices_o:
     650            self._check_device(dev_o)
     651
     652    def __get_devices_error_cb(self, err):
     653        logging.error('Failed to get devices: %s', err)
     654
     655    def _check_device(self, device_o):
     656        device = self._bus.get_object(_NM_SERVICE, device_o)
     657        props = dbus.Interface(device, 'org.freedesktop.DBus.Properties')
     658
     659        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
     660        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
     661            self._devices[device_o] = DeviceObserver(self._box, device)
     662
     663    def _get_device_path_error_cb(self, err):
     664        logging.error('Failed to get device type: %s', err)
     665
     666    def __device_added_cb(self, device_o):
     667        self._check_device(device_o)
     668
     669    def __device_removed_cb(self, device_o):
     670        if device_o in self._devices:
     671            observer = self._devices[device_o]
     672            observer.disconnect()
     673            del self._devices[device_o]
     674
    439675class MeshBox(gtk.VBox):
    440676    __gtype_name__ = 'SugarMeshBox'
     677
    441678    def __init__(self):
     679        logging.debug("STARTUP: Loading the mesh view")
     680
    442681        gobject.GObject.__init__(self)
    443682
    444         self._model = shellmodel.get_instance().get_mesh()
     683        self.access_points = {}
     684
     685        self._model = neighborhood.get_model()
    445686        self._buddies = {}
    446687        self._activities = {}
    447         self._access_points = {}
    448688        self._mesh = {}
    449689        self._buddy_to_activity = {}
    450690        self._suspended = True
    class MeshBox(gtk.VBox): 
    480720        self._model.connect('activity-added', self._activity_added_cb)
    481721        self._model.connect('activity-removed', self._activity_removed_cb)
    482722
    483         for ap_model in self._model.get_access_points():
    484             self._add_access_point(ap_model)
    485 
    486         self._model.connect('access-point-added',
    487                             self._access_point_added_cb)
    488         self._model.connect('access-point-removed',
    489                             self._access_point_removed_cb)
    490 
    491         if self._model.get_mesh():
    492             self.__mesh_added_cb(self._model, self._model.get_mesh())
    493 
    494         self._model.connect('mesh-added', self.__mesh_added_cb)
    495         self._model.connect('mesh-removed', self.__mesh_removed_cb)
    496 
    497     def __mesh_added_cb(self, model, meshdev):
    498         self._add_mesh_icon(meshdev, 1)
    499         self._add_mesh_icon(meshdev, 6)
    500         self._add_mesh_icon(meshdev, 11)
    501 
    502     def __mesh_removed_cb(self, model):
    503         self._remove_mesh_icon(1)
    504         self._remove_mesh_icon(6)
    505         self._remove_mesh_icon(11)
     723        netmgr_observer = NetworkManagerObserver(self)
     724        netmgr_observer.listen()
    506725
    507726    def do_size_allocate(self, allocation):
    508727        width = allocation.width       
    class MeshBox(gtk.VBox): 
    534753    def _activity_removed_cb(self, model, activity_model):
    535754        self._remove_activity(activity_model)
    536755
    537     def _access_point_added_cb(self, model, ap_model):
    538         self._add_access_point(ap_model)
    539 
    540     def _access_point_removed_cb(self, model, ap_model):
    541         self._remove_access_point(ap_model)
    542 
    543     def _add_mesh_icon(self, meshdev, channel):
    544         if self._mesh.has_key(channel):
    545             self._remove_mesh_icon(channel)
    546         if not meshdev:
    547             return
    548         self._mesh[channel] = MeshDeviceView(meshdev, channel)
    549         self._layout.add(self._mesh[channel])
    550 
    551     def _remove_mesh_icon(self, channel):
    552         if not self._mesh.has_key(channel):
    553             return
    554         self._layout.remove(self._mesh[channel])
    555         del self._mesh[channel]
    556 
    557756    def _add_alone_buddy(self, buddy_model):
    558757        icon = BuddyIcon(buddy_model)
    559758        if buddy_model.is_owner():
    class MeshBox(gtk.VBox): 
    563762        if hasattr(icon, 'set_filter'):
    564763            icon.set_filter(self._query)
    565764
    566         self._buddies[buddy_model.get_key()] = icon
     765        self._buddies[buddy_model.get_buddy().object_path()] = icon
    567766
    568767    def _remove_alone_buddy(self, buddy_model):
    569         icon = self._buddies[buddy_model.get_key()]
     768        icon = self._buddies[buddy_model.get_buddy().object_path()]
    570769        self._layout.remove(icon)
    571         del self._buddies[buddy_model.get_key()]
     770        del self._buddies[buddy_model.get_buddy().object_path()]
    572771        icon.destroy()
    573772
    574773    def _remove_buddy(self, buddy_model):
    575         key = buddy_model.get_key()
    576         if self._buddies.has_key(key):
     774        object_path = buddy_model.get_buddy().object_path()
     775        if self._buddies.has_key(object_path):
    577776            self._remove_alone_buddy(buddy_model)
    578777        else:
    579778            for activity in self._activities.values():
    580                 if activity.has_buddy_icon(key):
    581                     activity.remove_buddy_icon(key)
     779                if activity.has_buddy_icon(object_path):
     780                    activity.remove_buddy_icon(object_path)
    582781
    583782    def _move_buddy(self, buddy_model, activity_model):
    584783        self._remove_buddy(buddy_model)
    class MeshBox(gtk.VBox): 
    589788            activity = self._activities[activity_model.get_id()]
    590789
    591790            icon = BuddyIcon(buddy_model, style.STANDARD_ICON_SIZE)
    592             activity.add_buddy_icon(buddy_model.get_key(), icon)
     791            activity.add_buddy_icon(buddy_model.get_buddy().object_path(), icon)
    593792
    594793            if hasattr(icon, 'set_filter'):
    595794                icon.set_filter(self._query)
    class MeshBox(gtk.VBox): 
    609808        del self._activities[activity_model.get_id()]
    610809        icon.destroy()
    611810
    612     def _add_access_point(self, ap_model):
    613         meshdev = self._model.get_mesh()
    614         icon = AccessPointView(ap_model, meshdev)
     811    def add_access_point(self, device, ap):
     812        icon = AccessPointView(device, ap)
    615813        self._layout.add(icon)
    616814
    617815        if hasattr(icon, 'set_filter'):
    618816            icon.set_filter(self._query)
    619817
    620         self._access_points[ap_model.get_id()] = icon
     818        self.access_points[ap.object_path] = icon
    621819
    622     def _remove_access_point(self, ap_model):
    623         icon = self._access_points[ap_model.get_id()]
    624         self._layout.remove(icon)
    625         del self._access_points[ap_model.get_id()]
     820    def remove_access_point(self, ap_o):
     821        if ap_o in self.access_points:
     822            icon = self.access_points[ap_o]
     823            icon.disconnect()
     824            self._layout.remove(icon)
     825            del self.access_points[ap_o]
     826        else:
     827            logging.error('Can not remove access point %s' % ap_o)
    626828
    627829    def suspend(self):
    628830        if not self._suspended:
    629831            self._suspended = True
    630             for ap in self._access_points.values():
     832            for ap in self.access_points.values():
    631833                ap.props.paused = True
    632834
    633835    def resume(self):
    634836        if self._suspended:
    635837            self._suspended = False
    636             for ap in self._access_points.values():
     838            for ap in self.access_points.values():
    637839                ap.props.paused = False
    638840
    639841    def _toolbar_query_changed_cb(self, toolbar, query):
  • new file src/view/home/keydialog.py

    diff --git a/src/view/home/keydialog.py b/src/view/home/keydialog.py
    new file mode 100644
    index 0000000..92e8f40
    - +  
     1# Copyright (C) 2006-2007 Red Hat, Inc.
     2#
     3# This program is free software; you can redistribute it and/or modify
     4# it under the terms of the GNU General Public License as published by
     5# the Free Software Foundation; either version 2 of the License, or
     6# (at your option) any later version.
     7#
     8# This program is distributed in the hope that it will be useful,
     9# but WITHOUT ANY WARRANTY; without even the implied warranty of
     10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11# GNU General Public License for more details.
     12#
     13# You should have received a copy of the GNU General Public License
     14# along with this program; if not, write to the Free Software
     15# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     16
     17import md5
     18from gettext import gettext as _
     19
     20import gtk
     21import dbus
     22
     23from model import network
     24from model.network import Secrets
     25
     26IW_AUTH_ALG_OPEN_SYSTEM = 'open'
     27IW_AUTH_ALG_SHARED_KEY  = 'shared'
     28
     29def string_is_hex(key):
     30    is_hex = True
     31    for c in key:
     32        if not 'a' <= c.lower() <= 'f' and not '0' <= c <= '9':
     33            is_hex = False
     34    return is_hex
     35
     36def string_is_ascii(string):
     37    try:
     38        string.encode('ascii')
     39        return True
     40    except UnicodeEncodeError:
     41        return False
     42
     43def string_to_hex(passphrase):
     44    key = ''
     45    for c in passphrase:
     46        key += '%02x' % ord(c)
     47    return key
     48
     49def hash_passphrase(passphrase):
     50    # passphrase must have a length of 64
     51    if len(passphrase) > 64:
     52        passphrase = passphrase[:64]
     53    elif len(passphrase) < 64:
     54        while len(passphrase) < 64:
     55            passphrase += passphrase[:64 - len(passphrase)]
     56    passphrase = md5.new(passphrase).digest()
     57    return string_to_hex(passphrase)[:26]
     58
     59class CanceledKeyRequestError(dbus.DBusException):
     60    def __init__(self):
     61        dbus.DBusException.__init__(self)
     62        self._dbus_error_name = network.NM_SETTINGS_IFACE + '.CanceledError'
     63
     64class KeyDialog(gtk.Dialog):
     65    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
     66        gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
     67        self.set_title("Wireless Key Required")
     68
     69        self._response = response
     70        self._entry = None
     71        self._ssid = ssid
     72        self._flags = flags
     73        self._wpa_flags = wpa_flags
     74        self._rsn_flags = rsn_flags
     75        self._dev_caps = dev_caps
     76
     77        self.set_has_separator(False)       
     78
     79        label = gtk.Label("A wireless encryption key is required for\n" \
     80                          " the wireless network '%s'." % self._ssid)
     81        self.vbox.pack_start(label)
     82
     83        self.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
     84                         gtk.STOCK_OK, gtk.RESPONSE_OK)
     85        self.set_default_response(gtk.RESPONSE_OK)
     86        self.set_has_separator(True)
     87
     88    def add_key_entry(self):
     89        self._entry = gtk.Entry()
     90        self._entry.connect('changed', self._update_response_sensitivity)
     91        self._entry.connect('activate', self._entry_activate_cb)
     92        self.vbox.pack_start(self._entry)
     93        self.vbox.set_spacing(6)
     94        self.vbox.show_all()
     95
     96        self._update_response_sensitivity()
     97        self._entry.grab_focus()
     98
     99    def _entry_activate_cb(self, entry):
     100        self.response(gtk.RESPONSE_OK)
     101
     102    def create_security(self):
     103        raise NotImplementedError
     104
     105    def get_response_object(self):
     106        return self._response
     107
     108WEP_PASSPHRASE = 1
     109WEP_HEX = 2
     110WEP_ASCII = 3
     111
     112class WEPKeyDialog(KeyDialog):
     113    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
     114        KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
     115                           dev_caps, response)
     116
     117        # WEP key type
     118        self.key_store = gtk.ListStore(str, int)
     119        self.key_store.append(["Passphrase (128-bit)", WEP_PASSPHRASE])
     120        self.key_store.append(["Hex (40/128-bit)", WEP_HEX])
     121        self.key_store.append(["ASCII (40/128-bit)", WEP_ASCII])
     122
     123        self.key_combo = gtk.ComboBox(self.key_store)
     124        cell = gtk.CellRendererText()
     125        self.key_combo.pack_start(cell, True)
     126        self.key_combo.add_attribute(cell, 'text', 0)
     127        self.key_combo.set_active(0)
     128        self.key_combo.connect('changed', self._key_combo_changed_cb)
     129
     130        hbox = gtk.HBox()
     131        hbox.pack_start(gtk.Label(_("Key Type:")))
     132        hbox.pack_start(self.key_combo)
     133        hbox.show_all()
     134        self.vbox.pack_start(hbox)
     135
     136        # Key entry field
     137        self.add_key_entry()
     138
     139        # WEP authentication mode
     140        self.auth_store = gtk.ListStore(str, str)
     141        self.auth_store.append(["Open System", IW_AUTH_ALG_OPEN_SYSTEM])
     142        self.auth_store.append(["Shared Key", IW_AUTH_ALG_SHARED_KEY])
     143
     144        self.auth_combo = gtk.ComboBox(self.auth_store)
     145        cell = gtk.CellRendererText()
     146        self.auth_combo.pack_start(cell, True)
     147        self.auth_combo.add_attribute(cell, 'text', 0)
     148        self.auth_combo.set_active(0)
     149
     150        hbox = gtk.HBox()
     151        hbox.pack_start(gtk.Label(_("Authentication Type:")))
     152        hbox.pack_start(self.auth_combo)
     153        hbox.show_all()
     154
     155        self.vbox.pack_start(hbox)
     156
     157    def _key_combo_changed_cb(self, widget):
     158        self._update_response_sensitivity()
     159
     160    def _get_security(self):
     161        key = self._entry.get_text()
     162
     163        it = self.key_combo.get_active_iter()
     164        (key_type, ) = self.key_store.get(it, 1)
     165
     166        if key_type == WEP_PASSPHRASE:
     167            key = hash_passphrase(key)
     168        elif key_type == WEP_ASCII:
     169            key = string_to_hex(key)
     170
     171        it = self.auth_combo.get_active_iter()
     172        (auth_alg, ) = self.auth_store.get(it, 1)
     173
     174        return (key, auth_alg)
     175
     176    def print_security(self):
     177        (key, auth_alg) = self._get_security()
     178        print "Key: %s" % key
     179        print "Auth: %d" % auth_alg
     180
     181    def create_security(self):
     182        (key, auth_alg) = self._get_security()
     183        secrets = Secrets()
     184        secrets.wep_key = key
     185        secrets.auth_alg = auth_alg
     186        return secrets
     187
     188    def _update_response_sensitivity(self, ignored=None):
     189        key = self._entry.get_text()
     190        it = self.key_combo.get_active_iter()
     191        (key_type, ) = self.key_store.get(it, 1)
     192
     193        valid = False
     194        if key_type == WEP_PASSPHRASE:
     195            # As the md5 passphrase can be of any length and has no indicator,
     196            # we cannot check for the validity of the input.
     197            if len(key) > 0:
     198                valid = True
     199        elif key_type == WEP_ASCII:
     200            if len(key) == 5 or len(key) == 13:
     201                valid = string_is_ascii(key)
     202        elif key_type == WEP_HEX:
     203            if len(key) == 10 or len(key) == 26:
     204                valid = string_is_hex(key)
     205
     206        self.set_response_sensitive(gtk.RESPONSE_OK, valid)
     207
     208class WPAKeyDialog(KeyDialog):
     209    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
     210        KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
     211                           dev_caps, response)
     212        self.add_key_entry()
     213
     214        self.store = gtk.ListStore(str)
     215        self.store.append([_("WPA & WPA2 Personal")])
     216
     217        self.combo = gtk.ComboBox(self.store)
     218        cell = gtk.CellRendererText()
     219        self.combo.pack_start(cell, True)
     220        self.combo.add_attribute(cell, 'text', 0)
     221        self.combo.set_active(0)
     222
     223        self.hbox = gtk.HBox()
     224        self.hbox.pack_start(gtk.Label(_("Wireless Security:")))
     225        self.hbox.pack_start(self.combo)
     226        self.hbox.show_all()
     227
     228        self.vbox.pack_start(self.hbox)
     229
     230    def _get_security(self):
     231        ssid = self._ssid
     232        key = self._entry.get_text()
     233        is_hex = string_is_hex(key)
     234
     235        real_key = None
     236        if len(key) == 64 and is_hex:
     237            # Hex key
     238            real_key = key
     239        elif len(key) >= 8 and len(key) <= 63:
     240            # passphrase
     241            from subprocess import Popen, PIPE
     242            p = Popen(['/usr/sbin/wpa_passphrase', ssid, key], stdout=PIPE)
     243            for line in p.stdout:
     244                if line.strip().startswith("psk="):
     245                    real_key = line.strip()[4:]
     246            if p.wait() != 0:
     247                raise RuntimeError("Error hashing passphrase")
     248            if real_key and len(real_key) != 64:
     249                real_key = None
     250
     251        if not real_key:
     252            raise RuntimeError("Invalid key")
     253
     254        return real_key
     255
     256    def print_security(self):
     257        key = self._get_security()
     258        print "Key: %s" % key
     259
     260    def create_security(self):
     261        secrets = Secrets()
     262        secrets.psk = self._get_security()
     263        return secrets
     264
     265    def _update_response_sensitivity(self, ignored=None):
     266        key = self._entry.get_text()
     267        is_hex = string_is_hex(key)
     268
     269        valid = False
     270        if len(key) == 64 and is_hex:
     271            # hex key
     272            valid = True
     273        elif len(key) >= 8 and len(key) <= 63:
     274            # passphrase
     275            valid = True
     276        self.set_response_sensitive(gtk.RESPONSE_OK, valid)
     277        return False
     278
     279def create(ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
     280    if wpa_flags == network.NM_802_11_AP_SEC_NONE and \
     281            rsn_flags == network.NM_802_11_AP_SEC_NONE:
     282        key_dialog = WEPKeyDialog(ssid, flags, wpa_flags, rsn_flags,
     283                                  dev_caps, response)
     284    else:
     285        key_dialog = WPAKeyDialog(ssid, flags, wpa_flags, rsn_flags,
     286                                  dev_caps, response)
     287
     288    key_dialog.connect("response", _key_dialog_response_cb)
     289    key_dialog.connect("destroy", _key_dialog_destroy_cb)
     290    key_dialog.show_all()
     291
     292def _key_dialog_destroy_cb(key_dialog, data=None):
     293    _key_dialog_response_cb(key_dialog, gtk.RESPONSE_CANCEL)
     294
     295def _key_dialog_response_cb(key_dialog, response_id):
     296    response = key_dialog.get_response_object()
     297    secrets = None
     298    if response_id == gtk.RESPONSE_OK:
     299        secrets = key_dialog.create_security()
     300
     301    if response_id in [gtk.RESPONSE_CANCEL, gtk.RESPONSE_NONE]:
     302        # key dialog dialog was canceled; send the error back to NM
     303        response.set_error(CanceledKeyRequestError())
     304    elif response_id == gtk.RESPONSE_OK:
     305        if not secrets:
     306            raise RuntimeError("Invalid security arguments.")
     307        response.set_secrets(secrets)
     308    else:
     309        raise RuntimeError("Unhandled key dialog response %d" % response_id)
     310
     311    key_dialog.destroy()