From 6ad6f43606f3007531754ed7d97c5f941ca72793 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 29 May 2013 14:58:47 +0100 Subject: [PATCH 2/2] Acknowledge Jingle IQs in a way that the Google webmail client likes The Google webmail client currently starts calls like this: ... ... (This isn't valid XMPP Core, because 'An IQ stanza of type "get" or "set" MUST contain exactly one child element', but we can tolerate it.) When called, it also echoes the contents of the sender's IQ back to the sender. It appears that this is how, when it makes an outgoing call, it determines which dialect the recipient wants to use: the recipient echoes the appropriate child element. --- wocky/wocky-jingle-factory.c | 2 +- wocky/wocky-jingle-session.c | 72 ++++++++++++++++++++++++++++++++++++++---- wocky/wocky-jingle-session.h | 3 ++ 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/wocky/wocky-jingle-factory.c b/wocky/wocky-jingle-factory.c index 7d78ce6..f099df2 100644 --- a/wocky/wocky-jingle-factory.c +++ b/wocky/wocky-jingle-factory.c @@ -420,7 +420,7 @@ jingle_cb ( g_signal_emit (self, signals[NEW_SESSION], 0, sess, FALSE); /* all went well, we can acknowledge the IQ */ - wocky_porter_acknowledge_iq (porter, msg, NULL); + wocky_jingle_session_acknowledge_iq (sess, msg); return TRUE; diff --git a/wocky/wocky-jingle-session.c b/wocky/wocky-jingle-session.c index 3caa975..0289429 100644 --- a/wocky/wocky-jingle-session.c +++ b/wocky/wocky-jingle-session.c @@ -37,6 +37,7 @@ */ #include "wocky-jingle-media-rtp.h" #include "wocky-namespaces.h" +#include "wocky-node-private.h" #include "wocky-resource-contact.h" #include "wocky-utils.h" @@ -1566,11 +1567,12 @@ detect_google_dialect (WockyNode *session_node) return WOCKY_JINGLE_DIALECT_GTALK4; } -const gchar * -wocky_jingle_session_detect ( +static const gchar * +wocky_jingle_session_detect_internal ( WockyStanza *stanza, WockyJingleAction *action, - WockyJingleDialect *dialect) + WockyJingleDialect *dialect, + WockyNode **session_node_out) { const gchar *actxt, *sid; WockyNode *iq_node, *session_node; @@ -1593,7 +1595,8 @@ wocky_jingle_session_detect ( if (session_node != NULL) { - *dialect = WOCKY_JINGLE_DIALECT_V032; + if (dialect != NULL) + *dialect = WOCKY_JINGLE_DIALECT_V032; } else { @@ -1602,7 +1605,8 @@ wocky_jingle_session_detect ( if (session_node != NULL) { - *dialect = WOCKY_JINGLE_DIALECT_V015; + if (dialect != NULL) + *dialect = WOCKY_JINGLE_DIALECT_V015; } else { @@ -1612,7 +1616,9 @@ wocky_jingle_session_detect ( if (session_node != NULL) { - *dialect = detect_google_dialect (session_node); + if (dialect != NULL) + *dialect = detect_google_dialect (session_node); + google_mode = TRUE; } else @@ -1633,11 +1639,24 @@ wocky_jingle_session_detect ( sid = wocky_node_get_attribute (session_node, "sid"); } - *action = parse_action (actxt); + if (session_node_out != NULL) + *session_node_out = session_node; + + if (action != NULL) + *action = parse_action (actxt); return sid; } +const gchar * +wocky_jingle_session_detect ( + WockyStanza *stanza, + WockyJingleAction *action, + WockyJingleDialect *dialect) +{ + return wocky_jingle_session_detect_internal (stanza, action, dialect, NULL); +} + gboolean wocky_jingle_session_parse ( WockyJingleSession *sess, @@ -2513,3 +2532,42 @@ wocky_jingle_session_get_porter (WockyJingleSession *self) { return self->priv->porter; } + +void +wocky_jingle_session_acknowledge_iq (WockyJingleSession *self, + WockyStanza *stanza) +{ + if (wocky_jingle_session_peer_has_cap (self, WOCKY_QUIRK_GOOGLE_WEBMAIL_CLIENT)) + { + WockyJingleAction action = WOCKY_JINGLE_ACTION_UNKNOWN; + WockyNode *used_node = NULL; + + /* As of 2013-05-29, the Google webmail client sends a session-initiate + * IQ with two child nodes (which is not valid XMPP Core but never mind) + * and replies to session-initiate by echoing the child for the dialect + * it chose. We have to do the same echoing, otherwise it can't call us. + * + * It doesn't seem to reply to our other IQs at all; we still reply + * here (we'd be violating XMPP Core if we didn't), but we don't + * bother putting content in the IQ, to reduce bandwidth. */ + if (wocky_jingle_session_detect_internal (stanza, &action, NULL, + &used_node) != NULL && + action == WOCKY_JINGLE_ACTION_SESSION_INITIATE) + { + WockyStanza *reply = wocky_stanza_build_iq_result (stanza, NULL); + + if (reply != NULL) + { + WockyNode *reply_node = wocky_stanza_get_top_node (reply); + + reply_node->children = g_slist_append (reply_node->children, + _wocky_node_copy (used_node)); + wocky_porter_send (self->priv->porter, reply); + g_object_unref (reply); + } + } + } + + /* normal Jingle just says "OK" without echoing */ + wocky_porter_acknowledge_iq (self->priv->porter, stanza, NULL); +} diff --git a/wocky/wocky-jingle-session.h b/wocky/wocky-jingle-session.h index 9a49a37..43c8db3 100644 --- a/wocky/wocky-jingle-session.h +++ b/wocky/wocky-jingle-session.h @@ -131,6 +131,9 @@ const gchar *wocky_jingle_session_get_reason_name (WockyJingleReason reason); WockyJingleFactory *wocky_jingle_session_get_factory (WockyJingleSession *self); WockyPorter *wocky_jingle_session_get_porter (WockyJingleSession *self); +void wocky_jingle_session_acknowledge_iq (WockyJingleSession *self, + WockyStanza *stanza); + G_END_DECLS #endif /* __JINGLE_SESSION_H__ */ -- 1.7.10.4