diff options
author | Will Thompson <will.thompson@collabora.co.uk> | 2009-11-27 12:26:50 +0000 |
---|---|---|
committer | Will Thompson <will.thompson@collabora.co.uk> | 2009-11-27 12:26:50 +0000 |
commit | 0b0506542442aa801fdf21afa5f880cf6320bc05 (patch) | |
tree | 34354bb0392286b5113f3dc3212180fff2c752d4 /src | |
parent | 2ee360dce6b0ea69d0f4d1fdea4e1148291a13d0 (diff) | |
parent | 2059502c054f55e332aafe29c2476c5963033dc7 (diff) |
Merge branch 'master' into plugins
Diffstat (limited to 'src')
-rw-r--r-- | src/bytestream-factory.c | 11 | ||||
-rw-r--r-- | src/bytestream-factory.h | 3 | ||||
-rw-r--r-- | src/capabilities.c | 2 | ||||
-rw-r--r-- | src/capabilities.h | 2 | ||||
-rw-r--r-- | src/connection-manager.c | 4 | ||||
-rw-r--r-- | src/connection-manager.h | 2 | ||||
-rw-r--r-- | src/connection.c | 407 | ||||
-rw-r--r-- | src/connection.h | 5 | ||||
-rw-r--r-- | src/ft-channel.c | 7 | ||||
-rw-r--r-- | src/ft-manager.c | 51 | ||||
-rw-r--r-- | src/gabble.c | 1 | ||||
-rw-r--r-- | src/im-channel.c | 137 | ||||
-rw-r--r-- | src/im-channel.h | 15 | ||||
-rw-r--r-- | src/im-factory.c | 8 | ||||
-rw-r--r-- | src/muc-factory.c | 3 | ||||
-rw-r--r-- | src/muc-factory.h | 2 | ||||
-rw-r--r-- | src/register.c | 3 | ||||
-rw-r--r-- | src/register.h | 2 | ||||
-rw-r--r-- | src/tube-dbus.c | 8 | ||||
-rw-r--r-- | src/tube-stream.c | 4 | ||||
-rw-r--r-- | src/util.c | 46 | ||||
-rw-r--r-- | src/write-mgr-file.c | 5 |
22 files changed, 235 insertions, 493 deletions
diff --git a/src/bytestream-factory.c b/src/bytestream-factory.c index 4336aa48c..728d2a414 100644 --- a/src/bytestream-factory.c +++ b/src/bytestream-factory.c @@ -297,8 +297,6 @@ disco_item_found_cb (GabbleDisco *disco, send_proxy_query (self, item->jid, FALSE); } -static void query_socks5_proxies (GabbleBytestreamFactory *self); - static gboolean socks5_proxies_timeout_cb (gpointer data) { @@ -316,13 +314,14 @@ socks5_proxies_timeout_cb (gpointer data) return FALSE; } - query_socks5_proxies (self); + gabble_bytestream_factory_query_socks5_proxies (self); return FALSE; } -static void -query_socks5_proxies (GabbleBytestreamFactory *self) +/* ask to the factory to try to find more proxies if needed */ +void +gabble_bytestream_factory_query_socks5_proxies (GabbleBytestreamFactory *self) { GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE ( self); @@ -422,8 +421,6 @@ conn_status_changed_cb (GabbleConnection *conn, priv->socks5_potential_proxies = randomize_g_slist ( priv->socks5_potential_proxies); - query_socks5_proxies (self); - g_strfreev (jids); } } diff --git a/src/bytestream-factory.h b/src/bytestream-factory.h index dcc58fc53..ff5523de6 100644 --- a/src/bytestream-factory.h +++ b/src/bytestream-factory.h @@ -109,6 +109,9 @@ gchar *gabble_bytestream_factory_generate_stream_id (void); GSList *gabble_bytestream_factory_get_socks5_proxies ( GabbleBytestreamFactory *self); +void gabble_bytestream_factory_query_socks5_proxies ( + GabbleBytestreamFactory *self); + G_END_DECLS #endif /* #ifndef __BYTESTREAM_FACTORY_H__ */ diff --git a/src/capabilities.c b/src/capabilities.c index 4b9f44a34..0a241cf40 100644 --- a/src/capabilities.c +++ b/src/capabilities.c @@ -63,7 +63,7 @@ static const Feature self_advertised_features[] = { FEATURE_FIXED, NS_IBB }, { FEATURE_FIXED, NS_TUBES }, { FEATURE_FIXED, NS_BYTESTREAMS }, - { FEATURE_FIXED, NS_FILE_TRANSFER }, + { FEATURE_OPTIONAL, NS_FILE_TRANSFER }, { FEATURE_OPTIONAL, NS_GOOGLE_TRANSPORT_P2P }, { FEATURE_OPTIONAL, NS_JINGLE_TRANSPORT_ICEUDP }, diff --git a/src/capabilities.h b/src/capabilities.h index 6b4266803..9a4cbfd3e 100644 --- a/src/capabilities.h +++ b/src/capabilities.h @@ -112,6 +112,8 @@ const GabbleCapabilitySet *gabble_capabilities_get_olpc_notify (void); const GabbleCapabilitySet *gabble_capabilities_get_bundle_voice_v1 (void); const GabbleCapabilitySet *gabble_capabilities_get_bundle_video_v1 (void); +#define BUNDLE_PMUC_V1 "pmuc-v1" + /* * capabilities_fill_cache * diff --git a/src/connection-manager.c b/src/connection-manager.c index 5753b2714..9e798d0cd 100644 --- a/src/connection-manager.c +++ b/src/connection-manager.c @@ -126,7 +126,9 @@ static TpCMParamSpec jabber_params[] = { /* FIXME: validate the JID according to the RFC */ tp_cm_param_filter_string_nonempty, NULL }, { "password", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, - TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, NULL, + TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER | + TP_CONN_MGR_PARAM_FLAG_SECRET, + NULL, G_STRUCT_OFFSET(GabbleParams, password), NULL, NULL }, { "server", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, diff --git a/src/connection-manager.h b/src/connection-manager.h index 4ef773511..89a5f50f4 100644 --- a/src/connection-manager.h +++ b/src/connection-manager.h @@ -36,8 +36,6 @@ struct _GabbleConnectionManagerClass { struct _GabbleConnectionManager { TpBaseConnectionManager parent; - - GabbleConnectionManagerPrivate *priv; }; GType gabble_connection_manager_get_type (void); diff --git a/src/connection.c b/src/connection.c index d301d3dbf..1d91a4573 100644 --- a/src/connection.c +++ b/src/connection.c @@ -40,7 +40,6 @@ #include <telepathy-glib/handle-repo-dynamic.h> #include <telepathy-glib/handle-repo-static.h> #include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-connection.h> #include <telepathy-glib/svc-generic.h> #include "extensions/extensions.h" @@ -81,7 +80,6 @@ static guint disco_reply_timeout = 5; #define DISCONNECT_TIMEOUT 5 -static void conn_service_iface_init (gpointer, gpointer); static void capabilities_service_iface_init (gpointer, gpointer); static void gabble_conn_contact_caps_iface_init (gpointer, gpointer); static void conn_capabilities_fill_contact_attributes (GObject *obj, @@ -92,8 +90,6 @@ static void conn_contact_capabilities_fill_contact_attributes (GObject *obj, G_DEFINE_TYPE_WITH_CODE(GabbleConnection, gabble_connection, TP_TYPE_BASE_CONNECTION, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION, - conn_service_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING, conn_aliasing_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS, @@ -665,7 +661,7 @@ _gabble_connection_create_handle_repos (TpBaseConnection *conn, gabble_normalize_contact, GUINT_TO_POINTER (GABBLE_JID_ANY)); repos[TP_HANDLE_TYPE_ROOM] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_ROOM, gabble_normalize_room, - NULL); + conn); repos[TP_HANDLE_TYPE_GROUP] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_GROUP, NULL, NULL); repos[TP_HANDLE_TYPE_LIST] = @@ -1970,6 +1966,7 @@ _gabble_connection_signal_own_presence (GabbleConnection *self, GError **error) gboolean ret; gchar *caps_hash; gboolean voice_v1, video_v1; + GString *ext = g_string_new (""); if (presence->status == GABBLE_PRESENCE_HIDDEN) { @@ -1995,27 +1992,19 @@ _gabble_connection_signal_own_presence (GabbleConnection *self, GError **error) /* XEP-0115 deprecates 'ext' feature bundles. But we still need * BUNDLE_VOICE_V1 it for backward-compatibility with Gabble 0.2 */ + g_string_append (ext, BUNDLE_PMUC_V1); + voice_v1 = gabble_presence_has_cap (presence, NS_GOOGLE_FEAT_VOICE); video_v1 = gabble_presence_has_cap (presence, NS_GOOGLE_FEAT_VIDEO); - if (voice_v1 || video_v1) - { - GString *ext = g_string_new (""); - - if (voice_v1) - g_string_append (ext, BUNDLE_VOICE_V1); + if (voice_v1) + g_string_append (ext, " " BUNDLE_VOICE_V1); - if (video_v1) - { - if (ext->len > 0) - g_string_append_c (ext, ' '); - g_string_append (ext, BUNDLE_VIDEO_V1); - } + if (video_v1) + g_string_append (ext, " " BUNDLE_VIDEO_V1); - lm_message_node_set_attribute (node, "ext", ext->str); - - g_string_free (ext, TRUE); - } + lm_message_node_set_attribute (node, "ext", ext->str); + g_string_free (ext, TRUE); ret = _gabble_connection_send (self, message, error); @@ -2256,15 +2245,19 @@ connection_iq_disco_cb (LmMessageHandler *handler, features = gabble_capabilities_get_bundle_video_v1 (); } - if (features == NULL) + if (features == NULL && tp_strdiff (suffix, BUNDLE_PMUC_V1)) { _gabble_connection_send_iq_error (self, message, XMPP_ERROR_ITEM_NOT_FOUND, NULL); } else { - gabble_capability_set_foreach (features, add_feature_node, - result_query); + /* Send an empty reply for a pmuc-v1 disco, matching Google's behaviour. */ + if (features != NULL) + { + gabble_capability_set_foreach (features, add_feature_node, + result_query); + } NODE_DEBUG (result_iq, "sending disco response"); @@ -3074,8 +3067,8 @@ _gabble_connection_find_conference_server (GabbleConnection *conn) } -static gchar * -_gabble_connection_get_canonical_room_name (GabbleConnection *conn, +gchar * +gabble_connection_get_canonical_room_name (GabbleConnection *conn, const gchar *name) { const gchar *server; @@ -3093,355 +3086,6 @@ _gabble_connection_get_canonical_room_name (GabbleConnection *conn, return gabble_encode_jid (name, server, NULL); } - -typedef struct _RoomVerifyContext RoomVerifyContext; - -typedef struct { - GabbleConnection *conn; - DBusGMethodInvocation *invocation; - gboolean errored; - guint count; - GArray *handles; - RoomVerifyContext *contexts; -} RoomVerifyBatch; - -struct _RoomVerifyContext { - gchar *jid; - guint index; - RoomVerifyBatch *batch; - GabbleDiscoRequest *request; -}; - -static void -room_verify_batch_free (RoomVerifyBatch *batch) -{ - TpBaseConnection *base = (TpBaseConnection *) (batch->conn); - TpHandleRepoIface *room_handles = tp_base_connection_get_handles (base, - TP_HANDLE_TYPE_ROOM); - guint i; - - tp_handles_unref (room_handles, batch->handles); - g_array_free (batch->handles, TRUE); - for (i = 0; i < batch->count; i++) - { - g_free (batch->contexts[i].jid); - } - g_free (batch->contexts); - g_slice_free (RoomVerifyBatch, batch); -} - -/* Frees the error and the batch. */ -static void -room_verify_batch_raise_error (RoomVerifyBatch *batch, - GError *error) -{ - guint i; - - dbus_g_method_return_error (batch->invocation, error); - g_error_free (error); - batch->errored = TRUE; - for (i = 0; i < batch->count; i++) - { - if (batch->contexts[i].request) - { - gabble_disco_cancel_request (batch->conn->disco, - batch->contexts[i].request); - } - } - room_verify_batch_free (batch); -} - -static RoomVerifyBatch * -room_verify_batch_new (GabbleConnection *conn, - DBusGMethodInvocation *invocation, - guint count, - const gchar **jids) -{ - TpBaseConnection *base = (TpBaseConnection *) conn; - TpHandleRepoIface *room_handles = tp_base_connection_get_handles (base, - TP_HANDLE_TYPE_ROOM); - RoomVerifyBatch *batch = g_slice_new (RoomVerifyBatch); - guint i; - - batch->errored = FALSE; - batch->conn = conn; - batch->invocation = invocation; - batch->count = count; - batch->handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), count); - batch->contexts = g_new0(RoomVerifyContext, count); - for (i = 0; i < count; i++) - { - const gchar *name = jids[i]; - gchar *qualified_name; - TpHandle handle; - - batch->contexts[i].index = i; - batch->contexts[i].batch = batch; - - qualified_name = _gabble_connection_get_canonical_room_name (conn, name); - - if (!qualified_name) - { - GError *error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "requested room handle %s does not specify a server, but we " - "have not discovered any local conference servers and no " - "fallback was provided", name); - DEBUG ("%s", error->message); - room_verify_batch_raise_error (batch, error); - return NULL; - } - - batch->contexts[i].jid = qualified_name; - - /* has the handle been verified before? */ - handle = tp_handle_lookup (room_handles, qualified_name, NULL, NULL); - if (handle) - tp_handle_ref (room_handles, handle); - g_array_append_val (batch->handles, handle); - } - - return batch; -} - -/* If all handles in the array have been disco'd or got from cache, -free the batch and return TRUE. Else return FALSE. */ -static gboolean -room_verify_batch_try_return (RoomVerifyBatch *batch) -{ - guint i; - TpHandleRepoIface *room_handles = tp_base_connection_get_handles ( - (TpBaseConnection *) batch->conn, TP_HANDLE_TYPE_ROOM); - gchar *sender; - GError *error = NULL; - - for (i = 0; i < batch->count; i++) - { - if (!g_array_index (batch->handles, TpHandle, i)) - { - /* we're not ready yet */ - return FALSE; - } - } - - sender = dbus_g_method_get_sender (batch->invocation); - if (!tp_handles_client_hold (room_handles, sender, batch->handles, &error)) - { - g_assert (error != NULL); - } - g_free (sender); - - if (error == NULL) - { - tp_svc_connection_return_from_request_handles (batch->invocation, - batch->handles); - } - else - { - dbus_g_method_return_error (batch->invocation, error); - g_error_free (error); - } - - room_verify_batch_free (batch); - return TRUE; -} - -static void -room_jid_disco_cb (GabbleDisco *disco, - GabbleDiscoRequest *request, - const gchar *jid, - const gchar *node, - LmMessageNode *query_result, - GError *error, - gpointer user_data) -{ - RoomVerifyContext *rvctx = user_data; - RoomVerifyBatch *batch = rvctx->batch; - TpHandleRepoIface *room_handles = tp_base_connection_get_handles ( - (TpBaseConnection *) batch->conn, TP_HANDLE_TYPE_ROOM); - gboolean found = FALSE; - TpHandle handle; - NodeIter i; - - /* stop the request getting cancelled after it's already finished */ - rvctx->request = NULL; - - /* if an error is being handled already, quietly go away */ - if (batch->errored) - { - return; - } - - if (error != NULL) - { - DEBUG ("disco reply error %s", error->message); - - /* disco will free the old error, _raise_error will free the new one */ - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "can't retrieve room info: %s", error->message); - - room_verify_batch_raise_error (batch, error); - - return; - } - - for (i = node_iter (query_result); i; i = node_iter_next (i)) - { - LmMessageNode *lm_node = node_iter_data (i); - const gchar *var; - - if (tp_strdiff (lm_node->name, "feature")) - continue; - - var = lm_message_node_get_attribute (lm_node, "var"); - - /* for servers who consider schema compliance to be an optional bonus */ - if (var == NULL) - var = lm_message_node_get_attribute (lm_node, "type"); - - if (!tp_strdiff (var, NS_MUC)) - { - found = TRUE; - break; - } - } - - if (!found) - { - DEBUG ("no MUC support for service name in jid %s", rvctx->jid); - - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "specified server doesn't support MUC"); - - room_verify_batch_raise_error (batch, error); - - return; - } - - /* this refs the handle, so we're putting a ref in batch->handles */ - handle = tp_handle_ensure (room_handles, rvctx->jid, NULL, &error); - if (handle == 0) - { - room_verify_batch_raise_error (batch, error); - return; - } - - DEBUG ("disco reported MUC support for service name in jid %s", rvctx->jid); - g_array_index (batch->handles, TpHandle, rvctx->index) = handle; - - /* if this was the last callback to be run, send off the result */ - room_verify_batch_try_return (batch); -} - -/** - * room_jid_verify: - * - * Utility function that verifies that the service name of - * the specified jid exists and reports MUC support. - */ -static gboolean -room_jid_verify (RoomVerifyBatch *batch, - guint i, - DBusGMethodInvocation *context) -{ - gchar *room, *service; - gboolean ret; - GError *error = NULL; - - room = service = NULL; - - if (!gabble_decode_jid (batch->contexts[i].jid, &room, &service, NULL) || - room == NULL) - { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "unable to get room name and service from JID %s", - batch->contexts[i].jid); - ret = FALSE; - goto out; - } - - ret = (gabble_disco_request (batch->conn->disco, GABBLE_DISCO_TYPE_INFO, - service, NULL, room_jid_disco_cb, - batch->contexts + i, - G_OBJECT (batch->conn), &error) != NULL); - -out: - if (!ret) - { - room_verify_batch_raise_error (batch, error); - } - - g_free (room); - g_free (service); - - return ret; -} - - -/** - * gabble_connection_request_handles - * - * Implements D-Bus method RequestHandles - * on interface org.freedesktop.Telepathy.Connection - * - * @context: The D-Bus invocation context to use to return values - * or throw an error. - */ -static void -gabble_connection_request_handles (TpSvcConnection *iface, - guint handle_type, - const gchar **names, - DBusGMethodInvocation *context) -{ - GabbleConnection *self = GABBLE_CONNECTION (iface); - TpBaseConnection *base = (TpBaseConnection *) self; - - g_assert (GABBLE_IS_CONNECTION (self)); - - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); - - if (handle_type == TP_HANDLE_TYPE_ROOM) - { - RoomVerifyBatch *batch = NULL; - guint count = 0, i; - const gchar **cur_name; - - for (cur_name = names; *cur_name != NULL; cur_name++) - { - count++; - } - - batch = room_verify_batch_new (self, context, count, names); - if (!batch) - { - /* an error occurred while setting up the batch, and we returned - error to dbus */ - return; - } - - /* have all the handles been verified already? If so, nothing to do */ - if (room_verify_batch_try_return (batch)) - { - return; - } - - for (i = 0; i < count; i++) - { - if (!room_jid_verify (batch, i, context)) - { - return; - } - } - - /* we've set the verification process going - the callback will handle - returning or raising error */ - return; - } - - /* else it's either an invalid type, or a type we can verify immediately - - * in either case, let the superclass do it */ - tp_base_connection_dbus_request_handles (iface, handle_type, names, context); -} - void gabble_connection_ensure_capabilities (GabbleConnection *self, const GabbleCapabilitySet *ensured) @@ -3477,19 +3121,6 @@ gabble_connection_send_presence (GabbleConnection *conn, return result; } -/* We reimplement RequestHandles to be able to do async validation on - * room handles */ -static void -conn_service_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcConnectionClass *klass = (TpSvcConnectionClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_connection_implement_##x (klass, \ - gabble_connection_##x) - IMPLEMENT(request_handles); -#undef IMPLEMENT -} - static void capabilities_service_iface_init (gpointer g_iface, gpointer iface_data) { diff --git a/src/connection.h b/src/connection.h index e15c25d6c..383393ee1 100644 --- a/src/connection.h +++ b/src/connection.h @@ -55,10 +55,9 @@ G_BEGIN_DECLS "proxy.downtempo.de",\ "proxy.im.flosoft.biz",\ "proxy.jabber.bluendo.com", "proxy.jabber.dk", "proxy.jabber.freenet.de",\ - "proxy.fsinf.at", "proxy.jabber.minus273.org",\ + "proxy.jabber.minus273.org",\ "proxy.jabber.planetteamspeak.com", "proxy.jabber.tf-network.de",\ "proxy.jabjab.de", "proxy.jabster.pl",\ - "proxy.schokokeks.org",\ "proxy.ubuntu-jabber.de", "proxy.ubuntu-jabber.net",\ "proxy65.unstable.nl", "proxy.verdammung.org", "proxy.vke.ru",\ "proxy.vodka-pomme.net", "proxy.jabbernet.eu",\ @@ -253,6 +252,8 @@ void _gabble_connection_send_iq_error (GabbleConnection *conn, LmMessage *message, GabbleXmppError error, const gchar *errmsg); const char *_gabble_connection_find_conference_server (GabbleConnection *); +gchar *gabble_connection_get_canonical_room_name (GabbleConnection *conn, + const gchar *jid); gboolean _gabble_connection_signal_own_presence (GabbleConnection *, GError **); diff --git a/src/ft-channel.c b/src/ft-channel.c index 516238433..2450a0b9d 100644 --- a/src/ft-channel.c +++ b/src/ft-channel.c @@ -494,6 +494,13 @@ gabble_file_transfer_channel_constructor (GType type, tp_handle_inspect (contact_repo, self->priv->initiator), self->priv->filename, self->priv->size); + if (self->priv->initiator == base_conn->self_handle) + { + /* Outgoing FT , we'll need SOCK5 proxies when we'll offer the file */ + gabble_bytestream_factory_query_socks5_proxies ( + self->priv->connection->bytestream_factory); + } + return obj; } diff --git a/src/ft-manager.c b/src/ft-manager.c index 87338a35c..5ab700227 100644 --- a/src/ft-manager.c +++ b/src/ft-manager.c @@ -545,8 +545,6 @@ void gabble_ft_manager_handle_si_request (GabbleFtManager *self, { GTimeVal val; - g_time_val_from_iso8601 (date_str, &val); - /* FIXME: this assume the timezone is always UTC */ if (g_time_val_from_iso8601 (date_str, &val)) date = val.tv_sec; @@ -601,16 +599,13 @@ gabble_ft_manager_get_tmp_dir (GabbleFtManager *self) } static void -add_file_transfer_channel_class (GPtrArray *arr, - TpHandle handle) +add_file_transfer_channel_class (GPtrArray *arr) { GValue monster = {0, }; GHashTable *fixed_properties; GValue *channel_type_value; GValue *target_handle_type_value; - g_assert (handle != 0); - g_value_init (&monster, TP_STRUCT_TYPE_REQUESTABLE_CHANNEL_CLASS); g_value_take_boxed (&monster, dbus_g_type_specialized_construct ( @@ -641,19 +636,46 @@ add_file_transfer_channel_class (GPtrArray *arr, } static void -gabble_ft_manager_get_contact_caps (GabbleCapsChannelManager *manager, - TpHandle handle, +gabble_ft_manager_get_contact_caps ( + GabbleCapsChannelManager *manager G_GNUC_UNUSED, + TpHandle handle G_GNUC_UNUSED, const GabbleCapabilitySet *caps, GPtrArray *arr) { - GabbleFtManager *self = GABBLE_FT_MANAGER (manager); + if (gabble_capability_set_has (caps, NS_FILE_TRANSFER)) + add_file_transfer_channel_class (arr); +} - g_assert (handle != 0); +static void +gabble_ft_manager_represent_client ( + GabbleCapsChannelManager *manager G_GNUC_UNUSED, + const gchar *client_name, + const GPtrArray *filters, + const gchar * const *cap_tokens G_GNUC_UNUSED, + GabbleCapabilitySet *cap_set) +{ + guint i; - /* We always support file transfer */ - if (handle == self->priv->connection->parent.self_handle || - gabble_capability_set_has (caps, NS_FILE_TRANSFER)) - add_file_transfer_channel_class (arr, handle); + for (i = 0; i < filters->len; i++) + { + GHashTable *channel_class = g_ptr_array_index (filters, i); + + if (tp_strdiff (tp_asv_get_string (channel_class, + TP_IFACE_CHANNEL ".ChannelType"), + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER)) + continue; + + if (tp_asv_get_uint32 (channel_class, + TP_IFACE_CHANNEL ".TargetHandleType", NULL) + != TP_HANDLE_TYPE_CONTACT) + continue; + + DEBUG ("client %s supports file transfer", client_name); + gabble_capability_set_add (cap_set, NS_FILE_TRANSFER); + /* there's no point in looking at the subsequent filters if we've + * already added the FT capability */ + break; + } } static void @@ -663,4 +685,5 @@ caps_channel_manager_iface_init (gpointer g_iface, GabbleCapsChannelManagerIface *iface = g_iface; iface->get_contact_caps = gabble_ft_manager_get_contact_caps; + iface->represent_client = gabble_ft_manager_represent_client; } diff --git a/src/gabble.c b/src/gabble.c index 992d12e08..18ce1ac51 100644 --- a/src/gabble.c +++ b/src/gabble.c @@ -144,6 +144,7 @@ gabble_main (int argc, construct_cm, argc, argv); #ifdef ENABLE_DEBUG + g_log_set_default_handler (g_log_default_handler, NULL); g_object_unref (debug_sender); #endif diff --git a/src/im-channel.c b/src/im-channel.c index 6db5e53f6..f4edc54cb 100644 --- a/src/im-channel.c +++ b/src/im-channel.c @@ -95,6 +95,12 @@ enum /* private structure */ +typedef enum { + CHAT_STATES_UNKNOWN, + CHAT_STATES_SUPPORTED, + CHAT_STATES_NOT_SUPPORTED +} ChatStateSupport; + struct _GabbleIMChannelPrivate { GabbleConnection *conn; @@ -104,6 +110,7 @@ struct _GabbleIMChannelPrivate gchar *peer_jid; gboolean send_nick; + ChatStateSupport chat_states_supported; /* FALSE unless at least one chat state notification has been sent; <gone/> * will only be sent when the channel closes if this is TRUE. This prevents @@ -172,6 +179,8 @@ gabble_im_channel_constructor (GType type, guint n_props, else priv->send_nick = TRUE; + priv->chat_states_supported = CHAT_STATES_UNKNOWN; + tp_message_mixin_init (obj, G_STRUCT_OFFSET (GabbleIMChannel, message_mixin), conn); @@ -394,20 +403,43 @@ gabble_im_channel_class_init (GabbleIMChannelClass *gabble_im_channel_class) tp_message_mixin_init_dbus_properties (object_class); } +static gboolean +chat_states_supported (GabbleIMChannel *self, + gboolean include_unknown) +{ + GabbleIMChannelPrivate *priv = self->priv; + GabblePresence *presence; + + presence = gabble_presence_cache_get (priv->conn->presence_cache, + priv->handle); + + if (presence != NULL && gabble_presence_has_cap (presence, NS_CHAT_STATES)) + return TRUE; + + switch (priv->chat_states_supported) + { + case CHAT_STATES_UNKNOWN: + return include_unknown; + case CHAT_STATES_SUPPORTED: + return TRUE; + case CHAT_STATES_NOT_SUPPORTED: + return FALSE; + default: + g_assert_not_reached (); + return FALSE; + } +} + static void emit_closed_and_send_gone (GabbleIMChannel *self) { GabbleIMChannelPrivate *priv = self->priv; - GabblePresence *presence; if (priv->send_gone) { - presence = gabble_presence_cache_get (priv->conn->presence_cache, - priv->handle); - - if (presence && gabble_presence_has_cap (presence, NS_CHAT_STATES)) + if (chat_states_supported (self, FALSE)) gabble_message_util_send_chat_state (G_OBJECT (self), priv->conn, - LM_MESSAGE_SUB_TYPE_NORMAL, TP_CHANNEL_CHAT_STATE_GONE, + LM_MESSAGE_SUB_TYPE_CHAT, TP_CHANNEL_CHAT_STATE_GONE, priv->peer_jid, NULL); priv->send_gone = FALSE; @@ -487,16 +519,12 @@ _gabble_im_channel_send_message (GObject *object, { GabbleIMChannel *self = GABBLE_IM_CHANNEL (object); GabbleIMChannelPrivate *priv; - GabblePresence *presence; gint state = -1; g_assert (GABBLE_IS_IM_CHANNEL (self)); priv = self->priv; - presence = gabble_presence_cache_get (priv->conn->presence_cache, - priv->handle); - - if (presence && gabble_presence_has_cap (presence, NS_CHAT_STATES)) + if (chat_states_supported (self, TRUE)) { state = TP_CHANNEL_CHAT_STATE_ACTIVE; priv->send_gone = TRUE; @@ -512,7 +540,6 @@ _gabble_im_channel_send_message (GObject *object, priv->send_nick = FALSE; } - /** * _gabble_im_channel_receive * @@ -526,7 +553,8 @@ _gabble_im_channel_receive (GabbleIMChannel *chan, const gchar *id, const char *text, TpChannelTextSendError send_error, - TpDeliveryStatus delivery_status) + TpDeliveryStatus delivery_status, + gint state) { GabbleIMChannelPrivate *priv; TpBaseConnection *base_conn; @@ -545,6 +573,19 @@ _gabble_im_channel_receive (GabbleIMChannel *chan, g_free (priv->peer_jid); priv->peer_jid = g_strdup (from); } + + if (state == -1) + { + priv->chat_states_supported = CHAT_STATES_NOT_SUPPORTED; + } + else + { + priv->chat_states_supported = CHAT_STATES_SUPPORTED; + + tp_svc_channel_interface_chat_state_emit_chat_state_changed ( + (TpSvcChannelInterfaceChatState *) chan, + priv->handle, (TpChannelChatState) state); + } } else { @@ -553,6 +594,8 @@ _gabble_im_channel_receive (GabbleIMChannel *chan, if (slash != NULL) *slash = '\0'; + + priv->chat_states_supported = CHAT_STATES_UNKNOWN; } msg = tp_message_new (base_conn, 2, 2); @@ -629,7 +672,7 @@ _gabble_im_channel_receive (GabbleIMChannel *chan, void _gabble_im_channel_state_receive (GabbleIMChannel *chan, - guint state) + TpChannelChatState state) { GabbleIMChannelPrivate *priv; @@ -637,6 +680,8 @@ _gabble_im_channel_state_receive (GabbleIMChannel *chan, g_assert (GABBLE_IS_IM_CHANNEL (chan)); priv = chan->priv; + priv->chat_states_supported = CHAT_STATES_SUPPORTED; + tp_svc_channel_interface_chat_state_emit_chat_state_changed ( (TpSvcChannelInterfaceChatState *) chan, priv->handle, state); @@ -790,53 +835,47 @@ gabble_im_channel_set_chat_state (TpSvcChannelInterfaceChatState *iface, { GabbleIMChannel *self = GABBLE_IM_CHANNEL (iface); GabbleIMChannelPrivate *priv; - GabblePresence *presence; GError *error = NULL; g_assert (GABBLE_IS_IM_CHANNEL (self)); priv = self->priv; - presence = gabble_presence_cache_get (priv->conn->presence_cache, - priv->handle); - - if (presence && gabble_presence_has_cap (presence, NS_CHAT_STATES)) + if (state >= NUM_TP_CHANNEL_CHAT_STATES) { - if (state >= NUM_TP_CHANNEL_CHAT_STATES) - { - DEBUG ("invalid state %u", state); - - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "invalid state: %u", state); - } - - if (state == TP_CHANNEL_CHAT_STATE_GONE) - { - /* We cannot explicitly set the Gone state */ - DEBUG ("you may not explicitly set the Gone state"); - - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "you may not explicitly set the Gone state"); - } - else if (gabble_message_util_send_chat_state (G_OBJECT (self), priv->conn, - LM_MESSAGE_SUB_TYPE_NORMAL, state, priv->peer_jid, &error)) + g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "invalid state: %u", state); + } + else if (state == TP_CHANNEL_CHAT_STATE_GONE) + { + g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + "you may not explicitly set the Gone state"); + } + /* Only send anything to the peer if we actually know they support chat + * states. + */ + else if (chat_states_supported (self, FALSE)) + { + if (gabble_message_util_send_chat_state (G_OBJECT (self), priv->conn, + LM_MESSAGE_SUB_TYPE_CHAT, state, priv->peer_jid, &error)) { priv->send_gone = TRUE; - } - - if (error != NULL) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; + /* Send the ChatStateChanged signal for the local user */ + tp_svc_channel_interface_chat_state_emit_chat_state_changed (iface, + priv->conn->parent.self_handle, state); } - - /* Send the ChatStateChanged signal for the local user */ - tp_svc_channel_interface_chat_state_emit_chat_state_changed (iface, - priv->conn->parent.self_handle, state); } - tp_svc_channel_interface_chat_state_return_from_set_chat_state (context); + if (error != NULL) + { + DEBUG ("%s", error->message); + dbus_g_method_return_error (context, error); + g_error_free (error); + } + else + { + tp_svc_channel_interface_chat_state_return_from_set_chat_state (context); + } } static void diff --git a/src/im-channel.h b/src/im-channel.h index 7d7d96a14..2a2a2dc1e 100644 --- a/src/im-channel.h +++ b/src/im-channel.h @@ -66,10 +66,17 @@ GType gabble_im_channel_get_type (void); GabbleIMChannelClass)) 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); -void _gabble_im_channel_state_receive (GabbleIMChannel *chan, guint state); + 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); G_END_DECLS diff --git a/src/im-factory.c b/src/im-factory.c index 8f5cccca0..d2b12a112 100644 --- a/src/im-factory.c +++ b/src/im-factory.c @@ -283,12 +283,12 @@ im_factory_message_cb (LmMessageHandler *handler, from, handle, msgtype, body); } - if (state != -1 && send_error == GABBLE_TEXT_CHANNEL_SEND_NO_ERROR) - _gabble_im_channel_state_receive (chan, state); - if (body != NULL) _gabble_im_channel_receive (chan, msgtype, handle, from, stamp, id, body, - send_error, delivery_status); + 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; } diff --git a/src/muc-factory.c b/src/muc-factory.c index 2caba4787..fd3b10d35 100644 --- a/src/muc-factory.c +++ b/src/muc-factory.c @@ -62,7 +62,6 @@ enum LAST_PROPERTY }; -typedef struct _GabbleMucFactoryPrivate GabbleMucFactoryPrivate; struct _GabbleMucFactoryPrivate { GabbleConnection *conn; @@ -105,6 +104,8 @@ gabble_muc_factory_init (GabbleMucFactory *fac) { GabbleMucFactoryPrivate *priv = GABBLE_MUC_FACTORY_GET_PRIVATE (fac); + fac->priv = priv; + 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, diff --git a/src/muc-factory.h b/src/muc-factory.h index c17935ef4..8a5485bff 100644 --- a/src/muc-factory.h +++ b/src/muc-factory.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS typedef struct _GabbleMucFactory GabbleMucFactory; typedef struct _GabbleMucFactoryClass GabbleMucFactoryClass; +typedef struct _GabbleMucFactoryPrivate GabbleMucFactoryPrivate; struct _GabbleMucFactoryClass { GObjectClass parent_class; @@ -36,6 +37,7 @@ struct _GabbleMucFactoryClass { struct _GabbleMucFactory { GObject parent; + GabbleMucFactoryPrivate *priv; }; GType gabble_muc_factory_get_type (void); diff --git a/src/register.c b/src/register.c index aff4cb65b..9a9e0ff1b 100644 --- a/src/register.c +++ b/src/register.c @@ -60,7 +60,6 @@ enum G_DEFINE_TYPE(GabbleRegister, gabble_register, G_TYPE_OBJECT); /* private structure */ -typedef struct _GabbleRegisterPrivate GabbleRegisterPrivate; struct _GabbleRegisterPrivate { GabbleConnection *conn; @@ -75,6 +74,8 @@ struct _GabbleRegisterPrivate static void gabble_register_init (GabbleRegister *obj) { + obj->priv = G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_REGISTER, + GabbleRegisterPrivate); } static void gabble_register_set_property (GObject *object, guint property_id, diff --git a/src/register.h b/src/register.h index e38e52044..f4ea593d4 100644 --- a/src/register.h +++ b/src/register.h @@ -33,6 +33,7 @@ G_BEGIN_DECLS typedef struct _GabbleRegister GabbleRegister; typedef struct _GabbleRegisterClass GabbleRegisterClass; +typedef struct _GabbleRegisterPrivate GabbleRegisterPrivate; GType gabble_register_get_type (void); @@ -57,6 +58,7 @@ struct _GabbleRegisterClass { struct _GabbleRegister { GObject parent; + GabbleRegisterPrivate *priv; }; GabbleRegister *gabble_register_new (GabbleConnection *conn); diff --git a/src/tube-dbus.c b/src/tube-dbus.c index 9db9f1968..bb4961840 100644 --- a/src/tube-dbus.c +++ b/src/tube-dbus.c @@ -955,6 +955,14 @@ gabble_tube_dbus_constructor (GType type, priv->reassembly_bytes_needed = 0; g_assert (priv->muc == NULL); + + if (priv->requested) + { + /* We created this outgoing 1-1 D-Bus tube and so will need SOCKS5 + * proxies when we'll offer it. */ + gabble_bytestream_factory_query_socks5_proxies ( + priv->conn->bytestream_factory); + } } /* Tube needs to be offered if we initiated AND requested it. Being diff --git a/src/tube-stream.c b/src/tube-stream.c index 9aedd5f98..de9bf4fb0 100644 --- a/src/tube-stream.c +++ b/src/tube-stream.c @@ -1516,6 +1516,10 @@ gabble_tube_stream_constructor (GType type, else { priv->state = TP_TUBE_CHANNEL_STATE_LOCAL_PENDING; + + /* We'll need SOCKS5 proxies if the tube is accepted */ + gabble_bytestream_factory_query_socks5_proxies ( + priv->conn->bytestream_factory); } if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) diff --git a/src/util.c b/src/util.c index d22844d42..351bacda1 100644 --- a/src/util.c +++ b/src/util.c @@ -415,35 +415,47 @@ gabble_normalize_room (TpHandleRepoIface *repo, gpointer context, GError **error) { - char *at = strchr (jid, '@'); - char *slash = strchr (jid, '/'); + GabbleConnection *conn; + gchar *qualified_name, *resource; - /* there'd better be an @ somewhere after the first character */ - if (at == NULL) + /* Only look up the canonical room name if we got a GabbleConnection. + * This should only happen in the test-handles test. */ + if (context != NULL) { - INVALID_HANDLE (error, - "invalid room JID %s: does not contain '@'", jid); - return NULL; + conn = GABBLE_CONNECTION (context); + qualified_name = gabble_connection_get_canonical_room_name (conn, jid); + + if (qualified_name == NULL) + { + INVALID_HANDLE (error, + "requested room handle %s does not specify a server, but we " + "have not discovered any local conference servers and no " + "fallback was provided", jid); + return NULL; + } } - if (at == jid) + else { - INVALID_HANDLE (error, - "invalid room JID %s: room name before '@' may not be empty", jid); + qualified_name = g_strdup (jid); + } + + if (!gabble_decode_jid (qualified_name, NULL, NULL, &resource)) + { + INVALID_HANDLE (error, "room JID %s is invalid", qualified_name); return NULL; } - /* room names can't contain the nick part */ - if (slash != NULL) + if (resource != NULL) { INVALID_HANDLE (error, - "invalid room JID %s: contains nickname part after '/' too", jid); + "invalid room JID %s: contains nickname part after '/' too", + qualified_name); + g_free (qualified_name); + g_free (resource); return NULL; } - /* the room and service parts are both case-insensitive, so lowercase - * them both; gabble_decode_jid is overkill here - */ - return g_utf8_strdown (jid, -1); + return qualified_name; } gchar * diff --git a/src/write-mgr-file.c b/src/write-mgr-file.c index a5c9cd905..8a26a50c9 100644 --- a/src/write-mgr-file.c +++ b/src/write-mgr-file.c @@ -48,9 +48,10 @@ mgr_file_contents (const char *busname, for (row = protocol->parameters; row->name; row++) { gchar *param_name = g_strdup_printf ("param-%s", row->name); - gchar *param_value = g_strdup_printf ("%s%s%s", row->dtype, + gchar *param_value = g_strdup_printf ("%s%s%s%s", row->dtype, (row->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED ? " required" : ""), - (row->flags & TP_CONN_MGR_PARAM_FLAG_REGISTER ? " register" : "")); + (row->flags & TP_CONN_MGR_PARAM_FLAG_REGISTER ? " register" : ""), + (row->flags & TP_CONN_MGR_PARAM_FLAG_SECRET ? " secret" : "")); g_key_file_set_string (f, section_name, param_name, param_value); g_free (param_value); g_free (param_name); |