Ticket #1610: 0001-Add-default-Ad-hoc-networks-1610-5.patch

File 0001-Add-default-Ad-hoc-networks-1610-5.patch, 44.9 KB (added by erikos, 12 years ago)

fixed a typo

  • data/sugar.schemas.in

    From e0d1315cbb39d5f4f9ecfd68006d8fa5b84d834d Mon Sep 17 00:00:00 2001
    From: Simon Schampijer <simon@schampijer.de>
    Date: Thu, 12 Aug 2010 16:26:52 +0200
    Subject: [PATCH] Add default Ad-hoc networks #1610
    
    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.
    ---
     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 b  
    329329      </locale>
    330330    </schema>
    331331
     332    <schema>
     333      <key>/schemas/desktop/sugar/network/adhoc</key>
     334      <applyto>/desktop/sugar/network/adhoc</applyto>
     335      <owner>sugar</owner>
     336      <type>bool</type>
     337      <default>true</default>
     338      <locale name="C">
     339        <short>Show Sugar Ad-hoc networks</short>
     340        <long>If TRUE, Sugar will show default Ad-hoc networks for
     341          channel 1,6 and 11. If Sugar sees no "known" network when
     342          it starts, it does autoconnect to an Ad-hoc network.</long>
     343      </locale>
     344    </schema>
     345
    332346  </schemalist>
    333347</gconfschemafile>
  • extensions/deviceicon/network.py

    diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
    index 227ba46..d76e8f1 100644
    a b _GSM_STATE_CONNECTING = 2 
    6767_GSM_STATE_CONNECTED = 3
    6868_GSM_STATE_NEED_AUTH = 4
    6969
    70 def frequency_to_channel(frequency):
    71     ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4,
    72              2432: 5, 2437: 6, 2442: 7, 2447: 8,
    73              2452: 9, 2457: 10, 2462: 11, 2467: 12,
    74              2472: 13}
    75     return ftoc[frequency]
    7670
    7771class WirelessPalette(Palette):
    7872    __gtype_name__ = 'SugarWirelessPalette'
    7973
    8074    __gsignals__ = {
    8175        'deactivate-connection' : (gobject.SIGNAL_RUN_FIRST,
    82                                    gobject.TYPE_NONE, ([])),
    83         'create-connection'     : (gobject.SIGNAL_RUN_FIRST,
    84                                    gobject.TYPE_NONE, ([])),
     76                                   gobject.TYPE_NONE, ([]))
    8577    }
    8678
    87     def __init__(self, primary_text, can_create=True):
     79    def __init__(self, primary_text):
    8880        Palette.__init__(self, label=primary_text)
    8981
    9082        self._disconnect_item = None
    class WirelessPalette(Palette): 
    117109        self._disconnect_item.connect('activate', self.__disconnect_activate_cb)
    118110        self.menu.append(self._disconnect_item)
    119111
    120         if can_create:
    121             self._adhoc_item = gtk.MenuItem(_('Create new wireless network'))
    122             self._adhoc_item.connect('activate', self.__adhoc_activate_cb)
    123             self.menu.append(self._adhoc_item)
    124             self._adhoc_item.show()
    125 
    126112    def set_connecting(self):
    127113        self.props.secondary_text = _('Connecting...')
    128114
    class WirelessPalette(Palette): 
    149135    def __disconnect_activate_cb(self, menuitem):
    150136        self.emit('deactivate-connection')
    151137
    152     def __adhoc_activate_cb(self, menuitem):
    153         self.emit('create-connection')
    154 
    155138    def _set_frequency(self, frequency):
    156         try:
    157             channel = frequency_to_channel(frequency)
    158         except KeyError:
    159             channel = 0
     139        channel = network.frequency_to_channel(frequency)
    160140        self._set_channel(channel)
    161141
    162142    def _set_channel(self, channel):
    class GsmPalette(Palette): 
    318298
    319299class WirelessDeviceView(ToolButton):
    320300
    321     _ICON_NAME = 'network-wireless'
    322301    FRAME_POSITION_RELATIVE = 302
    323302
    324303    def __init__(self, device):
    class WirelessDeviceView(ToolButton): 
    337316        self._active_ap_op = None
    338317
    339318        self._icon = PulsingIcon()
    340         self._icon.props.icon_name = get_icon_state(self._ICON_NAME, 0)
     319        self._icon.props.icon_name = get_icon_state('network-wireless', 0)
    341320        self._inactive_color = xocolor.XoColor( \
    342321            "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
    343322                       style.COLOR_TRANSPARENT.get_svg()))
    class WirelessDeviceView(ToolButton): 
    351330        self._palette = WirelessPalette(self._name)
    352331        self._palette.connect('deactivate-connection',
    353332                              self.__deactivate_connection_cb)
    354         self._palette.connect('create-connection',
    355                               self.__create_connection_cb)
    356333        self.set_palette(self._palette)
    357334        self._palette.set_group_id('frame')
    358335
    class WirelessDeviceView(ToolButton): 
    422399    def __ap_properties_changed_cb(self, properties):
    423400        self._update_properties(properties)
    424401
    425     def _name_encodes_colors(self):
    426         """Match #XXXXXX,#YYYYYY at the end of the network name"""
    427         return self._name[-7] == '#' and self._name[-8] == ',' \
    428             and self._name[-15] == '#'
    429 
    430402    def _update_properties(self, properties):
    431403        if 'Mode' in properties:
    432404            self._mode = properties['Mode']
    class WirelessDeviceView(ToolButton): 
    442414            self._frequency = properties['Frequency']
    443415
    444416        if self._color == None:
    445             if self._mode == network.NM_802_11_MODE_ADHOC \
    446                     and self._name_encodes_colors():
    447                 encoded_color = self._name.split("#", 1)
    448                 if len(encoded_color) == 2:
    449                     self._color = xocolor.XoColor('#' + encoded_color[1])
     417            if self._mode == network.NM_802_11_MODE_ADHOC and \
     418                    network.is_sugar_adhoc_network(self._name):
     419                self._color = profile.get_color()
    450420            else:
    451421                sha_hash = hashlib.sha1()
    452422                data = self._name + hex(self._flags)
    class WirelessDeviceView(ToolButton): 
    482452        else:
    483453            state = network.DEVICE_STATE_UNKNOWN
    484454
    485         if state == network.DEVICE_STATE_ACTIVATED:
    486             icon_name = '%s-connected' % self._ICON_NAME
    487         else:
    488             icon_name = self._ICON_NAME
     455        if self._mode != network.NM_802_11_MODE_ADHOC and \
     456                network.is_sugar_adhoc_network(self._name) == False:
     457            if state == network.DEVICE_STATE_ACTIVATED:
     458                icon_name = '%s-connected' % 'network-wireless'
     459            else:
     460                icon_name = 'network-wireless'
    489461
    490         icon_name = get_icon_state(icon_name, self._strength)
    491         if icon_name:
    492             self._icon.props.icon_name = icon_name
     462            icon_name = get_icon_state(icon_name, self._strength)
     463            if icon_name:
     464                self._icon.props.icon_name = icon_name
     465        else:
     466            channel = network.frequency_to_channel(self._frequency)
     467            if state == network.DEVICE_STATE_ACTIVATED:
     468                self._icon.props.icon_name = 'network-adhoc-%s-connected' \
     469                        % channel
     470            else:
     471                self._icon.props.icon_name = 'network-adhoc-%s' % channel
     472            self._icon.props.base_color = profile.get_color()
    493473
    494474        if state == network.DEVICE_STATE_PREPARE or \
    495475           state == network.DEVICE_STATE_CONFIG or \
    class WirelessDeviceView(ToolButton): 
    528508                    netmgr.DeactivateConnection(conn_o)
    529509                    break
    530510
    531     def __create_connection_cb(self, palette, data=None):
    532         """Create an 802.11 IBSS network.
    533 
    534         The user's color is encoded at the end of the network name. The network
    535         name is truncated so that it does not exceed the 32 byte SSID limit.
    536         """
    537         client = gconf.client_get_default()
    538         nick = client.get_string('/desktop/sugar/user/nick').decode('utf-8')
    539         color = client.get_string('/desktop/sugar/user/color')
    540         color_suffix = ' %s' % color
    541 
    542         format = _('%s\'s network').encode('utf-8')
    543         extra_length = (len(format) - len('%s')) + len(color_suffix)
    544         name_limit = 32 - extra_length
    545 
    546         # truncate the nick and use a regex to drop any partial characters
    547         # at the end
    548         nick = nick.encode('utf-8')[:name_limit]
    549         pattern = "([\xf6-\xf7][\x80-\xbf]{0,2}|[\xe0-\xef][\x80-\xbf]{0,1}|[\xc0-\xdf])$"
    550         nick = re.sub(pattern, '', nick)
    551 
    552         connection_name = format % nick
    553         connection_name += color_suffix
    554 
    555         connection = network.find_connection_by_ssid(connection_name)
    556         if connection is None:
    557             settings = Settings()
    558             settings.connection.id = 'Auto ' + connection_name
    559             uuid = settings.connection.uuid = unique_id()
    560             settings.connection.type = '802-11-wireless'
    561             settings.wireless.ssid = dbus.ByteArray(connection_name)
    562             settings.wireless.band = 'bg'
    563             settings.wireless.mode = 'adhoc'
    564             settings.ip4_config = IP4Config()
    565             settings.ip4_config.method = 'link-local'
    566 
    567             connection = network.add_connection(uuid, settings)
    568 
    569         obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
    570         netmgr = dbus.Interface(obj, _NM_IFACE)
    571 
    572         netmgr.ActivateConnection(network.SETTINGS_SERVICE,
    573                                   connection.path,
    574                                   self._device.object_path,
    575                                   '/',
    576                                   reply_handler=self.__activate_reply_cb,
    577                                   error_handler=self.__activate_error_cb)
    578 
    579511    def __activate_reply_cb(self, connection):
    580512        logging.debug('Network created: %s', connection)
    581513
  • src/jarabe/desktop/meshbox.py

    diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
    index e5ef720..b88b545 100644
    a b  
    11# Copyright (C) 2006-2007 Red Hat, Inc.
    22# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
    3 # Copyright (C) 2009 One Laptop per Child
     3# Copyright (C) 2009-2010 One Laptop per Child
    44#
    55# This program is free software; you can redistribute it and/or modify
    66# it under the terms of the GNU General Public License as published by
    import dbus 
    2424import hippo
    2525import gobject
    2626import gtk
     27import gconf
    2728
    2829from sugar.graphics.icon import CanvasIcon, Icon
    2930from sugar.graphics.xocolor import XoColor
    from jarabe.model.network import IP4Config 
    5253from jarabe.model.network import WirelessSecurity
    5354from jarabe.model.network import AccessPoint
    5455from jarabe.model.olpcmesh import OlpcMeshManager
     56from jarabe.model.adhoc import get_adhoc_manager_instance
    5557from jarabe.journal import misc
    5658
    5759_NM_SERVICE = 'org.freedesktop.NetworkManager'
    _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' 
    6668_AP_ICON_NAME = 'network-wireless'
    6769_OLPC_MESH_ICON_NAME = 'network-mesh'
    6870
     71
    6972class WirelessNetworkView(CanvasPulsingIcon):
    7073    def __init__(self, initial_ap):
    7174        CanvasPulsingIcon.__init__(self, size=style.STANDARD_ICON_SIZE,
    class WirelessNetworkView(CanvasPulsingIcon): 
    8992        self._connection = None
    9093        self._color = None
    9194
    92         if self._mode == network.NM_802_11_MODE_ADHOC \
    93                 and self._name_encodes_colors():
    94             encoded_color = self._name.split("#", 1)
    95             if len(encoded_color) == 2:
    96                 self._color = xocolor.XoColor('#' + encoded_color[1])
     95        if self._mode == network.NM_802_11_MODE_ADHOC and \
     96                network.is_sugar_adhoc_network(self._name):
     97            self._color = profile.get_color()
    9798        else:
    9899            sha_hash = hashlib.sha1()
    99100            data = self._name + hex(self._flags)
    class WirelessNetworkView(CanvasPulsingIcon): 
    115116        self.set_palette(self._palette)
    116117        self._palette_icon.props.xo_color = self._color
    117118
    118         if network.find_connection_by_ssid(self._name) is not None:
    119             self.props.badge_name = "emblem-favorite"
    120             self._palette_icon.props.badge_name = "emblem-favorite"
    121         elif initial_ap.flags == network.NM_802_11_AP_FLAGS_PRIVACY:
    122             self.props.badge_name = "emblem-locked"
    123             self._palette_icon.props.badge_name = "emblem-locked"
     119        if self._mode != network.NM_802_11_MODE_ADHOC:
     120            if network.find_connection_by_ssid(self._name) is not None:
     121                self.props.badge_name = "emblem-favorite"
     122                self._palette_icon.props.badge_name = "emblem-favorite"
     123            elif self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
     124                self.props.badge_name = "emblem-locked"
     125                self._palette_icon.props.badge_name = "emblem-locked"
     126            else:
     127                self.props.badge_name = None
     128                self._palette_icon.props.badge_name = None
    124129        else:
    125130            self.props.badge_name = None
    126131            self._palette_icon.props.badge_name = None
    class WirelessNetworkView(CanvasPulsingIcon): 
    146151                                      path=self._device.object_path,
    147152                                      dbus_interface=_NM_WIRELESS_IFACE)
    148153
    149     def _name_encodes_colors(self):
    150         """Match #XXXXXX,#YYYYYY at the end of the network name"""
    151         return self._name[-7] == '#' and self._name[-8] == ',' \
    152             and self._name[-15] == '#'
    153 
    154154    def _create_palette(self):
    155155        icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
    156156        self._palette_icon = Icon(icon_name=icon_name,
    class WirelessNetworkView(CanvasPulsingIcon): 
    221221        else:
    222222            state = network.DEVICE_STATE_UNKNOWN
    223223
    224         if state == network.DEVICE_STATE_ACTIVATED:
    225             connection = network.find_connection_by_ssid(self._name)
    226             if connection:
    227                 if self._mode == network.NM_802_11_MODE_INFRA:
    228                     connection.set_connected()
    229 
    230             icon_name = '%s-connected' % _AP_ICON_NAME
    231         else:
    232             icon_name = _AP_ICON_NAME
    233 
    234         icon_name = get_icon_state(icon_name, self._strength)
    235         if icon_name:
     224        if self._mode == network.NM_802_11_MODE_ADHOC and \
     225                network.is_sugar_adhoc_network(self._name):
     226            channel = max([1] + [ap.channel for ap in
     227                                 self._access_points.values()])
     228            if state == network.DEVICE_STATE_ACTIVATED:
     229                icon_name = 'network-adhoc-%s-connected' % channel
     230            else:
     231                icon_name = 'network-adhoc-%s' % channel
    236232            self.props.icon_name = icon_name
    237233            icon = self._palette.props.icon
    238234            icon.props.icon_name = icon_name
     235        else:
     236            if state == network.DEVICE_STATE_ACTIVATED:
     237                connection = network.find_connection_by_ssid(self._name)
     238                if connection is not None:
     239                    if self._mode == network.NM_802_11_MODE_INFRA:
     240                        connection.set_connected()
     241                icon_name = '%s-connected' % _AP_ICON_NAME
     242            else:
     243                icon_name = _AP_ICON_NAME
     244
     245            icon_name = get_icon_state(icon_name, self._strength)
     246            if icon_name:
     247                self.props.icon_name = icon_name
     248                icon = self._palette.props.icon
     249                icon.props.icon_name = icon_name
    239250
    240251        if state == network.DEVICE_STATE_PREPARE or \
    241252           state == network.DEVICE_STATE_CONFIG or \
    class WirelessNetworkView(CanvasPulsingIcon): 
    443454                                         path=self._device.object_path,
    444455                                         dbus_interface=_NM_WIRELESS_IFACE)
    445456
     457class SugarAdhocView(CanvasPulsingIcon):
     458    """To mimic the mesh behavior on devices where mesh hardware is
     459    not available we support the creation of an Ad-hoc network on
     460    three channels 1, 6, 11. This is the class for an icon
     461    representing a channel in the neighborhood view.
     462
     463    """
     464
     465    _ICON_NAME = 'network-adhoc-'
     466    _NAME = 'Ad-hoc Network '
     467
     468    def __init__(self, channel):
     469        CanvasPulsingIcon.__init__(self,
     470                                   icon_name=self._ICON_NAME + str(channel),
     471                                   size=style.STANDARD_ICON_SIZE, cache=True)
     472        self._bus = dbus.SystemBus()
     473        self._channel = channel
     474        self._disconnect_item = None
     475        self._connect_item = None
     476        self._palette_icon = None
     477        self._greyed_out = False
     478
     479        get_adhoc_manager_instance().connect('members-changed',
     480                                             self.__members_changed_cb)
     481        get_adhoc_manager_instance().connect('state-changed',
     482                                             self.__state_changed_cb)
     483
     484        self.connect('button-release-event', self.__button_release_event_cb)
     485
     486        pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
     487                                         style.COLOR_TRANSPARENT.get_svg()))
     488        self.props.pulse_color = pulse_color
     489        self._state_color = XoColor('%s,%s' % \
     490                                       (profile.get_color().get_stroke_color(),
     491                                        style.COLOR_TRANSPARENT.get_svg()))
     492        self.props.base_color = self._state_color
     493        self._palette = self._create_palette()
     494        self.set_palette(self._palette)
     495        self._palette_icon.props.xo_color = self._state_color
     496
     497    def _create_palette(self):
     498        self._palette_icon = Icon( \
     499                icon_name=self._ICON_NAME + str(self._channel),
     500                icon_size=style.STANDARD_ICON_SIZE)
     501
     502        palette_ = palette.Palette(_("Ad-hoc Network %d") % self._channel,
     503                                   icon=self._palette_icon)
     504
     505        self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
     506        self._connect_item.connect('activate', self.__connect_activate_cb)
     507        palette_.menu.append(self._connect_item)
     508
     509        self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
     510        self._disconnect_item.connect('activate',
     511                                      self.__disconnect_activate_cb)
     512        palette_.menu.append(self._disconnect_item)
     513
     514        return palette_
     515
     516    def __button_release_event_cb(self, icon, event):
     517        get_adhoc_manager_instance().activate_channel(self._channel)
     518
     519    def __connect_activate_cb(self, icon):
     520        get_adhoc_manager_instance().activate_channel(self._channel)
     521
     522    def __disconnect_activate_cb(self, icon):
     523        get_adhoc_manager_instance().deactivate_active_channel()
     524
     525    def __state_changed_cb(self, adhoc_manager, channel, device_state):
     526        if self._channel == channel:
     527            state = device_state
     528        else:
     529            state = network.DEVICE_STATE_UNKNOWN
     530
     531        if state == network.DEVICE_STATE_ACTIVATED:
     532            icon_name = '%s-connected' % (self._ICON_NAME + str(self._channel))
     533        else:
     534            icon_name = self._ICON_NAME + str(self._channel)
     535
     536        self.props.base_color = self._state_color
     537        self._palette_icon.props.xo_color = self._state_color
     538
     539        if icon_name is not None:
     540            self.props.icon_name = icon_name
     541            icon = self._palette.props.icon
     542            icon.props.icon_name = icon_name
     543
     544        if state in [network.DEVICE_STATE_PREPARE,
     545                     network.DEVICE_STATE_CONFIG,
     546                     network.DEVICE_STATE_NEED_AUTH,
     547                     network.DEVICE_STATE_IP_CONFIG]:
     548            if self._disconnect_item:
     549                self._disconnect_item.show()
     550            self._connect_item.hide()
     551            self._palette.props.secondary_text = _('Connecting...')
     552            self.props.pulsing = True
     553        elif state == network.DEVICE_STATE_ACTIVATED:
     554            if self._disconnect_item:
     555                self._disconnect_item.show()
     556            self._connect_item.hide()
     557            self._palette.props.secondary_text = _('Connected')
     558            self.props.pulsing = False
     559        else:
     560            if self._disconnect_item:
     561                self._disconnect_item.hide()
     562            self._connect_item.show()
     563            self._palette.props.secondary_text = None
     564            self.props.pulsing = False
     565
     566    def _update_color(self):
     567        if self._greyed_out:
     568            self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
     569        else:
     570            self.props.base_color = self._state_color
     571
     572    def __members_changed_cb(self, adhoc_manager, channel, has_members):
     573        if channel == self._channel:
     574            if has_members == True:
     575                self._state_color = profile.get_color()
     576                self.props.base_color = self._state_color
     577                self._palette_icon.props.xo_color = self._state_color
     578            else:
     579                color = '%s,%s' % (profile.get_color().get_stroke_color(),
     580                                   style.COLOR_TRANSPARENT.get_svg())
     581                self._state_color = XoColor(color)
     582                self.props.base_color = self._state_color
     583                self._palette_icon.props.xo_color = self._state_color
     584
     585    def set_filter(self, query):
     586        name = self._NAME + str(self._channel)
     587        self._greyed_out = name.lower().find(query) == -1
     588        self._update_color()
     589
    446590
    447591class OlpcMeshView(CanvasPulsingIcon):
    448592    def __init__(self, mesh_mgr, channel):
    class MeshToolbar(gtk.Toolbar): 
    762906        return False
    763907
    764908
    765 class DeviceObserver(object):
    766     def __init__(self, box, device):
    767         self._box = box
     909class DeviceObserver(gobject.GObject):
     910    __gsignals__ = {
     911        'access-point-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
     912                               ([gobject.TYPE_PYOBJECT])),
     913        'access-point-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
     914                                 ([gobject.TYPE_PYOBJECT]))
     915    }
     916    def __init__(self, device):
     917        gobject.GObject.__init__(self)
    768918        self._bus = dbus.SystemBus()
    769         self._device = device
     919        self.device = device
    770920
    771         wireless = dbus.Interface(self._device, _NM_WIRELESS_IFACE)
     921        wireless = dbus.Interface(device, _NM_WIRELESS_IFACE)
    772922        wireless.GetAccessPoints(reply_handler=self._get_access_points_reply_cb,
    773923                                 error_handler=self._get_access_points_error_cb)
    774924
    class DeviceObserver(object): 
    784934    def _get_access_points_reply_cb(self, access_points_o):
    785935        for ap_o in access_points_o:
    786936            ap = self._bus.get_object(_NM_SERVICE, ap_o)
    787             self._box.add_access_point(self._device, ap)
     937            self.emit('access-point-added', ap)
    788938
    789939    def _get_access_points_error_cb(self, err):
    790940        logging.error('Failed to get access points: %s', err)
    791941
    792942    def __access_point_added_cb(self, access_point_o):
    793943        ap = self._bus.get_object(_NM_SERVICE, access_point_o)
    794         self._box.add_access_point(self._device, ap)
     944        self.emit('access-point-added', ap)
    795945
    796946    def __access_point_removed_cb(self, access_point_o):
    797         self._box.remove_access_point(access_point_o)
     947        self.emit('access-point-removed', access_point_o)
    798948
    799949    def disconnect(self):
    800950        self._bus.remove_signal_receiver(self.__access_point_added_cb,
    801951                                         signal_name='AccessPointAdded',
    802                                          path=self._device.object_path,
     952                                         path=self.device.object_path,
    803953                                         dbus_interface=_NM_WIRELESS_IFACE)
    804954        self._bus.remove_signal_receiver(self.__access_point_removed_cb,
    805955                                         signal_name='AccessPointRemoved',
    806                                          path=self._device.object_path,
     956                                         path=self.device.object_path,
    807957                                         dbus_interface=_NM_WIRELESS_IFACE)
    808958
    809959
    810960class NetworkManagerObserver(object):
     961
     962    _SHOW_ADHOC_GCONF_KEY = '/desktop/sugar/network/adhoc'
     963
    811964    def __init__(self, box):
    812965        self._box = box
    813966        self._bus = None
    class NetworkManagerObserver(object): 
    815968        self._netmgr = None
    816969        self._olpc_mesh_device_o = None
    817970
     971        client = gconf.client_get_default()
     972        self._have_adhoc_networks = client.get_bool(self._SHOW_ADHOC_GCONF_KEY)
     973
    818974    def listen(self):
    819975        try:
    820976            self._bus = dbus.SystemBus()
    class NetworkManagerObserver(object): 
    833989        self._bus.add_signal_receiver(self.__device_removed_cb,
    834990                                      signal_name='DeviceRemoved',
    835991                                      dbus_interface=_NM_IFACE)
     992        self._bus.add_signal_receiver(self.__properties_changed_cb,
     993                                      signal_name='PropertiesChanged',
     994                                      dbus_interface=_NM_IFACE)
    836995
    837996        settings = network.get_settings()
    838997        if settings is not None:
    class NetworkManagerObserver(object): 
    8761035
    8771036        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
    8781037        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
    879             self._devices[device_o] = DeviceObserver(self._box, device)
     1038            self._devices[device_o] = DeviceObserver(device)
     1039            self._devices[device_o].connect('access-point-added',
     1040                                            self.__ap_added_cb)
     1041            self._devices[device_o].connect('access-point-removed',
     1042                                            self.__ap_removed_cb)
     1043            if self._have_adhoc_networks:
     1044                self._box.add_adhoc_networks(device)
    8801045        elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
    8811046            self._olpc_mesh_device_o = device_o
    8821047            self._box.enable_olpc_mesh(device)
    class NetworkManagerObserver(object): 
    8921057            observer = self._devices[device_o]
    8931058            observer.disconnect()
    8941059            del self._devices[device_o]
     1060            if self._have_adhoc_networks:
     1061                self._box.remove_adhoc_networks()
    8951062            return
    8961063
    8971064        if self._olpc_mesh_device_o == device_o:
    8981065            self._box.disable_olpc_mesh(device_o)
    8991066
     1067    def __ap_added_cb(self, device_observer, access_point):
     1068        self._box.add_access_point(device_observer.device, access_point)
     1069
     1070    def __ap_removed_cb(self, device_observer, access_point_o):
     1071        self._box.remove_access_point(access_point_o)
     1072
     1073    def __properties_changed_cb(self, properties):
     1074        if 'WirelessHardwareEnabled' in properties:
     1075            if properties['WirelessHardwareEnabled']:
     1076                if not self._have_adhoc_networks:
     1077                    self._box.remove_adhoc_networks()
     1078            elif properties['WirelessHardwareEnabled']:
     1079                for device in self._devices:
     1080                    if self._have_adhoc_networks:
     1081                        self._box.add_adhoc_networks(device)
     1082
     1083
    9001084class MeshBox(gtk.VBox):
    9011085    __gtype_name__ = 'SugarMeshBox'
    9021086
    class MeshBox(gtk.VBox): 
    9061090        gobject.GObject.__init__(self)
    9071091
    9081092        self.wireless_networks = {}
     1093        self._adhoc_manager = None
     1094        self._adhoc_networks = []
    9091095
    9101096        self._model = neighborhood.get_model()
    9111097        self._buddies = {}
    class MeshBox(gtk.VBox): 
    10631249            ap.disconnect()
    10641250            return
    10651251
     1252        if self._adhoc_manager is not None and \
     1253                network.is_sugar_adhoc_network(ap.name) and \
     1254                ap.mode == network.NM_802_11_MODE_ADHOC:
     1255            if old_hash is None: # new Ad-hoc network finished initializing
     1256                self._adhoc_manager.add_access_point(ap)
     1257            # we are called as well in other cases but we do not need to
     1258            # act here as we don't display signal strength for Ad-hoc networks
     1259            return
     1260
    10661261        if old_hash is None: # new AP finished initializing
    10671262            self._add_ap_to_network(ap)
    10681263            return
    class MeshBox(gtk.VBox): 
    10851280        ap.initialize()
    10861281
    10871282    def remove_access_point(self, ap_o):
     1283        if self._adhoc_manager is not None:
     1284            if self._adhoc_manager.is_sugar_adhoc_access_point(ap_o):
     1285                self._adhoc_manager.remove_access_point(ap_o)
     1286                return
     1287
    10881288        # we don't keep an index of ap object path to network, but since
    10891289        # we'll only ever have a handful of networks, just try them all...
    10901290        for net in self.wireless_networks.values():
    class MeshBox(gtk.VBox): 
    11011301        # it (e.g. olpc-mesh adhoc network)
    11021302        logging.debug('Can not remove access point %s' % ap_o)
    11031303
     1304    def add_adhoc_networks(self, device):
     1305        if self._adhoc_manager is None:
     1306            self._adhoc_manager = get_adhoc_manager_instance()
     1307            self._adhoc_manager.start_listening(device)
     1308        self._add_adhoc_network_icon(1)
     1309        self._add_adhoc_network_icon(6)
     1310        self._add_adhoc_network_icon(11)
     1311        self._adhoc_manager.autoconnect()
     1312
     1313    def remove_adhoc_networks(self):
     1314        for icon in self._adhoc_networks:
     1315            icon.disconnect()
     1316            self._layout.remove(icon)
     1317        self._adhoc_networks = []
     1318
     1319    def _add_adhoc_network_icon(self, channel):
     1320        icon = SugarAdhocView(channel)
     1321        self._layout.add(icon)
     1322        self._adhoc_networks.append(icon)
     1323
    11041324    def _add_olpc_mesh_icon(self, mesh_mgr, channel):
    11051325        icon = OlpcMeshView(mesh_mgr, channel)
    11061326        self._layout.add(icon)
  • src/jarabe/model/Makefile.am

    diff --git a/src/jarabe/model/Makefile.am b/src/jarabe/model/Makefile.am
    index e9f0700..4650c3b 100644
    a b  
    11sugardir = $(pythondir)/jarabe/model
    22sugar_PYTHON =                  \
     3        adhoc.py                \
    34        __init__.py             \
    45        buddy.py                \
    56        bundleregistry.py       \
  • new file src/jarabe/model/adhoc.py

    diff --git a/src/jarabe/model/adhoc.py b/src/jarabe/model/adhoc.py
    new file mode 100644
    index 0000000..65dac01
    - +  
     1# Copyright (C) 2010 One Laptop per Child
     2#
     3# This program is free software; you can redistribute it and/or modify
     4# it under the terms of the GNU General Public License as published by
     5# the Free Software Foundation; either version 2 of the License, or
     6# (at your option) any later version.
     7#
     8# This program is distributed in the hope that it will be useful,
     9# but WITHOUT ANY WARRANTY; without even the implied warranty of
     10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11# GNU General Public License for more details.
     12#
     13# You should have received a copy of the GNU General Public License
     14# along with this program; if not, write to the Free Software
     15# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     16
     17import logging
     18
     19import dbus
     20import gobject
     21
     22from jarabe.model import network
     23from jarabe.model.network import Settings
     24from sugar.util import unique_id
     25from jarabe.model.network import IP4Config
     26
     27_NM_SERVICE = 'org.freedesktop.NetworkManager'
     28_NM_IFACE = 'org.freedesktop.NetworkManager'
     29_NM_PATH = '/org/freedesktop/NetworkManager'
     30_NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device'
     31_NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless'
     32_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
     33_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
     34
     35
     36_adhoc_manager_instance = None
     37def get_adhoc_manager_instance():
     38    global _adhoc_manager_instance
     39    if _adhoc_manager_instance is None:
     40        _adhoc_manager_instance = AdHocManager()
     41    return _adhoc_manager_instance
     42
     43
     44class AdHocManager(gobject.GObject):
     45    """To mimic the mesh behavior on devices where mesh hardware is
     46    not available we support the creation of an Ad-hoc network on
     47    three channels 1, 6, 11. If Sugar sees no "known" network when it
     48    starts, it does autoconnect to an Ad-hoc network.
     49
     50    """
     51
     52    __gsignals__ = {
     53        'members-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
     54                            ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
     55        'state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
     56                          ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
     57    }
     58
     59    _AUTOCONNECT_TIMEOUT = 30
     60    _CHANNEL_1 = 1
     61    _CHANNEL_6 = 6
     62    _CHANNEL_11 = 11
     63
     64    def __init__(self):
     65        gobject.GObject.__init__(self)
     66
     67        self._bus = dbus.SystemBus()
     68        self._device = None
     69        self._idle_source = 0
     70        self._listening_called = 0
     71        self._device_state = network.DEVICE_STATE_UNKNOWN
     72
     73        self._current_channel = None
     74        self._networks = {self._CHANNEL_1: None,
     75                          self._CHANNEL_6: None,
     76                          self._CHANNEL_11: None}
     77
     78    def start_listening(self, device):
     79        self._listening_called += 1
     80        if self._listening_called > 1:
     81            raise RuntimeError('The start listening method can' \
     82                                   ' only be called once.')
     83
     84        self._device = device
     85        props = dbus.Interface(device,
     86                                   'org.freedesktop.DBus.Properties')
     87        props.Get(_NM_DEVICE_IFACE, 'State',
     88                  reply_handler=self.__get_device_state_reply_cb,
     89                  error_handler=self.__get_state_error_cb)
     90
     91        self._bus.add_signal_receiver(self.__device_state_changed_cb,
     92                                      signal_name='StateChanged',
     93                                      path=self._device.object_path,
     94                                      dbus_interface=_NM_DEVICE_IFACE)
     95
     96        self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
     97                                      signal_name='PropertiesChanged',
     98                                      path=self._device.object_path,
     99                                      dbus_interface=_NM_WIRELESS_IFACE)
     100
     101    def stop_listening(self):
     102        self._bus.remove_signal_receiver(self.__device_state_changed_cb,
     103                                         signal_name='StateChanged',
     104                                         path=self._device.object_path,
     105                                         dbus_interface=_NM_DEVICE_IFACE)
     106        self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
     107                                         signal_name='PropertiesChanged',
     108                                         path=self._device.object_path,
     109                                         dbus_interface=_NM_WIRELESS_IFACE)
     110
     111    def __get_state_error_cb(self, err):
     112        logging.debug('Error getting the device state: %s', err)
     113
     114    def __get_device_state_reply_cb(self, state):
     115        self._device_state = state
     116
     117    def __device_state_changed_cb(self, new_state, old_state, reason):
     118        self._device_state = new_state
     119        self._update_state()
     120
     121    def __wireless_properties_changed_cb(self, properties):
     122        if 'ActiveAccessPoint' in properties and \
     123                properties['ActiveAccessPoint'] != '/':
     124            active_ap = self._bus.get_object(_NM_SERVICE,
     125                                             properties['ActiveAccessPoint'])
     126            props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
     127            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
     128                         reply_handler=self.__get_all_ap_props_reply_cb,
     129                         error_handler=self.__get_all_ap_props_error_cb)
     130
     131    def __get_all_ap_props_reply_cb(self, properties):
     132        if properties['Mode'] == network.NM_802_11_MODE_ADHOC and \
     133                'Frequency' in properties:
     134            frequency = properties['Frequency']
     135            self._current_channel = network.frequency_to_channel(frequency)
     136        else:
     137            self._current_channel = None
     138        self._update_state()
     139
     140    def __get_all_ap_props_error_cb(self, err):
     141        logging.error('Error getting the access point properties: %s', err)
     142
     143    def _update_state(self):
     144        self.emit('state-changed', self._current_channel, self._device_state)
     145
     146    def _have_configured_connections(self):
     147        return len(network.get_settings().connections) > 0
     148
     149    def autoconnect(self):
     150        """Autoconnect to an Ad-hoc network"""
     151        if self._have_configured_connections():
     152            self._autoconnect_adhoc_timer()
     153        else:
     154            self._autoconnect_adhoc()
     155
     156    def _autoconnect_adhoc_timer(self):
     157        """Start a timer which basically looks for 30 seconds of inactivity
     158        on the device, then does autoconnect to an Ad-hoc network.
     159
     160        """
     161        if self._idle_source != 0:
     162            gobject.source_remove(self._idle_source)
     163        self._idle_source = gobject.timeout_add_seconds( \
     164                self._AUTOCONNECT_TIMEOUT, self.__idle_check_cb)
     165
     166    def __idle_check_cb(self):
     167        if  self._device_state == network.DEVICE_STATE_DISCONNECTED:
     168            logging.debug("Connect to Ad-hoc network due to inactivity.")
     169            self._autoconnect_adhoc()
     170        return False
     171
     172    def _autoconnect_adhoc(self):
     173        """First we try if there is an Ad-hoc network that is used by other
     174        learners in the area, if not we default to channel 1.
     175
     176        """
     177        if self._networks[self._CHANNEL_1] is not None:
     178            self._connect(self._CHANNEL_1)
     179        elif self._networks[self._CHANNEL_6] is not None:
     180            self._connect(self._CHANNEL_6)
     181        elif self._networks[self._CHANNEL_11] is not None:
     182            self._connect(self._CHANNEL_11)
     183        else:
     184            self._connect(self._CHANNEL_1)
     185
     186    def activate_channel(self, channel):
     187        """Activate a sugar Ad-hoc network.
     188
     189        Keyword arguments:
     190        channel -- Channel to connect to (should be 1, 6, 11)
     191
     192        """
     193        self._connect(channel)
     194
     195    def _connect(self, channel):
     196        name = "Ad-hoc Network %d" % channel
     197        connection = network.find_connection_by_ssid(name)
     198        if connection is None:
     199            settings = Settings()
     200            settings.connection.id = name
     201            settings.connection.uuid = unique_id()
     202            settings.connection.type = '802-11-wireless'
     203            settings.wireless.ssid = dbus.ByteArray(name)
     204            settings.wireless.band = 'bg'
     205            settings.wireless.channel = channel
     206            settings.wireless.mode = 'adhoc'
     207            settings.ip4_config = IP4Config()
     208            settings.ip4_config.method = 'link-local'
     209
     210            connection = network.add_connection(name, settings)
     211
     212        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     213        netmgr = dbus.Interface(obj, _NM_IFACE)
     214
     215        netmgr.ActivateConnection(network.SETTINGS_SERVICE,
     216                                  connection.path,
     217                                  self._device.object_path,
     218                                  '/',
     219                                  reply_handler=self.__activate_reply_cb,
     220                                  error_handler=self.__activate_error_cb)
     221
     222    def deactivate_active_channel(self):
     223        """Deactivate the current active channel."""
     224        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     225        netmgr = dbus.Interface(obj, _NM_IFACE)
     226
     227        netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
     228        netmgr_props.Get(_NM_IFACE, 'ActiveConnections', \
     229                reply_handler=self.__get_active_connections_reply_cb,
     230                error_handler=self.__get_active_connections_error_cb)
     231
     232    def __get_active_connections_reply_cb(self, active_connections_o):
     233        for connection_o in active_connections_o:
     234            obj = self._bus.get_object(_NM_IFACE, connection_o)
     235            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
     236            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
     237            if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
     238                access_point_o = props.Get(_NM_ACTIVE_CONN_IFACE,
     239                                           'SpecificObject')
     240                if access_point_o != '/':
     241                    obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     242                    netmgr = dbus.Interface(obj, _NM_IFACE)
     243                    netmgr.DeactivateConnection(connection_o)
     244
     245    def __get_active_connections_error_cb(self, err):
     246        logging.error('Error getting the active connections: %s', err)
     247
     248    def __activate_reply_cb(self, connection):
     249        logging.debug('Ad-hoc network created: %s', connection)
     250
     251    def __activate_error_cb(self, err):
     252        logging.error('Failed to create Ad-hoc network: %s', err)
     253
     254    def add_access_point(self, access_point):
     255        """Add an access point to a network and notify the view to idicate
     256        the member change.
     257
     258        Keyword arguments:
     259        access_point -- Access Point
     260
     261        """
     262        if access_point.name.endswith(' 1'):
     263            self._networks[self._CHANNEL_1] = access_point
     264            self.emit('members-changed', self._CHANNEL_1, True)
     265        elif access_point.name.endswith(' 6'):
     266            self._networks[self._CHANNEL_6] = access_point
     267            self.emit('members-changed', self._CHANNEL_6, True)
     268        elif access_point.name.endswith('11'):
     269            self._networks[self._CHANNEL_11] = access_point
     270            self.emit('members-changed', self._CHANNEL_11, True)
     271
     272    def is_sugar_adhoc_access_point(self, ap_object_path):
     273        """Checks whether an access point is part of a sugar Ad-hoc network.
     274
     275        Keyword arguments:
     276        ap_object_path -- Access Point object path
     277
     278        Return: Boolean
     279
     280        """
     281        for access_point in self._networks.values():
     282            if access_point is not None:
     283                if access_point.model.object_path == ap_object_path:
     284                    return True
     285        return False
     286
     287    def remove_access_point(self, ap_object_path):
     288        """Remove an access point from a sugar Ad-hoc network.
     289
     290        Keyword arguments:
     291        ap_object_path -- Access Point object path
     292
     293        """
     294        for channel in self._networks:
     295            if self._networks[channel] is not None:
     296                if self._networks[channel].model.object_path == ap_object_path:
     297                    self.emit('members-changed', channel, False)
     298                    self._networks[channel] = None
     299                    break
  • src/jarabe/model/network.py

    diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
    index 47db43f..984da67 100644
    a b  
    11# Copyright (C) 2008 Red Hat, Inc.
    22# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
    3 # Copyright (C) 2009 One Laptop per Child
     3# Copyright (C) 2009-2010 One Laptop per Child
    44# Copyright (C) 2009 Paraguay Educa, Martin Abente
    55# Copyright (C) 2010 Plan Ceibal, Daniel Castelo
    66#
    GSM_PUK_PATH = '/desktop/sugar/network/gsm/puk' 
    100100_nm_settings = None
    101101_conn_counter = 0
    102102
     103
     104def frequency_to_channel(frequency):
     105    """Returns the channel matching a given radio channel frequency. If a
     106    frequency is not in the dictionary channel 1 will be returned.
     107
     108    Keyword arguments:
     109    frequency -- The radio channel frequency in MHz.
     110
     111    Return: Channel
     112
     113    """
     114    ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4,
     115            2432: 5, 2437: 6, 2442: 7, 2447: 8,
     116            2452: 9, 2457: 10, 2462: 11, 2467: 12,
     117            2472: 13}
     118    if frequency not in ftoc:
     119        logging.warning("The frequency %s can not be mapped to a channel, " \
     120                            "defaulting to channel 1.", frequncy)
     121        return 1
     122    return ftoc[frequency]
     123
     124def is_sugar_adhoc_network(ssid):
     125    """Checks whether an access point is a sugar Ad-hoc network.
     126
     127    Keyword arguments:
     128    ssid -- Ssid of the access point.
     129
     130    Return: Boolean
     131
     132    """
     133    return ssid.startswith('Ad-hoc Network')
     134
     135
    103136class WirelessSecurity(object):
    104137    def __init__(self):
    105138        self.key_mgmt = None
    class Wireless(object): 
    127160        self.security = None
    128161        self.mode = None
    129162        self.band = None
     163        self.channel = None
    130164
    131165    def get_dict(self):
    132166        wireless = {'ssid': self.ssid}
    class Wireless(object): 
    136170            wireless['mode'] = self.mode
    137171        if self.band:
    138172            wireless['band'] = self.band
     173        if self.channel:
     174            wireless['channel'] = self.channel
    139175        return wireless
    140176
    141177
    class AccessPoint(gobject.GObject): 
    476512        self.wpa_flags = 0
    477513        self.rsn_flags = 0
    478514        self.mode = 0
     515        self.channel = 0
    479516
    480517    def initialize(self):
    481518        model_props = dbus.Interface(self.model,
    class AccessPoint(gobject.GObject): 
    545582            self.rsn_flags = properties['RsnFlags']
    546583        if 'Mode' in properties:
    547584            self.mode = properties['Mode']
     585        if 'Frequency' in properties:
     586            self.channel = frequency_to_channel(properties['Frequency'])
     587
    548588        self._initialized = True
    549589        self.emit('props-changed', old_hash)
    550590