[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