[Dextrose] [PATCH] Sharing 3G connection

Martin Abente martin.abente.lahaye at gmail.com
Mon Nov 1 09:13:06 EDT 2010


Add a new toggle button to gsm palette, which allow users
to share the gsm connection with one click.
---
 extensions/deviceicon/network.py |  178 +++++++++++++++++++++++++++++++++++--
 1 files changed, 168 insertions(+), 10 deletions(-)

diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
index 0789f9c..1510abd 100644
--- a/extensions/deviceicon/network.py
+++ b/extensions/deviceicon/network.py
@@ -23,6 +23,7 @@ import logging
 import hashlib
 import socket
 import struct
+import random
 import re
 import datetime
 import time
@@ -61,6 +62,7 @@ _NM_SERIAL_IFACE = 'org.freedesktop.NetworkManager.Device.Serial'
 _NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
 _NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
 _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
+_NM_OBJ_PROPERTIES = 'org.freedesktop.DBus.Properties'
 
 _GSM_STATE_NOT_READY = 0
 _GSM_STATE_DISCONNECTED = 1
@@ -68,6 +70,11 @@ _GSM_STATE_CONNECTING = 2
 _GSM_STATE_CONNECTED = 3
 _GSM_STATE_FAILED = 4
 
+_GSM_SHARING_PRIVATE = 0
+_GSM_SHARING_TRYING = 1
+_GSM_SHARING_NEIGHBORHOOD = 2
+
+_GSM_SHARING_CHANNELS = [2,3,4,5,7,8,9,10,12,13]
 
 class WirelessPalette(Palette):
     __gtype_name__ = 'SugarWirelessPalette'
@@ -207,6 +214,10 @@ class GsmPalette(Palette):
                                  gobject.TYPE_NONE, ([])),
         'gsm-disconnect'      : (gobject.SIGNAL_RUN_FIRST,
                                  gobject.TYPE_NONE, ([])),
+        'gsm-private'         : (gobject.SIGNAL_RUN_FIRST,
+                                 gobject.TYPE_NONE, ([])),
+        'gsm-neighborhood'    : (gobject.SIGNAL_RUN_FIRST,
+                                 gobject.TYPE_NONE, ([]))
     }
 
     def __init__(self):
@@ -215,12 +226,17 @@ class GsmPalette(Palette):
 
         self._current_state = None
         self._failed_connection = False
+        self._sharing_state = _GSM_SHARING_PRIVATE
 
         self._toggle_state_item = MenuItem('')
         self._toggle_state_item.connect('activate', self.__toggle_state_cb)
         self.menu.append(self._toggle_state_item)
         self._toggle_state_item.show()
 
+        self._sharing_toggle_item = MenuItem('')
+        self._sharing_toggle_item.connect('activate', self.__sharing_toggle_cb)
+        self.menu.append(self._sharing_toggle_item)
+
         self.info_box = gtk.VBox()
 
         self.error_title_label = gtk.Label("")
@@ -302,6 +318,10 @@ class GsmPalette(Palette):
             icon = Icon(icon_name='media-eject', \
                             icon_size=gtk.ICON_SIZE_MENU)
             self._toggle_state_item.set_image(icon)
+
+            self.sharing_update_text()
+            self._sharing_toggle_item.show()
+            return
             
         elif self._current_state == _GSM_STATE_FAILED:
             message_error = self._get_error_by_nm_reason(reason)
@@ -310,6 +330,8 @@ class GsmPalette(Palette):
             raise ValueError('Invalid GSM state while updating label and ' \
                              'text, %s' % str(self._current_state))
 
+        self._sharing_toggle_item.hide()
+
     def __toggle_state_cb(self, menuitem):
         if self._current_state == _GSM_STATE_NOT_READY:
             pass
@@ -325,6 +347,38 @@ class GsmPalette(Palette):
             raise ValueError('Invalid GSM state while emitting signal, %s' % \
                              str(self._current_state))
 
