diff --git a/js/ui/components/telepathyClient.js b/js/ui/components/telepathyClient.js index 63ca776fa..8c7d92eca 100644 --- a/js/ui/components/telepathyClient.js +++ b/js/ui/components/telepathyClient.js @@ -102,15 +102,6 @@ const TelepathyClient = new Lang.Class({ this._tpClient.set_handle_channels_func( Lang.bind(this, this._handleChannels)); - // Watch subscription requests and connection errors - this._subscriptionSource = null; - this._accountSource = null; - - // Workaround for gjs not supporting GPtrArray in signals. - // See BGO bug #653941 for context. - this._tpClient.set_contact_list_changed_func( - Lang.bind(this, this._contactListChanged)); - // Allow other clients (such as Empathy) to pre-empt our channels if // needed this._tpClient.set_delegated_channels_callback( @@ -124,17 +115,12 @@ const TelepathyClient = new Lang.Class({ throw new Error('Couldn\'t register Telepathy client. Error: \n' + e); } - this._accountManagerValidityChangedId = this._accountManager.connect('account-validity-changed', - Lang.bind(this, this._accountValidityChanged)); - if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core())) this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared)); }, disable: function() { this._tpClient.unregister(); - this._accountManager.disconnect(this._accountManagerValidityChangedId); - this._accountManagerValidityChangedId = 0; }, _observeChannels: function(observer, account, conn, channels, @@ -219,33 +205,6 @@ const TelepathyClient = new Lang.Class({ } }, - _displayRoomInvitation: function(conn, channel, dispatchOp, context) { - // We can only approve the rooms if we have been invited to it - let selfContact = channel.group_get_self_contact(); - if (selfContact == null) { - context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT, - message: 'Not invited to the room' })); - return; - } - - let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact); - if (!invited) { - context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT, - message: 'Not invited to the room' })); - return; - } - - // FIXME: We don't have a 'chat room' icon (bgo #653737) use - // system-users for now as Empathy does. - let source = new ApproverSource(dispatchOp, _("Invitation"), - Gio.icon_new_for_string('system-users')); - Main.messageTray.add(source); - - let notif = new RoomInviteNotification(source, dispatchOp, channel, inviter); - source.notify(notif); - context.accept(); - }, - _approveChannels: function(approver, account, conn, channels, dispatchOp, context) { let channel = channels[0]; @@ -259,10 +218,6 @@ const TelepathyClient = new Lang.Class({ if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT) this._approveTextChannel(account, conn, channel, dispatchOp, context); - else if (chanType == Tp.IFACE_CHANNEL_TYPE_CALL) - this._approveCall(account, conn, channel, dispatchOp, context); - else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER) - this._approveFileTransfer(account, conn, channel, dispatchOp, context); else context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT, message: 'Unsupported channel type' })); @@ -283,45 +238,9 @@ const TelepathyClient = new Lang.Class({ }})); context.accept(); - } else { - this._displayRoomInvitation(conn, channel, dispatchOp, context); } }, - _approveCall: function(account, conn, channel, dispatchOp, context) { - let isVideo = false; - - let props = channel.borrow_immutable_properties(); - - if (props[Tp.PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO]) - isVideo = true; - - // We got the TpContact - let source = new ApproverSource(dispatchOp, _("Call"), isVideo ? - Gio.icon_new_for_string('camera-web') : - Gio.icon_new_for_string('audio-input-microphone')); - Main.messageTray.add(source); - - let notif = new AudioVideoNotification(source, dispatchOp, channel, - channel.get_target_contact(), isVideo); - source.notify(notif); - context.accept(); - }, - - _approveFileTransfer: function(account, conn, channel, dispatchOp, context) { - // Use the icon of the file being transferred - let gicon = Gio.content_type_get_icon(channel.get_mime_type()); - - // We got the TpContact - let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon); - Main.messageTray.add(source); - - let notif = new FileTransferNotification(source, dispatchOp, channel, - channel.get_target_contact()); - source.notify(notif); - context.accept(); - }, - _delegatedChannelsCb: function(client, channels) { // Nothing to do as we don't make a distinction between observed and // handled channels. @@ -329,105 +248,7 @@ const TelepathyClient = new Lang.Class({ _accountManagerPrepared: function(am, result) { am.prepare_finish(result); - - let accounts = am.get_valid_accounts(); - for (let i = 0; i < accounts.length; i++) { - this._accountValidityChanged(am, accounts[i], true); - } }, - - _accountValidityChanged: function(am, account, valid) { - if (!valid) - return; - - // It would be better to connect to "status-changed" but we cannot. - // See discussion in https://bugzilla.gnome.org/show_bug.cgi?id=654159 - account.connect("notify::connection-status", - Lang.bind(this, this._accountConnectionStatusNotifyCb)); - - account.connect('notify::connection', - Lang.bind(this, this._connectionChanged)); - this._connectionChanged(account); - }, - - _connectionChanged: function(account) { - let conn = account.get_connection(); - if (conn == null) - return; - - this._tpClient.grab_contact_list_changed(conn); - if (conn.get_contact_list_state() == Tp.ContactListState.SUCCESS) { - this._contactListChanged(conn, conn.dup_contact_list(), []); - } - }, - - _contactListChanged: function(conn, added, removed) { - for (let i = 0; i < added.length; i++) { - let contact = added[i]; - - contact.connect('subscription-states-changed', - Lang.bind(this, this._subscriptionStateChanged)); - this._subscriptionStateChanged(contact); - } - }, - - _subscriptionStateChanged: function(contact) { - if (contact.get_publish_state() != Tp.SubscriptionState.ASK) - return; - - /* Implicitly accept publish requests if contact is already subscribed */ - if (contact.get_subscribe_state() == Tp.SubscriptionState.YES || - contact.get_subscribe_state() == Tp.SubscriptionState.ASK) { - - contact.authorize_publication_async(function(src, result) { - src.authorize_publication_finish(result)}); - - return; - } - - /* Display notification to ask user to accept/reject request */ - let source = this._ensureAppSource(); - - let notif = new SubscriptionRequestNotification(source, contact); - source.notify(notif); - }, - - _accountConnectionStatusNotifyCb: function(account) { - let connectionError = account.connection_error; - - if (account.connection_status != Tp.ConnectionStatus.DISCONNECTED || - connectionError == Tp.error_get_dbus_name(Tp.Error.CANCELLED)) { - return; - } - - let notif = this._accountNotifications[account.get_object_path()]; - if (notif) - return; - - /* Display notification that account failed to connect */ - let source = this._ensureAppSource(); - - notif = new AccountNotification(source, account, connectionError); - this._accountNotifications[account.get_object_path()] = notif; - notif.connect('destroy', Lang.bind(this, function() { - delete this._accountNotifications[account.get_object_path()]; - })); - source.notify(notif); - }, - - _ensureAppSource: function() { - if (this._appSource == null) { - this._appSource = new MessageTray.Source(_("Chat"), 'empathy'); - this._appSource.policy = new MessageTray.NotificationApplicationPolicy('empathy'); - - Main.messageTray.add(this._appSource); - this._appSource.connect('destroy', Lang.bind(this, function () { - this._appSource = null; - })); - } - - return this._appSource; - } }); const ChatSource = new Lang.Class({ @@ -1105,359 +926,4 @@ const ChatNotification = new Lang.Class({ } }); -const ApproverSource = new Lang.Class({ - Name: 'ApproverSource', - Extends: MessageTray.Source, - - _init: function(dispatchOp, text, gicon) { - this._gicon = gicon; - - this.parent(text); - - this._dispatchOp = dispatchOp; - - // Destroy the source if the channel dispatch operation is invalidated - // as we can't approve any more. - this._invalidId = dispatchOp.connect('invalidated', - Lang.bind(this, function(domain, code, msg) { - this.destroy(); - })); - }, - - _createPolicy: function() { - return new MessageTray.NotificationApplicationPolicy('empathy'); - }, - - destroy: function() { - if (this._invalidId != 0) { - this._dispatchOp.disconnect(this._invalidId); - this._invalidId = 0; - } - - this.parent(); - }, - - getIcon: function() { - return this._gicon; - } -}); - -const RoomInviteNotification = new Lang.Class({ - Name: 'RoomInviteNotification', - Extends: MessageTray.Notification, - - _init: function(source, dispatchOp, channel, inviter) { - this.parent(source, - /* translators: argument is a room name like - * room@jabber.org for example. */ - _("Invitation to %s").format(channel.get_identifier()), - null, - { customContent: true }); - this.setResident(true); - - /* translators: first argument is the name of a contact and the second - * one the name of a room. "Alice is inviting you to join room@jabber.org - * for example. */ - this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier())); - - this.addAction(_("Decline"), Lang.bind(this, function() { - dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) { - src.leave_channels_finish(result); - }); - this.destroy(); - })); - this.addAction(_("Accept"), Lang.bind(this, function() { - dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) { - src.handle_with_time_finish(result); - }); - this.destroy(); - })); - } -}); - -// Audio Video -const AudioVideoNotification = new Lang.Class({ - Name: 'AudioVideoNotification', - Extends: MessageTray.Notification, - - _init: function(source, dispatchOp, channel, contact, isVideo) { - let title = ''; - - if (isVideo) - /* translators: argument is a contact name like Alice for example. */ - title = _("Video call from %s").format(contact.get_alias()); - else - /* translators: argument is a contact name like Alice for example. */ - title = _("Call from %s").format(contact.get_alias()); - - this.parent(source, title, null, { customContent: true }); - this.setResident(true); - - this.setUrgency(MessageTray.Urgency.CRITICAL); - - this.addAction(_("Decline"), Lang.bind(this, function() { - dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) { - src.leave_channels_finish(result); - }); - this.destroy(); - })); - /* translators: this is a button label (verb), not a noun */ - this.addAction(_("Answer"), Lang.bind(this, function() { - dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) { - src.handle_with_time_finish(result); - }); - this.destroy(); - })); - } -}); - -// File Transfer -const FileTransferNotification = new Lang.Class({ - Name: 'FileTransferNotification', - Extends: MessageTray.Notification, - - _init: function(source, dispatchOp, channel, contact) { - this.parent(source, - /* To translators: The first parameter is - * the contact's alias and the second one is the - * file name. The string will be something - * like: "Alice is sending you test.ogg" - */ - _("%s is sending you %s").format(contact.get_alias(), - channel.get_filename()), - null, - { customContent: true }); - this.setResident(true); - - this.addAction(_("Decline"), Lang.bind(this, function() { - dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) { - src.leave_channels_finish(result); - }); - this.destroy(); - })); - this.addAction(_("Accept"), Lang.bind(this, function() { - dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) { - src.handle_with_time_finish(result); - }); - this.destroy(); - })); - } -}); - -// Subscription request -const SubscriptionRequestNotification = new Lang.Class({ - Name: 'SubscriptionRequestNotification', - Extends: MessageTray.Notification, - - _init: function(source, contact) { - this.parent(source, - /* To translators: The parameter is the contact's alias */ - _("%s would like permission to see when you are online").format(contact.get_alias()), - null, { customContent: true }); - - this._contact = contact; - this._connection = contact.get_connection(); - - let layout = new St.BoxLayout({ vertical: false }); - - // Display avatar - let iconBox = new St.Bin({ style_class: 'avatar-box' }); - iconBox._size = 48; - - let textureCache = St.TextureCache.get_default(); - let file = contact.get_avatar_file(); - - if (file) { - let uri = file.get_uri(); - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - iconBox.child = textureCache.load_uri_async(uri, iconBox._size, iconBox._size, scaleFactor); - } - else { - iconBox.child = new St.Icon({ icon_name: 'avatar-default', - icon_size: iconBox._size }); - } - - layout.add(iconBox); - - // subscription request message - let label = new St.Label({ style_class: 'subscription-message', - text: contact.get_publish_request() }); - - layout.add(label); - - this.addActor(layout); - - this.addAction(_("Decline"), Lang.bind(this, function() { - contact.remove_async(function(src, result) { - src.remove_finish(result); - }); - })); - this.addAction(_("Accept"), Lang.bind(this, function() { - // Authorize the contact and request to see his status as well - contact.authorize_publication_async(function(src, result) { - src.authorize_publication_finish(result); - }); - - contact.request_subscription_async('', function(src, result) { - src.request_subscription_finish(result); - }); - })); - - this._changedId = contact.connect('subscription-states-changed', - Lang.bind(this, this._subscriptionStatesChangedCb)); - this._invalidatedId = this._connection.connect('invalidated', - Lang.bind(this, this.destroy)); - }, - - destroy: function() { - if (this._changedId != 0) { - this._contact.disconnect(this._changedId); - this._changedId = 0; - } - - if (this._invalidatedId != 0) { - this._connection.disconnect(this._invalidatedId); - this._invalidatedId = 0; - } - - this.parent(); - }, - - _subscriptionStatesChangedCb: function(contact, subscribe, publish, msg) { - // Destroy the notification if the subscription request has been - // answered - if (publish != Tp.SubscriptionState.ASK) - this.destroy(); - } -}); - -// Messages from empathy/libempathy/empathy-utils.c -// create_errors_to_message_hash() - -/* Translator note: these should be the same messages that are - * used in Empathy, so just copy and paste from there. */ -let _connectionErrorMessages = {}; -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.NETWORK_ERROR)] - = _("Network error"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED)] - = _("Authentication failed"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ENCRYPTION_ERROR)] - = _("Encryption error"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_NOT_PROVIDED)] - = _("Certificate not provided"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_UNTRUSTED)] - = _("Certificate untrusted"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_EXPIRED)] - = _("Certificate expired"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_NOT_ACTIVATED)] - = _("Certificate not activated"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_HOSTNAME_MISMATCH)] - = _("Certificate hostname mismatch"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_FINGERPRINT_MISMATCH)] - = _("Certificate fingerprint mismatch"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_SELF_SIGNED)] - = _("Certificate self-signed"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CANCELLED)] - = _("Status is set to offline"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ENCRYPTION_NOT_AVAILABLE)] - = _("Encryption is not available"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INVALID)] - = _("Certificate is invalid"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REFUSED)] - = _("Connection has been refused"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_FAILED)] - = _("Connection can't be established"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)] - = _("Connection has been lost"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)] - = _("This account is already connected to the server"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)] - = _("Connection has been replaced by a new connection using the same resource"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)] - = _("The account already exists on the server"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.SERVICE_BUSY)] - = _("Server is currently too busy to handle the connection"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_REVOKED)] - = _("Certificate has been revoked"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INSECURE)] - = _("Certificate uses an insecure cipher algorithm or is cryptographically weak"); -_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)] - = _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library"); -_connectionErrorMessages['org.freedesktop.DBus.Error.NoReply'] - = _("Internal error"); - -const AccountNotification = new Lang.Class({ - Name: 'AccountNotification', - Extends: MessageTray.Notification, - - _init: function(source, account, connectionError) { - this.parent(source, - /* translators: argument is the account name, like - * name@jabber.org for example. */ - _("Unable to connect to %s").format(account.get_display_name()), - this._getMessage(connectionError)); - - this._account = account; - - this.addAction(_("View account"), Lang.bind(this, function() { - let cmd = 'empathy-accounts --select-account=' + - account.get_path_suffix(); - let app_info = Gio.app_info_create_from_commandline(cmd, null, 0); - app_info.launch([], global.create_app_launch_context(0, -1)); - })); - - this._enabledId = account.connect('notify::enabled', - Lang.bind(this, function() { - if (!account.is_enabled()) - this.destroy(); - })); - - this._invalidatedId = account.connect('invalidated', - Lang.bind(this, this.destroy)); - - this._connectionStatusId = account.connect('notify::connection-status', - Lang.bind(this, function() { - let status = account.connection_status; - if (status == Tp.ConnectionStatus.CONNECTED) { - this.destroy(); - } else if (status == Tp.ConnectionStatus.DISCONNECTED) { - let connectionError = account.connection_error; - - if (connectionError == Tp.error_get_dbus_name(Tp.Error.CANCELLED)) - this.destroy(); - else - this.update(this.title, this._getMessage(connectionError)); - } - })); - }, - - _getMessage: function(connectionError) { - let message; - if (connectionError in _connectionErrorMessages) { - message = _connectionErrorMessages[connectionError]; - } else { - message = _("Unknown reason"); - } - return message; - }, - - destroy: function() { - if (this._enabledId != 0) { - this._account.disconnect(this._enabledId); - this._enabledId = 0; - } - - if (this._invalidatedId != 0) { - this._account.disconnect(this._invalidatedId); - this._invalidatedId = 0; - } - - if (this._connectionStatusId != 0) { - this._account.disconnect(this._connectionStatusId); - this._connectionStatusId = 0; - } - - this.parent(); - } -}); const Component = TelepathyClient; diff --git a/src/shell-tp-client.c b/src/shell-tp-client.c index 400b8296e..817700e57 100644 --- a/src/shell-tp-client.c +++ b/src/shell-tp-client.c @@ -21,10 +21,6 @@ struct _ShellTpClientPrivate ShellTpClientHandleChannelsImpl handle_channels_impl; gpointer user_data_handle_channels; GDestroyNotify destroy_handle_channels; - - ShellTpClientContactListChangedImpl contact_list_changed_impl; - gpointer user_data_contact_list_changed; - GDestroyNotify destroy_contact_list_changed; }; /** @@ -83,16 +79,6 @@ struct _ShellTpClientPrivate * Signature of the implementation of the HandleChannels method. */ -/** - * ShellTpClientContactListChangedImpl: - * @connection: a #TpConnection having %TP_CONNECTION_FEATURE_CORE prepared - * if possible - * @added: (element-type TelepathyGLib.Contact): a #GPtrArray of added #TpContact - * @removed: (element-type TelepathyGLib.Contact): a #GPtrArray of removed #TpContact - * - * Signature of the implementation of the ContactListChanged method. - */ - static void shell_tp_client_init (ShellTpClient *self) { @@ -226,13 +212,6 @@ shell_tp_client_dispose (GObject *object) self->priv->user_data_handle_channels = NULL; } - if (self->priv->destroy_contact_list_changed != NULL) - { - self->priv->destroy_contact_list_changed (self->priv->user_data_contact_list_changed); - self->priv->destroy_contact_list_changed = NULL; - self->priv->user_data_contact_list_changed = NULL; - } - if (dispose != NULL) dispose (object); } @@ -290,40 +269,3 @@ shell_tp_client_set_handle_channels_func (ShellTpClient *self, self->priv->user_data_handle_channels = user_data; self->priv->destroy_handle_channels = destroy; } - -void -shell_tp_client_set_contact_list_changed_func (ShellTpClient *self, - ShellTpClientContactListChangedImpl contact_list_changed_impl, - gpointer user_data, - GDestroyNotify destroy) -{ - g_assert (self->priv->contact_list_changed_impl == NULL); - - self->priv->contact_list_changed_impl = contact_list_changed_impl; - self->priv->user_data_handle_channels = user_data; - self->priv->destroy_handle_channels = destroy; -} - -static void -on_contact_list_changed (TpConnection *conn, - GPtrArray *added, - GPtrArray *removed, - gpointer user_data) -{ - ShellTpClient *self = (ShellTpClient *) user_data; - - g_assert (self->priv->contact_list_changed_impl != NULL); - - self->priv->contact_list_changed_impl (conn, - added, removed, - self->priv->user_data_contact_list_changed); -} - -void -shell_tp_client_grab_contact_list_changed (ShellTpClient *self, - TpConnection *conn) -{ - g_signal_connect (conn, "contact-list-changed", - G_CALLBACK (on_contact_list_changed), - self); -} diff --git a/src/shell-tp-client.h b/src/shell-tp-client.h index 107bcb46a..15bcf75e7 100644 --- a/src/shell-tp-client.h +++ b/src/shell-tp-client.h @@ -86,19 +86,5 @@ void shell_tp_client_set_handle_channels_func (ShellTpClient *self, gpointer user_data, GDestroyNotify destroy); -typedef void (*ShellTpClientContactListChangedImpl) ( - TpConnection *connection, - GPtrArray *added, - GPtrArray *removed, - gpointer user_data); - -void shell_tp_client_set_contact_list_changed_func (ShellTpClient *self, - ShellTpClientContactListChangedImpl contact_list_changed_impl, - gpointer user_data, - GDestroyNotify destroy); - -void shell_tp_client_grab_contact_list_changed (ShellTpClient *self, - TpConnection *conn); - G_END_DECLS #endif /* __SHELL_TP_CLIENT_H__ */