28
27
#include <dbus/dbus-glib.h>
29
28
#include <dbus/dbus-glib-lowlevel.h>
30
29
#include <glib-object.h>
31
#include <loudmouth/loudmouth.h>
32
#include <wocky/wocky-connector.h>
33
#include <wocky/wocky-disco-identity.h>
34
#include <wocky/wocky-tls-handler.h>
35
#include <wocky/wocky-ping.h>
36
#include <wocky/wocky-utils.h>
37
#include <wocky/wocky-xmpp-error.h>
38
#include <wocky/wocky-data-form.h>
30
#include <wocky/wocky.h>
39
31
#include <telepathy-glib/channel-manager.h>
40
32
#include <telepathy-glib/dbus.h>
41
33
#include <telepathy-glib/enums.h>
98
92
const GArray *contacts, GHashTable *attributes_hash);
99
93
static void conn_contact_capabilities_fill_contact_attributes (GObject *obj,
100
94
const GArray *contacts, GHashTable *attributes_hash);
95
static void gabble_plugin_connection_iface_init (
96
GabblePluginConnectionInterface *iface,
98
static gchar *_gabble_plugin_connection_get_full_jid (
99
GabblePluginConnection *conn);
100
static TpBaseContactList *_gabble_plugin_connection_get_contact_list (
101
GabblePluginConnection *conn);
102
103
G_DEFINE_TYPE_WITH_CODE(GabbleConnection,
103
104
gabble_connection,
288
291
* to connected */
289
292
guint waiting_connected;
294
/* Used to cancel pending calls to _gabble_connection_send_with_reply(). It
295
* should not be necessary because by the time we get to cancelling this (in
296
* our dispose()) the porter should be long dead and have called back for all
297
* outstanding requests. However... call this paranoia, and a desire to
298
* delete the Loudmouth compatibility layer without spending any more hours
299
* untangling even more old code.
301
GCancellable *iq_reply_cancellable;
291
303
gboolean closing;
292
304
/* gobject housekeeping */
293
305
gboolean dispose_has_run;
296
static guint sig_id_porter_available = 0;
298
308
static void connection_capabilities_update_cb (GabblePresenceCache *cache,
300
310
const GabbleCapabilitySet *old_cap_set,
365
376
"connection", self,
379
#ifdef ENABLE_FILE_TRANSFER
368
380
self->ft_manager = gabble_ft_manager_new (self);
369
381
g_ptr_array_add (channel_managers, self->ft_manager);
371
384
/* plugin channel managers */
372
385
loader = gabble_plugin_loader_dup ();
373
tmp = gabble_plugin_loader_create_channel_managers (loader, conn);
386
tmp = gabble_plugin_loader_create_channel_managers (loader,
374
388
g_object_unref (loader);
376
390
g_ptr_array_foreach (tmp, add_to_array, channel_managers);
379
393
return channel_managers;
397
gabble_plugin_connection_iface_init (
398
GabblePluginConnectionInterface *iface,
401
iface->add_sidecar_own_caps = gabble_connection_add_sidecar_own_caps;
402
iface->add_sidecar_own_caps_full=
403
gabble_connection_add_sidecar_own_caps_full;
404
iface->get_session = gabble_connection_get_session;
405
iface->get_full_jid = _gabble_plugin_connection_get_full_jid;
406
iface->get_jid_for_caps = gabble_connection_get_jid_for_caps;
407
iface->pick_best_resource_for_caps =
408
gabble_connection_pick_best_resource_for_caps;
409
iface->get_contact_list = _gabble_plugin_connection_get_contact_list;
410
iface->get_caps = gabble_connection_get_caps;
383
414
gabble_connection_constructor (GType type,
384
415
guint n_construct_properties,
1164
1195
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1167
* @self: a connection
1170
* Emitted when the WockyPorter becomes available.
1172
sig_id_porter_available = g_signal_new ("porter-available",
1173
G_OBJECT_CLASS_TYPE (gabble_connection_class),
1174
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL,
1175
g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, WOCKY_TYPE_PORTER);
1177
1197
gabble_connection_class->properties_class.interfaces = prop_interfaces;
1178
1198
tp_dbus_properties_mixin_class_init (object_class,
1179
1199
G_STRUCT_OFFSET (GabbleConnectionClass, properties_class));
1233
1253
tp_clear_object (&priv->connector);
1234
1254
tp_clear_object (&self->session);
1236
/* ownership of our porter was transferred to the LmConnection */
1256
/* The porter was borrowed from the session. */
1237
1257
priv->porter = NULL;
1238
tp_clear_pointer (&self->lmconn, lm_connection_unref);
1258
/* Cancel any outstanding _gabble_connection_send_with_reply() requests. */
1259
g_cancellable_cancel (priv->iq_reply_cancellable);
1260
tp_clear_object (&priv->iq_reply_cancellable);
1240
1262
g_hash_table_unref (priv->client_caps);
1241
1263
gabble_capability_set_free (priv->all_caps);
1398
1429
* _gabble_connection_send
1400
* Send an LmMessage and trap network errors appropriately.
1431
* Send an WockyStanza and trap network errors appropriately.
1403
_gabble_connection_send (GabbleConnection *conn, LmMessage *msg, GError **error)
1434
_gabble_connection_send (GabbleConnection *conn, WockyStanza *msg, GError **error)
1405
1436
g_assert (GABBLE_IS_CONNECTION (conn));
1407
if (conn->lmconn == NULL || conn->priv->porter == NULL)
1438
if (conn->priv->porter == NULL)
1409
1440
g_set_error_literal (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR,
1410
1441
"connection is disconnected");
1431
1462
GabbleConnectionMsgReplyFunc reply_func;
1433
1464
GabbleConnection *conn;
1434
LmMessage *sent_msg;
1465
WockyStanza *sent_msg;
1435
1466
gpointer user_data;
1437
1468
GObject *object;
1438
1469
gboolean object_alive;
1439
1470
} GabbleMsgHandlerData;
1441
static LmHandlerResult
1442
message_send_reply_cb (LmMessageHandler *handler,
1443
LmConnection *connection,
1444
LmMessage *reply_msg,
1447
GabbleMsgHandlerData *handler_data = user_data;
1448
LmMessageSubType sub_type;
1450
sub_type = lm_message_get_sub_type (reply_msg);
1452
/* Is it a reply to this message? If we're talking to another loudmouth,
1453
* they can send us messages which have the same ID as ones we send. :-O */
1454
if (sub_type != LM_MESSAGE_SUB_TYPE_RESULT &&
1455
sub_type != LM_MESSAGE_SUB_TYPE_ERROR)
1457
return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
1460
if (handler_data->object_alive && handler_data->reply_func != NULL)
1462
return handler_data->reply_func (handler_data->conn,
1463
handler_data->sent_msg,
1465
handler_data->object,
1466
handler_data->user_data);
1469
return LM_HANDLER_RESULT_REMOVE_MESSAGE;
1473
1473
message_send_object_destroy_notify_cb (gpointer data,
1474
1474
GObject *where_the_object_was)
1496
1494
g_slice_free (GabbleMsgHandlerData, handler_data);
1498
message_send_reply_cb (
1500
GAsyncResult *result,
1503
GabbleMsgHandlerData *handler_data = user_data;
1505
if (handler_data->object_alive && handler_data->reply_func != NULL)
1507
WockyPorter *porter = WOCKY_PORTER (source);
1508
GError *error = NULL;
1509
WockyStanza *stanza = wocky_porter_send_iq_finish (porter, result, &error);
1513
handler_data->reply_func (handler_data->conn,
1514
handler_data->sent_msg,
1516
handler_data->object,
1517
handler_data->user_data);
1518
g_object_unref (stanza);
1522
DEBUG ("send_iq_async failed: %s", error->message);
1523
g_error_free (error);
1527
msg_handler_data_free (handler_data);
1500
1531
* _gabble_connection_send_with_reply
1502
* Send a tracked LmMessage and trap network errors appropriately.
1533
* Send a tracked WockyStanza and trap network errors appropriately.
1504
1535
* If object is non-NULL the handler will follow the lifetime of that object,
1505
1536
* which means that if the object is destroyed the callback will not be invoked.
1507
* if reply_func is NULL the reply will be ignored but connection_iq_unknown_cb
1538
* if reply_func is NULL the reply will be ignored.
1511
1541
_gabble_connection_send_with_reply (GabbleConnection *conn,
1513
1543
GabbleConnectionMsgReplyFunc reply_func,
1514
1544
GObject *object,
1515
1545
gpointer user_data,
1516
1546
GError **error)
1518
LmMessageHandler *handler;
1548
GabbleConnectionPrivate *priv;
1519
1549
GabbleMsgHandlerData *handler_data;
1521
GError *lmerror = NULL;
1523
1551
g_assert (GABBLE_IS_CONNECTION (conn));
1525
if (conn->lmconn == NULL)
1554
if (priv->porter == NULL)
1527
1556
g_set_error_literal (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR,
1528
1557
"connection is disconnected");
1532
lm_message_ref (msg);
1534
1563
handler_data = g_slice_new (GabbleMsgHandlerData);
1535
1564
handler_data->reply_func = reply_func;
1549
handler = lm_message_handler_new (message_send_reply_cb, handler_data,
1550
message_send_handler_destroy_cb);
1552
ret = lm_connection_send_with_reply (conn->lmconn, msg, handler, &lmerror);
1555
DEBUG ("failed: %s", lmerror->message);
1559
g_set_error (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR,
1560
"message send failed: %s", lmerror->message);
1563
g_error_free (lmerror);
1566
lm_message_handler_unref (handler);
1578
wocky_porter_send_iq_async (priv->porter, msg,
1579
priv->iq_reply_cancellable, message_send_reply_cb, handler_data);
1571
1584
static void connect_iq_callbacks (GabbleConnection *conn);
1572
1585
static gboolean iq_disco_cb (WockyPorter *, WockyStanza *, gpointer);
1573
1586
static gboolean iq_version_cb (WockyPorter *, WockyStanza *, gpointer);
1574
static gboolean iq_unknown_cb (WockyPorter *, WockyStanza *, gpointer);
1575
1587
static void connection_disco_cb (GabbleDisco *, GabbleDiscoRequest *,
1576
const gchar *, const gchar *, LmMessageNode *, GError *, gpointer);
1588
const gchar *, const gchar *, WockyNode *, GError *, gpointer);
1577
1589
static void decrement_waiting_connected (GabbleConnection *connection);
1578
1590
static void connection_initial_presence_cb (GObject *, GAsyncResult *,
1738
for (i = node_iter (result); i; i = node_iter_next (i))
1752
wocky_node_iter_init (&i, result, "identity", NULL);
1753
while (wocky_node_iter_next (&i, &child))
1740
LmMessageNode *child = node_iter_data (i);
1755
const gchar *category = wocky_node_get_attribute (child,
1757
const gchar *type = wocky_node_get_attribute (child, "type");
1742
if (!tp_strdiff (child->name, "identity"))
1759
if (!tp_strdiff (category, "pubsub") &&
1760
!tp_strdiff (type, "pep"))
1744
const gchar *category = lm_message_node_get_attribute (child,
1746
const gchar *type = lm_message_node_get_attribute (child, "type");
1748
if (!tp_strdiff (category, "pubsub") &&
1749
!tp_strdiff (type, "pep"))
1751
DEBUG ("Server advertises PEP support in our jid features");
1752
conn->features |= GABBLE_CONNECTION_FEATURES_PEP;
1762
DEBUG ("Server advertises PEP support in our jid features");
1763
conn->features |= GABBLE_CONNECTION_FEATURES_PEP;
1885
1895
g_signal_connect (priv->porter, "remote-error",
1886
1896
G_CALLBACK (remote_error_cb), self);
1888
lm_connection_set_porter (self->lmconn, priv->porter);
1889
g_signal_emit (self, sig_id_porter_available, 0, priv->porter);
1898
g_signal_emit_by_name (self, "porter-available", priv->porter);
1890
1899
connect_iq_callbacks (self);
1892
1901
wocky_pep_service_start (self->pep_location, self->session);
2078
2087
WOCKY_PORTER_HANDLER_PRIORITY_NORMAL,
2079
2088
connection_iq_last_cb, conn,
2080
2089
'(', "query", ':', NS_LAST, ')', NULL);
2082
/* FIXME: the porter should do this for us. */
2083
wocky_porter_register_handler_from_anyone (priv->porter,
2084
WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_NONE,
2085
WOCKY_PORTER_HANDLER_PRIORITY_MIN,
2086
iq_unknown_cb, conn, NULL);
2316
2319
gabble_connection_fill_in_caps (GabbleConnection *self,
2317
LmMessage *presence_message)
2320
WockyStanza *presence_message)
2319
2322
GabblePresence *presence = self->self_presence;
2320
LmMessageNode *node = lm_message_get_node (presence_message);
2323
WockyNode *node = wocky_stanza_get_top_node (presence_message);
2321
2324
gchar *caps_hash;
2322
2325
gboolean share_v1, voice_v1, video_v1;
2323
2326
GString *ext = g_string_new ("");
2325
2328
/* XEP-0115 version 1.5 uses a verification string in the 'ver' attribute */
2326
2329
caps_hash = caps_hash_compute_from_self_presence (self);
2327
node = lm_message_node_add_child (node, "c", NULL);
2328
lm_message_node_set_attributes (
2330
node = wocky_node_add_child_with_content (node, "c", NULL);
2331
wocky_node_set_attributes (
2331
2333
"hash", "sha-1",
2332
2334
"node", NS_GABBLE_CAPS,
2333
2335
"ver", caps_hash,
2337
node->ns = g_quark_from_string (NS_CAPS);
2336
2339
/* Ensure this set of capabilities is in the cache. */
2337
2340
gabble_presence_cache_add_own_caps (self->presence_cache, caps_hash,
2387
2390
/* We deliberately don't include anything except the caps here */
2388
message = lm_message_new_with_sub_type (recipient, LM_MESSAGE_TYPE_PRESENCE,
2389
LM_MESSAGE_SUB_TYPE_AVAILABLE);
2391
message = wocky_stanza_build (
2392
WOCKY_STANZA_TYPE_PRESENCE, WOCKY_STANZA_SUB_TYPE_AVAILABLE,
2391
2396
gabble_connection_fill_in_caps (self, message);
2393
2398
ret = _gabble_connection_send (self, message, error);
2395
lm_message_unref (message);
2400
g_object_unref (message);
2404
2409
GError **error)
2406
2411
GabblePresence *presence = self->self_presence;
2407
LmMessage *message = gabble_presence_as_message (presence, to);
2408
LmMessageNode *decloak;
2412
WockyStanza *message = gabble_presence_as_message (presence, to);
2411
2416
gabble_connection_fill_in_caps (self, message);
2413
decloak = lm_message_node_add_child (lm_message_get_node (message),
2418
decloak = wocky_node_add_child_with_content (wocky_stanza_get_top_node (message),
2414
2419
"temppres", NULL);
2415
lm_message_node_set_attribute (decloak, "xmlns", NS_TEMPPRES);
2420
decloak->ns = g_quark_from_string (NS_TEMPPRES);
2417
2422
if (reason != NULL && *reason != '\0')
2419
lm_message_node_set_attribute (decloak, "reason", reason);
2424
wocky_node_set_attribute (decloak, "reason", reason);
2422
2427
ret = _gabble_connection_send (self, message, error);
2423
lm_message_unref (message);
2428
g_object_unref (message);
2521
2526
_gabble_connection_acknowledge_set_iq (GabbleConnection *conn,
2526
g_assert (LM_MESSAGE_TYPE_IQ == lm_message_get_type (iq));
2527
g_assert (LM_MESSAGE_SUB_TYPE_SET == lm_message_get_sub_type (iq));
2529
result = lm_iq_message_make_result (iq);
2533
_gabble_connection_send (conn, result, NULL);
2534
lm_message_unref (result);
2539
* _gabble_connection_send_iq_error
2541
* Function used to acknowledge an IQ stanza with an error.
2544
_gabble_connection_send_iq_error (GabbleConnection *conn,
2546
GabbleXmppError error,
2547
const gchar *errmsg)
2549
const gchar *to, *id;
2551
LmMessageNode *iq_node;
2553
iq_node = lm_message_get_node (message);
2554
to = lm_message_node_get_attribute (iq_node, "from");
2555
id = lm_message_node_get_attribute (iq_node, "id");
2559
NODE_DEBUG (iq_node, "can't acknowledge IQ with no id");
2563
msg = lm_message_new_with_sub_type (to, LM_MESSAGE_TYPE_IQ,
2564
LM_MESSAGE_SUB_TYPE_ERROR);
2566
lm_message_node_set_attribute (wocky_stanza_get_top_node (msg), "id", id);
2568
lm_message_node_steal_children (
2569
wocky_stanza_get_top_node (msg), iq_node);
2571
gabble_xmpp_error_to_node (error, wocky_stanza_get_top_node (msg), errmsg);
2573
_gabble_connection_send (conn, msg, NULL);
2575
lm_message_unref (msg);
2529
wocky_porter_acknowledge_iq (wocky_session_get_porter (conn->session),
2579
2534
add_feature_node (gpointer namespace,
2580
2535
gpointer result_query)
2582
LmMessageNode *feature_node;
2537
WockyNode *feature_node;
2584
feature_node = lm_message_node_add_child (result_query, "feature",
2539
feature_node = wocky_node_add_child_with_content (result_query, "feature",
2586
lm_message_node_set_attribute (feature_node, "var", namespace);
2541
wocky_node_set_attribute (feature_node, "var", namespace);
2590
2545
add_identity_node (const GabbleDiscoIdentity *identity,
2591
2546
gpointer result_query)
2593
LmMessageNode *identity_node;
2548
WockyNode *identity_node;
2595
identity_node = lm_message_node_add_child
2550
identity_node = wocky_node_add_child_with_content
2596
2551
(result_query, "identity", NULL);
2597
lm_message_node_set_attribute (identity_node, "category", identity->category);
2598
lm_message_node_set_attribute (identity_node, "type", identity->type);
2552
wocky_node_set_attribute (identity_node, "category", identity->category);
2553
wocky_node_set_attribute (identity_node, "type", identity->type);
2599
2554
if (identity->lang)
2600
lm_message_node_set_attribute (identity_node, "lang", identity->lang);
2555
wocky_node_set_attribute (identity_node, "lang", identity->lang);
2601
2556
if (identity->name)
2602
lm_message_node_set_attribute (identity_node, "name", identity->name);
2557
wocky_node_set_attribute (identity_node, "name", identity->name);
2768
* Called by Wocky when we get an incoming <iq>. This handler is
2769
* at a lower priority than the others, and should reply with an error
2770
* about unsupported get/set attempts.
2773
iq_unknown_cb (WockyPorter *porter,
2774
WockyStanza *stanza,
2777
GabbleConnection *conn = GABBLE_CONNECTION (user_data);
2778
WockyStanzaSubType subtype;
2780
wocky_stanza_get_type_info (stanza, NULL, &subtype);
2784
case WOCKY_STANZA_SUB_TYPE_GET:
2785
case WOCKY_STANZA_SUB_TYPE_SET:
2786
_gabble_connection_send_iq_error (conn, stanza,
2787
XMPP_ERROR_SERVICE_UNAVAILABLE, NULL);
2797
2721
* set_status_to_connected
2799
2723
* Stage 4 of connecting, this function is called once all the events we were
2885
2810
NODE_DEBUG (result, "got");
2887
for (i = node_iter (result); i; i = node_iter_next (i))
2812
wocky_node_iter_init (&i, result, NULL, NULL);
2813
while (wocky_node_iter_next (&i, &child))
2889
LmMessageNode *child = node_iter_data (i);
2891
2815
if (0 == strcmp (child->name, "identity"))
2893
const gchar *category = lm_message_node_get_attribute (child,
2817
const gchar *category = wocky_node_get_attribute (child,
2895
const gchar *type = lm_message_node_get_attribute (child, "type");
2819
const gchar *type = wocky_node_get_attribute (child, "type");
2897
2821
if (!tp_strdiff (category, "pubsub") &&
2898
2822
!tp_strdiff (type, "pep"))
3812
3736
gabble_connection_send_presence (GabbleConnection *conn,
3813
LmMessageSubType sub_type,
3737
WockyStanzaSubType sub_type,
3814
3738
const gchar *contact,
3815
3739
const gchar *status,
3816
3740
GError **error)
3742
WockyStanza *message;
3819
3743
gboolean result;
3821
message = lm_message_new_with_sub_type (contact,
3822
LM_MESSAGE_TYPE_PRESENCE,
3745
message = wocky_stanza_build (WOCKY_STANZA_TYPE_PRESENCE, sub_type,
3825
if (LM_MESSAGE_SUB_TYPE_SUBSCRIBE == sub_type)
3749
if (WOCKY_STANZA_SUB_TYPE_SUBSCRIBE == sub_type)
3826
3750
lm_message_node_add_own_nick (
3827
3751
wocky_stanza_get_top_node (message), conn);
3829
3753
if (!tp_str_empty (status))
3830
lm_message_node_add_child (
3754
wocky_node_add_child_with_content (
3831
3755
wocky_stanza_get_top_node (message), "status", status);
3833
3757
result = _gabble_connection_send (conn, message, error);
3835
lm_message_unref (message);
3759
g_object_unref (message);
3917
3841
/* identities is actually a WockyDiscoIdentityArray */
3919
gabble_connection_add_sidecar_own_caps_full (GabbleConnection *self,
3843
gabble_connection_add_sidecar_own_caps_full (GabblePluginConnection *self,
3920
3844
const GabbleCapabilitySet *cap_set,
3921
3845
const GPtrArray *identities,
3922
3846
GPtrArray *data_forms)
3848
GabbleConnection *conn = GABBLE_CONNECTION (self);
3924
3849
GPtrArray *identities_copy = ((identities == NULL) ?
3925
3850
wocky_disco_identity_array_new () :
3926
3851
wocky_disco_identity_array_copy (identities));
4022
3950
return (TpBaseContactList *) connection->roster;
3953
static TpBaseContactList *
3954
_gabble_plugin_connection_get_contact_list (
3955
GabblePluginConnection *plugin_connection)
3957
GabbleConnection *connection = GABBLE_CONNECTION (plugin_connection);
3958
return gabble_connection_get_contact_list (connection);
4025
3961
WockyXep0115Capabilities *
4026
gabble_connection_get_caps (GabbleConnection *connection,
3962
gabble_connection_get_caps (GabblePluginConnection *plugin_connection,
4027
3963
TpHandle handle)
4029
3965
GabblePresence *presence;
3966
GabbleConnection *connection = GABBLE_CONNECTION (plugin_connection);
4031
3968
g_return_val_if_fail (GABBLE_IS_CONNECTION (connection), NULL);
4032
3969
g_return_val_if_fail (handle > 0, NULL);