+    def sharing_update_text(self):
+        if self._sharing_state == _GSM_SHARING_PRIVATE:
+            self._sharing_toggle_item.get_child().set_label(_('Private'))
+            icon = Icon(icon_name='zoom-home', icon_size=gtk.ICON_SIZE_MENU)
+            self._sharing_toggle_item.set_image(icon)
+
+        elif self._sharing_state == _GSM_SHARING_TRYING:
+            self._sharing_toggle_item.get_child().set_label(_('Please wait...'))
+
+        elif self._sharing_state == _GSM_SHARING_NEIGHBORHOOD:
+            self._sharing_toggle_item.get_child().set_label(_('My Neighborhood'))
+            icon = Icon(icon_name='zoom-neighborhood', icon_size=gtk.ICON_SIZE_MENU)
+            self._sharing_toggle_item.set_image(icon)
+
+        else:
+             raise ValueError('Invalid GSM sharing state while updating, %s' % \
+                             str(self._sharing_state))
+
+    def __sharing_toggle_cb(self, menuitem):
+        if self._sharing_state == _GSM_SHARING_PRIVATE:
+            self.emit('gsm-neighborhood')
+            
+        elif self._sharing_state == _GSM_SHARING_TRYING:
+            pass
+
+        elif self._sharing_state == _GSM_SHARING_NEIGHBORHOOD:
+            self.emit('gsm-private')
+
+        else:
+             raise ValueError('Invalid GSM sharing state, %s' % \
+                             str(self._sharing_state))
+
     def add_alert(self, error, suggestion):
         self._failed_connection = True
         self._toggle_state_item.get_child().set_label(_('Try connection again'))
@@ -525,8 +579,16 @@ class WirelessDeviceView(ToolButton):
         else:
             state = network.DEVICE_STATE_UNKNOWN
 
-        if self._mode != network.NM_802_11_MODE_ADHOC and \
-                network.is_sugar_adhoc_network(self._name) == False:
+        if self._mode == network.NM_802_11_MODE_ADHOC and \
+                network.is_sugar_adhoc_network(self._name):
+            channel = network.frequency_to_channel(self._frequency)
+            if state == network.DEVICE_STATE_ACTIVATED:
+                self._icon.props.icon_name = 'network-adhoc-%s-connected' \
+                        % channel
+            else:
+                self._icon.props.icon_name = 'network-adhoc-%s' % channel
+            self._icon.props.base_color = profile.get_color()
+        else:
             if state == network.DEVICE_STATE_ACTIVATED:
                 icon_name = '%s-connected' % 'network-wireless'
             else:
@@ -535,14 +597,6 @@ class WirelessDeviceView(ToolButton):
             icon_name = get_icon_state(icon_name, self._strength)
             if icon_name:
                 self._icon.props.icon_name = icon_name
-        else:
-            channel = network.frequency_to_channel(self._frequency)
-            if state == network.DEVICE_STATE_ACTIVATED:
-                self._icon.props.icon_name = 'network-adhoc-%s-connected' \
-                        % channel
-            else:
-                self._icon.props.icon_name = 'network-adhoc-%s' % channel
-            self._icon.props.base_color = profile.get_color()
 
         if state == network.DEVICE_STATE_PREPARE or \
            state == network.DEVICE_STATE_CONFIG or \
@@ -730,6 +784,8 @@ class GsmDeviceView(TrayIcon):
     def __init__(self, device):
         self._connection_time_handler = None
         self._connection_timestamp = 0
+        self._shared_connection = None
+        self._target_dev_path = None
 
         client = gconf.client_get_default()
         color = xocolor.XoColor(client.get_string('/desktop/sugar/user/color'))
@@ -755,6 +811,8 @@ class GsmDeviceView(TrayIcon):
         palette.set_group_id('frame')
         palette.connect('gsm-connect', self.__gsm_connect_cb)
         palette.connect('gsm-disconnect', self.__gsm_disconnect_cb)
+        palette.connect('gsm-neighborhood', self.__gsm_start_sharing_cb)
+        palette.connect('gsm-private', self.__gsm_stop_sharing_cb)
 
         self._palette = palette
 
@@ -785,6 +843,106 @@ class GsmDeviceView(TrayIcon):
         logging.debug('Connected successfully to gsm device, %s',
                       active_connection)
 
