[Sugar-devel] [PATCH v3] Simple NetworkManager-0.9 port

Daniel Drake dsd at laptop.org
Mon Nov 14 12:20:02 EST 2011


Adapt sugar to NetworkManager-0.9 API changes.

The major change here is the removal of the user-level connections
mechanism; instead of storing connection information in Sugar,
NetworkManager now Manages our Networks for us.

However, some level of interfacing/monitoring NM is now needed,
implemented with the Connections and Connection classes in
jarabe.model.network.

If found, connections in sugar's connections.cfg are automatically
migrated, and then connections.cfg is deleted. Similarly, if modem
connection details are found in gconf, they are migrated into NM
and then the gconf keys are unset.

The existing network code is far from perfect and actually quite messy.
In this port I've tried not to make fundamental changes to improve this,
in order to keep task complexity down and aid review.
In the medium term I do plan to improve this code, by moving it to
use gobject-introspection on libnm, and rewriting/restructuring at the
same time. By letting libnm do most of the work for us, this layer can
be greatly simplified. However, libnm and gobject-introspection
improvements are needed first, which I will continue to work on.

Modem PUK configuration has been removed as NetworkManager no longer
has configuration for this. It hasn't been used (and was marked
deprecated) throughout the NM-0.8 release series.
---
 data/sugar.schemas.in                            |   24 +-
 extensions/cpsection/modemconfiguration/model.py |  107 ++--
 extensions/cpsection/modemconfiguration/view.py  |  206 ++-----
 extensions/cpsection/network/model.py            |   16 +-
 extensions/deviceicon/network.py                 |  178 +++---
 src/jarabe/desktop/keydialog.py                  |   32 +-
 src/jarabe/desktop/meshbox.py                    |   59 +-
 src/jarabe/desktop/networkviews.py               |  167 ++---
 src/jarabe/model/adhoc.py                        |  115 ++--
 src/jarabe/model/network.py                      |  762 +++++++++++----------
 src/jarabe/model/olpcmesh.py                     |  158 +++--
 11 files changed, 856 insertions(+), 968 deletions(-)

v2: handle review comments from Simon and Sascha's Oct 24 mail. Only non-minor
resulting change is a refactoring of modem setting handling so that undo
is supported again.

v3: minor changes from Simon's review

diff --git a/data/sugar.schemas.in b/data/sugar.schemas.in
index 8b3e1ad..aaef381 100644
--- a/data/sugar.schemas.in
+++ b/data/sugar.schemas.in
@@ -280,8 +280,8 @@
       <type>string</type>
       <default></default>
       <locale name="C">
-        <short>GSM network username</short>
-        <long>GSM network username configuration</long>
+        <short>GSM network username (DEPRECATED/UNUSED)</short>
+        <long>GSM network username configuration (DEPRECATED/UNUSED)</long>
       </locale>
     </schema>
     <schema>
@@ -291,8 +291,8 @@
       <type>string</type>
       <default></default>
       <locale name="C">
-        <short>GSM network password</short>
-        <long>GSM network password configuration</long>
+        <short>GSM network password (DEPRECATED/UNUSED)</short>
+        <long>GSM network password configuration (DEPRECATED/UNUSED)</long>
       </locale>
     </schema>
     <schema>
@@ -302,8 +302,8 @@
       <type>string</type>
       <default>*99#</default>
       <locale name="C">
-        <short>GSM network number</short>
-        <long>GSM network telephone number configuration</long>
+        <short>GSM network number (DEPRECATED/UNUSED)</short>
+        <long>GSM network telephone number configuration (DEPRECATED/UNUSED)</long>
       </locale>
     </schema>
     <schema>
@@ -313,8 +313,8 @@
       <type>string</type>
       <default></default>
       <locale name="C">
-        <short>GSM network APN</short>
-        <long>GSM network access point name configuration</long>
+        <short>GSM network APN (DEPRECATED/UNUSED)</short>
+        <long>GSM network access point name configuration (DEPRECATED/UNUSED)</long>
       </locale>
     </schema>
     <schema>
@@ -324,8 +324,8 @@
       <type>string</type>
       <default></default>
       <locale name="C">
-        <short>GSM network PIN</short>
-        <long>GSM network personal identification number configuration</long>
+        <short>GSM network PIN (DEPRECATED/UNUSED)</short>
+        <long>GSM network personal identification number configuration (DEPRECATED/UNUSED)</long>
       </locale>
     </schema>
     <schema>
@@ -335,8 +335,8 @@
       <type>string</type>
       <default></default>
       <locale name="C">
-        <short>GSM network PUK</short>
-        <long>GSM network personal unlock key configuration</long>
+        <short>GSM network PUK (DEPRECATED/UNUSED)</short>
+        <long>GSM network personal unlock key configuration (DEPRECATED/UNUSED)</long>
       </locale>
     </schema>
 
diff --git a/extensions/cpsection/modemconfiguration/model.py b/extensions/cpsection/modemconfiguration/model.py
index 1e83c44..969b5d9 100755
--- a/extensions/cpsection/modemconfiguration/model.py
+++ b/extensions/cpsection/modemconfiguration/model.py
@@ -14,68 +14,87 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  US
 
-import gconf
+import logging
 
-from jarabe.model.network import GSM_USERNAME_PATH, GSM_PASSWORD_PATH, \
-                                 GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH, \
-                                 GSM_PUK_PATH
+import dbus
+import gtk
 
+from jarabe.model import network
 
-def get_username():
-    client = gconf.client_get_default()
-    return client.get_string(GSM_USERNAME_PATH) or ''
 
+def get_connection():
+    return network.find_gsm_connection()
 
-def get_password():
-    client = gconf.client_get_default()
-    return client.get_string(GSM_PASSWORD_PATH) or ''
 
+def get_modem_settings():
+    modem_settings = {}
+    connection = get_connection()
+    if not connection:
+        return modem_settings
 
-def get_number():
-    client = gconf.client_get_default()
-    return client.get_string(GSM_NUMBER_PATH) or ''
+    settings = connection.get_settings('gsm')
+    for setting in ('username', 'number', 'apn'):
+        modem_settings[setting] = settings.get(setting, '')
 
+    # use mutable container for nested function control variable
+    secrets_call_done = [False]
 
-def get_apn():
-    client = gconf.client_get_default()
-    return client.get_string(GSM_APN_PATH) or ''
+    def _secrets_cb(secrets):
+        secrets_call_done[0] = True
+        if not secrets or not 'gsm' in secrets:
+            return
 
+        gsm_secrets = secrets['gsm']
+        modem_settings['password'] = gsm_secrets.get('password', '')
+        modem_settings['pin'] = gsm_secrets.get('pin', '')
 
-def get_pin():
-    client = gconf.client_get_default()
-    return client.get_string(GSM_PIN_PATH) or ''
+    def _secrets_err_cb(err):
+        secrets_call_done[0] = True
+        if isinstance(err, dbus.exceptions.DBusException) and \
+                err.get_dbus_name() == network.NM_AGENT_MANAGER_ERR_NO_SECRETS:
+            logging.debug('No GSM secrets present')
+        else:
+            logging.error('Error retrieving GSM secrets: %s', err)
 
+    # must be called asynchronously as this re-enters the GTK main loop
+    connection.get_secrets('gsm', _secrets_cb, _secrets_err_cb)
 
-def get_puk():
-    client = gconf.client_get_default()
-    return client.get_string(GSM_PUK_PATH) or ''
+    # wait til asynchronous execution completes
+    while not secrets_call_done[0]:
+        gtk.main_iteration()
 
+    return modem_settings
 
-def set_username(username):
-    client = gconf.client_get_default()
-    client.set_string(GSM_USERNAME_PATH, username)
 
+def _set_or_clear(_dict, key, value):
+    """Update a dictionary value for a specific key. If value is None or
+    zero-length, but the key is present in the dictionary, delete that
+    dictionary entry."""
+    if value:
+        _dict[key] = value
+        return
 
-def set_password(password):
-    client = gconf.client_get_default()
-    client.set_string(GSM_PASSWORD_PATH, password)
+    if key in _dict:
+        del _dict[key]
 
 
-def set_number(number):
-    client = gconf.client_get_default()
-    client.set_string(GSM_NUMBER_PATH, number)
+def set_modem_settings(modem_settings):
+    username = modem_settings.get('username', '')
+    password = modem_settings.get('password', '')
+    number = modem_settings.get('number', '')
+    apn = modem_settings.get('apn', '')
+    pin = modem_settings.get('pin', '')
 
+    connection = get_connection()
+    if not connection:
+        network.create_gsm_connection(username, password, number, apn, pin)
+        return
 
-def set_apn(apn):
-    client = gconf.client_get_default()
-    client.set_string(GSM_APN_PATH, apn)
-
-
-def set_pin(pin):
-    client = gconf.client_get_default()
-    client.set_string(GSM_PIN_PATH, pin)
-
-
-def set_puk(puk):
-    client = gconf.client_get_default()
-    client.set_string(GSM_PUK_PATH, puk)
+    settings = connection.get_settings()
+    gsm_settings = settings['gsm']
+    _set_or_clear(gsm_settings, 'username', username)
+    _set_or_clear(gsm_settings, 'password', password)
+    _set_or_clear(gsm_settings, 'number', number)
+    _set_or_clear(gsm_settings, 'apn', apn)
+    _set_or_clear(gsm_settings, 'pin', pin)
+    connection.update_settings(settings)
diff --git a/extensions/cpsection/modemconfiguration/view.py b/extensions/cpsection/modemconfiguration/view.py
index c31edba..9a508e9 100644
--- a/extensions/cpsection/modemconfiguration/view.py
+++ b/extensions/cpsection/modemconfiguration/view.py
@@ -14,9 +14,8 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  US
 
-import os
-import logging
 from gettext import gettext as _
+import logging
 
 import gtk
 import gobject
@@ -35,10 +34,6 @@ class EntryWithLabel(gtk.HBox):
     def __init__(self, label_text):
         gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING)
 
-        self._timeout_sid = 0
-        self._changed_handler = None
-        self._is_valid = True
-
         self.label = gtk.Label(label_text)
         self.label.modify_fg(gtk.STATE_NORMAL,
                         style.COLOR_SELECTION_GREY.get_gdk_color())
@@ -47,118 +42,14 @@ class EntryWithLabel(gtk.HBox):
         self.label.show()
 
         self._entry = gtk.Entry(25)
-        self._entry.connect('changed', self.__entry_changed_cb)
         self._entry.set_width_chars(25)
         self.pack_start(self._entry, expand=False)
         self._entry.show()
 
-    def __entry_changed_cb(self, widget, data=None):
-        if self._timeout_sid:
-            gobject.source_remove(self._timeout_sid)
-        self._timeout_sid = gobject.timeout_add(APPLY_TIMEOUT,
-                                                self.__timeout_cb)
-
-    def __timeout_cb(self):
-        self._timeout_sid = 0
-
-        if self._entry.get_text() == self.get_value():
-            return False
-
-        try:
-            self.set_value(self._entry.get_text())
-        except ValueError:
-            self._is_valid = False
-        else:
-            self._is_valid = True
-
-        self.notify('is-valid')
-
-        return False
-
-    def set_text_from_model(self):
-        self._entry.set_text(self.get_value())
-
-    def get_value(self):
-        raise NotImplementedError
-
-    def set_value(self):
-        raise NotImplementedError
-
-    def _get_is_valid(self):
-        return self._is_valid
-    is_valid = gobject.property(type=bool, getter=_get_is_valid, default=True)
-
-
-class UsernameEntry(EntryWithLabel):
-    def __init__(self, model):
-        EntryWithLabel.__init__(self, _('Username:'))
-        self._model = model
-
-    def get_value(self):
-        return self._model.get_username()
-
-    def set_value(self, username):
-        self._model.set_username(username)
-
-
-class PasswordEntry(EntryWithLabel):
-    def __init__(self, model):
-        EntryWithLabel.__init__(self, _('Password:'))
-        self._model = model
-
-    def get_value(self):
-        return self._model.get_password()
-
-    def set_value(self, password):
-        self._model.set_password(password)
-
-
-class NumberEntry(EntryWithLabel):
-    def __init__(self, model):
-        EntryWithLabel.__init__(self, _('Number:'))
-        self._model = model
-
-    def get_value(self):
-        return self._model.get_number()
-
-    def set_value(self, number):
-        self._model.set_number(number)
-
-
-class ApnEntry(EntryWithLabel):
-    def __init__(self, model):
-        EntryWithLabel.__init__(self, _('Access Point Name (APN):'))
-        self._model = model
-
-    def get_value(self):
-        return self._model.get_apn()
-
-    def set_value(self, apn):
-        self._model.set_apn(apn)
-
-
-class PinEntry(EntryWithLabel):
-    def __init__(self, model):
-        EntryWithLabel.__init__(self, _('Personal Identity Number (PIN):'))
-        self._model = model
-
-    def get_value(self):
-        return self._model.get_pin()
-
-    def set_value(self, pin):
-        self._model.set_pin(pin)
-
-
-class PukEntry(EntryWithLabel):
-    def __init__(self, model):
-        EntryWithLabel.__init__(self, _('Personal Unblocking Key (PUK):'))
-        self._model = model
+    def get_entry(self):
+        return self._entry
 
-    def get_value(self):
-        return self._model.get_puk()
-
-    def set_value(self, puk):
-        self._model.set_puk(puk)
+    entry = gobject.property(type=object, getter=get_entry)
 
 
 class ModemConfiguration(SectionView):
@@ -167,6 +58,7 @@ class ModemConfiguration(SectionView):
 
         self._model = model
         self.restart_alerts = alerts
+        self._timeout_sid = 0
 
         self.set_border_width(style.DEFAULT_SPACING)
         self.set_spacing(style.DEFAULT_SPACING)
@@ -182,75 +74,71 @@ class ModemConfiguration(SectionView):
         self.pack_start(self._text, False)
         self._text.show()
 
-        self._username_entry = UsernameEntry(model)
-        self._username_entry.connect('notify::is-valid',
-                                     self.__notify_is_valid_cb)
+        self._username_entry = EntryWithLabel(_('Username:'))
+        self._username_entry.entry.connect('changed', self.__entry_changed_cb)
         self._group.add_widget(self._username_entry.label)
         self.pack_start(self._username_entry, expand=False)
         self._username_entry.show()
 
-        self._password_entry = PasswordEntry(model)
-        self._password_entry.connect('notify::is-valid',
-                                     self.__notify_is_valid_cb)
+        self._password_entry = EntryWithLabel(_('Password:'))
+        self._password_entry.entry.connect('changed', self.__entry_changed_cb)
         self._group.add_widget(self._password_entry.label)
         self.pack_start(self._password_entry, expand=False)
         self._password_entry.show()
 
-        self._number_entry = NumberEntry(model)
-        self._number_entry.connect('notify::is-valid',
-                                   self.__notify_is_valid_cb)
+        self._number_entry = EntryWithLabel(_('Number:'))
+        self._number_entry.entry.connect('changed', self.__entry_changed_cb)
         self._group.add_widget(self._number_entry.label)
         self.pack_start(self._number_entry, expand=False)
         self._number_entry.show()
 
