summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Thompson <will.thompson@collabora.co.uk>2011-11-07 17:46:04 +0000
committerWill Thompson <will.thompson@collabora.co.uk>2011-11-07 17:46:11 +0000
commitdf3882d34528ccb320835fafbad74034a589dc64 (patch)
tree35637b42b4e45ca0049ed4270d4767fbd814df90
parent6ef3ca940f0b4a4ae1aedb2c03ddc794fe659582 (diff)
parent6895340badaff9f97683230848ae8e0f9f6f99d8 (diff)
Merge branch 'facebook-own-message'
Reviewed-by: Jonny Lamb <jonny.lamb@collabora.co.uk>
-rw-r--r--src/connection.c4
-rw-r--r--src/disco.c2
-rw-r--r--src/ft-channel.c2
-rw-r--r--src/im-channel.c190
-rw-r--r--src/im-channel.h12
-rw-r--r--src/im-factory.c286
-rw-r--r--src/jingle-session.c2
-rw-r--r--src/media-factory.c2
-rw-r--r--src/muc-factory.c194
-rw-r--r--src/namespaces.h8
-rw-r--r--src/roster.c2
-rw-r--r--src/util.h2
-rw-r--r--src/vcard-manager.c2
-rw-r--r--tests/twisted/Makefile.am1
-rw-r--r--tests/twisted/constants.py8
-rw-r--r--tests/twisted/text/facebook-own-message.py70
-rw-r--r--tests/twisted/tools/exec-with-log.sh.in4
17 files changed, 508 insertions, 283 deletions
diff --git a/src/connection.c b/src/connection.c
index eeec1cd16..606e398fb 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -25,8 +25,6 @@
#include <stdio.h>
#include <string.h>
-#define DBUS_API_SUBJECT_TO_CHANGE
-
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <glib-object.h>
@@ -3814,7 +3812,7 @@ gabble_connection_send_presence (GabbleConnection *conn,
lm_message_node_add_own_nick (
wocky_stanza_get_top_node (message), conn);
- if (!CHECK_STR_EMPTY(status))
+ if (!tp_str_empty (status))
lm_message_node_add_child (
wocky_stanza_get_top_node (message), "status", status);
diff --git a/src/disco.c b/src/disco.c
index ba29a0fb7..21a15423b 100644
--- a/src/disco.c
+++ b/src/disco.c
@@ -26,8 +26,6 @@
#include <string.h>
-#define DBUS_API_SUBJECT_TO_CHANGE
-
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include <telepathy-glib/dbus.h>
diff --git a/src/ft-channel.c b/src/ft-channel.c
index 70b73f7ec..cc2eb57c4 100644
--- a/src/ft-channel.c
+++ b/src/ft-channel.c
@@ -1471,7 +1471,7 @@ gabble_file_transfer_channel_offer_file (GabbleFileTransferChannel *self,
gboolean jingle_share = FALSE;
const gchar *si_resource = NULL;
const gchar *share_resource = NULL;
- g_assert (!CHECK_STR_EMPTY (self->priv->filename));
+ g_assert (!tp_str_empty (self->priv->filename));
g_assert (self->priv->size != GABBLE_UNDEFINED_FILE_SIZE);
g_return_val_if_fail (self->priv->bytestream == NULL, FALSE);
g_return_val_if_fail (self->priv->gtalk_file_collection == NULL, FALSE);
diff --git a/src/im-channel.c b/src/im-channel.c
index 40b3a368f..dba3aedba 100644
--- a/src/im-channel.c
+++ b/src/im-channel.c
@@ -176,6 +176,13 @@ gabble_im_channel_fill_immutable_properties (TpBaseChannel *chan,
NULL);
}
+static gchar *
+gabble_im_channel_get_object_path_suffix (TpBaseChannel *chan)
+{
+ return g_strdup_printf ("ImChannel%u",
+ tp_base_channel_get_target_handle (chan));
+}
+
static void
gabble_im_channel_class_init (GabbleIMChannelClass *gabble_im_channel_class)
{
@@ -196,6 +203,7 @@ gabble_im_channel_class_init (GabbleIMChannelClass *gabble_im_channel_class)
base_class->close = gabble_im_channel_close;
base_class->fill_immutable_properties =
gabble_im_channel_fill_immutable_properties;
+ base_class->get_object_path_suffix = gabble_im_channel_get_object_path_suffix;
tp_message_mixin_init_dbus_properties (object_class);
}
@@ -384,118 +392,154 @@ _gabble_im_channel_send_message (GObject *object,
priv->send_nick = FALSE;
}
-/**
- * _gabble_im_channel_receive
+static TpMessage *
+build_message (
+ GabbleIMChannel *self,
+ TpChannelTextMessageType type,
+ time_t timestamp,
+ const char *text)
+{
+ TpBaseChannel *base_chan = (TpBaseChannel *) self;
+ TpBaseConnection *base_conn = tp_base_channel_get_connection (base_chan);
+ TpMessage *msg = tp_cm_message_new (base_conn, 2);
+
+ if (type != TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL)
+ tp_message_set_uint32 (msg, 0, "message-type", type);
+
+ if (timestamp != 0)
+ tp_message_set_int64 (msg, 0, "message-sent", timestamp);
+
+ /* Body */
+ tp_message_set_string (msg, 1, "content-type", "text/plain");
+ tp_message_set_string (msg, 1, "content", text);
+
+ return msg;
+}
+
+/*
+ * _gabble_im_channel_receive:
+ * @chan: a channel
+ * @type: the message type
+ * @from: the full JID we received the message from
+ * @timestamp: the time at which the message was sent (not the time it was
+ * received)
+ * @id: the id='' attribute from the <message/> stanza, if any
+ * @text: the plaintext body of the message
+ * @send_error: the reason why sending @text to @sender failed, or
+ * GABBLE_TEXT_CHANNEL_SEND_NO_ERROR if this call is not to report
+ * a failure to send.
+ * @delivery_status: if @send_error is GABBLE_TEXT_CHANNEL_SEND_NO_ERROR,
+ * ignored; else the delivery status to attach to the report.
+ * @state: a #TpChannelChatState, or -1 if there was no chat state in the
+ * message.
*
+ * Shoves an incoming message into @chan, possibly updating the chat state at
+ * the same time; or maybe this is a delivery report? Who knows! It's a magical
+ * adventure.
*/
void
_gabble_im_channel_receive (GabbleIMChannel *chan,
TpChannelTextMessageType type,
- TpHandle sender,
const char *from,
time_t timestamp,
const gchar *id,
const char *text,
- TpChannelTextSendError send_error,
- TpDeliveryStatus delivery_status,
gint state)
{
GabbleIMChannelPrivate *priv;
TpBaseChannel *base_chan;
- TpBaseConnection *base_conn;
+ TpHandle peer;
TpMessage *msg;
- gchar *tmp;
g_assert (GABBLE_IS_IM_CHANNEL (chan));
priv = chan->priv;
base_chan = (TpBaseChannel *) chan;
- base_conn = tp_base_channel_get_connection (base_chan);
+ peer = tp_base_channel_get_target_handle (base_chan);
- if (send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
+ /* update peer's full JID if it's changed */
+ if (tp_strdiff (from, priv->peer_jid))
{
- /* update peer's full JID if it's changed */
- if (tp_strdiff (from, priv->peer_jid))
- {
- g_free (priv->peer_jid);
- priv->peer_jid = g_strdup (from);
- }
-
- if (state == -1)
- {
- priv->chat_states_supported = CHAT_STATES_NOT_SUPPORTED;
- }
- else
- {
- _gabble_im_channel_state_receive (chan, state);
- }
+ g_free (priv->peer_jid);
+ priv->peer_jid = g_strdup (from);
}
- else
- {
- /* strip off the resource (if any), since we just failed to send to it */
- char *slash = strchr (priv->peer_jid, '/');
- if (slash != NULL)
- *slash = '\0';
+ if (state == -1)
+ priv->chat_states_supported = CHAT_STATES_NOT_SUPPORTED;
+ else
+ _gabble_im_channel_state_receive (chan, state);
- priv->chat_states_supported = CHAT_STATES_UNKNOWN;
- }
+ msg = build_message (chan, type, timestamp, text);
+ tp_cm_message_set_sender (msg, peer);
+ tp_message_set_int64 (msg, 0, "message-received", time (NULL));
- msg = tp_cm_message_new (base_conn, 2);
+ if (id != NULL)
+ tp_message_set_string (msg, 0, "message-token", id);
- /* Header */
- if (type != TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL)
- tp_message_set_uint32 (msg, 0, "message-type", type);
+ tp_message_mixin_take_received (G_OBJECT (chan), msg);
+}
- if (timestamp != 0)
- tp_message_set_int64 (msg, 0, "message-sent", timestamp);
+void
+_gabble_im_channel_report_delivery (
+ GabbleIMChannel *self,
+ TpChannelTextMessageType type,
+ time_t timestamp,
+ const gchar *id,
+ const char *text,
+ TpChannelTextSendError send_error,
+ TpDeliveryStatus delivery_status)
+{
+ GabbleIMChannelPrivate *priv;
+ TpBaseChannel *base_chan = (TpBaseChannel *) self;
+ TpBaseConnection *base_conn;
+ TpHandle peer;
+ TpMessage *msg, *delivery_report;
+ gchar *tmp;
- /* Body */
- tp_message_set_string (msg, 1, "content-type", "text/plain");
- tp_message_set_string (msg, 1, "content", text);
+ g_return_if_fail (GABBLE_IS_IM_CHANNEL (self));
+ priv = self->priv;
+ peer = tp_base_channel_get_target_handle (base_chan);
+ base_conn = tp_base_channel_get_connection (base_chan);
- if (send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
+ if (send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
{
- tp_cm_message_set_sender (msg, sender);
- tp_message_set_int64 (msg, 0, "message-received", time (NULL));
+ /* strip off the resource (if any), since we just failed to send to it */
+ char *slash = strchr (priv->peer_jid, '/');
- if (id != NULL)
- tp_message_set_string (msg, 0, "message-token", id);
+ if (slash != NULL)
+ *slash = '\0';
- tp_message_mixin_take_received (G_OBJECT (chan), msg);
+ priv->chat_states_supported = CHAT_STATES_UNKNOWN;
}
- else
- {
- TpMessage *delivery_report = tp_cm_message_new (base_conn, 1);
-
- tp_message_set_uint32 (delivery_report, 0, "message-type",
- TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT);
- tp_cm_message_set_sender (delivery_report, sender);
- tp_message_set_int64 (delivery_report, 0, "message-received",
- time (NULL));
- tmp = gabble_generate_id ();
- tp_message_set_string (delivery_report, 0, "message-token", tmp);
- g_free (tmp);
+ msg = build_message (self, type, timestamp, text);
+ delivery_report = tp_cm_message_new (base_conn, 1);
+ tp_message_set_uint32 (delivery_report, 0, "message-type",
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT);
+ tp_cm_message_set_sender (delivery_report, peer);
+ tp_message_set_int64 (delivery_report, 0, "message-received",
+ time (NULL));
- tp_message_set_uint32 (delivery_report, 0, "delivery-status",
- delivery_status);
- tp_message_set_uint32 (delivery_report, 0, "delivery-error", send_error);
+ tmp = gabble_generate_id ();
+ tp_message_set_string (delivery_report, 0, "message-token", tmp);
+ g_free (tmp);
- if (id != NULL)
- tp_message_set_string (delivery_report, 0, "delivery-token", id);
+ tp_message_set_uint32 (delivery_report, 0, "delivery-status",
+ delivery_status);
+ tp_message_set_uint32 (delivery_report, 0, "delivery-error", send_error);
- /* We're getting a send error, so the original sender of the echoed
- * message must be us! */
- tp_cm_message_set_sender (msg, base_conn->self_handle);
+ if (id != NULL)
+ tp_message_set_string (delivery_report, 0, "delivery-token", id);
- /* Since this is a send error, we can trust the id on the message. */
- if (id != NULL)
- tp_message_set_string (msg, 0, "message-token", id);
+ /* This is a delivery report, so the original sender of the echoed message
+ * must be us! */
+ tp_cm_message_set_sender (msg, base_conn->self_handle);
- tp_cm_message_take_message (delivery_report, 0, "delivery-echo", msg);
+ /* Since this is a delivery report, we can trust the id on the message. */
+ if (id != NULL)
+ tp_message_set_string (msg, 0, "message-token", id);
- tp_message_mixin_take_received (G_OBJECT (chan), delivery_report);
- }
+ tp_cm_message_take_message (delivery_report, 0, "delivery-echo", msg);
+ tp_message_mixin_take_received (G_OBJECT (self), delivery_report);
}
/**
diff --git a/src/im-channel.h b/src/im-channel.h
index 17d6271b0..fdbae19bf 100644
--- a/src/im-channel.h
+++ b/src/im-channel.h
@@ -66,17 +66,23 @@ 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 *id,
const char *text,
- TpChannelTextSendError send_error,
- TpDeliveryStatus delivery_status,
gint state);
void _gabble_im_channel_state_receive (GabbleIMChannel *chan,
TpChannelChatState state);
+void _gabble_im_channel_report_delivery (
+ GabbleIMChannel *self,
+ TpChannelTextMessageType type,
+ time_t timestamp,
+ const gchar *id,
+ const char *text,
+ TpChannelTextSendError send_error,
+ TpDeliveryStatus delivery_status);
+
G_END_DECLS
#endif /* #ifndef __GABBLE_IM_CHANNEL_H__*/
diff --git a/src/im-factory.c b/src/im-factory.c
index be518b276..b695a601d 100644
--- a/src/im-factory.c
+++ b/src/im-factory.c
@@ -20,8 +20,6 @@
#include "config.h"
#include "im-factory.h"
-#define DBUS_API_SUBJECT_TO_CHANGE
-
#include <string.h>
#include <dbus/dbus-glib.h>
@@ -31,6 +29,7 @@
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/gtypes.h>
#include <telepathy-glib/interfaces.h>
+#include <wocky/wocky-c2s-porter.h>
#define DEBUG_FLAG GABBLE_DEBUG_IM
@@ -42,6 +41,7 @@
#include "disco.h"
#include "im-channel.h"
#include "message-util.h"
+#include "namespaces.h"
static void channel_manager_iface_init (gpointer, gpointer);
static void caps_channel_manager_iface_init (gpointer, gpointer);
@@ -70,11 +70,6 @@ struct _GabbleImFactoryPrivate
gboolean dispose_has_run;
};
-#define GABBLE_IM_FACTORY_GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), GABBLE_TYPE_IM_FACTORY,\
- GabbleImFactoryPrivate))
-
-
static void
gabble_im_factory_init (GabbleImFactory *self)
{
@@ -93,20 +88,24 @@ gabble_im_factory_init (GabbleImFactory *self)
static void connection_status_changed_cb (GabbleConnection *conn,
guint status, guint reason, GabbleImFactory *self);
+static void porter_available_cb (
+ GabbleConnection *conn,
+ WockyPorter *porter,
+ gpointer user_data);
-
-static GObject *
-gabble_im_factory_constructor (GType type, guint n_props,
- GObjectConstructParam *props)
+static void
+gabble_im_factory_constructed (GObject *obj)
{
- GObject *obj = G_OBJECT_CLASS (gabble_im_factory_parent_class)->
- constructor (type, n_props, props);
GabbleImFactory *self = GABBLE_IM_FACTORY (obj);
+ GObjectClass *parent_class = gabble_im_factory_parent_class;
+
+ if (parent_class->constructed != NULL)
+ parent_class->constructed (obj);
self->priv->status_changed_id = g_signal_connect (self->priv->conn,
"status-changed", (GCallback) connection_status_changed_cb, obj);
-
- return obj;
+ tp_g_signal_connect_object (self->priv->conn,
+ "porter-available", (GCallback) porter_available_cb, obj, 0);
}
@@ -117,7 +116,7 @@ static void
gabble_im_factory_dispose (GObject *object)
{
GabbleImFactory *fac = GABBLE_IM_FACTORY (object);
- GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (fac);
+ GabbleImFactoryPrivate *priv = fac->priv;
if (priv->dispose_has_run)
return;
@@ -139,7 +138,7 @@ gabble_im_factory_get_property (GObject *object,
GParamSpec *pspec)
{
GabbleImFactory *fac = GABBLE_IM_FACTORY (object);
- GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (fac);
+ GabbleImFactoryPrivate *priv = fac->priv;
switch (property_id) {
case PROP_CONNECTION:
@@ -158,7 +157,7 @@ gabble_im_factory_set_property (GObject *object,
GParamSpec *pspec)
{
GabbleImFactory *fac = GABBLE_IM_FACTORY (object);
- GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (fac);
+ GabbleImFactoryPrivate *priv = fac->priv;
switch (property_id) {
case PROP_CONNECTION:
@@ -179,7 +178,7 @@ gabble_im_factory_class_init (GabbleImFactoryClass *gabble_im_factory_class)
g_type_class_add_private (gabble_im_factory_class,
sizeof (GabbleImFactoryPrivate));
- object_class->constructor = gabble_im_factory_constructor;
+ object_class->constructed = gabble_im_factory_constructed;
object_class->dispose = gabble_im_factory_dispose;
object_class->get_property = gabble_im_factory_get_property;
@@ -193,11 +192,10 @@ gabble_im_factory_class_init (GabbleImFactoryClass *gabble_im_factory_class)
}
-static GabbleIMChannel *new_im_channel (GabbleImFactory *fac,
- TpHandle handle, TpHandle initiator, gpointer request_token);
-
-static void im_channel_closed_cb (GabbleIMChannel *chan, gpointer user_data);
-
+static GabbleIMChannel *get_channel_for_incoming_message (
+ GabbleImFactory *self,
+ const gchar *jid,
+ gboolean create_if_missing);
/**
* im_factory_message_cb:
@@ -211,18 +209,14 @@ im_factory_message_cb (LmMessageHandler *handler,
gpointer user_data)
{
GabbleImFactory *fac = GABBLE_IM_FACTORY (user_data);
- GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (fac);
- TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
- TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
- TP_HANDLE_TYPE_CONTACT);
const gchar *from, *body, *id;
time_t stamp;
TpChannelTextMessageType msgtype;
- TpHandle handle;
GabbleIMChannel *chan;
gint state;
TpChannelTextSendError send_error;
TpDeliveryStatus delivery_status;
+ gboolean create_if_missing;
if (!gabble_message_util_parse_incoming_message (message, &from, &stamp,
&msgtype, &id, &body, &state, &send_error, &delivery_status))
@@ -233,62 +227,46 @@ im_factory_message_cb (LmMessageHandler *handler,
return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
- handle = tp_handle_ensure (contact_repo, from, NULL, NULL);
- if (handle == 0)
+ /* We don't want to open up a channel for the sole purpose of reporting a
+ * send error, nor if this is just a chat state notification.
+ */
+ create_if_missing =
+ (send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR) &&
+ (body != NULL);
+ chan = get_channel_for_incoming_message (fac, from, create_if_missing);
+ if (chan == NULL)
{
- STANZA_DEBUG (message, "ignoring message node from malformed jid");
+ if (create_if_missing)
+ STANZA_DEBUG (message, "ignoring message from non-contact JID");
+ else
+ DEBUG ("ignoring message error or chat state notification from '%s': "
+ "no existing channel", from);
+
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
- chan = g_hash_table_lookup (priv->channels, GUINT_TO_POINTER (handle));
-
- if (chan == NULL)
+ if (send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
{
- if (send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
- {
- DEBUG ("ignoring message error; no sending channel");
- tp_handle_unref (contact_repo, handle);
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
if (body == NULL)
{
- /* don't create a new channel if all we have is a chat state */
- DEBUG ("ignoring message without body; no existing channel");
- tp_handle_unref (contact_repo, handle);
+ DEBUG ("ignoring error sending chat state to %s", from);
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
- DEBUG ("found no IM channel, creating one");
+ DEBUG ("got error sending to %s, msgtype %u, body:\n%s",
+ from, msgtype, body);
- chan = new_im_channel (fac, handle, handle, NULL);
+ _gabble_im_channel_report_delivery (chan, msgtype, stamp, id, body,
+ send_error, delivery_status);
}
-
- g_assert (chan != NULL);
-
- /* now the channel is referencing the handle, so if we unref it, that's
- * not a problem */
- tp_handle_unref (contact_repo, handle);
-
- if (send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
+ else if (body != NULL)
{
- if (body == NULL)
- {
- DEBUG ("ignoring error sending chat state to %s (handle %u)", from,
- handle);
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- DEBUG ("got error sending to %s (handle %u), msgtype %u, body:\n%s",
- from, handle, msgtype, body);
+ _gabble_im_channel_receive (chan, msgtype, from, stamp, id, body, state);
+ }
+ else if (state != -1)
+ {
+ _gabble_im_channel_state_receive (chan, (TpChannelChatState) state);
}
-
- if (body != NULL)
- _gabble_im_channel_receive (chan, msgtype, handle, from, stamp, id, body,
- send_error, delivery_status, state);
- else if (state != -1 && send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
- _gabble_im_channel_state_receive (chan, (TpChannelChatState) state);
-
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
}
@@ -305,7 +283,7 @@ static void
im_channel_closed_cb (GabbleIMChannel *chan, gpointer user_data)
{
GabbleImFactory *self = GABBLE_IM_FACTORY (user_data);
- GabbleImFactoryPrivate *priv = GABBLE_IM_FACTORY_GET_PRIVATE (self);
+ GabbleImFactoryPrivate *priv = self->priv;
TpHandle contact_handle;
gboolean really_destroyed;
@@ -338,40 +316,43 @@ im_channel_closed_cb (GabbleIMChannel *chan, gpointer user_data)
}
}
-/**
- * new_im_channel
+/*
+ * new_im_channel:
+ * @fac: the factory
+ * @handle: a contact handle, for whom a channel must not yet exist
+ * @request_token: if the channel is being created in response to a channel
+ * request, the associated request token; otherwise, NULL.
+ *
+ * Creates a new 1-1 text channel to a contact. Must only be called when no 1-1
+ * text channel is already open to that contact.
+ *
+ * Returns: (transfer none): a freshly-constructed channel
*/
static GabbleIMChannel *
new_im_channel (GabbleImFactory *fac,
TpHandle handle,
- TpHandle initiator,
gpointer request_token)
{
- GabbleImFactoryPrivate *priv;
- TpBaseConnection *conn;
+ GabbleImFactoryPrivate *priv = fac->priv;
+ TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
GabbleIMChannel *chan;
- char *object_path;
GSList *request_tokens;
+ TpHandle initiator;
- g_return_val_if_fail (GABBLE_IS_IM_FACTORY (fac), NULL);
g_return_val_if_fail (handle != 0, NULL);
- g_return_val_if_fail (initiator != 0, NULL);
- priv = GABBLE_IM_FACTORY_GET_PRIVATE (fac);
- conn = (TpBaseConnection *) priv->conn;
+ if (request_token != NULL)
+ initiator = conn->self_handle;
+ else
+ initiator = handle;
- object_path = g_strdup_printf ("%s/ImChannel%u",
- conn->object_path, handle);
chan = g_object_new (GABBLE_TYPE_IM_CHANNEL,
"connection", priv->conn,
- "object-path", object_path,
"handle", handle,
"initiator-handle", initiator,
"requested", (handle != initiator),
NULL);
- DEBUG ("object path %s", object_path);
tp_base_channel_register ((TpBaseChannel *) chan);
- g_free (object_path);
g_signal_connect (chan, "closed", (GCallback) im_channel_closed_cb, fac);
@@ -390,6 +371,48 @@ new_im_channel (GabbleImFactory *fac,
return chan;
}
+/*
+ * get_channel_for_incoming_message:
+ * @self: a factory
+ * @jid: a contact's JID
+ * @create_if_missing: if %TRUE, a new channel will be created if there is no
+ * existing channel to @jid
+ *
+ * Retrieves a 1-1 text channel to a particular contact. If no channel is open
+ * to @jid, it will be created only if @create_if_missing is %TRUE. If @jid is
+ * not of the form 'user@domain' (optionally with a resource), no channel will
+ * be opened.
+ *
+ * Returns: an IM channel to @jid, or %NULL
+ */
+static GabbleIMChannel *
+get_channel_for_incoming_message (
+ GabbleImFactory *self,
+ const gchar *jid,
+ gboolean create_if_missing)
+{
+ GabbleImFactoryPrivate *priv = self->priv;
+ TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpHandle handle;
+ GabbleIMChannel *chan;
+
+ g_return_val_if_fail (jid != NULL, NULL);
+
+ handle = tp_handle_ensure (contact_repo, jid, NULL, NULL);
+ if (handle == 0)
+ return NULL;
+
+ chan = g_hash_table_lookup (priv->channels, GUINT_TO_POINTER (handle));
+ if (chan != NULL)
+ return chan;
+ else if (create_if_missing)
+ return new_im_channel (self, handle, NULL);
+ else
+ return NULL;
+}
+
static void
gabble_im_factory_close_all (GabbleImFactory *self)
{
@@ -441,6 +464,92 @@ connection_status_changed_cb (GabbleConnection *conn,
}
}
+static gboolean
+im_factory_own_message_cb (
+ WockyPorter *porter,
+ WockyStanza *stanza,
+ gpointer user_data)
+{
+ GabbleImFactory *self = GABBLE_IM_FACTORY (user_data);
+ WockyNode *own_message, *body;
+ const gchar *to;
+ gboolean sent_locally;
+ GabbleIMChannel *chan;
+
+ /* Our stanza filter should guarantee that these are present. */
+ own_message = wocky_node_get_child (wocky_stanza_get_top_node (stanza),
+ "own-message");
+ g_return_val_if_fail (own_message != NULL, FALSE);
+ body = wocky_node_get_child (own_message, "body");
+ g_return_val_if_fail (body != NULL, FALSE);
+
+ to = wocky_node_get_attribute (own_message, "to");
+ if (to == NULL)
+ {
+ DEBUG ("own-message missing to='' attribute; ignoring");
+ return FALSE;
+ }
+
+ /* If self='true', the message was sent by the local user on this machine,
+ * rather than by the local user on some other machine. We don't really have
+ * a good way to show this in Messages. Also we don't get told the id='' of
+ * the original message, which is annoying.
+ */
+ sent_locally = !tp_strdiff ("true",
+ wocky_node_get_attribute (own_message, "self"));
+ DEBUG ("this report is for a message to '%s', sent %s",
+ to, sent_locally ? "locally" : "remotely");
+
+ /* Don't create a channel for the sole purpose of reporting an own-message.
+ * This is consistent with not creating a channel to report send errors
+ * (given that both are delivery reports).
+ */
+ chan = get_channel_for_incoming_message (self, to, FALSE);
+ if (chan != NULL)
+ _gabble_im_channel_report_delivery (chan,
+ TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, 0, NULL, body->content,
+ GABBLE_TEXT_CHANNEL_SEND_NO_ERROR, TP_DELIVERY_STATUS_ACCEPTED);
+ else
+ DEBUG ("no channel for '%s'; not spawning one just for the delivery report",
+ to);
+
+ wocky_porter_acknowledge_iq (porter, stanza, NULL);
+ return TRUE;
+}
+
+static void
+porter_available_cb (
+ GabbleConnection *conn,
+ WockyPorter *porter,
+ gpointer user_data)
+{
+ GabbleImFactory *self = GABBLE_IM_FACTORY (user_data);
+ gchar *stream_server;
+
+ g_object_get (conn, "stream-server", &stream_server, NULL);
+
+ if (!tp_strdiff (stream_server, "chat.facebook.com"))
+ {
+ wocky_porter_register_handler_from (
+ porter, WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
+ /* We could use _from_server() if that accepted messages from our
+ * JID's domain, not just from bare JID, full JID, or no sender
+ * specified—which would allow the extension to work on other servers
+ * too—but it doesn't.
+ */
+ stream_server,
+ WOCKY_PORTER_HANDLER_PRIORITY_NORMAL,
+ im_factory_own_message_cb, self,
+ '(',
+ "own-message", ':', NS_FACEBOOK_MESSAGES,
+ '(', "body", ')',
+ ')', NULL);
+ }
+
+ g_free (stream_server);
+}
+
+
static void
gabble_im_factory_get_contact_caps (GabbleCapsChannelManager *manager,
TpHandle handle,
@@ -570,7 +679,6 @@ gabble_im_factory_requestotron (GabbleImFactory *self,
GHashTable *request_properties,
gboolean require_new)
{
- TpBaseConnection *base_conn = (TpBaseConnection *) self->priv->conn;
TpHandle handle;
GError *error = NULL;
TpExportableChannel *channel;
@@ -598,7 +706,7 @@ gabble_im_factory_requestotron (GabbleImFactory *self,
if (channel == NULL)
{
- new_im_channel (self, handle, base_conn->self_handle, request_token);
+ new_im_channel (self, handle, request_token);
return TRUE;
}
diff --git a/src/jingle-session.c b/src/jingle-session.c
index 2981e3e83..d65721cfa 100644
--- a/src/jingle-session.c
+++ b/src/jingle-session.c
@@ -2092,7 +2092,7 @@ gabble_jingle_session_terminate (GabbleJingleSession *sess,
lm_message_node_add_child (r, reason_elt, NULL);
- if (!CHECK_STR_EMPTY(text))
+ if (!tp_str_empty (text))
lm_message_node_add_child (r, "text", text);
}
diff --git a/src/media-factory.c b/src/media-factory.c
index e8ec99081..575534089 100644
--- a/src/media-factory.c
+++ b/src/media-factory.c
@@ -20,8 +20,6 @@
#include "config.h"
#include "media-factory.h"
-#define DBUS_API_SUBJECT_TO_CHANGE
-
#include <stdlib.h>
#include <string.h>
diff --git a/src/muc-factory.c b/src/muc-factory.c
index 971244454..c8275a25e 100644
--- a/src/muc-factory.c
+++ b/src/muc-factory.c
@@ -20,8 +20,6 @@
#include "config.h"
#include "muc-factory.h"
-#define DBUS_API_SUBJECT_TO_CHANGE
-
#include <string.h>
#include <dbus/dbus-glib.h>
@@ -99,17 +97,14 @@ struct _GabbleMucFactoryPrivate
gboolean dispose_has_run;
};
-#define GABBLE_MUC_FACTORY_GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), GABBLE_TYPE_MUC_FACTORY, \
- GabbleMucFactoryPrivate))
-
static GObject *gabble_muc_factory_constructor (GType type, guint n_props,
GObjectConstructParam *props);
static void
gabble_muc_factory_init (GabbleMucFactory *fac)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (fac,
+ GABBLE_TYPE_MUC_FACTORY, GabbleMucFactoryPrivate);
fac->priv = priv;
@@ -150,7 +145,7 @@ static void
gabble_muc_factory_dispose (GObject *object)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (object);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
if (priv->dispose_has_run)
return;
@@ -179,7 +174,7 @@ gabble_muc_factory_get_property (GObject *object,
GParamSpec *pspec)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (object);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
switch (property_id) {
case PROP_CONNECTION:
@@ -198,7 +193,7 @@ gabble_muc_factory_set_property (GObject *object,
GParamSpec *pspec)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (object);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
switch (property_id) {
case PROP_CONNECTION:
@@ -242,7 +237,7 @@ static void
muc_channel_closed_cb (GabbleMucChannel *chan, gpointer user_data)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
TpHandle room_handle;
tp_channel_manager_emit_channel_closed_for_object (fac,
@@ -265,7 +260,7 @@ muc_ready_cb (GabbleMucChannel *text_chan,
gpointer data)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
GabbleTubesChannel *tubes_chan;
GSList *requests_satisfied_text, *requests_satisfied_tubes = NULL;
gboolean text_requested;
@@ -354,7 +349,7 @@ muc_join_error_cb (GabbleMucChannel *chan,
gpointer data)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
GabbleTubesChannel *tubes_chan;
GSList *requests_satisfied;
GSList *iter;
@@ -455,7 +450,7 @@ new_muc_channel (GabbleMucFactory *fac,
char **initial_ids,
const char *room_name)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
GabbleMucChannel *chan;
char *object_path;
@@ -531,7 +526,7 @@ do_invite (GabbleMucFactory *fac,
TpHandle inviter_handle,
const gchar *reason)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
(TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
TpHandle room_handle;
@@ -583,7 +578,7 @@ obsolete_invite_disco_cb (GabbleDisco *self,
struct DiscoInviteData *data = (struct DiscoInviteData *) user_data;
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data->factory);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
(TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
LmMessageNode *identity;
@@ -628,7 +623,7 @@ process_muc_invite (GabbleMucFactory *fac,
const gchar *from,
TpChannelTextSendError send_error)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
TP_HANDLE_TYPE_CONTACT);
@@ -702,7 +697,7 @@ process_obsolete_invite (GabbleMucFactory *fac,
const gchar *body,
TpChannelTextSendError send_error)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
TP_HANDLE_TYPE_CONTACT);
@@ -790,7 +785,7 @@ muc_factory_message_cb (LmMessageHandler *handler,
gpointer user_data)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
const gchar *from, *body, *id;
time_t stamp;
@@ -826,7 +821,7 @@ muc_factory_message_cb (LmMessageHandler *handler,
void
gabble_muc_factory_broadcast_presence (GabbleMucFactory *self)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
GHashTableIter iter;
gpointer channel = NULL;
@@ -844,7 +839,7 @@ gabble_muc_factory_associate_request (GabbleMucFactory *self,
gpointer channel,
gpointer request)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
GSList *list = g_hash_table_lookup (priv->queued_requests, channel);
g_assert (TP_IS_EXPORTABLE_CHANNEL (channel));
@@ -882,7 +877,7 @@ cancel_queued_requests (gpointer k,
static void
gabble_muc_factory_close_all (GabbleMucFactory *self)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
DEBUG ("closing channels");
@@ -937,7 +932,7 @@ connection_status_changed_cb (GabbleConnection *conn,
guint reason,
GabbleMucFactory *self)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
switch (status)
{
@@ -966,7 +961,7 @@ gabble_muc_factory_constructor (GType type, guint n_props,
GObject *obj = G_OBJECT_CLASS (gabble_muc_factory_parent_class)->
constructor (type, n_props, props);
GabbleMucFactory *self = GABBLE_MUC_FACTORY (obj);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
priv->status_changed_id = g_signal_connect (priv->conn,
"status-changed", (GCallback) connection_status_changed_cb, obj);
@@ -1011,7 +1006,7 @@ gabble_muc_factory_foreach_channel (TpChannelManager *manager,
gpointer user_data)
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (manager);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
+ GabbleMucFactoryPrivate *priv = fac->priv;
struct _ForeachData data;
data.user_data = user_data;
@@ -1065,7 +1060,7 @@ gabble_muc_factory_handle_si_stream_request (GabbleMucFactory *self,
const gchar *stream_id,
LmMessage *msg)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
(TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
GabbleMucChannel *gmuc = NULL;
@@ -1095,15 +1090,15 @@ GabbleMucChannel *
gabble_muc_factory_find_text_channel (GabbleMucFactory *self,
TpHandle handle)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
return g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle));
}
static const gchar * const muc_channel_fixed_properties[] = {
- TP_IFACE_CHANNEL ".ChannelType",
- TP_IFACE_CHANNEL ".TargetHandleType",
+ TP_PROP_CHANNEL_CHANNEL_TYPE,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
NULL
};
@@ -1111,20 +1106,20 @@ static const gchar * const * muc_tubes_channel_fixed_properties =
muc_channel_fixed_properties;
static const gchar * const muc_channel_allowed_properties[] = {
- TP_IFACE_CHANNEL ".TargetHandle",
- TP_IFACE_CHANNEL ".TargetID",
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialChannels",
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeHandles",
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeIDs",
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InvitationMessage",
+ TP_PROP_CHANNEL_TARGET_HANDLE,
+ TP_PROP_CHANNEL_TARGET_ID,
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS,
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_HANDLES,
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS,
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INVITATION_MESSAGE,
TP_PROP_CHANNEL_INTERFACE_ROOM_ROOM_NAME,
TP_PROP_CHANNEL_INTERFACE_ROOM_SERVER,
NULL
};
static const gchar * const muc_tubes_channel_allowed_properties[] = {
- TP_IFACE_CHANNEL ".TargetHandle",
- TP_IFACE_CHANNEL ".TargetID",
+ TP_PROP_CHANNEL_TARGET_HANDLE,
+ TP_PROP_CHANNEL_TARGET_ID,
NULL
};
@@ -1139,12 +1134,12 @@ gabble_muc_factory_type_foreach_channel_class (GType type,
channel_type_value = tp_g_value_slice_new (G_TYPE_STRING);
/* no string value yet - we'll change it for each channel class */
- g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType",
+ g_hash_table_insert (table, TP_PROP_CHANNEL_CHANNEL_TYPE,
channel_type_value);
handle_type_value = tp_g_value_slice_new (G_TYPE_UINT);
g_value_set_uint (handle_type_value, TP_HANDLE_TYPE_ROOM);
- g_hash_table_insert (table, TP_IFACE_CHANNEL ".TargetHandleType",
+ g_hash_table_insert (table, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
handle_type_value);
/* Channel.Type.Text */
@@ -1186,7 +1181,7 @@ ensure_tubes_channel (GabbleMucFactory *self,
GabbleTubesChannel **tubes_chan,
gboolean requested)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
GabbleMucChannel *text_chan;
TpHandle initiator = base_conn->self_handle;
@@ -1212,7 +1207,7 @@ handle_text_channel_request (GabbleMucFactory *self,
TpHandle room,
GError **error)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
TpBaseConnection *conn = TP_BASE_CONNECTION (priv->conn);
GabbleMucChannel *text_chan;
TpHandleSet *handles;
@@ -1239,16 +1234,16 @@ handle_text_channel_request (GabbleMucFactory *self,
return FALSE;
initial_channels = tp_asv_get_boxed (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialChannels",
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS,
TP_ARRAY_TYPE_OBJECT_PATH_LIST);
initial_handles = tp_asv_get_boxed (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeHandles",
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_HANDLES,
DBUS_TYPE_G_UINT_ARRAY);
initial_ids = tp_asv_get_boxed (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeIDs",
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS,
G_TYPE_STRV);
invite_msg = tp_asv_get_string (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InvitationMessage");
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INVITATION_MESSAGE);
room_name = tp_asv_get_string (request_properties,
TP_PROP_CHANNEL_INTERFACE_ROOM_ROOM_NAME);
@@ -1558,7 +1553,7 @@ handle_tubes_channel_request (GabbleMucFactory *self,
TpHandle handle,
GError **error)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
GabbleTubesChannel *tube = NULL;
GabbleMucChannel *gmuc = NULL;
@@ -1615,7 +1610,7 @@ handle_tube_channel_request (GabbleMucFactory *self,
GError **error)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
gboolean can_announce_now = TRUE;
gboolean tubes_channel_created = FALSE;
GabbleTubesChannel *tube = NULL;
@@ -1703,12 +1698,12 @@ handle_stream_tube_channel_request (GabbleMucFactory *self,
/* "Service" is a mandatory, not-fixed property */
service = tp_asv_get_string (request_properties,
- TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service");
+ TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
if (service == NULL)
{
g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
"Request does not contain the mandatory property '%s'",
- TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service");
+ TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
return FALSE;
}
@@ -1734,12 +1729,12 @@ handle_dbus_tube_channel_request (GabbleMucFactory *self,
/* "ServiceName" is a mandatory, not-fixed property */
service = tp_asv_get_string (request_properties,
- TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
+ TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME);
if (service == NULL)
{
g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
"Request does not contain the mandatory property '%s'",
- TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName");
+ TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME);
return FALSE;
}
@@ -1781,7 +1776,7 @@ handle_call_channel_request (GabbleMucFactory *self,
TpHandle handle,
GError **error)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
gboolean initial_audio, initial_video;
GabbleMucChannel *muc;
GabbleCallMucChannel *call;
@@ -1844,6 +1839,27 @@ error:
return FALSE;
}
+typedef gboolean (*ChannelTypeHandlerFunc) (
+ GabbleMucFactory *self,
+ gpointer request_token,
+ GHashTable *request_properties,
+ gboolean require_new,
+ TpHandle room,
+ GError **error);
+
+typedef struct {
+ const gchar *channel_type;
+ ChannelTypeHandlerFunc f;
+} ChannelTypeHandler;
+
+static ChannelTypeHandler channel_type_handlers[] = {
+ { TP_IFACE_CHANNEL_TYPE_TEXT, handle_text_channel_request },
+ { TP_IFACE_CHANNEL_TYPE_TUBES, handle_tubes_channel_request },
+ { TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, handle_stream_tube_channel_request },
+ { TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, handle_dbus_tube_channel_request },
+ { TPY_IFACE_CHANNEL_TYPE_CALL, handle_call_channel_request },
+ { NULL }
+};
static gboolean
gabble_muc_factory_request (GabbleMucFactory *self,
@@ -1856,21 +1872,22 @@ gabble_muc_factory_request (GabbleMucFactory *self,
TpHandle handle;
gboolean conference, room;
const gchar *channel_type;
+ ChannelTypeHandler *h;
handle_type = tp_asv_get_uint32 (request_properties,
- TP_IFACE_CHANNEL ".TargetHandleType", NULL);
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL);
channel_type = tp_asv_get_string (request_properties,
- TP_IFACE_CHANNEL ".ChannelType");
+ TP_PROP_CHANNEL_CHANNEL_TYPE);
/* Conference channels can be anonymous (HandleTypeNone) */
conference = (handle_type == TP_HANDLE_TYPE_NONE &&
!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT) &&
(g_hash_table_lookup (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialChannels") ||
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS) ||
g_hash_table_lookup (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeHandles") ||
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_HANDLES) ||
g_hash_table_lookup (request_properties,
- TP_IFACE_CHANNEL_INTERFACE_CONFERENCE ".InitialInviteeIDs")));
+ TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS)));
room = (handle_type == TP_HANDLE_TYPE_NONE
&& !tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)
@@ -1881,58 +1898,29 @@ gabble_muc_factory_request (GabbleMucFactory *self,
if (handle_type != TP_HANDLE_TYPE_ROOM && !conference && !room)
return FALSE;
- if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT) &&
- tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) &&
- tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) &&
- tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE) &&
- tp_strdiff (channel_type, TPY_IFACE_CHANNEL_TYPE_CALL))
- return FALSE;
-
/* validity already checked by TpBaseConnection */
handle = tp_asv_get_uint32 (request_properties,
- TP_IFACE_CHANNEL ".TargetHandle", NULL);
+ TP_PROP_CHANNEL_TARGET_HANDLE, NULL);
g_assert (conference || room || handle != 0);
- if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT))
- {
- if (handle_text_channel_request (self, request_token,
- request_properties, require_new, handle, &error))
- return TRUE;
- }
- else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES))
- {
- if (handle_tubes_channel_request (self, request_token,
- request_properties, require_new, handle, &error))
- return TRUE;
- }
- else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+ for (h = channel_type_handlers; h->channel_type != NULL; h++)
{
- if (handle_stream_tube_channel_request (self, request_token,
- request_properties, require_new, handle, &error))
- return TRUE;
- }
- else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
- {
- if (handle_dbus_tube_channel_request (self, request_token,
- request_properties, require_new, handle, &error))
- return TRUE;
- }
- else if (!tp_strdiff (channel_type, TPY_IFACE_CHANNEL_TYPE_CALL))
- {
- if (handle_call_channel_request (self, request_token,
- request_properties, require_new, handle, &error))
- return TRUE;
- }
- else
- {
- g_assert_not_reached ();
+ if (tp_strdiff (channel_type, h->channel_type))
+ continue;
+
+ if (!h->f (self, request_token, request_properties, require_new,
+ handle, &error))
+ {
+ tp_channel_manager_emit_request_failed (self, request_token,
+ error->domain, error->code, error->message);
+ g_error_free (error);
+ }
+
+ /* We've handled the request one way or another. */
+ return TRUE;
}
- /* Something failed */
- tp_channel_manager_emit_request_failed (self, request_token,
- error->domain, error->code, error->message);
- g_error_free (error);
- return TRUE;
+ return FALSE;
}
@@ -1975,7 +1963,7 @@ gboolean
gabble_muc_factory_handle_jingle_session (GabbleMucFactory *self,
GabbleJingleSession *session)
{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
+ GabbleMucFactoryPrivate *priv = self->priv;
TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
(TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
TpHandle room;
diff --git a/src/namespaces.h b/src/namespaces.h
index bacbb2ac5..59aded50a 100644
--- a/src/namespaces.h
+++ b/src/namespaces.h
@@ -123,4 +123,12 @@
#define NS_TEMPPRES "urn:xmpp:temppres:0"
#define NS_GOOGLE_SHARED_STATUS "google:shared-status"
+/* This is used by the extension Facebook uses to push you messages you send
+ * using other devices (or the website).
+ *
+ * http://www.youtube.com/watch?v=rSnXE2791yg is not the song I was looking
+ * for, but it's not bad.
+ */
+#define NS_FACEBOOK_MESSAGES "http://www.facebook.com/xmpp/messages"
+
#endif /* __GABBLE_NAMESPACES__H__ */
diff --git a/src/roster.c b/src/roster.c
index 85b654cda..c7caa043b 100644
--- a/src/roster.c
+++ b/src/roster.c
@@ -22,8 +22,6 @@
#include "config.h"
#include "roster.h"
-#define DBUS_API_SUBJECT_TO_CHANGE
-
#include <string.h>
#include <dbus/dbus-glib.h>
diff --git a/src/util.h b/src/util.h
index 9727e60de..fc83ee3b6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -35,8 +35,6 @@
#include "types.h"
-#define CHECK_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0')
-
typedef GSList * NodeIter;
#define node_iter(node) (node->children)
#define node_iter_next(i) (g_slist_next (i))
diff --git a/src/vcard-manager.c b/src/vcard-manager.c
index ba8e834f7..71c3b2b08 100644
--- a/src/vcard-manager.c
+++ b/src/vcard-manager.c
@@ -847,7 +847,7 @@ observe_vcard (GabbleConnection *conn,
{
const gchar *fn = lm_message_node_get_value (fn_node);
- if (!CHECK_STR_EMPTY(fn))
+ if (!tp_str_empty (fn))
{
field = "<FN>";
alias = g_strdup (fn);
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index debb6591b..50cf68313 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -105,6 +105,7 @@ TWISTED_TESTS = \
test-register.py \
text/destroy.py \
text/ensure.py \
+ text/facebook-own-message.py \
text/initiate.py \
text/initiate-requestotron.py \
text/respawn.py \
diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py
index bbb10caa7..2a879d810 100644
--- a/tests/twisted/constants.py
+++ b/tests/twisted/constants.py
@@ -444,6 +444,14 @@ DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_SUCCESSES = 2
DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_READ = 4
DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_DELETED = 8
+DELIVERY_STATUS_UNKNOWN = 0
+DELIVERY_STATUS_DELIVERED = 1
+DELIVERY_STATUS_TEMPORARILY_FAILED = 2
+DELIVERY_STATUS_PERMANENTLY_FAILED = 3
+DELIVERY_STATUS_ACCEPTED = 4
+DELIVERY_STATUS_READ = 5
+DELIVERY_STATUS_DELETED = 6
+
MEDIA_STREAM_ERROR_UNKNOWN = 0
MEDIA_STREAM_ERROR_EOS = 1
MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED = 2
diff --git a/tests/twisted/text/facebook-own-message.py b/tests/twisted/text/facebook-own-message.py
new file mode 100644
index 000000000..a695b3d92
--- /dev/null
+++ b/tests/twisted/text/facebook-own-message.py
@@ -0,0 +1,70 @@
+"""
+Tests exposing Facebook's own-message extension via delivery reports.
+
+I would say that this has been reverse-engineered, but reading the completely
+trivial protocol out of debug logs is hardly reverse-engineering. It isn't
+documented anywhere I can find, mind you.
+"""
+from servicetest import (
+ assertEquals, assertLength, assertContains, wrap_channel, EventPattern,
+ sync_dbus,
+ )
+from gabbletest import exec_test, elem, elem_iq
+import constants as cs
+
+NS_FACEBOOK_MESSAGES = "http://www.facebook.com/xmpp/messages"
+
+def test(q, bus, conn, stream):
+ def send_own_message(to, text):
+ iq = elem_iq(stream, 'set', from_='chat.facebook.com')(
+ elem(NS_FACEBOOK_MESSAGES, 'own-message', to=to, self='false')(
+ elem('body')(text)
+ )
+ )
+ stream.send(iq)
+ q.expect('stream-iq', iq_type='result', iq_id=iq['id'])
+
+ # First, test receiving an own-message stanza for a message sent to a
+ # contact we have an open channel for.
+ jid = '-5678@chat.facebook.com'
+ _, path, props = conn.Requests.EnsureChannel({
+ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT,
+ cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT,
+ cs.TARGET_ID: jid,
+ })
+ channel = wrap_channel(bus.get_object(conn.bus_name, path),
+ 'Text', ['Messages'])
+ handle = props[cs.TARGET_HANDLE]
+
+ text = u'omg omg its ur birthdayy <3 <3 xoxoxoxo'
+ send_own_message(to=jid, text=text)
+ e = q.expect('dbus-signal', signal='MessageReceived')
+ message, = e.args
+ assertLength(1, message)
+ header = message[0]
+
+ assertEquals(handle, header['message-sender'])
+ assertEquals(cs.MT_DELIVERY_REPORT, header['message-type'])
+ assertEquals(cs.DELIVERY_STATUS_ACCEPTED, header['delivery-status'])
+
+ assertContains('delivery-echo', header)
+ echo = header['delivery-echo']
+ echo_header, echo_body = echo
+
+ assertEquals(conn.GetSelfHandle(), echo_header['message-sender'])
+ assertEquals('text/plain', echo_body['content-type'])
+ assertEquals(text, echo_body['content'])
+
+ channel.Text.AcknowledgePendingMessages([header['pending-message-id']])
+ channel.Close()
+
+ # Now test receiving an own-message stanza for a message sent to a contact
+ # we don't have a channel open for. It should be ignored (but acked). This
+ # is consistent with delivery failure reports.
+ q.forbid_events([EventPattern('dbus-signal', signal='MessageReceived')])
+ send_own_message(to='-393939@chat.facebook.com',
+ text=u'please ignore this message')
+ sync_dbus(bus, q, conn)
+
+if __name__ == '__main__':
+ exec_test(test, params={'account': 'test@chat.facebook.com'})
diff --git a/tests/twisted/tools/exec-with-log.sh.in b/tests/twisted/tools/exec-with-log.sh.in
index 0225e5038..11302e6f6 100644
--- a/tests/twisted/tools/exec-with-log.sh.in
+++ b/tests/twisted/tools/exec-with-log.sh.in
@@ -2,8 +2,10 @@
cd "@abs_top_builddir@/tests/twisted/tools"
-GABBLE_DEBUG=all LM_DEBUG=net GIBBER_DEBUG=all WOCKY_DEBUG=all
+GABBLE_DEBUG=all GIBBER_DEBUG=all WOCKY_DEBUG=all
export GABBLE_DEBUG
+export GIBBER_DEBUG
+export WOCKY_DEBUG
GABBLE_TIMING=1
export GABBLE_TIMING
GABBLE_PLUGIN_DIR="@abs_top_builddir@/plugins/.libs"