[telepathy-gabble/master] First attempt at moving the muc backend over to wocky, and moving most of the tubes support into the muc-channel object. Builds, most tests fail as of this check in.
Vivek Dasmohapatra
vivek at collabora.co.uk
Sun Dec 27 11:35:45 PST 2009
---
src/muc-channel.c | 1396 ++++++++++++++++++++++++++++++++---------------------
src/muc-channel.h | 9 +
src/muc-factory.c | 456 +++---------------
3 files changed, 918 insertions(+), 943 deletions(-)
diff --git a/src/muc-channel.c b/src/muc-channel.c
index 05396ea..f339e9a 100644
--- a/src/muc-channel.c
+++ b/src/muc-channel.c
@@ -25,6 +25,9 @@
#include <stdio.h>
#include <string.h>
+#include <wocky/wocky-muc.h>
+#include <wocky/wocky-xmpp-error.h>
+
#include <dbus/dbus-glib.h>
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/debug-ansi.h>
@@ -122,6 +125,8 @@ enum
PROP_CHANNEL_DESTROYED,
PROP_CHANNEL_PROPERTIES,
PROP_SELF_JID,
+ PROP_WOCKY_MUC,
+ PROP_TUBE,
LAST_PROPERTY
};
@@ -159,22 +164,6 @@ typedef enum {
INVALID_AFFILIATION,
} GabbleMucAffiliation;
-static const gchar *muc_roles[NUM_ROLES] =
-{
- "none",
- "visitor",
- "participant",
- "moderator",
-};
-
-static const gchar *muc_affiliations[NUM_AFFILIATIONS] =
-{
- "none",
- "member",
- "admin",
- "owner",
-};
-
/* room properties */
enum
{
@@ -229,13 +218,6 @@ const TpPropertySignature room_property_signatures[NUM_ROOM_PROPS] = {
};
/* private structures */
-
-typedef struct {
- TpHandleSet *members;
- TpHandleSet *owners;
- GHashTable *owner_map;
-} InitialStateAggregator;
-
struct _GabbleMucChannelPrivate
{
GabbleConnection *conn;
@@ -272,35 +254,17 @@ struct _GabbleMucChannelPrivate
gchar *invitation_message;
- /* Aggregate all presences when joining the chatroom */
- InitialStateAggregator *initial_state_aggregator;
+ WockyMuc *wmuc;
+ GabbleTubesChannel *tube;
};
#define GABBLE_MUC_CHANNEL_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), GABBLE_TYPE_MUC_CHANNEL, \
GabbleMucChannelPrivate))
-
-static void
-initial_state_aggregator_free (InitialStateAggregator *isa)
-{
- g_hash_table_destroy (isa->owner_map);
- tp_handle_set_destroy (isa->members);
- tp_handle_set_destroy (isa->owners);
- g_slice_free (InitialStateAggregator, isa);
-}
-
-
static void
gabble_muc_channel_init (GabbleMucChannel *obj)
{
- GabbleMucChannelPrivate *priv;
-
- priv = obj->priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (obj);
-
- priv->initial_state_aggregator = g_slice_new0 (InitialStateAggregator);
- priv->initial_state_aggregator->owner_map = g_hash_table_new (g_direct_hash,
- g_direct_equal);
}
@@ -309,6 +273,77 @@ static TpHandle create_room_identity (GabbleMucChannel *)
#define NUM_SUPPORTED_MESSAGE_TYPES 3
+/* signatures for presence handlers */
+
+static void handle_renamed (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ gpointer data);
+
+static void handle_error (GObject *source,
+ WockyXmppStanza *stanza,
+ WockyXmppError errnum,
+ const gchar *message,
+ gpointer data);
+
+static void handle_join (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ gpointer data);
+
+static void handle_parted (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ const gchar *actor_jid,
+ const gchar *why,
+ const gchar *msg,
+ gpointer data);
+
+static void handle_left (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ WockyMucMember *who,
+ const gchar *actor_jid,
+ const gchar *why,
+ const gchar *msg,
+ gpointer data);
+
+static void handle_presence (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ WockyMucMember *who,
+ gpointer data);
+
+static void handle_perms (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ const gchar *actor,
+ const gchar *why,
+ gpointer data);
+
+/* signatures for message handlers */
+static void handle_message (GObject *source,
+ WockyXmppStanza *stanza,
+ WockyMucMsgType type,
+ const gchar *xmpp_id,
+ time_t stamp,
+ WockyMucMember *who,
+ const gchar *text,
+ const gchar *subject,
+ WockyMucMsgState state,
+ gpointer data);
+
+static void handle_errmsg (GObject *source,
+ WockyXmppStanza *stanza,
+ WockyMucMsgType type,
+ const gchar *xmpp_id,
+ time_t stamp,
+ WockyMucMember *who,
+ const gchar *text,
+ WockyXmppError error,
+ const gchar *etype,
+ gpointer data);
+
static GObject *
gabble_muc_channel_constructor (GType type, guint n_props,
GObjectConstructParam *props)
@@ -337,6 +372,8 @@ gabble_muc_channel_constructor (GType type, guint n_props,
priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (self);
conn = (TpBaseConnection *) priv->conn;
+ priv->tube = NULL;
+
room_handles = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_ROOM);
contact_handles = tp_base_connection_get_handles (conn,
TP_HANDLE_TYPE_CONTACT);
@@ -355,14 +392,40 @@ gabble_muc_channel_constructor (GType type, guint n_props,
/* this causes us to have one ref to the self handle which is unreffed
* at the end of this function */
- priv->initial_state_aggregator->members = tp_handle_set_new (
- contact_handles);
- priv->initial_state_aggregator->owners = tp_handle_set_new (contact_handles);
-
/* initialize our own role and affiliation */
priv->self_role = ROLE_NONE;
priv->self_affil = AFFILIATION_NONE;
+ /* initialise the wocky muc object */
+ {
+ WockyPorter *porter = gabble_connection_get_porter (priv->conn);
+ const gchar *room_jid = tp_handle_inspect (contact_handles, self_handle);
+ gchar *user_jid = gabble_connection_get_full_jid (priv->conn);
+ WockyMuc *wmuc = g_object_new (WOCKY_TYPE_MUC,
+ "porter", porter,
+ "jid", room_jid, /* room at service.name/nick */
+ "user", user_jid, /* user at doma.in/resource */
+ NULL);
+
+ /* various presence handlers */
+ g_signal_connect (wmuc, "nick-change", (GCallback) handle_renamed, self);
+ g_signal_connect (wmuc, "presence", (GCallback) handle_presence, self);
+ g_signal_connect (wmuc, "joined", (GCallback) handle_join, self);
+ g_signal_connect (wmuc, "permissions", (GCallback) handle_perms, self);
+ g_signal_connect (wmuc, "parted", (GCallback) handle_parted, self);
+ g_signal_connect (wmuc, "left", (GCallback) handle_left, self);
+ g_signal_connect (wmuc, "error", (GCallback) handle_error, self);
+
+ /* message handler(s) (just one needed so far) */
+ g_signal_connect (wmuc, "message", (GCallback) handle_message, self);
+ g_signal_connect (wmuc, "message-error",(GCallback) handle_errmsg, self);
+
+ priv->wmuc = wmuc;
+
+ g_free (user_jid);
+ g_object_unref (porter);
+ }
+
/* register object on the bus */
bus = tp_get_bus ();
dbus_g_connection_register_g_object (bus, priv->object_path, obj);
@@ -431,8 +494,7 @@ gabble_muc_channel_constructor (GType type, guint n_props,
g_assert (priv->invitation_message == NULL);
g_array_append_val (members, self_handle);
- tp_group_mixin_add_members (obj, members,
- "", &error);
+ tp_group_mixin_add_members (obj, members, "", &error);
g_assert (error == NULL);
g_array_free (members, TRUE);
}
@@ -731,105 +793,39 @@ create_room_identity (GabbleMucChannel *chan)
GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
}
-static LmMessage *
-create_presence_message (GabbleMucChannel *self,
- LmMessageSubType sub_type,
- LmMessageNode **x_node)
-{
- GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (self);
- LmMessage *msg;
- LmMessageNode *node;
-
- /* only take the connection-wide presence if the MUC protocol doesn't rely on
- * a particular subtype (eg, leaving the room requires type='unavailable') */
- if (sub_type == LM_MESSAGE_SUB_TYPE_NOT_SET)
- {
- /* note that this message doesn't contain capabilities, but that's OK as
- * most IQ-based protocols won't work in a MUC anyway */
- msg = gabble_presence_as_message (priv->conn->self_presence,
- priv->self_jid->str);
- }
- else
- {
- msg = lm_message_new_with_sub_type (priv->self_jid->str,
- LM_MESSAGE_TYPE_PRESENCE, sub_type);
- }
-
- node = lm_message_node_add_child (msg->node, "x", NULL);
- lm_message_node_set_attribute (node, "xmlns", NS_MUC);
-
- if (x_node != NULL)
- *x_node = node;
-
- return msg;
-}
-
static gboolean
-send_join_request (GabbleMucChannel *channel,
+send_join_request (GabbleMucChannel *gmuc,
const gchar *password,
GError **error)
{
- GabbleMucChannelPrivate *priv;
- LmMessage *msg;
- LmMessageNode *x_node;
- gboolean ret;
-
- priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (channel);
-
- /* build the message */
- msg = create_presence_message (channel, LM_MESSAGE_SUB_TYPE_NOT_SET,
- &x_node);
-
- g_free (priv->password);
-
- if (password != NULL)
- {
- priv->password = g_strdup (password);
- lm_message_node_add_child (x_node, "password", password);
- }
-
- g_signal_emit (channel, signals[PRE_PRESENCE], 0, msg);
-
- /* send it */
- ret = _gabble_connection_send (priv->conn, msg, error);
- if (!ret)
- {
- DEBUG ("_gabble_connection_send failed");
- }
- else
- {
- DEBUG ("join request sent");
- }
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
- lm_message_unref (msg);
+ g_object_set (priv->wmuc, "password", password, NULL);
+ wocky_muc_join (priv->wmuc, NULL);
- return ret;
+ /* this used to be a meaningful success/failure return, but the two-stage *
+ * async op involved means we don't have any way of detecting failure here */
+ return TRUE;
}
static gboolean
-send_leave_message (GabbleMucChannel *channel,
+send_leave_message (GabbleMucChannel *gmuc,
const gchar *reason)
{
- GabbleMucChannelPrivate *priv;
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
LmMessage *msg;
GError *error = NULL;
gboolean ret;
- priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (channel);
-
/* build the message */
- msg = create_presence_message (channel, LM_MESSAGE_SUB_TYPE_UNAVAILABLE,
- NULL);
+ msg = (LmMessage *) wocky_muc_create_presence (priv->wmuc,
+ WOCKY_STANZA_SUB_TYPE_UNAVAILABLE, reason, NULL);
- if (reason != NULL)
- {
- lm_message_node_add_child (msg->node, "status", reason);
- }
-
- g_signal_emit (channel, signals[PRE_PRESENCE], 0, msg);
+ g_signal_emit (gmuc, signals[PRE_PRESENCE], 0, msg);
/* send it */
ret = _gabble_connection_send (priv->conn, msg, &error);
+
if (!ret)
{
DEBUG ("_gabble_connection_send failed");
@@ -917,6 +913,12 @@ gabble_muc_channel_get_property (GObject *object,
case PROP_SELF_JID:
g_value_set_string (value, priv->self_jid->str);
break;
+ case PROP_TUBE:
+ if (priv->tube)
+ g_value_set_object (value, priv->tube);
+ else
+ g_value_set_pointer (value, NULL);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -1103,6 +1105,16 @@ gabble_muc_channel_class_init (GabbleMucChannelClass *gabble_muc_channel_class)
g_object_class_install_property (object_class, PROP_SELF_JID,
param_spec);
+ param_spec = g_param_spec_object ("tube", "Tube Channel",
+ "The GabbleTubesChannel associated with this MUC (if any)",
+ GABBLE_TYPE_TUBES_CHANNEL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_TUBE, param_spec);
+
+ param_spec = g_param_spec_object ("wocky-muc", "Wocky MUC Object",
+ "The backend (Wocky) MUC instance",
+ WOCKY_TYPE_MUC, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_WOCKY_MUC, param_spec);
+
signals[READY] =
g_signal_new ("ready",
G_OBJECT_CLASS_TYPE (gabble_muc_channel_class),
@@ -1209,12 +1221,6 @@ gabble_muc_channel_finalize (GObject *object)
DEBUG ("called");
- if (priv->initial_state_aggregator != NULL)
- {
- initial_state_aggregator_free (priv->initial_state_aggregator);
- priv->initial_state_aggregator = NULL;
- }
-
/* free any data held directly by the object here */
tp_handle_unref (room_handles, priv->handle);
@@ -1490,151 +1496,6 @@ handle_nick_conflict (GabbleMucChannel *chan,
return send_join_request (chan, priv->password, tp_error);
}
-/**
- * _gabble_muc_channel_presence_error
- */
-void
-_gabble_muc_channel_presence_error (GabbleMucChannel *chan,
- const gchar *jid,
- LmMessageNode *pres_node)
-{
- GabbleMucChannelPrivate *priv;
- LmMessageNode *error_node;
- GabbleXmppError error;
- TpHandle actor = 0;
- guint reason_code = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
-
- g_assert (GABBLE_IS_MUC_CHANNEL (chan));
-
- priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (chan);
-
- if (strcmp (jid, priv->self_jid->str) != 0)
- {
- DEBUG ("presence error from other jids than self not handled");
- return;
- }
-
- error_node = lm_message_node_get_child (pres_node, "error");
- if (error_node == NULL)
- {
- DEBUG ("missing required node 'error'");
- return;
- }
-
- error = gabble_xmpp_error_from_node (error_node, NULL);
-
- if (priv->state >= MUC_STATE_JOINED)
- {
- DEBUG ("presence error while already member of the channel "
- "-- NYI");
- return;
- }
-
- /* We're not a member, find out why the join request failed
- * and act accordingly. */
- if (error == XMPP_ERROR_NOT_AUTHORIZED)
- {
- /* channel can sit requiring a password indefinitely */
- clear_join_timer (chan);
-
- /* Password already provided and incorrect? */
- if (priv->state == MUC_STATE_AUTH)
- {
- provide_password_return_if_pending (chan, FALSE);
-
- return;
- }
-
- DEBUG ("password required to join, changing password flags");
-
- change_password_flags (chan, TP_CHANNEL_PASSWORD_FLAG_PROVIDE, 0);
-
- g_object_set (chan, "state", MUC_STATE_AUTH, NULL);
- }
- else
- {
- GError *tp_error /* doesn't need initializing */;
-
- switch (error) {
- case XMPP_ERROR_FORBIDDEN:
- tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_BANNED,
- "banned from room");
- reason_code = TP_CHANNEL_GROUP_CHANGE_REASON_BANNED;
- break;
- case XMPP_ERROR_SERVICE_UNAVAILABLE:
- tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_FULL,
- "room is full");
- break;
- case XMPP_ERROR_REGISTRATION_REQUIRED:
- tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_INVITE_ONLY,
- "room is invite only");
- break;
- case XMPP_ERROR_CONFLICT:
- if (handle_nick_conflict (chan, &tp_error))
- return;
-
- break;
- default:
- tp_error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
- "%s", gabble_xmpp_error_description (error));
- break;
- }
-
- g_signal_emit (chan, signals[JOIN_ERROR], 0, tp_error);
-
- close_channel (chan, tp_error->message, FALSE, actor, reason_code);
-
- g_error_free (tp_error);
- }
-}
-
-static GabbleMucRole
-get_role_from_string (const gchar *role)
-{
- guint i;
-
- if (role == NULL)
- {
- return ROLE_VISITOR;
- }
-
- for (i = 0; i < NUM_ROLES; i++)
- {
- if (strcmp (role, muc_roles[i]) == 0)
- {
- return i;
- }
- }
-
- DEBUG ("unknown role '%s' -- defaulting to ROLE_VISITOR", role);
-
- return ROLE_VISITOR;
-}
-
-static GabbleMucAffiliation
-get_affiliation_from_string (const gchar *affil)
-{
- guint i;
-
- if (affil == NULL)
- {
- return AFFILIATION_NONE;
- }
-
- for (i = 0; i < NUM_AFFILIATIONS; i++)
- {
- if (strcmp (affil, muc_affiliations[i]) == 0)
- {
- return i;
- }
- }
-
- DEBUG ("unknown affiliation '%s' -- defaulting to "
- "AFFILIATION_NONE", affil);
-
- return AFFILIATION_NONE;
-}
-
static LmHandlerResult
room_created_submit_reply_cb (GabbleConnection *conn, LmMessage *sent_msg,
LmMessage *reply_msg, GObject *object,
@@ -1896,358 +1757,766 @@ update_permissions (GabbleMucChannel *chan)
tp_intset_destroy (changed_props_flags);
}
+
+
+/* ************************************************************************* */
+/* wocky MUC implementation */
+static GabbleMucRole
+get_role_from_backend (WockyMucRole role)
+{
+ switch (role)
+ {
+ case WOCKY_MUC_ROLE_NONE:
+ return ROLE_NONE;
+ case WOCKY_MUC_ROLE_VISITOR:
+ return ROLE_VISITOR;
+ case WOCKY_MUC_ROLE_PARTICIPANT:
+ return ROLE_PARTICIPANT;
+ case WOCKY_MUC_ROLE_MODERATOR:
+ return ROLE_MODERATOR;
+ default:
+ DEBUG ("unknown role '%d' -- defaulting to ROLE_VISITOR", role);
+ return ROLE_VISITOR;
+ }
+}
+
+static GabbleMucAffiliation
+get_aff_from_backend (WockyMucAffiliation aff)
+{
+ switch (aff)
+ {
+ case WOCKY_MUC_AFFILIATION_OUTCAST:
+ case WOCKY_MUC_AFFILIATION_NONE:
+ return AFFILIATION_NONE;
+ case WOCKY_MUC_AFFILIATION_MEMBER:
+ return AFFILIATION_MEMBER;
+ case WOCKY_MUC_AFFILIATION_ADMIN:
+ return AFFILIATION_ADMIN;
+ case WOCKY_MUC_AFFILIATION_OWNER:
+ return AFFILIATION_OWNER;
+ default:
+ DEBUG ("unknown affiliation %d -- defaulting to AFFILIATION_NONE", aff);
+ return AFFILIATION_NONE;
+ }
+}
+
+/* connect to wocky-muc:SIG_PRESENCE_ERROR */
static void
-handle_unavailable_presence_update (GabbleMucChannel *chan,
- TpHandleRepoIface *contact_handles,
- TpHandle handle,
- TpIntSet *handle_singleton,
- LmMessageNode *item_node,
- const gchar *status_code)
+handle_error (GObject *source,
+ WockyXmppStanza *stanza,
+ WockyXmppError errnum,
+ const gchar *message,
+ gpointer data)
{
- TpGroupMixin *mixin = TP_GROUP_MIXIN (chan);
- LmMessageNode *reason_node, *actor_node;
- const gchar *reason = "", *actor_jid = "";
- TpHandle actor = 0;
- TpChannelGroupChangeReason reason_code = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpChannelGroupChangeReason reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
+
+ g_assert (GABBLE_IS_MUC_CHANNEL (gmuc));
- actor_node = lm_message_node_get_child (item_node, "actor");
- if (actor_node != NULL)
+ if (priv->state >= MUC_STATE_JOINED)
{
- actor_jid = lm_message_node_get_attribute (actor_node, "jid");
- if (actor_jid != NULL)
- {
- actor = tp_handle_ensure (contact_handles, actor_jid, NULL,
- NULL);
- if (actor == 0)
- {
- DEBUG ("ignoring invalid actor JID %s", actor_jid);
- }
- }
+ DEBUG ("presence error while already member of the channel -- NYI");
+ return;
}
- /* Possible reasons we could have been removed from the room:
- * 301 banned
- * 307 kicked
- * 321 "because of an affiliation change" - no reason_code
- * 322 room has become members-only and we're not a member - no
- * reason_code
- * 332 system (server) is being shut down - no reason code
- */
- if (status_code)
+ if (errnum == WOCKY_XMPP_ERROR_NOT_AUTHORIZED)
{
- if (strcmp (status_code, "301") == 0)
+ /* channel can sit requiring a password indefinitely */
+ clear_join_timer (gmuc);
+
+ /* Password already provided and incorrect? */
+ if (priv->state == MUC_STATE_AUTH)
{
- reason_code = TP_CHANNEL_GROUP_CHANGE_REASON_BANNED;
+ provide_password_return_if_pending (gmuc, FALSE);
+ return;
}
- else if (strcmp (status_code, "307") == 0)
+
+ DEBUG ("password required to join, changing password flags");
+ change_password_flags (gmuc, TP_CHANNEL_PASSWORD_FLAG_PROVIDE, 0);
+ g_object_set (gmuc, "state", MUC_STATE_AUTH, NULL);
+ }
+ else
+ {
+ GError *tp_error /* doesn't need initializing */;
+
+ // FIXME, the wocky enum is identical to the gabble enum, but
+ // don't rely on this:
+ switch ((GabbleXmppError) errnum)
{
- reason_code = TP_CHANNEL_GROUP_CHANGE_REASON_KICKED;
+ case XMPP_ERROR_FORBIDDEN:
+ tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_BANNED,
+ "banned from room");
+ reason = TP_CHANNEL_GROUP_CHANGE_REASON_BANNED;
+ break;
+ case XMPP_ERROR_SERVICE_UNAVAILABLE:
+ tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_FULL,
+ "room is full");
+ break;
+
+ case XMPP_ERROR_REGISTRATION_REQUIRED:
+ tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_INVITE_ONLY,
+ "room is invite only");
+ break;
+
+ case XMPP_ERROR_CONFLICT:
+ if (handle_nick_conflict (gmuc, &tp_error))
+ return;
+ break;
+
+ default:
+ tp_error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "%s", gabble_xmpp_error_description (errnum));
+ break;
}
- }
- reason_node = lm_message_node_get_child (item_node, "reason");
- if (reason_node != NULL)
- {
- reason = lm_message_node_get_value (reason_node);
- }
+ g_signal_emit (gmuc, signals[JOIN_ERROR], 0, tp_error);
- if (handle != mixin->self_handle)
- {
- tp_group_mixin_change_members ((GObject *) chan, reason,
- NULL, handle_singleton, NULL, NULL,
- actor, reason_code);
+ close_channel (gmuc, tp_error->message, FALSE, 0, reason);
+ g_error_free (tp_error);
}
- else
+}
+
+static void
+tube_closed_cb (GabbleTubesChannel *chan, gpointer user_data)
+{
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (user_data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpHandle room;
+
+ tp_channel_manager_emit_channel_closed_for_object (gmuc,
+ TP_EXPORTABLE_CHANNEL (chan));
+
+ if (priv->tube != NULL)
{
- close_channel (chan, reason, FALSE, actor, reason_code);
+ priv->tube = NULL;
+ g_object_get (chan, "handle", &room, NULL);
+ DEBUG ("removing MUC tubes channel with handle %d", room);
+ g_object_unref (chan);
}
-
- if (actor)
- tp_handle_unref (contact_handles, actor);
}
-static gboolean
-renamed_by_server (LmMessageNode *x_node)
+static GabbleTubesChannel *
+new_tube (GabbleMucChannel *gmuc,
+ TpHandle initiator,
+ gboolean requested)
{
- gboolean is_self = FALSE;
- gboolean renamed = FALSE;
- NodeIter i;
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
+ char *object_path;
- for (i = node_iter (x_node); i; i = node_iter_next (i))
- {
- LmMessageNode *child = node_iter_data (i);
- const gchar *code;
+ g_assert (priv->tube == NULL);
- if (strcmp (child->name, "status") != 0)
- continue;
+ object_path = g_strdup_printf ("%s/MucTubesChannel%u",
+ conn->object_path, priv->handle);
- code = lm_message_node_get_attribute (child, "code");
+ DEBUG ("creating new tubes chan, object path %s", object_path);
- if (!tp_strdiff (code, "110"))
- is_self = TRUE;
- else if (!tp_strdiff (code, "210"))
- renamed = TRUE;
- }
+ priv->tube = g_object_new (GABBLE_TYPE_TUBES_CHANNEL,
+ "connection", priv->conn,
+ "object-path", object_path,
+ "handle", priv->handle,
+ "handle-type", TP_HANDLE_TYPE_ROOM,
+ "muc", gmuc,
+ "initiator-handle", initiator,
+ "requested", requested,
+ NULL);
- return (is_self && renamed);
+ g_signal_connect (priv->tube, "closed", (GCallback) tube_closed_cb, gmuc);
+
+ tp_channel_manager_emit_new_channel (gmuc,
+ TP_EXPORTABLE_CHANNEL (priv->tube), NULL);
+
+ g_free (object_path);
+
+ return priv->tube;
}
+/* ************************************************************************* */
+/* presence related signal handlers */
+
+/* not actually a signal handler, but used by them: *
+ * creates a tube if none exists, and then prods the presence handler *
+ * in the gabble tubes implementation to do whatever else needs to be done */
static void
-handle_member_added (GabbleMucChannel *chan,
- GabbleMucChannelPrivate *priv,
- TpGroupMixin *mixin,
- TpHandleRepoIface *contact_handles,
- TpHandle handle,
- TpIntSet *handle_singleton,
- LmMessageNode *x_node,
- LmMessageNode *item_node)
+handle_tube_presence (GabbleMucChannel *gmuc,
+ TpHandle from,
+ WockyXmppStanza *stanza)
{
- TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
- const gchar *owner_jid = lm_message_node_get_attribute (item_node, "jid");
- TpHandle owner_handle = 0;
- TpIntSet *old_self_handle_singleton = NULL;
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ WockyXmppNode *node = stanza->node;
+
+ if (from == 0)
+ return;
- if (owner_jid != NULL)
+ if (priv->tube == NULL)
{
- owner_handle = tp_handle_ensure (contact_handles, owner_jid,
- GUINT_TO_POINTER (GABBLE_JID_GLOBAL), NULL);
+ WockyXmppNode *tubes;
+ tubes = wocky_xmpp_node_get_child_ns (node, "tubes", NS_TUBES);
+
+ /* presence doesn't contain tubes information, no need
+ * to create a tubes channel */
+ if (tubes == NULL)
+ return;
- if (owner_handle == 0)
- DEBUG ("Invalid owner handle '%s', treating as no owner", owner_jid);
+ /* MUC Tubes channels (as opposed to the individual tubes) don't
+ * have a well-defined initiator (they're a consensus) so use 0 */
+ priv->tube = new_tube (gmuc, 0, FALSE);
}
- if (renamed_by_server (x_node))
- {
- old_self_handle_singleton = tp_intset_new ();
- tp_intset_add (old_self_handle_singleton, mixin->self_handle);
+ gabble_tubes_channel_presence_updated (priv->tube, from, node);
+}
- tp_group_mixin_change_self_handle ((GObject *) chan, handle);
- }
- if (handle == mixin->self_handle &&
- owner_handle != conn->self_handle)
- {
- /* In XEP-0045-compliant MUCs, if we get presence for the jid we asked
- * for (or for another jid, with status 110 and 210) then we know it's
- * us. There can't be another user in the MUC with the nick we asked for:
- * the service MUST reject us with code 409/"conflict" in this case. So,
- * if someone in the room has the nick we want, it's us.
- *
- * If the MUC service fails to comply with this requirement, we get
- * hopelessly confused. Given that the service isn't required to label
- * our own presence as 110 ("this is you") and there's no way to label a
- * presence for the jid we asked for as "not you" it's not possible for a
- * client not to get hopelessly confused if the service is broken. So
- * this is the best we can do.
- */
- DEBUG ("Overriding ownership of channel-specific handle %u "
- "from %u to %u because I know it's mine",
- mixin->self_handle, owner_handle, conn->self_handle);
+/* connect to wocky-muc:SIG_PARTED, which we will receive when the MUC tells *
+ * us that we have left the channel */
+static void
+handle_parted (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ const gchar *actor_jid,
+ const gchar *why,
+ const gchar *msg,
+ gpointer data)
+{
+ WockyMuc *wmuc = WOCKY_MUC (source);
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpChannelGroupChangeReason reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
+ TpHandleRepoIface *contact_repo =
+ tp_base_connection_get_handles ((TpBaseConnection *) priv->conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpIntSet *handles = NULL;
+ TpHandle member = 0;
+ TpHandle actor = 0;
+ int x = 0;
+ static const gpointer banned = GUINT_TO_POINTER (WOCKY_MUC_CODE_BANNED);
+ static const gpointer const kicked[] =
+ { GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED),
+ GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED_AFFILIATION),
+ GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED_ROOM_PRIVATISED),
+ GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED_SHUTDOWN),
+ NULL };
+ const char *jid = wocky_muc_jid (wmuc);
- if (owner_handle != 0)
- tp_handle_unref (contact_handles, owner_handle);
+ member = tp_handle_ensure (contact_repo, jid, NULL, NULL);
- tp_handle_ref (contact_handles, conn->self_handle);
- owner_handle = conn->self_handle;
+ if (member == 0)
+ {
+ DEBUG ("bizarre: ignoring our own malformed MUC JID '%s'", jid);
+ return;
}
- if (priv->initial_state_aggregator == NULL)
+ handles = tp_intset_new ();
+ tp_intset_add (handles, member);
+
+ if (actor_jid != NULL)
{
- /* we've already had the initial batch of presence stanzas */
- tp_group_mixin_add_handle_owner ((GObject *) chan, handle,
- owner_handle);
- tp_group_mixin_change_members ((GObject *) chan, "",
- handle_singleton, NULL, NULL, NULL, 0, 0);
+ actor = tp_handle_ensure (contact_repo, actor_jid, NULL, NULL);
+ if (actor == 0)
+ DEBUG ("ignoring invalid actor JID %s", actor_jid);
}
+
+ if (g_hash_table_lookup (code, banned) != NULL)
+ reason = TP_CHANNEL_GROUP_CHANGE_REASON_BANNED;
else
- {
- /* aggregate this presence */
- tp_handle_set_add (priv->initial_state_aggregator->members,
- handle);
+ for (x = 0; kicked[x] != NULL; x++)
+ {
+ if (g_hash_table_lookup (code, kicked[x]) != NULL)
+ reason = TP_CHANNEL_GROUP_CHANGE_REASON_KICKED;
+ }
- g_hash_table_insert (priv->initial_state_aggregator->owner_map,
- GUINT_TO_POINTER (handle), GUINT_TO_POINTER (owner_handle));
+ /* handle_tube_presence creates tubes if need be, so bypass it here: */
+ if (priv->tube != NULL)
+ gabble_tubes_channel_presence_updated (priv->tube, member, stanza->node);
- if (owner_handle != 0)
- tp_handle_set_add (priv->initial_state_aggregator->owners,
- owner_handle);
+ close_channel (gmuc, why, FALSE, actor, reason);
- /* Do not emit one signal per presence. Instead, get all
- * presences, and add them in priv->initial_state_aggregator.
- * When we get the last presence, emit the signal. The last
- * presence is ourselves. */
- if (handle == mixin->self_handle)
- {
- /* Add all handle owners in a single operation */
- tp_group_mixin_add_handle_owners ((GObject *) chan,
- priv->initial_state_aggregator->owner_map);
-
- /* Change all presences in a single operation */
- tp_group_mixin_change_members ((GObject *) chan, "",
- tp_handle_set_peek (
- priv->initial_state_aggregator->members),
- old_self_handle_singleton, NULL, NULL, 0, 0);
-
- initial_state_aggregator_free (
- priv->initial_state_aggregator);
- priv->initial_state_aggregator = NULL;
- g_object_set (chan, "state", MUC_STATE_JOINED, NULL);
- }
- }
+ if (actor != 0)
+ tp_handle_unref (contact_repo, actor);
+ tp_intset_destroy (handles);
+ tp_handle_unref (contact_repo, member);
+}
+
+
+/* connect to wocky-muc:SIG_LEFT, which we will receive when the MUC informs *
+ * us someone [else] has left the channel */
+static void
+handle_left (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ WockyMucMember *who,
+ const gchar *actor_jid,
+ const gchar *why,
+ const gchar *msg,
+ gpointer data)
+{
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpChannelGroupChangeReason reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
+ TpHandleRepoIface *contact_repo =
+ tp_base_connection_get_handles ((TpBaseConnection *) priv->conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpIntSet *handles = NULL;
+ TpHandle member = 0;
+ TpHandle actor = 0;
+ int x = 0;
+ static const gpointer banned = GUINT_TO_POINTER (WOCKY_MUC_CODE_BANNED);
+ static const gpointer const kicked[] =
+ { GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED),
+ GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED_AFFILIATION),
+ GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED_ROOM_PRIVATISED),
+ GUINT_TO_POINTER (WOCKY_MUC_CODE_KICKED_SHUTDOWN),
+ NULL };
+
+ member = tp_handle_ensure (contact_repo, who->from, NULL, NULL);
- if (owner_handle != 0)
+ if (member == 0)
{
- if (handle != mixin->self_handle)
- {
- /* If at least one other handle in the channel has an owner,
- * the HANDLE_OWNERS_NOT_AVAILABLE flag should be removed.
- */
- tp_group_mixin_change_flags ((GObject *) chan, 0,
- TP_CHANNEL_GROUP_FLAG_HANDLE_OWNERS_NOT_AVAILABLE);
- }
+ DEBUG ("ignoring malformed MUC JID '%s'", who->from);
+ return;
+ }
- g_signal_emit (chan, signals[CONTACT_JOIN], 0, owner_handle);
+ handles = tp_intset_new ();
+ tp_intset_add (handles, member);
- tp_handle_unref (contact_handles, owner_handle);
+ if (actor_jid != NULL)
+ {
+ actor = tp_handle_ensure (contact_repo, actor_jid, NULL, NULL);
+ if (actor == 0)
+ DEBUG ("ignoring invalid actor JID %s", actor_jid);
}
- if (old_self_handle_singleton != NULL)
- tp_intset_destroy (old_self_handle_singleton);
+ if (g_hash_table_lookup (code, banned) != NULL)
+ reason = TP_CHANNEL_GROUP_CHANGE_REASON_BANNED;
+ else
+ for (x = 0; kicked[x] != NULL; x++)
+ {
+ if (g_hash_table_lookup (code, kicked[x]) != NULL)
+ reason = TP_CHANNEL_GROUP_CHANGE_REASON_KICKED;
+ }
+
+ /* handle_tube_presence creates tubes if need be, so bypass it here: */
+ if (priv->tube != NULL)
+ gabble_tubes_channel_presence_updated (priv->tube, member, stanza->node);
+
+ tp_group_mixin_change_members (data, why, NULL, handles, NULL, NULL,
+ actor, reason);
+
+ if (actor != 0)
+ tp_handle_unref (contact_repo, actor);
+ tp_intset_destroy (handles);
+ tp_handle_unref (contact_repo, member);
}
+/* connect to wocky-muc:SIG_PERM_CHANGE, which we will receive when the *
+ * MUC informs us our role/affiliation has been altered */
static void
-handle_presence_update (GabbleMucChannel *chan,
- TpHandleRepoIface *contact_handles,
- TpHandle handle,
- TpIntSet *handle_singleton,
- LmMessageNode *x_node,
- LmMessageNode *item_node,
- const gchar *status_code)
+handle_perms (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ const gchar *actor,
+ const gchar *why,
+ gpointer data)
{
- GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (chan);
- TpGroupMixin *mixin = TP_GROUP_MIXIN (chan);
+ WockyMuc *wmuc = WOCKY_MUC (source);
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpHandle myself = TP_GROUP_MIXIN (gmuc)->self_handle;
- if (!tp_handle_set_is_member (mixin->members, handle))
- handle_member_added (chan, priv, mixin, contact_handles, handle,
- handle_singleton, x_node, item_node);
+ priv->self_role = get_role_from_backend (wocky_muc_role (wmuc));
+ priv->self_affil = get_aff_from_backend (wocky_muc_affiliation (wmuc));
- if (handle == mixin->self_handle)
+ room_properties_update (gmuc);
+ update_permissions (gmuc);
+
+ handle_tube_presence (gmuc, myself, stanza);
+}
+
+/* connect to wocky-muc:SIG_NICK_CHANGE, which we will receive when the *
+ * MUC informs us our nick has been changed for some reason */
+static void
+handle_renamed (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ gpointer data)
+{
+ WockyMuc *wmuc = WOCKY_MUC (source);
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpHandleRepoIface *contact_repo =
+ tp_base_connection_get_handles ((TpBaseConnection *) priv->conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpIntSet *old_self = tp_intset_new ();
+ const gchar *me = wocky_muc_jid (wmuc);
+ const gchar *me2 = wocky_muc_user (wmuc);
+ TpHandle myself = tp_handle_ensure (contact_repo, me,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
+ TpHandle userid = tp_handle_ensure (contact_repo, me2,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
+
+ tp_intset_add (old_self, TP_GROUP_MIXIN (gmuc)->self_handle);
+ tp_group_mixin_change_self_handle (data, myself);
+ tp_group_mixin_add_handle_owner (data, myself, userid);
+ tp_group_mixin_change_members (data, "", NULL, old_self, NULL, NULL, 0, 0);
+
+ handle_tube_presence (gmuc, myself, stanza);
+
+ tp_intset_destroy (old_self);
+ tp_handle_unref (contact_repo, userid);
+ tp_handle_unref (contact_repo, myself);
+}
+
+struct _roster_foreach
+{
+ GabbleMucChannel *gmuc;
+ TpHandleRepoIface *contact_repo;
+ TpHandleSet *members;
+ TpHandleSet *owners;
+ GHashTable *omap;
+};
+
+static void
+roster_presence (gpointer key, gpointer val, gpointer data)
+{
+ const WockyMucMember *member = val;
+ struct _roster_foreach *blob = data;
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (blob->gmuc);
+ TpHandleSet *members = blob->members;
+ TpHandleSet *owners = blob->owners;
+ GHashTable *omap = blob->omap;
+ TpHandleRepoIface *contact_repo = blob->contact_repo;
+ TpHandle owner = 0;
+ TpHandle handle = tp_handle_ensure (contact_repo, member->from,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
+
+ if (member->jid != NULL)
{
- const gchar *role, *affil;
- GabbleMucRole new_role;
- GabbleMucAffiliation new_affil;
+ owner = tp_handle_ensure (contact_repo, member->jid,
+ GUINT_TO_POINTER (GABBLE_JID_GLOBAL), NULL);
+ if (owner == 0)
+ DEBUG ("Invalid owner handle '%s', treating as no owner", member->jid);
+ else
+ tp_handle_set_add (owners, owner);
+ }
- /* accept newly-created room settings before we send anything
- * below which queryies them. */
- if (status_code && strcmp (status_code, "201") == 0)
- {
- LmMessage *msg;
- LmMessageNode *node;
- GError *error = NULL;
+ tp_handle_set_add (members, handle);
+ g_hash_table_insert (omap,
+ GUINT_TO_POINTER (handle),
+ GUINT_TO_POINTER (owner));
- msg = lm_message_new_with_sub_type (priv->jid,
- LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
+ tp_handle_unref (contact_repo, handle);
+ /* make a note of the fact that owner JIDs are visible to us */
+ /* notify whomever that an identifiable contact joined the MUC */
+ if (owner != 0)
+ {
+ tp_group_mixin_change_flags (G_OBJECT (data), 0,
+ TP_CHANNEL_GROUP_FLAG_HANDLE_OWNERS_NOT_AVAILABLE);
+ g_signal_emit (gmuc, signals[CONTACT_JOIN], 0, owner);
+ tp_handle_unref (contact_repo, owner);
+ }
+}
+
+/* connect to wocky_muc SIG_JOINED which we should receive when we receive *
+ * the final (ie our own) presence in the roster: (note that if our nick was *
+ * changed by the MUC we will already have received a SIG_NICK_CHANGE: */
+static void
+handle_join (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ gpointer data)
+{
+ WockyMuc *wmuc = WOCKY_MUC (source);
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpHandleRepoIface *contact_repo =
+ tp_base_connection_get_handles ((TpBaseConnection *) priv->conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpHandleSet *members = tp_handle_set_new (contact_repo);
+ TpHandleSet *owners = tp_handle_set_new (contact_repo);
+ GHashTable *omap = g_hash_table_new (g_direct_hash, g_direct_equal);
+ GHashTable *member_jids = wocky_muc_members (wmuc);
+ const gchar *me = wocky_muc_jid (wmuc);
+ const gchar *me2 = wocky_muc_user (wmuc);
+ TpHandle myself = tp_handle_ensure (contact_repo, me,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
+ TpHandle userid = tp_handle_ensure (contact_repo, me2,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
- node = lm_message_node_add_child (msg->node, "query", NULL);
- lm_message_node_set_attribute (node, "xmlns", NS_MUC_OWNER);
+ struct _roster_foreach blob = { gmuc, contact_repo, members, owners, omap };
- node = lm_message_node_add_child (node, "x", NULL);
- lm_message_node_set_attributes (node,
- "xmlns", NS_X_DATA,
- "type", "submit",
- NULL);
+ g_hash_table_foreach (member_jids, roster_presence, &blob);
- if (!_gabble_connection_send_with_reply (priv->conn, msg,
- room_created_submit_reply_cb, G_OBJECT (chan), NULL,
- &error))
- {
- DEBUG ("failed to send submit message: %s",
- error->message);
- g_error_free (error);
+ g_hash_table_insert (omap,
+ GUINT_TO_POINTER (userid),
+ GUINT_TO_POINTER (myself));
- lm_message_unref (msg);
- close_channel (chan, NULL, TRUE, 0,
- TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
+ tp_handle_set_add (members, myself);
+ tp_group_mixin_add_handle_owners (source, omap);
+ tp_group_mixin_change_members (source, "",
+ tp_handle_set_peek (members), NULL, NULL, NULL, 0, 0);
- return;
- }
+ /* accept the config of the room if it was created for us: */
+ if (g_hash_table_lookup (code, (gpointer) WOCKY_MUC_CODE_NEW_ROOM))
+ {
+ GError *error = NULL;
+ gboolean sent = FALSE;
+ WockyXmppStanza *accept = wocky_xmpp_stanza_build (
+ WOCKY_STANZA_TYPE_IQ,
+ WOCKY_STANZA_SUB_TYPE_SET,
+ WOCKY_NODE, "query", WOCKY_NODE_XMLNS, WOCKY_NS_MUC_OWN,
+ WOCKY_NODE, "x", WOCKY_NODE_XMLNS, WOCKY_XMPP_NS_DATA,
+ WOCKY_NODE_ATTRIBUTE, "type", "submit",
+ WOCKY_NODE_END,
+ WOCKY_NODE_END,
+ WOCKY_STANZA_END);
+
+ sent = _gabble_connection_send_with_reply (priv->conn, accept,
+ room_created_submit_reply_cb, data, NULL, &error);
+
+ g_object_unref (accept);
+
+ if (!sent)
+ {
+ DEBUG ("failed to send submit message: %s", error->message);
+ g_error_free (error);
+
+ g_object_unref (accept);
+ close_channel (gmuc, NULL, TRUE, 0,
+ TP_CHANNEL_GROUP_CHANGE_REASON_NONE);
- lm_message_unref (msg);
+ goto out;
}
+ }
- /* Update room properties */
- room_properties_update (chan);
+ g_object_set (gmuc, "state", MUC_STATE_JOINED, NULL);
+
+ out:
+ tp_handle_unref (contact_repo, myself);
+ tp_handle_unref (contact_repo, userid);
+ tp_handle_set_destroy (members);
+ tp_handle_set_destroy (owners);
+ g_hash_table_unref (omap);
+ g_hash_table_unref (member_jids);
+}
- /* update permissions after requesting new properties so that if we
- * become an owner, we get our configuration form reply after the
- * discovery reply, so we know whether there is a description
- * property before we try and decide whether we can write to it. */
- role = lm_message_node_get_attribute (item_node, "role");
- affil = lm_message_node_get_attribute (item_node, "affiliation");
- new_role = get_role_from_string (role);
- new_affil = get_affiliation_from_string (affil);
+/* connect to wocky-muc:SIG_PRESENCE, which is fired for presences that are *
+ * NOT our own after the initial roster has been received: */
+static void
+handle_presence (GObject *source,
+ WockyXmppStanza *stanza,
+ GHashTable *code,
+ WockyMucMember *who,
+ gpointer data)
+{
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpHandleRepoIface *contact_repo =
+ tp_base_connection_get_handles ((TpBaseConnection *) priv->conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpHandle owner = 0;
+ TpHandle handle = tp_handle_ensure (contact_repo, who->from,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
+ TpHandleSet *handles = tp_handle_set_new (contact_repo);
- if (new_role != priv->self_role || new_affil != priv->self_affil)
- {
- priv->self_role = new_role;
- priv->self_affil = new_affil;
+ /* is the 'real' jid field of the presence set? If so, use it: */
+ if (who->jid != NULL)
+ {
+ /* ******************************************************* */
+ /* OLPC Hack: *
+ * We drop OLPC Gadget's inspector presence as activities *
+ * doesn't have to see it as a member of the room and the *
+ * presence cache should ignore it as well. */
+ if (!tp_strdiff (who->jid, priv->conn->olpc_gadget_activity))
+ goto out;
+ /* ******************************************************* */
- update_permissions (chan);
+ owner = tp_handle_ensure (contact_repo, who->jid,
+ GUINT_TO_POINTER (GABBLE_JID_GLOBAL), NULL);
+ if (owner == 0)
+ {
+ DEBUG ("Invalid owner handle '%s' ignored", who->jid);
+ }
+ else /* note that JIDs are known to us in this MUC */
+ {
+ tp_group_mixin_change_flags (G_OBJECT (data), 0,
+ TP_CHANNEL_GROUP_FLAG_HANDLE_OWNERS_NOT_AVAILABLE);
}
}
+
+ /* add the member in quesion */
+ tp_handle_set_add (handles, handle);
+ tp_group_mixin_change_members (data, "", tp_handle_set_peek (handles),
+ NULL, NULL, NULL, 0, 0);
+
+ /* record the owner (0 for no owner) */
+ tp_group_mixin_add_handle_owner (data, handle, owner);
+
+ handle_tube_presence (gmuc, handle, stanza);
+
+ /* zap the handle refs we created */
+ out:
+ tp_handle_unref (contact_repo, handle);
+ if (owner != 0)
+ tp_handle_unref (contact_repo, owner);
+ tp_handle_set_destroy (handles);
}
-/**
- * _gabble_muc_channel_member_presence_updated:
- *
- * Handles <presence> stanzas with type='unavailable' or other non-'error'
- * types, updating channel members and/or closing the channel as appropriate.
- * (<presence type='error'> is handled by _gabble_muc_channel_presence_error.)
- */
-void
-_gabble_muc_channel_member_presence_updated (GabbleMucChannel *chan,
- TpHandle handle,
- LmMessage *message,
- LmMessageNode *x_node,
- LmMessageNode *item_node)
-{
- GabbleMucChannelPrivate *priv;
- TpBaseConnection *conn;
- TpIntSet *handle_singleton;
- LmMessageNode *status_node;
- const gchar *status_code = NULL;
- TpHandleRepoIface *contact_handles;
+/* ************************************************************************ */
+/* message signal handlers */
- DEBUG ("called");
+static void
+handle_message (GObject *source,
+ WockyXmppStanza *stanza,
+ WockyMucMsgType type,
+ const gchar *xmpp_id,
+ time_t stamp,
+ WockyMucMember *who,
+ const gchar *text,
+ const gchar *subject,
+ WockyMucMsgState state,
+ gpointer data)
+{
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
+ gboolean from_member = (who != NULL);
- g_assert (GABBLE_IS_MUC_CHANNEL (chan));
- g_assert (handle != 0);
+ TpChannelTextMessageType msg_type;
+ TpHandleRepoIface *repo;
+ TpHandleType handle_type;
+ TpHandle from;
- priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (chan);
- conn = (TpBaseConnection *) priv->conn;
- contact_handles = tp_base_connection_get_handles (conn,
- TP_HANDLE_TYPE_CONTACT);
+ if (from_member)
+ {
+ handle_type = TP_HANDLE_TYPE_CONTACT;
+ repo = tp_base_connection_get_handles (conn, handle_type);
+ from = tp_handle_ensure (repo, who->from,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
- status_node = lm_message_node_get_child (x_node, "status");
+ if (from == 0)
+ {
+ DEBUG ("Message from MUC member with no handle, discarding.");
+ return;
+ }
+ }
+ else /* directly from MUC itself */
+ {
+ handle_type = TP_HANDLE_TYPE_ROOM;
+ repo = tp_base_connection_get_handles (conn, handle_type);
+ from = priv->handle;
+ tp_handle_ref (repo, from);
+ }
- if (status_node != NULL)
- status_code = lm_message_node_get_attribute (status_node, "code");
+ switch (type)
+ {
+ case WOCKY_MUC_MSG_NORMAL:
+ msg_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
+ break;
+ case WOCKY_MUC_MSG_ACTION:
+ msg_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION;
+ break;
+ default:
+ msg_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE;
+ }
- /* update channel members according to presence */
- handle_singleton = tp_intset_new ();
- tp_intset_add (handle_singleton, handle);
+ if (text != NULL)
+ _gabble_muc_channel_receive (gmuc,
+ msg_type, handle_type, from, stamp, xmpp_id, text, stanza,
+ GABBLE_TEXT_CHANNEL_SEND_NO_ERROR, TP_DELIVERY_STATUS_DELIVERED);
- if (lm_message_get_sub_type (message) == LM_MESSAGE_SUB_TYPE_UNAVAILABLE)
- handle_unavailable_presence_update (chan, contact_handles, handle,
- handle_singleton, item_node, status_code);
- else
- handle_presence_update (chan, contact_handles, handle, handle_singleton,
- x_node, item_node, status_code);
+ if (from_member && state != WOCKY_MUC_MSG_STATE_NONE)
+ {
+ gint tp_msg_state;
+ switch (state)
+ {
+ case WOCKY_MUC_MSG_STATE_ACTIVE:
+ tp_msg_state = TP_CHANNEL_CHAT_STATE_ACTIVE;
+ break;
+ case WOCKY_MUC_MSG_STATE_TYPING:
+ tp_msg_state = TP_CHANNEL_CHAT_STATE_COMPOSING;
+ break;
+ case WOCKY_MUC_MSG_STATE_INACTIVE:
+ tp_msg_state = TP_CHANNEL_CHAT_STATE_INACTIVE;
+ break;
+ case WOCKY_MUC_MSG_STATE_PAUSED:
+ tp_msg_state = TP_CHANNEL_CHAT_STATE_PAUSED;
+ break;
+ case WOCKY_MUC_MSG_STATE_GONE:
+ tp_msg_state = TP_CHANNEL_CHAT_STATE_GONE;
+ default:
+ tp_msg_state = TP_CHANNEL_CHAT_STATE_ACTIVE;
+ }
+ _gabble_muc_channel_state_receive (gmuc, tp_msg_state, from);
+ }
+
+ if (subject != NULL)
+ _gabble_muc_channel_handle_subject (gmuc, msg_type, handle_type, from,
+ stamp, subject, stanza);
- tp_intset_destroy (handle_singleton);
+ tp_handle_unref (repo, from);
}
+static void
+handle_errmsg (GObject *source,
+ WockyXmppStanza *stanza,
+ WockyMucMsgType type,
+ const gchar *xmpp_id,
+ time_t stamp,
+ WockyMucMember *who,
+ const gchar *text,
+ WockyXmppError error,
+ const gchar *etype,
+ gpointer data)
+{
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data);
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+ TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
+ gboolean from_member = (who != NULL);
+ GabbleXmppErrorType status = XMPP_ERROR_TYPE_UNDEFINED;
+ TpChannelTextSendError tp_err = TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN;
+ TpDeliveryStatus ds = TP_DELIVERY_STATUS_DELIVERED;
+ TpHandleRepoIface *repo = NULL;
+ TpHandleType handle_type;
+ TpHandle from = 0;
+
+ if (from_member)
+ {
+ handle_type = TP_HANDLE_TYPE_CONTACT;
+ repo = tp_base_connection_get_handles (conn, handle_type);
+ from = tp_handle_ensure (repo, who->from,
+ GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
+
+ if (from == 0)
+ {
+ DEBUG ("Message from MUC member with no handle, discarding.");
+ return;
+ }
+ }
+ else /* directly from MUC itself */
+ {
+ handle_type = TP_HANDLE_TYPE_ROOM;
+ repo = tp_base_connection_get_handles (conn, handle_type);
+ from = priv->handle;
+ tp_handle_ref (repo, from);
+ }
+
+ tp_err = gabble_tp_send_error_from_wocky_xmpp_error (error);
+ status = gabble_xmpp_error_type_to_enum (etype);
+
+ if (status == XMPP_ERROR_TYPE_WAIT)
+ ds = TP_DELIVERY_STATUS_TEMPORARILY_FAILED;
+ else
+ ds = TP_DELIVERY_STATUS_PERMANENTLY_FAILED;
+
+ if (text != NULL)
+ _gabble_muc_channel_receive (gmuc, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
+ handle_type, from, stamp, xmpp_id, text, stanza, tp_err, ds);
+
+ tp_handle_unref (repo, from);
+}
+/* ************************************************************************* */
/**
* _gabble_muc_channel_handle_subject: handle room subject updates
*/
@@ -3354,7 +3623,9 @@ gabble_muc_channel_send_presence (GabbleMucChannel *self,
if (priv->state < MUC_STATE_INITIATED)
return TRUE;
- msg = create_presence_message (self, LM_MESSAGE_SUB_TYPE_NOT_SET, NULL);
+ msg = (LmMessage *) wocky_muc_create_presence (priv->wmuc,
+ WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL);
+
g_signal_emit (self, signals[PRE_PRESENCE], 0, msg);
result = _gabble_connection_send (priv->conn, msg, error);
@@ -3362,6 +3633,41 @@ gabble_muc_channel_send_presence (GabbleMucChannel *self,
return result;
}
+GabbleTubesChannel *
+gabble_muc_channel_open_tube (GabbleMucChannel *gmuc,
+ TpHandle initiator,
+ gboolean requested)
+{
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+
+ if (priv->tube == NULL)
+ priv->tube = new_tube (gmuc, initiator, requested);
+
+ if (priv->tube != NULL)
+ return g_object_ref (priv->tube);
+
+ return NULL;
+}
+
+
+void
+gabble_muc_channel_close_tube (GabbleMucChannel *gmuc)
+{
+ GabbleMucChannelPrivate *priv = GABBLE_MUC_CHANNEL_GET_PRIVATE (gmuc);
+
+ if (priv->tube != NULL)
+ {
+ TpHandle room;
+ GabbleTubesChannel *tube = priv->tube;
+
+ priv->tube = NULL;
+ g_object_get (tube, "handle", &room, NULL);
+ DEBUG ("removing MUC tubes channel with handle %d", room);
+ gabble_tubes_channel_close (tube);
+ g_object_unref (tube);
+ }
+}
+
static void
channel_iface_init (gpointer g_iface, gpointer iface_data)
{
diff --git a/src/muc-channel.h b/src/muc-channel.h
index a8481ec..a7e5ce3 100644
--- a/src/muc-channel.h
+++ b/src/muc-channel.h
@@ -31,6 +31,7 @@
#include <telepathy-glib/properties-mixin.h>
#include "types.h"
+#include "tubes-channel.h"
G_BEGIN_DECLS
@@ -106,6 +107,14 @@ gboolean gabble_muc_channel_send_presence (GabbleMucChannel *chan,
gboolean gabble_muc_channel_send_invite (GabbleMucChannel *self,
const gchar *jid, const gchar *message, GError **error);
+GabbleTubesChannel *
+gabble_muc_channel_open_tube (GabbleMucChannel *gmuc,
+ TpHandle initiator,
+ gboolean requested);
+
+void gabble_muc_channel_close_tube (GabbleMucChannel *gmuc);
+
+
G_END_DECLS
#endif /* #ifndef __GABBLE_MUC_CHANNEL_H__*/
diff --git a/src/muc-factory.c b/src/muc-factory.c
index fd3b10d..eda7719 100644
--- a/src/muc-factory.c
+++ b/src/muc-factory.c
@@ -68,11 +68,8 @@ struct _GabbleMucFactoryPrivate
gulong status_changed_id;
LmMessageHandler *message_cb;
- LmMessageHandler *presence_cb;
/* GUINT_TO_POINTER(room_handle) => (GabbleMucChannel *) */
GHashTable *text_channels;
- /* GUINT_TO_POINTER(room_handle) => (GabbleTubesChannel *) */
- GHashTable *tubes_channels;
/* Tubes channels which will be considered ready when the corresponding
* text channel is created.
* Borrowed GabbleMucChannel => borrowed GabbleTubesChannel */
@@ -108,8 +105,6 @@ gabble_muc_factory_init (GabbleMucFactory *fac)
priv->text_channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, g_object_unref);
- priv->tubes_channels = g_hash_table_new_full (g_direct_hash, g_direct_equal,
- NULL, g_object_unref);
priv->text_needed_for_tubes = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, NULL);
priv->tubes_needed_for_tube = g_hash_table_new_full (g_direct_hash,
@@ -122,7 +117,6 @@ gabble_muc_factory_init (GabbleMucFactory *fac)
g_direct_equal, NULL, NULL);
priv->message_cb = NULL;
- priv->presence_cb = NULL;
priv->conn = NULL;
priv->dispose_has_run = FALSE;
@@ -156,7 +150,6 @@ gabble_muc_factory_dispose (GObject *object)
gabble_muc_factory_close_all (fac);
g_assert (priv->text_channels == NULL);
- g_assert (priv->tubes_channels == NULL);
g_assert (priv->text_needed_for_tubes == NULL);
g_assert (priv->tubes_needed_for_tube == NULL);
g_assert (priv->queued_requests == NULL);
@@ -251,49 +244,12 @@ muc_channel_closed_cb (GabbleMucChannel *chan, gpointer user_data)
DEBUG ("removing MUC channel with handle %d", room_handle);
- if (priv->tubes_channels != NULL)
- {
- GabbleTubesChannel *tubes;
-
- tubes = g_hash_table_lookup (priv->tubes_channels,
- GUINT_TO_POINTER (room_handle));
- if (tubes != NULL)
- gabble_tubes_channel_close (tubes);
- }
-
- g_hash_table_remove (priv->text_channels,
- GUINT_TO_POINTER (room_handle));
- }
-}
-
-/**
- * tubes_channel_closed_cb:
- *
- * Signal callback for when a tubes channel is closed. Removes the references
- * that MucFactory holds to them.
- */
-static void
-tubes_channel_closed_cb (GabbleTubesChannel *chan, gpointer user_data)
-{
- GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
- TpHandle room_handle;
-
- tp_channel_manager_emit_channel_closed_for_object (fac,
- TP_EXPORTABLE_CHANNEL (chan));
-
- if (priv->tubes_channels != NULL)
- {
- g_object_get (chan, "handle", &room_handle, NULL);
-
- DEBUG ("removing MUC tubes channel with handle %d", room_handle);
+ gabble_muc_channel_close_tube (chan);
- g_hash_table_remove (priv->tubes_channels,
- GUINT_TO_POINTER (room_handle));
+ g_hash_table_remove (priv->text_channels, GUINT_TO_POINTER (room_handle));
}
}
-
static void
muc_ready_cb (GabbleMucChannel *text_chan,
gpointer data)
@@ -478,49 +434,7 @@ new_muc_channel (GabbleMucFactory *fac,
return chan;
}
-/**
- * new_tubes_channel:
- *
- * Creates the GabbleTubesChannel object with the given parameters.
- */
-static GabbleTubesChannel *
-new_tubes_channel (GabbleMucFactory *fac,
- TpHandle room,
- GabbleMucChannel *muc,
- TpHandle initiator,
- gboolean requested)
-{
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
- TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
- GabbleTubesChannel *chan;
- char *object_path;
-
- g_assert (g_hash_table_lookup (priv->tubes_channels,
- GUINT_TO_POINTER (room)) == NULL);
-
- object_path = g_strdup_printf ("%s/MucTubesChannel%u",
- conn->object_path, room);
-
- DEBUG ("creating new tubes chan, object path %s", object_path);
-
- chan = g_object_new (GABBLE_TYPE_TUBES_CHANNEL,
- "connection", priv->conn,
- "object-path", object_path,
- "handle", room,
- "handle-type", TP_HANDLE_TYPE_ROOM,
- "muc", muc,
- "initiator-handle", initiator,
- "requested", requested,
- NULL);
-
- g_signal_connect (chan, "closed", (GCallback) tubes_channel_closed_cb, fac);
-
- g_hash_table_insert (priv->tubes_channels, GUINT_TO_POINTER (room), chan);
-
- g_free (object_path);
-
- return chan;
-}
+// tubes_channel_closed_cb
static void
do_invite (GabbleMucFactory *fac,
@@ -785,24 +699,13 @@ muc_factory_message_cb (LmMessageHandler *handler,
{
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data);
GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
- TpBaseConnection *conn = (TpBaseConnection *) priv->conn;
- TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
- TP_HANDLE_TYPE_CONTACT);
- TpHandleRepoIface *room_repo = tp_base_connection_get_handles (conn,
- TP_HANDLE_TYPE_ROOM);
- const gchar *from, *body, *subject, *id;
+ const gchar *from, *body, *id;
time_t stamp;
TpChannelTextMessageType msgtype;
- TpHandleRepoIface *handle_source;
- TpHandleType handle_type;
- TpHandle room_handle, handle;
- GabbleMucChannel *chan;
gint state;
TpChannelTextSendError send_error;
TpDeliveryStatus delivery_status;
- gchar *room;
- LmMessageNode *subj_node;
if (!gabble_message_util_parse_incoming_message (message, &from, &stamp,
&msgtype, &id, &body, &state, &send_error, &delivery_status))
@@ -822,236 +725,12 @@ muc_factory_message_cb (LmMessageHandler *handler,
if (process_obsolete_invite (fac, message, from, body, send_error))
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- /* check if a room with the jid exists */
- room = gabble_remove_resource (from);
- room_handle = tp_handle_lookup (room_repo, room, NULL, NULL);
- g_free (room);
-
- /* the message is nothing to do with MUC, do nothing */
- if (room_handle == 0)
- {
- return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
- }
-
- /* find the MUC channel */
- chan = g_hash_table_lookup (priv->text_channels,
- GUINT_TO_POINTER (room_handle));
-
- if (chan == NULL)
- {
- NODE_DEBUG (message->node, "ignoring MUC message from known "
- "handle with no corresponding channel");
-
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- /* get the handle of the sender, which is either the room
- * itself or one of its members */
- if (strchr (from, '/') == NULL)
- {
- handle_source = room_repo;
- handle_type = TP_HANDLE_TYPE_ROOM;
- handle = room_handle;
- tp_handle_ref (room_repo, handle);
- }
- else
- {
- handle_source = contact_repo;
- handle_type = TP_HANDLE_TYPE_CONTACT;
- handle = tp_handle_ensure (contact_repo, from,
- GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
-
- if (handle == 0)
- {
- NODE_DEBUG (message->node, "MUC message from invalid JID; ignoring");
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- /* anything other than a type="groupchat" is from the person directly and
- * simply relayed by the MUC, so should be left to the normal handlers */
- if (lm_message_get_sub_type (message) != LM_MESSAGE_SUB_TYPE_GROUPCHAT)
- {
- tp_handle_unref (contact_repo, handle);
-
- return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
- }
- }
-
- if (body != NULL)
- _gabble_muc_channel_receive (chan, msgtype, handle_type, handle, stamp,
- id, body, message, send_error, delivery_status);
-
- if (send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR)
- {
- if (state != -1 && handle_type == TP_HANDLE_TYPE_CONTACT)
- _gabble_muc_channel_state_receive (chan, state, handle);
-
- subj_node = lm_message_node_get_child (message->node, "subject");
- if (subj_node != NULL)
- {
- subject = lm_message_node_get_value (subj_node);
- _gabble_muc_channel_handle_subject (chan, msgtype, handle_type, handle,
- stamp, subject, message);
- }
- }
-
- tp_handle_unref (handle_source, handle);
-
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
-}
-
-
-/**
- * connection_presence_muc_cb:
- * @handler: #LmMessageHandler for this message
- * @connection: #LmConnection that originated the message
- * @message: the presence message
- * @user_data: callback data
- *
- * Called by loudmouth when we get an incoming <presence>.
- */
-static LmHandlerResult
-muc_factory_presence_cb (LmMessageHandler *handler,
- LmConnection *lmconn,
- LmMessage *msg,
- gpointer user_data)
-{
- GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data);
- GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
- TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
- (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
- TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
- (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
- const char *from;
- LmMessageSubType sub_type;
- GabbleMucChannel *muc_chan = NULL;
- LmMessageNode *x_node;
- TpHandle room_handle;
-
- g_assert (lmconn == priv->conn->lmconn);
-
- from = lm_message_node_get_attribute (msg->node, "from");
-
- if (from == NULL)
- {
- NODE_DEBUG (msg->node,
- "presence stanza without from attribute, ignoring");
- return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
- }
-
- sub_type = lm_message_get_sub_type (msg);
-
- room_handle = gabble_get_room_handle_from_jid (room_repo, from);
- if (room_handle != 0)
- muc_chan = g_hash_table_lookup (priv->text_channels,
- GUINT_TO_POINTER (room_handle));
-
- /* is it an error and for a MUC? */
- if (sub_type == LM_MESSAGE_SUB_TYPE_ERROR
- && muc_chan != NULL)
- {
- _gabble_muc_channel_presence_error (muc_chan, from, msg->node);
-
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- x_node = lm_message_node_get_child_with_namespace (msg->node, "x",
- NS_MUC_USER);
-
- /* is it a MUC member presence? */
- if (x_node != NULL)
- {
- if (muc_chan != NULL)
- {
- TpHandle handle;
- LmMessageNode *item_node;
- const gchar *owner_jid;
-
- handle = tp_handle_ensure (contact_repo, from,
- GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
- if (handle == 0)
- {
- NODE_DEBUG (msg->node,
- "discarding MUC presence from malformed jid");
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- item_node = lm_message_node_get_child (x_node, "item");
- if (item_node == NULL)
- {
- DEBUG ("node missing 'item' child, ignoring");
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- owner_jid = lm_message_node_get_attribute (item_node, "jid");
- /* We drop OLPC Gadget's inspector presence as activities
- * doesn't have to see it as a member of the room and the
- * presence cache should ignore it as well. */
- if (owner_jid != NULL &&
- !tp_strdiff (owner_jid, priv->conn->olpc_gadget_activity))
- {
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- _gabble_muc_channel_member_presence_updated (muc_chan, handle,
- msg, x_node, item_node);
- tp_handle_unref (contact_repo, handle);
- }
- else
- {
- NODE_DEBUG (msg->node, "discarding unexpected MUC member presence");
-
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
- }
-
- /* is it presence from an in-MUC JID containing tubes info? */
-
- if (muc_chan != NULL)
- {
- TpHandle handle;
- GabbleTubesChannel *tubes_chan;
-
- tubes_chan = g_hash_table_lookup (priv->tubes_channels,
- GUINT_TO_POINTER (room_handle));
- if (tubes_chan == NULL)
- {
- LmMessageNode *tubes_node;
-
- tubes_node = lm_message_node_get_child_with_namespace (
- msg->node, "tubes", NS_TUBES);
-
- if (tubes_node == NULL)
- /* presence doesn't contain tubes information, no need
- * to create a tubes channel */
- return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-
- /* MUC Tubes channels (as opposed to the individual tubes) don't
- * have a well-defined initiator (they're a consensus) so use 0 */
- tubes_chan = new_tubes_channel (fac, room_handle, muc_chan,
- 0, FALSE);
- tp_channel_manager_emit_new_channel (fac,
- TP_EXPORTABLE_CHANNEL (tubes_chan), NULL);
- }
-
- handle = tp_handle_ensure (contact_repo, from,
- GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
- if (handle == 0)
- {
- NODE_DEBUG (msg->node,
- "discarding Tubes presence from malformed jid");
- return LM_HANDLER_RESULT_REMOVE_MESSAGE;
- }
-
- gabble_tubes_channel_presence_updated (tubes_chan, handle,
- msg);
- tp_handle_unref (contact_repo, handle);
- }
-
+ /* we used to check if a room with the jid exists, instead at this *
+ * point we stop caring: actual MUC messages are handled internally *
+ * by the wocky muc implementation */
return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
-
void
gabble_muc_factory_broadcast_presence (GabbleMucFactory *self)
{
@@ -1068,7 +747,6 @@ gabble_muc_factory_broadcast_presence (GabbleMucFactory *self)
}
}
-
static void
gabble_muc_factory_associate_request (GabbleMucFactory *self,
gpointer channel,
@@ -1153,27 +831,14 @@ gabble_muc_factory_close_all (GabbleMucFactory *self)
g_hash_table_destroy (tmp);
}
- if (priv->tubes_channels != NULL)
- {
- GHashTable *tmp = priv->tubes_channels;
- priv->tubes_channels = NULL;
- g_hash_table_destroy (tmp);
- }
-
if (priv->message_cb != NULL)
{
DEBUG ("removing callbacks");
- g_assert (priv->presence_cb != NULL);
lm_connection_unregister_message_handler (priv->conn->lmconn,
priv->message_cb, LM_MESSAGE_TYPE_MESSAGE);
lm_message_handler_unref (priv->message_cb);
priv->message_cb = NULL;
-
- lm_connection_unregister_message_handler (priv->conn->lmconn,
- priv->presence_cb, LM_MESSAGE_TYPE_PRESENCE);
- lm_message_handler_unref (priv->presence_cb);
- priv->presence_cb = NULL;
}
}
@@ -1191,20 +856,12 @@ connection_status_changed_cb (GabbleConnection *conn,
case TP_CONNECTION_STATUS_CONNECTING:
DEBUG ("adding callbacks");
g_assert (priv->message_cb == NULL);
- g_assert (priv->presence_cb == NULL);
priv->message_cb = lm_message_handler_new (muc_factory_message_cb,
self, NULL);
lm_connection_register_message_handler (priv->conn->lmconn,
priv->message_cb, LM_MESSAGE_TYPE_MESSAGE,
LM_HANDLER_PRIORITY_NORMAL);
-
- priv->presence_cb = lm_message_handler_new (
- muc_factory_presence_cb, self, NULL);
- lm_connection_register_message_handler (priv->conn->lmconn,
- priv->presence_cb, LM_MESSAGE_TYPE_PRESENCE,
- LM_HANDLER_PRIORITY_NORMAL);
-
break;
case TP_CONNECTION_STATUS_DISCONNECTED:
@@ -1241,8 +898,20 @@ _foreach_slave (gpointer key, gpointer value, gpointer user_data)
{
struct _ForeachData *data = (struct _ForeachData *) user_data;
TpExportableChannel *channel = TP_EXPORTABLE_CHANNEL (value);
+ GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (value);
+ GabbleTubesChannel *tube = NULL;
data->foreach (channel, data->user_data);
+
+ g_object_get (gmuc, "tube", &tube, NULL);
+
+ if (tube != NULL)
+ {
+ channel = TP_EXPORTABLE_CHANNEL (tube);
+ data->foreach (channel, data->user_data);
+ gabble_tubes_channel_foreach (tube, data->foreach, data->user_data);
+ g_object_unref (tube);
+ }
}
static void
@@ -1253,27 +922,11 @@ gabble_muc_factory_foreach_channel (TpChannelManager *manager,
GabbleMucFactory *fac = GABBLE_MUC_FACTORY (manager);
GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac);
struct _ForeachData data;
- GHashTableIter iter;
- gpointer value;
data.user_data = user_data;
data.foreach = foreach;
g_hash_table_foreach (priv->text_channels, _foreach_slave, &data);
-
- g_hash_table_iter_init (&iter, priv->tubes_channels);
- while (g_hash_table_iter_next (&iter, NULL, &value))
- {
- TpExportableChannel *chan = TP_EXPORTABLE_CHANNEL (value);
-
- /* Add channels of type Channel.Type.Tubes */
- foreach (chan, user_data);
-
- /* Add channels of type Channel.Type.{Stream|DBus}Tube which live in the
- * GabbleTubesChannel object */
- gabble_tubes_channel_foreach (GABBLE_TUBES_CHANNEL (chan), foreach,
- user_data);
- }
}
@@ -1320,13 +973,16 @@ gabble_muc_factory_handle_si_stream_request (GabbleMucFactory *self,
GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
(TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
- GabbleTubesChannel *chan;
+ GabbleMucChannel *gmuc = NULL;
+ GabbleTubesChannel *tube = NULL;
g_return_if_fail (tp_handle_is_valid (room_repo, room_handle, NULL));
- chan = g_hash_table_lookup (priv->tubes_channels,
+ gmuc = g_hash_table_lookup (priv->text_channels,
GUINT_TO_POINTER (room_handle));
- if (chan == NULL)
+ g_object_get (gmuc, "tube", &tube, NULL);
+
+ if (tube == NULL)
{
GError e = { GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
"No tubes channel available for this MUC" };
@@ -1336,7 +992,8 @@ gabble_muc_factory_handle_si_stream_request (GabbleMucFactory *self,
return;
}
- gabble_tubes_channel_bytestream_offered (chan, bytestream, msg);
+ gabble_tubes_channel_bytestream_offered (tube, bytestream, msg);
+ g_object_unref (tube);
}
GabbleMucChannel *
@@ -1421,17 +1078,18 @@ ensure_tubes_channel (GabbleMucFactory *self,
GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn;
GabbleMucChannel *text_chan;
+ TpHandle initiator = base_conn->self_handle;
gboolean result;
result = ensure_muc_channel (self, priv, handle, &text_chan, FALSE);
- *tubes_chan = new_tubes_channel (self, handle, text_chan,
- base_conn->self_handle, requested);
+ /* this refs the tube channel object */
+ *tubes_chan = gabble_muc_channel_open_tube (text_chan, initiator, requested);
if (!result)
- {
- g_hash_table_insert (priv->text_needed_for_tubes, text_chan, *tubes_chan);
- }
+ g_hash_table_insert (priv->text_needed_for_tubes, text_chan, *tubes_chan);
+
+ g_object_unref (tubes_chan);
return result;
}
@@ -1485,7 +1143,8 @@ handle_tubes_channel_request (GabbleMucFactory *self,
GError **error)
{
GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
- GabbleTubesChannel *tubes_chan;
+ GabbleTubesChannel *tube = NULL;
+ GabbleMucChannel *gmuc = NULL;
if (tp_channel_manager_asv_has_unknown_properties (request_properties,
muc_tubes_channel_fixed_properties,
@@ -1493,10 +1152,12 @@ handle_tubes_channel_request (GabbleMucFactory *self,
error))
return FALSE;
- tubes_chan = g_hash_table_lookup (priv->tubes_channels,
- GUINT_TO_POINTER (handle));
+ gmuc = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle));
- if (tubes_chan != NULL)
+ if (gmuc != NULL)
+ g_object_get (gmuc, "tube", &tube, NULL);
+
+ if (tube != NULL)
{
if (require_new)
{
@@ -1507,22 +1168,21 @@ handle_tubes_channel_request (GabbleMucFactory *self,
else
{
tp_channel_manager_emit_request_already_satisfied (self,
- request_token, TP_EXPORTABLE_CHANNEL (tubes_chan));
+ request_token, TP_EXPORTABLE_CHANNEL (tube));
}
}
- else if (ensure_tubes_channel (self, handle, &tubes_chan, TRUE))
+ else if (ensure_tubes_channel (self, handle, &tube, TRUE))
{
GSList *list = NULL;
list = g_slist_prepend (list, request_token);
tp_channel_manager_emit_new_channel (self,
- TP_EXPORTABLE_CHANNEL (tubes_chan), list);
+ TP_EXPORTABLE_CHANNEL (tube), list);
g_slist_free (list);
}
else
{
- gabble_muc_factory_associate_request (self, tubes_chan,
- request_token);
+ gabble_muc_factory_associate_request (self, tube, request_token);
}
return TRUE;
@@ -1540,29 +1200,29 @@ handle_tube_channel_request (GabbleMucFactory *self,
GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (self);
gboolean can_announce_now = TRUE;
gboolean tubes_channel_created = FALSE;
- GabbleTubesChannel *tubes_chan;
+ GabbleTubesChannel *tube;
+ GabbleMucChannel * gmuc;
GabbleTubeIface *new_channel;
- tubes_chan = g_hash_table_lookup (priv->tubes_channels,
- GUINT_TO_POINTER (handle));
- if (tubes_chan == NULL)
+ gmuc = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle));
+ g_object_get (gmuc, "tube", &tube, NULL);
+
+ if (tube == NULL)
{
/* Need to create a tubes channel */
- if (!ensure_tubes_channel (self, handle, &tubes_chan, FALSE))
+ if (!ensure_tubes_channel (self, handle, &tube, FALSE))
{
/* We have to wait the tubes channel before announcing */
can_announce_now = FALSE;
-
- gabble_muc_factory_associate_request (self, tubes_chan,
- request_token);
+ gabble_muc_factory_associate_request (self, tube, request_token);
}
tubes_channel_created = TRUE;
}
- g_assert (tubes_chan != NULL);
+ g_assert (tube != NULL);
- new_channel = gabble_tubes_channel_tube_request (tubes_chan,
+ new_channel = gabble_tubes_channel_tube_request (tube,
request_token, request_properties, TRUE);
g_assert (new_channel != NULL);
@@ -1575,7 +1235,7 @@ handle_tube_channel_request (GabbleMucFactory *self,
NULL, NULL);
if (tubes_channel_created)
- g_hash_table_insert (channels, tubes_chan, NULL);
+ g_hash_table_insert (channels, tube, NULL);
request_tokens = g_slist_prepend (NULL, request_token);
@@ -1589,11 +1249,11 @@ handle_tube_channel_request (GabbleMucFactory *self,
{
GSList *l;
- l = g_hash_table_lookup (priv->tubes_needed_for_tube, tubes_chan);
- g_hash_table_steal (priv->tubes_needed_for_tube, tubes_chan);
+ l = g_hash_table_lookup (priv->tubes_needed_for_tube, tube);
+ g_hash_table_steal (priv->tubes_needed_for_tube, tube);
l = g_slist_prepend (l, new_channel);
- g_hash_table_insert (priv->tubes_needed_for_tube, tubes_chan, l);
+ g_hash_table_insert (priv->tubes_needed_for_tube, tube, l);
}
return TRUE;
--
1.5.6.5
More information about the telepathy-commits
mailing list