-        self._apn_entry = ApnEntry(model)
-        self._apn_entry.connect('notify::is-valid',
-                                self.__notify_is_valid_cb)
+        self._apn_entry = EntryWithLabel(_('Access Point Name (APN):'))
+        self._apn_entry.entry.connect('changed', self.__entry_changed_cb)
         self._group.add_widget(self._apn_entry.label)
         self.pack_start(self._apn_entry, expand=False)
         self._apn_entry.show()
 
-        self._pin_entry = PinEntry(model)
-        self._pin_entry.connect('notify::is-valid',
-                                self.__notify_is_valid_cb)
+        self._pin_entry = EntryWithLabel(_('Personal Identity Number (PIN):'))
+        self._pin_entry.entry.connect('changed', self.__entry_changed_cb)
         self._group.add_widget(self._pin_entry.label)
         self.pack_start(self._pin_entry, expand=False)
         self._pin_entry.show()
 
-        self._puk_entry = PukEntry(model)
-        self._puk_entry.connect('notify::is-valid',
-                                self.__notify_is_valid_cb)
-        self._group.add_widget(self._puk_entry.label)
-        self.pack_start(self._puk_entry, expand=False)
-        self._puk_entry.show()
-
         self.setup()
 
-    def setup(self):
-        self._username_entry.set_text_from_model()
-        self._password_entry.set_text_from_model()
-        self._number_entry.set_text_from_model()
-        self._apn_entry.set_text_from_model()
-        self._pin_entry.set_text_from_model()
-        self._puk_entry.set_text_from_model()
-
-        self.needs_restart = False
-
     def undo(self):
         self._model.undo()
 
-    def _validate(self):
-        if self._username_entry.is_valid and \
-            self._password_entry.is_valid and \
-                self._number_entry.is_valid and \
-                    self._apn_entry.is_valid and \
-                        self._pin_entry.is_valid and \
-                            self._puk_entry.is_valid:
-                                self.props.is_valid = True
-        else:
-            self.props.is_valid = False
+    def _populate_entry(self, entrywithlabel, text):
+        """Populate an entry with text, without triggering its 'changed'
+        handler."""
+        entry = entrywithlabel.entry
+        entry.handler_block_by_func(self.__entry_changed_cb)
+        entry.set_text(text)
+        entry.handler_unblock_by_func(self.__entry_changed_cb)
+
+    def setup(self):
+        settings = self._model.get_modem_settings()
+        self._populate_entry(self._username_entry,
+            settings.get('username', ''))
+        self._populate_entry(self._number_entry, settings.get('number', ''))
+        self._populate_entry(self._apn_entry, settings.get('apn', ''))
+        self._populate_entry(self._password_entry,
+            settings.get('password', ''))
+        self._populate_entry(self._pin_entry, settings.get('pin', ''))
+
+    def __entry_changed_cb(self, widget, data=None):
+        if self._timeout_sid:
+            gobject.source_remove(self._timeout_sid)
+        self._timeout_sid = gobject.timeout_add(APPLY_TIMEOUT,
+                                                self.__timeout_cb)
 
-    def __notify_is_valid_cb(self, entry, pspec):
-        if entry.is_valid:
-            self.needs_restart = True
-        self._validate()
+    def __timeout_cb(self):
+        self._timeout_sid = 0
+        settings = {}
+        settings['username'] = self._username_entry.entry.get_text()
+        settings['password'] = self._password_entry.entry.get_text()
+        settings['number'] = self._number_entry.entry.get_text()
+        settings['apn'] = self._apn_entry.entry.get_text()
+        settings['pin'] = self._pin_entry.entry.get_text()
+        self._model.set_modem_settings(settings)
diff --git a/extensions/cpsection/network/model.py b/extensions/cpsection/network/model.py
index 916ce8c..4ddab35 100644
--- a/extensions/cpsection/network/model.py
+++ b/extensions/cpsection/network/model.py
@@ -15,6 +15,8 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #
 
+import logging
+
 import dbus
 from gettext import gettext as _
 import gconf
@@ -112,11 +114,21 @@ def clear_registration():
 def clear_networks():
     """Clear saved passwords and network configurations.
     """
-    network.clear_wifi_connections()
+    try:
+        connections = network.get_connections()
+    except dbus.DBusException:
+        logging.debug('NetworkManager not available')
+        return
+    connections.clear()
 
 
 def have_networks():
-    return network.have_wifi_connections()
+    try:
+        connections = network.get_connections()
+        return len(connections.get_list()) > 0
+    except dbus.DBusException:
+        logging.debug('NetworkManager not available')
+        return False
 
 
 def get_publish_information():
diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
index 789ea13..213fa41 100644
--- a/extensions/deviceicon/network.py
+++ b/extensions/deviceicon/network.py
@@ -48,17 +48,6 @@ from jarabe.view.pulsingicon import PulsingIcon
 
 IP_ADDRESS_TEXT_TEMPLATE = _('IP address: %s')
 
-_NM_SERVICE = 'org.freedesktop.NetworkManager'
-_NM_IFACE = 'org.freedesktop.NetworkManager'
-_NM_PATH = '/org/freedesktop/NetworkManager'
-_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
-_NM_WIRED_IFACE = 'org.freedesktop.NetworkManager.Device.Wired'
-_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
-_NM_SERIAL_IFACE = 'org.freedesktop.NetworkManager.Device.Serial'
-_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
-_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
-_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
-
 _GSM_STATE_NOT_READY = 0
 _GSM_STATE_DISCONNECTED = 1
 _GSM_STATE_CONNECTING = 2
@@ -413,24 +402,24 @@ class WirelessDeviceView(ToolButton):
 
         self._device_props = dbus.Interface(self._device,
                                             dbus.PROPERTIES_IFACE)
-        self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+        self._device_props.GetAll(network.NM_DEVICE_IFACE, byte_arrays=True,
                               reply_handler=self.__get_device_props_reply_cb,
                               error_handler=self.__get_device_props_error_cb)
 
-        self._device_props.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
+        self._device_props.Get(network.NM_WIRELESS_IFACE, 'ActiveAccessPoint',
                                reply_handler=self.__get_active_ap_reply_cb,
                                error_handler=self.__get_active_ap_error_cb)
 
         self._bus.add_signal_receiver(self.__state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
 
     def disconnect(self):
         self._bus.remove_signal_receiver(self.__state_changed_cb,
                                          signal_name='StateChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
 
     def __get_device_props_reply_cb(self, properties):
         if 'State' in properties:
@@ -447,22 +436,22 @@ class WirelessDeviceView(ToolButton):
                     self.__ap_properties_changed_cb,
                     signal_name='PropertiesChanged',
                     path=self._active_ap_op,
-                    dbus_interface=_NM_ACCESSPOINT_IFACE)
+                    dbus_interface=network.NM_ACCESSPOINT_IFACE)
             if active_ap_op == '/':
                 self._active_ap_op = None
                 return
             self._active_ap_op = active_ap_op
-            active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op)
+            active_ap = self._bus.get_object(network.NM_SERVICE, active_ap_op)
             props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
 
-            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
+            props.GetAll(network.NM_ACCESSPOINT_IFACE, byte_arrays=True,
                          reply_handler=self.__get_all_ap_props_reply_cb,
                          error_handler=self.__get_all_ap_props_error_cb)
 
             self._bus.add_signal_receiver(self.__ap_properties_changed_cb,
                                           signal_name='PropertiesChanged',
                                           path=self._active_ap_op,
-                                          dbus_interface=_NM_ACCESSPOINT_IFACE)
+                                          dbus_interface=network.NM_ACCESSPOINT_IFACE)
 
     def __get_active_ap_error_cb(self, err):
         logging.error('Error getting the active access point: %s', err)
@@ -470,7 +459,7 @@ class WirelessDeviceView(ToolButton):
     def __state_changed_cb(self, new_state, old_state, reason):
         self._device_state = new_state
         self._update_state()
-        self._device_props.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
+        self._device_props.Get(network.NM_WIRELESS_IFACE, 'ActiveAccessPoint',
                                reply_handler=self.__get_active_ap_reply_cb,
                                error_handler=self.__get_active_ap_error_cb)
 
@@ -528,11 +517,11 @@ class WirelessDeviceView(ToolButton):
         if self._active_ap_op is not None:
             state = self._device_state
         else:
-            state = network.DEVICE_STATE_UNKNOWN
+            state = network.NM_DEVICE_STATE_UNKNOWN
 
         if self._mode != network.NM_802_11_MODE_ADHOC and \
                 network.is_sugar_adhoc_network(self._name) == False:
-            if state == network.DEVICE_STATE_ACTIVATED:
+            if state == network.NM_DEVICE_STATE_ACTIVATED:
                 icon_name = '%s-connected' % 'network-wireless'
             else:
                 icon_name = 'network-wireless'
@@ -542,21 +531,19 @@ class WirelessDeviceView(ToolButton):
                 self._icon.props.icon_name = icon_name
         else:
             channel = network.frequency_to_channel(self._frequency)
-            if state == network.DEVICE_STATE_ACTIVATED:
+            if state == network.NM_DEVICE_STATE_ACTIVATED:
                 self._icon.props.icon_name = 'network-adhoc-%s-connected' \
                         % channel
             else:
                 self._icon.props.icon_name = 'network-adhoc-%s' % channel
             self._icon.props.base_color = profile.get_color()
 
-        if state == network.DEVICE_STATE_PREPARE or \
-           state == network.DEVICE_STATE_CONFIG or \
-           state == network.DEVICE_STATE_NEED_AUTH or \
-           state == network.DEVICE_STATE_IP_CONFIG:
+        if (state >= network.NM_DEVICE_STATE_PREPARE) and \
+           (state <= network.NM_DEVICE_STATE_IP_CONFIG):
             self._palette.set_connecting()
             self._icon.props.pulsing = True
-        elif state == network.DEVICE_STATE_ACTIVATED:
-            address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
+        elif state == network.NM_DEVICE_STATE_ACTIVATED:
+            address = self._device_props.Get(network.NM_DEVICE_IFACE, 'Ip4Address')
             self._palette.set_connected_with_frequency(self._frequency,
                                                        address)
             self._icon.props.pulsing = False
@@ -571,11 +558,6 @@ class WirelessDeviceView(ToolButton):
         self._icon.props.base_color = self._color
 
     def __deactivate_connection_cb(self, palette, data=None):
-        if self._mode == network.NM_802_11_MODE_INFRA:
-            connection = network.find_connection_by_ssid(self._name)
-            if connection:
-                connection.disable_autoconnect()
-
         network.disconnect_access_points([self._active_ap_op])
 
     def __activate_reply_cb(self, connection):
@@ -620,20 +602,20 @@ class OlpcMeshDeviceView(ToolButton):
 
         self._device_props = dbus.Interface(self._device,
                                             dbus.PROPERTIES_IFACE)
-        self._device_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel',
+        self._device_props.Get(network.NM_OLPC_MESH_IFACE, 'ActiveChannel',
                             reply_handler=self.__get_active_channel_reply_cb,
                             error_handler=self.__get_active_channel_error_cb)
 
         self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
                                       signal_name='PropertiesChanged',
                                       path=device.object_path,
-                                      dbus_interface=_NM_OLPC_MESH_IFACE)
+                                      dbus_interface=network.NM_OLPC_MESH_IFACE)
 
     def disconnect(self):
         self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
                                          signal_name='PropertiesChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_OLPC_MESH_IFACE)
+                                         dbus_interface=network.NM_OLPC_MESH_IFACE)
 
     def __get_active_channel_reply_cb(self, channel):
         self._channel = channel
@@ -659,16 +641,14 @@ class OlpcMeshDeviceView(ToolButton):
     def _update(self):
         state = self._device_state
 
-        if state in [network.DEVICE_STATE_PREPARE,
-                     network.DEVICE_STATE_CONFIG,
-                     network.DEVICE_STATE_NEED_AUTH,
-                     network.DEVICE_STATE_IP_CONFIG]:
+        if (state >= network.NM_DEVICE_STATE_PREPARE) and \
+           (state <= network.NM_DEVICE_STATE_IP_CONFIG):
             self._icon.props.base_color = self._inactive_color
             self._icon.props.pulse_color = profile.get_color()
             self._palette.set_connecting()
             self._icon.props.pulsing = True
-        elif state == network.DEVICE_STATE_ACTIVATED:
-            address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
+        elif state == network.NM_DEVICE_STATE_ACTIVATED:
+            address = self._device_props.Get(network.NM_DEVICE_IFACE, 'Ip4Address')
             self._palette.set_connected_with_channel(self._channel, address)
             self._icon.props.base_color = profile.get_color()
             self._icon.props.pulsing = False
@@ -679,23 +659,23 @@ class OlpcMeshDeviceView(ToolButton):
         self._update()
 
     def __deactivate_connection(self, palette, data=None):
-        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-        netmgr = dbus.Interface(obj, _NM_IFACE)
+        obj = self._bus.get_object(network.NM_SERVICE, network.NM_PATH)
+        netmgr = dbus.Interface(obj, network.NM_IFACE)
         netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
