diff options
Diffstat (limited to 'extensions')
-rw-r--r-- | extensions/cpsection/Makefile.am | 3 | ||||
-rw-r--r-- | extensions/cpsection/aboutcomputer/view.py | 2 | ||||
-rw-r--r-- | extensions/cpsection/modemconfiguration/Makefile.am | 6 | ||||
-rw-r--r-- | extensions/cpsection/modemconfiguration/__init__.py | 22 | ||||
-rw-r--r-- | extensions/cpsection/modemconfiguration/model.py | 70 | ||||
-rw-r--r-- | extensions/cpsection/modemconfiguration/view.py | 250 | ||||
-rw-r--r-- | extensions/cpsection/network/model.py | 115 | ||||
-rw-r--r-- | extensions/cpsection/network/view.py | 8 | ||||
-rw-r--r-- | extensions/cpsection/power/model.py | 31 | ||||
-rw-r--r-- | extensions/cpsection/power/view.py | 58 | ||||
-rw-r--r-- | extensions/deviceicon/network.py | 628 |
11 files changed, 967 insertions, 226 deletions
diff --git a/extensions/cpsection/Makefile.am b/extensions/cpsection/Makefile.am index 73e5164..90d36ea 100644 --- a/extensions/cpsection/Makefile.am +++ b/extensions/cpsection/Makefile.am @@ -1,4 +1,5 @@ -SUBDIRS = aboutme aboutcomputer datetime frame language network power +SUBDIRS = aboutme aboutcomputer datetime frame language \ + modemconfiguration network power sugardir = $(pkgdatadir)/extensions/cpsection sugar_PYTHON = __init__.py diff --git a/extensions/cpsection/aboutcomputer/view.py b/extensions/cpsection/aboutcomputer/view.py index dd4f8f3..4b638ff 100644 --- a/extensions/cpsection/aboutcomputer/view.py +++ b/extensions/cpsection/aboutcomputer/view.py @@ -174,7 +174,7 @@ class AboutComputer(SectionView): vbox_copyright.set_border_width(style.DEFAULT_SPACING * 2) vbox_copyright.set_spacing(style.DEFAULT_SPACING) - label_copyright = gtk.Label("© 2006-2009 One Laptop per Child " + label_copyright = gtk.Label("© 2006-2010 One Laptop per Child " "Association Inc; Red Hat Inc; Collabora Ltd; " "and Contributors.") label_copyright.set_alignment(0, 0) diff --git a/extensions/cpsection/modemconfiguration/Makefile.am b/extensions/cpsection/modemconfiguration/Makefile.am new file mode 100644 index 0000000..3e2613e --- /dev/null +++ b/extensions/cpsection/modemconfiguration/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/modemconfiguration + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/modemconfiguration/__init__.py b/extensions/cpsection/modemconfiguration/__init__.py new file mode 100644 index 0000000..8a219dc --- /dev/null +++ b/extensions/cpsection/modemconfiguration/__init__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2009 Paraguay Educa, Martin Abente +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US + +from gettext import gettext as _ + +CLASS = 'ModemConfiguration' +ICON = 'module-modemconfiguration' +TITLE = _('Modem Configuration') + diff --git a/extensions/cpsection/modemconfiguration/model.py b/extensions/cpsection/modemconfiguration/model.py new file mode 100644 index 0000000..2545ce1 --- /dev/null +++ b/extensions/cpsection/modemconfiguration/model.py @@ -0,0 +1,70 @@ +# Copyright (C) 2009 Paraguay Educa, Martin Abente +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US + +import gconf + +from jarabe.model.network import GSM_USERNAME_PATH, GSM_PASSWORD_PATH, \ + GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH, \ + GSM_PUK_PATH + +def get_username(): + client = gconf.client_get_default() + return client.get_string(GSM_USERNAME_PATH) or '' + +def get_password(): + client = gconf.client_get_default() + return client.get_string(GSM_PASSWORD_PATH) or '' + +def get_number(): + client = gconf.client_get_default() + return client.get_string(GSM_NUMBER_PATH) or '' + +def get_apn(): + client = gconf.client_get_default() + return client.get_string(GSM_APN_PATH) or '' + +def get_pin(): + client = gconf.client_get_default() + return client.get_string(GSM_PIN_PATH) or '' + +def get_puk(): + client = gconf.client_get_default() + return client.get_string(GSM_PUK_PATH) or '' + +def set_username(username): + client = gconf.client_get_default() + client.set_string(GSM_USERNAME_PATH, username) + +def set_password(password): + client = gconf.client_get_default() + client.set_string(GSM_PASSWORD_PATH, password) + +def set_number(number): + client = gconf.client_get_default() + client.set_string(GSM_NUMBER_PATH, number) + +def set_apn(apn): + client = gconf.client_get_default() + client.set_string(GSM_APN_PATH, apn) + +def set_pin(pin): + client = gconf.client_get_default() + client.set_string(GSM_PIN_PATH, pin) + +def set_puk(puk): + client = gconf.client_get_default() + client.set_string(GSM_PUK_PATH, puk) + diff --git a/extensions/cpsection/modemconfiguration/view.py b/extensions/cpsection/modemconfiguration/view.py new file mode 100644 index 0000000..b236f3f --- /dev/null +++ b/extensions/cpsection/modemconfiguration/view.py @@ -0,0 +1,250 @@ +# Copyright (C) 2009 Paraguay Educa, Martin Abente +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US + +import os +import logging +from gettext import gettext as _ + +import gtk +import gobject + +from sugar.graphics import style + +from jarabe.controlpanel.sectionview import SectionView + +APPLY_TIMEOUT = 1000 + +class EntryWithLabel(gtk.HBox): + __gtype_name__ = "SugarEntryWithLabel" + + def __init__(self, label_text): + gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING) + + self._timeout_sid = 0 + self._changed_handler = None + self._is_valid = True + + self.label = gtk.Label(label_text) + self.label.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + self.label.set_alignment(1, 0.5) + self.pack_start(self.label, expand=False) + self.label.show() + + self._entry = gtk.Entry(25) + self._entry.connect('changed', self.__entry_changed_cb) + self._entry.set_width_chars(25) + self.pack_start(self._entry, expand=False) + self._entry.show() + + def __entry_changed_cb(self, widget, data=None): + if self._timeout_sid: + gobject.source_remove(self._timeout_sid) + self._timeout_sid = gobject.timeout_add(APPLY_TIMEOUT, + self.__timeout_cb) + + def __timeout_cb(self): + self._timeout_sid = 0 + + if self._entry.get_text() == self.get_value(): + return False + + try: + self.set_value(self._entry.get_text()) + except ValueError: + self._is_valid = False + else: + self._is_valid = True + + self.notify('is-valid') + + return False + + def set_text_from_model(self): + self._entry.set_text(self.get_value()) + + def get_value(self): + raise NotImplementedError + + def set_value(self): + raise NotImplementedError + + def _get_is_valid(self): + return self._is_valid + is_valid = gobject.property(type=bool, getter=_get_is_valid, default=True) + +class UsernameEntry(EntryWithLabel): + def __init__(self, model): + EntryWithLabel.__init__(self, _('Username:')) + self._model = model + + def get_value(self): + return self._model.get_username() + + def set_value(self, username): + self._model.set_username(username) + +class PasswordEntry(EntryWithLabel): + def __init__(self, model): + EntryWithLabel.__init__(self, _('Password:')) + self._model = model + + def get_value(self): + return self._model.get_password() + + def set_value(self, password): + self._model.set_password(password) + +class NumberEntry(EntryWithLabel): + def __init__(self, model): + EntryWithLabel.__init__(self, _('Number:')) + self._model = model + + def get_value(self): + return self._model.get_number() + + def set_value(self, number): + self._model.set_number(number) + +class ApnEntry(EntryWithLabel): + def __init__(self, model): + EntryWithLabel.__init__(self, _('Access Point Name (APN):')) + self._model = model + + def get_value(self): + return self._model.get_apn() + + def set_value(self, apn): + self._model.set_apn(apn) + +class PinEntry(EntryWithLabel): + def __init__(self, model): + EntryWithLabel.__init__(self, _('Personal Identity Number (PIN):')) + self._model = model + + def get_value(self): + return self._model.get_pin() + + def set_value(self, pin): + self._model.set_pin(pin) + +class PukEntry(EntryWithLabel): + def __init__(self, model): + EntryWithLabel.__init__(self, _('Personal Unblocking Key (PUK):')) + self._model = model + + def get_value(self): + return self._model.get_puk() + + def set_value(self, puk): + self._model.set_puk(puk) + + +class ModemConfiguration(SectionView): + def __init__(self, model, alerts=None): + SectionView.__init__(self) + + self._model = model + self.restart_alerts = alerts + + self.set_border_width(style.DEFAULT_SPACING) + self.set_spacing(style.DEFAULT_SPACING) + self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + explanation = _("You will need to provide the following " \ + "information to set up a mobile " \ + "broadband connection to a cellular "\ + "(3G) network.") + self._text = gtk.Label(explanation) + self._text.set_width_chars(100) + self._text.set_line_wrap(True) + self._text.set_alignment(0, 0) + self.pack_start(self._text, False) + self._text.show() + + self._username_entry = UsernameEntry(model) + self._username_entry.connect('notify::is-valid', + self.__notify_is_valid_cb) + self._group.add_widget(self._username_entry.label) + self.pack_start(self._username_entry, expand=False) + self._username_entry.show() + + self._password_entry = PasswordEntry(model) + self._password_entry.connect('notify::is-valid', + self.__notify_is_valid_cb) + self._group.add_widget(self._password_entry.label) + self.pack_start(self._password_entry, expand=False) + self._password_entry.show() + + self._number_entry = NumberEntry(model) + self._number_entry.connect('notify::is-valid', + self.__notify_is_valid_cb) + self._group.add_widget(self._number_entry.label) + self.pack_start(self._number_entry, expand=False) + self._number_entry.show() + + self._apn_entry = ApnEntry(model) + self._apn_entry.connect('notify::is-valid', + self.__notify_is_valid_cb) + self._group.add_widget(self._apn_entry.label) + self.pack_start(self._apn_entry, expand=False) + self._apn_entry.show() + + self._pin_entry = PinEntry(model) + self._pin_entry.connect('notify::is-valid', + self.__notify_is_valid_cb) + self._group.add_widget(self._pin_entry.label) + self.pack_start(self._pin_entry, expand=False) + self._pin_entry.show() + + self._puk_entry = PukEntry(model) + self._puk_entry.connect('notify::is-valid', + self.__notify_is_valid_cb) + self._group.add_widget(self._puk_entry.label) + self.pack_start(self._puk_entry, expand=False) + self._puk_entry.show() + + self.setup() + + def setup(self): + self._username_entry.set_text_from_model() + self._password_entry.set_text_from_model() + self._number_entry.set_text_from_model() + self._apn_entry.set_text_from_model() + self._pin_entry.set_text_from_model() + self._puk_entry.set_text_from_model() + + self.needs_restart = False + + def undo(self): + self._model.undo() + + def _validate(self): + if self._username_entry.is_valid and \ + self._password_entry.is_valid and \ + self._number_entry.is_valid and \ + self._apn_entry.is_valid and \ + self._pin_entry.is_valid and \ + self._puk_entry.is_valid: + self.props.is_valid = True + else: + self.props.is_valid = False + + def __notify_is_valid_cb(self, entry, pspec): + if entry.is_valid: + self.needs_restart = True + self._validate() + diff --git a/extensions/cpsection/network/model.py b/extensions/cpsection/network/model.py index 87db6d9..945254a 100644 --- a/extensions/cpsection/network/model.py +++ b/extensions/cpsection/network/model.py @@ -15,9 +15,14 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # +import logging import dbus from gettext import gettext as _ +from jarabe.model import network import gconf +import os + +_logger = logging.getLogger('ControlPanel - Network') _NM_SERVICE = 'org.freedesktop.NetworkManager' _NM_PATH = '/org/freedesktop/NetworkManager' @@ -62,50 +67,107 @@ def _restart_jabber(): _PS_INTERFACE) except dbus.DBusException: raise ReadError('%s service not available' % _PS_SERVICE) - ps.RestartServerConnection() + ps.RetryConnections() -def get_radio(): +def print_radio(): + print ('off', 'on')[get_radio()] + +def get_radio_nm(): + """ Get the state of NetworkManager + The user can enable/disable wireless and/or networking + return true only if wireless and network are enabled + """ bus = dbus.SystemBus() try: obj = bus.get_object(_NM_SERVICE, _NM_PATH) - nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') + nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) except dbus.DBusException: raise ReadError('%s service not available' % _NM_SERVICE) - state = nm_props.Get(_NM_IFACE, 'WirelessEnabled') - if state in (0, 1): - return state + state = nm_props.Get(_NM_IFACE, 'NetworkingEnabled') + wireless_state = nm_props.Get(_NM_IFACE, 'WirelessEnabled') + _logger.debug('nm state: %s' % state) + _logger.debug('nm wireless_state: %s' % wireless_state) + if state in (0, 1) and wireless_state in (0, 1): + return (state == 1) and (wireless_state == 1) else: raise ReadError(_('State is unknown.')) -def print_radio(): - print ('off', 'on')[get_radio()] - -def set_radio(state): +def set_radio_nm(state): + """Enable/disable NetworkManager + state : 'on/off' + """ + if not state in ('on', 1, 'off', 0): + raise ValueError(_("Error in specified radio argument use on/off.")) + + bus = dbus.SystemBus() + try: + obj = bus.get_object(_NM_SERVICE, _NM_PATH) + nm_props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) + nm = dbus.Interface(obj, _NM_IFACE) + except dbus.DBusException: + raise ReadError('%s service not available' % _NM_SERVICE) + + if state == 'on' or state == 1: + new_state = True + else: + new_state = False + + prev_state = nm_props.Get(_NM_IFACE, 'NetworkingEnabled') + if prev_state != new_state: + nm.Enable(new_state) + nm_props.Set(_NM_IFACE, 'WirelessEnabled', new_state) + + return 0 + +def get_radio_rfkill(): + pipe_stdout = os.popen('/sbin/rfkill list wifi', 'r') + try: + output = pipe_stdout.read() + _logger.debug('rfkill said: %s' % output) + blocked = " blocked: yes" in output + # if not soft- or hard-blocked, radio is on + return not blocked + + finally: + pipe_stdout.close() + +RFKILL_STATE_FILE = '/home/olpc/.rfkill_block_wifi' + +def set_radio_rfkill(state): """Turn Radio 'on' or 'off' state : 'on/off' - """ + """ if state == 'on' or state == 1: - bus = dbus.SystemBus() + os.spawnl(os.P_WAIT, "/sbin/rfkill", "rfkill", "unblock", "wifi") + # remove the flag file (checked at boot) try: - obj = bus.get_object(_NM_SERVICE, _NM_PATH) - nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') - except dbus.DBusException: - raise ReadError('%s service not available' % _NM_SERVICE) - nm_props.Set(_NM_IFACE, 'WirelessEnabled', True) + os.unlink(RFKILL_STATE_FILE) + except: + _logger.debug('File %s was not unlinked' % RFKILL_STATE_FILE) elif state == 'off' or state == 0: - bus = dbus.SystemBus() + os.spawnl(os.P_WAIT, "/sbin/rfkill", "rfkill", "block", "wifi") + # touch the flag file try: - obj = bus.get_object(_NM_SERVICE, _NM_PATH) - nm_props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') - except dbus.DBusException: - raise ReadError('%s service not available' % _NM_SERVICE) - nm_props.Set(_NM_IFACE, 'WirelessEnabled', False) + fd = open(RFKILL_STATE_FILE, 'w') + except IOError: + _logger.debug('File %s is not writeable' % RFKILL_STATE_FILE) + else: + fd.close() else: raise ValueError(_("Error in specified radio argument use on/off.")) return 0 +def get_radio(): + """Get status from rfkill and nm""" + return get_radio_rfkill() and get_radio_nm() + +def set_radio(state): + """ Set status to dot-file and rfkill, and nm""" + set_radio_rfkill(state) + set_radio_nm(state) + def clear_registration(): """Clear the registration with the schoolserver """ @@ -116,13 +178,16 @@ def clear_registration(): def clear_networks(): """Clear saved passwords and network configurations. """ - pass + network.clear_connections() + +def count_networks(): + return network.count_connections() def get_publish_information(): client = gconf.client_get_default() publish = client.get_bool('/desktop/sugar/collaboration/publish_gadget') return publish - + def print_publish_information(): print get_publish_information() diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py index ef28f00..c387667 100644 --- a/extensions/cpsection/network/view.py +++ b/extensions/cpsection/network/view.py @@ -101,6 +101,8 @@ class Network(SectionView): self._clear_history_button = gtk.Button() self._clear_history_button.set_label(_('Discard network history')) box_clear_history.pack_start(self._clear_history_button, expand=False) + if self._model.count_networks() == 0: + self._clear_history_button.set_sensitive(False) self._clear_history_button.show() box_wireless.pack_start(box_clear_history, expand=False) box_clear_history.show() @@ -208,7 +210,9 @@ class Network(SectionView): self._radio_alert.props.msg = detail self._radio_valid = False else: - self._radio_valid = True + self._radio_valid = True + if self._model.count_networks() != 0: + self._clear_history_button.set_sensitive(True) self._validate() return False @@ -239,3 +243,5 @@ class Network(SectionView): def __network_configuration_reset_cb(self, widget): self._model.clear_networks() + if self._model.count_networks() == 0: + self._clear_history_button.set_sensitive(False) diff --git a/extensions/cpsection/power/model.py b/extensions/cpsection/power/model.py index 33ec905..c580439 100644 --- a/extensions/cpsection/power/model.py +++ b/extensions/cpsection/power/model.py @@ -66,7 +66,10 @@ def set_automatic_pm(enabled): else: fd.close() else: - os.unlink(POWERD_INHIBIT_FLAG) + try: + os.unlink(POWERD_INHIBIT_FLAG) + except: + _logger.debug('File %s was not unlinked' % POWERD_INHIBIT_FLAG) return 0 # ohmd @@ -87,29 +90,3 @@ def set_automatic_pm(enabled): client.set_bool('/desktop/sugar/power/automatic', enabled) return 0 -def get_extreme_pm(): - client = gconf.client_get_default() - return client.get_bool('/desktop/sugar/power/extreme') - -def print_extreme_pm(): - print ('off', 'on')[get_extreme_pm()] - -def set_extreme_pm(enabled): - """Extreme power management on/off.""" - - bus = dbus.SystemBus() - proxy = bus.get_object(OHM_SERVICE_NAME, OHM_SERVICE_PATH) - keystore = dbus.Interface(proxy, OHM_SERVICE_IFACE) - - if enabled == 'on' or enabled == 1: - keystore.SetKey("suspend.extreme_pm", 1) - enabled = True - elif enabled == 'off' or enabled == 0: - keystore.SetKey("suspend.extreme_pm", 0) - enabled = False - else: - raise ValueError(_("Error in extreme pm argument, use on/off.")) - - client = gconf.client_get_default() - client.set_bool('/desktop/sugar/power/extreme', enabled) - return 0 diff --git a/extensions/cpsection/power/view.py b/extensions/cpsection/power/view.py index 8f1ed56..d6e2b8c 100644 --- a/extensions/cpsection/power/view.py +++ b/extensions/cpsection/power/view.py @@ -29,8 +29,6 @@ class Power(SectionView): self._model = model self.restart_alerts = alerts self._automatic_pm_valid = True - self._extreme_pm_valid = True - self._extreme_pm_change_handler = None self._automatic_pm_change_handler = None self.set_border_width(style.DEFAULT_SPACING * 2) @@ -38,7 +36,6 @@ class Power(SectionView): group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) self._automatic_pm_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) - self._extreme_pm_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) separator_pm = gtk.HSeparator() self.pack_start(separator_pm, expand=False) @@ -80,35 +77,6 @@ class Power(SectionView): self._automatic_pm_alert.props.msg = self.restart_msg self._automatic_pm_alert.show() - box_extreme_pm = gtk.HBox(spacing=style.DEFAULT_SPACING) - label_extreme_pm = gtk.Label( - _('Extreme power management (disables' \ - 'wireless radio, increases battery life)')) - label_extreme_pm.set_alignment(0, 0.5) - self._extreme_button = gtk.CheckButton() - self._extreme_button.set_alignment(0, 0) - box_extreme_pm.pack_start(self._extreme_button, expand=False) - self._extreme_button.show() - box_extreme_pm.pack_start(label_extreme_pm, expand=False) - group.add_widget(label_extreme_pm) - label_extreme_pm.show() - box_pm.pack_start(box_extreme_pm, expand=False) - box_extreme_pm.show() - - self._extreme_pm_alert = InlineAlert() - label_extreme_pm_error = gtk.Label() - group.add_widget(label_extreme_pm_error) - self._extreme_pm_alert_box.pack_start(label_extreme_pm_error, - expand=False) - label_extreme_pm_error.show() - self._extreme_pm_alert_box.pack_start(self._extreme_pm_alert, - expand=False) - box_pm.pack_end(self._extreme_pm_alert_box, expand=False) - self._extreme_pm_alert_box.show() - if 'extreme_pm' in self.restart_alerts: - self._extreme_pm_alert.props.msg = self.restart_msg - self._extreme_pm_alert.show() - self.pack_start(box_pm, expand=False) box_pm.show() @@ -117,38 +85,26 @@ class Power(SectionView): def setup(self): try: automatic_state = self._model.get_automatic_pm() - extreme_state = self._model.get_extreme_pm() except Exception, detail: self._automatic_pm_alert.props.msg = detail self._automatic_pm_alert.show() - self._extreme_pm_alert.props.msg = detail - self._extreme_pm_alert.show() else: self._automatic_button.set_active(automatic_state) - self._extreme_button.set_active(extreme_state) - self._extreme_pm_valid = True self._automatic_pm_valid = True self.needs_restart = False self._automatic_pm_change_handler = self._automatic_button.connect( \ 'toggled', self.__automatic_pm_toggled_cb) - self._extreme_pm_change_handler = self._extreme_button.connect( \ - 'toggled', self.__extreme_pm_toggled_cb) def undo(self): self._automatic_button.disconnect(self._automatic_pm_change_handler) - self._extreme_button.disconnect(self._extreme_pm_change_handler) self._model.undo() - self._extreme_pm_alert.hide() self._automatic_pm_alert.hide() def _validate(self): - if self._extreme_pm_valid and self._automatic_pm_valid: - self.props.is_valid = True - else: - self.props.is_valid = False + self.props.is_valid = self._automatic_pm_valid def __automatic_pm_toggled_cb(self, widget, data=None): state = widget.get_active() @@ -163,15 +119,3 @@ class Power(SectionView): self._validate() return False - def __extreme_pm_toggled_cb(self, widget, data=None): - state = widget.get_active() - try: - self._model.set_extreme_pm(state) - except Exception, detail: - print detail - self._extreme_pm_alert.props.msg = detail - else: - self._extreme_pm_valid = True - - self._validate() - return False diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py index dc14f9c..12ea9f6 100644 --- a/extensions/deviceicon/network.py +++ b/extensions/deviceicon/network.py @@ -1,6 +1,7 @@ # -# Copyright (C) 2008 One Laptop Per Child +# Copyright (C) 2008-2010 One Laptop Per Child # Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer +# Copyright (C) 2009 Paraguay Educa, Martin Abente # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -22,7 +23,8 @@ import sha import socket import struct import re - +import datetime +import time import gtk import gobject import gconf @@ -35,6 +37,7 @@ from sugar.graphics.toolbutton import ToolButton from sugar.graphics.tray import TrayIcon from sugar.graphics import xocolor from sugar.util import unique_id +from sugar import profile from jarabe.model import network from jarabe.model.network import Settings @@ -50,35 +53,23 @@ _NM_PATH = '/org/freedesktop/NetworkManager' _NM_DEVICE_IFACE = 'org.freedesktop.NetworkManager.Device' _NM_WIRED_IFACE = 'org.freedesktop.NetworkManager.Device.Wired' _NM_WIRELESS_IFACE = 'org.freedesktop.NetworkManager.Device.Wireless' +_NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh' +_NM_SERIAL_IFACE = 'org.freedesktop.NetworkManager.Device.Serial' _NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint' _NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active' -_NM_DEVICE_STATE_UNKNOWN = 0 -_NM_DEVICE_STATE_UNMANAGED = 1 -_NM_DEVICE_STATE_UNAVAILABLE = 2 -_NM_DEVICE_STATE_DISCONNECTED = 3 -_NM_DEVICE_STATE_PREPARE = 4 -_NM_DEVICE_STATE_CONFIG = 5 -_NM_DEVICE_STATE_NEED_AUTH = 6 -_NM_DEVICE_STATE_IP_CONFIG = 7 -_NM_DEVICE_STATE_ACTIVATED = 8 -_NM_DEVICE_STATE_FAILED = 9 - -def frequency_to_channel(frequency): - ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4, - 2432: 5, 2437: 6, 2442: 7, 2447: 8, - 2452: 9, 2457: 10, 2462: 11, 2467: 12, - 2472: 13} - return ftoc[frequency] +_GSM_STATE_NOT_READY = 0 +_GSM_STATE_DISCONNECTED = 1 +_GSM_STATE_CONNECTING = 2 +_GSM_STATE_CONNECTED = 3 +_GSM_STATE_NEED_AUTH = 4 class WirelessPalette(Palette): __gtype_name__ = 'SugarWirelessPalette' __gsignals__ = { 'deactivate-connection' : (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ([])), - 'create-connection' : (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ([])), + gobject.TYPE_NONE, ([])) } def __init__(self, primary_text): @@ -112,21 +103,23 @@ class WirelessPalette(Palette): self._disconnect_item.connect('activate', self.__disconnect_activate_cb) self.menu.append(self._disconnect_item) - self._adhoc_item = gtk.MenuItem(_('Create new wireless network')) - self._adhoc_item.connect('activate', self.__adhoc_activate_cb) - self.menu.append(self._adhoc_item) - self._adhoc_item.show() - def set_connecting(self): self.props.secondary_text = _('Connecting...') - def set_connected(self, frequency, iaddress): + def _set_connected(self, iaddress): self.set_content(self._info) self.props.secondary_text = _('Connected') - self._set_channel(frequency) self._set_ip_address(iaddress) self._disconnect_item.show() + def set_connected_with_frequency(self, frequency, iaddress): + self._set_connected(iaddress) + self._set_frequency(frequency) + + def set_connected_with_channel(self, channel, iaddress): + self._set_connected(iaddress) + self._set_channel(channel) + def set_disconnected(self): self.props.primary_text = '' self.props.secondary_text = '' @@ -136,14 +129,14 @@ class WirelessPalette(Palette): def __disconnect_activate_cb(self, menuitem): self.emit('deactivate-connection') - def __adhoc_activate_cb(self, menuitem): - self.emit('create-connection') - - def _set_channel(self, frequency): + def _set_frequency(self, frequency): try: - channel = frequency_to_channel(frequency) + channel = network.frequency_to_channel(frequency) except KeyError: channel = 0 + self._set_channel(channel) + + def _set_channel(self, channel): self._channel_label.set_text("%s: %d" % (_("Channel"), channel)) def _set_ip_address(self, ip_address): @@ -202,10 +195,105 @@ class WiredPalette(Palette): ip_address_text = "" self._ip_address_label.set_text(ip_address_text) +class GsmPalette(Palette): + __gtype_name__ = 'SugarGsmPalette' + + __gsignals__ = { + 'gsm-connect' : (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([])), + 'gsm-disconnect' : (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([])), + } + + def __init__(self): + Palette.__init__(self, label=_('Wireless modem')) + + self._current_state = None + + self._toggle_state_item = gtk.MenuItem('') + self._toggle_state_item.connect('activate', self.__toggle_state_cb) + self.menu.append(self._toggle_state_item) + self._toggle_state_item.show() + + self.set_gsm_state(_GSM_STATE_NOT_READY) + + self.info_box = gtk.VBox() + + self.data_label = gtk.Label() + self.data_label.props.xalign = 0.0 + label_alignment = self._add_widget_with_padding(self.data_label) + self.info_box.pack_start(label_alignment) + self.data_label.show() + label_alignment.show() + + self.connection_time_label = gtk.Label() + self.connection_time_label.props.xalign = 0.0 + label_alignment = self._add_widget_with_padding( \ + self.connection_time_label) + self.info_box.pack_start(label_alignment) + self.connection_time_label.show() + label_alignment.show() + + self.info_box.show() + self.set_content(self.info_box) + + def _add_widget_with_padding(self, child, xalign=0, yalign=0.5): + alignment = gtk.Alignment(xalign=xalign, yalign=yalign, + xscale=1, yscale=0.33) + alignment.set_padding(style.DEFAULT_SPACING, + style.DEFAULT_SPACING, + style.DEFAULT_SPACING, + style.DEFAULT_SPACING) + alignment.add(child) + return alignment + + def set_gsm_state(self, state): + self._current_state = state + self._update_label_and_text() + + def _update_label_and_text(self): + if self._current_state == _GSM_STATE_NOT_READY: + self._toggle_state_item.get_child().set_label('...') + self.props.secondary_text = _('Please wait...') + + elif self._current_state == _GSM_STATE_DISCONNECTED: + self._toggle_state_item.get_child().set_label(_('Connect')) + self.props.secondary_text = _('Disconnected') + + elif self._current_state == _GSM_STATE_CONNECTING: + self._toggle_state_item.get_child().set_label(_('Cancel')) + self.props.secondary_text = _('Connecting...') + + elif self._current_state == _GSM_STATE_CONNECTED: + self._toggle_state_item.get_child().set_label(_('Disconnect')) + self.props.secondary_text = _('Connected') + + elif self._current_state == _GSM_STATE_NEED_AUTH: + self._toggle_state_item.get_child().set_label(_('Sim requires Pin/Puk')) + self.props.secondary_text = _('Authentication Error') + + else: + raise ValueError('Invalid GSM state while updating label and ' \ + 'text, %s' % str(self._current_state)) + + def __toggle_state_cb(self, menuitem): + if self._current_state == _GSM_STATE_NOT_READY: + pass + elif self._current_state == _GSM_STATE_DISCONNECTED: + self.emit('gsm-connect') + elif self._current_state == _GSM_STATE_CONNECTING: + self.emit('gsm-disconnect') + elif self._current_state == _GSM_STATE_CONNECTED: + self.emit('gsm-disconnect') + elif self._current_state == _GSM_STATE_NEED_AUTH: + self.emit('gsm-disconnect') + else: + raise ValueError('Invalid GSM state while emitting signal, %s' % \ + str(self._current_state)) + class WirelessDeviceView(ToolButton): - _ICON_NAME = 'network-wireless' FRAME_POSITION_RELATIVE = 302 def __init__(self, device): @@ -224,7 +312,7 @@ class WirelessDeviceView(ToolButton): self._active_ap_op = None self._icon = PulsingIcon() - self._icon.props.icon_name = get_icon_state(self._ICON_NAME, 0) + self._icon.props.icon_name = get_icon_state('network-wireless', 0) self._inactive_color = xocolor.XoColor( \ "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(), style.COLOR_TRANSPARENT.get_svg())) @@ -238,13 +326,10 @@ class WirelessDeviceView(ToolButton): self._palette = WirelessPalette(self._name) self._palette.connect('deactivate-connection', self.__deactivate_connection_cb) - self._palette.connect('create-connection', - self.__create_connection_cb) self.set_palette(self._palette) self._palette.set_group_id('frame') - self._device_props = dbus.Interface(self._device, - 'org.freedesktop.DBus.Properties') + self._device_props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) self._device_props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, reply_handler=self.__get_device_props_reply_cb, error_handler=self.__get_device_props_error_cb) @@ -285,7 +370,7 @@ class WirelessDeviceView(ToolButton): return self._active_ap_op = active_ap_op active_ap = self._bus.get_object(_NM_SERVICE, active_ap_op) - props = dbus.Interface(active_ap, 'org.freedesktop.DBus.Properties') + props = dbus.Interface(active_ap, dbus.PROPERTIES_IFACE) props.GetAll(_NM_ACCESSPOINT_IFACE, byte_arrays=True, reply_handler=self.__get_all_ap_props_reply_cb, @@ -309,11 +394,6 @@ class WirelessDeviceView(ToolButton): def __ap_properties_changed_cb(self, properties): self._update_properties(properties) - def _name_encodes_colors(self): - """Match #XXXXXX,#YYYYYY at the end of the network name""" - return self._name[-7] == '#' and self._name[-8] == ',' \ - and self._name[-15] == '#' - def _update_properties(self, properties): if 'Mode' in properties: self._mode = properties['Mode'] @@ -329,11 +409,9 @@ class WirelessDeviceView(ToolButton): self._frequency = properties['Frequency'] if self._color == None: - if self._mode == network.NM_802_11_MODE_ADHOC \ - and self._name_encodes_colors(): - encoded_color = self._name.split("#", 1) - if len(encoded_color) == 2: - self._color = xocolor.XoColor('#' + encoded_color[1]) + if self._mode == network.NM_802_11_MODE_ADHOC and \ + self._name.startswith('Ad-hoc Network'): + self._color = profile.get_color() else: sh = sha.new() data = self._name + hex(self._flags) @@ -369,14 +447,27 @@ class WirelessDeviceView(ToolButton): else: state = network.DEVICE_STATE_UNKNOWN - if state == network.DEVICE_STATE_ACTIVATED: - icon_name = '%s-connected' % self._ICON_NAME - else: - icon_name = self._ICON_NAME + if self._mode != network.NM_802_11_MODE_ADHOC and \ + self._name.startswith('Ad-hoc Network') == False: + if state == network.DEVICE_STATE_ACTIVATED: + icon_name = '%s-connected' % 'network-wireless' + else: + icon_name = 'network-wireless' - icon_name = get_icon_state(icon_name, self._strength) - if icon_name: - self._icon.props.icon_name = icon_name + icon_name = get_icon_state(icon_name, self._strength) + if icon_name: + self._icon.props.icon_name = icon_name + else: + try: + channel = network.frequency_to_channel(self._frequency) + except KeyError: + channel = 1 + 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 \ @@ -386,7 +477,8 @@ class WirelessDeviceView(ToolButton): self._icon.props.pulsing = True elif state == network.DEVICE_STATE_ACTIVATED: address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address') - self._palette.set_connected(self._frequency, address) + self._palette.set_connected_with_frequency(self._frequency, + address) self._icon.props.pulsing = False else: self._icon.props.badge_name = None @@ -399,75 +491,146 @@ class WirelessDeviceView(ToolButton): self._icon.props.base_color = self._color def __deactivate_connection_cb(self, palette, data=None): + connection = network.find_connection_by_ssid(self._name) + if connection: + if self._mode == network.NM_802_11_MODE_INFRA: + connection.set_disconnected() + if self._active_ap_op is not None: obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) netmgr = dbus.Interface(obj, _NM_IFACE) - netmgr_props = dbus.Interface( - netmgr, 'org.freedesktop.DBus.Properties') + netmgr_props = dbus.Interface(netmgr, dbus.PROPERTIES_IFACE) active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections') for conn_o in active_connections_o: obj = self._bus.get_object(_NM_IFACE, conn_o) - props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') + props = dbus.Interface(obj, dbus.PROPERTIES_IFACE) ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') if ap_op == self._active_ap_op: netmgr.DeactivateConnection(conn_o) break - def __create_connection_cb(self, palette, data=None): - """Create an 802.11 IBSS network. - - The user's color is encoded at the end of the network name. The network - name is truncated so that it does not exceed the 32 byte SSID limit. - """ - client = gconf.client_get_default() - nick = client.get_string('/desktop/sugar/user/nick').decode('utf-8') - color = client.get_string('/desktop/sugar/user/color') - color_suffix = ' %s' % color - - format = _('%s\'s network').encode('utf-8') - extra_length = (len(format) - len('%s')) + len(color_suffix) - name_limit = 32 - extra_length - - # truncate the nick and use a regex to drop any partial characters - # at the end - nick = nick.encode('utf-8')[:name_limit] - nick = re.sub("([\xf6-\xf7][\x80-\xbf]{0,2}|[\xe0-\xef][\x80-\xbf]{0,1}|[\xc0-\xdf])$", '', nick) - - connection_name = format % nick - connection_name += color_suffix - - connection = network.find_connection(connection_name) - if connection is None: - settings = Settings() - settings.connection.id = 'Auto ' + connection_name - settings.connection.uuid = unique_id() - settings.connection.type = '802-11-wireless' - settings.wireless.ssid = dbus.ByteArray(connection_name) - settings.wireless.band = 'bg' - settings.wireless.mode = 'adhoc' - settings.ip4_config = IP4Config() - settings.ip4_config.method = 'link-local' - - connection = network.add_connection(connection_name, settings) - - obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) - netmgr = dbus.Interface(obj, _NM_IFACE) - - netmgr.ActivateConnection(network.SETTINGS_SERVICE, - connection.path, - self._device.object_path, - '/', - reply_handler=self.__activate_reply_cb, - error_handler=self.__activate_error_cb) - def __activate_reply_cb(self, connection): logging.debug('Network created: %s', connection) def __activate_error_cb(self, err): logging.debug('Failed to create network: %s', err) +class OlpcMeshDeviceView(ToolButton): + _ICON_NAME = 'network-mesh' + FRAME_POSITION_RELATIVE = 302 + + def __init__(self, device, state): + ToolButton.__init__(self) + + self._bus = dbus.SystemBus() + self._device = device + self._device_props = None + self._device_state = None + self._channel = 0 + + self._icon = PulsingIcon(icon_name=self._ICON_NAME) + self._inactive_color = xocolor.XoColor( \ + "%s,%s" % (style.COLOR_BUTTON_GREY.get_svg(), + style.COLOR_TRANSPARENT.get_svg())) + self._icon.props.pulse_color = profile.get_color() + self._icon.props.base_color = self._inactive_color + + self.set_icon_widget(self._icon) + self._icon.show() + + self.set_palette_invoker(FrameWidgetInvoker(self)) + self._palette = WirelessPalette(_("Mesh Network")) + self._palette.connect('deactivate-connection', + self.__deactivate_connection) + self.set_palette(self._palette) + self._palette.set_group_id('frame') + + self.update_state(state) + + self._device_props = dbus.Interface(self._device, + 'org.freedesktop.DBus.Properties') + self._device_props.Get(_NM_OLPC_MESH_IFACE, 'ActiveChannel', + reply_handler=self.__get_active_channel_reply_cb, + error_handler=self.__get_active_channel_error_cb) + + self._bus.add_signal_receiver(self.__wireless_properties_changed_cb, + signal_name='PropertiesChanged', + path=device.object_path, + dbus_interface=_NM_OLPC_MESH_IFACE) + + def disconnect(self): + self._bus.remove_signal_receiver(self.__wireless_properties_changed_cb, + signal_name='PropertiesChanged', + path=self._device.object_path, + dbus_interface=_NM_OLPC_MESH_IFACE) + + def __get_active_channel_reply_cb(self, channel): + self._channel = channel + self._update_text() + + def __get_active_channel_error_cb(self, err): + logging.error('Error getting the active channel: %s', err) + + def __state_changed_cb(self, new_state, old_state, reason): + self._device_state = new_state + self._update() + + def __wireless_properties_changed_cb(self, properties): + if 'ActiveChannel' in properties: + self._channel = properties['ActiveChannel'] + self._update_text() + + def _update_text(self): + text = _("Mesh Network") + " " + str(self._channel) + self._palette.props.primary_text = text + + def _update(self): + state = self._device_state + + if state in [network.DEVICE_STATE_PREPARE, + network.DEVICE_STATE_CONFIG, + network.DEVICE_STATE_NEED_AUTH, + network.DEVICE_STATE_IP_CONFIG]: + self._icon.props.base_color = self._inactive_color + self._icon.props.pulse_color = profile.get_color() + self._palette.set_connecting() + self._icon.props.pulsing = True + elif state == network.DEVICE_STATE_ACTIVATED: + address = self._device_props.Get(_NM_DEVICE_IFACE, 'Ip4Address') + self._palette.set_connected_with_channel(self._channel, address) + self._icon.props.base_color = profile.get_color() + self._icon.props.pulsing = False + self._update_text() + + def update_state(self, state): + self._device_state = state + self._update() + + def __deactivate_connection(self, palette, data=None): + obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) + netmgr = dbus.Interface(obj, _NM_IFACE) + netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties') + active_connections_o = netmgr_props.Get(_NM_IFACE, + 'ActiveConnections') + + for conn_o in active_connections_o: + # The connection path for a mesh connection is the device itself. + obj = self._bus.get_object(_NM_IFACE, conn_o) + props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') + ap_op = props.Get(_NM_ACTIVE_CONN_IFACE, 'SpecificObject') + + try: + obj = self._bus.get_object(_NM_IFACE, ap_op) + props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') + type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') + if type == network.DEVICE_TYPE_802_11_OLPC_MESH: + netmgr.DeactivateConnection(conn_o) + break + except dbus.exceptions.DBusException: + pass + class WiredDeviceView(TrayIcon): _ICON_NAME = 'network-wired' @@ -486,12 +649,172 @@ class WiredDeviceView(TrayIcon): self._palette.set_connected(speed, address) +class GsmDeviceView(TrayIcon): + + _ICON_NAME = 'network-gsm' + FRAME_POSITION_RELATIVE = 303 + + def __init__(self, device): + self._connection_time_handler = None + self._connection_timestamp = 0 + + client = gconf.client_get_default() + color = xocolor.XoColor(client.get_string('/desktop/sugar/user/color')) + + TrayIcon.__init__(self, icon_name=self._ICON_NAME, xo_color=color) + + self._bus = dbus.SystemBus() + self._device = device + + self.set_palette_invoker(FrameWidgetInvoker(self)) + self._palette = self._create_gsm_palette() + self.set_palette(self._palette) + + self._bus.add_signal_receiver(self.__state_changed_cb, + signal_name='StateChanged', + path=self._device.object_path, + dbus_interface=_NM_DEVICE_IFACE) + self._bus.add_signal_receiver(self.__ppp_stats_changed_cb, + signal_name='PppStats', + path=self._device.object_path, + dbus_interface=_NM_SERIAL_IFACE) + + def _create_gsm_palette(self): + palette = GsmPalette() + + palette.set_group_id('frame') + palette.connect('gsm-connect', self.__gsm_connect_cb) + palette.connect('gsm-disconnect', self.__gsm_disconnect_cb) + + props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties') + props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, + reply_handler=self.__current_state_check_cb, + error_handler=self.__current_state_check_error_cb) + + return palette + + def __gsm_connect_cb(self, palette, data=None): + connection = network.find_gsm_connection() + if connection is not None: + obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) + netmgr = dbus.Interface(obj, _NM_IFACE) + netmgr.ActivateConnection(network.SETTINGS_SERVICE, + connection.path, + self._device.object_path, + '/', + reply_handler=self.__connect_cb, + error_handler=self.__connect_error_cb) + + def __connect_cb(self, active_connection): + logging.debug('Connected successfully to gsm device, %s', + active_connection) + + def __connect_error_cb(self, error): + raise RuntimeError('Error when connecting to gsm device, %s' % error) + + def __gsm_disconnect_cb(self, palette, data=None): + obj = self._bus.get_object(_NM_SERVICE, _NM_PATH) + netmgr = dbus.Interface(obj, _NM_IFACE) + netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties') + active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections') + + for conn_o in active_connections_o: + obj = self._bus.get_object(_NM_IFACE, conn_o) + props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties') + devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices') + if self._device.object_path in devices: + netmgr.DeactivateConnection( + conn_o, + reply_handler=self.__disconnect_cb, + error_handler=self.__disconnect_error_cb) + break + + def __disconnect_cb(self): + logging.debug('Disconnected successfully gsm device') + + def __disconnect_error_cb(self, error): + raise RuntimeError('Error when disconnecting gsm device, %s' % error) + + def __state_changed_cb(self, new_state, old_state, reason): + logging.debug('GSM State: %s to %s, reason %s', old_state, new_state, reason) + self._update_state(int(new_state)) + + def __current_state_check_cb(self, properties): + self._update_state(int(properties['State'])) + + def __current_state_check_error_cb(self, error): + raise RuntimeError('Error when checking gsm device state, %s' % error) + + def _update_state(self, state): + gsm_state = None + + if state == network.DEVICE_STATE_ACTIVATED: + gsm_state = _GSM_STATE_CONNECTED + connection = network.find_gsm_connection() + if connection is not None: + connection.set_connected() + self._connection_timestamp = time.time() - \ + connection.get_settings().connection.timestamp + self._connection_time_handler = gobject.timeout_add( \ + 1000, self.__connection_timecount_cb) + self._update_stats(0, 0) + self._update_connection_time() + self._palette.info_box.show() + + if state == network.DEVICE_STATE_DISCONNECTED: + gsm_state = _GSM_STATE_DISCONNECTED + self._connection_timestamp = 0 + if self._connection_time_handler is not None: + gobject.source_remove(self._connection_time_handler) + self._palette.info_box.hide() + + elif state in [network.DEVICE_STATE_UNMANAGED, + network.DEVICE_STATE_UNAVAILABLE, + network.DEVICE_STATE_UNKNOWN]: + gsm_state = _GSM_STATE_NOT_READY + + elif state in [network.DEVICE_STATE_PREPARE, + network.DEVICE_STATE_CONFIG, + network.DEVICE_STATE_IP_CONFIG]: + gsm_state = _GSM_STATE_CONNECTING + + elif state in [network.DEVICE_STATE_NEED_AUTH]: + gsm_state = _GSM_STATE_NEED_AUTH + + if self._palette is not None: + self._palette.set_gsm_state(gsm_state) + + def disconnect(self): + self._bus.remove_signal_receiver(self.__state_changed_cb, + signal_name='StateChanged', + path=self._device.object_path, + dbus_interface=_NM_DEVICE_IFACE) + + def __ppp_stats_changed_cb(self, in_bytes, out_bytes): + self._update_stats(in_bytes, out_bytes) + + def _update_stats(self, in_bytes, out_bytes): + in_kbytes = in_bytes / 1024 + out_kbytes = out_bytes / 1024 + text = _("Data sent %d kb / received %d kb") % (out_kbytes, in_kbytes) + self._palette.data_label.set_text(text) + + def __connection_timecount_cb(self): + self._connection_timestamp = self._connection_timestamp + 1 + self._update_connection_time() + return True + + def _update_connection_time(self): + connection_time = datetime.datetime.fromtimestamp( \ + self._connection_timestamp) + text = _("Connection time ") + connection_time.strftime('%H : %M : %S') + self._palette.connection_time_label.set_text(text) + class WirelessDeviceObserver(object): def __init__(self, device, tray): self._device = device self._device_view = None self._tray = tray - self._device_view = WirelessDeviceView(self._device) self._tray.add_device(self._device_view) @@ -502,6 +825,65 @@ class WirelessDeviceObserver(object): self._device_view = None +class MeshDeviceObserver(object): + def __init__(self, device, tray): + self._bus = dbus.SystemBus() + self._device = device + self._device_view = None + self._tray = tray + + props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) + props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, + reply_handler=self.__get_device_props_reply_cb, + error_handler=self.__get_device_props_error_cb) + + self._bus.add_signal_receiver(self.__state_changed_cb, + signal_name='StateChanged', + path=self._device.object_path, + dbus_interface=_NM_DEVICE_IFACE) + + def _remove_device_view(self): + self._device_view.disconnect() + self._tray.remove_device(self._device_view) + self._device_view = None + + + + def disconnect(self): + if self._device_view is not None: + self._remove_device_view() + + self._bus.remove_signal_receiver(self.__state_changed_cb, + signal_name='StateChanged', + path=self._device.object_path, + dbus_interface=_NM_DEVICE_IFACE) + + def __get_device_props_reply_cb(self, properties): + if 'State' in properties: + self._update_state(properties['State']) + + def __get_device_props_error_cb(self, err): + logging.error('Error getting the device properties: %s', err) + + def __state_changed_cb(self, new_state, old_state, reason): + self._update_state(new_state) + + def _update_state(self, state): + if state in (network.DEVICE_STATE_PREPARE, network.DEVICE_STATE_CONFIG, + network.DEVICE_STATE_NEED_AUTH, + network.DEVICE_STATE_IP_CONFIG, + network.DEVICE_STATE_ACTIVATED): + if self._device_view is not None: + self._device_view.update_state(state) + return + + self._device_view = OlpcMeshDeviceView(self._device, state) + self._tray.add_device(self._device_view) + else: + if self._device_view is not None: + self._remove_device_view() + + class WiredDeviceObserver(object): def __init__(self, device, tray): self._bus = dbus.SystemBus() @@ -510,7 +892,7 @@ class WiredDeviceObserver(object): self._device_view = None self._tray = tray - props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties') + props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True, reply_handler=self.__get_device_props_reply_cb, error_handler=self.__get_device_props_error_cb) @@ -538,8 +920,7 @@ class WiredDeviceObserver(object): def _update_state(self, state): if state == network.DEVICE_STATE_ACTIVATED: - props = dbus.Interface(self._device, - 'org.freedesktop.DBus.Properties') + props = dbus.Interface(self._device, dbus.PROPERTIES_IFACE) address = props.Get(_NM_DEVICE_IFACE, 'Ip4Address') speed = props.Get(_NM_WIRED_IFACE, 'Speed') self._device_view = WiredDeviceView(speed, address) @@ -550,6 +931,19 @@ class WiredDeviceObserver(object): del self._device_view self._device_view = None +class GsmDeviceObserver(object): + def __init__(self, device, tray): + self._device = device + self._device_view = None + self._tray = tray + + self._device_view = GsmDeviceView(device) + self._tray.add_device(self._device_view) + + def disconnect(self): + self._device_view.disconnect() + self._tray.remove_device(self._device_view) + self._device_view = None class NetworkManagerObserver(object): def __init__(self, tray): @@ -584,7 +978,7 @@ class NetworkManagerObserver(object): def _check_device(self, device_op): nm_device = self._bus.get_object(_NM_SERVICE, device_op) - props = dbus.Interface(nm_device, 'org.freedesktop.DBus.Properties') + props = dbus.Interface(nm_device, dbus.PROPERTIES_IFACE) device_type = props.Get(_NM_DEVICE_IFACE, 'DeviceType') if device_type == network.DEVICE_TYPE_802_3_ETHERNET: @@ -593,6 +987,12 @@ class NetworkManagerObserver(object): elif device_type == network.DEVICE_TYPE_802_11_WIRELESS: device = WirelessDeviceObserver(nm_device, self._tray) self._devices[device_op] = device + elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH: + device = MeshDeviceObserver(nm_device, self._tray) + self._devices[device_op] = device + elif device_type == network.DEVICE_TYPE_GSM_MODEM: + device = GsmDeviceObserver(nm_device, self._tray) + self._devices[device_op] = device def __device_added_cb(self, device_op): self._check_device(device_op) |