[Telepathy-commits] [telepathy-gabble/master] ImChannel: emit failed delivery reports in response to incoming errors

Will Thompson will.thompson at collabora.co.uk
Tue Feb 3 06:34:49 PST 2009


TpMessageMixin emits SendError on top of [Message]Received when such a
delivery report is passed to _take_received().
---
 src/im-channel.c                 |   42 ++++++++++++--
 src/im-channel.h                 |    2 +-
 src/im-factory.c                 |   11 +---
 tests/twisted/Makefile.am        |    1 +
 tests/twisted/text/send-error.py |  110 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 151 insertions(+), 15 deletions(-)
 create mode 100644 tests/twisted/text/send-error.py

diff --git a/src/im-channel.c b/src/im-channel.c
index 70fd15f..0fc5ab3 100644
--- a/src/im-channel.c
+++ b/src/im-channel.c
@@ -499,22 +499,26 @@ _gabble_im_channel_receive (GabbleIMChannel *chan,
                             TpHandle sender,
                             const char *from,
                             time_t timestamp,
-                            const char *text)
+                            const char *text,
+                            TpChannelTextSendError send_error)
 {
   GabbleIMChannelPrivate *priv;
+  TpBaseConnection *base_conn;
   TpMessage *msg;
 
   g_assert (GABBLE_IS_IM_CHANNEL (chan));
   priv = GABBLE_IM_CHANNEL_GET_PRIVATE (chan);
+  base_conn = (TpBaseConnection *) priv->conn;
 
   /* update peer's full JID if it's changed */
-  if (0 != strcmp (from, priv->peer_jid))
+  if (send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR &&
+      0 != strcmp (from, priv->peer_jid))
     {
       g_free (priv->peer_jid);
       priv->peer_jid = g_strdup (from);
     }
 
-  msg = tp_message_new ((TpBaseConnection *) priv->conn, 2, 2);
+  msg = tp_message_new (base_conn, 2, 2);
 
   /* Header */
   if (type != TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL)
@@ -524,15 +528,41 @@ _gabble_im_channel_receive (GabbleIMChannel *chan,
     tp_message_set_uint64 (msg, 0, "message-sent", timestamp);
 
   tp_message_set_uint64 (msg, 0, "message-received", time (NULL));
-  tp_message_set_handle (msg, 0, "message-sender", TP_HANDLE_TYPE_CONTACT,
-      sender);
 
   /* Body */
   tp_message_set_string (msg, 1, "content-type", "text/plain");
   tp_message_set_string (msg, 1, "content", text);
 
+  if (send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
+    {
+      tp_message_set_handle (msg, 0, "message-sender", TP_HANDLE_TYPE_CONTACT,
+          sender);
+
+      tp_message_mixin_take_received (G_OBJECT (chan), msg);
+    }
+  else
+    {
+      TpMessage *delivery_report = tp_message_new (base_conn, 1, 1);
+
+      tp_message_set_uint32 (delivery_report, 0, "message-type",
+          TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT);
+      tp_message_set_handle (delivery_report, 0, "message-sender",
+          TP_HANDLE_TYPE_CONTACT, sender);
+      /* FIXME: Propagate whether the error is temporary or permanent from
+       * gabble_xmpp_error_from_node via _tp_send_error_from_error_node
+       */
+      tp_message_set_uint32 (delivery_report, 0, "delivery-status",
+          TP_DELIVERY_STATUS_PERMANENTLY_FAILED);
+      tp_message_set_uint32 (delivery_report, 0, "delivery-error", send_error);
 
-  tp_message_mixin_take_received (G_OBJECT (chan), msg);
+      /* We're getting a send error, so the original sender of the echoed
+       * message must be us! */
+      tp_message_set_handle (msg, 0, "message-sender", TP_HANDLE_TYPE_CONTACT,
+          base_conn->self_handle);
+      tp_message_take_message (delivery_report, 0, "delivery-echo", msg);
+
+      tp_message_mixin_take_received (G_OBJECT (chan), delivery_report);
+    }
 }
 
 /**
diff --git a/src/im-channel.h b/src/im-channel.h
index a48a982..bc02c24 100644
--- a/src/im-channel.h
+++ b/src/im-channel.h
@@ -67,7 +67,7 @@ GType gabble_im_channel_get_type (void);
 
 void _gabble_im_channel_receive (GabbleIMChannel *chan,
     TpChannelTextMessageType type, TpHandle sender, const char *from,
-    time_t timestamp, const char *text);
+    time_t timestamp, const char *text, TpChannelTextSendError send_error);
 void _gabble_im_channel_state_receive (GabbleIMChannel *chan, guint state);
 
 G_END_DECLS
diff --git a/src/im-factory.c b/src/im-factory.c
index 0dc69c9..b7122d7 100644
--- a/src/im-factory.c
+++ b/src/im-factory.c
@@ -273,19 +273,14 @@ im_factory_message_cb (LmMessageHandler *handler,
 
       DEBUG ("got error sending to %s (handle %u), msgtype %u, body:\n%s",
          from, handle, msgtype, body);
-
-      /* FIXME: emit a delivery report */
-      tp_svc_channel_type_text_emit_send_error ((TpSvcChannelTypeText *) chan,
-          send_error, stamp, msgtype, body);
-
-      return LM_HANDLER_RESULT_REMOVE_MESSAGE;
     }
 
-  if (state != -1)
+  if (state != -1 && send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
     _gabble_im_channel_state_receive (chan, state);
 
   if (body != NULL)
-    _gabble_im_channel_receive (chan, msgtype, handle, from, stamp, body);
+    _gabble_im_channel_receive (chan, msgtype, handle, from, stamp, body,
+        send_error);
 
   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
 }
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index dc97295..dcf24d3 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -33,6 +33,7 @@ TWISTED_TESTS = \
 	text/destroy.py \
 	text/ensure.py \
 	text/respawn.py \
+	text/send-error.py \
 	text/test-text-delayed.py \
 	text/test-text-no-body.py \
 	text/test-text.py \
diff --git a/tests/twisted/text/send-error.py b/tests/twisted/text/send-error.py
new file mode 100644
index 0000000..73c5b0a
--- /dev/null
+++ b/tests/twisted/text/send-error.py
@@ -0,0 +1,110 @@
+"""
+Test that an incoming <message><error/></> for a contact gives both a SendError
+and a delivery report on a 1-1 text channel to that contact.
+"""
+
+import dbus
+
+from twisted.words.xish import domish
+
+from gabbletest import exec_test
+from servicetest import call_async, EventPattern
+
+import ns
+
+def test(q, bus, conn, stream):
+    conn.Connect()
+    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])
+
+    self_handle = conn.GetSelfHandle()
+
+    jid = 'foo at bar.com'
+    call_async(q, conn, 'RequestHandles', 1, [jid])
+
+    event = q.expect('dbus-return', method='RequestHandles')
+    foo_handle = event.value[0][0]
+
+    properties = conn.GetAll(
+            'org.freedesktop.Telepathy.Connection.Interface.Requests',
+            dbus_interface='org.freedesktop.DBus.Properties')
+
+    requestotron = dbus.Interface(conn,
+            'org.freedesktop.Telepathy.Connection.Interface.Requests')
+    call_async(q, requestotron, 'CreateChannel',
+            { 'org.freedesktop.Telepathy.Channel.ChannelType':
+                'org.freedesktop.Telepathy.Channel.Type.Text',
+              'org.freedesktop.Telepathy.Channel.TargetHandleType': 1,
+              'org.freedesktop.Telepathy.Channel.TargetHandle': foo_handle,
+              })
+
+    ret = q.expect('dbus-return', method='CreateChannel')
+    text_chan = bus.get_object(conn.bus_name, ret.value[0])
+
+    # <message from='foo at bar.com' type='error'>
+    #   <body>what is up, my good sir?</body>
+    #   <error code='404' type='cancel'>
+    #     <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
+    #   </error>
+    # </message>
+    message_body = 'what is up, my good sir?'
+
+    m = domish.Element(('', 'message'))
+    m['from'] = 'foo at bar.com'
+    m['type'] = 'error'
+    m.addElement('body', content=message_body)
+
+    e = domish.Element(('', 'error'))
+    e['code'] = '404'
+    e['type'] = 'cancel'
+    e.addElement((ns.STANZA, 'item-not-found'))
+
+    m.addChild(e)
+
+    stream.send(m)
+
+    send_error, received, message_received = q.expect_many(
+        EventPattern('dbus-signal', signal='SendError'),
+        EventPattern('dbus-signal', signal='Received'),
+        EventPattern('dbus-signal', signal='MessageReceived'),
+        )
+
+    expected_send_error = 2 # Invalid_Contact
+
+    assert send_error.args[0] == expected_send_error, send_error.args
+    # FIXME: It doesn't look like it's possible to know what the original
+    # message type is, given that the type attribute of <message> is 'error'
+    # for error reports.
+    #assert send_error.args[2] == 0, send_error.args
+    assert send_error.args[3] == message_body, send_error.args
+
+    assert received.args[2] == foo_handle, (received.args, foo_handle)
+    assert received.args[3] == 4, received.args # Channel_Text_Message_Type_Delivery_Report
+    assert received.args[4] == 2, received.args # Channel_Text_Message_Flag_Non_Text_Content
+    assert received.args[5] == '', received.args
+
+    delivery_report = message_received.args[0]
+    assert len(delivery_report) == 1, delivery_report
+    header = delivery_report[0]
+    assert header['message-sender'] == foo_handle, header
+    assert header['message-type'] == 4, header # Channel_Text_Message_Type_Delivery_Report
+    assert header['delivery-status'] == 3, header # Delivery_Status_Permanently_Failed
+    assert 'delivery-token' not in header, header
+    assert header['delivery-error'] == expected_send_error, header
+
+    delivery_echo = header['delivery-echo']
+    assert len(delivery_echo) == 2, delivery_echo
+
+    assert delivery_echo[0]['message-sender'] == self_handle, delivery_echo
+    assert 'message-token' not in delivery_echo[0], delivery_echo
+    # FIXME: see above
+    #assert delivery_echo[0]['message-type'] == 0, delivery_echo
+
+    assert delivery_echo[1]['content-type'] == "text/plain", delivery_echo
+    assert delivery_echo[1]['content'] == message_body, delivery_echo
+
+    conn.Disconnect()
+    q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
+
+if __name__ == '__main__':
+    exec_test(test)
+
-- 
1.5.6.5




More information about the telepathy-commits mailing list