-        active_connections_o = netmgr_props.Get(_NM_IFACE,
+        active_connections_o = netmgr_props.Get(network.NM_IFACE,
                                                 'ActiveConnections')
 
         for conn_o in active_connections_o:
             # The connection path for a mesh connection is the device itself.
-            obj = self._bus.get_object(_NM_IFACE, conn_o)
+            obj = self._bus.get_object(network.NM_IFACE, conn_o)
             props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
-            ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+            ap_op = props.Get(network.NM_ACTIVE_CONN_IFACE, 'SpecificObject')
 
             try:
-                obj = self._bus.get_object(_NM_IFACE, ap_op)
+                obj = self._bus.get_object(network.NM_IFACE, ap_op)
                 props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
-                device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
-                if device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+                device_type = props.Get(network.NM_DEVICE_IFACE, 'DeviceType')
+                if device_type == network.NM_DEVICE_TYPE_OLPC_MESH:
                     netmgr.DeactivateConnection(conn_o)
                     break
             except dbus.exceptions.DBusException:
@@ -742,11 +722,11 @@ class GsmDeviceView(TrayIcon):
         self._bus.add_signal_receiver(self.__state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
         self._bus.add_signal_receiver(self.__ppp_stats_changed_cb,
                                       signal_name='PppStats',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_SERIAL_IFACE)
+                                      dbus_interface=network.NM_MODEM_IFACE)
 
     def create_palette(self):
         palette = GsmPalette()
@@ -758,7 +738,7 @@ class GsmDeviceView(TrayIcon):
         self._palette = palette
 
         props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
-        props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+        props.GetAll(network.NM_DEVICE_IFACE, byte_arrays=True,
                      reply_handler=self.__current_state_check_cb,
                      error_handler=self.__current_state_check_error_cb)
 
@@ -767,14 +747,9 @@ class GsmDeviceView(TrayIcon):
     def __gsm_connect_cb(self, palette, data=None):
         connection = network.find_gsm_connection()
         if connection is not None:
-            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-            netmgr = dbus.Interface(obj, _NM_IFACE)
-            netmgr.ActivateConnection(network.SETTINGS_SERVICE,
-                                        connection.path,
-                                        self._device.object_path,
-                                        '/',
-                                        reply_handler=self.__connect_cb,
-                                        error_handler=self.__connect_error_cb)
+            connection.activate(self._device.object_path,
+                                reply_handler=self.__connect_cb,
+                                error_handler=self.__connect_error_cb)
         else:
             self._palette.add_alert(_('No GSM connection available.'), \
                                         _('Create a connection in the ' \
@@ -788,15 +763,15 @@ class GsmDeviceView(TrayIcon):
         raise RuntimeError('Error when connecting to gsm device, %s' % error)
 
     def __gsm_disconnect_cb(self, palette, data=None):
-        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-        netmgr = dbus.Interface(obj, _NM_IFACE)
+        obj = self._bus.get_object(network.NM_SERVICE, network.NM_PATH)
+        netmgr = dbus.Interface(obj, network.NM_IFACE)
         netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
-        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+        active_connections_o = netmgr_props.Get(network.NM_IFACE, 'ActiveConnections')
 
         for conn_o in active_connections_o:
-            obj = self._bus.get_object(_NM_IFACE, conn_o)
+            obj = self._bus.get_object(network.NM_IFACE, conn_o)
             props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
-            devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices')
+            devices = props.Get(network.NM_ACTIVE_CONN_IFACE, 'Devices')
             if self._device.object_path in devices:
                 netmgr.DeactivateConnection(
                         conn_o,
@@ -824,13 +799,12 @@ class GsmDeviceView(TrayIcon):
     def _update_state(self, state, old_state, reason):
         gsm_state = None
 
-        if state is network.DEVICE_STATE_ACTIVATED:
+        if state is network.NM_DEVICE_STATE_ACTIVATED:
             gsm_state = _GSM_STATE_CONNECTED
             connection = network.find_gsm_connection()
             if connection is not None:
-                connection.set_connected()
                 self._connection_timestamp = time.time() - \
-                        connection.get_settings().connection.timestamp
+                        connection.get_settings('connection')['timestamp']
                 self._connection_time_handler = gobject.timeout_add_seconds( \
                         1, self.__connection_timecount_cb)
                 self._palette.update_connection_time()
@@ -838,7 +812,7 @@ class GsmDeviceView(TrayIcon):
                 if self._palette is not None:
                     self._palette.connection_info_box.show()
 
-        elif state is network.DEVICE_STATE_DISCONNECTED:
+        elif state is network.NM_DEVICE_STATE_DISCONNECTED:
             gsm_state = _GSM_STATE_DISCONNECTED
             self._connection_timestamp = 0
             if self._connection_time_handler is not None:
@@ -846,18 +820,16 @@ class GsmDeviceView(TrayIcon):
             if self._palette is not None:
                 self._palette.connection_info_box.hide()
 
-        elif state in [network.DEVICE_STATE_UNMANAGED,
-                       network.DEVICE_STATE_UNAVAILABLE,
-                       network.DEVICE_STATE_UNKNOWN]:
+        elif state in [network.NM_DEVICE_STATE_UNMANAGED,
+                       network.NM_DEVICE_STATE_UNAVAILABLE,
+                       network.NM_DEVICE_STATE_UNKNOWN]:
             gsm_state = _GSM_STATE_NOT_READY
 
-        elif state in [network.DEVICE_STATE_PREPARE,
-                       network.DEVICE_STATE_CONFIG,
-                       network.DEVICE_STATE_IP_CONFIG,
-                       network.DEVICE_STATE_NEED_AUTH]:
+        elif (state >= network.NM_DEVICE_STATE_PREPARE) and \
+             (state <= network.NM_DEVICE_STATE_IP_CONFIG):
             gsm_state = _GSM_STATE_CONNECTING
 
-        elif state == network.DEVICE_STATE_FAILED:
+        elif state == network.NM_DEVICE_STATE_FAILED:
             gsm_state = _GSM_STATE_FAILED
 
         if self._palette is not None:
@@ -867,7 +839,7 @@ class GsmDeviceView(TrayIcon):
         self._bus.remove_signal_receiver(self.__state_changed_cb,
                                          signal_name='StateChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
 
     def __ppp_stats_changed_cb(self, in_bytes, out_bytes):
         self._palette.update_stats(in_bytes, out_bytes)
@@ -903,14 +875,14 @@ class MeshDeviceObserver(object):
         self._tray = tray
 
         props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
-        props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+        props.GetAll(network.NM_DEVICE_IFACE, byte_arrays=True,
                      reply_handler=self.__get_device_props_reply_cb,
                      error_handler=self.__get_device_props_error_cb)
 
         self._bus.add_signal_receiver(self.__state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
 
     def _remove_device_view(self):
         self._device_view.disconnect()
@@ -924,7 +896,7 @@ class MeshDeviceObserver(object):
         self._bus.remove_signal_receiver(self.__state_changed_cb,
                                          signal_name='StateChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
 
     def __get_device_props_reply_cb(self, properties):
         if 'State' in properties:
@@ -937,10 +909,8 @@ class MeshDeviceObserver(object):
         self._update_state(new_state)
 
     def _update_state(self, state):
-        if state in (network.DEVICE_STATE_PREPARE, network.DEVICE_STATE_CONFIG,
-                     network.DEVICE_STATE_NEED_AUTH,
-                     network.DEVICE_STATE_IP_CONFIG,
-                     network.DEVICE_STATE_ACTIVATED):
+        if (state >= network.NM_DEVICE_STATE_PREPARE) and \
+           (state <= network.NM_DEVICE_STATE_ACTIVATED):
             if self._device_view is not None:
                 self._device_view.update_state(state)
                 return
@@ -961,20 +931,20 @@ class WiredDeviceObserver(object):
         self._tray = tray
 
         props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
-        props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+        props.GetAll(network.NM_DEVICE_IFACE, byte_arrays=True,
                      reply_handler=self.__get_device_props_reply_cb,
                      error_handler=self.__get_device_props_error_cb)
 
         self._bus.add_signal_receiver(self.__state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
 
     def disconnect(self):
         self._bus.remove_signal_receiver(self.__state_changed_cb,
                                          signal_name='StateChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
 
     def __get_device_props_reply_cb(self, properties):
         if 'State' in properties:
@@ -987,10 +957,10 @@ class WiredDeviceObserver(object):
         self._update_state(new_state)
 
     def _update_state(self, state):
-        if state == network.DEVICE_STATE_ACTIVATED:
+        if state == network.NM_DEVICE_STATE_ACTIVATED:
             props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
-            address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
-            speed = props.Get(_NM_WIRED_IFACE, 'Speed')
+            address = props.Get(network.NM_DEVICE_IFACE, 'Ip4Address')
+            speed = props.Get(network.NM_WIRED_IFACE, 'Speed')
             self._device_view = WiredDeviceView(speed, address)
             self._tray.add_device(self._device_view)
         else:
@@ -1023,10 +993,10 @@ class NetworkManagerObserver(object):
         self._tray = tray
 
         try:
-            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-            self._netmgr = dbus.Interface(obj, _NM_IFACE)
+            obj = self._bus.get_object(network.NM_SERVICE, network.NM_PATH)
+            self._netmgr = dbus.Interface(obj, network.NM_IFACE)
         except dbus.DBusException:
-            logging.error('%s service not available', _NM_SERVICE)
+            logging.error('%s service not available', network.NM_SERVICE)
             return
 
         self._netmgr.GetDevices(reply_handler=self.__get_devices_reply_cb,
@@ -1034,10 +1004,10 @@ class NetworkManagerObserver(object):
 
         self._bus.add_signal_receiver(self.__device_added_cb,
                                       signal_name='DeviceAdded',
-                                      dbus_interface=_NM_IFACE)
+                                      dbus_interface=network.NM_IFACE)
         self._bus.add_signal_receiver(self.__device_removed_cb,
                                       signal_name='DeviceRemoved',
-                                      dbus_interface=_NM_IFACE)
+                                      dbus_interface=network.NM_IFACE)
 
     def __get_devices_reply_cb(self, devices):
         for device_op in devices:
@@ -1047,20 +1017,20 @@ class NetworkManagerObserver(object):
         logging.error('Failed to get devices: %s', err)
 
     def _check_device(self, device_op):
-        nm_device = self._bus.get_object(_NM_SERVICE, device_op)
+        nm_device = self._bus.get_object(network.NM_SERVICE, device_op)
         props = dbus.Interface(nm_device, dbus.PROPERTIES_IFACE)
 
-        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
-        if device_type == network.DEVICE_TYPE_802_3_ETHERNET:
+        device_type = props.Get(network.NM_DEVICE_IFACE, 'DeviceType')
+        if device_type == network.NM_DEVICE_TYPE_ETHERNET:
             device = WiredDeviceObserver(nm_device, self._tray)
             self._devices[device_op] = device
-        elif device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+        elif device_type == network.NM_DEVICE_TYPE_WIFI:
             device = WirelessDeviceObserver(nm_device, self._tray)
             self._devices[device_op] = device
-        elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+        elif device_type == network.NM_DEVICE_TYPE_OLPC_MESH:
             device = MeshDeviceObserver(nm_device, self._tray)
             self._devices[device_op] = device
-        elif device_type == network.DEVICE_TYPE_GSM_MODEM:
+        elif device_type == network.NM_DEVICE_TYPE_MODEM:
             device = GsmDeviceObserver(nm_device, self._tray)
             self._devices[device_op] = device
 
diff --git a/src/jarabe/desktop/keydialog.py b/src/jarabe/desktop/keydialog.py
index c72f498..17ff6bd 100644
--- a/src/jarabe/desktop/keydialog.py
+++ b/src/jarabe/desktop/keydialog.py
@@ -22,7 +22,6 @@ import gtk
 import dbus
 
 from jarabe.model import network
-from jarabe.model.network import Secrets
 
 
 IW_AUTH_ALG_OPEN_SYSTEM = 'open'
@@ -74,12 +73,10 @@ class CanceledKeyRequestError(dbus.DBusException):
 
 
 class KeyDialog(gtk.Dialog):
-    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
-                 response):
+    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
         gtk.Dialog.__init__(self, flags=gtk.DIALOG_MODAL)
         self.set_title('Wireless Key Required')
 
-        self._settings = settings
         self._response = response
         self._entry = None
         self._ssid = ssid
@@ -121,10 +118,9 @@ class KeyDialog(gtk.Dialog):
 
 
 class WEPKeyDialog(KeyDialog):
-    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
-                 response):
+    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
         KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
-                           dev_caps, settings, response)
+                           dev_caps, response)
 
         # WEP key type
         self.key_store = gtk.ListStore(str, int)
@@ -192,10 +188,8 @@ class WEPKeyDialog(KeyDialog):
 
     def create_security(self):
         (key, auth_alg) = self._get_security()
-        secrets = Secrets(self._settings)
-        secrets.wep_key = key
-        secrets.auth_alg = auth_alg
-        return secrets
+        wsec = {'wep-key0': key, 'auth-alg': auth_alg}
+        return {'802-11-wireless-security': wsec}
 
     def _update_response_sensitivity(self, ignored=None):
         key = self._entry.get_text()
@@ -219,10 +213,9 @@ class WEPKeyDialog(KeyDialog):
 
 
 class WPAKeyDialog(KeyDialog):
-    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, settings,
-                 response):
+    def __init__(self, ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
         KeyDialog.__init__(self, ssid, flags, wpa_flags, rsn_flags,
-                           dev_caps, settings, response)
+                           dev_caps, response)
         self.add_key_entry()
 
         self.store = gtk.ListStore(str)
@@ -272,9 +265,8 @@ class WPAKeyDialog(KeyDialog):
         print 'Key: %s' % key
 
     def create_security(self):
-        secrets = Secrets(self._settings)
-        secrets.psk = self._get_security()
-        return secrets
+        wsec = {'psk': self._get_security()}
+        return {'802-11-wireless-security': wsec}
 
     def _update_response_sensitivity(self, ignored=None):
         key = self._entry.get_text()
@@ -291,14 +283,14 @@ class WPAKeyDialog(KeyDialog):
         return False
 
 
-def create(ssid, flags, wpa_flags, rsn_flags, dev_caps, settings, response):
+def create(ssid, flags, wpa_flags, rsn_flags, dev_caps, response):
     if wpa_flags == network.NM_802_11_AP_SEC_NONE and \
             rsn_flags == network.NM_802_11_AP_SEC_NONE:
         key_dialog = WEPKeyDialog(ssid, flags, wpa_flags, rsn_flags,
-                                  dev_caps, settings, response)
+                                  dev_caps, response)
     else:
         key_dialog = WPAKeyDialog(ssid, flags, wpa_flags, rsn_flags,
-                                  dev_caps, settings, response)
+                                  dev_caps, response)
 
     key_dialog.connect('response', _key_dialog_response_cb)
     key_dialog.show_all()
diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
index 6d5bb48..174d25e 100644
--- a/src/jarabe/desktop/meshbox.py
+++ b/src/jarabe/desktop/meshbox.py
@@ -48,15 +48,6 @@ from jarabe.model.adhoc import get_adhoc_manager_instance
 from jarabe.journal import misc
 
 
-_NM_SERVICE = 'org.freedesktop.NetworkManager'
-_NM_IFACE = 'org.freedesktop.NetworkManager'
-_NM_PATH = '/org/freedesktop/NetworkManager'
-_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
-_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
-_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
-_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
-_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
-
 _AP_ICON_NAME = 'network-wireless'
 _OLPC_MESH_ICON_NAME = 'network-mesh'
 
@@ -244,7 +235,7 @@ class DeviceObserver(gobject.GObject):
         self._bus = dbus.SystemBus()
         self.device = device
 
-        wireless = dbus.Interface(device, _NM_WIRELESS_IFACE)
+        wireless = dbus.Interface(device, network.NM_WIRELESS_IFACE)
         wireless.GetAccessPoints(
             reply_handler=self._get_access_points_reply_cb,
             error_handler=self._get_access_points_error_cb)
@@ -252,22 +243,22 @@ class DeviceObserver(gobject.GObject):
         self._bus.add_signal_receiver(self.__access_point_added_cb,
                                       signal_name='AccessPointAdded',
                                       path=device.object_path,
-                                      dbus_interface=_NM_WIRELESS_IFACE)
+                                      dbus_interface=network.NM_WIRELESS_IFACE)
         self._bus.add_signal_receiver(self.__access_point_removed_cb,
                                       signal_name='AccessPointRemoved',
                                       path=device.object_path,
-                                      dbus_interface=_NM_WIRELESS_IFACE)
+                                      dbus_interface=network.NM_WIRELESS_IFACE)
 
     def _get_access_points_reply_cb(self, access_points_o):
         for ap_o in access_points_o:
-            ap = self._bus.get_object(_NM_SERVICE, ap_o)
+            ap = self._bus.get_object(network.NM_SERVICE, ap_o)
             self.emit('access-point-added', ap)
 
     def _get_access_points_error_cb(self, err):
         logging.error('Failed to get access points: %s', err)
 
     def __access_point_added_cb(self, access_point_o):
-        ap = self._bus.get_object(_NM_SERVICE, access_point_o)
+        ap = self._bus.get_object(network.NM_SERVICE, access_point_o)
         self.emit('access-point-added', ap)
 
     def __access_point_removed_cb(self, access_point_o):
@@ -277,11 +268,11 @@ class DeviceObserver(gobject.GObject):
         self._bus.remove_signal_receiver(self.__access_point_added_cb,
                                          signal_name='AccessPointAdded',
                                          path=self.device.object_path,
-                                         dbus_interface=_NM_WIRELESS_IFACE)
+                                         dbus_interface=network.NM_WIRELESS_IFACE)
         self._bus.remove_signal_receiver(self.__access_point_removed_cb,
                                          signal_name='AccessPointRemoved',
                                          path=self.device.object_path,
-                                         dbus_interface=_NM_WIRELESS_IFACE)
+                                         dbus_interface=network.NM_WIRELESS_IFACE)
 
 
 class NetworkManagerObserver(object):
