telepathy-gabble: MUC: stop sending chat states after <error type=wait>

Will Thompson wjt at kemper.freedesktop.org
Mon Mar 4 04:22:17 PST 2013


Module: telepathy-gabble
Branch: master
Commit: fa8be7c05185ce92696a5771b556e70b8eb99a00
URL:    http://cgit.freedesktop.org/telepathy/telepathy-gabble/commit/?id=fa8be7c05185ce92696a5771b556e70b8eb99a00

Author: Will Thompson <will.thompson at collabora.co.uk>
Date:   Fri Feb 22 08:31:18 2013 +0000

MUC: stop sending chat states after <error type=wait>

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=43166#c0

---

 src/muc-channel.c                |   25 ++++++++++++++++++++++-
 tests/twisted/muc/chat-states.py |   39 +++++++++++++++++++++++++++++++++----
 2 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/src/muc-channel.c b/src/muc-channel.c
index 47ab9d5..15c337b 100644
--- a/src/muc-channel.c
+++ b/src/muc-channel.c
@@ -214,6 +214,8 @@ struct _GabbleMucChannelPrivate
   GPtrArray *initial_channels;
   GArray *initial_handles;
   char **initial_ids;
+
+  gboolean have_received_error_type_wait;
 };
 
 typedef struct {
@@ -2885,9 +2887,25 @@ handle_errmsg (GObject *source,
     }
 
   if (etype == WOCKY_XMPP_ERROR_TYPE_WAIT)
-    ds = TP_DELIVERY_STATUS_TEMPORARILY_FAILED;
+    {
+      ds = TP_DELIVERY_STATUS_TEMPORARILY_FAILED;
+      /* Some MUCs have very strict rate limiting like "at most one stanza per
+       * second". Since chat state notifications count towards this, if the
+       * user types a message very quickly then the typing notification is
+       * accepted but then the stanza containing the actual message is
+       * rejected.
+       *
+       * So: if we ever get rate-limited, let's just stop sending chat states.
+       *
+       * https://bugs.freedesktop.org/show_bug.cgi?id=43166
+       */
+      DEBUG ("got <error type='wait'>, disabling chat state notifications");
+      priv->have_received_error_type_wait = TRUE;
+    }
   else
-    ds = TP_DELIVERY_STATUS_PERMANENTLY_FAILED;
+    {
+      ds = TP_DELIVERY_STATUS_PERMANENTLY_FAILED;
+    }
 
   if (text != NULL)
     _gabble_muc_channel_receive (gmuc, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
@@ -3831,6 +3849,9 @@ gabble_muc_channel_send_chat_state (GObject *object,
   GabbleMucChannelPrivate *priv = self->priv;
   TpBaseChannel *base = TP_BASE_CHANNEL (self);
 
+  if (priv->have_received_error_type_wait)
+    return TRUE;
+
   return gabble_message_util_send_chat_state (G_OBJECT (self),
       GABBLE_CONNECTION (tp_base_channel_get_connection (base)),
       WOCKY_STANZA_SUB_TYPE_GROUPCHAT, state, priv->jid, error);
diff --git a/tests/twisted/muc/chat-states.py b/tests/twisted/muc/chat-states.py
index 48e6678..4be5f50 100644
--- a/tests/twisted/muc/chat-states.py
+++ b/tests/twisted/muc/chat-states.py
@@ -3,8 +3,8 @@ Regression test for <https://bugs.freedesktop.org/show_bug.cgi?id=32952>,
 wherein chat states in MUCs were misparsed, and MUC chat states in general.
 """
 
-from servicetest import assertEquals, assertLength
-from gabbletest import exec_test, elem, make_muc_presence
+from servicetest import assertEquals, assertLength, EventPattern
+from gabbletest import exec_test, elem, make_muc_presence, sync_stream
 from mucutil import join_muc_and_check
 import ns
 import constants as cs
@@ -12,16 +12,23 @@ import constants as cs
 MUC = 'ohai at groupchat.google.com'
 BOB = MUC + '/bob'
 
+def get_state_notification(stanza):
+    for x in stanza.elements():
+        if x.uri == ns.CHAT_STATES:
+            return x
+
+    return None
+
 def check_state_notification(elem, name, allow_body=False):
     assertEquals('message', elem.name)
     assertEquals('groupchat', elem['type'])
 
-    children = list(elem.elements())
-    notification = [x for x in children if x.uri == ns.CHAT_STATES][0]
+    notification = get_state_notification(elem)
+    assert notification is not None, elem.toXml()
     assert notification.name == name, notification.toXml()
 
     if not allow_body:
-        assert len(children) == 1, elem.toXml()
+        assert len(elem.children) == 1, elem.toXml()
 
 def test(q, bus, conn, stream):
     (muc_handle, chan, user, bob) = join_muc_and_check(q, bus, conn, stream,
@@ -115,5 +122,27 @@ def test(q, bus, conn, stream):
     assertLength(1, bodies)
     assertEquals(u'hi.', bodies[0].children[0])
 
+    # If we get an error with type='wait', stop sending chat states.
+    stanza['type'] = 'error'
+    stanza['from'] = MUC
+    stanza['to'] = 'test at localhost/Resource'
+
+    error = stanza.addElement('error')
+    error['type'] = 'wait'
+    error.addElement((ns.STANZA, 'resource-constraint'))
+    stream.send(stanza)
+
+    q.expect('dbus-signal', signal='MessageReceived',
+        predicate=lambda e: e.args[0][0]['message-type'] == cs.MT_DELIVERY_REPORT)
+
+    q.forbid_events([
+        EventPattern('stream-message', to=MUC,
+            predicate=lambda e: get_state_notification(e.stanza) is not None)
+        ])
+
+    # User starts typing again but nothing should be seen or heard on the stream.
+    chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING)
+    sync_stream(q, stream)
+
 if __name__ == '__main__':
       exec_test(test)



More information about the telepathy-commits mailing list