[gnome-shell] Approve room invitations



commit 998c5f17fc95a77821115bacc75ac344b406377c
Author: Guillaume Desmottes <guillaume desmottes collabora co uk>
Date:   Thu Jun 30 14:05:41 2011 +0200

    Approve room invitations
    
    We use to rely on Empathy for this but as we plan to allow users to be
    connected on IM without having Empathy running the Shell should do it now.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=653740

 js/ui/notificationDaemon.js |    3 +-
 js/ui/telepathyClient.js    |  149 +++++++++++++++++++++++++++++++++++++++---
 src/shell-tp-client.c       |   21 ++++++
 src/shell-tp-client.h       |    3 +
 4 files changed, 164 insertions(+), 12 deletions(-)
---
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index 35eb581..66bd0c5 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -190,9 +190,10 @@ NotificationDaemon.prototype = {
                      actions, hints, timeout) {
         let id;
 
-        // Filter out chat and presence notifications from Empathy, since we
+        // Filter out chat, presence and invitation notifications from Empathy, since we
         // handle that information from telepathyClient.js
         if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
+              hints['category'] == 'x-empathy.im.room-invitation' ||
               hints['category'] == 'presence.online' ||
               hints['category'] == 'presence.offline')) {
             // Ignore replacesId since we already sent back a
diff --git a/js/ui/telepathyClient.js b/js/ui/telepathyClient.js
index d81b40a..8a47601 100644
--- a/js/ui/telepathyClient.js
+++ b/js/ui/telepathyClient.js
@@ -178,21 +178,65 @@ Client.prototype = {
         }
     },
 