+    def __gsm_start_sharing_cb(self, palette):
+        if self._palette._sharing_state == _GSM_SHARING_PRIVATE:
+            logging.debug('GSM will start sharing now')
+            self._palette._sharing_state = _GSM_SHARING_TRYING
+            self._palette.sharing_update_text()
+
+            nm_obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+            nm_iface = dbus.Interface(nm_obj, _NM_IFACE)
+            devs_paths = nm_iface.GetDevices()
+
+            target_dev_path = None           
+            for dev_path in devs_paths:
+                dev_obj = self._bus.get_object(_NM_SERVICE, dev_path)
+                dev_props = dbus.Interface(dev_obj, _NM_OBJ_PROPERTIES)
+                device_type = dev_props.Get(_NM_DEVICE_IFACE, 'DeviceType')
+                if device_type == network.DEVICE_TYPE_802_11_WIRELESS:
+                    target_dev_path = dev_path
+                    break
+
+            if target_dev_path == None:
+                self._gsm_sharing_reset()
+                raise RuntimeError('No device for sharing')
+            self._target_dev_path = target_dev_path
+
+            client = gconf.client_get_default()
+            nick = client.get_string('/desktop/sugar/user/nick')
+            nick = re.sub('\W', '', nick)
+
+            name_format = '%s network'
+            format_length = len(name_format) - len('%s')
+            nick_length = 31 - format_length
+            name = name_format % nick[:nick_length]
+
+            connection = network.find_connection_by_ssid(name)
+            if connection == None:
+                settings = Settings()
+                settings.connection.id = name
+                settings.connection.uuid = unique_id()
+                settings.connection.type = '802-11-wireless'
+                settings.wireless.ssid = dbus.ByteArray(name)
+                settings.wireless.mode = 'adhoc'
+                settings.wireless.band = 'bg'
+                chosen_channel = random.randrange(len(_GSM_SHARING_CHANNELS))
+                settings.wireless.channel = _GSM_SHARING_CHANNELS[chosen_channel]
+                settings.ip4_config = IP4Config()
+                settings.ip4_config.method = 'shared'
+                connection = network.add_connection(name, settings)
+
+            nm_iface.ActivateConnection(network.SETTINGS_SERVICE,
+                          connection.path,
+                          target_dev_path,
+                          '/',
+                          reply_handler=self.__gsm_sharing_ok_cb,
+                          error_handler=self.__gsm_sharing_error_cb)
+
+    def __gsm_sharing_ok_cb(self, connection):
+        logging.debug('GSM sharing is enabled')
+        self._shared_connection = connection
+        self._bus.add_signal_receiver(self.__gsm_sharing_changed_cb,
+                                      signal_name='StateChanged',
+                                      path=self._target_dev_path,
+                                      dbus_interface=_NM_DEVICE_IFACE)
+        self._palette._sharing_state = _GSM_SHARING_NEIGHBORHOOD
+        self._palette.sharing_update_text()
+
+    def __gsm_sharing_changed_cb(self, new_state, old_state, reason):
+        if new_state == network.DEVICE_STATE_DISCONNECTED:
+            self._gsm_sharing_reset()
+
+    def _gsm_sharing_reset(self):
+            logging.debug('GSM sharing is disabled')
+            if self._target_dev_path != None:
+                self._bus.remove_signal_receiver(self.__gsm_sharing_changed_cb,
+                                                         signal_name='StateChanged',
+                                                         path=self._target_dev_path,
+                                                         dbus_interface=_NM_DEVICE_IFACE)
+            self._shared_connection = None
+            self._target_dev_path = None
+            self._palette._sharing_state = _GSM_SHARING_PRIVATE
+            self._palette.sharing_update_text()
+
+    def __gsm_sharing_error_cb(self, error):
+        logging.debug('GSM sharing could not start: %s' % str(error))
+        self._gsm_sharing_reset()
+
+    def __gsm_stop_sharing_cb(self, palette):
+        logging.debug('GSM will stop sharing now')
+        nm_obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+        nm_iface = dbus.Interface(nm_obj, _NM_IFACE)
+        nm_iface.DeactivateConnection(
+                self._shared_connection,
+                reply_handler=self.__gsm_stop_sharing_ok_cb,
+                error_handler=self.__gsm_stop_sharing_error_cb)
+
+    def __gsm_stop_sharing_ok_cb(self):
+        self._gsm_sharing_reset()
+
+    def __gsm_stop_sharing_error_cb(self):
+        logging.debug('GSM sharing could not stop')
+
     def __connect_error_cb(self, error):
         raise RuntimeError('Error when connecting to gsm device, %s' % error)
 
-- 
1.7.1



More information about the Dextrose mailing list