@@ -301,10 +292,9 @@ class NetworkManagerObserver(object):
     def listen(self):
         try:
             self._bus = dbus.SystemBus()
-            obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-            self._netmgr = dbus.Interface(obj, _NM_IFACE)
+            self._netmgr = network.get_manager()
         except dbus.DBusException:
-            logging.debug('%s service not available', _NM_SERVICE)
+            logging.debug('NetworkManager not available')
             return
 
         self._netmgr.GetDevices(reply_handler=self.__get_devices_reply_cb,
@@ -312,38 +302,37 @@ class NetworkManagerObserver(object):
 
         self._bus.add_signal_receiver(self.__device_added_cb,
                                       signal_name='DeviceAdded',
-                                      dbus_interface=_NM_IFACE)
+                                      dbus_interface=network.NM_IFACE)
         self._bus.add_signal_receiver(self.__device_removed_cb,
                                       signal_name='DeviceRemoved',
-                                      dbus_interface=_NM_IFACE)
+                                      dbus_interface=network.NM_IFACE)
         self._bus.add_signal_receiver(self.__properties_changed_cb,
                                       signal_name='PropertiesChanged',
-                                      dbus_interface=_NM_IFACE)
+                                      dbus_interface=network.NM_IFACE)
 
-        settings = network.get_settings()
-        if settings is not None:
-            settings.secrets_request.connect(self.__secrets_request_cb)
+        secret_agent = network.get_secret_agent()
+        if secret_agent is not None:
+            secret_agent.secrets_request.connect(self.__secrets_request_cb)
 
     def __secrets_request_cb(self, **kwargs):
         # FIXME It would be better to do all of this async, but I cannot think
         # of a good way to. NM could really use some love here.
 
         netmgr_props = dbus.Interface(self._netmgr, dbus.PROPERTIES_IFACE)
-        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+        active_connections_o = netmgr_props.Get(network.NM_IFACE, 'ActiveConnections')
 
         for conn_o in active_connections_o:
-            obj = self._bus.get_object(_NM_IFACE, conn_o)
+            obj = self._bus.get_object(network.NM_IFACE, conn_o)
             props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
-            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
+            state = props.Get(network.NM_ACTIVE_CONN_IFACE, 'State')
             if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
-                ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+                ap_o = props.Get(network.NM_ACTIVE_CONN_IFACE, 'SpecificObject')
                 found = False
                 if ap_o != '/':
                     for net in self._box.wireless_networks.values():
                         if net.find_ap(ap_o) is not None:
                             found = True
-                            settings = kwargs['connection'].get_settings()
-                            net.create_keydialog(settings, kwargs['response'])
+                            net.create_keydialog(kwargs['response'])
                 if not found:
                     logging.error('Could not determine AP for specific object'
                                   ' %s', conn_o)
@@ -356,11 +345,11 @@ class NetworkManagerObserver(object):
         logging.error('Failed to get devices: %s', err)
 
     def _check_device(self, device_o):
-        device = self._bus.get_object(_NM_SERVICE, device_o)
+        device = self._bus.get_object(network.NM_SERVICE, device_o)
         props = dbus.Interface(device, dbus.PROPERTIES_IFACE)
 
-        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
-        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+        device_type = props.Get(network.NM_DEVICE_IFACE, 'DeviceType')
+        if device_type == network.NM_DEVICE_TYPE_WIFI:
             self._devices[device_o] = DeviceObserver(device)
             self._devices[device_o].connect('access-point-added',
                                             self.__ap_added_cb)
@@ -368,7 +357,7 @@ class NetworkManagerObserver(object):
                                             self.__ap_removed_cb)
             if self._have_adhoc_networks:
                 self._box.add_adhoc_networks(device)
-        elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+        elif device_type == network.NM_DEVICE_TYPE_OLPC_MESH:
             self._olpc_mesh_device_o = device_o
             self._box.enable_olpc_mesh(device)
 
diff --git a/src/jarabe/desktop/networkviews.py b/src/jarabe/desktop/networkviews.py
index 677452d..31a366c 100644
--- a/src/jarabe/desktop/networkviews.py
+++ b/src/jarabe/desktop/networkviews.py
@@ -42,15 +42,6 @@ from jarabe.model.network import WirelessSecurity
 from jarabe.model.adhoc import get_adhoc_manager_instance
 
 
-_NM_SERVICE = 'org.freedesktop.NetworkManager'
-_NM_IFACE = 'org.freedesktop.NetworkManager'
-_NM_PATH = '/org/freedesktop/NetworkManager'
-_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
-_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
-_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
-_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
-_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
-
 _AP_ICON_NAME = 'network-wireless'
 _OLPC_MESH_ICON_NAME = 'network-mesh'
 
@@ -105,24 +96,21 @@ class WirelessNetworkView(CanvasPulsingIcon):
         self._update_badge()
 
         interface_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
-        interface_props.Get(_NM_DEVICE_IFACE, 'State',
-                            reply_handler=self.__get_device_state_reply_cb,
-                            error_handler=self.__get_device_state_error_cb)
-        interface_props.Get(_NM_WIRELESS_IFACE, 'WirelessCapabilities',
+        interface_props.Get(network.NM_WIRELESS_IFACE, 'WirelessCapabilities',
                             reply_handler=self.__get_device_caps_reply_cb,
                             error_handler=self.__get_device_caps_error_cb)
-        interface_props.Get(_NM_WIRELESS_IFACE, 'ActiveAccessPoint',
+        interface_props.Get(network.NM_WIRELESS_IFACE, 'ActiveAccessPoint',
                             reply_handler=self.__get_active_ap_reply_cb,
                             error_handler=self.__get_active_ap_error_cb)
 
         self._bus.add_signal_receiver(self.__device_state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
         self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
                                       signal_name='PropertiesChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_WIRELESS_IFACE)
+                                      dbus_interface=network.NM_WIRELESS_IFACE)
 
     def _create_palette(self):
         icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
@@ -168,6 +156,10 @@ class WirelessNetworkView(CanvasPulsingIcon):
 
     def __get_active_ap_reply_cb(self, ap_path):
         self.__update_active_ap(ap_path)
+        interface_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+        interface_props.Get(network.NM_DEVICE_IFACE, 'State',
+                            reply_handler=self.__get_device_state_reply_cb,
+                            error_handler=self.__get_device_state_error_cb)
 
     def __get_active_ap_error_cb(self, err):
         logging.error('Error getting the active access point: %s', err)
@@ -182,6 +174,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
         self._device_state = state
         self._update_state()
         self._update_color()
+        self._update_icon()
         self._update_badge()
 
     def __get_device_state_error_cb(self, err):
@@ -192,7 +185,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
                 network.is_sugar_adhoc_network(self._name):
             channel = max([1] + [ap.channel for ap in
                                  self._access_points.values()])
-            if self._device_state == network.DEVICE_STATE_ACTIVATED and \
+            if self._device_state == network.NM_DEVICE_STATE_ACTIVATED and \
                     self._active_ap is not None:
                 icon_name = 'network-adhoc-%s-connected' % channel
             else:
@@ -201,7 +194,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
             icon = self._palette.props.icon
             icon.props.icon_name = icon_name
         else:
-            if self._device_state == network.DEVICE_STATE_ACTIVATED and \
+            if self._device_state == network.NM_DEVICE_STATE_ACTIVATED and \
                     self._active_ap is not None:
                 icon_name = '%s-connected' % _AP_ICON_NAME
             else:
@@ -232,22 +225,19 @@ class WirelessNetworkView(CanvasPulsingIcon):
         if self._active_ap is not None:
             state = self._device_state
         else:
-            state = network.DEVICE_STATE_UNKNOWN
+            state = network.NM_DEVICE_STATE_UNKNOWN
 
-        if state == network.DEVICE_STATE_PREPARE or \
-           state == network.DEVICE_STATE_CONFIG or \
-           state == network.DEVICE_STATE_NEED_AUTH or \
-           state == network.DEVICE_STATE_IP_CONFIG:
+        if state == network.NM_DEVICE_STATE_PREPARE or \
+           state == network.NM_DEVICE_STATE_CONFIG or \
+           state == network.NM_DEVICE_STATE_NEED_AUTH or \
+           state == network.NM_DEVICE_STATE_IP_CONFIG:
             if self._disconnect_item:
                 self._disconnect_item.show()
             self._connect_item.hide()
             self._palette.props.secondary_text = _('Connecting...')
             self.props.pulsing = True
-        elif state == network.DEVICE_STATE_ACTIVATED:
-            connection = network.find_connection_by_ssid(self._name)
-            if connection is not None:
-                if self._mode == network.NM_802_11_MODE_INFRA:
-                    connection.set_connected()
+        elif state == network.NM_DEVICE_STATE_ACTIVATED:
+            network.set_connected()
             if self._disconnect_item:
                 self._disconnect_item.show()
             self._connect_item.hide()
@@ -269,11 +259,6 @@ class WirelessNetworkView(CanvasPulsingIcon):
             self.alpha = 1.0
 
     def _disconnect_activate_cb(self, item):
-        if self._mode == network.NM_802_11_MODE_INFRA:
-            connection = network.find_connection_by_ssid(self._name)
-            if connection:
-                connection.disable_autoconnect()
-
         ap_paths = self._access_points.keys()
         network.disconnect_access_points(ap_paths)
 
@@ -317,7 +302,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
             return None
 
         if (self._rsn_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) and \
-                (self._device_caps & network.NM_802_11_DEVICE_CAP_RSN):
+                (self._device_caps & network.NM_WIFI_DEVICE_CAP_RSN):
             # WPA2 PSK first
             pairwise = self._add_ciphers_from_flags(self._rsn_flags, True)
             group = self._add_ciphers_from_flags(self._rsn_flags, False)
@@ -329,7 +314,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
             return wireless_security
 
         if (self._wpa_flags & network.NM_802_11_AP_SEC_KEY_MGMT_PSK) and \
-                (self._device_caps & network.NM_802_11_DEVICE_CAP_WPA):
+                (self._device_caps & network.NM_WIFI_DEVICE_CAP_WPA):
             # WPA PSK
             pairwise = self._add_ciphers_from_flags(self._wpa_flags, True)
             group = self._add_ciphers_from_flags(self._wpa_flags, False)
@@ -347,54 +332,47 @@ class WirelessNetworkView(CanvasPulsingIcon):
         self._connect()
 
     def _connect(self):
+        # Activate existing connection, if there is one
         connection = network.find_connection_by_ssid(self._name)
-        if connection is None:
-            settings = Settings()
-            settings.connection.id = 'Auto ' + self._name
-            uuid = settings.connection.uuid = unique_id()
-            settings.connection.type = '802-11-wireless'
-            settings.wireless.ssid = self._name
-
-            if self._mode == network.NM_802_11_MODE_INFRA:
-                settings.wireless.mode = 'infrastructure'
-            elif self._mode == network.NM_802_11_MODE_ADHOC:
-                settings.wireless.mode = 'adhoc'
-                settings.wireless.band = 'bg'
-                settings.ip4_config = IP4Config()
-                settings.ip4_config.method = 'link-local'
-
-            wireless_security = self._get_security()
-            settings.wireless_security = wireless_security
-
-            if wireless_security is not None:
-                settings.wireless.security = '802-11-wireless-security'
+        if connection:
+            logging.debug("Activating existing connection for %s", self._name)
+            connection.activate(self._device)
+            return
 
-            connection = network.add_connection(uuid, settings)
+        # Otherwise, create new connection and activate it
+        logging.debug("Creating new connection for %s", self._name)
+        settings = Settings()
+        settings.connection.id = str(self._name)
+        settings.connection.uuid = unique_id()
+        settings.connection.type = '802-11-wireless'
+        settings.wireless.ssid = self._name
 
-        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-        netmgr = dbus.Interface(obj, _NM_IFACE)
+        if self._mode == network.NM_802_11_MODE_INFRA:
+            settings.wireless.mode = 'infrastructure'
+            settings.connection.autoconnect = True
+        elif self._mode == network.NM_802_11_MODE_ADHOC:
+            settings.wireless.mode = 'adhoc'
+            settings.wireless.band = 'bg'
+            settings.ip4_config = IP4Config()
+            settings.ip4_config.method = 'link-local'
 
-        netmgr.ActivateConnection(network.SETTINGS_SERVICE, connection.path,
-                                  self._device.object_path,
-                                  '/',
-                                  reply_handler=self.__activate_reply_cb,
-                                  error_handler=self.__activate_error_cb)
+        wireless_security = self._get_security()
+        settings.wireless_security = wireless_security
 
-    def __activate_reply_cb(self, connection):
-        logging.debug('Connection activated: %s', connection)
+        if wireless_security is not None:
+            settings.wireless.security = '802-11-wireless-security'
 
-    def __activate_error_cb(self, err):
-        logging.error('Failed to activate connection: %s', err)
+        network.add_and_activate_connection(self._device, settings,
+                                            self.get_first_ap().model)
 
     def set_filter(self, query):
         self._filtered = self._name.lower().find(query) == -1
         self._update_icon()
         self._update_color()
 
-    def create_keydialog(self, settings, response):
+    def create_keydialog(self, response):
         keydialog.create(self._name, self._flags, self._wpa_flags,
-                         self._rsn_flags, self._device_caps, settings,
-                         response)
+                         self._rsn_flags, self._device_caps, response)
 
     def update_strength(self):
         if self._active_ap is not None:
@@ -431,6 +409,9 @@ class WirelessNetworkView(CanvasPulsingIcon):
             return None
         return self._access_points[ap_path]
 
+    def get_first_ap(self):
+        return self._access_points.values()[0]
+
     def is_olpc_mesh(self):
         return self._mode == network.NM_802_11_MODE_ADHOC \
             and self.name == 'olpc-mesh'
@@ -446,11 +427,11 @@ class WirelessNetworkView(CanvasPulsingIcon):
         self._bus.remove_signal_receiver(self.__device_state_changed_cb,
                                          signal_name='StateChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
         self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
                                          signal_name='PropertiesChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_WIRELESS_IFACE)
+                                         dbus_interface=network.NM_WIRELESS_IFACE)
 
 
 class SugarAdhocView(CanvasPulsingIcon):
@@ -526,9 +507,9 @@ class SugarAdhocView(CanvasPulsingIcon):
         if self._channel == channel:
             state = device_state
         else:
-            state = network.DEVICE_STATE_UNKNOWN
+            state = network.NM_DEVICE_STATE_UNKNOWN
 
-        if state == network.DEVICE_STATE_ACTIVATED:
+        if state == network.NM_DEVICE_STATE_ACTIVATED:
             icon_name = '%s-connected' % (self._ICON_NAME + str(self._channel))
         else:
             icon_name = self._ICON_NAME + str(self._channel)
@@ -538,16 +519,14 @@ class SugarAdhocView(CanvasPulsingIcon):
             icon = self._palette.props.icon
             icon.props.icon_name = icon_name
 
-        if state in [network.DEVICE_STATE_PREPARE,
-                     network.DEVICE_STATE_CONFIG,
-                     network.DEVICE_STATE_NEED_AUTH,
-                     network.DEVICE_STATE_IP_CONFIG]:
+        if (state >= network.NM_DEVICE_STATE_PREPARE) and \
+           (state <= network.NM_DEVICE_STATE_IP_CONFIG):
             if self._disconnect_item:
                 self._disconnect_item.show()
             self._connect_item.hide()
             self._palette.props.secondary_text = _('Connecting...')
             self.props.pulsing = True
-        elif state == network.DEVICE_STATE_ACTIVATED:
+        elif state == network.NM_DEVICE_STATE_ACTIVATED:
             if self._disconnect_item:
                 self._disconnect_item.show()
             self._connect_item.hide()
@@ -609,21 +588,21 @@ class OlpcMeshView(CanvasPulsingIcon):
         self.connect('button-release-event', self.__button_release_event_cb)
 
         interface_props = dbus.Interface(device, dbus.PROPERTIES_IFACE)
-        interface_props.Get(_NM_DEVICE_IFACE, 'State',
+        interface_props.Get(network.NM_DEVICE_IFACE, 'State',
                             reply_handler=self.__get_device_state_reply_cb,
                             error_handler=self.__get_device_state_error_cb)
-        interface_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel',
+        interface_props.Get(network.NM_OLPC_MESH_IFACE, 'ActiveChannel',
                             reply_handler=self.__get_active_channel_reply_cb,
                             error_handler=self.__get_active_channel_error_cb)
 
         self._bus.add_signal_receiver(self.__device_state_changed_cb,
                                       signal_name='StateChanged',
                                       path=device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
         self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
                                       signal_name='PropertiesChanged',
                                       path=device.object_path,
-                                      dbus_interface=_NM_OLPC_MESH_IFACE)
+                                      dbus_interface=network.NM_OLPC_MESH_IFACE)
 
         pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
                                          style.COLOR_TRANSPARENT.get_svg()))
