Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/rpms
diff options
context:
space:
mode:
authorBernie Innocenti <bernie@codewiz.org>2010-08-25 02:54:57 (GMT)
committer Bernie Innocenti <bernie@codewiz.org>2010-08-25 02:54:57 (GMT)
commit9e38b5be6f736f947763ca56435e455c20776754 (patch)
treeb71a2f7493bbe5ba44c451520e9131d1f6f54921 /rpms
parent731c306f07c9c1f72019bb8ac6751fabdbcdd1fa (diff)
Add patches for sl#1610 and sl#1673
sl#1673 obsoletes discard_network_connections.patch and causes a ripple effect on several other patches.
Diffstat (limited to 'rpms')
-rw-r--r--rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch2
-rw-r--r--rpms/sugar/discard_network_connections.patch46
-rw-r--r--rpms/sugar/sl1610-default-ad-hoc-networks.patch1120
-rw-r--r--rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch507
-rw-r--r--rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch292
-rw-r--r--rpms/sugar/sl1940-register-session-failed-fix.patch8
-rw-r--r--rpms/sugar/sugar.spec6
7 files changed, 1928 insertions, 53 deletions
diff --git a/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch b/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch
index 2b009f5..c1e426d 100644
--- a/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch
+++ b/rpms/sugar/accessibility_0001_cp_accessibility_keyboard.patch
@@ -469,8 +469,8 @@ diff -u -r -N sugar-0.88.1.original/src/jarabe/model/Makefile.am sugar-0.88.1/sr
--- sugar-0.88.1.original/src/jarabe/model/Makefile.am 2010-07-27 10:55:14.456503932 -0300
+++ sugar-0.88.1/src/jarabe/model/Makefile.am 2010-07-27 11:47:46.002753886 -0300
@@ -1,6 +1,7 @@
- sugardir = $(pythondir)/jarabe/model
sugar_PYTHON = \
+ adhoc.py \
__init__.py \
+ accessibility.py \
buddy.py \
diff --git a/rpms/sugar/discard_network_connections.patch b/rpms/sugar/discard_network_connections.patch
deleted file mode 100644
index 8a0943c..0000000
--- a/rpms/sugar/discard_network_connections.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From: Daniel Castelo
-
-diff -u -r -N sugar-0.88.1-copy/extensions/cpsection/network/model.py sugar-0.88.1/extensions/cpsection/network/model.py
---- sugar-0.88.1-copy/extensions/cpsection/network/model.py 2010-02-20 14:47:08.000000000 -0200
-+++ sugar-0.88.1/extensions/cpsection/network/model.py 2010-07-28 19:55:53.067894000 -0300
-@@ -15,10 +15,15 @@
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- #
-
-+import logging
-+import os
-+
- import dbus
- from gettext import gettext as _
- import gconf
-
-+from sugar import env
-+
- _NM_SERVICE = 'org.freedesktop.NetworkManager'
- _NM_PATH = '/org/freedesktop/NetworkManager'
- _NM_IFACE = 'org.freedesktop.NetworkManager'
-@@ -116,7 +121,15 @@
- def clear_networks():
- """Clear saved passwords and network configurations.
- """
-- pass
-+ profile_path = env.get_profile_path()
-+ config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
-+ config_file = open(config_path, 'w')
-+ try:
-+ config_file.write('')
-+ except:
-+ logging.exception('Can not write %s', config_path)
-+ f.close()
-+ return 1
-
- def get_publish_information():
- client = gconf.client_get_default()
-diff -u -r -N sugar-0.88.1-copy/extensions/cpsection/network/view.py sugar-0.88.1/extensions/cpsection/network/view.py
---- sugar-0.88.1-copy/extensions/cpsection/network/view.py 2010-02-20 14:47:08.000000000 -0200
-+++ sugar-0.88.1/extensions/cpsection/network/view.py 2010-07-28 19:54:18.746893000 -0300
-@@ -248,3 +248,4 @@
-
- def __network_configuration_reset_cb(self, widget):
- self._model.clear_networks()
-+ self.needs_restart = True
diff --git a/rpms/sugar/sl1610-default-ad-hoc-networks.patch b/rpms/sugar/sl1610-default-ad-hoc-networks.patch
new file mode 100644
index 0000000..1db172f
--- /dev/null
+++ b/rpms/sugar/sl1610-default-ad-hoc-networks.patch
@@ -0,0 +1,1120 @@
+From 5ff30eadf670f5225ae305f10e248c7d97a88fb4 Mon Sep 17 00:00:00 2001
+From: Simon Schampijer <simon@schampijer.de>
+Date: Fri, 13 Aug 2010 13:14:29 +0200
+Subject: [PATCH] Add default Ad-hoc networks #1610
+Organization: Sugar Labs Foundation
+X-Subversion: sucks
+
+This patch adds three default Ad-hoc networks, for channel 1, 6 and 11. They
+are represented with designated icons in the neighborhood view. This will
+mimic the mesh behavior on devices where mesh hardware is not available
+and make the "under a tree"-scenario possible in those cases. If Sugar sees
+no "known" network when it starts, it does autoconnect to an Ad-hoc network.
+
+http://wiki.sugarlabs.org/go/Features/Sugar_Adhoc_Networks
+---
+ data/sugar.schemas.in | 14 ++
+ extensions/deviceicon/network.py | 116 +++------------
+ src/jarabe/desktop/meshbox.py | 300 +++++++++++++++++++++++++++++++++-----
+ src/jarabe/model/Makefile.am | 1 +
+ src/jarabe/model/adhoc.py | 299 +++++++++++++++++++++++++++++++++++++
+ src/jarabe/model/network.py | 42 +++++-
+ 6 files changed, 639 insertions(+), 133 deletions(-)
+ create mode 100644 src/jarabe/model/adhoc.py
+
+diff --git a/data/sugar.schemas.in b/data/sugar.schemas.in
+index b9606ba..2e6b820 100644
+--- a/data/sugar.schemas.in
++++ b/data/sugar.schemas.in
+diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
+@@ -329,5 +329,18 @@
+ <long>GSM network personal unlock key configuration</long>
+ </locale>
+ </schema>
++ <schema>
++ <key>/schemas/desktop/sugar/network/adhoc</key>
++ <applyto>/desktop/sugar/network/adhoc</applyto>
++ <owner>sugar</owner>
++ <type>bool</type>
++ <default>true</default>
++ <locale name="C">
++ <short>Show Sugar Ad-hoc networks</short>
++ <long>If TRUE, Sugar will show default Ad-hoc networks for
++ channel 1,6 and 11. If Sugar sees no "known" network when
++ it starts, it does autoconnect to an Ad-hoc network.</long>
++ </locale>
++ </schema>
+ </schemalist>
+ </gconfschemafile>
+index b61de22..562d63b 100644
+--- a/extensions/deviceicon/network.py
++++ b/extensions/deviceicon/network.py
+@@ -68,24 +68,16 @@ _GSM_STATE_CONNECTING = 2
+ _GSM_STATE_CONNECTED = 3
+ _GSM_STATE_FAILED = 4
+
+-def frequency_to_channel(frequency):
+- ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4,
+- 2432: 5, 2437: 6, 2442: 7, 2447: 8,
+- 2452: 9, 2457: 10, 2462: 11, 2467: 12,
+- 2472: 13}
+- return ftoc[frequency]
+
+ class WirelessPalette(Palette):
+ __gtype_name__ = 'SugarWirelessPalette'
+
+ __gsignals__ = {
+ 'deactivate-connection' : (gobject.SIGNAL_RUN_FIRST,
+- gobject.TYPE_NONE, ([])),
+- 'create-connection' : (gobject.SIGNAL_RUN_FIRST,
+- gobject.TYPE_NONE, ([])),
++ gobject.TYPE_NONE, ([]))
+ }
+
+- def __init__(self, primary_text, can_create=True):
++ def __init__(self, primary_text):
+ Palette.__init__(self, label=primary_text)
+
+ self._disconnect_item = None
+@@ -119,12 +111,6 @@ class WirelessPalette(Palette):
+ self._disconnect_item.connect('activate', self.__disconnect_activate_cb)
+ self.menu.append(self._disconnect_item)
+
+- if can_create:
+- self._adhoc_item = gtk.MenuItem(_('Create new wireless network'))
+- self._adhoc_item.connect('activate', self.__adhoc_activate_cb)
+- self.menu.append(self._adhoc_item)
+- self._adhoc_item.show()
+-
+ def set_connecting(self):
+ self.props.secondary_text = _('Connecting...')
+
+@@ -151,14 +137,8 @@ class WirelessPalette(Palette):
+ def __disconnect_activate_cb(self, menuitem):
+ self.emit('deactivate-connection')
+
+- def __adhoc_activate_cb(self, menuitem):
+- self.emit('create-connection')
+-
+ def _set_frequency(self, frequency):
+- try:
+- channel = frequency_to_channel(frequency)
+- except KeyError:
+- channel = 0
++ channel = network.frequency_to_channel(frequency)
+ self._set_channel(channel)
+
+ def _set_channel(self, channel):
+@@ -391,7 +371,6 @@ class GsmPalette(Palette):
+
+ class WirelessDeviceView(ToolButton):
+
+- _ICON_NAME = 'network-wireless'
+ FRAME_POSITION_RELATIVE = 302
+
+ def __init__(self, device):
+@@ -410,7 +389,7 @@ class WirelessDeviceView(ToolButton):
+ self._active_ap_op = None
+
+ self._icon = PulsingIcon()
+- self._icon.props.icon_name = get_icon_state(self._ICON_NAME, 0)
++ self._icon.props.icon_name = get_icon_state('network-wireless', 0)
+ self._inactive_color = xocolor.XoColor( \
+ "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
+ style.COLOR_TRANSPARENT.get_svg()))
+@@ -424,8 +403,6 @@ class WirelessDeviceView(ToolButton):
+ self._palette = WirelessPalette(self._name)
+ self._palette.connect('deactivate-connection',
+ self.__deactivate_connection_cb)
+- self._palette.connect('create-connection',
+- self.__create_connection_cb)
+ self.set_palette(self._palette)
+ self._palette.set_group_id('frame')
+
+@@ -495,11 +472,6 @@ class WirelessDeviceView(ToolButton):
+ def __ap_properties_changed_cb(self, properties):
+ self._update_properties(properties)
+
+- def _name_encodes_colors(self):
+- """Match #XXXXXX,#YYYYYY at the end of the network name"""
+- return self._name[-7] == '#' and self._name[-8] == ',' \
+- and self._name[-15] == '#'
+-
+ def _update_properties(self, properties):
+ if 'Mode' in properties:
+ self._mode = properties['Mode']
+@@ -515,11 +487,9 @@ class WirelessDeviceView(ToolButton):
+ self._frequency = properties['Frequency']
+
+ if self._color == None:
+- if self._mode == network.NM_802_11_MODE_ADHOC \
+- and self._name_encodes_colors():
+- encoded_color = self._name.split("#", 1)
+- if len(encoded_color) == 2:
+- self._color = xocolor.XoColor('#' + encoded_color[1])
++ if self._mode == network.NM_802_11_MODE_ADHOC and \
++ network.is_sugar_adhoc_network(self._name):
++ self._color = profile.get_color()
+ else:
+ sha_hash = hashlib.sha1()
+ data = self._name + hex(self._flags)
+@@ -555,14 +525,24 @@ class WirelessDeviceView(ToolButton):
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+- if state == network.DEVICE_STATE_ACTIVATED:
+- icon_name = '%s-connected' % self._ICON_NAME
+- else:
+- icon_name = self._ICON_NAME
++ if self._mode != network.NM_802_11_MODE_ADHOC and \
++ network.is_sugar_adhoc_network(self._name) == False:
++ if state == network.DEVICE_STATE_ACTIVATED:
++ icon_name = '%s-connected' % 'network-wireless'
++ else:
++ icon_name = 'network-wireless'
+
+- icon_name = get_icon_state(icon_name, self._strength)
+- if icon_name:
+- self._icon.props.icon_name = icon_name
++ icon_name = get_icon_state(icon_name, self._strength)
++ if icon_name:
++ self._icon.props.icon_name = icon_name
++ else:
++ channel = network.frequency_to_channel(self._frequency)
++ if state == network.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 \
+@@ -601,54 +581,6 @@ class WirelessDeviceView(ToolButton):
+ netmgr.DeactivateConnection(conn_o)
+ break
+
+- def __create_connection_cb(self, palette, data=None):
+- """Create an 802.11 IBSS network.
+-
+- The user's color is encoded at the end of the network name. The network
+- name is truncated so that it does not exceed the 32 byte SSID limit.
+- """
+- client = gconf.client_get_default()
+- nick = client.get_string('/desktop/sugar/user/nick').decode('utf-8')
+- color = client.get_string('/desktop/sugar/user/color')
+- color_suffix = ' %s' % color
+-
+- format = _('%s\'s network').encode('utf-8')
+- extra_length = (len(format) - len('%s')) + len(color_suffix)
+- name_limit = 32 - extra_length
+-
+- # truncate the nick and use a regex to drop any partial characters
+- # at the end
+- nick = nick.encode('utf-8')[:name_limit]
+- pattern = "([\xf6-\xf7][\x80-\xbf]{0,2}|[\xe0-\xef][\x80-\xbf]{0,1}|[\xc0-\xdf])$"
+- nick = re.sub(pattern, '', nick)
+-
+- connection_name = format % nick
+- connection_name += color_suffix
+-
+- connection = network.find_connection_by_ssid(connection_name)
+- if connection is None:
+- settings = Settings()
+- settings.connection.id = 'Auto ' + connection_name
+- uuid = settings.connection.uuid = unique_id()
+- settings.connection.type = '802-11-wireless'
+- settings.wireless.ssid = dbus.ByteArray(connection_name)
+- settings.wireless.band = 'bg'
+- settings.wireless.mode = 'adhoc'
+- settings.ip4_config = IP4Config()
+- settings.ip4_config.method = 'link-local'
+-
+- connection = network.add_connection(uuid, 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)
+-
+ def __activate_reply_cb(self, connection):
+ logging.debug('Network created: %s', connection)
+
+diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
+index bc7f59b..ae63ad2 100644
+--- a/src/jarabe/desktop/meshbox.py
++++ b/src/jarabe/desktop/meshbox.py
+@@ -1,6 +1,6 @@
+ # Copyright (C) 2006-2007 Red Hat, Inc.
+ # Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+-# Copyright (C) 2009 One Laptop per Child
++# Copyright (C) 2009-2010 One Laptop per Child
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -25,6 +25,7 @@ import hippo
+ import hippo
+ import gobject
+ import gtk
++import gconf
+
+ from sugar.graphics.icon import CanvasIcon, Icon
+ from sugar.graphics.xocolor import XoColor
+@@ -53,6 +54,7 @@ from jarabe.model.network import IP4Config
+ from jarabe.model.network import WirelessSecurity
+ from jarabe.model.network import AccessPoint
+ from jarabe.model.olpcmesh import OlpcMeshManager
++from jarabe.model.adhoc import get_adhoc_manager_instance
+
+ _NM_SERVICE = 'org.freedesktop.NetworkManager'
+ _NM_IFACE = 'org.freedesktop.NetworkManager'
+@@ -67,6 +69,7 @@ _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+ _AP_ICON_NAME = 'network-wireless'
+ _OLPC_MESH_ICON_NAME = 'network-mesh'
+
++
+ class WirelessNetworkView(CanvasPulsingIcon):
+ def __init__(self, initial_ap):
+ CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE,
+@@ -90,11 +93,9 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ self._device_state = None
+ self._color = None
+
+- if self._mode == network.NM_802_11_MODE_ADHOC \
+- and self._name_encodes_colors():
+- encoded_color = self._name.split("#", 1)
+- if len(encoded_color) == 2:
+- self._color = xocolor.XoColor('#' + encoded_color[1])
++ if self._mode == network.NM_802_11_MODE_ADHOC and \
++ network.is_sugar_adhoc_network(self._name):
++ self._color = profile.get_color()
+ else:
+ sha_hash = hashlib.sha1()
+ data = self._name + hex(self._flags)
+@@ -147,11 +152,6 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ path=self._device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+- def _name_encodes_colors(self):
+- """Match #XXXXXX,#YYYYYY at the end of the network name"""
+- return self._name[-7] == '#' and self._name[-8] == ',' \
+- and self._name[-15] == '#'
+-
+ def _create_palette(self):
+ icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
+ self._palette_icon = Icon(icon_name=icon_name,
+@@ -222,21 +222,32 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ else:
+ state = network.DEVICE_STATE_UNKNOWN
+
+- if state == network.DEVICE_STATE_ACTIVATED:
+- connection = network.find_connection_by_ssid(self._name)
+- if connection:
+- if self._mode == network.NM_802_11_MODE_INFRA:
+- connection.set_connected()
+-
+- icon_name = '%s-connected' % _AP_ICON_NAME
+- else:
+- icon_name = _AP_ICON_NAME
+-
+- icon_name = get_icon_state(icon_name, self._strength)
+- if icon_name:
++ if self._mode == network.NM_802_11_MODE_ADHOC and \
++ network.is_sugar_adhoc_network(self._name):
++ channel = max([1] + [ap.channel for ap in
++ self._access_points.values()])
++ if state == network.DEVICE_STATE_ACTIVATED:
++ icon_name = 'network-adhoc-%s-connected' % channel
++ else:
++ icon_name = 'network-adhoc-%s' % channel
+ self.props.icon_name = icon_name
+ icon = self._palette.props.icon
+ icon.props.icon_name = icon_name
++ else:
++ if 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()
++ icon_name = '%s-connected' % _AP_ICON_NAME
++ else:
++ icon_name = _AP_ICON_NAME
++
++ icon_name = get_icon_state(icon_name, self._strength)
++ if icon_name:
++ self.props.icon_name = icon_name
++ icon = self._palette.props.icon
++ icon.props.icon_name = icon_name
+
+ if state == network.DEVICE_STATE_PREPARE or \
+ state == network.DEVICE_STATE_CONFIG or \
+@@ -259,15 +268,15 @@ class WirelessNetworkView(CanvasPulsingI
+ self.props.base_color = self._color
+
+ def _update_badge(self):
+- if network.find_connection_by_ssid(self._name) is not None:
+- self.props.badge_name = "emblem-favorite"
+- self._palette_icon.props.badge_name = "emblem-favorite"
+- elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
+- self.props.badge_name = "emblem-locked"
+- self._palette_icon.props.badge_name = "emblem-locked"
+- else:
+- self.props.badge_name = None
+- self._palette_icon.props.badge_name = None
++ self.props.badge_name = None
++ self._palette_icon.props.badge_name = None
++ if self._mode != network.NM_802_11_MODE_ADHOC:
++ if network.find_connection_by_ssid(self._name) is not None:
++ self.props.badge_name = "emblem-favorite"
++ self._palette_icon.props.badge_name = "emblem-favorite"
++ elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
++ self.props.badge_name = "emblem-locked"
++ self._palette_icon.props.badge_name = "emblem-locked"
+
+ def _disconnect_activate_cb(self, item):
+ connection = network.find_connection_by_ssid(self._name)
+@@ -444,6 +455,139 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ path=self._device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
++class SugarAdhocView(CanvasPulsingIcon):
++ """To mimic the mesh behavior on devices where mesh hardware is
++ not available we support the creation of an Ad-hoc network on
++ three channels 1, 6, 11. This is the class for an icon
++ representing a channel in the neighborhood view.
++
++ """
++
++ _ICON_NAME = 'network-adhoc-'
++ _NAME = 'Ad-hoc Network '
++
++ def __init__(self, channel):
++ CanvasPulsingIcon.__init__(self,
++ icon_name=self._ICON_NAME + str(channel),
++ size=style.STANDARD_ICON_SIZE, cache=True)
++ self._bus = dbus.SystemBus()
++ self._channel = channel
++ self._disconnect_item = None
++ self._connect_item = None
++ self._palette_icon = None
++ self._greyed_out = False
++
++ get_adhoc_manager_instance().connect('members-changed',
++ self.__members_changed_cb)
++ get_adhoc_manager_instance().connect('state-changed',
++ self.__state_changed_cb)
++
++ self.connect('button-release-event', self.__button_release_event_cb)
++
++ pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
++ style.COLOR_TRANSPARENT.get_svg()))
++ self.props.pulse_color = pulse_color
++ self._state_color = XoColor('%s,%s' % \
++ (profile.get_color().get_stroke_color(),
++ style.COLOR_TRANSPARENT.get_svg()))
++ self.props.base_color = self._state_color
++ self._palette = self._create_palette()
++ self.set_palette(self._palette)
++ self._palette_icon.props.xo_color = self._state_color
++
++ def _create_palette(self):
++ self._palette_icon = Icon( \
++ icon_name=self._ICON_NAME + str(self._channel),
++ icon_size=style.STANDARD_ICON_SIZE)
++
++ palette_ = palette.Palette(_("Ad-hoc Network %d") % self._channel,
++ icon=self._palette_icon)
++
++ self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
++ self._connect_item.connect('activate', self.__connect_activate_cb)
++ palette_.menu.append(self._connect_item)
++
++ self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
++ self._disconnect_item.connect('activate',
++ self.__disconnect_activate_cb)
++ palette_.menu.append(self._disconnect_item)
++
++ return palette_
++
++ def __button_release_event_cb(self, icon, event):
++ get_adhoc_manager_instance().activate_channel(self._channel)
++
++ def __connect_activate_cb(self, icon):
++ get_adhoc_manager_instance().activate_channel(self._channel)
++
++ def __disconnect_activate_cb(self, icon):
++ get_adhoc_manager_instance().deactivate_active_channel()
++
++ def __state_changed_cb(self, adhoc_manager, channel, device_state):
++ if self._channel == channel:
++ state = device_state
++ else:
++ state = network.DEVICE_STATE_UNKNOWN
++
++ if state == network.DEVICE_STATE_ACTIVATED:
++ icon_name = '%s-connected' % (self._ICON_NAME + str(self._channel))
++ else:
++ icon_name = self._ICON_NAME + str(self._channel)
++
++ self.props.base_color = self._state_color
++ self._palette_icon.props.xo_color = self._state_color
++
++ if icon_name is not None:
++ self.props.icon_name = icon_name
++ 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 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:
++ if self._disconnect_item:
++ self._disconnect_item.show()
++ self._connect_item.hide()
++ self._palette.props.secondary_text = _('Connected')
++ self.props.pulsing = False
++ else:
++ if self._disconnect_item:
++ self._disconnect_item.hide()
++ self._connect_item.show()
++ self._palette.props.secondary_text = None
++ self.props.pulsing = False
++
++ def _update_color(self):
++ if self._greyed_out:
++ self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
++ else:
++ self.props.base_color = self._state_color
++
++ def __members_changed_cb(self, adhoc_manager, channel, has_members):
++ if channel == self._channel:
++ if has_members == True:
++ self._state_color = profile.get_color()
++ self.props.base_color = self._state_color
++ self._palette_icon.props.xo_color = self._state_color
++ else:
++ color = '%s,%s' % (profile.get_color().get_stroke_color(),
++ style.COLOR_TRANSPARENT.get_svg())
++ self._state_color = XoColor(color)
++ self.props.base_color = self._state_color
++ self._palette_icon.props.xo_color = self._state_color
++
++ def set_filter(self, query):
++ name = self._NAME + str(self._channel)
++ self._greyed_out = name.lower().find(query) == -1
++ self._update_color()
++
+
+ class OlpcMeshView(CanvasPulsingIcon):
+ def __init__(self, mesh_mgr, channel):
+@@ -765,13 +909,19 @@ class MeshToolbar(gtk.Toolbar):
+ return False
+
+
+-class DeviceObserver(object):
+- def __init__(self, box, device):
+- self._box = box
++class DeviceObserver(gobject.GObject):
++ __gsignals__ = {
++ 'access-point-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
++ ([gobject.TYPE_PYOBJECT])),
++ 'access-point-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
++ ([gobject.TYPE_PYOBJECT]))
++ }
++ def __init__(self, device):
++ gobject.GObject.__init__(self)
+ self._bus = dbus.SystemBus()
+- self._device = device
++ self.device = device
+
+- wireless = dbus.Interface(self._device, _NM_WIRELESS_IFACE)
++ wireless = dbus.Interface(device, _NM_WIRELESS_IFACE)
+ wireless.GetAccessPoints(reply_handler=self._get_access_points_reply_cb,
+ error_handler=self._get_access_points_error_cb)
+
+@@ -787,30 +937,33 @@ class DeviceObserver(object):
+ 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)
+- self._box.add_access_point(self._device, ap)
++ 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)
+- self._box.add_access_point(self._device, ap)
++ self.emit('access-point-added', ap)
+
+ def __access_point_removed_cb(self, access_point_o):
+- self._box.remove_access_point(access_point_o)
++ self.emit('access-point-removed', access_point_o)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__access_point_added_cb,
+ signal_name='AccessPointAdded',
+- path=self._device.object_path,
++ path=self.device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+ self._bus.remove_signal_receiver(self.__access_point_removed_cb,
+ signal_name='AccessPointRemoved',
+- path=self._device.object_path,
++ path=self.device.object_path,
+ dbus_interface=_NM_WIRELESS_IFACE)
+
+
+ class NetworkManagerObserver(object):
++
++ _SHOW_ADHOC_GCONF_KEY = '/desktop/sugar/network/adhoc'
++
+ def __init__(self, box):
+ self._box = box
+ self._bus = None
+@@ -818,6 +971,9 @@ class NetworkManagerObserver(object):
+ self._netmgr = None
+ self._olpc_mesh_device_o = None
+
++ client = gconf.client_get_default()
++ self._have_adhoc_networks = client.get_bool(self._SHOW_ADHOC_GCONF_KEY)
++
+ def listen(self):
+ try:
+ self._bus = dbus.SystemBus()
+@@ -836,6 +992,9 @@ class NetworkManagerObserver(object):
+ self._bus.add_signal_receiver(self.__device_removed_cb,
+ signal_name='DeviceRemoved',
+ dbus_interface=_NM_IFACE)
++ self._bus.add_signal_receiver(self.__properties_changed_cb,
++ signal_name='PropertiesChanged',
++ dbus_interface=_NM_IFACE)
+
+ settings = network.get_settings()
+ if settings is not None:
+@@ -879,7 +1038,13 @@ class NetworkManagerObserver(object):
+
+ device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+- self._devices[device_o] = DeviceObserver(self._box, device)
++ self._devices[device_o] = DeviceObserver(device)
++ self._devices[device_o].connect('access-point-added',
++ self.__ap_added_cb)
++ self._devices[device_o].connect('access-point-removed',
++ 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:
+ self._olpc_mesh_device_o = device_o
+ self._box.enable_olpc_mesh(device)
+@@ -895,11 +1060,30 @@ class NetworkManagerObserver(object):
+ observer = self._devices[device_o]
+ observer.disconnect()
+ del self._devices[device_o]
++ if self._have_adhoc_networks:
++ self._box.remove_adhoc_networks()
+ return
+
+ if self._olpc_mesh_device_o == device_o:
+ self._box.disable_olpc_mesh(device_o)
+
++ def __ap_added_cb(self, device_observer, access_point):
++ self._box.add_access_point(device_observer.device, access_point)
++
++ def __ap_removed_cb(self, device_observer, access_point_o):
++ self._box.remove_access_point(access_point_o)
++
++ def __properties_changed_cb(self, properties):
++ if 'WirelessHardwareEnabled' in properties:
++ if properties['WirelessHardwareEnabled']:
++ if not self._have_adhoc_networks:
++ self._box.remove_adhoc_networks()
++ elif properties['WirelessHardwareEnabled']:
++ for device in self._devices:
++ if self._have_adhoc_networks:
++ self._box.add_adhoc_networks(device)
++
++
+ class MeshBox(gtk.VBox):
+ __gtype_name__ = 'SugarMeshBox'
+
+@@ -909,6 +1093,8 @@ class MeshBox(gtk.VBox):
+ gobject.GObject.__init__(self)
+
+ self.wireless_networks = {}
++ self._adhoc_manager = None
++ self._adhoc_networks = []
+
+ self._model = neighborhood.get_model()
+ self._buddies = {}
+@@ -1066,6 +1252,15 @@ class MeshBox(gtk.VBox):
+ ap.disconnect()
+ return
+
++ if self._adhoc_manager is not None and \
++ network.is_sugar_adhoc_network(ap.name) and \
++ ap.mode == network.NM_802_11_MODE_ADHOC:
++ if old_hash is None: # new Ad-hoc network finished initializing
++ self._adhoc_manager.add_access_point(ap)
++ # we are called as well in other cases but we do not need to
++ # act here as we don't display signal strength for Ad-hoc networks
++ return
++
+ if old_hash is None: # new AP finished initializing
+ self._add_ap_to_network(ap)
+ return
+@@ -1088,6 +1283,11 @@ class MeshBox(gtk.VBox):
+ ap.initialize()
+
+ def remove_access_point(self, ap_o):
++ if self._adhoc_manager is not None:
++ if self._adhoc_manager.is_sugar_adhoc_access_point(ap_o):
++ self._adhoc_manager.remove_access_point(ap_o)
++ return
++
+ # we don't keep an index of ap object path to network, but since
+ # we'll only ever have a handful of networks, just try them all...
+ for net in self.wireless_networks.values():
+@@ -1104,6 +1304,26 @@ class MeshBox(gtk.VBox):
+ # it (e.g. olpc-mesh adhoc network)
+ logging.debug('Can not remove access point %s' % ap_o)
+
++ def add_adhoc_networks(self, device):
++ if self._adhoc_manager is None:
++ self._adhoc_manager = get_adhoc_manager_instance()
++ self._adhoc_manager.start_listening(device)
++ self._add_adhoc_network_icon(1)
++ self._add_adhoc_network_icon(6)
++ self._add_adhoc_network_icon(11)
++ self._adhoc_manager.autoconnect()
++
++ def remove_adhoc_networks(self):
++ for icon in self._adhoc_networks:
++ icon.disconnect()
++ self._layout.remove(icon)
++ self._adhoc_networks = []
++
++ def _add_adhoc_network_icon(self, channel):
++ icon = SugarAdhocView(channel)
++ self._layout.add(icon)
++ self._adhoc_networks.append(icon)
++
+ def _add_olpc_mesh_icon(self, mesh_mgr, channel):
+ icon = OlpcMeshView(mesh_mgr, channel)
+ self._layout.add(icon)
+diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am
+index e9f0700..4650c3b 100644
+--- a/src/jarabe/model/Makefile.am
++++ b/src/jarabe/model/Makefile.am
+@@ -1,5 +1,6 @@
+ sugardir = $(pythondir)/jarabe/model
+ sugar_PYTHON = \
++ adhoc.py \
+ __init__.py \
+ buddy.py \
+ bundleregistry.py \
+diff --git a/src/jarabe/model/adhoc.py b/src/jarabe/model/adhoc.py
+new file mode 100644
+index 0000000..65dac01
+--- /dev/null
++++ b/src/jarabe/model/adhoc.py
+@@ -0,0 +1,299 @@
++# Copyright (C) 2010 One Laptop per Child
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++
++import logging
++
++import dbus
++import gobject
++
++from jarabe.model import network
++from jarabe.model.network import Settings
++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
++def get_adhoc_manager_instance():
++ global _adhoc_manager_instance
++ if _adhoc_manager_instance is None:
++ _adhoc_manager_instance = AdHocManager()
++ return _adhoc_manager_instance
++
++
++class AdHocManager(gobject.GObject):
++ """To mimic the mesh behavior on devices where mesh hardware is
++ not available we support the creation of an Ad-hoc network on
++ three channels 1, 6, 11. If Sugar sees no "known" network when it
++ starts, it does autoconnect to an Ad-hoc network.
++
++ """
++
++ __gsignals__ = {
++ 'members-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
++ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
++ 'state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
++ ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
++ }
++
++ _AUTOCONNECT_TIMEOUT = 30
++ _CHANNEL_1 = 1
++ _CHANNEL_6 = 6
++ _CHANNEL_11 = 11
++
++ def __init__(self):
++ gobject.GObject.__init__(self)
++
++ self._bus = dbus.SystemBus()
++ self._device = None
++ self._idle_source = 0
++ self._listening_called = 0
++ self._device_state = network.DEVICE_STATE_UNKNOWN
++
++ self._current_channel = None
++ self._networks = {self._CHANNEL_1: None,
++ self._CHANNEL_6: None,
++ self._CHANNEL_11: None}
++
++ def start_listening(self, device):
++ self._listening_called += 1
++ if self._listening_called > 1:
++ raise RuntimeError('The start listening method can' \
++ ' only be called once.')
++
++ self._device = device
++ props = dbus.Interface(device,
++ 'org.freedesktop.DBus.Properties')
++ props.Get(_NM_DEVICE_IFACE, 'State',
++ reply_handler=self.__get_device_state_reply_cb,
++ error_handler=self.__get_state_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)
++
++ self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
++ signal_name='PropertiesChanged',
++ path=self._device.object_path,
++ dbus_interface=_NM_WIRELESS_IFACE)
++
++ def stop_listening(self):
++ self._bus.remove_signal_receiver(self.__device_state_changed_cb,
++ signal_name='StateChanged',
++ path=self._device.object_path,
++ dbus_interface=_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)
++
++ def __get_state_error_cb(self, err):
++ logging.debug('Error getting the device state: %s', err)
++
++ def __get_device_state_reply_cb(self, state):
++ self._device_state = state
++
++ def __device_state_changed_cb(self, new_state, old_state, reason):
++ self._device_state = new_state
++ self._update_state()
++
++ def __wireless_properties_changed_cb(self, properties):
++ if 'ActiveAccessPoint' in properties and \
++ properties['ActiveAccessPoint'] != '/':
++ active_ap = self._bus.get_object(_NM_SERVICE,
++ properties['ActiveAccessPoint'])
++ props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
++ props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
++ reply_handler=self.__get_all_ap_props_reply_cb,
++ error_handler=self.__get_all_ap_props_error_cb)
++
++ def __get_all_ap_props_reply_cb(self, properties):
++ if properties['Mode'] == network.NM_802_11_MODE_ADHOC and \
++ 'Frequency' in properties:
++ frequency = properties['Frequency']
++ self._current_channel = network.frequency_to_channel(frequency)
++ else:
++ self._current_channel = None
++ self._update_state()
++
++ def __get_all_ap_props_error_cb(self, err):
++ logging.error('Error getting the access point properties: %s', err)
++
++ 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):
++ """Autoconnect to an Ad-hoc network"""
++ if self._have_configured_connections():
++ self._autoconnect_adhoc_timer()
++ else:
++ self._autoconnect_adhoc()
++
++ def _autoconnect_adhoc_timer(self):
++ """Start a timer which basically looks for 30 seconds of inactivity
++ on the device, then does autoconnect to an Ad-hoc network.
++
++ """
++ if self._idle_source != 0:
++ gobject.source_remove(self._idle_source)
++ self._idle_source = gobject.timeout_add_seconds( \
++ self._AUTOCONNECT_TIMEOUT, self.__idle_check_cb)
++
++ def __idle_check_cb(self):
++ if self._device_state == network.DEVICE_STATE_DISCONNECTED:
++ logging.debug("Connect to Ad-hoc network due to inactivity.")
++ self._autoconnect_adhoc()
++ return False
++
++ def _autoconnect_adhoc(self):
++ """First we try if there is an Ad-hoc network that is used by other
++ learners in the area, if not we default to channel 1.
++
++ """
++ if self._networks[self._CHANNEL_1] is not None:
++ self._connect(self._CHANNEL_1)
++ elif self._networks[self._CHANNEL_6] is not None:
++ self._connect(self._CHANNEL_6)
++ elif self._networks[self._CHANNEL_11] is not None:
++ self._connect(self._CHANNEL_11)
++ else:
++ self._connect(self._CHANNEL_1)
++
++ def activate_channel(self, channel):
++ """Activate a sugar Ad-hoc network.
++
++ Keyword arguments:
++ 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.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)
++
++ 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)
++
++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
++ netmgr_props.Get(_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)
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
++ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
++ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
++ access_point_o = props.Get(_NM_ACTIVE_CONN_IFACE,
++ 'SpecificObject')
++ if access_point_o != '/':
++ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
++ netmgr = dbus.Interface(obj, _NM_IFACE)
++ netmgr.DeactivateConnection(connection_o)
++
++ def __get_active_connections_error_cb(self, err):
++ logging.error('Error getting the active connections: %s', err)
++
++ def __activate_reply_cb(self, connection):
++ logging.debug('Ad-hoc network created: %s', connection)
++
++ def __activate_error_cb(self, err):
++ logging.error('Failed to create Ad-hoc network: %s', err)
++
++ def add_access_point(self, access_point):
++ """Add an access point to a network and notify the view to idicate
++ the member change.
++
++ Keyword arguments:
++ access_point -- Access Point
++
++ """
++ if access_point.name.endswith(' 1'):
++ self._networks[self._CHANNEL_1] = access_point
++ self.emit('members-changed', self._CHANNEL_1, True)
++ elif access_point.name.endswith(' 6'):
++ self._networks[self._CHANNEL_6] = access_point
++ self.emit('members-changed', self._CHANNEL_6, True)
++ elif access_point.name.endswith('11'):
++ self._networks[self._CHANNEL_11] = access_point
++ self.emit('members-changed', self._CHANNEL_11, True)
++
++ def is_sugar_adhoc_access_point(self, ap_object_path):
++ """Checks whether an access point is part of a sugar Ad-hoc network.
++
++ Keyword arguments:
++ ap_object_path -- Access Point object path
++
++ Return: Boolean
++
++ """
++ for access_point in self._networks.values():
++ if access_point is not None:
++ if access_point.model.object_path == ap_object_path:
++ return True
++ return False
++
++ def remove_access_point(self, ap_object_path):
++ """Remove an access point from a sugar Ad-hoc network.
++
++ Keyword arguments:
++ ap_object_path -- Access Point object path
++
++ """
++ for channel in self._networks:
++ if self._networks[channel] is not None:
++ if self._networks[channel].model.object_path == ap_object_path:
++ self.emit('members-changed', channel, False)
++ self._networks[channel] = None
++ break
+diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
+index 47db43f..984da67 100644
+--- a/src/jarabe/model/network.py
++++ b/src/jarabe/model/network.py
+@@ -1,6 +1,6 @@
+ # Copyright (C) 2008 Red Hat, Inc.
+ # Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+-# Copyright (C) 2009 One Laptop per Child
++# Copyright (C) 2009-2010 One Laptop per Child
+ # Copyright (C) 2009 Paraguay Educa, Martin Abente
+ # Copyright (C) 2010 Plan Ceibal, Daniel Castelo
+ #
+@@ -100,6 +100,39 @@ GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk'
+ _nm_settings = None
+ _conn_counter = 0
+
++
++def frequency_to_channel(frequency):
++ """Returns the channel matching a given radio channel frequency. If a
++ frequency is not in the dictionary channel 1 will be returned.
++
++ Keyword arguments:
++ frequency -- The radio channel frequency in MHz.
++
++ Return: Channel
++
++ """
++ ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4,
++ 2432: 5, 2437: 6, 2442: 7, 2447: 8,
++ 2452: 9, 2457: 10, 2462: 11, 2467: 12,
++ 2472: 13}
++ if frequency not in ftoc:
++ logging.warning("The frequency %s can not be mapped to a channel, " \
++ "defaulting to channel 1.", frequncy)
++ return 1
++ return ftoc[frequency]
++
++def is_sugar_adhoc_network(ssid):
++ """Checks whether an access point is a sugar Ad-hoc network.
++
++ Keyword arguments:
++ ssid -- Ssid of the access point.
++
++ Return: Boolean
++
++ """
++ return ssid.startswith('Ad-hoc Network')
++
++
+ class WirelessSecurity(object):
+ def __init__(self):
+ self.key_mgmt = None
+@@ -127,6 +160,7 @@ class Wireless(object):
+ self.security = None
+ self.mode = None
+ self.band = None
++ self.channel = None
+
+ def get_dict(self):
+ wireless = {'ssid': self.ssid}
+@@ -136,6 +170,8 @@ class Wireless(object):
+ wireless['mode'] = self.mode
+ if self.band:
+ wireless['band'] = self.band
++ if self.channel:
++ wireless['channel'] = self.channel
+ return wireless
+
+
+@@ -476,6 +512,7 @@ class AccessPoint(gobject.GObject):
+ self.wpa_flags = 0
+ self.rsn_flags = 0
+ self.mode = 0
++ self.channel = 0
+
+ def initialize(self):
+ model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE)
+@@ -545,6 +582,9 @@ class AccessPoint(gobject.GObject):
+ self.rsn_flags = properties['RsnFlags']
+ if 'Mode' in properties:
+ self.mode = properties['Mode']
++ if 'Frequency' in properties:
++ self.channel = frequency_to_channel(properties['Frequency'])
++
+ self._initialized = True
+ self.emit('props-changed', old_hash)
+
+--
+1.7.2.2
+
diff --git a/rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch b/rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch
new file mode 100644
index 0000000..1f06ce9
--- /dev/null
+++ b/rpms/sugar/sl1673-fix-network-disconnect-and-discard-history-v2.patch
@@ -0,0 +1,507 @@
+From 7ae1a9903237c0d26bebbf699084eb258a533173 Mon Sep 17 00:00:00 2001
+From: James Cameron <quozl@laptop.org>
+Date: Tue, 25 May 2010 17:27:44 +1000
+Subject: [PATCH] fix network disconnect and discard history
+
+User interface changes:
+
+- enable the disconnect button on the access point menu in the
+ neighbourhood view, (rather than the button doing nothing),
+
+- fix the disconnect button on the wireless device icon in the frame
+ so that the disconnection remains effective, (rather than
+ disconnecting and then reconnecting automatically),
+
+- enable the discard network history button in the network control
+ panel, which also now forces a disconnect, and will be insensitive
+ if there are no networks to be discarded, (rather than the button
+ doing nothing),
+
+- enforce consistency between the neighbourhood view, the frame, and
+ the control panel, with respect to how the access point is shown.
+
+References:
+
+ http://dev.laptop.org/ticket/9977 (fixes a workaround)
+ http://bugs.sugarlabs.org/ticket/1673
+ http://bugs.sugarlabs.org/ticket/1802
+ http://bugs.sugarlabs.org/ticket/1737
+ http://bugs.sugarlabs.org/ticket/1736
+ http://bugs.sugarlabs.org/ticket/1608
+ http://dev.laptop.org/ticket/9788
+---
+ extensions/cpsection/network/model.py | 12 ++++--
+ extensions/cpsection/network/view.py | 8 ++++-
+ extensions/deviceicon/network.py | 37 ++++++++++---------
+ src/jarabe/desktop/meshbox.py | 61 +++++++++++++++++++++----------
+ src/jarabe/model/network.py | 62 ++++++++++++++++++++++++++------
+ 5 files changed, 125 insertions(+), 55 deletions(-)
+
+diff --git a/extensions/cpsection/network/model.py b/extensions/cpsection/network/model.py
+index e1c3dab..2bc5e3a 100644
+--- a/extensions/cpsection/network/model.py
++++ b/extensions/cpsection/network/model.py
+@@ -17,6 +17,7 @@
+
+ import dbus
+ from gettext import gettext as _
++from jarabe.model import network
+ import gconf
+
+ _NM_SERVICE = 'org.freedesktop.NetworkManager'
+@@ -68,7 +69,7 @@ def get_radio():
+ try:
+ bus = dbus.SystemBus()
+ obj = bus.get_object(_NM_SERVICE, _NM_PATH)
+- nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _NM_SERVICE)
+
+@@ -89,7 +90,7 @@ def set_radio(state):
+ try:
+ bus = dbus.SystemBus()
+ obj = bus.get_object(_NM_SERVICE, _NM_PATH)
+- nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _NM_SERVICE)
+ nm_props.Set(_NM_IFACE, 'WirelessEnabled', True)
+@@ -97,7 +98,7 @@ def set_radio(state):
+ try:
+ bus = dbus.SystemBus()
+ obj = bus.get_object(_NM_SERVICE, _NM_PATH)
+- nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ except dbus.DBusException:
+ raise ReadError('%s service not available' % _NM_SERVICE)
+ nm_props.Set(_NM_IFACE, 'WirelessEnabled', False)
+@@ -116,7 +117,10 @@ def clear_registration():
+ def clear_networks():
+ """Clear saved passwords and network configurations.
+ """
+- pass
++ network.clear_wifi_connections()
++
++def count_networks():
++ return network.count_wifi_connections()
+
+ def get_publish_information():
+ client = gconf.client_get_default()
+diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py
+index 588daeb..b0f1336 100644
+--- a/extensions/cpsection/network/view.py
++++ b/extensions/cpsection/network/view.py
+@@ -104,6 +104,8 @@ class Network(SectionView):
+ self._clear_history_button = gtk.Button()
+ self._clear_history_button.set_label(_('Discard network history'))
+ box_clear_history.pack_start(self._clear_history_button, expand=False)
++ if self._model.count_networks() == 0:
++ self._clear_history_button.set_sensitive(False)
+ self._clear_history_button.show()
+ box_wireless.pack_start(box_clear_history, expand=False)
+ box_clear_history.show()
+@@ -217,7 +219,9 @@ class Network(SectionView):
+ self._radio_alert.props.msg = detail
+ self._radio_valid = False
+ else:
+- self._radio_valid = True
++ self._radio_valid = True
++ if self._model.count_networks() != 0:
++ self._clear_history_button.set_sensitive(True)
+
+ self._validate()
+ return False
+@@ -248,3 +252,5 @@ class Network(SectionView):
+
+ def __network_configuration_reset_cb(self, widget):
+ self._model.clear_networks()
++ if self._model.count_networks() == 0:
++ self._clear_history_button.set_sensitive(False)
+diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
+index 94a4293..a828497 100644
+--- a/extensions/deviceicon/network.py
++++ b/extensions/deviceicon/network.py
+@@ -352,8 +352,7 @@ class WirelessDeviceView(ToolButton):
+ self.set_palette(self._palette)
+ self._palette.set_group_id('frame')
+
+- self._device_props = dbus.Interface(self._device,
+- 'org.freedesktop.DBus.Properties')
++ self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+ self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__get_device_props_reply_cb,
+ error_handler=self.__get_device_props_error_cb)
+@@ -394,7 +393,7 @@ class WirelessDeviceView(ToolButton):
+ return
+ self._active_ap_op = active_ap_op
+ active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op)
+- props = dbus.Interface(active_ap, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
+
+ props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
+ reply_handler=self.__get_all_ap_props_reply_cb,
+@@ -508,17 +507,21 @@ class WirelessDeviceView(ToolButton):
+ self._icon.props.base_color = self._color
+
+ def __deactivate_connection_cb(self, palette, data=None):
++ connection = network.find_connection_by_ssid(self._name)
++ if connection:
++ if self._mode == network.NM_802_11_MODE_INFRA:
++ connection.set_disconnected()
++
+ if self._active_ap_op is not None:
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+- netmgr_props = dbus.Interface(
+- netmgr, 'org.freedesktop.DBus.Properties')
++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
+ active_connections_o = netmgr_props.Get(_NM_IFACE,
+ 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+ if ap_op == self._active_ap_op:
+ netmgr.DeactivateConnection(conn_o)
+@@ -608,8 +611,7 @@ class OlpcMeshDeviceView(ToolButton):
+ self.set_palette(self._palette)
+ self._palette.set_group_id('frame')
+
+- self._device_props = dbus.Interface(self._device,
+- 'org.freedesktop.DBus.Properties')
++ self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+ self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__get_device_props_reply_cb,
+ error_handler=self.__get_device_props_error_cb)
+@@ -681,19 +683,19 @@ class OlpcMeshDeviceView(ToolButton):
+ def __deactivate_connection(self, palette, data=None):
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+- netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
+ active_connections_o = netmgr_props.Get(_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)
+- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+
+ try:
+ obj = self._bus.get_object(_NM_IFACE, ap_op)
+- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if type == network.DEVICE_TYPE_802_11_OLPC_MESH:
+ netmgr.DeactivateConnection(conn_o)
+@@ -756,7 +758,7 @@ class GsmDeviceView(TrayIcon):
+
+ self._palette = palette
+
+- props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+ props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__current_state_check_cb,
+ error_handler=self.__current_state_check_error_cb)
+@@ -785,12 +787,12 @@ class GsmDeviceView(TrayIcon):
+ def __gsm_disconnect_cb(self, palette, data=None):
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+- netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
+ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices')
+ if self._device.object_path in devices:
+ netmgr.DeactivateConnection(
+@@ -910,7 +912,7 @@ class WiredDeviceObserver(object):
+ self._device_view = None
+ self._tray = tray
+
+- props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+ props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__get_device_props_reply_cb,
+ error_handler=self.__get_device_props_error_cb)
+@@ -938,8 +940,7 @@ class WiredDeviceObserver(object):
+
+ def _update_state(self, state):
+ if state == network.DEVICE_STATE_ACTIVATED:
+- props = dbus.Interface(self._device,
+- 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE)
+ address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address')
+ speed = props.Get(_NM_WIRED_IFACE, 'Speed')
+ self._device_view = WiredDeviceView(speed, address)
+@@ -997,7 +998,7 @@ class NetworkManagerObserver(object):
+
+ def _check_device(self, device_op):
+ nm_device = self._bus.get_object(_NM_SERVICE, device_op)
+- props = dbus.Interface(nm_device, 'org.freedesktop.DBus.Properties')
++ 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:
+diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
+index a04922b..280adb9 100644
+--- a/src/jarabe/desktop/meshbox.py
++++ b/src/jarabe/desktop/meshbox.py
+@@ -86,7 +86,6 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ self._rsn_flags = initial_ap.rsn_flags
+ self._device_caps = 0
+ self._device_state = None
+- self._connection = None
+ self._color = None
+
+ if self._mode == network.NM_802_11_MODE_ADHOC \
+@@ -115,18 +114,9 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ self.set_palette(self._palette)
+ self._palette_icon.props.xo_color = self._color
+
+- if network.find_connection_by_ssid(self._name) is not None:
+- self.props.badge_name = "emblem-favorite"
+- self._palette_icon.props.badge_name = "emblem-favorite"
+- elif initial_ap.flags == network.NM_802_11_AP_FLAGS_PRIVACY:
+- self.props.badge_name = "emblem-locked"
+- self._palette_icon.props.badge_name = "emblem-locked"
+- else:
+- self.props.badge_name = None
+- self._palette_icon.props.badge_name = None
++ self._update_badge()
+
+- interface_props = dbus.Interface(self._device,
+- 'org.freedesktop.DBus.Properties')
++ 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)
+@@ -174,6 +164,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ def __device_state_changed_cb(self, new_state, old_state, reason):
+ self._device_state = new_state
+ self._update_state()
++ self._update_badge()
+
+ def __update_active_ap(self, ap_path):
+ if ap_path in self._access_points:
+@@ -214,6 +205,7 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ def _update(self):
+ self._update_state()
+ self._update_color()
++ self._update_badge()
+
+ def _update_state(self):
+ if self._active_ap is not None:
+@@ -266,8 +258,40 @@ class WirelessNetworkView(CanvasPulsingIcon):
+ else:
+ self.props.base_color = self._color
+
++ def _update_badge(self):
++ if network.find_connection_by_ssid(self._name) is not None:
++ self.props.badge_name = "emblem-favorite"
++ self._palette_icon.props.badge_name = "emblem-favorite"
++ elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
++ self.props.badge_name = "emblem-locked"
++ self._palette_icon.props.badge_name = "emblem-locked"
++ else:
++ self.props.badge_name = None
++ self._palette_icon.props.badge_name = None
++
+ def _disconnect_activate_cb(self, item):
+- pass
++ connection = network.find_connection_by_ssid(self._name)
++ if connection:
++ if self._mode == network.NM_802_11_MODE_INFRA:
++ connection.set_disconnected()
++
++ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
++ netmgr = dbus.Interface(obj, _NM_IFACE)
++
++ netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
++ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
++
++ for conn_o in active_connections_o:
++ obj = self._bus.get_object(_NM_IFACE, conn_o)
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
++ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
++ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
++ ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
++ if ap_o != '/' and self.find_ap(ap_o) is not None:
++ netmgr.DeactivateConnection(conn_o)
++ else:
++ logging.error('Could not determine AP for'
++ ' specific object %s' % conn_o)
+
+ def _add_ciphers_from_flags(self, flags, pairwise):
+ ciphers = []
+@@ -456,14 +480,12 @@ class OlpcMeshView(CanvasPulsingIcon):
+ self._greyed_out = False
+ self._name = ''
+ self._device_state = None
+- self._connection = None
+ self._active = False
+ device = mesh_mgr.mesh_device
+
+ self.connect('button-release-event', self.__button_release_event_cb)
+
+- interface_props = dbus.Interface(device,
+- 'org.freedesktop.DBus.Properties')
++ interface_props = dbus.Interface(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)
+@@ -849,13 +871,12 @@ class NetworkManagerObserver(object):
+ # 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, 'org.freedesktop.DBus.Properties')
++ netmgr_props = dbus.Interface(self._netmgr, dbus.PROPERTIES_IFACE)
+ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+- props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
+ state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
+ if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+ ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
+@@ -879,7 +900,7 @@ class NetworkManagerObserver(object):
+
+ def _check_device(self, device_o):
+ device = self._bus.get_object(_NM_SERVICE, device_o)
+- props = dbus.Interface(device, 'org.freedesktop.DBus.Properties')
++ props = dbus.Interface(device, dbus.PROPERTIES_IFACE)
+
+ device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+ if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
+index 3a949da..33088c4 100644
+--- a/src/jarabe/model/network.py
++++ b/src/jarabe/model/network.py
+@@ -330,6 +330,13 @@ class NMSettings(dbus.service.Object):
+ 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.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
+@@ -358,6 +365,16 @@ class NMSettingsConnection(dbus.service.Object):
+ 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())
+@@ -366,8 +383,17 @@ class NMSettingsConnection(dbus.service.Object):
+ 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()
+
++ def set_disconnected(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:
+@@ -377,8 +403,7 @@ class NMSettingsConnection(dbus.service.Object):
+ return self._settings
+
+ def save(self):
+- profile_path = env.get_profile_path()
+- config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
++ config_path = _get_wifi_connections_path()
+
+ config = ConfigParser.ConfigParser()
+ try:
+@@ -477,8 +502,7 @@ class AccessPoint(gobject.GObject):
+ self.mode = 0
+
+ def initialize(self):
+- model_props = dbus.Interface(self.model,
+- 'org.freedesktop.DBus.Properties')
++ model_props = dbus.Interface(self.model, dbus.PROPERTIES_IFACE)
+ model_props.GetAll(NM_ACCESSPOINT_IFACE, byte_arrays=True,
+ reply_handler=self._ap_properties_changed_cb,
+ error_handler=self._get_all_props_error_cb)
+@@ -590,19 +614,23 @@ def add_connection(uuid, settings, secrets=None):
+ _nm_settings.add_connection(uuid, conn)
+ return conn
+
+-def load_wifi_connections():
++def _get_wifi_connections_path():
+ profile_path = env.get_profile_path()
+- config_path = os.path.join(profile_path, 'nm', 'connections.cfg')
++ return os.path.join(profile_path, 'nm', 'connections.cfg')
+
+- config = ConfigParser.ConfigParser()
++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 load_wifi_connections():
++ config_path = _get_wifi_connections_path()
+
+ if not os.path.exists(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')
+- config.write(f)
+- f.close()
++ _create_wifi_connections(config_path)
+
++ config = ConfigParser.ConfigParser()
+ try:
+ if not config.read(config_path):
+ logging.error('Error reading the nm config file')
+@@ -708,3 +736,13 @@ def find_gsm_connection():
+
+ logging.debug('There is no gsm connection in the NMSettings.')
+ return None
++
++def count_wifi_connections():
++ return len(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)
+--
+1.7.1
+
diff --git a/rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch b/rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch
new file mode 100644
index 0000000..03dd862
--- /dev/null
+++ b/rpms/sugar/sl1814-consolidate-activity-launch-entry-point.patch
@@ -0,0 +1,292 @@
+From 1a32f508e70ccbfe2f9dad65260727222c7a727b Mon Sep 17 00:00:00 2001
+From: Aleksey Lim <alsroot@member.fsf.org>
+Date: Thu, 11 Mar 2010 15:55:05 +0000
+Subject: Use only one entry point for activity launch #1814
+
+
+diff --git a/src/jarabe/desktop/activitieslist.py b/src/jarabe/desktop/activitieslist.py
+index 87f2af0..e14d0f7 100644
+--- a/src/jarabe/desktop/activitieslist.py
++++ b/src/jarabe/desktop/activitieslist.py
+@@ -36,6 +36,7 @@ from sugar.activity.activityhandle import ActivityHandle
+ from jarabe.model import bundleregistry
+ from jarabe.view.palettes import ActivityPalette
+ from jarabe.view import launcher
++from jarabe.journal import misc
+
+ class ActivitiesTreeView(gtk.TreeView):
+ __gtype_name__ = 'SugarActivitiesTreeView'
+@@ -143,13 +144,7 @@ class ActivitiesTreeView(gtk.TreeView):
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(row[ListModel.COLUMN_BUNDLE_ID])
+
+- activity_id = activityfactory.create_activity_id()
+-
+- client = gconf.client_get_default()
+- xo_color = XoColor(client.get_string('/desktop/sugar/user/color'))
+-
+- launcher.add_launcher(activity_id, bundle.get_icon(), xo_color)
+- activityfactory.create(bundle, ActivityHandle(activity_id))
++ misc.launch(bundle)
+
+ def set_filter(self, query):
+ self._query = query.lower()
+diff --git a/src/jarabe/desktop/favoritesview.py b/src/jarabe/desktop/favoritesview.py
+index 9f3c37b..a843741 100644
+--- a/src/jarabe/desktop/favoritesview.py
++++ b/src/jarabe/desktop/favoritesview.py
+@@ -484,16 +484,7 @@ class ActivityIcon(CanvasIcon):
+ if self._resume_mode and self._journal_entries:
+ self._resume(self._journal_entries[0])
+ else:
+- client = gconf.client_get_default()
+- xo_color = XoColor(client.get_string('/desktop/sugar/user/color'))
+-
+- activity_id = activityfactory.create_activity_id()
+- launcher.add_launcher(activity_id,
+- self._activity_info.get_icon(),
+- xo_color)
+-
+- handle = ActivityHandle(activity_id)
+- activityfactory.create(self._activity_info, handle)
++ misc.launch(self._activity_info)
+
+ def get_bundle_id(self):
+ return self._activity_info.get_bundle_id()
+diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
+index a04922b..10aa514 100644
+--- a/src/jarabe/desktop/meshbox.py
++++ b/src/jarabe/desktop/meshbox.py
+@@ -47,12 +47,12 @@ from jarabe.desktop.spreadlayout import SpreadLayout
+ from jarabe.desktop import keydialog
+ from jarabe.model import bundleregistry
+ from jarabe.model import network
+-from jarabe.model import shell
+ from jarabe.model.network import Settings
+ from jarabe.model.network import IP4Config
+ from jarabe.model.network import WirelessSecurity
+ from jarabe.model.network import AccessPoint
+ from jarabe.model.olpcmesh import OlpcMeshManager
++from jarabe.journal import misc
+
+ _NM_SERVICE = 'org.freedesktop.NetworkManager'
+ _NM_IFACE = 'org.freedesktop.NetworkManager'
+@@ -654,21 +654,11 @@ class ActivityView(hippo.CanvasBox):
+ icon.destroy()
+
+ def _clicked_cb(self, item):
+- shell_model = shell.get_model()
+- activity = shell_model.get_activity_by_id(self._model.get_id())
+- if activity:
+- activity.get_window().activate(gtk.get_current_event_time())
+- return
+-
+ bundle_id = self._model.get_bundle_id()
+ bundle = bundleregistry.get_registry().get_bundle(bundle_id)
+
+- launcher.add_launcher(self._model.get_id(),
+- bundle.get_icon(),
+- self._model.get_color())
+-
+- handle = ActivityHandle(self._model.get_id())
+- activityfactory.create(bundle, handle)
++ misc.launch(bundle, activity_id=self._model.get_id(),
++ color=self._model.get_color())
+
+ def set_filter(self, query):
+ text_to_check = self._model.activity.props.name.lower() + \
+diff --git a/src/jarabe/frame/activitiestray.py b/src/jarabe/frame/activitiestray.py
+index b5762ee..b7bf621 100644
+--- a/src/jarabe/frame/activitiestray.py
++++ b/src/jarabe/frame/activitiestray.py
+@@ -49,6 +49,7 @@ from jarabe.view.pulsingicon import PulsingIcon
+ from jarabe.view import launcher
+ from jarabe.frame.frameinvoker import FrameWidgetInvoker
+ from jarabe.frame.notification import NotificationIcon
++from jarabe.journal import misc
+ import jarabe.frame
+
+
+@@ -164,22 +165,10 @@ class ActivityInviteButton(BaseInviteButton):
+
+ def _launch(self):
+ """Join the activity in the invite."""
+-
+- shell_model = shell.get_model()
+- activity = shell_model.get_activity_by_id(self._activity_model.get_id())
+- if activity:
+- activity.get_window().activate(gtk.get_current_event_time())
+- return
+-
+ registry = bundleregistry.get_registry()
+ bundle = registry.get_bundle(self._bundle_id)
+
+- launcher.add_launcher(self._activity_model.get_id(),
+- bundle.get_icon(),
+- self._activity_model.get_color())
+-
+- handle = ActivityHandle(self._activity_model.get_id())
+- activityfactory.create(bundle, handle)
++ misc.launch(bundle, color=self._activity_model.get_color())
+
+ class PrivateInviteButton(BaseInviteButton):
+ """Invite to a private one to one channel"""
+@@ -223,7 +212,7 @@ class PrivateInviteButton(BaseInviteButton):
+
+ def _launch(self):
+ """Start the activity with private channel."""
+- activityfactory.create_with_uri(self._bundle, self._private_channel)
++ misc.launch(self._bundle, uri=self._private_channel)
+
+ class BaseInvitePalette(Palette):
+ """Palette for frame or notification icon for invites."""
+@@ -272,8 +261,7 @@ class ActivityInvitePalette(BaseInvitePalette):
+ self.set_primary_text(self._bundle_id)
+
+ def _join(self):
+- handle = ActivityHandle(self._activity_model.get_id())
+- activityfactory.create(self._bundle, handle)
++ misc.launch(self._bundle, activity_id=self._activity_model.get_id())
+
+ def _decline(self):
+ invites = owner.get_model().get_invites()
+@@ -298,7 +286,7 @@ class PrivateInvitePalette(BaseInvitePalette):
+ self.set_primary_text(self._bundle_id)
+
+ def _join(self):
+- activityfactory.create_with_uri(self._bundle, self._private_channel)
++ misc.launch(self._bundle, uri=self._private_channel)
+
+ invites = owner.get_model().get_invites()
+ invites.remove_private_channel(self._private_channel)
+diff --git a/src/jarabe/journal/misc.py b/src/jarabe/journal/misc.py
+index 24ad216..65e5221 100644
+--- a/src/jarabe/journal/misc.py
++++ b/src/jarabe/journal/misc.py
+@@ -168,7 +168,7 @@ def resume(metadata, bundle_id=None):
+ bundle.get_bundle_id())
+ installed_bundle = registry.get_bundle(bundle.get_bundle_id())
+ if installed_bundle:
+- activityfactory.create(installed_bundle)
++ launch(installed_bundle)
+ else:
+ logging.error('Bundle %r is not installed.',
+ bundle.get_bundle_id())
+@@ -192,17 +192,11 @@ def resume(metadata, bundle_id=None):
+ logging.debug('activityfactory.creating with uri %s', uri)
+
+ activity_bundle = registry.get_bundle(activities[0].get_bundle_id())
+- activityfactory.create_with_uri(activity_bundle, bundle.get_start_uri())
++ launch(activity_bundle, uri=uri)
++
+ else:
+ activity_id = metadata.get('activity_id', '')
+
+- if activity_id:
+- shell_model = shell.get_model()
+- activity = shell_model.get_activity_by_id(activity_id)
+- if activity:
+- activity.get_window().activate(gtk.get_current_event_time())
+- return
+-
+ if bundle_id is None:
+ activities = get_activities(metadata)
+ if not activities:
+@@ -213,20 +207,36 @@ def resume(metadata, bundle_id=None):
+
+ bundle = registry.get_bundle(bundle_id)
+
+-
+ if metadata.get('mountpoint', '/') == '/':
+ object_id = metadata['uid']
+ else:
+ object_id = model.copy(metadata, '/')
+
+- if activity_id:
+- launcher.add_launcher(activity_id, bundle.get_icon(),
+- get_icon_color(metadata))
+- handle = ActivityHandle(object_id=object_id,
+- activity_id=activity_id)
+- activityfactory.create(bundle, handle)
+- else:
+- activityfactory.create_with_object_id(bundle, object_id)
++ launch(bundle, activity_id=activity_id, object_id=object_id,
++ color=get_icon_color(metadata))
++
++def launch(bundle, activity_id=None, object_id=None, uri=None, color=None):
++ if activity_id is None:
++ activity_id = activityfactory.create_activity_id()
++
++ logging.debug('launch bundle_id=%s activity_id=%s object_id=%s uri=%s',
++ bundle.get_bundle_id(), activity_id, object_id, uri)
++
++ shell_model = shell.get_model()
++ activity = shell_model.get_activity_by_id(activity_id)
++ if activity is not None:
++ logging.debug('re-launch %r', activity.get_window())
++ activity.get_window().activate(gtk.get_current_event_time())
++ return
++
++ if color is None:
++ client = gconf.client_get_default()
++ color = XoColor(client.get_string('/desktop/sugar/user/color'))
++
++ launcher.add_launcher(activity_id, bundle.get_icon(), color)
++ activity_handle = ActivityHandle(activity_id=activity_id,
++ object_id=object_id, uri=uri)
++ activityfactory.create(bundle, activity_handle)
+
+ def is_activity_bundle(metadata):
+ mime_type = metadata.get('mime_type', '')
+diff --git a/src/jarabe/model/shell.py b/src/jarabe/model/shell.py
+index e03e0f7..c1380d1 100644
+--- a/src/jarabe/model/shell.py
++++ b/src/jarabe/model/shell.py
+@@ -559,6 +559,11 @@ class ShellModel(gobject.GObject):
+ raise ValueError("Activity service name '%s'" \
+ " was not found in the bundle registry."
+ % service_name)
++
++ home_activity = self.get_activity_by_id(activity_id)
++ if home_activity is not None:
++ self._remove_activity(home_activity)
++
+ home_activity = Activity(activity_info, activity_id)
+ home_activity.props.launching = True
+ self._add_activity(home_activity)
+diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
+index 2beceff..0c0e957 100644
+--- a/src/jarabe/view/palettes.py
++++ b/src/jarabe/view/palettes.py
+@@ -32,8 +32,8 @@ from sugar.activity import activityfactory
+ from sugar.activity.activityhandle import ActivityHandle
+
+ from jarabe.model import shell
+-from jarabe.view import launcher
+ from jarabe.view.viewsource import setup_view_source
++from jarabe.journal import misc
+
+ class BasePalette(Palette):
+ def __init__(self, home_activity):
+@@ -133,17 +133,7 @@ class ActivityPalette(Palette):
+
+ def __start_activate_cb(self, menu_item):
+ self.popdown(immediate=True)
+-
+- client = gconf.client_get_default()
+- xo_color = XoColor(client.get_string('/desktop/sugar/user/color'))
+-
+- activity_id = activityfactory.create_activity_id()
+- launcher.add_launcher(activity_id,
+- self._activity_info.get_icon(),
+- xo_color)
+-
+- handle = ActivityHandle(activity_id)
+- activityfactory.create(self._activity_info, handle)
++ misc.launch(self._activity_info)
+
+ class JournalPalette(BasePalette):
+ def __init__(self, home_activity):
+--
+1.6.5.3
+
diff --git a/rpms/sugar/sl1940-register-session-failed-fix.patch b/rpms/sugar/sl1940-register-session-failed-fix.patch
index e5060b2..261b4ee 100644
--- a/rpms/sugar/sl1940-register-session-failed-fix.patch
+++ b/rpms/sugar/sl1940-register-session-failed-fix.patch
@@ -18,7 +18,7 @@ index 47db43f..218752c 100644
from sugar import dispatch
from sugar import env
@@ -501,6 +502,16 @@ class NMSettingsConnection(dbus.service.Object):
- if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
+ self.Updated(self._settings.get_dict())
self.save()
+ try:
@@ -31,8 +31,8 @@ index 47db43f..218752c 100644
+ except:
+ logging.error('Error calling libc.__res_init')
+
- def set_secrets(self, secrets):
- self._secrets = secrets
- if self._settings.connection.type == NM_CONNECTION_TYPE_802_11_WIRELESS:
+ def set_disconnected(self):
+ if self._settings.connection.type != NM_CONNECTION_TYPE_GSM and \
+ self._settings.connection.autoconnect:
--
diff --git a/rpms/sugar/sugar.spec b/rpms/sugar/sugar.spec
index 4bfa7ae..22df3a4 100644
--- a/rpms/sugar/sugar.spec
+++ b/rpms/sugar/sugar.spec
@@ -3,7 +3,7 @@
Summary: Constructionist learning platform
Name: sugar
Version: 0.88.1
-Release: 5.31dxo%{?dist}
+Release: 5.34dxo%{?dist}
URL: http://sugarlabs.org/
Source0: http://download.sugarlabs.org/sources/sucrose/glucose/%{name}/%{name}-%{version}.tar.bz2
@@ -30,7 +30,7 @@ Patch16: journal-xobundle-removal-wont-remove-installed-one.patch
Patch18: disconnect-icon-in-wifi-palette-1736.patch
Patch19: improve-activity-updater-icon.patch
Patch20: indicate-inactive-state-in-mesh-device-icon.patch
-Patch21: discard_network_connections.patch
+Patch21: sl1673-fix-network-disconnect-and-discard-history-v2.patch
#Patch22: sl1814-consolidate-activity-launch-entry-point.patch
Patch23: sl1940-register-session-failed-fix.patch
@@ -61,6 +61,7 @@ Patch504: sl2064-always-listen-for-NameOwnerChanged-DBus-message.patch
Patch506: jasg-register-rename.patch
Patch507: prevent-multiple-XS-icons-when-re-register.patch
Patch508: microformat-updater.patch
+Patch509: sl1610-default-ad-hoc-networks.patch
# tch experimental patches
patch601: bundle-Delete-profile-data-only-when-erased.patch
@@ -198,6 +199,7 @@ multiple instances of sugar.
%patch506 -p1
%patch507 -p1
%patch508 -p1
+%patch509 -p1
%patch601 -p1
%patch602 -p1