-    _approveChannels: function(approver, account, conn, channels,
-                               dispatchOp, context) {
-        // Approve the channels right away as we are going to handle it
-        dispatchOp.claim_with_async(this._tpClient,
-                                    Lang.bind (this, function(dispatchOp, result) {
-            try {
-                dispatchOp.claim_with_finish(result);
-                this._handlingChannels(account, conn, channels);
-            } catch (err) {
-                global.logError('Failed to Claim channel: ' + err);
-            }}));
+    _displayRoomInvitation: function(conn, channel, dispatchOp, context) {
+        // We can only approve the rooms if we have been invited to it
+        let selfHandle = channel.group_get_self_handle();
+        if (selfHandle == 0) {
+            Shell.decline_dispatch_op(context, 'Not invited to the room');
+            return;
+        }
+
+        let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
+        if (!invited) {
+            Shell.decline_dispatch_op(context, 'Not invited to the room');
+            return;
+        }
+
+        // Request a TpContact for the inviter
+        Shell.get_tp_contacts(conn, [inviter],
+                contactFeatures,
+                Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
+
+        context.delay();
+     },
+
+    _createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
+        if (contacts.length < 1) {
+            Shell.decline_dispatch_op(context, 'Failed to get inviter');
+            return;
+        }
 
+        // We got the TpContact
+        let source = new RoomInviteSource(dispatchOp);
+        Main.messageTray.add(source);
+
+        let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
+        source.notify(notif);
         context.accept();
     },
 
+    _approveChannels: function(approver, account, conn, channels,
+                               dispatchOp, context) {
+        let channel = channels[0];
+        let [targetHandle, targetHandleType] = channel.get_handle();
+
+        if (targetHandleType == Tp.HandleType.CONTACT) {
+            // Approve private text channels right away as we are going to handle it
+            dispatchOp.claim_with_async(this._tpClient,
+                                        Lang.bind(this, function(dispatchOp, result) {
+                try {
+                    dispatchOp.claim_with_finish(result);
+                    this._handlingChannels(account, conn, channels);
+                } catch (err) {
+                    throw new Error('Failed to Claim channel: ' + err);
+                }}));
+
+            context.accept();
+        } else {
+            this._displayRoomInvitation(conn, channel, dispatchOp, context);
+        }
+    },
+
     _handleChannels: function(handler, account, conn, channels,
                               requests, user_action_time, context) {
         this._handlingChannels(account, conn, channels);
@@ -684,3 +728,86 @@ ChatNotification.prototype = {
         this.source.respond(text);
     }
 };
+
+function RoomInviteSource(dispatchOp) {
+    this._init(dispatchOp);
+}
+
+RoomInviteSource.prototype = {
+    __proto__: MessageTray.Source.prototype,
+
+    _init: function(dispatchOp) {
+        MessageTray.Source.prototype._init.call(this, _("Invitation"));
+
+        this._setSummaryIcon(this.createNotificationIcon());
+
+        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();
+        }));
+    },
+
+    destroy: function() {
+        if (this._invalidId != 0) {
+            this._dispatchOp.disconnect(this._invalidId);
+            this._invalidId = 0;
+        }
+
+        MessageTray.Source.prototype.destroy.call(this);
+    },
+
+    createNotificationIcon: function() {
+        // FIXME: We don't have a 'chat room' icon (bgo #653737) use
+        // system-users for now as Empathy does.
+        return new St.Icon({ icon_name: 'system-users',
+                             icon_type: St.IconType.FULLCOLOR,
+                             icon_size: this.ICON_SIZE });
+    }
+}
+
+function RoomInviteNotification(source, dispatchOp, channel, inviter) {
+    this._init(source, dispatchOp, channel, inviter);
+}
+
+RoomInviteNotification.prototype = {
+    __proto__: MessageTray.Notification.prototype,
+
+    _init: function(source, dispatchOp, channel, inviter) {
+        MessageTray.Notification.prototype._init.call(this,
+                                                      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.addButton('decline', _("Decline"));
+        this.addButton('accept', _("Accept"));
+
+        this.connect('action-invoked', Lang.bind(this, function(self, action) {
+            switch (action) {
+            case 'decline':
+                dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
+                                                '', function(src, result) {
+                    src.leave_channels_finish(result)});
+                break;
+            case 'accept':
+                dispatchOp.handle_with_time_async('', global.get_current_time(),
+                                                  function(src, result) {
+                    src.handle_with_time_finish(result)});
+                break;
+            }
+            this.destroy();
+        }));
+    }
+};
diff --git a/src/shell-tp-client.c b/src/shell-tp-client.c
index af507bc..018f233 100644
--- a/src/shell-tp-client.c
+++ b/src/shell-tp-client.c
@@ -101,6 +101,15 @@ shell_tp_client_init (ShellTpClient *self)
   /* Approver */
   tp_base_client_add_approver_filter (TP_BASE_CLIENT (self), filter);
 
+  /* Approve room invitations. We don't handle or observe room channels so
+   * just register this filter for the approver. */
+  tp_base_client_take_approver_filter (TP_BASE_CLIENT (self), tp_asv_new (
+      TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+        TP_IFACE_CHANNEL_TYPE_TEXT,
+      TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
+        TP_HANDLE_TYPE_ROOM,
+      NULL));
+
   /* Handler */
   tp_base_client_add_handler_filter (TP_BASE_CLIENT (self), filter);
 
@@ -371,3 +380,15 @@ shell_get_contact_events (TplLogManager *log_manager,
                                              NULL, NULL,
                                              callback, NULL);
 }
+
+/* gjs doesn't allow us to craft a GError so we need a C wrapper */
+void
+shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
+    const gchar *message)
+{
+  GError *error = g_error_new_literal (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+      message);
+
+  tp_add_dispatch_operation_context_fail (context, error);
+  g_error_free (error);
+}
diff --git a/src/shell-tp-client.h b/src/shell-tp-client.h
index 064c6ab..b323045 100644
--- a/src/shell-tp-client.h
+++ b/src/shell-tp-client.h
@@ -111,5 +111,8 @@ void shell_get_contact_events (TplLogManager *log_manager,
                                guint num_events,
                                GAsyncReadyCallback callback);
 
+void shell_decline_dispatch_op (TpAddDispatchOperationContext *context,
+                                const gchar *message);
+
 G_END_DECLS
 #endif /* __SHELL_TP_CLIENT_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]