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

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

Merged two patches and fixed a typo

  • extensions/deviceicon/network.py

    From edfe8baf0c19c16d751a2bd0daa97336c937eda0 Mon Sep 17 00:00:00 2001
    From: Simon Schampijer <simon@schampijer.de>
    Date: Mon, 9 Aug 2010 16:10:33 +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.
    ---
     extensions/deviceicon/network.py |  116 +++----------
     src/jarabe/desktop/meshbox.py    |  341 ++++++++++++++++++++++++++++++++++----
     src/jarabe/model/Makefile.am     |    1 +
     src/jarabe/model/adhoc.py        |  196 ++++++++++++++++++++++
     src/jarabe/model/network.py      |   21 +++-
     5 files changed, 555 insertions(+), 120 deletions(-)
     create mode 100644 src/jarabe/model/adhoc.py
    
    diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
    index 227ba46..a8c3124 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):
    156139        try:
    157             channel = frequency_to_channel(frequency)
     140            channel = network.frequency_to_channel(frequency)
    158141        except KeyError:
    159142            channel = 0
    160143        self._set_channel(channel)
    class GsmPalette(Palette): 
    318301
    319302class WirelessDeviceView(ToolButton):
    320303
    321     _ICON_NAME = 'network-wireless'
    322304    FRAME_POSITION_RELATIVE = 302
    323305
    324306    def __init__(self, device):
    class WirelessDeviceView(ToolButton): 
    337319        self._active_ap_op = None
    338320
    339321        self._icon = PulsingIcon()
    340         self._icon.props.icon_name = get_icon_state(self._ICON_NAME, 0)
     322        self._icon.props.icon_name = get_icon_state('network-wireless', 0)
    341323        self._inactive_color = xocolor.XoColor( \
    342324            "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(),
    343325                       style.COLOR_TRANSPARENT.get_svg()))
    class WirelessDeviceView(ToolButton): 
    351333        self._palette = WirelessPalette(self._name)
    352334        self._palette.connect('deactivate-connection',
    353335                              self.__deactivate_connection_cb)
    354         self._palette.connect('create-connection',
    355                               self.__create_connection_cb)
    356336        self.set_palette(self._palette)
    357337        self._palette.set_group_id('frame')
    358338
    class WirelessDeviceView(ToolButton): 
    422402    def __ap_properties_changed_cb(self, properties):
    423403        self._update_properties(properties)
    424404
    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 
    430405    def _update_properties(self, properties):
    431406        if 'Mode' in properties:
    432407            self._mode = properties['Mode']
    class WirelessDeviceView(ToolButton): 
    442417            self._frequency = properties['Frequency']
    443418
    444419        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])
     420            if self._mode == network.NM_802_11_MODE_ADHOC and \
     421                    self._name.startswith('Ad-hoc Network'):
     422                self._color = profile.get_color()
    450423            else:
    451424                sha_hash = hashlib.sha1()
    452425                data = self._name + hex(self._flags)
    class WirelessDeviceView(ToolButton): 
    482455        else:
    483456            state = network.DEVICE_STATE_UNKNOWN
    484457
    485         if state == network.DEVICE_STATE_ACTIVATED:
    486             icon_name = '%s-connected' % self._ICON_NAME
    487         else:
    488             icon_name = self._ICON_NAME
     458        if self._mode != network.NM_802_11_MODE_ADHOC and \
     459                self._name.startswith('Ad-hoc Network') == False:
     460            if state == network.DEVICE_STATE_ACTIVATED:
     461                icon_name = '%s-connected' % 'network-wireless'
     462            else:
     463                icon_name = 'network-wireless'
    489464
    490         icon_name = get_icon_state(icon_name, self._strength)
    491         if icon_name:
    492             self._icon.props.icon_name = icon_name
     465            icon_name = get_icon_state(icon_name, self._strength)
     466            if icon_name:
     467                self._icon.props.icon_name = icon_name
     468        else:
     469            try:
     470                channel = network.frequency_to_channel(self._frequency)
     471            except KeyError:
     472                channel = 1
     473            if state == network.DEVICE_STATE_ACTIVATED:
     474                self._icon.props.icon_name = 'network-adhoc-%s-connected' \
     475                        % channel
     476            else:
     477                self._icon.props.icon_name = 'network-adhoc-%s' % channel
     478            self._icon.props.base_color = profile.get_color()
    493479
    494480        if state == network.DEVICE_STATE_PREPARE or \
    495481           state == network.DEVICE_STATE_CONFIG or \
    class WirelessDeviceView(ToolButton): 
    528514                    netmgr.DeactivateConnection(conn_o)
    529515                    break
    530516
    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 
    579517    def __activate_reply_cb(self, connection):
    580518        logging.debug('Network created: %s', connection)
    581519
  • src/jarabe/desktop/meshbox.py

    diff --git a/src/jarabe/desktop/meshbox.py b/src/jarabe/desktop/meshbox.py
    index e5ef720..c3812d5 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
    from jarabe.model.network import IP4Config 
    5252from jarabe.model.network import WirelessSecurity
    5353from jarabe.model.network import AccessPoint
    5454from jarabe.model.olpcmesh import OlpcMeshManager
     55from jarabe.model.adhoc import AdHocManager
    5556from jarabe.journal import misc
    5657
    5758_NM_SERVICE = 'org.freedesktop.NetworkManager'
    class WirelessNetworkView(CanvasPulsingIcon): 
    8990        self._connection = None
    9091        self._color = None
    9192
    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])
     93        if self._mode == network.NM_802_11_MODE_ADHOC and \
     94                self._name.startswith('Ad-hoc Network'):
     95            self._color = profile.get_color()
    9796        else:
    9897            sha_hash = hashlib.sha1()
    9998            data = self._name + hex(self._flags)
    class WirelessNetworkView(CanvasPulsingIcon): 
    115114        self.set_palette(self._palette)
    116115        self._palette_icon.props.xo_color = self._color
    117116
    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"
     117        if self._mode != network.NM_802_11_MODE_ADHOC:
     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 self._flags == network.NM_802_11_AP_FLAGS_PRIVACY:
     122                self.props.badge_name = "emblem-locked"
     123                self._palette_icon.props.badge_name = "emblem-locked"
     124            else:
     125                self.props.badge_name = None
     126                self._palette_icon.props.badge_name = None
    124127        else:
    125128            self.props.badge_name = None
    126129            self._palette_icon.props.badge_name = None
    class WirelessNetworkView(CanvasPulsingIcon): 
    146149                                      path=self._device.object_path,
    147150                                      dbus_interface=_NM_WIRELESS_IFACE)
    148151
    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 
    154152    def _create_palette(self):
    155153        icon_name = get_icon_state(_AP_ICON_NAME, self._strength)
    156154        self._palette_icon = Icon(icon_name=icon_name,
    class WirelessNetworkView(CanvasPulsingIcon): 
    221219        else:
    222220            state = network.DEVICE_STATE_UNKNOWN
    223221
    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:
     222        if self._mode == network.NM_802_11_MODE_ADHOC and \
     223                self._name.startswith('Ad-hoc Network'):
     224            channel = max([1] + [ap.channel for ap in
     225                                 self._access_points.values()])
     226            if state == network.DEVICE_STATE_ACTIVATED:
     227                icon_name = 'network-adhoc-%s-connected' % channel
     228            else:
     229                icon_name = 'network-adhoc-%s' % channel
    236230            self.props.icon_name = icon_name
    237231            icon = self._palette.props.icon
    238232            icon.props.icon_name = icon_name
     233        else:
     234            if state == network.DEVICE_STATE_ACTIVATED:
     235                connection = network.find_connection_by_ssid(self._name)
     236                if connection:
     237                    if self._mode == network.NM_802_11_MODE_INFRA:
     238                        connection.set_connected()
     239                icon_name = '%s-connected' % _AP_ICON_NAME
     240            else:
     241                icon_name = _AP_ICON_NAME
     242
     243            icon_name = get_icon_state(icon_name, self._strength)
     244            if icon_name:
     245                self.props.icon_name = icon_name
     246                icon = self._palette.props.icon
     247                icon.props.icon_name = icon_name
    239248
    240249        if state == network.DEVICE_STATE_PREPARE or \
    241250           state == network.DEVICE_STATE_CONFIG or \
    class WirelessNetworkView(CanvasPulsingIcon): 
    353362                settings.wireless.mode = 'adhoc'
    354363                settings.wireless.band = 'bg'
    355364                settings.ip4_config = IP4Config()
    356                 settings.ip4_config.method = 'link-local'
     365                settings.ip4_config.method = 'shared'
    357366
    358367            wireless_security = self._get_security()
    359368            settings.wireless_security = wireless_security
    class WirelessNetworkView(CanvasPulsingIcon): 
    443452                                         path=self._device.object_path,
    444453                                         dbus_interface=_NM_WIRELESS_IFACE)
    445454
     455class AdHocView(CanvasPulsingIcon):
     456    def __init__(self, manager, channel):
     457        CanvasPulsingIcon.__init__(self,
     458                                   icon_name='network-adhoc-%s' % channel,
     459                                   size=style.STANDARD_ICON_SIZE, cache=True)
     460        self._bus = dbus.SystemBus()
     461        self._manager = manager
     462        self._device = manager.device
     463        self._channel = channel
     464        self._icon_name = 'network-adhoc-%s' % self._channel
     465        self._disconnect_item = None
     466        self._connect_item = None
     467        self._palette_icon = None
     468        self._greyed_out = False
     469        self._name = "Ad-hoc Network %d" % channel
     470        self._device_state = None
     471        self._connection = None
     472        self._active = False
     473
     474        self.connect('button-release-event', self.__button_release_event_cb)
     475
     476        interface_props = dbus.Interface(self._device,
     477                                         'org.freedesktop.DBus.Properties')
     478        interface_props.Get(_NM_DEVICE_IFACE, 'State',
     479                            reply_handler=self.__get_device_state_reply_cb,
     480                            error_handler=self.__get_device_state_error_cb)
     481
     482        self._bus.add_signal_receiver(self.__device_state_changed_cb,
     483                                      signal_name='StateChanged',
     484                                      path=self._device.object_path,
     485                                      dbus_interface=_NM_DEVICE_IFACE)
     486        self._bus.add_signal_receiver(self.__wireless_properties_changed_cb,
     487                                      signal_name='PropertiesChanged',
     488                                      path=self._device.object_path,
     489                                      dbus_interface=_NM_WIRELESS_IFACE)
     490
     491        pulse_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(),
     492                                         style.COLOR_TRANSPARENT.get_svg()))
     493        self.props.pulse_color = pulse_color
     494        self._state_color = XoColor('%s,%s' % \
     495                                       (profile.get_color().get_stroke_color(),
     496                                        style.COLOR_TRANSPARENT.get_svg()))
     497        self.props.base_color = self._state_color
     498        self._palette = self._create_palette()
     499        self.set_palette(self._palette)
     500        self._palette_icon.props.xo_color = self._state_color
     501
     502    def _create_palette(self):
     503        self._palette_icon = Icon(icon_name=self._icon_name,
     504                                  icon_size=style.STANDARD_ICON_SIZE)
     505
     506        _palette = palette.Palette(_("Ad-hoc Network %d") % self._channel,
     507                                   icon=self._palette_icon)
     508
     509        self._connect_item = MenuItem(_('Connect'), 'dialog-ok')
     510        self._connect_item.connect('activate', self.__connect_activate_cb)
     511        _palette.menu.append(self._connect_item)
     512
     513        self._disconnect_item = MenuItem(_('Disconnect'), 'media-eject')
     514        self._disconnect_item.connect('activate',
     515                                      self.__disconnect_activate_cb)
     516        _palette.menu.append(self._disconnect_item)
     517
     518        return _palette
     519
     520    def __button_release_event_cb(self, icon, event):
     521        self._manager.activate_channel(self._channel)
     522
     523    def __connect_activate_cb(self, icon):
     524        self._manager.activate_channel(self._channel)
     525
     526    def __disconnect_activate_cb(self, icon):
     527        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     528        netmgr = dbus.Interface(obj, _NM_IFACE)
     529
     530        netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE)
     531        netmgr_props.Get(_NM_IFACE, 'ActiveConnections', \
     532                reply_handler=self.__get_active_connections_reply_cb,
     533                error_handler=self.__get_active_connections_error_cb)
     534
     535    def __get_active_connections_reply_cb(self, active_connections_o):
     536        for connection_o in active_connections_o:
     537            obj = self._bus.get_object(_NM_IFACE, connection_o)
     538            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
     539            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
     540            if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
     541                access_point_o = props.Get(_NM_ACTIVE_CONN_IFACE,
     542                                           'SpecificObject')
     543                if access_point_o != '/':
     544                    obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     545                    netmgr = dbus.Interface(obj, _NM_IFACE)
     546                    netmgr.DeactivateConnection(connection_o)
     547
     548    def __get_active_connections_error_cb(self, err):
     549        logging.error('Error getting the active connections: %s', err)
     550
     551    def __get_device_state_reply_cb(self, state):
     552        self._device_state = state
     553        self._update()
     554
     555    def __get_device_state_error_cb(self, err):
     556        logging.error('Error getting the device state: %s', err)
     557
     558    def __device_state_changed_cb(self, new_state, old_state, reason):
     559        self._device_state = new_state
     560        self._update()
     561
     562    def __wireless_properties_changed_cb(self, properties):
     563        if 'ActiveAccessPoint' in properties and \
     564                properties['ActiveAccessPoint'] != '/':
     565            active_ap = self._bus.get_object(_NM_SERVICE,
     566                                             properties['ActiveAccessPoint'])
     567            props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
     568            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
     569                         reply_handler=self.__get_all_ap_props_reply_cb,
     570                         error_handler=self.__get_all_ap_props_error_cb)
     571
     572    def __get_all_ap_props_reply_cb(self, properties):
     573        if properties['Mode'] == network.NM_802_11_MODE_ADHOC:
     574            if 'Frequency' in properties:
     575                try:
     576                    frequency = properties['Frequency']
     577                    channel = network.frequency_to_channel(frequency)
     578                    if self._channel == channel:
     579                        self._active = True
     580                    else:
     581                        self._active = False
     582                except KeyError:
     583                    logging.debug("Error getting the Frequency.")
     584        else:
     585            self._active = False
     586        self._update()
     587
     588    def __get_all_ap_props_error_cb(self, err):
     589        logging.error('Error getting the access point properties: %s', err)
     590
     591    def _update(self):
     592        if self._active:
     593            state = self._device_state
     594        else:
     595            state = network.DEVICE_STATE_UNKNOWN
     596
     597        if state == network.DEVICE_STATE_ACTIVATED:
     598            icon_name = '%s-connected' % self._icon_name
     599        else:
     600            icon_name = self._icon_name
     601
     602        self.props.base_color = self._state_color
     603        self._palette_icon.props.xo_color = self._state_color
     604
     605        if icon_name is not None:
     606            self.props.icon_name = icon_name
     607            icon = self._palette.props.icon
     608            icon.props.icon_name = icon_name
     609
     610        if state in [network.DEVICE_STATE_PREPARE,
     611                     network.DEVICE_STATE_CONFIG,
     612                     network.DEVICE_STATE_NEED_AUTH,
     613                     network.DEVICE_STATE_IP_CONFIG]:
     614            if self._disconnect_item:
     615                self._disconnect_item.show()
     616            self._connect_item.hide()
     617            self._palette.props.secondary_text = _('Connecting...')
     618            self.props.pulsing = True
     619        elif state == network.DEVICE_STATE_ACTIVATED:
     620            if self._disconnect_item:
     621                self._disconnect_item.show()
     622            self._connect_item.hide()
     623            self._palette.props.secondary_text = _('Connected')
     624            self.props.pulsing = False
     625        else:
     626            if self._disconnect_item:
     627                self._disconnect_item.hide()
     628            self._connect_item.show()
     629            self._palette.props.secondary_text = None
     630            self.props.pulsing = False
     631
     632    def _update_color(self):
     633        if self._greyed_out:
     634            self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
     635        else:
     636            self.props.base_color = self._state_color
     637
     638    def indicate_population(self, state):
     639        if state == True:
     640            self._state_color = profile.get_color()
     641            self.props.base_color = self._state_color
     642            self._palette_icon.props.xo_color = self._state_color
     643        else:
     644            color = '%s,%s' % (profile.get_color().get_stroke_color(),
     645                               style.COLOR_TRANSPARENT.get_svg())
     646            self._state_color = XoColor(color)
     647            self.props.base_color = self._state_color
     648            self._palette_icon.props.xo_color = self._state_color
     649
     650    def set_filter(self, query):
     651        self._greyed_out = self._name.lower().find(query) == -1
     652        self._update_color()
     653
     654    def disconnect(self):
     655        self._bus.remove_signal_receiver(self.__device_state_changed_cb,
     656                                         signal_name='StateChanged',
     657                                         path=self._device.object_path,
     658                                         dbus_interface=_NM_DEVICE_IFACE)
     659        self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
     660                                         signal_name='PropertiesChanged',
     661                                         path=self._device.object_path,
     662                                         dbus_interface=_NM_WIRELESS_IFACE)
     663
    446664
    447665class OlpcMeshView(CanvasPulsingIcon):
    448666    def __init__(self, mesh_mgr, channel):
    class NetworkManagerObserver(object): 
    8141032        self._devices = {}
    8151033        self._netmgr = None
    8161034        self._olpc_mesh_device_o = None
     1035        self._has_mesh_device = False
     1036        self._check_mesh_source = 0
    8171037
    8181038    def listen(self):
    8191039        try:
    class NetworkManagerObserver(object): 
    8331053        self._bus.add_signal_receiver(self.__device_removed_cb,
    8341054                                      signal_name='DeviceRemoved',
    8351055                                      dbus_interface=_NM_IFACE)
     1056        self._bus.add_signal_receiver(self.__properties_changed_cb,
     1057                                      signal_name='PropertiesChanged',
     1058                                      dbus_interface=_NM_IFACE)
    8361059
    8371060        settings = network.get_settings()
    8381061        if settings is not None:
    class NetworkManagerObserver(object): 
    8771100        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
    8781101        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
    8791102            self._devices[device_o] = DeviceObserver(self._box, device)
     1103            if self._check_mesh_source != 0:
     1104                gobject.source_remove(self._check_mesh_source)
     1105            self._check_mesh_source = gobject.timeout_add( \
     1106                    5, self._add_adhoc_networks, device)
    8801107        elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
     1108            self._has_mesh_device = True
    8811109            self._olpc_mesh_device_o = device_o
    8821110            self._box.enable_olpc_mesh(device)
    8831111
    class NetworkManagerObserver(object): 
    8921120            observer = self._devices[device_o]
    8931121            observer.disconnect()
    8941122            del self._devices[device_o]
     1123            if self._has_mesh_device == False:
     1124                self._box.remove_adhoc_networks()
    8951125            return
    8961126
    8971127        if self._olpc_mesh_device_o == device_o:
    8981128            self._box.disable_olpc_mesh(device_o)
    8991129
     1130    def _add_adhoc_networks(self, device):
     1131        """If we do not find mesh hardware we create Ad-hoc networks."""
     1132        if self._has_mesh_device == False:
     1133            self._box.add_adhoc_networks(device)
     1134        return False
     1135
     1136    def __properties_changed_cb(self, properties):
     1137        if 'WirelessHardwareEnabled' in properties:
     1138            if properties['WirelessHardwareEnabled'] == False:
     1139                if self._has_mesh_device == False:
     1140                    self._box.remove_adhoc_networks()
     1141            if properties['WirelessHardwareEnabled'] == True:
     1142                for device in self._devices:
     1143                    if self._has_mesh_device == False:
     1144                        self._box.add_adhoc_networks(device)
     1145
     1146
    9001147class MeshBox(gtk.VBox):
    9011148    __gtype_name__ = 'SugarMeshBox'
    9021149
    class MeshBox(gtk.VBox): 
    9061153        gobject.GObject.__init__(self)
    9071154
    9081155        self.wireless_networks = {}
     1156        self._adhoc_manager = None
    9091157
    9101158        self._model = neighborhood.get_model()
    9111159        self._buddies = {}
    class MeshBox(gtk.VBox): 
    10631311            ap.disconnect()
    10641312            return
    10651313
     1314        if self._adhoc_manager != None and \
     1315                ap.name.startswith('Ad-hoc Network') and \
     1316                ap.mode == network.NM_802_11_MODE_ADHOC:
     1317
     1318            if old_hash is None: # new Ad-hoc network finished initializing
     1319                self._adhoc_manager.add_access_point(ap)
     1320            # we are called as well in other cases but we do not need to
     1321            # act here as we don't display signal strength for Ad-hoc networks
     1322            return
     1323
    10661324        if old_hash is None: # new AP finished initializing
    10671325            self._add_ap_to_network(ap)
    10681326            return
    class MeshBox(gtk.VBox): 
    10851343        ap.initialize()
    10861344
    10871345    def remove_access_point(self, ap_o):
     1346        if self._adhoc_manager is not None:
     1347            if self._adhoc_manager.remove_access_point(ap_o) == True:
     1348                return
     1349
    10881350        # we don't keep an index of ap object path to network, but since
    10891351        # we'll only ever have a handful of networks, just try them all...
    10901352        for net in self.wireless_networks.values():
    class MeshBox(gtk.VBox): 
    11011363        # it (e.g. olpc-mesh adhoc network)
    11021364        logging.debug('Can not remove access point %s' % ap_o)
    11031365
     1366    def add_adhoc_networks(self, device):
     1367        if self._adhoc_manager is None:
     1368            self._adhoc_manager = AdHocManager(device)
     1369        for channel in self._adhoc_manager.channels:
     1370            self._add_adhoc_network_icon(self._adhoc_manager, channel)
     1371        self._adhoc_manager.autoconnect()
     1372
     1373    def remove_adhoc_networks(self):
     1374        for channel in self._adhoc_manger.channels:
     1375            icon = self._adhoc_manager.remove_network(channel)
     1376            if icon is not None:
     1377                icon.disconnect()
     1378                self._layout.remove(icon)
     1379
     1380    def _add_adhoc_network_icon(self, adhoc_manager, channel):
     1381        icon = AdHocView(adhoc_manager, channel)
     1382        self._layout.add(icon)
     1383        self._adhoc_manager.add_network(channel, icon)
     1384
    11041385    def _add_olpc_mesh_icon(self, mesh_mgr, channel):
    11051386        icon = OlpcMeshView(mesh_mgr, channel)
    11061387        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..828451e
    - +  
     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_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
     32
     33
     34class Network(object):
     35    """Representation of an Ad-hoc network"""
     36
     37    def __init__(self, icon, access_point):
     38        self.icon = icon
     39        self.access_point = access_point
     40
     41
     42class AdHocManager(object):
     43    """To mimic the mesh behavior on devices where mesh hardware is
     44    not available we support the creation of an Ad-hoc network on
     45    three channels 1, 6, 11. If Sugar sees no "known" network when it
     46    starts, it does autoconnect to an Ad-hoc network.
     47
     48    """
     49
     50    timeout = 30
     51
     52    def __init__(self, device):
     53        self._bus = dbus.SystemBus()
     54
     55        self.device = device
     56        self._idle_source = 0
     57        self._device_state = network.DEVICE_STATE_UNKNOWN
     58
     59        self.channels = [1, 6, 11]
     60        self._networks = {}
     61
     62        props = dbus.Interface(device,
     63                                   'org.freedesktop.DBus.Properties')
     64        props.Get(_NM_DEVICE_IFACE, 'State',
     65                  reply_handler=self.__get_device_state_reply_cb,
     66                  error_handler=self.__get_state_error_cb)
     67
     68        self._bus.add_signal_receiver(self.__device_state_changed_cb,
     69                                      signal_name='StateChanged',
     70                                      path=self.device.object_path,
     71                                      dbus_interface=_NM_DEVICE_IFACE)
     72
     73    def _have_configured_connections(self):
     74        return len(network.get_settings().connections) > 0
     75
     76    def autoconnect(self):
     77        """Autoconnect to an Ad-hoc network"""
     78        if self._have_configured_connections():
     79            self._autoconnect_adhoc_timer()
     80        else:
     81            self._autoconnect_adhoc()
     82
     83    def __get_state_error_cb(self, err):
     84        logging.debug('Error getting the device state: %s', err)
     85
     86    def __get_device_state_reply_cb(self, state):
     87        self._device_state = state
     88
     89    def __device_state_changed_cb(self, new_state, old_state, reason):
     90        self._device_state = new_state
     91
     92    def _autoconnect_adhoc_timer(self):
     93        """Start a timer which basically looks for 30 seconds of inactivity
     94        on the device, then does autoconnect to an Ad-hoc network.
     95
     96        """
     97        if self._idle_source != 0:
     98            gobject.source_remove(self._idle_source)
     99        self._idle_source = gobject.timeout_add_seconds(self.timeout,
     100                                                        self._idle_check)
     101
     102    def _autoconnect_adhoc(self):
     103        """First we try if there is an Ad-hoc network that is used by other
     104        learners in the area, if not we default to channel 1.
     105
     106        """
     107        if self._networks[1].access_point is not None:
     108            self._connect(1)
     109        elif self._networks[6].access_point is not None:
     110            self._connect(6)
     111        elif self._networks[11].access_point is not None:
     112            self._connect(11)
     113        else:
     114            self._connect(1)
     115
     116    def _idle_check(self):
     117        if  self._device_state == network.DEVICE_STATE_DISCONNECTED:
     118            logging.debug("Connect to Ad-hoc network due to inactivity.")
     119            self._autoconnect_adhoc()
     120        return False
     121
     122    def activate_channel(self, channel):
     123        self._connect(channel)
     124
     125    def _connect(self, channel):
     126        name = "Ad-hoc Network %d" % channel
     127        connection = network.find_connection_by_ssid(name)
     128        if connection is None:
     129            settings = Settings()
     130            settings.connection.id = name
     131            settings.connection.uuid = unique_id()
     132            settings.connection.type = '802-11-wireless'
     133            settings.wireless.ssid = dbus.ByteArray(name)
     134            settings.wireless.band = 'bg'
     135            settings.wireless.channel = channel
     136            settings.wireless.mode = 'adhoc'
     137            settings.ip4_config = IP4Config()
     138            settings.ip4_config.method = 'link-local'
     139
     140            connection = network.add_connection(name, settings)
     141
     142        obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
     143        netmgr = dbus.Interface(obj, _NM_IFACE)
     144
     145        netmgr.ActivateConnection(network.SETTINGS_SERVICE,
     146                                  connection.path,
     147                                  self.device.object_path,
     148                                  '/',
     149                                  reply_handler=self.__activate_reply_cb,
     150                                  error_handler=self.__activate_error_cb)
     151
     152    def __activate_reply_cb(self, connection):
     153        logging.debug('Ad-hoc network created: %s', connection)
     154
     155    def __activate_error_cb(self, err):
     156        logging.debug('Failed to create Ad-hoc network: %s', err)
     157
     158    def add_network(self, channel, icon):
     159        if channel not in self._networks:
     160            self._networks[channel] = Network(icon, None)
     161
     162    def remove_network(self, channel):
     163        if channel in self._networks:
     164            net = self._networks.pop(channel)
     165            return net.icon
     166        return None
     167
     168    def add_access_point(self, access_point):
     169        """If a new adhoc network is announcd that is named like an Ad-hoc
     170        network we take this as an indication that other learners are
     171        using the network an indicate this.
     172
     173        """
     174        if ' 1' == access_point.name[-2:]:
     175            self._networks[1].icon.indicate_population(True)
     176            self._networks[1].access_point = access_point
     177        elif '6' == access_point.name[-1]:
     178            self._networks[6].icon.indicate_population(True)
     179            self._networks[6].access_point = access_point
     180        elif '11' == access_point.name[-2:]:
     181            self._networks[11].icon.indicate_population(True)
     182            self._networks[11].access_point = access_point
     183
     184    def remove_access_point(self, ap_object_path):
     185        """When the last user of the network goes away we remove
     186        the access point and indicate this.
     187
     188        """
     189        for net in self._networks.values():
     190            if net.access_point is not None:
     191                if net.access_point.model.object_path == ap_object_path:
     192                    net.icon.indicate_population(False)
     193                    net.access_point.disconnect()
     194                    net.access_point = None
     195                    return True
     196        return False
  • src/jarabe/model/network.py

    diff --git a/src/jarabe/model/network.py b/src/jarabe/model/network.py
    index 47db43f..f53b924 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    ftoc = {2412: 1, 2417: 2, 2422: 3, 2427: 4,
     106            2432: 5, 2437: 6, 2442: 7, 2447: 8,
     107            2452: 9, 2457: 10, 2462: 11, 2467: 12,
     108            2472: 13}
     109    return ftoc[frequency]
     110
     111
    103112class WirelessSecurity(object):
    104113    def __init__(self):
    105114        self.key_mgmt = None
    class Wireless(object): 
    127136        self.security = None
    128137        self.mode = None
    129138        self.band = None
     139        self.channel = None
    130140
    131141    def get_dict(self):
    132142        wireless = {'ssid': self.ssid}
    class Wireless(object): 
    136146            wireless['mode'] = self.mode
    137147        if self.band:
    138148            wireless['band'] = self.band
     149        if self.channel:
     150            wireless['channel'] = self.channel
    139151        return wireless
    140152
    141153
    class AccessPoint(gobject.GObject): 
    476488        self.wpa_flags = 0
    477489        self.rsn_flags = 0
    478490        self.mode = 0
     491        self.channel = 0
    479492
    480493    def initialize(self):
    481494        model_props = dbus.Interface(self.model,
    class AccessPoint(gobject.GObject): 
    545558            self.rsn_flags = properties['RsnFlags']
    546559        if 'Mode' in properties:
    547560            self.mode = properties['Mode']
     561        if 'Frequency' in properties:
     562            try:
     563                self.channel = frequency_to_channel(properties['Frequency'])
     564            except KeyError:
     565                self.channel = 1
     566
    548567        self._initialized = True
    549568        self.emit('props-changed', old_hash)
    550569