diff --git a/src/config.py b/src/config.py index 5dcacfb86..fb606d8f2 100644 --- a/src/config.py +++ b/src/config.py @@ -377,7 +377,10 @@ class PreferencesWindow: # use dbus st = gajim.config.get('use_dbus') btn = self.xml.get_widget('enable_dbus_checkbutton') - btn.set_active(st) + if st and self.plugin.remote: + btn.set_active(True) + else: + btn.set_active(False) self.xml.signal_autoconnect(self) @@ -801,7 +804,10 @@ class PreferencesWindow: self.plugin.save_config() if isactive: if self.plugin.remote is None: - self.plugin.enable_dbus() + if not self.plugin.enable_dbus(): + btn = self.xml.get_widget('enable_dbus_checkbutton') + btn.set_sensitive(False) + btn.set_active(False) else: if self.plugin.remote is not None: self.plugin.disable_dbus() diff --git a/src/gajim.py b/src/gajim.py index dc8266bd6..779825117 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -174,7 +174,7 @@ class Interface: #('ROSTER', account, array) self.roster.mklists(data, account) self.roster.draw_roster() - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('Roster', (account, data)) def handle_event_warning(self, unused, data): @@ -210,7 +210,7 @@ class Interface: else: gajim.allow_notifications[account] = False self.roster.on_status_changed(account, status) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('AccountPresence', (status, account)) def handle_event_notify(self, account, array): @@ -310,7 +310,7 @@ class Interface: instance = dialogs.PopupNotificationWindow(self, _('Contact Signed In'), jid, account) self.roster.popup_notification_windows.append(instance) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('ContactPresence', (account, array)) elif old_show > 1 and new_show < 2: @@ -330,7 +330,7 @@ class Interface: instance = dialogs.PopupNotificationWindow(self, _('Contact Signed Out'), jid, account) self.roster.popup_notification_windows.append(instance) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('ContactAbsence', (account, array)) elif self.windows[account]['gc'].has_key(ji): @@ -340,7 +340,7 @@ class Interface: self.windows[account]['gc'][ji].chg_contact_status(ji, resource, array[1], array[2], array[6], array[7], array[8], array[9], array[10], array[11], array[12], account) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('GCPresence', (account, array)) def handle_event_msg(self, account, array): @@ -405,7 +405,7 @@ class Interface: if gajim.config.get_per('soundevents', 'next_message_received', 'enabled') and not first: self.play_sound('next_message_received') - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('NewMessage', (account, array)) if self.windows[account]['chats'].has_key(jid): chat_win = self.windows[account]['chats'][jid] @@ -462,7 +462,7 @@ class Interface: def handle_event_subscribe(self, account, array): #('SUBSCRIBE', account, (jid, text)) dialogs.SubscriptionRequestWindow(self, array[0], array[1], account) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('Subscribe', (account, array)) def handle_event_subscribed(self, account, array): @@ -492,13 +492,13 @@ class Interface: dialogs.InformationDialog(_('Authorization accepted'), _('The contact "%s" has authorized you to see his status.') % jid).get_response() - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('Subscribed', (account, array)) def handle_event_unsubscribed(self, account, jid): dialogs.InformationDialog(_('Contact "%s" removed subscription from you') % jid, _('You will always see him as offline.')).get_response() - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('Unsubscribed', (account, array)) def handle_event_agent_info(self, account, array): @@ -552,7 +552,7 @@ class Interface: if self.windows.has_key('accounts'): self.windows['accounts'].init_accounts() self.roster.draw_roster() - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('NewAccount', (account, array)) def handle_event_quit(self, p1, p2): @@ -582,7 +582,7 @@ class Interface: if self.windows[account]['infos'].has_key(array[0]): self.windows[account]['infos'][array[0]].set_os_info(array[1], \ array[2], array[3]) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('OsInfo', (account, array)) def handle_event_gc_msg(self, account, array): @@ -599,7 +599,7 @@ class Interface: #message from someone self.windows[account]['gc'][jid].print_conversation(array[1], jid, \ jids[1], array[2]) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('GCMessage', (account, array)) def handle_event_gc_subject(self, account, array): @@ -646,7 +646,7 @@ class Interface: if array[4]: user.groups = array[4] self.roster.draw_contact(jid, account) - if self.remote: + if self.remote and self.remote.is_enabled(): self.remote.raise_signal('RosterInfo', (account, array)) def handle_event_bookmarks(self, account, bms): @@ -836,17 +836,33 @@ class Interface: def save_config(self): parser.write() - def enable_dbus(self): + def enable_dbus(self, is_initial = False): if 'remote_control' not in globals(): import remote_control - self.remote = remote_control.Remote(self) + if not hasattr(self, 'remote') or not self.remote: + try: + self.remote = remote_control.Remote(self) + except remote_control.DbusNotSupported, e: + if not is_initial: + dialog = dialogs.ErrorDialog(_("D-Bus is not present on this machine"),_("Please install dbus if you want to use remote control.")).get_response() + self.remote = None + return False + except remote_control.SessionBusNotPresent, e: + if not is_initial: + dialog = dialogs.ErrorDialog(_("Session bus is not started"),_("Your system is running without session bus daemon. \n See: for instructions how to do it.")).get_response() + self.remote = None + return False + else: + # enable the previously disabled object + self.remote.set_enabled(True) + return True def disable_dbus(self): if hasattr(self, 'remote') and self.remote is not None: - pass - # FIXME: A handler is already registered for the path starting with path[0] = "org" - # so we need to unregister it from dbus - self.remote = None + # just tell the remote object to skip remote messages + self.remote.set_enabled(False) + else: + self.remote = None def __init__(self): self.default_values = { @@ -907,7 +923,7 @@ class Interface: self.roster = roster_window.RosterWindow(self) if gajim.config.get('use_dbus'): - self.enable_dbus() + self.enable_dbus(True) else: self.disable_dbus() diff --git a/src/remote_control.py b/src/remote_control.py index 0da981892..83de2d1cd 100644 --- a/src/remote_control.py +++ b/src/remote_control.py @@ -45,15 +45,13 @@ class Remote: def __init__(self, plugin): self.signal_object = None if 'dbus' not in globals(): - print 'DBUS python bindings are missing in this computer.' - print 'DBUS capabilities of Gajim cannot be used' - return None + print 'D-Bus python bindings are missing in this computer.' + print 'D-Bus capabilities of Gajim cannot be used' + raise DbusNotSupported() try: session_bus = dbus.SessionBus() except: - # FIXME: some status why remote is not supported - # When dbus 0.2.x is obsolete - return None + raise SessionBusNotPresent() if _version[1] >= 41: service = dbus.service.BusName(SERVICE, bus=session_bus) @@ -62,19 +60,28 @@ class Remote: service=dbus.Service(SERVICE, session_bus) self.signal_object = SignalObject(service, plugin) + def set_enabled(self, status): + self.signal_object.disabled = not status + + def is_enabled(self): + return not self.signal_object.disabled + def raise_signal(self, signal, arg): if self.signal_object: self.signal_object.raise_signal(signal, repr(arg)) class SignalObject(DbusPrototype): + ''' Local object definition for /org/gajim/dbus/RemoteObject. This doc must + not be visible, because the clients can access only the remote object. ''' _version = getattr(dbus, 'version', (0, 20, 0)) def __init__(self, service, plugin): self.plugin = plugin self.first_show = True self.vcard_account = None - + self.disabled = False + # register our dbus API if _version[1] >= 41: DbusPrototype.__init__(self, service, OBJ_PATH) @@ -92,8 +99,13 @@ class SignalObject(DbusPrototype): self.contact_info ]) + def disconnect(self): + self._connection.disconnect() + def raise_signal(self, signal, arg): ''' raise a signal, with a single string message ''' + if self.disabled : + return if _version[1] >= 30: from dbus import dbus_bindings message = dbus_bindings.Signal(OBJ_PATH, INTERFACE, signal) @@ -112,6 +124,8 @@ class SignalObject(DbusPrototype): ''' send_message(jid, message, keyID=None, account=None) send 'message' to 'jid', using account (optional) 'account'. if keyID is specified, encrypt the message with the pgp key ''' + if self.disabled: + return jid, message, keyID, account = self._get_real_arguments(args, 4) if not jid or not message: return None # or raise error @@ -130,6 +144,8 @@ class SignalObject(DbusPrototype): def new_message(self, *args): ''' new_message(jid, account=None) -> shows the tabbed window for new message to 'jid', using account(optional) 'account ' ''' + if self.disabled: + return jid, account = self._get_real_arguments(args, 2) if not jid: # FIXME: raise exception for missing argument (dbus0.3+) @@ -159,6 +175,8 @@ class SignalObject(DbusPrototype): def change_status(self, *args, **keywords): ''' change_status(status, message, account). account is optional - if not specified status is changed for all accounts. ''' + if self.disabled: + return status, message, account = self._get_real_arguments(args, 3) if status not in ('offline', 'online', 'chat', 'away', 'xa', 'dnd', 'invisible'): @@ -176,6 +194,8 @@ class SignalObject(DbusPrototype): def show_next_unread(self, *args): ''' Show the window(s) with next waiting messages in tabbed/group chats. ''' + if self.disabled: + return #FIXME: when systray is disabled this method does nothing. #FIXME: show message from GC that refer to us (like systray does) if len(self.plugin.systray.jids) != 0: @@ -204,6 +224,8 @@ class SignalObject(DbusPrototype): def contact_info(self, *args): ''' get vcard info for a contact. This method returns nothing. You have to register the 'VcardInfo' signal to get the real vcard. ''' + if self.disabled: + return jid = self._get_real_arguments(args, 1) if not jid: # FIXME: raise exception for missing argument (0.3+) @@ -223,6 +245,8 @@ class SignalObject(DbusPrototype): def list_accounts(self, *args): ''' list register accounts ''' + if self.disabled: + return if gajim.contacts: result = gajim.contacts.keys() if result and len(result) > 0: @@ -231,6 +255,8 @@ class SignalObject(DbusPrototype): def list_contacts(self, *args): + if self.disabled: + return ''' list all contacts in the roster. If the first argument is specified, then return the contacts for the specified account ''' [for_account] = self._get_real_arguments(args, 1) @@ -261,6 +287,8 @@ class SignalObject(DbusPrototype): def toggle_roster_appearance(self, *args): ''' shows/hides the roster window ''' + if self.disabled: + return win = self.plugin.roster.window if win.get_property('visible'): gobject.idle_add(win.hide) @@ -283,6 +311,8 @@ class SignalObject(DbusPrototype): gajim.connections[self.vcard_account].unregister_handler('VCARD', self._receive_vcard) self.unregistered_vcard = None + if self.disabled: + return if _version[1] >=30: self.VcardInfo(repr(array)) else: @@ -337,7 +367,7 @@ class SignalObject(DbusPrototype): if _version[1] >= 30: # prevent using decorators, because they are not supported # on python < 2.4 - # FIXME: use decorators when python2.3 is OOOOOOLD + # FIXME: use decorators when python2.3 (and dbus 0.23) is OOOOOOLD toggle_roster_appearance = method(INTERFACE)(toggle_roster_appearance) list_contacts = method(INTERFACE)(list_contacts) list_accounts = method(INTERFACE)(list_accounts) @@ -347,3 +377,19 @@ class SignalObject(DbusPrototype): contact_info = method(INTERFACE)(contact_info) send_message = method(INTERFACE)(send_message) VcardInfo = signal(INTERFACE)(VcardInfo) + +class SessionBusNotPresent(Exception): + ''' This exception indicates that there is no session daemon ''' + def __init__(self): + Exception.__init__(self) + + def __str__(self): + return _("Session bus is not available") + +class DbusNotSupported(Exception): + ''' D-Bus is not installed or python bindings are missing ''' + def __init__(self): + Exception.__init__(self) + + def __str__(self): + return _("D-Bus is not present on this machine")