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

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

New 'git fomat-patch'-ed version with a fix for the "Error getting the access point properties: org.freedesktop.DBus.Error.UnknownMethod: Method "GetAll" with signature "s" on interface "org.freedesktop.DBus.Properties" doesn't exist" error and another fix for a typo that caused weired behavior

  • extensions/deviceicon/network.py

    From aa328066d79eed324b179f2eb840d8b3afecf372 Mon Sep 17 00:00:00 2001
    From: Simon Schampijer <simon@schampijer.de>
    Date: Thu, 5 Aug 2010 10:29:40 +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    |  332 ++++++++++++++++++++++++++++++++++----
     src/jarabe/model/Makefile.am     |    1 +
     src/jarabe/model/adhoc.py        |  196 ++++++++++++++++++++++
     src/jarabe/model/network.py      |   21 +++-
     5 files changed, 546 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..454c767 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 = True
     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        active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
     532
     533        for conn_o in active_connections_o:
     534            obj = self._bus.get_object(_NM_IFACE, conn_o)
     535            props = dbus.Interface(obj, dbus.PROPERTIES_IFACE)
     536            state = props.Get(_NM_ACTIVE_CONN_IFACE, 'State')
     537            if state == network.NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
     538                ap_o = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject')
     539                if ap_o != '/':
     540                    netmgr.DeactivateConnection(conn_o)
     541
     542    def __get_device_state_reply_cb(self, state):
     543        self._device_state = state
     544        self._update()
     545
     546    def __get_device_state_error_cb(self, err):
     547        logging.error('Error getting the device state: %s', err)
     548
     549    def __device_state_changed_cb(self, new_state, old_state, reason):
     550        self._device_state = new_state
     551        self._update()
     552
     553    def __wireless_properties_changed_cb(self, properties):
     554        if 'ActiveAccessPoint' in properties and \
     555                properties['ActiveAccessPoint'] != '/':
     556            active_ap = self._bus.get_object(_NM_SERVICE,
     557                                             properties['ActiveAccessPoint'])
     558            props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE)
     559            props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True,
     560                         reply_handler=self.__get_all_ap_props_reply_cb,
     561                         error_handler=self.__get_all_ap_props_error_cb)
     562               
     563    def __get_all_ap_props_reply_cb(self, properties):
     564        if properties['Mode'] == network.NM_802_11_MODE_ADHOC:
     565            if 'Frequency' in properties:
     566                try:
     567                    frequency = properties['Frequency']
     568                    channel = network.frequency_to_channel(frequency)
     569                    if self._channel == channel:
     570                        self._active = True
     571                    else:
     572                        self._active = False
     573                except KeyError:
     574                    logging.debug("Error getting the Frequency.")
     575        else:
     576            self._active = False
     577        self._update()
     578
     579    def __get_all_ap_props_error_cb(self, err):
     580        logging.error('Error getting the access point properties: %s', err)
     581
     582    def _update(self):
     583        if self._active:
     584            state = self._device_state
     585        else:
     586            state = network.DEVICE_STATE_UNKNOWN
     587
     588        if state == network.DEVICE_STATE_ACTIVATED:
     589            icon_name = '%s-connected' % self._icon_name
     590        else:
     591            icon_name = self._icon_name
     592
     593        self.props.base_color = self._state_color
     594        self._palette_icon.props.xo_color = self._state_color
     595
     596        if icon_name is not None:
     597            self.props.icon_name = icon_name
     598            icon = self._palette.props.icon
     599            icon.props.icon_name = icon_name
     600
     601        if state in [network.DEVICE_STATE_PREPARE,
     602                     network.DEVICE_STATE_CONFIG,
     603                     network.DEVICE_STATE_NEED_AUTH,
     604                     network.DEVICE_STATE_IP_CONFIG]:
     605            if self._disconnect_item:
     606                self._disconnect_item.show()
     607            self._connect_item.hide()
     608            self._palette.props.secondary_text = _('Connecting...')
     609            self.props.pulsing = True
     610        elif state == network.DEVICE_STATE_ACTIVATED:
     611            if self._disconnect_item:
     612                self._disconnect_item.show()
     613            self._connect_item.hide()
     614            self._palette.props.secondary_text = _('Connected')
     615            self.props.pulsing = False
     616        else:
     617            if self._disconnect_item:
     618                self._disconnect_item.hide()
     619            self._connect_item.show()
     620            self._palette.props.secondary_text = None
     621            self.props.pulsing = False
     622
     623    def _update_color(self):
     624        if self._greyed_out:
     625            self.props.base_color = XoColor('#D5D5D5,#D5D5D5')
     626        else:
     627            self.props.base_color = self._state_color
     628
     629    def indicate_population(self, state):
     630        if state == True:
     631            self._state_color = profile.get_color()
     632            self.props.base_color = self._state_color
     633            self._palette_icon.props.xo_color = self._state_color
     634        else:
     635            color = '%s,%s' % (profile.get_color().get_stroke_color(),
     636                               style.COLOR_TRANSPARENT.get_svg())
     637            self._state_color = XoColor(color)
     638            self.props.base_color = self._state_color
     639            self._palette_icon.props.xo_color = self._state_color
     640
     641    def set_filter(self, query):
     642        self._greyed_out = self._name.lower().find(query) == -1
     643        self._update_color()
     644
     645    def disconnect(self):
     646        self._bus.remove_signal_receiver(self.__device_state_changed_cb,
     647                                         signal_name='StateChanged',
     648                                         path=self._device.object_path,
     649                                         dbus_interface=_NM_DEVICE_IFACE)
     650        self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb,
     651                                         signal_name='PropertiesChanged',
     652                                         path=self._device.object_path,
     653                                         dbus_interface=_NM_WIRELESS_IFACE)
     654
    446655
    447656class OlpcMeshView(CanvasPulsingIcon):
    448657    def __init__(self, mesh_mgr, channel):
    class NetworkManagerObserver(object): 
    8141023        self._devices = {}
    8151024        self._netmgr = None
    8161025        self._olpc_mesh_device_o = None
     1026        self._has_mesh_device = False
     1027        self._check_mesh_source = 0
    8171028
    8181029    def listen(self):
    8191030        try:
    class NetworkManagerObserver(object): 
    8331044        self._bus.add_signal_receiver(self.__device_removed_cb,
    8341045                                      signal_name='DeviceRemoved',
    8351046                                      dbus_interface=_NM_IFACE)
     1047        self._bus.add_signal_receiver(self.__properties_changed_cb,
     1048                                      signal_name='PropertiesChanged',
     1049                                      dbus_interface=_NM_IFACE)
    8361050
    8371051        settings = network.get_settings()
    8381052        if settings is not None:
    class NetworkManagerObserver(object): 
    8771091        device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType')
    8781092        if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
    8791093            self._devices[device_o] = DeviceObserver(self._box, device)
     1094            if self._check_mesh_source != 0:
     1095                gobject.source_remove(self._check_mesh_source)
     1096            self._check_mesh_source = gobject.timeout_add( \
     1097                    5, self._add_adhoc_networks, device)
    8801098        elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
     1099            self._has_mesh_device = True
    8811100            self._olpc_mesh_device_o = device_o
    8821101            self._box.enable_olpc_mesh(device)
    8831102
    class NetworkManagerObserver(object): 
    8921111            observer = self._devices[device_o]
    8931112            observer.disconnect()
    8941113            del self._devices[device_o]
     1114            if self._has_mesh_device == False:
     1115                self._box.remove_adhoc_networks()
    8951116            return
    8961117
    8971118        if self._olpc_mesh_device_o == device_o:
    8981119            self._box.disable_olpc_mesh(device_o)
    8991120
     1121    def _add_adhoc_networks(self, device):
     1122        """If we do not find mesh hardware we create Ad-hoc networks."""
     1123        if self._has_mesh_device == False:
     1124            self._box.add_adhoc_networks(device)
     1125        return False
     1126
     1127    def __properties_changed_cb(self, properties):
     1128        if 'WirelessHardwareEnabled' in properties:
     1129            if properties['WirelessHardwareEnabled'] == False:
     1130                if self._has_mesh_device == False:
     1131                    self._box.remove_adhoc_networks()
     1132            if properties['WirelessHardwareEnabled'] == True:
     1133                for device in self._devices:
     1134                    if self._has_mesh_device == False:
     1135                        self._box.add_adhoc_networks(device)
     1136
     1137
    9001138class MeshBox(gtk.VBox):
    9011139    __gtype_name__ = 'SugarMeshBox'
    9021140
    class MeshBox(gtk.VBox): 
    9061144        gobject.GObject.__init__(self)
    9071145
    9081146        self.wireless_networks = {}
     1147        self._adhoc_manager = None
    9091148
    9101149        self._model = neighborhood.get_model()
    9111150        self._buddies = {}
    class MeshBox(gtk.VBox): 
    10631302            ap.disconnect()
    10641303            return
    10651304
     1305        if self._adhoc_manager != None and \
     1306                ap.name.startswith('Ad-hoc Network') and \
     1307                ap.mode == network.NM_802_11_MODE_ADHOC:
     1308
     1309            if old_hash is None: # new Ad-hoc network finished initializing
     1310                self._adhoc_manager.add_access_point(ap)
     1311            # we are called as well in other cases but we do not need to
     1312            # act here as we don't display signal strength for Ad-hoc networks
     1313            return
     1314
    10661315        if old_hash is None: # new AP finished initializing
    10671316            self._add_ap_to_network(ap)
    10681317            return
    class MeshBox(gtk.VBox): 
    10851334        ap.initialize()
    10861335
    10871336    def remove_access_point(self, ap_o):
     1337        if self._adhoc_manager is not None:
     1338            if self._adhoc_manager.remove_access_point(ap_o) == True:
     1339                return
     1340
    10881341        # we don't keep an index of ap object path to network, but since
    10891342        # we'll only ever have a handful of networks, just try them all...
    10901343        for net in self.wireless_networks.values():
    class MeshBox(gtk.VBox): 
    11011354        # it (e.g. olpc-mesh adhoc network)
    11021355        logging.debug('Can not remove access point %s' % ap_o)
    11031356
     1357    def add_adhoc_networks(self, device):
     1358        if self._adhoc_manager is None:
     1359            self._adhoc_manager = AdHocManager(device)
     1360        for channel in self._adhoc_manager.channels:
     1361            self._add_adhoc_network_icon(self._adhoc_manager, channel)
     1362        self._adhoc_manager.autoconnect()
     1363
     1364    def remove_adhoc_networks(self):
     1365        for channel in self._adhoc_manger.channels:
     1366            icon = self._adhoc_manager.remove_network(channel)
     1367            if icon is not None:
     1368                icon.disconnect()
     1369                self._layout.remove(icon)
     1370
     1371    def _add_adhoc_network_icon(self, adhoc_manager, channel):
     1372        icon = AdHocView(adhoc_manager, channel)
     1373        self._layout.add(icon)
     1374        self._adhoc_manager.add_network(channel, icon)
     1375
    11041376    def _add_olpc_mesh_icon(self, mesh_mgr, channel):
    11051377        icon = OlpcMeshView(mesh_mgr, channel)
    11061378        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..783d474
    - +  
     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 = 'shared'
     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