@@ -671,18 +650,18 @@ class OlpcMeshView(CanvasPulsingIcon):
         if self._active:
             state = self._device_state
         else:
-            state = network.DEVICE_STATE_UNKNOWN
+            state = network.NM_DEVICE_STATE_UNKNOWN
 
-        if state in [network.DEVICE_STATE_PREPARE,
-                     network.DEVICE_STATE_CONFIG,
-                     network.DEVICE_STATE_NEED_AUTH,
-                     network.DEVICE_STATE_IP_CONFIG]:
+        if state in [network.NM_DEVICE_STATE_PREPARE,
+                     network.NM_DEVICE_STATE_CONFIG,
+                     network.NM_DEVICE_STATE_NEED_AUTH,
+                     network.NM_DEVICE_STATE_IP_CONFIG]:
             if self._disconnect_item:
                 self._disconnect_item.show()
             self._connect_item.hide()
             self._palette.props.secondary_text = _('Connecting...')
             self.props.pulsing = True
-        elif state == network.DEVICE_STATE_ACTIVATED:
+        elif state == network.NM_DEVICE_STATE_ACTIVATED:
             if self._disconnect_item:
                 self._disconnect_item.show()
             self._connect_item.hide()
@@ -711,12 +690,6 @@ class OlpcMeshView(CanvasPulsingIcon):
     def _connect(self):
         self._mesh_mgr.user_activate_channel(self._channel)
 
-    def __activate_reply_cb(self, connection):
-        logging.debug('Connection activated: %s', connection)
-
-    def __activate_error_cb(self, err):
-        logging.error('Failed to activate connection: %s', err)
-
     def set_filter(self, query):
         self._filtered = (query != '')
         self._update_color()
@@ -727,8 +700,8 @@ class OlpcMeshView(CanvasPulsingIcon):
         self._bus.remove_signal_receiver(self.__device_state_changed_cb,
                                          signal_name='StateChanged',
                                          path=device_object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
         self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
                                          signal_name='PropertiesChanged',
                                          path=device_object_path,
-                                         dbus_interface=_NM_OLPC_MESH_IFACE)
+                                         dbus_interface=network.NM_OLPC_MESH_IFACE)
diff --git a/src/jarabe/model/adhoc.py b/src/jarabe/model/adhoc.py
index 647bd8e..09325ed 100644
--- a/src/jarabe/model/adhoc.py
+++ b/src/jarabe/model/adhoc.py
@@ -25,14 +25,6 @@ from sugar.util import unique_id
 from jarabe.model.network import IP4Config
 
 
-_NM_SERVICE = 'org.freedesktop.NetworkManager'
-_NM_IFACE = 'org.freedesktop.NetworkManager'
-_NM_PATH = '/org/freedesktop/NetworkManager'
-_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
-_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
-_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
-_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
-
 _adhoc_manager_instance = None
 
 
@@ -70,13 +62,17 @@ class AdHocManager(gobject.GObject):
         self._device = None
         self._idle_source = 0
         self._listening_called = 0
-        self._device_state = network.DEVICE_STATE_UNKNOWN
+        self._device_state = network.NM_DEVICE_STATE_UNKNOWN
 
         self._current_channel = None
         self._networks = {self._CHANNEL_1: None,
                           self._CHANNEL_6: None,
                           self._CHANNEL_11: None}
 
+        for channel in (self._CHANNEL_1, self._CHANNEL_6, self._CHANNEL_11):
+            if not self._find_connection(channel):
+                self._add_connection(channel)
+
     def start_listening(self, device):
         self._listening_called += 1
         if self._listening_called > 1:
@@ -85,28 +81,28 @@ class AdHocManager(gobject.GObject):
 
         self._device = device
         props = dbus.Interface(device, dbus.PROPERTIES_IFACE)
-        self._device_state = props.Get(_NM_DEVICE_IFACE, 'State')
+        self._device_state = props.Get(network.NM_DEVICE_IFACE, 'State')
 
         self._bus.add_signal_receiver(self.__device_state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
 
         self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
                                       signal_name='PropertiesChanged',
                                       path=self._device.object_path,
-                                      dbus_interface=_NM_WIRELESS_IFACE)
+                                      dbus_interface=network.NM_WIRELESS_IFACE)
 
     def stop_listening(self):
         self._listening_called = 0
         self._bus.remove_signal_receiver(self.__device_state_changed_cb,
                                          signal_name='StateChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_DEVICE_IFACE)
+                                         dbus_interface=network.NM_DEVICE_IFACE)
         self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
                                          signal_name='PropertiesChanged',
                                          path=self._device.object_path,
-                                         dbus_interface=_NM_WIRELESS_IFACE)
+                                         dbus_interface=network.NM_WIRELESS_IFACE)
 
     def __device_state_changed_cb(self, new_state, old_state, reason):
         self._device_state = new_state
@@ -115,10 +111,10 @@ class AdHocManager(gobject.GObject):
     def __wireless_properties_changed_cb(self, properties):
         if 'ActiveAccessPoint' in properties and \
                 properties['ActiveAccessPoint'] != '/':
-            active_ap = self._bus.get_object(_NM_SERVICE,
+            active_ap = self._bus.get_object(network.NM_SERVICE,
                                              properties['ActiveAccessPoint'])
             props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
-            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
+            props.GetAll(network.NM_ACCESSPOINT_IFACE, byte_arrays=True,
                          reply_handler=self.__get_all_ap_props_reply_cb,
                          error_handler=self.__get_all_ap_props_error_cb)
 
@@ -137,13 +133,13 @@ class AdHocManager(gobject.GObject):
     def _update_state(self):
         self.emit('state-changed', self._current_channel, self._device_state)
 
-    def _have_configured_connections(self):
-        return len(network.get_settings().connections) > 0
-
     def autoconnect(self):
         """Start a timer which basically looks for 30 seconds of inactivity
         on the device, then does autoconnect to an Ad-hoc network.
 
+        This function may be called early on (e.g. when the device is still
+        in NM_DEVICE_STATE_UNMANAGED). It is assumed that initialisation
+        will complete quickly, and long before the timeout ticks.
         """
         if self._idle_source != 0:
             gobject.source_remove(self._idle_source)
@@ -151,7 +147,7 @@ class AdHocManager(gobject.GObject):
             self._AUTOCONNECT_TIMEOUT, self.__idle_check_cb)
 
     def __idle_check_cb(self):
-        if self._device_state == network.DEVICE_STATE_DISCONNECTED:
+        if self._device_state == network.NM_DEVICE_STATE_DISCONNECTED:
             logging.debug('Connect to Ad-hoc network due to inactivity.')
             self._autoconnect_adhoc()
         else:
@@ -164,13 +160,13 @@ class AdHocManager(gobject.GObject):
 
         """
         if self._networks[self._CHANNEL_1] is not None:
-            self._connect(self._CHANNEL_1)
+            self.activate_channel(self._CHANNEL_1)
         elif self._networks[self._CHANNEL_6] is not None:
-            self._connect(self._CHANNEL_6)
+            self.activate_channel(self._CHANNEL_6)
         elif self._networks[self._CHANNEL_11] is not None:
-            self._connect(self._CHANNEL_11)
+            self.activate_channel(self._CHANNEL_11)
         else:
-            self._connect(self._CHANNEL_1)
+            self.activate_channel(self._CHANNEL_1)
 
     def activate_channel(self, channel):
         """Activate a sugar Ad-hoc network.
@@ -179,57 +175,54 @@ class AdHocManager(gobject.GObject):
         channel -- Channel to connect to (should be 1, 6, 11)
 
         """
-        self._connect(channel)
-
-    def _connect(self, channel):
-        name = 'Ad-hoc Network %d' % channel
-        connection = network.find_connection_by_ssid(name)
-        if connection is None:
-            settings = Settings()
-            settings.connection.id = name
-            settings.connection.uuid = unique_id()
-            settings.connection.type = '802-11-wireless'
-            settings.connection.autoconnect = True
-            settings.wireless.ssid = dbus.ByteArray(name)
-            settings.wireless.band = 'bg'
-            settings.wireless.channel = channel
-            settings.wireless.mode = 'adhoc'
-            settings.ip4_config = IP4Config()
-            settings.ip4_config.method = 'link-local'
-
-            connection = network.add_connection(name, settings)
-
-        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-        netmgr = dbus.Interface(obj, _NM_IFACE)
-
-        netmgr.ActivateConnection(network.SETTINGS_SERVICE,
-                                  connection.path,
-                                  self._device.object_path,
-                                  '/',
-                                  reply_handler=self.__activate_reply_cb,
-                                  error_handler=self.__activate_error_cb)
+        connection = self._find_connection(channel)
+        if connection:
+            connection.activate(self._device.object_path)
+
+    @staticmethod
+    def _get_connection_id(channel):
+        return '%s%d' % (network.ADHOC_CONNECTION_ID_PREFIX, channel)
+
+    def _add_connection(self, channel):
+        ssid = 'Ad-hoc Network %d' % (channel,)
+        settings = Settings()
+        settings.connection.id = self._get_connection_id(channel)
+        settings.connection.uuid = unique_id()
+        settings.connection.type = '802-11-wireless'
+        settings.connection.autoconnect = False
+        settings.wireless.ssid = dbus.ByteArray(ssid)
+        settings.wireless.band = 'bg'
+        settings.wireless.channel = channel
+        settings.wireless.mode = 'adhoc'
+        settings.ip4_config = IP4Config()
+        settings.ip4_config.method = 'link-local'
+        network.add_connection(settings)
+
+    def _find_connection(self, channel):
+        connection_id = self._get_connection_id(channel)
+        return network.find_connection_by_id(connection_id)
 
     def deactivate_active_channel(self):
         """Deactivate the current active channel."""
-        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-        netmgr = dbus.Interface(obj, _NM_IFACE)
+        obj = self._bus.get_object(network.NM_SERVICE, network.NM_PATH)
+        netmgr = dbus.Interface(obj, network.NM_IFACE)
 
         netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
-        netmgr_props.Get(_NM_IFACE, 'ActiveConnections', \
+        netmgr_props.Get(network.NM_IFACE, 'ActiveConnections', \
                 reply_handler=self.__get_active_connections_reply_cb,
                 error_handler=self.__get_active_connections_error_cb)
 
     def __get_active_connections_reply_cb(self, active_connections_o):
         for connection_o in active_connections_o:
-            obj = self._bus.get_object(_NM_IFACE, connection_o)
+            obj = self._bus.get_object(network.NM_IFACE, connection_o)
             props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
-            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
+            state = props.Get(network.NM_ACTIVE_CONN_IFACE, 'State')
             if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
-                access_point_o = props.Get(_NM_ACTIVE_CONN_IFACE,
+                access_point_o = props.Get(network.NM_ACTIVE_CONN_IFACE,
                                            'SpecificObject')
                 if access_point_o != '/':
-                    obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-                    netmgr = dbus.Interface(obj, _NM_IFACE)
+                    obj = self._bus.get_object(network.NM_SERVICE, network.NM_PATH)
+                    netmgr = dbus.Interface(obj, network.NM_IFACE)
                     netmgr.DeactivateConnection(connection_o)
 
     def __get_active_connections_error_cb(self, err):
diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
index f265ae4..bac41ac 100644
--- a/src/jarabe/model/network.py
+++ b/src/jarabe/model/network.py
@@ -21,7 +21,6 @@
 from gettext import gettext as _
 import logging
 import os
-import time
 
 import dbus
 import dbus.service
@@ -34,22 +33,38 @@ from sugar import dispatch
 from sugar import env
 from sugar.util import unique_id
 
-
-DEVICE_TYPE_802_3_ETHERNET = 1
-DEVICE_TYPE_802_11_WIRELESS = 2
-DEVICE_TYPE_GSM_MODEM = 3
-DEVICE_TYPE_802_11_OLPC_MESH = 6
-
-DEVICE_STATE_UNKNOWN = 0
-DEVICE_STATE_UNMANAGED = 1
-DEVICE_STATE_UNAVAILABLE = 2
-DEVICE_STATE_DISCONNECTED = 3
-DEVICE_STATE_PREPARE = 4
-DEVICE_STATE_CONFIG = 5
-DEVICE_STATE_NEED_AUTH = 6
-DEVICE_STATE_IP_CONFIG = 7
-DEVICE_STATE_ACTIVATED = 8
-DEVICE_STATE_FAILED = 9
+NM_STATE_UNKNOWN = 0
+NM_STATE_ASLEEP = 10
+NM_STATE_DISCONNECTED = 20
+NM_STATE_DISCONNECTING = 30
+NM_STATE_CONNECTING = 40
+NM_STATE_CONNECTED_LOCAL = 50
+NM_STATE_CONNECTED_SITE = 60
+NM_STATE_CONNECTED_GLOBAL = 70
+
+NM_DEVICE_TYPE_UNKNOWN = 0
+NM_DEVICE_TYPE_ETHERNET = 1
+NM_DEVICE_TYPE_WIFI = 2
+NM_DEVICE_TYPE_UNUSED1 = 3
+NM_DEVICE_TYPE_UNUSED2 = 4
+NM_DEVICE_TYPE_BT = 5
+NM_DEVICE_TYPE_OLPC_MESH = 6
+NM_DEVICE_TYPE_WIMAX = 7
+NM_DEVICE_TYPE_MODEM = 8
+
+NM_DEVICE_STATE_UNKNOWN = 0
+NM_DEVICE_STATE_UNMANAGED = 10
+NM_DEVICE_STATE_UNAVAILABLE = 20
+NM_DEVICE_STATE_DISCONNECTED = 30
+NM_DEVICE_STATE_PREPARE = 40
+NM_DEVICE_STATE_CONFIG = 50
+NM_DEVICE_STATE_NEED_AUTH = 60
+NM_DEVICE_STATE_IP_CONFIG = 70
+NM_DEVICE_STATE_IP_CHECK = 80
+NM_DEVICE_STATE_SECONDARIES = 90
+NM_DEVICE_STATE_ACTIVATED = 100
+NM_DEVICE_STATE_DEACTIVATING = 110
+NM_DEVICE_STATE_FAILED = 120
 
 NM_CONNECTION_TYPE_802_11_WIRELESS = '802-11-wireless'
 NM_CONNECTION_TYPE_GSM = 'gsm'
@@ -57,15 +72,15 @@ NM_CONNECTION_TYPE_GSM = 'gsm'
 NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0
 NM_ACTIVE_CONNECTION_STATE_ACTIVATING = 1
 NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2
-
+NM_ACTIVE_CONNECTION_STATE_DEACTIVATING = 3
 
 NM_DEVICE_STATE_REASON_UNKNOWN = 0
 NM_DEVICE_STATE_REASON_NONE = 1
 NM_DEVICE_STATE_REASON_NOW_MANAGED = 2
 NM_DEVICE_STATE_REASON_NOW_UNMANAGED = 3
 NM_DEVICE_STATE_REASON_CONFIG_FAILED = 4
-NM_DEVICE_STATE_REASON_CONFIG_UNAVAILABLE = 5
-NM_DEVICE_STATE_REASON_CONFIG_EXPIRED = 6
+NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE = 5
+NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED = 6
 NM_DEVICE_STATE_REASON_NO_SECRETS = 7
 NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT = 8
 NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED = 9
@@ -100,47 +115,74 @@ NM_DEVICE_STATE_REASON_SLEEPING = 37
 NM_DEVICE_STATE_REASON_CONNECTION_REMOVED = 38
 NM_DEVICE_STATE_REASON_USER_REQUESTED = 39
 NM_DEVICE_STATE_REASON_CARRIER = 40
+NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED = 41
+NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE = 42
+NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND = 43
+NM_DEVICE_STATE_REASON_BT_FAILED = 44
+NM_DEVICE_STATE_REASON_LAST = 0xFFFF
 
 NM_802_11_AP_FLAGS_NONE = 0x00000000
 NM_802_11_AP_FLAGS_PRIVACY = 0x00000001
 
-NM_802_11_AP_SEC_NONE = 0x00000000
-NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001
-NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002
-NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004
-NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008
-NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010
-NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020
-NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040
-NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080
-NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100
-NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200
+NM_802_11_AP_SEC_NONE = 0x0
+NM_802_11_AP_SEC_PAIR_WEP40 = 0x1
+NM_802_11_AP_SEC_PAIR_WEP104 = 0x2
+NM_802_11_AP_SEC_PAIR_TKIP = 0x4
+NM_802_11_AP_SEC_PAIR_CCMP = 0x8
+NM_802_11_AP_SEC_GROUP_WEP40 = 0x10
+NM_802_11_AP_SEC_GROUP_WEP104 = 0x20
+NM_802_11_AP_SEC_GROUP_TKIP = 0x40
+NM_802_11_AP_SEC_GROUP_CCMP = 0x80
+NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x100
+NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x200
 
 NM_802_11_MODE_UNKNOWN = 0
 NM_802_11_MODE_ADHOC = 1
 NM_802_11_MODE_INFRA = 2
 
-NM_802_11_DEVICE_CAP_NONE = 0x00000000
-NM_802_11_DEVICE_CAP_CIPHER_WEP40 = 0x00000001
-NM_802_11_DEVICE_CAP_CIPHER_WEP104 = 0x00000002
-NM_802_11_DEVICE_CAP_CIPHER_TKIP = 0x00000004
-NM_802_11_DEVICE_CAP_CIPHER_CCMP = 0x00000008
-NM_802_11_DEVICE_CAP_WPA = 0x00000010
-NM_802_11_DEVICE_CAP_RSN = 0x00000020
+NM_WIFI_DEVICE_CAP_NONE = 0x00000000
+NM_WIFI_DEVICE_CAP_CIPHER_WEP40 = 0x00000001
+NM_WIFI_DEVICE_CAP_CIPHER_WEP104 = 0x00000002
+NM_WIFI_DEVICE_CAP_CIPHER_TKIP = 0x00000004
+NM_WIFI_DEVICE_CAP_CIPHER_CCMP = 0x00000008
+NM_WIFI_DEVICE_CAP_WPA = 0x00000010
+NM_WIFI_DEVICE_CAP_RSN = 0x00000020
+
+NM_BT_CAPABILITY_NONE = 0x00000000
+NM_BT_CAPABILITY_DUN = 0x00000001
+NM_BT_CAPABILITY_NAP = 0x00000002
+
+NM_DEVICE_MODEM_CAPABILITY_NONE = 0x00000000
+NM_DEVICE_MODEM_CAPABILITY_POTS = 0x00000001
+NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO = 0x00000002
+NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS = 0x00000004
+NM_DEVICE_MODEM_CAPABILITY_LTE = 0x00000008
 
-SETTINGS_SERVICE = 'org.freedesktop.NetworkManagerUserSettings'
+SETTINGS_SERVICE = 'org.freedesktop.NetworkManager'
 
 NM_SERVICE = 'org.freedesktop.NetworkManager'
 NM_IFACE = 'org.freedesktop.NetworkManager'
 NM_PATH = '/org/freedesktop/NetworkManager'
 NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
-NM_SETTINGS_PATH = '/org/freedesktop/NetworkManagerSettings'
-NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManagerSettings'
-NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection'
-NM_SECRETS_IFACE = 'org.freedesktop.NetworkManagerSettings.Connection.Secrets'
+NM_WIRED_IFACE = 'org.freedesktop.NetworkManager.Device.Wired'
+NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
+NM_MODEM_IFACE = 'org.freedesktop.NetworkManager.Device.Modem'
+NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
+NM_SETTINGS_PATH = '/org/freedesktop/NetworkManager/Settings'
+NM_SETTINGS_IFACE = 'org.freedesktop.NetworkManager.Settings'
+NM_CONNECTION_IFACE = 'org.freedesktop.NetworkManager.Settings.Connection'
 NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
 NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
 
+NM_SECRET_AGENT_IFACE = 'org.freedesktop.NetworkManager.SecretAgent'
+NM_SECRET_AGENT_PATH = '/org/freedesktop/NetworkManager/SecretAgent'
+NM_AGENT_MANAGER_IFACE = 'org.freedesktop.NetworkManager.AgentManager'
+NM_AGENT_MANAGER_PATH = '/org/freedesktop/NetworkManager/AgentManager'
+
+NM_AGENT_MANAGER_ERR_NO_SECRETS = 'org.freedesktop.NetworkManager.AgentManager.NoSecrets'
+
+GSM_CONNECTION_ID = 'Sugar Modem Connection'
+GSM_BAUD_RATE = 115200
 GSM_USERNAME_PATH = '/desktop/sugar/network/gsm/username'
 GSM_PASSWORD_PATH = '/desktop/sugar/network/gsm/password'
 GSM_NUMBER_PATH = '/desktop/sugar/network/gsm/number'
@@ -148,8 +190,14 @@ GSM_APN_PATH = '/desktop/sugar/network/gsm/apn'
 GSM_PIN_PATH = '/desktop/sugar/network/gsm/pin'
 GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk'
 
+ADHOC_CONNECTION_ID_PREFIX = 'Sugar Ad-hoc Network '
+MESH_CONNECTION_ID_PREFIX = 'OLPC Mesh Network '
+XS_MESH_CONNECTION_ID_PREFIX = 'OLPC XS Mesh Network '
+
+_network_manager = None
 _nm_settings = None
-_conn_counter = 0
+_secret_agent = None
+_connections = None
 
 _nm_device_state_reason_description = None
 
@@ -169,10 +217,10 @@ def get_error_by_reason(reason):
                 _('The device is no longer managed.'),
             NM_DEVICE_STATE_REASON_CONFIG_FAILED:
                 _('The device could not be readied for configuration.'),
-            NM_DEVICE_STATE_REASON_CONFIG_UNAVAILABLE:
+            NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE:
                 _('IP configuration could not be reserved '
                   '(no available address, timeout, etc).'),
-            NM_DEVICE_STATE_REASON_CONFIG_EXPIRED:
+            NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED:
                 _('The IP configuration is no longer valid.'),
             NM_DEVICE_STATE_REASON_NO_SECRETS:
                 _('Secrets were required, but not provided.'),
@@ -244,7 +292,18 @@ def get_error_by_reason(reason):
             NM_DEVICE_STATE_REASON_USER_REQUESTED:
                 _('A user or client requested the disconnection.'),
             NM_DEVICE_STATE_REASON_CARRIER:
-                _("The device's carrier/link changed.")}
+                _("The device's carrier/link changed."),
+            NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED:
+                _("The device's existing connection was assumed."),
+            NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE:
+                _("The supplicant is now available."),
+            NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND:
+                _("The modem could not be found."),
+            NM_DEVICE_STATE_REASON_BT_FAILED:
+                _("The Bluetooth connection failed or timed out."),
+            NM_DEVICE_STATE_REASON_LAST:
+                _("Unused."),
+        }
 
     return _nm_device_state_reason_description[reason]
 
@@ -288,6 +347,9 @@ class WirelessSecurity(object):
         self.proto = None
         self.group = None
         self.pairwise = None
+        self.wep_key = None
+        self.psk = None
+        self.auth_alg = None
 
     def get_dict(self):
         wireless_security = {}
@@ -299,6 +361,12 @@ class WirelessSecurity(object):
             wireless_security['pairwise'] = self.pairwise
         if self.group is not None:
             wireless_security['group'] = self.group
+        if self.wep_key is not None:
+            wireless_security['wep-key0'] = self.wep_key
+        if self.psk is not None:
+            wireless_security['psk'] = self.psk
+        if self.auth_alg is not None:
+            wireless_security['auth-alg'] = self.auth_alg
         return wireless_security
 
 
@@ -343,7 +411,7 @@ class OlpcMesh(object):
         return ret
 
 
-class Connection(object):
+class ConnectionSettings(object):
     def __init__(self):
         self.id = None
         self.uuid = None
@@ -399,23 +467,29 @@ class Gsm(object):
         self.apn = None
         self.number = None
         self.username = None
+        self.pin = None
+        self.password = None
 
     def get_dict(self):
         gsm = {}
 
-        if self.apn is not None:
+        if self.apn:
             gsm['apn'] = self.apn
-        if self.number is not None:
+        if self.number:
             gsm['number'] = self.number
-        if self.username is not None:
+        if self.username:
             gsm['username'] = self.username
+        if self.password:
+            gsm['password'] = self.password
+        if self.pin:
+            gsm['pin'] = self.pin
 
         return gsm
 
 
 class Settings(object):
     def __init__(self, wireless_cfg=None):
-        self.connection = Connection()
+        self.connection = ConnectionSettings()
         self.ip4_config = None
         self.wireless_security = None
 
@@ -436,35 +510,9 @@ class Settings(object):
         return settings
 
 
-class Secrets(object):
-    def __init__(self, settings):
-        self.settings = settings
-        self.wep_key = None
-        self.psk = None
-        self.auth_alg = None
-
-    def get_dict(self):
-        # Although we could just return the keys here, we instead return all
-        # of the network settings so that we can apply any late decisions made
-        # by the user (e.g. if they selected shared key authentication). see
-        # http://bugs.sugarlabs.org/ticket/1602
-        settings = self.settings.get_dict()
-        if '802-11-wireless-security' not in settings:
-            settings['802-11-wireless-security'] = {}
-
-        if self.wep_key is not None:
-            settings['802-11-wireless-security']['wep-key0'] = self.wep_key
-        if self.psk is not None:
-            settings['802-11-wireless-security']['psk'] = self.psk
-        if self.auth_alg is not None:
-            settings['802-11-wireless-security']['auth-alg'] = self.auth_alg
-
-        return settings
-
-
 class SettingsGsm(object):
     def __init__(self):
-        self.connection = Connection()
+        self.connection = ConnectionSettings()
         self.ip4_config = IP4Config()
         self.serial = Serial()
         self.ppp = Ppp()
@@ -482,222 +530,72 @@ class SettingsGsm(object):
         return settings
 
 
-class SecretsGsm(object):
-    def __init__(self):
-        self.password = None
-        self.pin = None
-        self.puk = None
-
-    def get_dict(self):
-        secrets = {}
-        if self.password is not None:
-            secrets['password'] = self.password
-        if self.pin is not None:
-            secrets['pin'] = self.pin
-        if self.puk is not None:
-            secrets['puk'] = self.puk
-        return {'gsm': secrets}
-
-
-class NMSettings(dbus.service.Object):
-    def __init__(self):
-        bus = dbus.SystemBus()
-        bus_name = dbus.service.BusName(SETTINGS_SERVICE, bus=bus)
-        dbus.service.Object.__init__(self, bus_name, NM_SETTINGS_PATH)
-
-        self.connections = {}
-        self.secrets_request = dispatch.Signal()
-
-    @dbus.service.method(dbus_interface=NM_SETTINGS_IFACE,
-                         in_signature='', out_signature='ao')
-    def ListConnections(self):
-        return self.connections.values()
-
-    @dbus.service.signal(NM_SETTINGS_IFACE, signature='o')
-    def NewConnection(self, connection_path):
-        pass
-
-    def add_connection(self, uuid, conn):
-        self.connections[uuid] = conn
-        conn.secrets_request.connect(self.__secrets_request_cb)
-        self.NewConnection(conn.path)
-
-    def __secrets_request_cb(self, sender, **kwargs):
-        self.secrets_request.send(self, connection=sender,
-                                  response=kwargs['response'])
-
-    def clear_wifi_connections(self):
-        for uuid in self.connections.keys():
-            conn = self.connections[uuid]
-            if conn._settings.connection.type == \
-               NM_CONNECTION_TYPE_802_11_WIRELESS:
-                conn.Removed()
-                self.connections.pop(uuid)
-
-
 class SecretsResponse(object):
     """Intermediate object to report the secrets from the dialog
     back to the connection object and which will inform NM
     """
-    def __init__(self, connection, reply_cb, error_cb):
-        self._connection = connection
+    def __init__(self, reply_cb, error_cb):
         self._reply_cb = reply_cb
         self._error_cb = error_cb
 
     def set_secrets(self, secrets):
-        self._connection.set_secrets(secrets)
-        self._reply_cb(secrets.get_dict())
+        self._reply_cb(secrets)
 
     def set_error(self, error):
         self._error_cb(error)
 
 
-class NMSettingsConnection(dbus.service.Object):
-    def __init__(self, path, settings, secrets):
-        bus = dbus.SystemBus()
-        bus_name = dbus.service.BusName(SETTINGS_SERVICE, bus=bus)
-        dbus.service.Object.__init__(self, bus_name, path)
-
-        self.path = path
+def set_connected():
+    try:
+        # try to flush resolver cache - SL#1940
+        # ctypes' syntactic sugar does not work
+        # so we must get the func ptr explicitly
+        libc = ctypes.CDLL('libc.so.6')
+        res_init = getattr(libc, '__res_init')
+        res_init(None)
+    except:
+        # pylint: disable=W0702
+        logging.exception('Error calling libc.__res_init')
+
+
+class SecretAgent(dbus.service.Object):
+    def __init__(self):
+        self._bus = dbus.SystemBus()
+        dbus.service.Object.__init__(self, self._bus, NM_SECRET_AGENT_PATH)
         self.secrets_request = dispatch.Signal()
+        proxy = self._bus.get_object(NM_IFACE, NM_AGENT_MANAGER_PATH)
+        proxy.Register("org.sugarlabs.sugar",
+                       dbus_interface=NM_AGENT_MANAGER_IFACE,
+                       reply_handler=self._register_reply_cb,
+                       error_handler=self._register_error_cb)
 
-        self._settings = settings
-        self._secrets = secrets
-
-    @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE,
-                         signature='')
-    def Removed(self):
-        pass
-
-    @dbus.service.signal(dbus_interface=NM_CONNECTION_IFACE,
-                         signature='a{sa{sv}}')
-    def Updated(self, settings):
-        pass
-
-    def set_connected(self):
-        if self._settings.connection.type == NM_CONNECTION_TYPE_GSM:
-            self._settings.connection.timestamp = int(time.time())
-        elif not self._settings.connection.autoconnect:
-            self._settings.connection.autoconnect = True
-            self._settings.connection.timestamp = int(time.time())
-            if (self._settings.connection.type ==
-                    NM_CONNECTION_TYPE_802_11_WIRELESS):
-                self.Updated(self._settings.get_dict())
-                self.save()
-
-        try:
-            # try to flush resolver cache - SL#1940
-            # ctypes' syntactic sugar does not work
-            # so we must get the func ptr explicitly
-            libc = ctypes.CDLL('libc.so.6')
-            res_init = getattr(libc, '__res_init')
-            res_init(None)
-        except:
-            # pylint: disable=W0702
-            logging.exception('Error calling libc.__res_init')
-
-    def disable_autoconnect(self):
-        if self._settings.connection.type != NM_CONNECTION_TYPE_GSM and \
-               self._settings.connection.autoconnect:
-            self._settings.connection.autoconnect = False
-            self._settings.connection.timestamp = None
-            self.Updated(self._settings.get_dict())
-            self.save()
-
-    def set_secrets(self, secrets):
-        self._secrets = secrets
-        if self._settings.connection.type == \
-           NM_CONNECTION_TYPE_802_11_WIRELESS:
-            self.save()
-
-    def get_settings(self):
-        return self._settings
+    def _register_reply_cb(self):
+        logging.debug("SecretAgent registered")
 
-    def save(self):
-        config_path = _get_wifi_connections_path()
+    def _register_error_cb(self, error):
+        logging.error("Failed to register SecretAgent: %s", error)
 
-        config = ConfigParser.ConfigParser()
-        try:
-            try:
-                if not config.read(config_path):
-                    logging.error('Error reading the nm config file')
-                    return
-            except ConfigParser.ParsingError:
-                logging.exception('Error reading the nm config file')
-                return
-            identifier = self._settings.connection.id
-
-            if identifier not in config.sections():
-                config.add_section(identifier)
-            config.set(identifier, 'type', self._settings.connection.type)
-            config.set(identifier, 'ssid', self._settings.wireless.ssid)
-            config.set(identifier, 'uuid', self._settings.connection.uuid)
-            config.set(identifier, 'autoconnect',
-                       self._settings.connection.autoconnect)
-            if self._settings.connection.timestamp is not None:
-                config.set(identifier, 'timestamp',
-                           self._settings.connection.timestamp)
-            if self._settings.wireless_security is not None:
-                if self._settings.wireless_security.key_mgmt is not None:
-                    config.set(identifier, 'key-mgmt',
-                               self._settings.wireless_security.key_mgmt)
-                if self._settings.wireless_security.proto is not None:
-                    config.set(identifier, 'proto',
-                               self._settings.wireless_security.proto)
-                if self._settings.wireless_security.pairwise is not None:
-                    config.set(identifier, 'pairwise',
-                               self._settings.wireless_security.pairwise)
-                if self._settings.wireless_security.group is not None:
-                    config.set(identifier, 'group',
-                               self._settings.wireless_security.group)
-                if self._settings.wireless.security is not None:
-                    config.set(identifier, 'security',
-                               self._settings.wireless.security)
-            if self._secrets is not None:
-                if self._settings.wireless_security.key_mgmt == 'none':
-                    config.set(identifier, 'key', self._secrets.wep_key)
-                    config.set(identifier, 'auth-alg', self._secrets.auth_alg)
-                elif self._settings.wireless_security.key_mgmt == 'wpa-psk':
-                    config.set(identifier, 'key', self._secrets.psk)
-        except ConfigParser.Error, e:
-            logging.exception('Error constructing %s', identifier)
-        else:
-            f = open(config_path, 'w')
-            try:
-                config.write(f)
-            except ConfigParser.Error:
-                logging.exception('Can not write %s', config_path)
-            f.close()
-
-    @dbus.service.method(dbus_interface=NM_CONNECTION_IFACE,
-                         in_signature='', out_signature='a{sa{sv}}')
-    def GetSettings(self):
-        return self._settings.get_dict()
-
-    @dbus.service.method(dbus_interface=NM_SECRETS_IFACE,
+    @dbus.service.method(NM_SECRET_AGENT_IFACE,
                          async_callbacks=('reply', 'error'),
-                         in_signature='sasb', out_signature='a{sa{sv}}')
-    def GetSecrets(self, setting_name, hints, request_new, reply, error):
-        logging.debug('Secrets requested for connection %s request_new=%s',
-                      self.path, request_new)
-        if self._settings.connection.type is not NM_CONNECTION_TYPE_GSM:
-            if request_new or self._secrets is None:
-                # request_new is for example the case when the pw on the AP
-                # changes
-                response = SecretsResponse(self, reply, error)
-                try:
-                    self.secrets_request.send(self, response=response)
-                except Exception:
-                    logging.exception('Error requesting the secrets via'
-                                      ' dialog')
-            else:
-                reply(self._secrets.get_dict())
-        else:
-            if not request_new:
-                reply(self._secrets.get_dict())
-            else:
-                raise Exception('The stored GSM secret has already been'
-                                ' supplied')
+                         in_signature='a{sa{sv}}osasb',
+                         out_signature='a{sa{sv}}',
+                         sender_keyword='sender',
+                         byte_arrays=True)
+    def GetSecrets(self, settings, connection_path, setting_name, hints,
+                   request_new, reply, error, sender=None):
+        if setting_name != '802-11-wireless-security':
+            raise ValueError("Unsupported setting type %s" % (setting_name,))
+        if not sender:
+            raise Exception("Internal error: couldn't get sender")
+        uid = self._bus.get_unix_user(sender)
+        if uid != 0:
+            raise Exception("UID %d not authorized" % (uid,))
+
+        response = SecretsResponse(reply, error)
+        try:
+            self.secrets_request.send(self, settings=settings, response=response)
+        except Exception:
+            logging.exception('Error requesting the secrets via dialog')
 
 
 class AccessPoint(gobject.GObject):
@@ -808,58 +706,214 @@ class AccessPoint(gobject.GObject):
                                          dbus_interface=NM_ACCESSPOINT_IFACE)
 
 
-def get_settings():
+def get_manager():
+    global _network_manager
+    if _network_manager is None:
+        obj = dbus.SystemBus().get_object(NM_SERVICE, NM_PATH)
+        _network_manager = dbus.Interface(obj, NM_IFACE)
+    return _network_manager
+
+
+def _get_settings():
     global _nm_settings
     if _nm_settings is None:
-        try:
-            _nm_settings = NMSettings()
-        except dbus.DBusException:
-            logging.exception('Cannot create the UserSettings service.')
-        load_connections()
+        obj = dbus.SystemBus().get_object(NM_SERVICE, NM_SETTINGS_PATH)
+        _nm_settings = dbus.Interface(obj, NM_SETTINGS_IFACE)
+        _migrate_old_wifi_connections()
+        _migrate_old_gsm_connection()
     return _nm_settings
 
 
-def find_connection_by_ssid(ssid):
-    connections = get_settings().connections
+def get_secret_agent():
+    global _secret_agent
+    if _secret_agent is None:
+        _secret_agent = SecretAgent()
+    return _secret_agent
+
+
+def _activate_reply_cb(connection):
+    logging.debug('Activated connection: %s', connection)
+
+
+def _activate_error_cb(err):
+    logging.error('Failed to activate connection: %s', err)
+
+
+class Connection(gobject.GObject):
+    __gsignals__ = {
+        'removed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
+    }
+
+    def __init__(self, bus, path):
+        gobject.GObject.__init__(self)
+        obj = bus.get_object(NM_SERVICE, path)
+        self._connection = dbus.Interface(obj, NM_CONNECTION_IFACE)
+        self._removed_handle = self._connection.connect_to_signal(
+            'Removed', self._removed_cb)
+        self._updated_handle = self._connection.connect_to_signal(
+            'Updated', self._updated_cb)
+        self._settings = self._connection.GetSettings(byte_arrays=True)
+
+    def _updated_cb(self):
+        self._settings = self._connection.GetSettings(byte_arrays=True)
+
+    def _removed_cb(self):
+        self._updated_handle.remove()
+        self._removed_handle.remove()
+        self.emit('removed')
+
+    def get_settings(self, stype=None):
+        if not stype:
+            return self._settings
+        elif stype in self._settings:
+            return self._settings[stype]
+        else:
+            return None
+
+    def get_secrets(self, stype, reply_handler, error_handler):
+        return self._connection.GetSecrets(stype, byte_arrays=True,
+                                           reply_handler=reply_handler,
+                                           error_handler=error_handler)
+
+    def update_settings(self, settings):
+        self._connection.Update(settings)
+
+    def activate(self, device_o, reply_handler=_activate_reply_cb,
+                 error_handler=_activate_error_cb):
+        activate_connection_by_path(self.get_path(), device_o,
+                                    reply_handler=reply_handler,
+                                    error_handler=error_handler)
+
+    def delete(self):
+        self._connection.Delete()
+
+    def get_ssid(self):
+        wifi_settings = self.get_settings('802-11-wireless')
+        if wifi_settings and 'ssid' in wifi_settings:
+            return wifi_settings['ssid']
+        else:
+            return None
+
+    def get_id(self):
+        return self.get_settings('connection')['id']
+
+    def get_path(self):
+        return self._connection.object_path
+
+    def is_sugar_internal_connection(self):
+        """Returns True if this connection is a 'special' Sugar connection,
+        i.e. one that has been created by Sugar internals and should not be
+        visible to the user or deleted by connection-clearing code."""
+        connection_id = self.get_id()
+        return connection_id == GSM_CONNECTION_ID \
+            or connection_id.startswith(ADHOC_CONNECTION_ID_PREFIX) \
+            or connection_id.startswith(MESH_CONNECTION_ID_PREFIX) \
+            or connection_id.startswith(XS_MESH_CONNECTION_ID_PREFIX)
+
+
+class Connections(object):
+    def __init__(self):
+        self._bus = dbus.SystemBus()
+        self._connections = []
+
+        settings = _get_settings()
+        settings.connect_to_signal('NewConnection', self._new_connection_cb)
+
+        for connection_o in settings.ListConnections():
+            self._monitor_connection(connection_o)
+
+    def get_list(self):
+        return self._connections
+
+    def _monitor_connection(self, connection_o):
+        connection = Connection(self._bus, connection_o)
+        connection.connect('removed', self._connection_removed_cb)
+        self._connections.append(connection)
+
+    def _new_connection_cb(self, connection_o):
+        self._monitor_connection(connection_o)
 
-    for conn_index in connections:
-        connection = connections[conn_index]
-        if connection._settings.connection.type == \
-           NM_CONNECTION_TYPE_802_11_WIRELESS and \
-           connection._settings.wireless.ssid == ssid:
+    def _connection_removed_cb(self, connection):
+        connection.disconnect_by_func(self._connection_removed_cb)
+        self._connections.remove(connection)
+
+    def clear(self):
+        """Remove all connections except Sugar-internal ones."""
+
+        # copy the list, to avoid problems with removing elements of a list
+        # while looping over it
+        connections = list(self._connections)
+        for connection in connections:
+            if connection.is_sugar_internal_connection():
+                continue
+            connection.delete()
+
+
+def get_connections():
+    global _connections
+    if _connections is None:
+        _connections = Connections()
+    return _connections
+
+
+def find_connection_by_ssid(ssid):
+    # FIXME: this check should be more extensive.
+    # it should look at mode (infra/adhoc), band, security, and really
+    # anything that is stored in the settings.
+    for connection in get_connections().get_list():
+        if connection.get_ssid() == ssid:
             return connection
+    return None
+
 
+def find_connection_by_id(connection_id):
+    for connection in get_connections().get_list():
+        if connection.get_id() == connection_id:
+            return connection
     return None
 
 
-def add_connection(uuid, settings, secrets=None):
-    global _conn_counter
+def _add_connection_reply_cb(connection):
+    logging.debug('Added connection: %s', connection)
 
-    path = NM_SETTINGS_PATH + '/' + str(_conn_counter)
-    _conn_counter += 1
 
-    conn = NMSettingsConnection(path, settings, secrets)
-    _nm_settings.add_connection(uuid, conn)
-    return conn
+def _add_connection_error_cb(err):
+    logging.error('Failed to add connection: %s', err)
 
 
-def _get_wifi_connections_path():
-    profile_path = env.get_profile_path()
-    return os.path.join(profile_path, 'nm', 'connections.cfg')
+def add_connection(settings, reply_handler=_add_connection_reply_cb,
+                   error_handler=_add_connection_error_cb):
+    _get_settings().AddConnection(settings.get_dict(),
+                                  reply_handler=reply_handler,
+                                  error_handler=error_handler)
+
+
+def activate_connection_by_path(connection, device_o,
+                                reply_handler=_activate_reply_cb,
+                                error_handler=_activate_error_cb):
+    get_manager().ActivateConnection(connection,
+                                     device_o,
+                                     '/',
+                                     reply_handler=reply_handler,
+                                     error_handler=error_handler)
 
 
-def _create_wifi_connections(config_path):
-    if not os.path.exists(os.path.dirname(config_path)):
-        os.makedirs(os.path.dirname(config_path), 0755)
-    f = open(config_path, 'w')
-    f.close()
+def add_and_activate_connection(device_o, settings, specific_object):
+    get_manager().AddAndActivateConnection(settings.get_dict(), device_o,
+                                           specific_object,
+                                           reply_handler=_activate_reply_cb,
+                                           error_handler=_activate_error_cb)
 
 
-def load_wifi_connections():
-    config_path = _get_wifi_connections_path()
+def _migrate_old_wifi_connections():
+    """Migrate connections.cfg from Sugar-0.94 and previous to NetworkManager
+    system-wide connections
+    """
 
+    profile_path = env.get_profile_path()
+    config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
     if not os.path.exists(config_path):
-        _create_wifi_connections(config_path)
+        return
 
     config = ConfigParser.ConfigParser()
     try:
@@ -887,9 +941,7 @@ def load_wifi_connections():
                 timestamp = int(config.get(section, 'timestamp'))
                 settings.connection.timestamp = timestamp
 
-            secrets = None
             if config.has_option(section, 'key-mgmt'):
-                secrets = Secrets(settings)
                 settings.wireless_security = WirelessSecurity()
                 mgmt = config.get(section, 'key-mgmt')
                 settings.wireless_security.key_mgmt = mgmt
@@ -897,11 +949,11 @@ def load_wifi_connections():
                 settings.wireless.security = security
                 key = config.get(section, 'key')
                 if mgmt == 'none':
-                    secrets.wep_key = key
+                    settings.wireless_security.wep_key = key
                     auth_alg = config.get(section, 'auth-alg')
-                    secrets.auth_alg = auth_alg
+                    settings.wireless_security.auth_alg = auth_alg
                 elif mgmt == 'wpa-psk':
-                    secrets.psk = key
+                    settings.wireless_security.psk = key
                     if config.has_option(section, 'proto'):
                         value = config.get(section, 'proto')
                         settings.wireless_security.proto = value
@@ -914,11 +966,33 @@ def load_wifi_connections():
         except ConfigParser.Error:
             logging.exception('Error reading section')
         else:
-            add_connection(uuid, settings, secrets)
+            add_connection(settings)
+
+    os.unlink(config_path)
 
 
-def load_gsm_connection():
-    _BAUD_RATE = 115200
+def create_gsm_connection(username, password, number, apn, pin):
+    settings = SettingsGsm()
+    settings.gsm.username = username
+    settings.gsm.number = number
+    settings.gsm.apn = apn
+    settings.gsm.pin = pin
+    settings.gsm.password = password
+
+    settings.connection.id = GSM_CONNECTION_ID
+    settings.connection.type = NM_CONNECTION_TYPE_GSM
+    settings.connection.uuid = unique_id()
+    settings.connection.autoconnect = False
+    settings.ip4_config.method = 'auto'
+    settings.serial.baud = GSM_BAUD_RATE
+
+    add_connection(settings)
+
+
+def _migrate_old_gsm_connection():
+    if find_gsm_connection():
+        # don't attempt migration if a NM-level connection already exists
+        return
 
     client = gconf.client_get_default()
 
@@ -927,60 +1001,22 @@ def load_gsm_connection():
     number = client.get_string(GSM_NUMBER_PATH) or ''
     apn = client.get_string(GSM_APN_PATH) or ''
     pin = client.get_string(GSM_PIN_PATH) or ''
-    puk = client.get_string(GSM_PUK_PATH) or ''
-
-    if username and number and apn:
-        settings = SettingsGsm()
-        settings.gsm.username = username
-        settings.gsm.number = number
-        settings.gsm.apn = apn
-
-        secrets = SecretsGsm()
-        secrets.pin = pin
-        secrets.puk = puk
-        secrets.password = password
-
-        settings.connection.id = 'gsm'
-        settings.connection.type = NM_CONNECTION_TYPE_GSM
-        uuid = settings.connection.uuid = unique_id()
-        settings.connection.autoconnect = False
-        settings.ip4_config.method = 'auto'
-        settings.serial.baud = _BAUD_RATE
 
+    if apn or number:
+        logging.info("Migrating old GSM connection details")
         try:
-            add_connection(uuid, settings, secrets)
+            create_gsm_connection(username, password, number, apn, pin)
+            # remove old connection
+            for setting in (GSM_USERNAME_PATH, GSM_PASSWORD_PATH,
+                            GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH,
+                            GSM_PUK_PATH):
+                client.set_string(setting, '')
         except Exception:
             logging.exception('Error adding gsm connection to NMSettings.')
-    else:
-        logging.warning('No gsm connection was set in GConf.')
-
-
-def load_connections():
-    load_wifi_connections()
-    load_gsm_connection()
 
 
 def find_gsm_connection():
-    connections = get_settings().connections
-
-    for connection in connections.values():
-        if connection.get_settings().connection.type == NM_CONNECTION_TYPE_GSM:
-            return connection
-
-    logging.debug('There is no gsm connection in the NMSettings.')
-    return None
-
-
-def have_wifi_connections():
-    return bool(get_settings().connections)
-
-
-def clear_wifi_connections():
-    if _nm_settings is not None:
-        _nm_settings.clear_wifi_connections()
-
-    config_path = _get_wifi_connections_path()
-    _create_wifi_connections(config_path)
+    return find_connection_by_id(GSM_CONNECTION_ID)
 
 
 def disconnect_access_points(ap_paths):
diff --git a/src/jarabe/model/olpcmesh.py b/src/jarabe/model/olpcmesh.py
index f070100..6ab7ab6 100644
--- a/src/jarabe/model/olpcmesh.py
+++ b/src/jarabe/model/olpcmesh.py
@@ -24,64 +24,61 @@ from jarabe.model.network import Settings
 from jarabe.model.network import OlpcMesh as OlpcMeshSettings
 from sugar.util import unique_id
 
-
-_NM_SERVICE = 'org.freedesktop.NetworkManager'
-_NM_IFACE = 'org.freedesktop.NetworkManager'
-_NM_PATH = '/org/freedesktop/NetworkManager'
-_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
-_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
-
 _XS_ANYCAST = '\xc0\x27\xc0\x27\xc0\x00'
 
-DEVICE_STATE_UNKNOWN = 0
-DEVICE_STATE_UNMANAGED = 1
-DEVICE_STATE_UNAVAILABLE = 2
-DEVICE_STATE_DISCONNECTED = 3
-DEVICE_STATE_PREPARE = 4
-DEVICE_STATE_CONFIG = 5
-DEVICE_STATE_NEED_AUTH = 6
-DEVICE_STATE_IP_CONFIG = 7
-DEVICE_STATE_ACTIVATED = 8
-DEVICE_STATE_FAILED = 9
-
 
 class OlpcMeshManager(object):
     def __init__(self, mesh_device):
         self._bus = dbus.SystemBus()
 
+        # counter for how many asynchronous connection additions we are
+        # waiting for
+        self._add_connections_pending = 0
+
         self.mesh_device = mesh_device
         self.eth_device = self._get_companion_device()
 
         self._connection_queue = []
         """Stack of connections that we'll iterate through until we find one
-           that works.
+           that works. Each entry in the list specifies the channel and
+           whether to seek an XS or not."""
 
-        """
+        # Ensure that all the connections we'll use later are present
+        for channel in (1, 6, 11):
+            self._ensure_connection_exists(channel, xs_hosted=True)
+            self._ensure_connection_exists(channel, xs_hosted=False)
 
         props = dbus.Interface(self.mesh_device, dbus.PROPERTIES_IFACE)
-        props.Get(_NM_DEVICE_IFACE, 'State',
+        props.Get(network.NM_DEVICE_IFACE, 'State',
                   reply_handler=self.__get_mesh_state_reply_cb,
                   error_handler=self.__get_state_error_cb)
 
         props = dbus.Interface(self.eth_device, dbus.PROPERTIES_IFACE)
-        props.Get(_NM_DEVICE_IFACE, 'State',
+        props.Get(network.NM_DEVICE_IFACE, 'State',
                   reply_handler=self.__get_eth_state_reply_cb,
                   error_handler=self.__get_state_error_cb)
 
         self._bus.add_signal_receiver(self.__eth_device_state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self.eth_device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
 
         self._bus.add_signal_receiver(self.__mshdev_state_changed_cb,
                                       signal_name='StateChanged',
                                       path=self.mesh_device.object_path,
-                                      dbus_interface=_NM_DEVICE_IFACE)
+                                      dbus_interface=network.NM_DEVICE_IFACE)
 
         self._idle_source = 0
-        self._mesh_device_state = DEVICE_STATE_UNKNOWN
-        self._eth_device_state = DEVICE_STATE_UNKNOWN
+        self._mesh_device_state = network.NM_DEVICE_STATE_UNKNOWN
+        self._eth_device_state = network.NM_DEVICE_STATE_UNKNOWN
 
+        if self._add_connections_pending == 0:
+            self.ready()
+
+    def ready(self):
+        """Called when all connections have been added (if they were not
+        already present), meaning that we can start the automesh functionality.
+        """
         if self._have_configured_connections():
             self._start_automesh_timer()
         else:
@@ -89,11 +86,11 @@ class OlpcMeshManager(object):
 
     def _get_companion_device(self):
         props = dbus.Interface(self.mesh_device, dbus.PROPERTIES_IFACE)
-        eth_device_o = props.Get(_NM_OLPC_MESH_IFACE, 'Companion')
-        return self._bus.get_object(_NM_SERVICE, eth_device_o)
+        eth_device_o = props.Get(network.NM_OLPC_MESH_IFACE, 'Companion')
+        return self._bus.get_object(network.NM_SERVICE, eth_device_o)
 
     def _have_configured_connections(self):
-        return len(network.get_settings().connections) > 0
+        return len(network.get_connections().get_list()) > 0
 
     def _start_automesh_timer(self):
         """Start our timer system which basically looks for 10 seconds of
@@ -123,8 +120,8 @@ class OlpcMeshManager(object):
         self._eth_device_state = new_state
         self._maybe_schedule_idle_check()
 
-        if new_state >= DEVICE_STATE_PREPARE \
-                and new_state <= DEVICE_STATE_ACTIVATED \
+        if new_state >= network.NM_DEVICE_STATE_PREPARE \
+                and new_state <= network.NM_DEVICE_STATE_ACTIVATED \
                 and len(self._connection_queue) > 0:
             self._connection_queue = []
 
@@ -132,62 +129,81 @@ class OlpcMeshManager(object):
         self._mesh_device_state = new_state
         self._maybe_schedule_idle_check()
 
-        if new_state == DEVICE_STATE_FAILED:
+        if new_state == network.NM_DEVICE_STATE_FAILED:
             self._try_next_connection_from_queue()
-        elif new_state == DEVICE_STATE_ACTIVATED \
+        elif new_state == network.NM_DEVICE_STATE_ACTIVATED \
                 and len(self._connection_queue) > 0:
             self._empty_connection_queue()
 
     def _maybe_schedule_idle_check(self):
-        if self._mesh_device_state == DEVICE_STATE_DISCONNECTED \
-                and self._eth_device_state == DEVICE_STATE_DISCONNECTED:
+        if self._mesh_device_state == network.NM_DEVICE_STATE_DISCONNECTED \
+                and self._eth_device_state == network.NM_DEVICE_STATE_DISCONNECTED:
             self._start_automesh_timer()
 
     def _idle_check(self):
-        if self._mesh_device_state == DEVICE_STATE_DISCONNECTED \
-                and self._eth_device_state == DEVICE_STATE_DISCONNECTED:
+        if self._mesh_device_state == network.NM_DEVICE_STATE_DISCONNECTED \
+                and self._eth_device_state == network.NM_DEVICE_STATE_DISCONNECTED:
             logging.debug('starting automesh due to inactivity')
             self._start_automesh()
         return False
 
-    def _make_connection(self, channel, anycast_address=None):
-        wireless_config = OlpcMeshSettings(channel, anycast_address)
+    @staticmethod
+    def _get_connection_id(channel, xs_hosted):
+        if xs_hosted:
+            return '%s%d' % (network.XS_MESH_CONNECTION_ID_PREFIX, channel)
+        else:
+            return '%s%d' % (network.MESH_CONNECTION_ID_PREFIX, channel)
+
+    def _connection_added(self):
+        if self._add_connections_pending > 0:
+            self._add_connections_pending = self._add_connections_pending - 1
+            if self._add_connections_pending == 0:
+                self.ready()
+
+    def _add_connection_reply_cb(self, connection):
+        logging.debug("Added connection: %s", connection)
+        self._connection_added()
+
+    def _add_connection_err_cb(self, err):
+        logging.debug("Error adding mesh connection: %s", err)
+        self._connection_added()
+
+    def _add_connection(self, channel, xs_hosted):
+        anycast_addr = _XS_ANYCAST if xs_hosted else None
+        wireless_config = OlpcMeshSettings(channel, anycast_addr)
         settings = Settings(wireless_cfg=wireless_config)
-        if not anycast_address:
+        if not xs_hosted:
             settings.ip4_config = network.IP4Config()
             settings.ip4_config.method = 'link-local'
-        settings.connection.id = 'olpc-mesh-' + str(channel)
+        settings.connection.id = self._get_connection_id(channel, xs_hosted)
+        settings.connection.autoconnect = False
         settings.connection.uuid = unique_id()
         settings.connection.type = '802-11-olpc-mesh'
-        connection = network.add_connection(settings.connection.id, settings)
-        return connection
-
-    def __activate_reply_cb(self, connection):
-        logging.debug('Connection activated: %s', connection)
-
-    def __activate_error_cb(self, err):
-        logging.error('Failed to activate connection: %s', err)
-
-    def _activate_connection(self, channel, anycast_address=None):
-        logging.debug('activate channel %d anycast %r',
-                      channel, anycast_address)
-        proxy = self._bus.get_object(_NM_SERVICE, _NM_PATH)
-        network_manager = dbus.Interface(proxy, _NM_IFACE)
-        connection = self._make_connection(channel, anycast_address)
-
-        network_manager.ActivateConnection(network.SETTINGS_SERVICE,
-                connection.path,
-                self.mesh_device.object_path,
-                self.mesh_device.object_path,
-                reply_handler=self.__activate_reply_cb,
-                error_handler=self.__activate_error_cb)
+        network.add_connection(settings,
+                               reply_handler=self._add_connection_reply_cb,
+                               error_handler=self._add_connection_err_cb)
+
+    def _find_connection(self, channel, xs_hosted):
+        connection_id = self._get_connection_id(channel, xs_hosted)
+        return network.find_connection_by_id(connection_id)
+
+    def _ensure_connection_exists(self, channel, xs_hosted):
+        if not self._find_connection(channel, xs_hosted):
+            self._add_connection(channel, xs_hosted)
+
+    def _activate_connection(self, channel, xs_hosted):
+        connection = self._find_connection(channel, xs_hosted)
+        if connection:
+            connection.activate(self.mesh_device.object_path)
+        else:
+            logging.warning("Could not find mesh connection")
 
     def _try_next_connection_from_queue(self):
         if len(self._connection_queue) == 0:
             return
 
-        channel, anycast = self._connection_queue.pop()
-        self._activate_connection(channel, anycast)
+        channel, xs_hosted = self._connection_queue.pop()
+        self._activate_connection(channel, xs_hosted)
 
     def _empty_connection_queue(self):
         self._connection_queue = []
@@ -196,8 +212,8 @@ class OlpcMeshManager(object):
         """Activate a mesh connection on a user-specified channel.
         Looks for XS first, then resorts to simple mesh."""
         self._empty_connection_queue()
-        self._connection_queue.append((channel, None))
-        self._connection_queue.append((channel, _XS_ANYCAST))
+        self._connection_queue.append((channel, False))
+        self._connection_queue.append((channel, True))
         self._try_next_connection_from_queue()
 
     def _start_automesh(self):
@@ -205,8 +221,8 @@ class OlpcMeshManager(object):
         networks to connect to. First looks for XS on all channels, then falls
         back to simple mesh on channel 1."""
         self._empty_connection_queue()
-        self._connection_queue.append((1, None))
-        self._connection_queue.append((11, _XS_ANYCAST))
-        self._connection_queue.append((6, _XS_ANYCAST))
-        self._connection_queue.append((1, _XS_ANYCAST))
+        self._connection_queue.append((1, False))
+        self._connection_queue.append((11, True))
+        self._connection_queue.append((6, True))
+        self._connection_queue.append((1, True))
         self._try_next_connection_from_queue()
-- 
1.7.7.1



More information about the Sugar-devel mailing list