diff options
254 files changed, 9014 insertions, 18519 deletions
@@ -1,14 +1,38 @@ -telepathy-gabble 0.16.7 (UNRELEASED) +telepathy-gabble 0.17.6 (UNRELEASED) ==================================== ... -telepathy-gabble 0.16.6 (2013-05-30) +telepathy-gabble 0.17.5 (2013-06-06) ==================================== -The “repeated gas boiler replacement” release. +The “4.5kg of laptops” release. -This release fixes a man-in-the-middle attack. You should upgrade. +Dependencies: + +• GLib 2.32 is now directly required. It was already indirectly required + by telepathy-glib 0.19.x. + +Fixes: + +• update Wocky: + · fd.o #65131: interoperate with non-XMPP-Core-compliant Jingle IQs + sent by Google's webmail UI (Simon) + · improve reference-counting for better stability (Simon) + +• fd.o #65296: initialize libdbus for thread-safety (Simon) + +• fd.o #64285: avoid running the same commands twice in parallel when doing a + highly parallel build (Simon) + +• fd.o #49595: disable an unreliable test-case (Simon) + +telepathy-gabble 0.17.4 (2013-05-30) +==================================== + +The “unattainably high curry standards” release. + +This development release fixes the same man-in-the-middle attack as 0.16.6. If you use an unencrypted connection to a "legacy Jabber" (pre-XMPP) server, this version of Gabble will not connect until you make @@ -20,18 +44,27 @@ one of these configuration changes: Fixes: -• fd.o #65036 (CVE-2013-1431): update Wocky to respect the tls-required - flag on legacy Jabber servers (Simon) +• update Wocky: + · fd.o #61792: fix linking an example program with ld versions that + default to --no-copy-dt-needed-entries + · fd.o #65036 (CVE-2013-1431): update Wocky to respect the tls-required + flag on legacy Jabber servers • fd.o #63119: improve regression tests' isolation from the session bus (Simon) -telepathy-gabble 0.16.5 (2013-03-01) +• fd.o #64319: consider the <URL> field to be "supported" on Google servers + (it's currently read-only and contains a Google+ URL) (Xavier) + +• fd.o #64354: don't claim we support X-TELEPATHY-PASSWORD if we don't + know the username (Xavier) + +telepathy-gabble 0.17.3 (2013-03-01) ==================================== -The “In Actuality You Are A Gigantic, Bloodthirsty Grizzly Bear” -release. This fixes a remotely-triggered denial-of-service bug. You -should upgrade. +The “less resplendent backup ruffs” release. This includes the fixes +from telepathy-gabble 0.16.5, including fixing a remotely-triggered +denial-of-service bug. You should upgrade. Fixes: @@ -45,9 +78,37 @@ Fixes: is just a NULL pointer dereference, rather than allowing the attacker to do anything more nefarious like execute code. (wjt) -telepathy-gabble 0.16.4 (2012-11-09) +• fd.o#43166: handle rate-limiting by MUCs better, including disabling + typing notifications if we get rate-limited, and including the error + message from the server in the D-Bus signal so that the user interface + could, in principle, show it to the user. (wjt) + +Enhancements: + +• fd.o#58198: the Jingle protocol code now lives in Wocky. This should make no + functional difference to Gabble. (wjt) + + +telepathy-gabble 0.17.2 (2012-12-07) ==================================== +Hooray! Hooray! Hooray! + +Dependencies: + +• telepathy-glib 0.19.9 is now required. + +Enhancements: + +• fd.o#54760, fd.o#57080: Gabble now uses GLib's base64 implementation + rather than including its own. (Heiher, Alban Browaeys) + +• fd.o#25961, fd.o#25385: Gabble now looks up a STUN server from the + _stun._udp SRV record for the user's domain. (Maiku, wjt) + +• fd.o#47378: XEP-0184 delivery reports are now supported. Note that + Empathy neither requests nor displays them. (wjt) + Fixes: • fd.o#56181: don't inadvertantly disable creating Call1 channels. (rishi) @@ -55,13 +116,33 @@ Fixes: • fd.o#52362: hopefully, don't crash if we disconnect in the middle of trying to change our Google Talk presence. (wjt) -telepathy-gabble 0.16.3 (2012-09-11) +• The Jingle code now sends back unknown-session errors correctly, as + mentioned on fd.o#33789. (wjt) + +• fd.o#57267: File transfer channels now include FileTransfer.FUTURE and + FileTransfer.METADATA in their Interfaces property (Daniele + Domenichelli) + +• fd.o#57521: Don't crash when connecting to the League of Legends XMPP + server. (wjt) + +• fd.o#52146: Don't crash in sympathy if the auth channel handler + crashes. (wjt) + +telepathy-gabble 0.17.1 (2012-09-11) ==================================== -Fixes: +Dependencies: -• Turn off deprecation warnings: we're not going to fix them on a - stable branch (Simon) +• telepathy-glib 0.19.7 is now required. (sorry about that) + +Enhancements: + +• fd.o#32612: Old-style Tubes channels have been removed. (Jonny) + +• Tube and Text channels are no longer announced together. (Jonny) + +Fixes: • Make sure capability discovery works for the camera-v1 capability bundle, avoiding an iChat bug in which it repeats failed capability discovery @@ -69,28 +150,25 @@ Fixes: • Fix some race conditions and other brokenness in the tests (Sjoerd) -telepathy-gabble 0.16.2 (2012-08-14) -==================================== - -Fixes: +• Make sure capability discovery works for the camera-v1 capability bundle, + avoiding an iChat bug in which it repeats failed capability discovery + requests in a rapid loop (fd.o #54634, Simon) -• fd.o#53087 - Crash in tp_base_channel_close +• Fix some race conditions and other brokenness in the tests (Sjoerd) -telepathy-gabble 0.16.1 (2012-06-20) +telepathy-gabble 0.17.0 (2012-08-14) ==================================== -Requirements: - -• glib 2.30 is now required. - -Enhancements: +Dependencies: -• "see-other-host" stream error is now supported. This fix connection issue - with Windows Live XMPP server. +• telepathy-glib 0.19.2 is now required. -Fixes: +Changes since 0.16.2: -• fd.o#36998: Fail to establish a video call with Android +• Fix calls with android devices (Marcus) +• Implement WLM jidlookup. This makes possible to add MSN contacts using XMPP. + (Xavier) +• Fix google caps parsing (Jonny) telepathy-gabble 0.16.0 (2012-04-02) ==================================== diff --git a/configure.ac b/configure.ac index 38b4a552e..645524a9d 100644 --- a/configure.ac +++ b/configure.ac @@ -8,8 +8,8 @@ AC_PREREQ([2.59]) # set gabble_nano_version to 0. m4_define([gabble_major_version], [0]) -m4_define([gabble_minor_version], [16]) -m4_define([gabble_micro_version], [6]) +m4_define([gabble_minor_version], [17]) +m4_define([gabble_micro_version], [5]) m4_define([gabble_nano_version], [1]) # Some magic @@ -93,7 +93,6 @@ TP_COMPILER_WARNINGS([ERROR_CFLAGS], [test "x$official_release" = xno], format-security \ init-self], [missing-field-initializers \ - deprecated-declarations \ unused-parameter]) AC_SUBST([ERROR_CFLAGS]) @@ -296,7 +295,11 @@ PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.1.0, dbus-glib-1 >= 0.82]) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) -PKG_CHECK_MODULES(TP_GLIB, [telepathy-glib >= 0.18.0]) +AC_DEFINE(TP_SEAL_ENABLE, [], [Prevent to use sealed variables]) +AC_DEFINE(TP_DISABLE_SINGLE_INCLUDE, [], [Disable single header include]) +AC_DEFINE(TP_VERSION_MIN_REQUIRED, TP_VERSION_0_18, [Ignore post 0.18 deprecations]) +AC_DEFINE(TP_VERSION_MAX_ALLOWED, TP_VERSION_0_20, [Prevent post 0.20 APIs]) +PKG_CHECK_MODULES(TP_GLIB, [telepathy-glib >= 0.19.9]) AC_SUBST(TP_GLIB_CFLAGS) AC_SUBST(TP_GLIB_LIBS) diff --git a/extensions/Makefile.am b/extensions/Makefile.am index 8e50ffbce..b435ae3f4 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -20,9 +20,6 @@ libgabble_extensions_la_SOURCES = \ extensions.h nodist_libgabble_extensions_la_SOURCES = \ - _gen/signals-marshal.c \ - _gen/signals-marshal.h \ - _gen/signals-marshal.list \ _gen/enums.h \ _gen/enums-gtk-doc.h \ _gen/gtypes.h \ @@ -62,40 +59,37 @@ extensions.html: _gen/all.xml $(tools_dir)/doc-generator.xsl Makefile.am $(tools_dir)/doc-generator.xsl \ $< > $@ -_gen/svc.c _gen/svc.h _gen/svc-gtk-doc.h: _gen/all.xml $(tools_dir)/glib-ginterface-gen.py \ - Makefile.am +_gen/svc.h: _gen/svc.c + @: # do nothing, output as a side-effect +_gen/svc-gtk-doc.h: _gen/svc.c + @: # do nothing, output as a side-effect +_gen/svc.c: _gen/all.xml $(tools_dir)/glib-ginterface-gen.py Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-ginterface-gen.py \ - --filename=_gen/svc --signal-marshal-prefix=_gabble_ext \ - --include='<telepathy-glib/dbus.h>' \ - --include='"_gen/signals-marshal.h"' \ + --filename=_gen/svc \ + --include='<telepathy-glib/telepathy-glib.h>' \ --allow-unstable \ --not-implemented-func='tp_dbus_g_method_return_not_implemented' \ $< Gabble_Svc_ -_gen/signals-marshal.list: _gen/all.xml \ - $(tools_dir)/glib-signals-marshal-gen.py \ - Makefile.am - $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@ - -_gen/signals-marshal.h: _gen/signals-marshal.list Makefile.am - $(AM_V_GEN)$(GLIB_GENMARSHAL) --header --prefix=_gabble_ext_marshal $< > $@ - -_gen/signals-marshal.c: _gen/signals-marshal.list Makefile.am - $(AM_V_GEN){ echo '#include "_gen/signals-marshal.h"' && \ - $(GLIB_GENMARSHAL) --body --prefix=_gabble_ext_marshal $< ; } > $@ - -_gen/enums.h _gen/enums-gtk-doc.h: _gen/all.xml $(tools_dir)/c-constants-gen.py \ - Makefile.am +_gen/enums-gtk-doc.h: _gen/enums.h + @: # do nothing, output as a side-effect +_gen/enums.h: _gen/all.xml $(tools_dir)/c-constants-gen.py Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py Gabble $< _gen/enums -_gen/interfaces.h _gen/interfaces-body.h _gen/interfaces-gtk-doc.h: _gen/all.xml \ - $(tools_dir)/glib-interfaces-gen.py \ - Makefile.am +_gen/interfaces-body.h: _gen/interfaces.h + @: # do nothing, output as a side-effect +_gen/interfaces-gtk-doc.h: _gen/interfaces.h + @: # do nothing, output as a side-effect +_gen/interfaces.h: _gen/all.xml $(tools_dir)/glib-interfaces-gen.py Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-interfaces-gen.py \ Gabble _gen/interfaces-body.h _gen/interfaces.h $< -_gen/gtypes.h _gen/gtypes-body.h _gen/gtypes-gtk-doc.h: _gen/all.xml \ - $(tools_dir)/glib-gtypes-generator.py Makefile.am +_gen/gtypes.h: _gen/gtypes-body.h + @: # do nothing, output as a side-effect +_gen/gtypes-gtk-doc.h: _gen/gtypes-body.h + @: # do nothing, output as a side-effect + +_gen/gtypes-body.h: _gen/all.xml $(tools_dir)/glib-gtypes-generator.py Makefile.am $(AM_V_GEN)$(PYTHON) $(tools_dir)/glib-gtypes-generator.py \ $< _gen/gtypes Gabble diff --git a/gabble/caps-channel-manager.h b/gabble/caps-channel-manager.h index a41bd20a6..898529fe0 100644 --- a/gabble/caps-channel-manager.h +++ b/gabble/caps-channel-manager.h @@ -24,8 +24,7 @@ #define GABBLE_CAPS_CHANNEL_MANAGER_H #include <glib-object.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/handle.h> +#include <telepathy-glib/telepathy-glib.h> #include "capabilities.h" @@ -90,7 +89,6 @@ void gabble_caps_channel_manager_represent_client ( struct _GabbleCapsChannelManagerInterface { GTypeInterface parent; - GabbleCapsChannelManagerResetCapsFunc reset_caps; GabbleCapsChannelManagerGetContactCapsFunc get_contact_caps; GabbleCapsChannelManagerRepresentClientFunc represent_client; diff --git a/gabble/connection.h b/gabble/connection.h index 5c7bf51e7..0365699d1 100644 --- a/gabble/connection.h +++ b/gabble/connection.h @@ -21,8 +21,7 @@ #ifndef GABBLE_PLUGINS_CONNECTION_H #define GABBLE_PLUGINS_CONNECTION_H -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/base-contact-list.h> +#include <telepathy-glib/telepathy-glib.h> #include <gabble/capabilities-set.h> #include <gabble/types.h> diff --git a/gabble/plugin-connection.h b/gabble/plugin-connection.h index 66302a746..1dd0638c2 100644 --- a/gabble/plugin-connection.h +++ b/gabble/plugin-connection.h @@ -22,8 +22,7 @@ #include <glib-object.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/base-contact-list.h> +#include <telepathy-glib/telepathy-glib.h> #include <gabble/capabilities-set.h> #include <gabble/types.h> diff --git a/gabble/plugin.h b/gabble/plugin.h index faf72a9e4..fcc7290e0 100644 --- a/gabble/plugin.h +++ b/gabble/plugin.h @@ -24,8 +24,7 @@ #include <glib-object.h> #include <gio/gio.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/presence-mixin.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #include <gabble/plugin-connection.h> diff --git a/lib/ext/wocky b/lib/ext/wocky -Subproject ff317a2783058e8e90fac21bd8ba18359c5401f +Subproject 7f139058d3323d99b11667f93cb4abcb3ccc9c4 diff --git a/plugins/console.c b/plugins/console.c index 7dde24fac..fd49d0bd8 100644 --- a/plugins/console.c +++ b/plugins/console.c @@ -95,7 +95,7 @@ gabble_console_plugin_create_sidecar_async ( } else { - g_simple_async_result_set_error (result, TP_ERRORS, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' not implemented", sidecar_interface); } @@ -206,7 +206,8 @@ gabble_console_sidecar_init (GabbleConsoleSidecar *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_CONSOLE_SIDECAR, GabbleConsoleSidecarPrivate); - self->priv->reader = wocky_xmpp_reader_new_no_stream (); + self->priv->reader = wocky_xmpp_reader_new_no_stream_ns ( + WOCKY_XMPP_NS_JABBER_CLIENT); self->priv->writer = wocky_xmpp_writer_new_no_stream (); } @@ -492,7 +493,7 @@ get_iq_type (const gchar *type_str, return TRUE; } - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Type must be 'get' or 'set', not '%s'", type_str); return FALSE; } @@ -510,14 +511,15 @@ validate_jid (const gchar **to, if (wocky_decode_jid (*to, NULL, NULL, NULL)) return TRUE; - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid (or empty) JID", *to); return FALSE; } /* * @xml: doesn't actually have to be a top-level stanza. It can be the body of - * an IQ or whatever. + * an IQ or whatever. If it has no namespace, it's assumed to be in + * jabber:client. */ static gboolean parse_me_a_stanza ( @@ -541,7 +543,7 @@ parse_me_a_stanza ( if (stanza == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Incomplete stanza! Bad person."); return FALSE; } @@ -620,27 +622,20 @@ stanza_looks_coherent ( if (t == WOCKY_STANZA_TYPE_UNKNOWN) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "I don't know what a <%s/> is", top_node->name); + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, + "I don't know what a <%s xmlns='%s'/> is", top_node->name, + g_quark_to_string (top_node->ns)); return FALSE; } else if (st == WOCKY_STANZA_SUB_TYPE_UNKNOWN) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "I don't know what type='%s' means", wocky_node_get_attribute (top_node, "type")); return FALSE; } - else - { - if (top_node->ns == g_quark_from_static_string ("")) - { - /* So... Wocky puts an empty string in as the namespace. Greaaat. */ - top_node->ns = g_quark_from_static_string (WOCKY_XMPP_NS_JABBER_CLIENT); - } - return TRUE; - } + return TRUE; } static void diff --git a/plugins/console.h b/plugins/console.h index 9a3d5d619..e646d067e 100644 --- a/plugins/console.h +++ b/plugins/console.h @@ -21,7 +21,7 @@ #include <gio/gio.h> #include <wocky/wocky.h> -#include <telepathy-glib/dbus-properties-mixin.h> +#include <telepathy-glib/telepathy-glib.h> typedef struct _GabbleConsolePlugin GabbleConsolePlugin; typedef struct _GabbleConsolePluginClass GabbleConsolePluginClass; diff --git a/plugins/gateways.c b/plugins/gateways.c index c40dc5191..eae683518 100644 --- a/plugins/gateways.c +++ b/plugins/gateways.c @@ -95,7 +95,7 @@ gabble_gateway_plugin_create_sidecar_async ( } else { - g_simple_async_result_set_error (result, TP_ERRORS, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' not implemented", sidecar_interface); } @@ -422,12 +422,12 @@ register_cb (GObject *source, switch (error->code) { case WOCKY_XMPP_ERROR_CONFLICT: - g_set_error (&tp_error, TP_ERRORS, TP_ERROR_REGISTRATION_EXISTS, + g_set_error (&tp_error, TP_ERROR, TP_ERROR_REGISTRATION_EXISTS, "someone else registered that username: %s", error->message); break; case WOCKY_XMPP_ERROR_NOT_ACCEPTABLE: - g_set_error (&tp_error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&tp_error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "registration not acceptable: %s", error->message); break; @@ -487,21 +487,21 @@ gateways_register ( if (strchr (gateway, '@') != NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Gateway names cannot contain '@': %s", gateway); goto error; } if (strchr (gateway, '/') != NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Gateway names cannot contain '/': %s", gateway); goto error; } if (!wocky_decode_jid (gateway, NULL, &normalized_gateway, NULL)) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Invalid gateway name: %s", gateway); goto error; } diff --git a/plugins/test.c b/plugins/test.c index b145373f4..bb6b71959 100644 --- a/plugins/test.c +++ b/plugins/test.c @@ -1,4 +1,5 @@ #include "config.h" + #include "test.h" #include <stdio.h> @@ -113,7 +114,7 @@ test_plugin_create_sidecar_async ( /* This deliberately doesn't check for IFACE_TEST_BUGGY, to test Gabble's * reactions to buggy plugins. :) */ - g_simple_async_result_set_error (result, TP_ERRORS, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' not implemented", sidecar_interface); } @@ -442,7 +443,7 @@ iq_cb ( if (t == WOCKY_STANZA_SUB_TYPE_RESULT) g_simple_async_result_set_op_res_gboolean (result, TRUE); else - g_simple_async_result_set_error (result, TP_ERRORS, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "server said no!"); g_object_unref (reply); diff --git a/src/Makefile.am b/src/Makefile.am index c0f831d46..22a0278db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,8 +17,6 @@ libgabble_convenience_la_SOURCES = \ addressing-util.c \ auth-manager.h \ auth-manager.c \ - base64.h \ - base64.c \ bytestream-factory.h \ bytestream-factory.c \ bytestream-ibb.h \ @@ -125,8 +123,6 @@ libgabble_convenience_la_SOURCES = \ tls-certificate.c \ tube-iface.h \ tube-iface.c \ - tubes-channel.h \ - tubes-channel.c \ tube-dbus.h \ tube-dbus.c \ tube-stream.h \ @@ -161,33 +157,12 @@ libgabble_convenience_la_SOURCES += \ call-member-content.c \ call-stream.h \ call-stream.c \ - google-relay.c \ - google-relay.h \ - jingle-content.h \ - jingle-content.c \ - jingle-factory.h \ - jingle-factory.c \ - jingle-info.c \ - jingle-info.h \ jingle-share.h \ jingle-share.c \ - jingle-media-rtp.h \ - jingle-media-rtp.c \ jingle-mint.h \ jingle-mint.c \ - jingle-session.h \ - jingle-session.c \ jingle-tp-util.h \ jingle-tp-util.c \ - jingle-transport-google.h \ - jingle-transport-google.c \ - jingle-transport-rawudp.h \ - jingle-transport-rawudp.c \ - jingle-transport-iceudp.h \ - jingle-transport-iceudp.c \ - jingle-transport-iface.h \ - jingle-transport-iface.c \ - jingle-types.h \ media-channel.h \ media-channel-internal.h \ media-channel.c \ @@ -206,7 +181,6 @@ endif enumtype_sources = \ $(top_srcdir)/src/connection.h \ - $(top_srcdir)/src/jingle-types.h \ $(top_srcdir)/src/room-config.h \ $(top_srcdir)/src/presence.h diff --git a/src/addressing-util.c b/src/addressing-util.c index 0f1b3ffcc..049c566c6 100644 --- a/src/addressing-util.c +++ b/src/addressing-util.c @@ -85,7 +85,7 @@ gabble_uri_to_jid (const gchar *uri, if (scheme == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid URI", uri); goto OUT; } @@ -106,7 +106,7 @@ gabble_uri_to_jid (const gchar *uri, } else { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' URI scheme is not supported by this protocol", scheme); goto OUT; @@ -137,7 +137,7 @@ gabble_jid_to_uri (const gchar *scheme, if (!wocky_decode_jid (jid, &node, &domain, &resource)) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid JID", jid); return NULL; } @@ -234,7 +234,7 @@ gabble_vcard_address_to_jid (const gchar *vcard_field, if (gabble_error != NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is an invalid address: %s", vcard_address, gabble_error->message); g_error_free (gabble_error); @@ -249,7 +249,7 @@ gabble_vcard_address_to_jid (const gchar *vcard_field, s++; if (G_UNLIKELY (*s != '\0')) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is an invalid facebook chat address", vcard_address); goto OUT; } @@ -258,7 +258,7 @@ gabble_vcard_address_to_jid (const gchar *vcard_field, } else { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' vCard field is not supported by this protocol", vcard_field); } @@ -286,7 +286,7 @@ gabble_jid_to_vcard_address (const gchar *vcard_field, if (gabble_error != NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is an invalid address: %s", jid, gabble_error->message); g_error_free (gabble_error); @@ -312,13 +312,13 @@ gabble_jid_to_vcard_address (const gchar *vcard_field, s++; if (G_UNLIKELY (*s != '\0')) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is an invalid facebook chat address", jid); } } else { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is an invalid facebook chat address", jid); } @@ -326,7 +326,7 @@ gabble_jid_to_vcard_address (const gchar *vcard_field, } else { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' vCard field is not supported by this protocol", vcard_field); } @@ -438,7 +438,7 @@ gabble_parse_xmpp_uri (const gchar *uri, if (scheme == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid URI", uri); goto OUT; } @@ -447,7 +447,7 @@ gabble_parse_xmpp_uri (const gchar *uri, if (!wocky_decode_jid (jid, &tmp_node, &tmp_domain, &tmp_resource)) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid XMPP URI", uri); goto OUT; } @@ -458,7 +458,7 @@ gabble_parse_xmpp_uri (const gchar *uri, unescaped_node = g_uri_unescape_string (tmp_node, NULL); if (unescaped_node == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid XMPP URI", uri); goto OUT; } @@ -468,7 +468,7 @@ gabble_parse_xmpp_uri (const gchar *uri, unescaped_domain = g_uri_unescape_string (tmp_domain, NULL); if (unescaped_domain == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid XMPP URI", uri); goto OUT; } @@ -478,7 +478,7 @@ gabble_parse_xmpp_uri (const gchar *uri, unescaped_resource = g_uri_unescape_string (tmp_resource, NULL); if (unescaped_resource == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid XMPP URI", uri); goto OUT; } @@ -491,7 +491,7 @@ gabble_parse_xmpp_uri (const gchar *uri, if (gabble_error != NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid XMPP URI: %s", uri, gabble_error->message); g_error_free (gabble_error); @@ -500,7 +500,7 @@ gabble_parse_xmpp_uri (const gchar *uri, if (!wocky_decode_jid (normalized_jid, node, domain, resource)) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is not a valid XMPP URI", uri); goto OUT; } diff --git a/src/addressing-util.h b/src/addressing-util.h index 9835e0d70..378d1fe78 100644 --- a/src/addressing-util.h +++ b/src/addressing-util.h @@ -20,7 +20,7 @@ #ifndef __GABBLE_UTIL_ADDRESSING_H__ #define __GABBLE_UTIL_ADDRESSING_H__ -#include <telepathy-glib/handle-repo-dynamic.h> +#include <telepathy-glib/telepathy-glib.h> const gchar * const * gabble_get_addressable_uri_schemes (void); diff --git a/src/auth-manager.c b/src/auth-manager.c index 57a8bbd62..ad60d0883 100644 --- a/src/auth-manager.c +++ b/src/auth-manager.c @@ -20,9 +20,8 @@ #include "config.h" #include "auth-manager.h" -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -54,6 +53,7 @@ typedef struct { gchar *name; GHashTable *details; TpConnectionStatusReason reason; + GError *wocky_error; } SavedError; struct _GabbleAuthManagerPrivate @@ -62,7 +62,10 @@ struct _GabbleAuthManagerPrivate GabbleServerSaslChannel *channel; gulong closed_id; - gboolean falling_back; + /* TRUE if we are authenticating using our parent class's methods (because we + * have a username and password). + */ + gboolean chaining_up; GSList *mechanisms; gchar *server; @@ -109,7 +112,7 @@ static void auth_channel_closed_cb (GabbleServerSaslChannel *channel, GabbleAuthManager *self) { - SavedError tmp = { NULL, NULL, 0 }; + SavedError tmp = { NULL, NULL, 0, NULL }; tp_channel_manager_emit_channel_closed_for_object (self, TP_EXPORTABLE_CHANNEL (channel)); @@ -118,7 +121,7 @@ auth_channel_closed_cb (GabbleServerSaslChannel *channel, /* this is our last chance to find out why it failed */ if (gabble_server_sasl_channel_get_failure_details (channel, - &tmp.name, &tmp.details, &tmp.reason)) + &tmp.name, &tmp.details, &tmp.reason, &tmp.wocky_error)) self->priv->error = g_slice_dup (SavedError, &tmp); g_signal_handler_disconnect (self->priv->channel, self->priv->closed_id); @@ -218,7 +221,7 @@ gabble_auth_manager_set_property (GObject *object, } static void -gabble_auth_manager_start_fallback_cb (GObject *self_object, +gabble_auth_manager_start_parent_cb (GObject *self_object, GAsyncResult *result, gpointer user_data) { @@ -261,7 +264,7 @@ gabble_auth_manager_start_auth_cb (GObject *channel, /* restart authentication using our own base class */ g_assert (start_data->initial_response != NULL); - self->priv->falling_back = TRUE; + self->priv->chaining_up = TRUE; WOCKY_AUTH_REGISTRY_CLASS ( gabble_auth_manager_parent_class)->start_auth_async_func ( WOCKY_AUTH_REGISTRY (self), self->priv->mechanisms, @@ -270,7 +273,7 @@ gabble_auth_manager_start_auth_cb (GObject *channel, start_data->initial_response->str, self->priv->server, self->priv->session_id, - gabble_auth_manager_start_fallback_cb, user_data); + gabble_auth_manager_start_parent_cb, user_data); /* we've transferred ownership of the result */ goto finally; } @@ -294,7 +297,7 @@ finally: static void gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, - const GSList *mechanisms, + GSList *mechanisms, gboolean allow_plain, gboolean is_secure_channel, const gchar *username, @@ -305,6 +308,8 @@ gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, gpointer user_data) { GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); + GSimpleAsyncResult *result = g_simple_async_result_new ((GObject *) self, + callback, user_data, gabble_auth_manager_start_auth_async); /* assumption: Wocky's API guarantees that we never have more than one * auth request outstanding */ @@ -313,7 +318,18 @@ gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, if (password == NULL || username == NULL) { GPtrArray *mech_array = g_ptr_array_new (); - const GSList *iter; + GSList *iter; + + if (username == NULL) + { + g_object_get (self->priv->conn, + "username", &self->priv->username, + NULL); + } + else + { + self->priv->username = g_strdup (username); + } for (iter = mechanisms; iter != NULL; iter = iter->next) { @@ -325,7 +341,8 @@ gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, g_ptr_array_add (mech_array, iter->data); } - if (wocky_auth_registry_supports_one_of (registry, mechanisms, + if (self->priv->username != NULL && + wocky_auth_registry_supports_one_of (registry, mechanisms, allow_plain)) g_ptr_array_add (mech_array, X_TELEPATHY_PASSWORD); @@ -339,17 +356,6 @@ gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, self->priv->server = g_strdup (server); self->priv->session_id = g_strdup (session_id); - if (username == NULL) - { - g_object_get (self->priv->conn, - "username", &self->priv->username, - NULL); - } - else - { - self->priv->username = g_strdup (username); - } - self->priv->channel = gabble_server_sasl_channel_new (self->priv->conn, (GStrv) mech_array->pdata, is_secure_channel, session_id); g_ptr_array_unref (mech_array); @@ -359,8 +365,7 @@ gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, gabble_server_sasl_channel_start_auth_async (self->priv->channel, gabble_auth_manager_start_auth_cb, - g_simple_async_result_new ((GObject *) self, - callback, user_data, gabble_auth_manager_start_auth_async)); + result); g_assert (!tp_base_channel_is_destroyed ( (TpBaseChannel *) self->priv->channel)); @@ -371,10 +376,12 @@ gabble_auth_manager_start_auth_async (WockyAuthRegistry *registry, } else { + self->priv->chaining_up = TRUE; WOCKY_AUTH_REGISTRY_CLASS ( gabble_auth_manager_parent_class)->start_auth_async_func ( registry, mechanisms, allow_plain, is_secure_channel, - username, password, server, session_id, callback, user_data); + username, password, server, session_id, + gabble_auth_manager_start_parent_cb, result); } } @@ -386,19 +393,31 @@ gabble_auth_manager_start_auth_finish (WockyAuthRegistry *registry, { GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); - if (self->priv->channel != NULL) - { - wocky_implement_finish_copy_pointer (self, - gabble_auth_manager_start_auth_async, - wocky_auth_registry_start_data_dup, start_data); - } + wocky_implement_finish_copy_pointer (self, + gabble_auth_manager_start_auth_async, + wocky_auth_registry_start_data_dup, start_data); +} + +static void +channel_challenge_cb ( + GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GabbleServerSaslChannel *channel = GABBLE_SERVER_SASL_CHANNEL (source); + GSimpleAsyncResult *our_result = G_SIMPLE_ASYNC_RESULT (user_data); + GString *response_data = NULL; + GError *error = NULL; + + if (gabble_server_sasl_channel_challenge_finish (channel, result, + &response_data, &error)) + g_simple_async_result_set_op_res_gpointer (our_result, response_data, + (GDestroyNotify) wocky_g_string_free); else - { - return WOCKY_AUTH_REGISTRY_CLASS - (gabble_auth_manager_parent_class)->start_auth_finish_func ( - registry, result, start_data, error); - } + g_simple_async_result_take_error (our_result, error); + g_simple_async_result_complete (our_result); + g_object_unref (our_result); } static void @@ -409,17 +428,31 @@ gabble_auth_manager_challenge_async (WockyAuthRegistry *registry, { GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); - if (self->priv->channel != NULL && !self->priv->falling_back) - { - gabble_server_sasl_channel_challenge_async (self->priv->channel, - challenge_data, callback, user_data); - } - else + if (self->priv->chaining_up) { WOCKY_AUTH_REGISTRY_CLASS ( gabble_auth_manager_parent_class)->challenge_async_func ( registry, challenge_data, callback, user_data); } + else + { + GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self), + callback, user_data, gabble_auth_manager_challenge_async); + + if (self->priv->channel != NULL) + { + gabble_server_sasl_channel_challenge_async (self->priv->channel, + challenge_data, channel_challenge_cb, result); + } + else + { + g_assert (self->priv->error != NULL); + + g_simple_async_result_set_from_error (result, self->priv->error->wocky_error); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); + } + } } static gboolean @@ -430,36 +463,110 @@ gabble_auth_manager_challenge_finish (WockyAuthRegistry *registry, { GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); - if (self->priv->channel != NULL && !self->priv->falling_back) - { - return gabble_server_sasl_channel_challenge_finish (self->priv->channel, - result, response, error); - } - else + if (self->priv->chaining_up) { return WOCKY_AUTH_REGISTRY_CLASS (gabble_auth_manager_parent_class)->challenge_finish_func ( registry, result, response, error); } + else + { + wocky_implement_finish_copy_pointer (self, + gabble_auth_manager_challenge_async, + wocky_g_string_dup, response); + } } static void -gabble_auth_manager_success_async (WockyAuthRegistry *registry, - GAsyncReadyCallback callback, +channel_success_cb ( + GObject *source, + GAsyncResult *result, gpointer user_data) { - GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); + GabbleServerSaslChannel *channel = GABBLE_SERVER_SASL_CHANNEL (source); + GSimpleAsyncResult *our_result = G_SIMPLE_ASYNC_RESULT (user_data); + GError *error = NULL; - if (self->priv->channel != NULL) + if (!gabble_server_sasl_channel_success_finish (channel, result, &error)) + g_simple_async_result_take_error (our_result, error); + + g_simple_async_result_complete (our_result); + g_object_unref (our_result); +} + +static void +gabble_auth_manager_channel_success ( + GabbleAuthManager *self, + GSimpleAsyncResult *our_result, + gboolean need_idle) +{ + GabbleAuthManagerPrivate *priv = self->priv; + + if (priv->channel != NULL) { gabble_server_sasl_channel_success_async (self->priv->channel, - callback, user_data); + channel_success_cb, our_result); + return; + } + + if (priv->error != NULL) + g_simple_async_result_set_from_error (our_result, priv->error->wocky_error); + + if (need_idle) + g_simple_async_result_complete_in_idle (our_result); + else + g_simple_async_result_complete (our_result); + + g_object_unref (our_result); +} + +static void +gabble_auth_manager_success_parent_cb ( + GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GabbleAuthManager *self = GABBLE_AUTH_MANAGER (source); + WockyAuthRegistry *registry = WOCKY_AUTH_REGISTRY (source); + GSimpleAsyncResult *our_result = G_SIMPLE_ASYNC_RESULT (user_data); + GError *error = NULL; + + if (!WOCKY_AUTH_REGISTRY_CLASS (gabble_auth_manager_parent_class)-> + success_finish_func (registry, result, &error)) + { + g_simple_async_result_take_error (our_result, error); + g_simple_async_result_complete (our_result); + g_object_unref (our_result); } else { + gabble_auth_manager_channel_success (self, our_result, FALSE); + } +} + +static void +gabble_auth_manager_success_async (WockyAuthRegistry *registry, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); + GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self), + callback, user_data, gabble_auth_manager_success_async); + + /* Annoyingly, in the X-TELEPATHY-PASSWORD case we actually want to both + * chain up to the parent class, *and* pass the success notification out to + * the client for consistency with other mechanisms. + */ + + if (self->priv->chaining_up) + { WOCKY_AUTH_REGISTRY_CLASS ( gabble_auth_manager_parent_class)->success_async_func ( - registry, callback, user_data); + registry, gabble_auth_manager_success_parent_cb, result); + } + else + { + gabble_auth_manager_channel_success (self, result, TRUE); } } @@ -470,17 +577,7 @@ gabble_auth_manager_success_finish (WockyAuthRegistry *registry, { GabbleAuthManager *self = GABBLE_AUTH_MANAGER (registry); - if (self->priv->channel != NULL) - { - return gabble_server_sasl_channel_success_finish (self->priv->channel, - result, error); - } - else - { - return WOCKY_AUTH_REGISTRY_CLASS - (gabble_auth_manager_parent_class)->success_finish_func ( - registry, result, error); - } + wocky_implement_finish_void (self, gabble_auth_manager_success_async); } static void @@ -493,7 +590,8 @@ gabble_auth_manager_failure (WockyAuthRegistry *registry, { gabble_server_sasl_channel_fail (self->priv->channel, error); } - else + + if (self->priv->chaining_up) { void (*chain_up)(WockyAuthRegistry *, GError *) = WOCKY_AUTH_REGISTRY_CLASS (gabble_auth_manager_parent_class)-> @@ -576,7 +674,7 @@ gabble_auth_manager_get_failure_details (GabbleAuthManager *self, if (self->priv->channel != NULL) { return gabble_server_sasl_channel_get_failure_details ( - self->priv->channel, dbus_error, details, reason); + self->priv->channel, dbus_error, details, reason, NULL); } else if (self->priv->error != NULL) { diff --git a/src/auth-manager.h b/src/auth-manager.h index bdf7ebfe2..dad5115f9 100644 --- a/src/auth-manager.h +++ b/src/auth-manager.h @@ -22,7 +22,9 @@ #include <glib-object.h> #include <wocky/wocky.h> -#include <telepathy-glib/handle.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> G_BEGIN_DECLS diff --git a/src/base-call-channel.c b/src/base-call-channel.c index 5ea79b27b..3a1c8045a 100644 --- a/src/base-call-channel.c +++ b/src/base-call-channel.c @@ -25,23 +25,14 @@ #include <gio/gio.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/dtmf.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-properties-interface.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "util.h" #include "call-content.h" #include "base-call-channel.h" #include "connection.h" -#include "jingle-session.h" #include "jingle-tp-util.h" #define DEBUG_FLAG GABBLE_DEBUG_MEDIA @@ -209,7 +200,7 @@ gabble_base_call_channel_finalize (GObject *object) GabbleCallContent * gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, const gchar *name, - JingleMediaType mtype, + WockyJingleMediaType mtype, TpCallContentDisposition disposition) { TpBaseChannel *base = TP_BASE_CHANNEL (self); @@ -229,7 +220,7 @@ gabble_base_call_channel_add_content (GabbleBaseCallChannel *self, "connection", tp_base_channel_get_connection (base), "object-path", object_path, "disposition", disposition, - "media-type", jingle_media_type_to_tp (mtype), + "media-type", wocky_jingle_media_type_to_tp (mtype), "name", name, NULL); diff --git a/src/base-call-channel.h b/src/base-call-channel.h index 068b2dada..065b03786 100644 --- a/src/base-call-channel.h +++ b/src/base-call-channel.h @@ -23,11 +23,10 @@ #include <glib-object.h> -#include <telepathy-glib/base-channel.h> -#include <telepathy-glib/base-call-channel.h> -#include <telepathy-glib/base-media-call-channel.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> +#include <wocky/wocky.h> -#include "jingle-content.h" #include "call-member.h" #include "call-content.h" @@ -84,7 +83,7 @@ GabbleCallMember * gabble_base_call_channel_get_member_from_handle ( GabbleCallContent * gabble_base_call_channel_add_content ( GabbleBaseCallChannel *self, const gchar *name, - JingleMediaType mtype, + WockyJingleMediaType mtype, TpCallContentDisposition disposition); void gabble_base_call_channel_remove_content (GabbleBaseCallChannel *self, diff --git a/src/base64.c b/src/base64.c deleted file mode 100644 index 600fa3950..000000000 --- a/src/base64.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * base64.c - Base 64 encoding/decoding implementation - * Copyright (C) 2006 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "base64.h" - -#define DEBUG_FLAG GABBLE_DEBUG_VCARD -#include "debug.h" - -#include <ctype.h> -#include <string.h> - - -/* -|AAAA AABB|BBBB CCCC|CCDD DDDD| - -0xFC = 1111 1100 -0x03 = 0000 0011 -0xF0 = 1111 0000 -0x0F = 0000 1111 -0xC0 = 1100 0000 -0x3F = 0011 1111 - -3 input bytes = 4 output bytes; -2 input bytes = 2 output bytes; -1 input byte = 1 output byte. -*/ - -static const gchar *encoding = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -static const guint decoding[256] = -{ - /* ... */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, - /* + */ - 62, - /* ... */ - 0, 0, 0, - /* / , 0-9 */ - 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - /* ... */ - 0, 0, 0, 0, 0, 0, 0, - /* A */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - /* ... */ - 0, 0, 0, 0, 0, 0, - /* a */ - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 -}; - -#define GET_6_BITS_0(s) (((s)[0] & 0xFC) >> 2) -#define GET_6_BITS_1(s) (((s)[0] & 0x03) << 4) | \ - (((s)[1] & 0xF0) >> 4) -#define GET_6_BITS_2(s) (((s)[1] & 0x0F) << 2) | \ - (((s)[2] & 0xC0) >> 6) -#define GET_6_BITS_3(s) (((s)[2] & 0x3F) << 0) - -#define GET_BYTE_0(s) (((decoding[(guchar)(s)[0]] & 0x3F) << 2) | \ - ((decoding[(guchar)(s)[1]] & 0x30) >> 4)) -#define GET_BYTE_1(s) (((decoding[(guchar)(s)[1]] & 0x0F) << 4) | \ - ((decoding[(guchar)(s)[2]] & 0x3C) >> 2)) -#define GET_BYTE_2(s) (((decoding[(guchar)(s)[2]] & 0x03) << 6) | \ - ((decoding[(guchar)(s)[3]] & 0xFF) << 0)) - -gchar *base64_encode (guint len, const gchar *str, gboolean split_lines) -{ - guint i; - GString *tmp; - - /* TODO: calculate requisite output string length and allocate that big a - * GString */ - tmp = g_string_new (""); - - for (i = 0; i < len; i += 3) - { - guint c1, c2, c3, c4; - - if (split_lines && i > 0 && (i * 4) % 76 == 0) - g_string_append_c (tmp, '\n'); - - switch (i + 3 - len) - { - case 1: - c1 = encoding[GET_6_BITS_0 (str + i)]; - c2 = encoding[GET_6_BITS_1 (str + i)]; - /* can't use GET_6_BITS_2 because str[i+2] is out of range */ - c3 = encoding[(str[i + 1] & 0x0f) << 2]; - c4 = '='; - break; - case 2: - c1 = encoding[GET_6_BITS_0 (str + i)]; - /* can't use GET_6_BITS_1 because str[i+1] is out of range */ - c2 = encoding[(str[i] & 0x03) << 4]; - c3 = '='; - c4 = '='; - break; - default: - c1 = encoding[GET_6_BITS_0 (str + i)]; - c2 = encoding[GET_6_BITS_1 (str + i)]; - c3 = encoding[GET_6_BITS_2 (str + i)]; - c4 = encoding[GET_6_BITS_3 (str + i)]; - } - - g_string_append_printf (tmp, "%c%c%c%c", c1, c2, c3, c4); - } - - return g_string_free (tmp, FALSE); -} - -GString *base64_decode (const gchar *str) -{ - guint i; - GString *tmp; - char group[4]; - guint filled = 0; - - for (i = 0; str[i]; i++) - { - if (str[i] != 'A' && - str[i] != '=' && - !isspace (str[i]) && - decoding[(guchar) str[i]] == 0) - { - DEBUG ("bad character %x at byte %u", (guchar)str[i], i); - return NULL; - } - } - - tmp = g_string_new (""); - - for (i = 0; str[i]; i++) - { - if (isspace (str[i])) - continue; - - group[filled++] = str[i]; - - if (filled == 4) - { - if (group[3] == '=') - { - if (group[2] == '=') - { - g_string_append_c (tmp, GET_BYTE_0(group)); - } - else - { - g_string_append_c (tmp, GET_BYTE_0(group)); - g_string_append_c (tmp, GET_BYTE_1(group)); - } - } - else - { - g_string_append_c (tmp, GET_BYTE_0(group)); - g_string_append_c (tmp, GET_BYTE_1(group)); - g_string_append_c (tmp, GET_BYTE_2(group)); - } - filled = 0; - } - } - - if (filled) - { - DEBUG ("insufficient padding at end of base64 string:\n%s", str); - g_string_free (tmp, TRUE); - return NULL; - } - - return tmp; -} - - diff --git a/src/base64.h b/src/base64.h deleted file mode 100644 index 35bd8f4c6..000000000 --- a/src/base64.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * base64.h - Base 64 encoding/decoding implementation - * Copyright (C) 2006 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __BASE64_H__ -#define __BASE64_H__ - -#include <glib.h> - -gchar *base64_encode (guint len, const gchar *str, gboolean split_lines); -GString *base64_decode (const gchar *str); - -#endif /* __BASE64_H__ */ diff --git a/src/bytestream-factory.c b/src/bytestream-factory.c index 725f06e9f..b3d50fc2a 100644 --- a/src/bytestream-factory.c +++ b/src/bytestream-factory.c @@ -26,7 +26,8 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> #include <wocky/wocky.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM @@ -36,6 +37,7 @@ #include "bytestream-multiple.h" #include "bytestream-socks5.h" #include "connection.h" +#include "conn-util.h" #include "debug.h" #include "disco.h" #include "namespaces.h" @@ -1298,8 +1300,6 @@ out: g_slist_free (stream_methods); g_free (peer_resource); g_free (self_jid); - if (peer_handle != 0) - tp_handle_unref (contact_repo, peer_handle); return TRUE; } @@ -1987,37 +1987,23 @@ streaminit_get_bytestream (GabbleBytestreamFactory *self, struct _streaminit_reply_cb_data { + GabbleBytestreamFactory *self; gchar *stream_id; GabbleBytestreamFactoryNegotiateReplyFunc func; - gpointer user_data; - GObject *object; - gboolean object_alive; + TpWeakRef *weak_object; }; -static void -negotiate_stream_object_destroy_notify_cb (gpointer _data, - GObject *where_the_object_was) -{ - struct _streaminit_reply_cb_data *data = - (struct _streaminit_reply_cb_data*) _data; - - data->object = NULL; - data->object_alive = FALSE; -} - /* Called when we receive the reply of a SI request */ static void -streaminit_reply_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, - gpointer user_data) +streaminit_reply_cb ( + GObject *source, + GAsyncResult *result, + gpointer user_data) { - GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (obj); - GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE ( - self); - struct _streaminit_reply_cb_data *data = - (struct _streaminit_reply_cb_data*) user_data; + GabbleConnection *conn = GABBLE_CONNECTION (source); + struct _streaminit_reply_cb_data *data = user_data; + GabbleBytestreamFactory *self = data->self; + GabbleBytestreamFactoryPrivate *priv = self->priv; GabbleBytestreamIface *bytestream = NULL; gchar *peer_resource = NULL; WockyNode *si; @@ -2030,20 +2016,16 @@ streaminit_reply_cb (GabbleConnection *conn, TpHandle room_handle; gboolean success = FALSE; gchar *self_jid = NULL; + GObject *object = tp_weak_ref_dup_object (data->weak_object); + WockyStanza *reply_msg = NULL; - if (data->object != NULL) - { - g_object_weak_unref (data->object, - negotiate_stream_object_destroy_notify_cb, data); - } - - if (!data->object_alive) + if (object == NULL) { DEBUG ("Object which requested the bytestream was disposed. Ignoring"); goto END; } - if (wocky_stanza_extract_errors (reply_msg, NULL, NULL, NULL, NULL)) + if (!conn_util_send_iq_finish (conn, result, &reply_msg, NULL)) { DEBUG ("stream %s declined", data->stream_id); goto END; @@ -2139,18 +2121,21 @@ END: } /* user callback */ - if (data->object_alive) - data->func (bytestream, (const gchar*) data->stream_id, reply_msg, - data->object, data->user_data); + if (object != NULL) + { + data->func (bytestream, reply_msg, + object, tp_weak_ref_get_user_data (data->weak_object)); + g_clear_object (&object); + } if (peer_resource != NULL) g_free (peer_resource); - if (peer_handle != 0) - tp_handle_unref (contact_repo, peer_handle); - + g_clear_object (&reply_msg); + g_clear_object (&data->self); g_free (self_jid); g_free (data->stream_id); + tp_weak_ref_destroy (data->weak_object); g_slice_free (struct _streaminit_reply_cb_data, data); } @@ -2162,54 +2147,37 @@ END: * @stream_id: the stream identifier * @func: the callback to call when we receive the answser of the request * @user_data: user data to pass to the callback - * @object: if non-NULL the handler will follow the lifetime of that object, + * @object: the handler will follow the lifetime of this object, * which means that if the object is destroyed the callback will not be invoked. - * @error: pointer in which to return a GError in case of failure. * * Send a Stream Initiation (XEP-0095) request. */ -gboolean +void gabble_bytestream_factory_negotiate_stream (GabbleBytestreamFactory *self, WockyStanza *msg, const gchar *stream_id, GabbleBytestreamFactoryNegotiateReplyFunc func, gpointer user_data, - GObject *object, - GError **error) + GObject *object) { GabbleBytestreamFactoryPrivate *priv; struct _streaminit_reply_cb_data *data; - gboolean result; g_assert (GABBLE_IS_BYTESTREAM_FACTORY (self)); g_assert (stream_id != NULL); g_assert (func != NULL); + g_assert (object != NULL); priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self); data = g_slice_new (struct _streaminit_reply_cb_data); + data->self = g_object_ref (self); data->stream_id = g_strdup (stream_id); data->func = func; - data->user_data = user_data; - data->object_alive = TRUE; - data->object = object; - - if (object != NULL) - { - g_object_weak_ref (object, negotiate_stream_object_destroy_notify_cb, - data); - } - - result = _gabble_connection_send_with_reply (priv->conn, msg, - streaminit_reply_cb, G_OBJECT (self), data, error); - - if (!result) - { - g_free (data->stream_id); - g_slice_free (struct _streaminit_reply_cb_data, data); - } + data->weak_object = tp_weak_ref_new (object, user_data, NULL); - return result; + conn_util_send_iq_async (priv->conn, msg, NULL, + streaminit_reply_cb, data); } /* diff --git a/src/bytestream-factory.h b/src/bytestream-factory.h index 7a86cd4f8..76287e0d3 100644 --- a/src/bytestream-factory.h +++ b/src/bytestream-factory.h @@ -21,7 +21,7 @@ #define __BYTESTREAM_FACTORY_H__ #include <glib-object.h> -#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/telepathy-glib.h> #include "types.h" #include "bytestream-iface.h" #include "bytestream-ibb.h" @@ -71,7 +71,7 @@ typedef struct { } GabbleSocks5Proxy; typedef void (* GabbleBytestreamFactoryNegotiateReplyFunc) ( - GabbleBytestreamIface *bytestream, const gchar *stream_id, WockyStanza *msg, + GabbleBytestreamIface *bytestream, WockyStanza *msg, GObject *object, gpointer user_data); GabbleBytestreamFactory *gabble_bytestream_factory_new ( @@ -97,10 +97,10 @@ WockyStanza *gabble_bytestream_factory_make_multi_accept_iq ( const gchar *full_jid, const gchar *stream_init_id, GList *stream_methods); -gboolean gabble_bytestream_factory_negotiate_stream ( +void gabble_bytestream_factory_negotiate_stream ( GabbleBytestreamFactory *fac, WockyStanza *msg, const gchar *stream_id, GabbleBytestreamFactoryNegotiateReplyFunc func, - gpointer user_data, GObject *object, GError **error); + gpointer user_data, GObject *object); gchar *gabble_bytestream_factory_generate_stream_id (void); diff --git a/src/bytestream-ibb.c b/src/bytestream-ibb.c index bfa1b5641..c413beb6a 100644 --- a/src/bytestream-ibb.c +++ b/src/bytestream-ibb.c @@ -24,11 +24,11 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM -#include "base64.h" #include "bytestream-factory.h" #include "bytestream-iface.h" #include "connection.h" @@ -124,16 +124,12 @@ gabble_bytestream_ibb_dispose (GObject *object) { GabbleBytestreamIBB *self = GABBLE_BYTESTREAM_IBB (object); GabbleBytestreamIBBPrivate *priv = GABBLE_BYTESTREAM_IBB_GET_PRIVATE (self); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); if (priv->dispose_has_run) return; priv->dispose_has_run = TRUE; - tp_handle_unref (contact_repo, priv->peer_handle); - if (priv->state != GABBLE_BYTESTREAM_STATE_CLOSED) { gabble_bytestream_iface_close (GABBLE_BYTESTREAM_IFACE (self), NULL); @@ -285,8 +281,6 @@ gabble_bytestream_ibb_constructor (GType type, contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - tp_handle_ref (contact_repo, priv->peer_handle); - jid = tp_handle_inspect (contact_repo, priv->peer_handle); if (priv->peer_resource != NULL) @@ -511,7 +505,7 @@ send_data (GabbleBytestreamIBB *self, send_now = remaining; } - encoded = base64_encode (send_now, str + sent, FALSE); + encoded = g_base64_encode ((const guchar *) str + sent, send_now); seq = g_strdup_printf ("%u", priv->seq++); iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, @@ -613,6 +607,8 @@ gabble_bytestream_ibb_receive (GabbleBytestreamIBB *self, GabbleBytestreamIBBPrivate *priv = GABBLE_BYTESTREAM_IBB_GET_PRIVATE (self); WockyNode *data; GString *str; + guchar *st; + gsize outlen; TpHandle sender; /* caller must have checked for this in order to know which bytestream to @@ -638,7 +634,9 @@ gabble_bytestream_ibb_receive (GabbleBytestreamIBB *self, /* FIXME: check sequence number */ - str = base64_decode (data->content); + st = g_base64_decode (data->content, &outlen); + str = g_string_new_len ((gchar *) st, outlen); + g_free (st); if (str == NULL) { DEBUG ("base64 decoding failed"); diff --git a/src/bytestream-ibb.h b/src/bytestream-ibb.h index fa1af3a2e..2d96baf12 100644 --- a/src/bytestream-ibb.h +++ b/src/bytestream-ibb.h @@ -22,7 +22,7 @@ #include <glib-object.h> #include <wocky/wocky.h> -#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/bytestream-muc.c b/src/bytestream-muc.c index 4a803bc58..6c0d28e47 100644 --- a/src/bytestream-muc.c +++ b/src/bytestream-muc.c @@ -24,11 +24,11 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM -#include "base64.h" #include "bytestream-factory.h" #include "bytestream-iface.h" #include "connection.h" @@ -100,16 +100,12 @@ gabble_bytestream_muc_dispose (GObject *object) { GabbleBytestreamMuc *self = GABBLE_BYTESTREAM_MUC (object); GabbleBytestreamMucPrivate *priv = GABBLE_BYTESTREAM_MUC_GET_PRIVATE (self); - TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM); if (priv->dispose_has_run) return; priv->dispose_has_run = TRUE; - tp_handle_unref (room_repo, priv->peer_handle); - if (priv->state != GABBLE_BYTESTREAM_STATE_CLOSED) { gabble_bytestream_iface_close (GABBLE_BYTESTREAM_IFACE (self), NULL); @@ -228,8 +224,6 @@ gabble_bytestream_muc_constructor (GType type, room_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM); - tp_handle_ref (room_repo, priv->peer_handle); - priv->peer_jid = tp_handle_inspect (room_repo, priv->peer_handle); @@ -345,7 +339,7 @@ send_data_to (GabbleBytestreamMuc *self, frag = FRAG_LAST; } - encoded = base64_encode (send_now, str + sent, FALSE); + encoded = g_base64_encode ((const guchar *) str + sent, send_now); wocky_node_set_content (data, encoded); switch (frag) @@ -411,6 +405,8 @@ gabble_bytestream_muc_receive (GabbleBytestreamMuc *self, const gchar *from; WockyNode *data; GString *str; + guchar *st; + gsize outlen; TpHandle sender; GString *buffer; const gchar *frag_val; @@ -459,7 +455,9 @@ gabble_bytestream_muc_receive (GabbleBytestreamMuc *self, return; } - str = base64_decode (data->content); + st = g_base64_decode (data->content, &outlen); + str = g_string_new_len ((const gchar *) st, outlen); + g_free (st); if (str == NULL) { DEBUG ("base64 decoding failed"); diff --git a/src/bytestream-muc.h b/src/bytestream-muc.h index 06dcd2689..393410eec 100644 --- a/src/bytestream-muc.h +++ b/src/bytestream-muc.h @@ -22,7 +22,7 @@ #include <glib-object.h> #include <wocky/wocky.h> -#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/bytestream-multiple.c b/src/bytestream-multiple.c index 07243e1f1..49bdc5907 100644 --- a/src/bytestream-multiple.c +++ b/src/bytestream-multiple.c @@ -22,11 +22,12 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/interfaces.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM -#include "base64.h" #include "bytestream-factory.h" #include "bytestream-iface.h" #include "connection.h" @@ -100,16 +101,12 @@ gabble_bytestream_multiple_dispose (GObject *object) GabbleBytestreamMultiple *self = GABBLE_BYTESTREAM_MULTIPLE (object); GabbleBytestreamMultiplePrivate *priv = GABBLE_BYTESTREAM_MULTIPLE_GET_PRIVATE (self); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); if (priv->dispose_has_run) return; priv->dispose_has_run = TRUE; - tp_handle_unref (contact_repo, priv->peer_handle); - if (priv->state != GABBLE_BYTESTREAM_STATE_CLOSED) { gabble_bytestream_iface_close (GABBLE_BYTESTREAM_IFACE (self), NULL); @@ -263,8 +260,6 @@ gabble_bytestream_multiple_constructor (GType type, contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - tp_handle_ref (contact_repo, priv->peer_handle); - jid = tp_handle_inspect (contact_repo, priv->peer_handle); if (priv->peer_resource != NULL) diff --git a/src/bytestream-socks5.c b/src/bytestream-socks5.c index 12bd7c509..48686d35f 100644 --- a/src/bytestream-socks5.c +++ b/src/bytestream-socks5.c @@ -44,7 +44,9 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/interfaces.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <gibber/gibber-transport.h> #include <gibber/gibber-tcp-transport.h> @@ -52,10 +54,10 @@ #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM -#include "base64.h" #include "bytestream-factory.h" #include "bytestream-iface.h" #include "connection.h" +#include "conn-util.h" #include "debug.h" #include "disco.h" #include "gabble-signals-marshal.h" @@ -232,8 +234,6 @@ gabble_bytestream_socks5_dispose (GObject *object) GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (object); GabbleBytestreamSocks5Private *priv = GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); if (priv->dispose_has_run) return; @@ -242,8 +242,6 @@ gabble_bytestream_socks5_dispose (GObject *object) stop_timer (self); - tp_handle_unref (contact_repo, priv->peer_handle); - if (priv->bytestream_state != GABBLE_BYTESTREAM_STATE_CLOSED) { gabble_bytestream_iface_close (GABBLE_BYTESTREAM_IFACE (self), NULL); @@ -398,8 +396,6 @@ gabble_bytestream_socks5_constructor (GType type, room_repo = tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_ROOM); - tp_handle_ref (contact_repo, priv->peer_handle); - jid = tp_handle_inspect (contact_repo, priv->peer_handle); if (priv->peer_resource != NULL) @@ -766,17 +762,22 @@ target_got_connect_reply (GabbleBytestreamSocks5 *self) } static void -socks5_activation_reply_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, - gpointer user_data) +socks5_activation_reply_cb ( + GObject *source, + GAsyncResult *result, + gpointer user_data) { - GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (user_data); - GabbleBytestreamSocks5Private *priv = GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE ( - self); + TpWeakRef *weak_ref = user_data; + GabbleBytestreamSocks5 *self = tp_weak_ref_dup_object (weak_ref); + GabbleBytestreamSocks5Private *priv; + WockyStanza *reply_msg = NULL; + + tp_weak_ref_destroy (weak_ref); + if (self == NULL) + return; + priv = self->priv; - if (wocky_stanza_extract_errors (reply_msg, NULL, NULL, NULL, NULL)) + if (!conn_util_send_iq_finish (GABBLE_CONNECTION (source), result, &reply_msg, NULL)) { DEBUG ("Activation failed"); goto activation_failed; @@ -795,11 +796,15 @@ socks5_activation_reply_cb (GabbleConnection *conn, g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_OPEN, NULL); /* We can read data from the sock5 socket now */ gibber_transport_block_receiving (priv->transport, FALSE); + goto out; - return; activation_failed: g_signal_emit_by_name (self, "connection-error"); g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_CLOSED, NULL); + +out: + g_clear_object (&reply_msg); + g_object_unref (self); } static void @@ -825,15 +830,8 @@ initiator_got_connect_reply (GabbleBytestreamSocks5 *self) /* Block reading while waiting for the activation reply */ gibber_transport_block_receiving (priv->transport, TRUE); - if (!_gabble_connection_send_with_reply (priv->conn, iq, - socks5_activation_reply_cb, G_OBJECT (self), self, NULL)) - { - DEBUG ("Sending activation IQ failed"); - - g_signal_emit_by_name (self, "connection-error"); - g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_CLOSED, NULL); - } - + conn_util_send_iq_async (priv->conn, iq, NULL, + socks5_activation_reply_cb, tp_weak_ref_new (self, NULL, NULL)); g_object_unref (iq); } @@ -1543,17 +1541,22 @@ initiator_connected_to_proxy (GabbleBytestreamSocks5 *self) } static void -socks5_init_reply_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, - gpointer user_data) +socks5_init_reply_cb ( + GObject *source, + GAsyncResult *result, + gpointer user_data) { - GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (obj); - GabbleBytestreamSocks5Private *priv = - GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self); + TpWeakRef *weak_ref = user_data; + GabbleBytestreamSocks5 *self = tp_weak_ref_dup_object (weak_ref); + GabbleBytestreamSocks5Private *priv; + WockyStanza *reply_msg = NULL; + + tp_weak_ref_destroy (weak_ref); + if (self == NULL) + return; + priv = self->priv; - if (!wocky_stanza_extract_errors (reply_msg, NULL, NULL, NULL, NULL)) + if (conn_util_send_iq_finish (GABBLE_CONNECTION (source), result, &reply_msg, NULL)) { WockyNode *query, *streamhost = NULL; const gchar *jid; @@ -1590,7 +1593,7 @@ socks5_init_reply_cb (GabbleConnection *conn, priv->proxy_jid = g_strdup (jid); initiator_connected_to_proxy (self); - return; + goto out; } /* No proxy used */ @@ -1609,7 +1612,7 @@ socks5_init_reply_cb (GabbleConnection *conn, g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_OPEN, NULL); /* We can read data from the sock5 socket now */ gibber_transport_block_receiving (priv->transport, FALSE); - return; + goto out; } socks5_init_error: @@ -1617,6 +1620,10 @@ socks5_init_error: g_signal_emit_by_name (self, "connection-error"); g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_CLOSED, NULL); + +out: + g_clear_object (&reply_msg); + g_object_unref (self); } #ifdef G_OS_WIN32 @@ -1866,49 +1873,19 @@ new_connection_cb (GibberListener *listener, } /* - * gabble_bytestream_socks5_initiate - * - * Implements gabble_bytestream_iface_initiate on GabbleBytestreamIface + * Consumes @ips. */ -static gboolean -gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface) +static void +send_streamhosts ( + GabbleBytestreamSocks5 *self, + GSList *ips, + gint port_num) { - GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (iface); - GabbleBytestreamSocks5Private *priv = - GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self); + GabbleBytestreamSocks5Private *priv = self->priv; gchar *port; - gint port_num; WockyStanza *msg; WockyNode *query_node; - GSList *ips, *ip; - - if (priv->bytestream_state != GABBLE_BYTESTREAM_STATE_INITIATING) - { - DEBUG ("bytestream is not is the initiating state (state %d)", - priv->bytestream_state); - return FALSE; - } - ips = get_local_interfaces_ips (); - if (ips == NULL) - { - DEBUG ("Can't get IP addresses"); - return FALSE; - } - - g_assert (priv->listener == NULL); - priv->listener = gibber_listener_new (); - - g_signal_connect (priv->listener, "new-connection", - G_CALLBACK (new_connection_cb), self); - - if (!gibber_listener_listen_tcp (priv->listener, 0, NULL)) - { - DEBUG ("can't listen for incoming connection"); - return FALSE; - } - - port_num = gibber_listener_get_port (priv->listener); port = g_strdup_printf ("%d", port_num); msg = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, @@ -1920,17 +1897,17 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface) '*', &query_node, ')', NULL); - for (ip = ips; ip != NULL; ip = g_slist_next (ip)) + for (; port_num != 0 && ips != NULL; ips = g_slist_delete_link (ips, ips)) { WockyNode *node = wocky_node_add_child (query_node, "streamhost"); wocky_node_set_attributes (node, "jid", priv->self_full_jid, - "host", ip->data, + "host", ips->data, "port", port, NULL); - g_free (ip->data); + g_free (ips->data); } g_slist_free (ips); @@ -1958,7 +1935,7 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface) NULL); g_free (portstr); } - g_slist_free (proxies); + g_slist_free (proxies); } else { @@ -1968,17 +1945,57 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface) priv->socks5_state = SOCKS5_STATE_INITIATOR_OFFER_SENT; - if (!_gabble_connection_send_with_reply (priv->conn, msg, - socks5_init_reply_cb, G_OBJECT (self), NULL, NULL)) - { - DEBUG ("Error when sending Socks5 init stanza"); + conn_util_send_iq_async (priv->conn, msg, NULL, + socks5_init_reply_cb, tp_weak_ref_new (self, NULL, NULL)); + g_object_unref (msg); +} + +/* + * gabble_bytestream_socks5_initiate + * + * Implements gabble_bytestream_iface_initiate on GabbleBytestreamIface + */ +static gboolean +gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface) +{ + GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (iface); + GabbleBytestreamSocks5Private *priv = + GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self); + GSList *ips; + guint port_num = 0; - g_object_unref (msg); + if (priv->bytestream_state != GABBLE_BYTESTREAM_STATE_INITIATING) + { + DEBUG ("bytestream is not is the initiating state (state %d)", + priv->bytestream_state); return FALSE; } - g_object_unref (msg); + ips = get_local_interfaces_ips (); + if (ips == NULL) + { + DEBUG ("Can't get IP addresses; will send empty offer."); + } + else + { + g_assert (priv->listener == NULL); + priv->listener = gibber_listener_new (); + + g_signal_connect (priv->listener, "new-connection", + G_CALLBACK (new_connection_cb), self); + + if (!gibber_listener_listen_tcp (priv->listener, 0, NULL)) + { + DEBUG ("can't listen for incoming connection; will send empty offer."); + g_slist_foreach (ips, (GFunc) g_free, NULL); + g_slist_free (ips); + ips = NULL; + } + + port_num = gibber_listener_get_port (priv->listener); + } + send_streamhosts (self, ips, port_num); return TRUE; } diff --git a/src/bytestream-socks5.h b/src/bytestream-socks5.h index 524812f32..f3704e469 100644 --- a/src/bytestream-socks5.h +++ b/src/bytestream-socks5.h @@ -24,7 +24,7 @@ #include <glib-object.h> #include <wocky/wocky.h> -#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/call-channel.c b/src/call-channel.c index 8e7b4bce2..6e247aa0d 100644 --- a/src/call-channel.c +++ b/src/call-channel.c @@ -26,20 +26,15 @@ #include <gio/gio.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> +#include <wocky/wocky.h> #include "util.h" #include "call-channel.h" #include "call-content.h" #include "connection.h" -#include "jingle-session.h" #include "jingle-tp-util.h" #include "presence-cache.h" @@ -49,15 +44,15 @@ static void async_initable_iface_init (GAsyncInitableIface *iface); -static void call_session_state_changed_cb (GabbleJingleSession *session, +static void call_session_state_changed_cb (WockyJingleSession *session, GParamSpec *param, GabbleCallChannel *self); static void call_member_content_added_cb (GabbleCallMember *member, GabbleCallMemberContent *content, GabbleCallChannel *self); static void call_member_content_removed_cb (GabbleCallMember *member, GabbleCallMemberContent *mcontent, GabbleBaseCallChannel *self); -static void call_session_terminated_cb (GabbleJingleSession *session, - gboolean locally_terminated, JingleReason termination_reason, +static void call_session_terminated_cb (WockyJingleSession *session, + gboolean locally_terminated, WockyJingleReason termination_reason, gchar *reason_text, GabbleCallChannel *self); static void call_channel_accept (TpBaseMediaCallChannel *channel); @@ -91,7 +86,7 @@ struct _GabbleCallChannelPrivate /* Our only call member, owned by the base channel */ GabbleCallMember *member; - GabbleJingleSession *session; + WockyJingleSession *session; }; static void @@ -227,9 +222,9 @@ gabble_call_channel_class_init ( tp_base_media_call_class->hold_state_changed = call_channel_hold_state_changed; - param_spec = g_param_spec_object ("session", "GabbleJingleSession object", + param_spec = g_param_spec_object ("session", "WockyJingleSession object", "Jingle session associated with this media channel object.", - GABBLE_TYPE_JINGLE_SESSION, + WOCKY_TYPE_JINGLE_SESSION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SESSION, param_spec); } @@ -258,8 +253,8 @@ gabble_call_channel_finalize (GObject *object) } static void -call_session_terminated_cb (GabbleJingleSession *session, - gboolean locally_terminated, JingleReason termination_reason, +call_session_terminated_cb (WockyJingleSession *session, + gboolean locally_terminated, WockyJingleReason termination_reason, gchar *reason_text, GabbleCallChannel *self) { TpHandle actor; @@ -283,66 +278,66 @@ call_session_terminated_cb (GabbleJingleSession *session, switch (termination_reason) { - case JINGLE_REASON_UNKNOWN: + case WOCKY_JINGLE_REASON_UNKNOWN: call_reason = TP_CALL_STATE_CHANGE_REASON_UNKNOWN; break; - case JINGLE_REASON_BUSY: + case WOCKY_JINGLE_REASON_BUSY: call_reason = TP_CALL_STATE_CHANGE_REASON_BUSY; break; - case JINGLE_REASON_CANCEL: + case WOCKY_JINGLE_REASON_CANCEL: if (locally_terminated) call_reason = TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED; else call_reason = TP_CALL_STATE_CHANGE_REASON_REJECTED; break; - case JINGLE_REASON_CONNECTIVITY_ERROR: + case WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR: call_reason = TP_CALL_STATE_CHANGE_REASON_CONNECTIVITY_ERROR; break; - case JINGLE_REASON_FAILED_APPLICATION: + case WOCKY_JINGLE_REASON_FAILED_APPLICATION: call_reason = TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR; dbus_detail = TP_ERROR_STR_MEDIA_CODECS_INCOMPATIBLE; break; - case JINGLE_REASON_GENERAL_ERROR: + case WOCKY_JINGLE_REASON_GENERAL_ERROR: call_reason = TP_CALL_STATE_CHANGE_REASON_SERVICE_ERROR; break; - case JINGLE_REASON_GONE: + case WOCKY_JINGLE_REASON_GONE: /* This one is only in the media channel, we don't have a * Call reason to match */ call_reason = TP_CALL_STATE_CHANGE_REASON_UNKNOWN; break; - case JINGLE_REASON_MEDIA_ERROR: + case WOCKY_JINGLE_REASON_MEDIA_ERROR: call_reason = TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR; break; - case JINGLE_REASON_SUCCESS: + case WOCKY_JINGLE_REASON_SUCCESS: call_reason = TP_CALL_STATE_CHANGE_REASON_USER_REQUESTED; break; - case JINGLE_REASON_TIMEOUT: + case WOCKY_JINGLE_REASON_TIMEOUT: call_reason = TP_CALL_STATE_CHANGE_REASON_NO_ANSWER; break; - case JINGLE_REASON_DECLINE: + case WOCKY_JINGLE_REASON_DECLINE: call_reason = TP_CALL_STATE_CHANGE_REASON_REJECTED; break; - case JINGLE_REASON_ALTERNATIVE_SESSION: + case WOCKY_JINGLE_REASON_ALTERNATIVE_SESSION: break; - case JINGLE_REASON_UNSUPPORTED_TRANSPORTS: + case WOCKY_JINGLE_REASON_UNSUPPORTED_TRANSPORTS: call_reason = TP_CALL_STATE_CHANGE_REASON_NETWORK_ERROR; break; - case JINGLE_REASON_FAILED_TRANSPORT: + case WOCKY_JINGLE_REASON_FAILED_TRANSPORT: call_reason = TP_CALL_STATE_CHANGE_REASON_CONNECTIVITY_ERROR; dbus_detail = TP_ERROR_STR_CONNECTION_FAILED; break; - case JINGLE_REASON_INCOMPATIBLE_PARAMETERS: + case WOCKY_JINGLE_REASON_INCOMPATIBLE_PARAMETERS: call_reason = TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR; dbus_detail = TP_ERROR_STR_MEDIA_CODECS_INCOMPATIBLE; break; - case JINGLE_REASON_SECURITY_ERROR: + case WOCKY_JINGLE_REASON_SECURITY_ERROR: call_reason = TP_CALL_STATE_CHANGE_REASON_CONNECTIVITY_ERROR; break; - case JINGLE_REASON_UNSUPPORTED_APPLICATIONS: + case WOCKY_JINGLE_REASON_UNSUPPORTED_APPLICATIONS: call_reason = TP_CALL_STATE_CHANGE_REASON_MEDIA_ERROR; dbus_detail = TP_ERROR_STR_MEDIA_UNSUPPORTED_TYPE; break; - case JINGLE_REASON_EXPIRED: + case WOCKY_JINGLE_REASON_EXPIRED: /* No matching error in our spec */ call_reason = TP_CALL_STATE_CHANGE_REASON_UNKNOWN; break; @@ -357,16 +352,16 @@ call_session_terminated_cb (GabbleJingleSession *session, } static void -call_session_state_changed_cb (GabbleJingleSession *session, +call_session_state_changed_cb (WockyJingleSession *session, GParamSpec *param, GabbleCallChannel *self) { TpBaseCallChannel *cbase = TP_BASE_CALL_CHANNEL (self); - JingleState state; + WockyJingleState state; g_object_get (session, "state", &state, NULL); - if (state == JINGLE_STATE_ACTIVE && !tp_base_call_channel_is_accepted (cbase)) + if (state == WOCKY_JINGLE_STATE_ACTIVE && !tp_base_call_channel_is_accepted (cbase)) { tp_base_call_channel_remote_accept (cbase); } @@ -379,13 +374,13 @@ call_member_content_added_cb (GabbleCallMember *member, GabbleCallChannel *self) { GabbleBaseCallChannel *cbase = GABBLE_BASE_CALL_CHANNEL (self); - GabbleJingleContent *jingle_content; + WockyJingleContent *jingle_content; GabbleCallContent *c; jingle_content = gabble_call_member_content_get_jingle_content (content); if (jingle_content == NULL || - gabble_jingle_content_is_created_by_us (jingle_content)) + wocky_jingle_content_is_created_by_us (jingle_content)) return; c = gabble_base_call_channel_add_content (cbase, @@ -435,11 +430,11 @@ contact_is_media_capable (GabbleCallChannel *self, *wait_ret = wait; if (presence == NULL) - g_set_error (error, TP_ERRORS, TP_ERROR_OFFLINE, + g_set_error (error, TP_ERROR, TP_ERROR_OFFLINE, "contact %d (%s) has no presence available", handle, tp_handle_inspect (contact_handles, handle)); else - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_CAPABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "contact %d (%s) doesn't have sufficient media caps", handle, tp_handle_inspect (contact_handles, handle)); @@ -649,7 +644,7 @@ static void call_channel_accept (TpBaseMediaCallChannel *channel) { GabbleCallChannel *self = GABBLE_CALL_CHANNEL (channel); - gabble_jingle_session_accept (self->priv->session); + wocky_jingle_session_accept (self->priv->session); } static TpBaseCallContent * @@ -662,12 +657,12 @@ call_channel_add_content (TpBaseCallChannel *base, GabbleCallChannel *self = GABBLE_CALL_CHANNEL (base); GabbleCallContent *content = NULL; GabbleCallMemberContent *mcontent; - JingleContentSenders senders; + WockyJingleContentSenders senders; gboolean initiated_by_us; if (initial_direction == TP_MEDIA_STREAM_DIRECTION_NONE) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Jingle can not do contents with direction = NONE"); return NULL; } @@ -679,25 +674,25 @@ call_channel_add_content (TpBaseCallChannel *base, { case TP_MEDIA_STREAM_DIRECTION_SEND: senders = initiated_by_us ? - JINGLE_CONTENT_SENDERS_INITIATOR : JINGLE_CONTENT_SENDERS_RESPONDER; + WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER; break; case TP_MEDIA_STREAM_DIRECTION_RECEIVE: senders = initiated_by_us ? - JINGLE_CONTENT_SENDERS_RESPONDER : JINGLE_CONTENT_SENDERS_INITIATOR; + WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; break; default: case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: - senders = JINGLE_CONTENT_SENDERS_BOTH; + senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; } mcontent = gabble_call_member_create_content (self->priv->member, name, - jingle_media_type_from_tp (type), senders, error); + wocky_jingle_media_type_from_tp (type), senders, error); if (mcontent != NULL) { content = gabble_base_call_channel_add_content ( GABBLE_BASE_CALL_CHANNEL (base), - name, jingle_media_type_from_tp (type), + name, wocky_jingle_media_type_from_tp (type), TP_CALL_CONTENT_DISPOSITION_NONE); gabble_call_content_add_member_content (content, mcontent); } @@ -715,10 +710,10 @@ call_channel_hold_state_changed (TpBaseMediaCallChannel *bmcc, { case TP_LOCAL_HOLD_STATE_HELD: case TP_LOCAL_HOLD_STATE_PENDING_HOLD: - gabble_jingle_session_set_local_hold (self->priv->session, TRUE); + wocky_jingle_session_set_local_hold (self->priv->session, TRUE); break; case TP_LOCAL_HOLD_STATE_UNHELD: - gabble_jingle_session_set_local_hold (self->priv->session, FALSE); + wocky_jingle_session_set_local_hold (self->priv->session, FALSE); break; case TP_LOCAL_HOLD_STATE_PENDING_UNHOLD: break; diff --git a/src/call-content.c b/src/call-content.c index 8550b82fc..827dc2445 100644 --- a/src/call-content.c +++ b/src/call-content.c @@ -23,19 +23,12 @@ #include <stdio.h> #include <stdlib.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/svc-properties-interface.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "call-member.h" #include "call-content.h" #include "call-stream.h" -#include "jingle-content.h" -#include "jingle-session.h" -#include "jingle-media-rtp.h" #include "jingle-tp-util.h" #include "connection.h" #include "util.h" @@ -167,7 +160,7 @@ gabble_call_content_new_offer (GabbleCallContent *self, codecs = gabble_call_member_content_get_remote_codecs (content); for (l = codecs; l != NULL; l = g_list_next (l)) { - JingleCodec *c = l->data; + WockyJingleCodec *c = l->data; tp_call_content_media_description_append_codec (md, c->id, c->name, c->clockrate, c->channels, @@ -184,12 +177,12 @@ gabble_call_content_new_offer (GabbleCallContent *self, g_free (path); } -JingleMediaType +WockyJingleMediaType gabble_call_content_get_media_type (GabbleCallContent *self) { TpBaseCallContent *base = TP_BASE_CALL_CONTENT (self); - return jingle_media_type_from_tp ( + return wocky_jingle_media_type_from_tp ( tp_base_call_content_get_media_type (base)); } @@ -214,7 +207,7 @@ codec_array_to_list (GPtrArray *codecs) for (i = 0; i < codecs->len ; i++) { - JingleCodec *c; + WockyJingleCodec *c; GValueArray *va; va = g_ptr_array_index (codecs, i); @@ -241,7 +234,7 @@ call_content_local_media_description_updated (GabbleCallContent *self, gpointer data) { GList *l; - JingleMediaDescription *md = jingle_media_description_new (); + WockyJingleMediaDescription *md = wocky_jingle_media_description_new (); md->codecs = codec_array_to_list (tp_asv_get_boxed (properties, TP_PROP_CALL_CONTENT_MEDIA_DESCRIPTION_CODECS, @@ -250,22 +243,22 @@ call_content_local_media_description_updated (GabbleCallContent *self, for (l = self->priv->contents; l != NULL; l = g_list_next (l)) { GabbleCallMemberContent *c = GABBLE_CALL_MEMBER_CONTENT (l->data); - GabbleJingleContent *j = + WockyJingleContent *j = gabble_call_member_content_get_jingle_content (c); if (j == NULL) continue; /* FIXME react properly on errors ? */ - jingle_media_rtp_set_local_media_description (GABBLE_JINGLE_MEDIA_RTP (j), - jingle_media_description_copy (md), TRUE, NULL); + jingle_media_rtp_set_local_media_description (WOCKY_JINGLE_MEDIA_RTP (j), + wocky_jingle_media_description_copy (md), TRUE, NULL); } - jingle_media_description_free (md); + wocky_jingle_media_description_free (md); } static TpStreamTransportType -_jingle_to_tp_transport (JingleTransportType jt) +_jingle_to_tp_transport (WockyJingleTransportType jt) { switch (jt) { @@ -285,11 +278,11 @@ call_content_setup_jingle (GabbleCallContent *self, GabbleCallMemberContent *mcontent) { TpBaseCallContent *base = TP_BASE_CALL_CONTENT (self); - GabbleJingleContent *jingle; + WockyJingleContent *jingle; GabbleCallStream *stream; gchar *path; - JingleTransportType transport; - JingleMediaDescription *md; + WockyJingleTransportType transport; + WockyJingleMediaDescription *md; GHashTable *tp_md; TpHandle contact; @@ -298,7 +291,7 @@ call_content_setup_jingle (GabbleCallContent *self, if (jingle == NULL) return; - transport = gabble_jingle_content_get_transport_type (jingle); + transport = wocky_jingle_content_get_transport_type (jingle); path = g_strdup_printf ("%s/Stream%p", tp_base_call_content_get_object_path (base), jingle); @@ -310,7 +303,7 @@ call_content_setup_jingle (GabbleCallContent *self, NULL); g_free (path); - md = jingle_media_description_new (); + md = wocky_jingle_media_description_new (); /* FIXME: correct??? */ contact = gabble_call_member_get_handle ( @@ -326,9 +319,9 @@ call_content_setup_jingle (GabbleCallContent *self, if (md->codecs != NULL) jingle_media_rtp_set_local_media_description ( - GABBLE_JINGLE_MEDIA_RTP (jingle), md, TRUE, NULL); + WOCKY_JINGLE_MEDIA_RTP (jingle), md, TRUE, NULL); else - jingle_media_description_free (md); + wocky_jingle_media_description_free (md); tp_base_call_content_add_stream (base, TP_BASE_CALL_STREAM (stream)); gabble_call_stream_update_member_states (stream); @@ -350,7 +343,7 @@ member_content_removed_cb (GabbleCallMemberContent *mcontent, GabbleCallContent *self = GABBLE_CALL_CONTENT (user_data); GabbleCallContentPrivate *priv = self->priv; TpBaseCallContent *base = TP_BASE_CALL_CONTENT (self); - GabbleJingleContent *content; + WockyJingleContent *content; GList *l; priv->contents = g_list_remove (priv->contents, mcontent); diff --git a/src/call-content.h b/src/call-content.h index ff3205f55..e675d57fa 100644 --- a/src/call-content.h +++ b/src/call-content.h @@ -23,9 +23,9 @@ #include <glib-object.h> -#include <telepathy-glib/base-media-call-content.h> +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> -#include "jingle-content.h" #include "call-member-content.h" G_BEGIN_DECLS @@ -63,7 +63,7 @@ GType gabble_call_content_get_type (void); (G_TYPE_INSTANCE_GET_CLASS ((obj), \ GABBLE_TYPE_CALL_CONTENT, GabbleCallContentClass)) -JingleMediaType gabble_call_content_get_media_type (GabbleCallContent *self); +WockyJingleMediaType gabble_call_content_get_media_type (GabbleCallContent *self); void gabble_call_content_new_offer (GabbleCallContent *self, GabbleCallMemberContent *content); diff --git a/src/call-member-content.c b/src/call-member-content.c index 8899b0f58..4500de14c 100644 --- a/src/call-member-content.c +++ b/src/call-member-content.c @@ -25,7 +25,6 @@ #include "call-member.h" #include "call-member-content.h" -#include "jingle-media-rtp.h" #include "util.h" #include "namespaces.h" @@ -62,9 +61,9 @@ struct _GabbleCallMemberContentPrivate GabbleCallMember *member; - GabbleJingleContent *jingle_content; + WockyJingleContent *jingle_content; gchar *name; - JingleMediaType media_type; + WockyJingleMediaType media_type; GList *remote_codecs; gboolean removed; @@ -136,7 +135,7 @@ gabble_call_member_content_set_property (GObject *object, break; case PROP_MEDIA_TYPE: priv->media_type = g_value_get_uint (value); - g_assert (priv->media_type != JINGLE_MEDIA_TYPE_NONE); + g_assert (priv->media_type != WOCKY_JINGLE_MEDIA_TYPE_NONE); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -152,8 +151,8 @@ gabble_call_member_content_add_to_session (GabbleCallMemberContent *self) { GabbleCallMemberContentPrivate *priv = self->priv; const gchar *content_ns; - GabbleJingleSession *session; - GabbleJingleContent *content; + WockyJingleSession *session; + WockyJingleContent *content; const gchar *peer_resource; const gchar *transport_ns; @@ -170,7 +169,7 @@ gabble_call_member_content_add_to_session (GabbleCallMemberContent *self) g_assert (session != NULL); - peer_resource = gabble_jingle_session_get_peer_resource (session); + peer_resource = wocky_jingle_session_get_peer_resource (session); if (peer_resource != NULL) DEBUG ("existing call, using peer resource %s", peer_resource); @@ -180,8 +179,8 @@ gabble_call_member_content_add_to_session (GabbleCallMemberContent *self) DEBUG ("Creating new jingle content with ns %s : %s", content_ns, transport_ns); - content = gabble_jingle_session_add_content (session, - priv->media_type, JINGLE_CONTENT_SENDERS_BOTH, + content = wocky_jingle_session_add_content (session, + priv->media_type, WOCKY_JINGLE_CONTENT_SENDERS_BOTH, priv->name, content_ns, transport_ns); gabble_call_member_content_set_jingle_content (self, content); @@ -237,16 +236,16 @@ gabble_call_member_content_class_init ( param_spec = g_param_spec_uint ("media-type", "MediaType", "The media type of this jingle content", - JINGLE_MEDIA_TYPE_NONE, - JINGLE_MEDIA_TYPE_VIDEO, - JINGLE_MEDIA_TYPE_NONE, + WOCKY_JINGLE_MEDIA_TYPE_NONE, + WOCKY_JINGLE_MEDIA_TYPE_VIDEO, + WOCKY_JINGLE_MEDIA_TYPE_NONE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); param_spec = g_param_spec_object ("jingle-content", "JingleContent", "The jingle content corresponding to this members content", - GABBLE_TYPE_JINGLE_CONTENT, + WOCKY_TYPE_JINGLE_CONTENT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_JINGLE_CONTENT, param_spec); @@ -311,7 +310,7 @@ gabble_call_member_content_finalize (GObject *object) G_OBJECT_CLASS (gabble_call_member_content_parent_class)->finalize (object); } -JingleMediaType +WockyJingleMediaType gabble_call_member_content_get_media_type (GabbleCallMemberContent *self) { return self->priv->media_type; @@ -323,7 +322,7 @@ gabble_call_member_content_get_name (GabbleCallMemberContent *self) return self->priv->name; } -GabbleJingleContent * +WockyJingleContent * gabble_call_member_content_get_jingle_content ( GabbleCallMemberContent *self) { @@ -332,7 +331,7 @@ gabble_call_member_content_get_jingle_content ( GabbleCallMemberContent * gabble_call_member_content_new (const gchar *name, - JingleMediaType type, + WockyJingleMediaType type, GabbleCallMember *member) { return GABBLE_CALL_MEMBER_CONTENT (g_object_new ( @@ -344,7 +343,7 @@ gabble_call_member_content_new (const gchar *name, } static void -call_member_content_jingle_removed_cb (GabbleJingleContent *jingle_content, +call_member_content_jingle_removed_cb (WockyJingleContent *jingle_content, GabbleCallMemberContent *content) { if (!content->priv->removed) @@ -355,8 +354,8 @@ call_member_content_jingle_removed_cb (GabbleJingleContent *jingle_content, } static void -call_member_content_jingle_media_description_cb (GabbleJingleMediaRtp *media, - JingleMediaDescription *md, +call_member_content_jingle_media_description_cb (WockyJingleMediaRtp *media, + WockyJingleMediaDescription *md, gpointer user_data) { GabbleCallMemberContent *self = GABBLE_CALL_MEMBER_CONTENT (user_data); @@ -368,12 +367,12 @@ call_member_content_jingle_media_description_cb (GabbleJingleMediaRtp *media, GabbleCallMemberContent * gabble_call_member_content_from_jingle_content ( - GabbleJingleContent *jingle_content, + WockyJingleContent *jingle_content, GabbleCallMember *member) { GabbleCallMemberContent *content; gchar *name; - JingleMediaType mtype; + WockyJingleMediaType mtype; g_object_get (jingle_content, "name", &name, @@ -403,9 +402,9 @@ gabble_call_member_content_get_remote_codecs (GabbleCallMemberContent *self) if (self->priv->jingle_content != NULL) { - JingleMediaDescription *md; - md = gabble_jingle_media_rtp_get_remote_media_description ( - GABBLE_JINGLE_MEDIA_RTP (self->priv->jingle_content)); + WockyJingleMediaDescription *md; + md = wocky_jingle_media_rtp_get_remote_media_description ( + WOCKY_JINGLE_MEDIA_RTP (self->priv->jingle_content)); if (md != NULL) jcodecs = md->codecs; } @@ -447,7 +446,7 @@ gabble_call_member_content_get_member (GabbleCallMemberContent *self) void gabble_call_member_content_set_jingle_content (GabbleCallMemberContent *self, - GabbleJingleContent *content) + WockyJingleContent *content) { g_assert (self->priv->jingle_content == NULL); @@ -478,7 +477,7 @@ gabble_call_member_content_remove (GabbleCallMemberContent *self) g_object_ref (self); /* Remove ourselves from the sesison */ if (priv->jingle_content != NULL) - gabble_jingle_session_remove_content (priv->jingle_content->session, + wocky_jingle_session_remove_content (priv->jingle_content->session, priv->jingle_content); g_signal_emit (self, signals[REMOVED], 0); diff --git a/src/call-member-content.h b/src/call-member-content.h index 98034096e..0f47d61ab 100644 --- a/src/call-member-content.h +++ b/src/call-member-content.h @@ -22,10 +22,9 @@ #define __CALL_MEMBER_CONTENT_H__ #include <glib-object.h> +#include <wocky/wocky.h> #include "types.h" -#include "jingle-content.h" -#include "jingle-media-rtp.h" G_BEGIN_DECLS @@ -61,20 +60,20 @@ GType gabble_call_member_content_get_type (void); GabbleCallMemberContentClass)) GabbleCallMemberContent *gabble_call_member_content_new (const gchar *name, - JingleMediaType type, + WockyJingleMediaType type, GabbleCallMember *member); GabbleCallMemberContent *gabble_call_member_content_from_jingle_content ( - GabbleJingleContent *jingle_content, + WockyJingleContent *jingle_content, GabbleCallMember *member); -JingleMediaType gabble_call_member_content_get_media_type ( +WockyJingleMediaType gabble_call_member_content_get_media_type ( GabbleCallMemberContent *self); const gchar *gabble_call_member_content_get_name ( GabbleCallMemberContent *self); -GabbleJingleContent *gabble_call_member_content_get_jingle_content ( +WockyJingleContent *gabble_call_member_content_get_jingle_content ( GabbleCallMemberContent *self); gboolean gabble_call_member_content_has_jingle_content ( @@ -95,7 +94,7 @@ GabbleCallMember *gabble_call_member_content_get_member ( void gabble_call_member_content_set_jingle_content ( GabbleCallMemberContent *self, - GabbleJingleContent *content); + WockyJingleContent *content); void gabble_call_member_content_add_to_session ( GabbleCallMemberContent *self); diff --git a/src/call-member.c b/src/call-member.c index aba19013b..935dfaf71 100644 --- a/src/call-member.c +++ b/src/call-member.c @@ -60,7 +60,7 @@ struct _GabbleCallMemberPrivate GabbleBaseCallChannel *call; TpCallMemberFlags flags; - GabbleJingleSession *session; + WockyJingleSession *session; GList *contents; gchar *transport_ns; @@ -126,7 +126,7 @@ gabble_call_member_set_property (GObject *object, break; case PROP_SESSION: gabble_call_member_set_session (self, - GABBLE_JINGLE_SESSION (g_value_get_object (value))); + WOCKY_JINGLE_SESSION (g_value_get_object (value))); break; case PROP_TARGET: priv->target = g_value_get_uint (value); @@ -165,7 +165,7 @@ gabble_call_member_class_init ( param_spec = g_param_spec_object ("session", "Session", "The jingle session below this call", - GABBLE_TYPE_JINGLE_SESSION, + WOCKY_TYPE_JINGLE_SESSION, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SESSION, param_spec); @@ -243,16 +243,16 @@ gabble_call_member_finalize (GObject *object) } static void -remote_state_changed_cb (GabbleJingleSession *session, gpointer user_data) +remote_state_changed_cb (WockyJingleSession *session, gpointer user_data) { GabbleCallMember *self = GABBLE_CALL_MEMBER (user_data); GabbleCallMemberPrivate *priv = self->priv; TpCallMemberFlags newflags = 0; - if (gabble_jingle_session_get_remote_ringing (session)) + if (wocky_jingle_session_get_remote_ringing (session)) newflags |= TP_CALL_MEMBER_FLAG_RINGING; - if (gabble_jingle_session_get_remote_hold (session)) + if (wocky_jingle_session_get_remote_hold (session)) newflags |= TP_CALL_MEMBER_FLAG_HELD; if (priv->flags == newflags) @@ -293,14 +293,14 @@ gabble_call_member_add_member_content (GabbleCallMember *self, /* This function handles additional contents added by the remote side */ static void -new_content_cb (GabbleJingleSession *session, - GabbleJingleContent *c, +new_content_cb (WockyJingleSession *session, + WockyJingleContent *c, gpointer user_data) { GabbleCallMember *self = GABBLE_CALL_MEMBER (user_data); GabbleCallMemberContent *content = NULL; - if (gabble_jingle_content_is_created_by_us (c)) + if (wocky_jingle_content_is_created_by_us (c)) return; content = gabble_call_member_content_from_jingle_content (c, self); @@ -310,7 +310,7 @@ new_content_cb (GabbleJingleSession *session, static gboolean call_member_update_existing_content (GabbleCallMember *self, - GabbleJingleContent *content) + WockyJingleContent *content) { GList *l; @@ -322,7 +322,7 @@ call_member_update_existing_content (GabbleCallMember *self, continue; if (!tp_strdiff (gabble_call_member_content_get_name (mcontent), - gabble_jingle_content_get_name (content))) + wocky_jingle_content_get_name (content))) { gabble_call_member_content_set_jingle_content (mcontent, content); return TRUE; @@ -334,7 +334,7 @@ call_member_update_existing_content (GabbleCallMember *self, void gabble_call_member_set_session (GabbleCallMember *self, - GabbleJingleSession *session) + WockyJingleSession *session) { GabbleCallMemberPrivate *priv = self->priv; GList *c, *contents; @@ -345,10 +345,10 @@ gabble_call_member_set_session (GabbleCallMember *self, DEBUG ("Setting session: %p -> %p\n", self, session); priv->session = g_object_ref (session); - contents = gabble_jingle_session_get_contents (session); + contents = wocky_jingle_session_get_contents (session); for (c = contents ; c != NULL; c = g_list_next (c)) { - GabbleJingleContent *content = GABBLE_JINGLE_CONTENT (c->data); + WockyJingleContent *content = WOCKY_JINGLE_CONTENT (c->data); if (priv->transport_ns == NULL) { @@ -380,7 +380,7 @@ gabble_call_member_set_session (GabbleCallMember *self, g_list_free (contents); } -GabbleJingleSession * +WockyJingleSession * gabble_call_member_get_session (GabbleCallMember *self) { return self->priv->session; @@ -409,7 +409,7 @@ gabble_call_member_get_contents (GabbleCallMember *self) GabbleCallMemberContent * gabble_call_member_ensure_content (GabbleCallMember *self, const gchar *name, - JingleMediaType mtype) + WockyJingleMediaType mtype) { GabbleCallMemberPrivate *priv = self->priv; GList *l; @@ -439,19 +439,19 @@ gabble_call_member_ensure_content (GabbleCallMember *self, GabbleCallMemberContent * gabble_call_member_create_content (GabbleCallMember *self, const gchar *name, - JingleMediaType mtype, - JingleContentSenders senders, + WockyJingleMediaType mtype, + WockyJingleContentSenders senders, GError **error) { GabbleCallMemberPrivate *priv = self->priv; const gchar *content_ns; - GabbleJingleContent *c; + WockyJingleContent *c; GabbleCallMemberContent *content; const gchar *peer_resource; g_assert (priv->session != NULL); - peer_resource = gabble_jingle_session_get_peer_resource (priv->session); + peer_resource = wocky_jingle_session_get_peer_resource (priv->session); DEBUG ("Creating new content %s, type %d", name, mtype); @@ -466,7 +466,7 @@ gabble_call_member_create_content (GabbleCallMember *self, if (content_ns == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Content type %d not available for this resource", mtype); return NULL; } @@ -474,7 +474,7 @@ gabble_call_member_create_content (GabbleCallMember *self, DEBUG ("Creating new jingle content with ns %s : %s", content_ns, priv->transport_ns); - c = gabble_jingle_session_add_content (priv->session, + c = wocky_jingle_session_add_content (priv->session, mtype, senders, name, content_ns, priv->transport_ns); g_assert (c != NULL); @@ -492,7 +492,7 @@ gabble_call_member_accept (GabbleCallMember *self) self->priv->accepted = TRUE; if (self->priv->session != NULL) - gabble_jingle_session_accept (self->priv->session); + wocky_jingle_session_accept (self->priv->session); } /** @@ -506,8 +506,8 @@ gabble_call_member_open_session (GabbleCallMember *self, { GabbleCallMemberPrivate *priv = self->priv; GabbleConnection *conn = gabble_call_member_get_connection (self); - GabbleJingleFactory *jf; - GabbleJingleSession *session; + WockyJingleFactory *jf; + WockyJingleSession *session; gchar *jid; jid = gabble_peer_to_jid (conn, priv->target, NULL); @@ -515,7 +515,7 @@ gabble_call_member_open_session (GabbleCallMember *self, jf = gabble_jingle_mint_get_factory (conn->jingle_mint); g_return_val_if_fail (jf != NULL, FALSE); - session = gabble_jingle_factory_create_session (jf, jid, JINGLE_DIALECT_V032, + session = wocky_jingle_factory_create_session (jf, jid, WOCKY_JINGLE_DIALECT_V032, FALSE); DEBUG ("Created a jingle session: %p", session); @@ -538,11 +538,11 @@ gabble_call_member_start_session (GabbleCallMember *self, TpBaseChannel *base_channel = TP_BASE_CHANNEL (priv->call); TpHandle target = tp_base_channel_get_target_handle (base_channel); const gchar *resource; - JingleDialect dialect; + WockyJingleDialect dialect; gchar *jid; const gchar *transport; - GabbleJingleFactory *jf; - GabbleJingleSession *session; + WockyJingleFactory *jf; + WockyJingleSession *session; /* FIXME might need to wait on capabilities, also don't need transport * and dialect already */ @@ -550,7 +550,7 @@ gabble_call_member_start_session (GabbleCallMember *self, target, audio_name != NULL, video_name != NULL, &transport, &dialect, &resource)) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_CAPABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "member does not have the desired audio/video capabilities"); return FALSE; } @@ -561,7 +561,7 @@ gabble_call_member_start_session (GabbleCallMember *self, gabble_call_member_get_connection (self)->jingle_mint); g_return_val_if_fail (jf != NULL, FALSE); - session = gabble_jingle_factory_create_session (jf, jid, dialect, FALSE); + session = wocky_jingle_factory_create_session (jf, jid, dialect, FALSE); g_free (jid); gabble_call_member_set_session (self, session); @@ -570,11 +570,11 @@ gabble_call_member_start_session (GabbleCallMember *self, if (audio_name != NULL) gabble_call_member_create_content (self, audio_name, - JINGLE_MEDIA_TYPE_AUDIO, JINGLE_CONTENT_SENDERS_BOTH, NULL); + WOCKY_JINGLE_MEDIA_TYPE_AUDIO, WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NULL); if (video_name != NULL) gabble_call_member_create_content (self, video_name, - JINGLE_MEDIA_TYPE_VIDEO, JINGLE_CONTENT_SENDERS_BOTH, NULL); + WOCKY_JINGLE_MEDIA_TYPE_VIDEO, WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NULL); return TRUE; } @@ -600,8 +600,8 @@ gabble_call_member_shutdown (GabbleCallMember *self) if (priv->session != NULL) { - gabble_jingle_session_terminate (priv->session, - JINGLE_REASON_UNKNOWN, NULL, NULL); + wocky_jingle_session_terminate (priv->session, + WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); } /* removing the content will remove it from our list */ diff --git a/src/call-member.h b/src/call-member.h index 5554a9ec0..bc8afe027 100644 --- a/src/call-member.h +++ b/src/call-member.h @@ -23,10 +23,10 @@ #include <glib-object.h> -#include <telepathy-glib/handle.h> +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> #include "types.h" -#include "jingle-session.h" #include "call-member-content.h" G_BEGIN_DECLS @@ -63,12 +63,12 @@ GType gabble_call_member_get_type (void); GabbleCallMemberClass)) void gabble_call_member_set_session (GabbleCallMember *member, - GabbleJingleSession *session); + WockyJingleSession *session); TpHandle gabble_call_member_get_handle ( GabbleCallMember *self); -GabbleJingleSession *gabble_call_member_get_session ( +WockyJingleSession *gabble_call_member_get_session ( GabbleCallMember *self); TpCallMemberFlags gabble_call_member_get_flags ( @@ -79,13 +79,13 @@ GList *gabble_call_member_get_contents (GabbleCallMember *self); GabbleCallMemberContent * gabble_call_member_ensure_content ( GabbleCallMember *self, const gchar *name, - JingleMediaType mtype); + WockyJingleMediaType mtype); GabbleCallMemberContent * gabble_call_member_create_content ( GabbleCallMember *self, const gchar *name, - JingleMediaType mtype, - JingleContentSenders senders, + WockyJingleMediaType mtype, + WockyJingleContentSenders senders, GError **error); gboolean gabble_call_member_start_session (GabbleCallMember *self, diff --git a/src/call-muc-channel.c b/src/call-muc-channel.c index 62d40c695..1dbf3b23c 100644 --- a/src/call-muc-channel.c +++ b/src/call-muc-channel.c @@ -23,11 +23,9 @@ #include <stdio.h> #include <stdlib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> -#include <wocky/wocky.h> #include "call-content.h" #include "muc-channel.h" @@ -418,7 +416,7 @@ call_muc_channel_member_content_added_cb (GabbleCallMember *member, { GabbleCallMucChannel *self = GABBLE_CALL_MUC_CHANNEL (user_data); const gchar *name; - JingleMediaType mtype; + WockyJingleMediaType mtype; GList *l; GabbleCallContent *ccontent; @@ -433,7 +431,7 @@ call_muc_channel_member_content_added_cb (GabbleCallMember *member, TP_BASE_CALL_CHANNEL (self)); l != NULL; l = g_list_next (l)) { const char *cname; - JingleMediaType cmtype; + WockyJingleMediaType cmtype; ccontent = GABBLE_CALL_CONTENT (l->data); cname = tp_base_call_content_get_name ( @@ -470,7 +468,7 @@ call_muc_channel_parse_codecs (GabbleCallMucChannel *self, guint id; guint clockrate = 0; guint channels = 0; - JingleCodec *codec; + WockyJingleCodec *codec; WockyNodeIter param_iter; WockyNode *parameter; @@ -542,13 +540,13 @@ call_muc_channel_send_new_state (GabbleCallMucChannel *self) GHashTable *tp_md; GPtrArray *codecs; guint i; - JingleMediaType mtype = gabble_call_content_get_media_type (content); + WockyJingleMediaType mtype = gabble_call_content_get_media_type (content); wocky_node_add_build (m, '(', "content", '@', "name", name, '(', "description", ':', NS_JINGLE_RTP, '*', &description, - '@', "media", mtype == JINGLE_MEDIA_TYPE_AUDIO ? "audio" : "video", + '@', "media", mtype == WOCKY_JINGLE_MEDIA_TYPE_AUDIO ? "audio" : "video", ')', ')', NULL); @@ -626,7 +624,7 @@ call_muc_channel_parse_participant (GabbleCallMucChannel *self, { GabbleCallMemberContent *member_content; WockyNode *description; - JingleMediaType mtype; + WockyJingleMediaType mtype; const gchar *name; const gchar *mattr; GList *codecs; @@ -656,11 +654,11 @@ call_muc_channel_parse_participant (GabbleCallMucChannel *self, if (!tp_strdiff (mattr, "video")) { - mtype = JINGLE_MEDIA_TYPE_VIDEO; + mtype = WOCKY_JINGLE_MEDIA_TYPE_VIDEO; } else if (!tp_strdiff (mattr, "audio")) { - mtype = JINGLE_MEDIA_TYPE_AUDIO; + mtype = WOCKY_JINGLE_MEDIA_TYPE_AUDIO; } else { @@ -679,7 +677,7 @@ call_muc_channel_parse_participant (GabbleCallMucChannel *self, if (!priv->initialized) { - if (mtype == JINGLE_MEDIA_TYPE_AUDIO) + if (mtype == WOCKY_JINGLE_MEDIA_TYPE_AUDIO) g_object_set (self, "initial-audio", TRUE, NULL); else g_object_set (self, "initial-video", TRUE, NULL); @@ -998,7 +996,7 @@ call_muc_channel_init_async (GAsyncInitable *initable, { content = gabble_base_call_channel_add_content ( GABBLE_BASE_CALL_CHANNEL (base), - initial_audio_name, JINGLE_MEDIA_TYPE_AUDIO, + initial_audio_name, WOCKY_JINGLE_MEDIA_TYPE_AUDIO, TP_CALL_CONTENT_DISPOSITION_INITIAL); call_muc_channel_setup_content (self, content); } @@ -1007,7 +1005,7 @@ call_muc_channel_init_async (GAsyncInitable *initable, { content = gabble_base_call_channel_add_content ( GABBLE_BASE_CALL_CHANNEL (base), - initial_video_name, JINGLE_MEDIA_TYPE_VIDEO, + initial_video_name, WOCKY_JINGLE_MEDIA_TYPE_VIDEO, TP_CALL_CONTENT_DISPOSITION_INITIAL); call_muc_channel_setup_content (self, content); } @@ -1110,13 +1108,13 @@ gabble_call_muc_channel_new_finish (GObject *source, void gabble_call_muc_channel_incoming_session (GabbleCallMucChannel *self, - GabbleJingleSession *session) + WockyJingleSession *session) { GabbleCallMember *member; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( tp_base_channel_get_connection (TP_BASE_CHANNEL (self)), TP_HANDLE_TYPE_CONTACT); - const gchar *jid = gabble_jingle_session_get_peer_jid (session); + const gchar *jid = wocky_jingle_session_get_peer_jid (session); TpHandle peer = tp_handle_ensure (contact_repo, jid, NULL, NULL); DEBUG ("New incoming session from %s", jid); @@ -1125,8 +1123,8 @@ gabble_call_muc_channel_incoming_session (GabbleCallMucChannel *self, if (member == NULL || gabble_call_member_get_session (member) != NULL) { - gabble_jingle_session_terminate (session, - JINGLE_REASON_UNKNOWN, + wocky_jingle_session_terminate (session, + WOCKY_JINGLE_REASON_UNKNOWN, "Muji jingle session initiated while there already was one", NULL); } @@ -1163,14 +1161,14 @@ call_muc_channel_add_content (TpBaseCallChannel *base, if (initial_direction == TP_MEDIA_STREAM_DIRECTION_NONE) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Jingle can not do contents with direction = NONE"); return NULL; } if (initial_direction != TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Adding un-directional contents is not supported" " in MUC channels"); return NULL; @@ -1178,7 +1176,7 @@ call_muc_channel_add_content (TpBaseCallChannel *base, content = gabble_base_call_channel_add_content ( GABBLE_BASE_CALL_CHANNEL (base), - name, jingle_media_type_from_tp (type), + name, wocky_jingle_media_type_from_tp (type), TP_CALL_CONTENT_DISPOSITION_NONE); call_muc_channel_setup_content (self, content); diff --git a/src/call-muc-channel.h b/src/call-muc-channel.h index aa51700e1..e3df68235 100644 --- a/src/call-muc-channel.h +++ b/src/call-muc-channel.h @@ -22,9 +22,9 @@ #define __GABBLE_CALL_MUC_CHANNEL_H__ #include <glib-object.h> +#include <wocky/wocky.h> #include "base-call-channel.h" -#include "jingle-session.h" G_BEGIN_DECLS @@ -75,7 +75,7 @@ GabbleCallMucChannel * gabble_call_muc_channel_new_finish (GObject *source, GError **error); void gabble_call_muc_channel_incoming_session (GabbleCallMucChannel *self, - GabbleJingleSession *session); + WockyJingleSession *session); G_END_DECLS diff --git a/src/call-stream.c b/src/call-stream.c index a25365db9..89af93ce1 100644 --- a/src/call-stream.c +++ b/src/call-stream.c @@ -23,16 +23,11 @@ #include <stdio.h> #include <stdlib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/svc-properties-interface.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "call-stream.h" #include "connection.h" -#include "jingle-session.h" -#include "jingle-content.h" #include "jingle-tp-util.h" #include "util.h" @@ -84,7 +79,7 @@ struct _GabbleCallStreamPrivate { gboolean dispose_has_run; - GabbleJingleContent *content; + WockyJingleContent *content; }; static void @@ -103,25 +98,25 @@ static GPtrArray * get_stun_servers (GabbleCallStream *self) { GPtrArray *arr; - GabbleJingleFactory *jf; - gchar *stun_server; - guint stun_port; + WockyJingleFactory *jf; + GList *stun_servers; arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free); - jf = gabble_jingle_session_get_factory (self->priv->content->session); + jf = wocky_jingle_session_get_factory (self->priv->content->session); + stun_servers = wocky_jingle_info_get_stun_servers ( + wocky_jingle_factory_get_jingle_info (jf)); - /* maybe one day we'll support multiple STUN servers */ - if (gabble_jingle_info_get_stun_server ( - gabble_jingle_factory_get_jingle_info (jf), - &stun_server, &stun_port)) + while (stun_servers != NULL) { + WockyStunServer *stun_server = stun_servers->data; GValueArray *va = tp_value_array_build (2, - G_TYPE_STRING, stun_server, - G_TYPE_UINT, stun_port, + G_TYPE_STRING, stun_server->address, + G_TYPE_UINT, (guint) stun_server->port, G_TYPE_INVALID); - g_free (stun_server); g_ptr_array_add (arr, va); + + stun_servers = g_list_delete_link (stun_servers, stun_servers); } return arr; @@ -143,9 +138,9 @@ gabble_call_stream_get_property (GObject *object, break; case PROP_CAN_REQUEST_RECEIVING: { - JingleDialect dialect = - gabble_jingle_session_get_dialect (priv->content->session); - g_value_set_boolean (value, !JINGLE_IS_GOOGLE_DIALECT (dialect)); + WockyJingleDialect dialect = + wocky_jingle_session_get_dialect (priv->content->session); + g_value_set_boolean (value, !WOCKY_JINGLE_DIALECT_IS_GOOGLE (dialect)); } break; default: @@ -195,7 +190,7 @@ google_relay_session_cb (GPtrArray *relays, } static void -content_state_changed_cb (GabbleJingleContent *content, +content_state_changed_cb (WockyJingleContent *content, GParamSpec *spec, gpointer user_data) { @@ -205,7 +200,7 @@ content_state_changed_cb (GabbleJingleContent *content, } static void -content_remote_members_changed_cb (GabbleJingleContent *content, +content_remote_members_changed_cb (WockyJingleContent *content, GParamSpec *spec, gpointer user_data) { @@ -216,7 +211,7 @@ content_remote_members_changed_cb (GabbleJingleContent *content, static void jingle_info_stun_server_changed_cb ( - GabbleJingleInfo *jingle_info, + WockyJingleInfo *jingle_info, const gchar *stun_server, guint stun_port, GabbleCallStream *self) @@ -231,7 +226,7 @@ jingle_info_stun_server_changed_cb ( static void _new_candidates_cb ( - GabbleJingleContent *content, + WockyJingleContent *content, GList *candidates, TpCallStreamEndpoint *endpoint) { @@ -241,7 +236,7 @@ _new_candidates_cb ( if (candidates == NULL) return; - if (gabble_jingle_content_get_credentials (content, &ufrag, &pwd)) + if (wocky_jingle_content_get_credentials (content, &ufrag, &pwd)) tp_call_stream_endpoint_set_remote_credentials (endpoint, ufrag, pwd); tp_candidates = gabble_call_candidates_to_array (candidates); @@ -253,19 +248,19 @@ static void _endpoint_state_changed_cb ( TpCallStreamEndpoint *endpoint, GParamSpec *spec, - GabbleJingleContent *content) + WockyJingleContent *content) { TpMediaStreamState state; /* We only care about connecting RTP, RTCP is optional */ state = tp_call_stream_endpoint_get_state (endpoint, 1); - gabble_jingle_content_set_transport_state (content, state); + wocky_jingle_content_set_transport_state (content, state); } static TpCallStreamEndpoint * _hook_up_endpoint (GabbleCallStream *self, const gchar *path, - GabbleJingleContent *content) + WockyJingleContent *content) { TpBaseCallStream *base = (TpBaseCallStream *) self; TpBaseConnection *conn = tp_base_call_stream_get_connection (base); @@ -276,7 +271,7 @@ _hook_up_endpoint (GabbleCallStream *self, GList *candidates; gchar *ufrag, *pwd; - switch (gabble_jingle_content_get_transport_type (content)) + switch (wocky_jingle_content_get_transport_type (content)) { case JINGLE_TRANSPORT_GOOGLE_P2P: type = TP_STREAM_TRANSPORT_TYPE_GTALK_P2P; @@ -295,9 +290,9 @@ _hook_up_endpoint (GabbleCallStream *self, /* FIXME: ice??? */ endpoint = tp_call_stream_endpoint_new (bus, path, type, FALSE); - if (gabble_jingle_content_get_credentials (content, &ufrag, &pwd)) + if (wocky_jingle_content_get_credentials (content, &ufrag, &pwd)) tp_call_stream_endpoint_set_remote_credentials (endpoint, ufrag, pwd); - candidates = gabble_jingle_content_get_remote_candidates (content); + candidates = wocky_jingle_content_get_remote_candidates (content); tp_candidates = gabble_call_candidates_to_array (candidates); tp_call_stream_endpoint_add_new_candidates (endpoint, tp_candidates); g_boxed_free (TP_ARRAY_TYPE_CANDIDATE_LIST, tp_candidates); @@ -321,7 +316,7 @@ gabble_call_stream_constructed (GObject *obj) GabbleConnection *conn; TpCallStreamEndpoint *endpoint; gchar *path; - JingleTransportType transport; + WockyJingleTransportType transport; GPtrArray *stun_servers; gboolean locally_created; @@ -333,7 +328,7 @@ gabble_call_stream_constructed (GObject *obj) g_object_get (priv->content, "locally-created", &locally_created, NULL); if (locally_created && - gabble_jingle_content_sending (priv->content)) + wocky_jingle_content_sending (priv->content)) tp_base_media_call_stream_set_local_sending ( TP_BASE_MEDIA_CALL_STREAM (self), TRUE); @@ -346,7 +341,7 @@ gabble_call_stream_constructed (GObject *obj) g_object_unref (endpoint); g_free (path); - transport = gabble_jingle_content_get_transport_type (priv->content); + transport = wocky_jingle_content_get_transport_type (priv->content); if (transport == JINGLE_TRANSPORT_GOOGLE_P2P) { @@ -355,7 +350,7 @@ gabble_call_stream_constructed (GObject *obj) /* See if our server is Google, and if it is, ask them for a relay. * We ask for enough relays for 2 components (RTP and RTCP) since we * don't yet know whether there will be RTCP. */ - gabble_jingle_info_create_google_relay_session ( + wocky_jingle_info_create_google_relay_session ( gabble_jingle_mint_get_info (conn->jingle_mint), 2, google_relay_session_cb, tp_weak_ref_new (self, NULL, NULL)); } @@ -388,7 +383,7 @@ gabble_call_stream_update_member_states (GabbleCallStream *self) TpBaseCallStream *base = TP_BASE_CALL_STREAM (self); TpBaseMediaCallStream *bmcs = TP_BASE_MEDIA_CALL_STREAM (self); GabbleCallStreamPrivate *priv = self->priv; - JingleContentState state; + WockyJingleContentState state; TpSendingState local_state; TpSendingState remote_state; TpBaseConnection *conn = tp_base_call_stream_get_connection (base); @@ -398,13 +393,13 @@ gabble_call_stream_update_member_states (GabbleCallStream *self) g_object_get (priv->content, "state", &state, NULL); - if (state == JINGLE_CONTENT_STATE_REMOVING) + if (state == WOCKY_JINGLE_CONTENT_STATE_REMOVING) return; local_state = tp_base_call_stream_get_local_sending_state (base); remote_state = tp_base_call_stream_get_remote_sending_state (base, 0); - if (gabble_jingle_content_sending (priv->content)) + if (wocky_jingle_content_sending (priv->content)) { if (tp_base_media_call_stream_get_local_sending (bmcs)) local_state = TP_SENDING_STATE_SENDING; @@ -419,7 +414,7 @@ gabble_call_stream_update_member_states (GabbleCallStream *self) local_state = TP_SENDING_STATE_NONE; } - if (gabble_jingle_content_receiving (priv->content)) + if (wocky_jingle_content_receiving (priv->content)) { remote_state = TP_SENDING_STATE_SENDING; } @@ -433,7 +428,7 @@ gabble_call_stream_update_member_states (GabbleCallStream *self) tp_base_call_stream_update_local_sending_state (base, local_state, 0, TP_CALL_STATE_CHANGE_REASON_PROGRESS_MADE, "", ""); peer = tp_handle_ensure (contact_repo, - gabble_jingle_session_get_peer_jid (priv->content->session), + wocky_jingle_session_get_peer_jid (priv->content->session), NULL, NULL); tp_base_call_stream_update_remote_sending_state (base, @@ -462,7 +457,7 @@ gabble_call_stream_class_init (GabbleCallStreamClass *gabble_call_stream_class) param_spec = g_param_spec_object ("jingle-content", "Jingle Content", "The Jingle Content related to this content object", - GABBLE_TYPE_JINGLE_CONTENT, + WOCKY_TYPE_JINGLE_CONTENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_JINGLE_CONTENT, param_spec); @@ -512,10 +507,10 @@ gabble_call_stream_add_candidates (TpBaseMediaCallStream *stream, for (i = 0; i < candidates->len ; i++) { GValueArray *va; - JingleCandidate *c; + WockyJingleCandidate *c; GHashTable *info; guint tptype; - JingleCandidateType type; + WockyJingleCandidateType type; /* borrowed strings, owned by other people. */ const gchar *username; const gchar *password; @@ -531,13 +526,13 @@ gabble_call_stream_add_candidates (TpBaseMediaCallStream *stream, default: /* Anything else is local */ case TP_CALL_STREAM_CANDIDATE_TYPE_HOST: - type = JINGLE_CANDIDATE_TYPE_LOCAL; + type = WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL; break; case TP_CALL_STREAM_CANDIDATE_TYPE_SERVER_REFLEXIVE: - type = JINGLE_CANDIDATE_TYPE_STUN; + type = WOCKY_JINGLE_CANDIDATE_TYPE_STUN; break; case TP_CALL_STREAM_CANDIDATE_TYPE_RELAY: - type = JINGLE_CANDIDATE_TYPE_RELAY; + type = WOCKY_JINGLE_CANDIDATE_TYPE_RELAY; break; } @@ -553,7 +548,7 @@ gabble_call_stream_add_candidates (TpBaseMediaCallStream *stream, if (foundation == NULL) foundation = "1"; - c = jingle_candidate_new ( + c = wocky_jingle_candidate_new ( /* transport protocol */ tp_asv_get_uint32 (info, "protocol", NULL), /* Candidate type */ @@ -580,11 +575,11 @@ gabble_call_stream_add_candidates (TpBaseMediaCallStream *stream, g_ptr_array_add (accepted_candidates, va); } - gabble_jingle_content_add_candidates (priv->content, l); + wocky_jingle_content_add_candidates (priv->content, l); if (accepted_candidates->len == 0 && candidates->len != 0) { - g_set_error_literal (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "All candidates had the wrong Type"); tp_clear_pointer (&accepted_candidates, g_ptr_array_unref); } @@ -602,7 +597,7 @@ gabble_call_stream_set_sending (TpBaseMediaCallStream *stream, if (sending) tp_base_media_call_stream_set_local_sending (stream, TRUE); - gabble_jingle_content_set_sending (self->priv->content, sending); + wocky_jingle_content_set_sending (self->priv->content, sending); return TRUE; } @@ -612,10 +607,10 @@ static void gabble_call_stream_request_receiving (TpBaseMediaCallStream *stream, { GabbleCallStream *self = GABBLE_CALL_STREAM (stream); - gabble_jingle_content_request_receiving (self->priv->content, receive); + wocky_jingle_content_request_receiving (self->priv->content, receive); } -GabbleJingleContent * +WockyJingleContent * gabble_call_stream_get_jingle_content (GabbleCallStream *stream) { return stream->priv->content; diff --git a/src/call-stream.h b/src/call-stream.h index ed8bb767f..e83a50c7a 100644 --- a/src/call-stream.h +++ b/src/call-stream.h @@ -23,9 +23,8 @@ #include <glib-object.h> -#include <telepathy-glib/base-media-call-stream.h> - -#include "jingle-types.h" +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> G_BEGIN_DECLS @@ -61,7 +60,7 @@ GType gabble_call_stream_get_type (void); (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CALL_STREAM, \ GabbleCallStreamClass)) -GabbleJingleContent *gabble_call_stream_get_jingle_content ( +WockyJingleContent *gabble_call_stream_get_jingle_content ( GabbleCallStream *stream); void gabble_call_stream_update_member_states (GabbleCallStream *self); diff --git a/src/capabilities.c b/src/capabilities.c index d2b25f57f..1c4801fd8 100644 --- a/src/capabilities.c +++ b/src/capabilities.c @@ -24,11 +24,8 @@ #include <stdlib.h> #include <string.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/handle-repo.h> -#include <telepathy-glib/handle-repo-dynamic.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_PRESENCE #include "debug.h" @@ -64,6 +61,8 @@ static const Feature self_advertised_features[] = { FEATURE_FIXED, NS_TUBES }, { FEATURE_FIXED, NS_BYTESTREAMS }, { FEATURE_FIXED, NS_VERSION }, + { FEATURE_FIXED, NS_LAST }, + { FEATURE_FIXED, NS_RECEIPTS }, #ifdef ENABLE_FILE_TRANSFER { FEATURE_OPTIONAL, NS_FILE_TRANSFER }, @@ -453,7 +452,7 @@ void gabble_capability_set_update (GabbleCapabilitySet *target, const GabbleCapabilitySet *source) { - TpIntSet *ret; + TpIntset *ret; g_return_if_fail (target != NULL); g_return_if_fail (source != NULL); @@ -539,9 +538,7 @@ gabble_capability_set_add (GabbleCapabilitySet *caps, g_return_if_fail (cap != NULL); handle = tp_handle_ensure (feature_handles, cap, NULL, NULL); - tp_handle_set_add (caps->handles, handle); - tp_handle_unref (feature_handles, handle); } gboolean @@ -613,16 +610,17 @@ gboolean gabble_capability_set_has_one (const GabbleCapabilitySet *caps, const GabbleCapabilitySet *alternatives) { - TpIntSetIter iter; + TpIntsetFastIter iter; + guint element; g_return_val_if_fail (caps != NULL, FALSE); g_return_val_if_fail (alternatives != NULL, FALSE); - tp_intset_iter_init (&iter, tp_handle_set_peek (alternatives->handles)); + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (alternatives->handles)); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { - if (tp_handle_set_is_member (caps->handles, iter.element)) + if (tp_handle_set_is_member (caps->handles, element)) { return TRUE; } @@ -636,16 +634,17 @@ gboolean gabble_capability_set_at_least (const GabbleCapabilitySet *caps, const GabbleCapabilitySet *query) { - TpIntSetIter iter; + TpIntsetFastIter iter; + guint element; g_return_val_if_fail (caps != NULL, FALSE); g_return_val_if_fail (query != NULL, FALSE); - tp_intset_iter_init (&iter, tp_handle_set_peek (query->handles)); + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (query->handles)); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { - if (!tp_handle_set_is_member (caps->handles, iter.element)) + if (!tp_handle_set_is_member (caps->handles, element)) { return FALSE; } @@ -670,16 +669,17 @@ void gabble_capability_set_foreach (const GabbleCapabilitySet *caps, GFunc func, gpointer user_data) { - TpIntSetIter iter; + TpIntsetFastIter iter; + guint element; g_return_if_fail (caps != NULL); g_return_if_fail (func != NULL); - tp_intset_iter_init (&iter, tp_handle_set_peek (caps->handles)); + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (caps->handles)); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { - const gchar *var = tp_handle_inspect (feature_handles, iter.element); + const gchar *var = tp_handle_inspect (feature_handles, element); g_return_if_fail (var != NULL); @@ -690,10 +690,10 @@ gabble_capability_set_foreach (const GabbleCapabilitySet *caps, static void append_intset (GString *ret, - const TpIntSet *cap_ints, + const TpIntset *cap_ints, const gchar *indent) { - TpIntSetFastIter iter; + TpIntsetFastIter iter; guint element; tp_intset_fast_iter_init (&iter, cap_ints); @@ -739,7 +739,7 @@ gabble_capability_set_dump_diff (const GabbleCapabilitySet *old_caps, const GabbleCapabilitySet *new_caps, const gchar *indent) { - TpIntSet *old_ints, *new_ints, *rem, *add; + TpIntset *old_ints, *new_ints, *rem, *add; GString *ret; g_return_val_if_fail (old_caps != NULL, NULL); diff --git a/src/caps-channel-manager.c b/src/caps-channel-manager.c index 135427aa0..ec18975e4 100644 --- a/src/caps-channel-manager.c +++ b/src/caps-channel-manager.c @@ -23,9 +23,7 @@ #include "config.h" #include "gabble/caps-channel-manager.h" -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/channel-manager.h> - +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_PRESENCE #include "debug.h" diff --git a/src/caps-hash.c b/src/caps-hash.c index 12d302ec3..ec2efc918 100644 --- a/src/caps-hash.c +++ b/src/caps-hash.c @@ -33,7 +33,6 @@ #define DEBUG_FLAG GABBLE_DEBUG_PRESENCE -#include "base64.h" #include "gabble/capabilities.h" #include "debug.h" #include "namespaces.h" diff --git a/src/conn-addressing.c b/src/conn-addressing.c index c02910e10..7fff35455 100644 --- a/src/conn-addressing.c +++ b/src/conn-addressing.c @@ -23,8 +23,8 @@ #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "extensions/extensions.h" @@ -104,7 +104,6 @@ conn_addressing_get_contacts_by_uri (GabbleSvcConnectionInterfaceAddressing *ifa gabble_svc_connection_interface_addressing_return_from_get_contacts_by_uri ( context, requested, attributes); - tp_handles_unref (contact_repo, handles); g_array_unref (handles); g_hash_table_unref (requested); g_hash_table_unref (attributes); @@ -145,7 +144,6 @@ conn_addressing_get_contacts_by_vcard_field (GabbleSvcConnectionInterfaceAddress gabble_svc_connection_interface_addressing_return_from_get_contacts_by_vcard_field ( context, requested, attributes); - tp_handles_unref (contact_repo, handles); g_array_unref (handles); g_hash_table_unref (requested); g_hash_table_unref (attributes); diff --git a/src/conn-aliasing.c b/src/conn-aliasing.c index f48758eaf..26637039e 100644 --- a/src/conn-aliasing.c +++ b/src/conn-aliasing.c @@ -22,10 +22,9 @@ #include "conn-aliasing.h" #include <wocky/wocky.h> -#include <telepathy-glib/contacts-mixin.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-connection.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_CONNECTION @@ -103,7 +102,6 @@ aliases_request_new (GabbleConnection *conn, const GArray *contacts) { AliasesRequest *request; - TpHandleRepoIface *contact_handles; request = g_slice_new0 (AliasesRequest); request->conn = conn; @@ -116,10 +114,6 @@ aliases_request_new (GabbleConnection *conn, g_new0 (GabbleRequestPipelineItem *, contacts->len); request->aliases = g_new0 (gchar *, contacts->len + 1); - contact_handles = tp_base_connection_get_handles ((TpBaseConnection *) conn, - TP_HANDLE_TYPE_CONTACT); - tp_handles_ref (contact_handles, contacts); - return request; } @@ -128,7 +122,6 @@ static void aliases_request_free (AliasesRequest *request) { guint i; - TpHandleRepoIface *contact_handles; for (i = 0; i < request->contacts->len; i++) { @@ -138,10 +131,6 @@ aliases_request_free (AliasesRequest *request) request->vcard_requests[i]); } - contact_handles = tp_base_connection_get_handles ( - (TpBaseConnection *) request->conn, TP_HANDLE_TYPE_CONTACT); - tp_handles_unref (contact_handles, request->contacts); - g_array_unref (request->contacts); g_free (request->vcard_requests); g_free (request->pep_requests); @@ -262,7 +251,7 @@ aliases_request_basic_pep_cb (GabbleConnection *self, source = _gabble_connection_get_cached_alias (self, handle, NULL); if (source < GABBLE_CONNECTION_ALIAS_FROM_VCARD && - base->status == TP_CONNECTION_STATUS_CONNECTED && + tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_CONNECTED && !gabble_vcard_manager_has_cached_alias (self->vcard_manager, handle)) { /* no alias in PEP, get the vcard */ @@ -303,7 +292,8 @@ aliases_request_pep_cb (GabbleConnection *self, { aliases_request->aliases[index] = alias; } - else if (base->status != TP_CONNECTION_STATUS_CONNECTED) + else if (tp_base_connection_get_status (base) != + TP_CONNECTION_STATUS_CONNECTED) { DEBUG ("no longer connected, not chaining up to vCard"); g_free (alias); @@ -341,7 +331,6 @@ pep_request_cb ( pep_request_ctx *ctx = user_data; ctx->callback (conn, msg, ctx->user_data, error); - tp_handle_unref (ctx->contact_handles, ctx->handle); g_slice_free (pep_request_ctx, ctx); } @@ -362,7 +351,8 @@ gabble_do_pep_request (GabbleConnection *self, pep_request_ctx *ctx; /* callers must check this... */ - g_assert (base->status == TP_CONNECTION_STATUS_CONNECTED); + g_assert (tp_base_connection_get_status (base) == + TP_CONNECTION_STATUS_CONNECTED); /* ... which implies this */ g_assert (self->req_pipeline != NULL); @@ -372,7 +362,6 @@ gabble_do_pep_request (GabbleConnection *self, ctx->contact_handles = contact_handles; ctx->handle = handle; - tp_handle_ref (contact_handles, handle); to = tp_handle_inspect (contact_handles, handle); msg = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET, NULL, to, @@ -512,7 +501,8 @@ set_one_alias ( TP_HANDLE_TYPE_CONTACT); gboolean ret = TRUE; - g_assert (base->status == TP_CONNECTION_STATUS_CONNECTED); + g_assert (tp_base_connection_get_status (base) == + TP_CONNECTION_STATUS_CONNECTED); if (tp_str_empty (alias)) alias = NULL; @@ -521,7 +511,7 @@ set_one_alias ( { ret = FALSE; } - else if (base->self_handle == handle) + else if (tp_base_connection_get_self_handle (base) == handle) { /* only alter the roster if we're already there, e.g. because someone * added us with another client @@ -555,7 +545,7 @@ set_one_alias ( maybe_request_vcard (conn, handle, source); } - if (base->self_handle == handle) + if (tp_base_connection_get_self_handle (base) == handle) { GabbleVCardManagerEditInfo *edit; GQueue edits = G_QUEUE_INIT; @@ -936,7 +926,7 @@ get_cached_remote_alias ( /* XXX: should this be more important than the ones from presence? */ /* if it's our own handle, use alias passed to the connmgr, if any */ - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) { gchar *cm_alias; @@ -1081,7 +1071,7 @@ maybe_request_vcard (GabbleConnection *self, TpHandle handle, /* If the source wasn't good enough then do a request */ if (source < GABBLE_CONNECTION_ALIAS_FROM_VCARD && - base->status == TP_CONNECTION_STATUS_CONNECTED && + tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_CONNECTED && !gabble_vcard_manager_has_cached_alias (self->vcard_manager, handle)) { if (self->features & GABBLE_CONNECTION_FEATURES_PEP) diff --git a/src/conn-avatars.c b/src/conn-avatars.c index 3a12ce290..a90555113 100644 --- a/src/conn-avatars.c +++ b/src/conn-avatars.c @@ -24,11 +24,9 @@ #include <string.h> -#include <telepathy-glib/svc-connection.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/contacts-mixin.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> -#include "base64.h" #include "presence.h" #include "presence-cache.h" #include "conn-presence.h" @@ -57,7 +55,7 @@ update_own_avatar_sha1 (GabbleConnection *conn, return TRUE; tp_svc_connection_interface_avatars_emit_avatar_updated (conn, - base->self_handle, sha1); + tp_base_connection_get_self_handle (base), sha1); g_free (conn->self_presence->avatar_sha1); conn->self_presence->avatar_sha1 = g_strdup (sha1); @@ -88,7 +86,7 @@ connection_avatar_update_cb (GabblePresenceCache *cache, /* sha1 can be "" if we know there is no avatar, but must not be NULL here */ g_assert (sha1 != NULL); - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) update_own_avatar_sha1 (conn, sha1, NULL); else tp_svc_connection_interface_avatars_emit_avatar_updated (conn, @@ -228,7 +226,7 @@ gabble_connection_get_avatar_tokens (TpSvcConnectionInterfaceAvatars *iface, handle = g_array_index (contacts, TpHandle, i); - if (base->self_handle == handle) + if (tp_base_connection_get_self_handle (base) == handle) { if (have_self_avatar) { @@ -294,9 +292,10 @@ _got_self_avatar_for_get_known_avatar_tokens (GObject *obj, g_signal_handler_disconnect (obj, context->signal_conn); - g_assert (base->self_handle != 0); + g_assert (tp_base_connection_get_self_handle (base) != 0); - g_hash_table_insert (context->ret, GUINT_TO_POINTER (base->self_handle), + g_hash_table_insert (context->ret, + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base)), g_strdup (sha1)); tp_svc_connection_interface_avatars_return_from_get_known_avatar_tokens ( @@ -357,7 +356,7 @@ gabble_connection_get_known_avatar_tokens (TpSvcConnectionInterfaceAvatars *ifac handle = g_array_index (contacts, TpHandle, i); - if (base->self_handle == handle) + if (tp_base_connection_get_self_handle (base) == handle) { if (have_self_avatar) { @@ -416,12 +415,14 @@ parse_avatar (WockyNode *vcard, WockyNode *type_node; WockyNode *binval_node; const gchar *binval_value; + guchar *st; + gsize outlen; photo_node = wocky_node_get_child (vcard, "PHOTO"); if (NULL == photo_node) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "contact vCard has no photo"); return FALSE; } @@ -441,7 +442,7 @@ parse_avatar (WockyNode *vcard, if (NULL == binval_node) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "contact avatar is missing binval node"); return FALSE; } @@ -450,16 +451,18 @@ parse_avatar (WockyNode *vcard, if (NULL == binval_value) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "contact avatar is missing binval content"); return FALSE; } - *avatar = base64_decode (binval_value); + st = g_base64_decode (binval_value, &outlen); + *avatar = g_string_new_len ((gchar *) st, outlen); + g_free (st); if (NULL == *avatar) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "failed to decode avatar from base64"); return FALSE; } @@ -489,7 +492,7 @@ _request_avatar_cb (GabbleVCardManager *self, if (NULL == vcard) { - GError tp_error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError tp_error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, vcard_error->message }; if (vcard_error->domain == WOCKY_XMPP_ERROR) @@ -518,7 +521,7 @@ _request_avatar_cb (GabbleVCardManager *self, goto out; } - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) presence = conn->self_presence; else presence = gabble_presence_cache_get (conn->presence_cache, handle); @@ -537,13 +540,13 @@ _request_avatar_cb (GabbleVCardManager *self, DEBUG ("treason uncloaked! avatar hash in presence does not match " "avatar in vCard for handle %u", handle); - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "avatar hash in presence does not match avatar in vCard"); dbus_g_method_return_error (context, error); g_error_free (error); error = NULL; - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) { update_own_avatar_sha1 (conn, sha1, NULL); g_free (sha1); @@ -755,7 +758,7 @@ _set_avatar_cb2 (GabbleVCardManager *manager, if (NULL == vcard) { - GError tp_error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError tp_error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, vcard_error->message }; /* Google Talk has been observed to return bad-request when the avatar is @@ -790,7 +793,8 @@ _set_avatar_cb2 (GabbleVCardManager *manager, tp_svc_connection_interface_avatars_return_from_set_avatar ( ctx->invocation, presence->avatar_sha1); tp_svc_connection_interface_avatars_emit_avatar_updated ( - ctx->conn, base->self_handle, presence->avatar_sha1); + ctx->conn, tp_base_connection_get_self_handle (base), + presence->avatar_sha1); } else { @@ -833,15 +837,25 @@ gabble_connection_set_avatar (TpSvcConnectionInterfaceAvatars *iface, if (avatar != NULL && avatar->len > 0) { + gint state = 0, save = 0, outlen; + /* See the documentation for g_base64_encode_step(). */ + guint base64_data_size = (avatar->len / 3 + 1) * 4 + 4; + guint base64_line_wrapped_data_size = + base64_data_size + (base64_data_size / 72) + 1; + ctx->avatar = g_string_new_len (avatar->data, avatar->len); - base64 = base64_encode (avatar->len, avatar->data, TRUE); + base64 = g_malloc (base64_line_wrapped_data_size); + outlen = g_base64_encode_step ((const guchar *) avatar->data, + avatar->len, TRUE, base64, &state, &save); + outlen += g_base64_encode_close (TRUE, base64 + outlen, &state, &save); + base64[outlen] = '\0'; DEBUG ("Replacing avatar"); edit_info = gabble_vcard_manager_edit_info_new ("PHOTO", NULL, GABBLE_VCARD_EDIT_REPLACE, - "TYPE", mime_type, - "BINVAL", base64, + '(', "TYPE", '$', mime_type, ')', + '(', "BINVAL", '$', base64, ')', NULL); g_free (base64); @@ -890,7 +904,7 @@ conn_avatars_fill_contact_attributes (GObject *obj, TpHandle handle = g_array_index (contacts, guint, i); GabblePresence *presence = NULL; - if (base->self_handle == handle) + if (tp_base_connection_get_self_handle (base) == handle) presence = self->self_presence; else presence = gabble_presence_cache_get (self->presence_cache, handle); diff --git a/src/conn-client-types.c b/src/conn-client-types.c index 012749c19..1a5ff1e8f 100644 --- a/src/conn-client-types.c +++ b/src/conn-client-types.c @@ -22,7 +22,8 @@ #include <string.h> #include <stdlib.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <extensions/extensions.h> diff --git a/src/conn-contact-info.c b/src/conn-contact-info.c index a78f172e4..599197b9b 100644 --- a/src/conn-contact-info.c +++ b/src/conn-contact-info.c @@ -24,9 +24,8 @@ #include <string.h> -#include <telepathy-glib/svc-connection.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "vcard-manager.h" @@ -484,7 +483,7 @@ _return_from_request_contact_info (WockyNode *vcard_node, if (NULL == vcard_node) { - GError tp_error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError tp_error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, vcard_error->message }; if (vcard_error->domain == WOCKY_XMPP_ERROR) @@ -650,7 +649,7 @@ conn_contact_info_new_edit (const VCardField *field, if (field->types[0] == NULL && field_params[0] != NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s vCard field expects no type-parameters", field->xmpp_name); gabble_vcard_manager_edit_info_free (edit_info); return NULL; @@ -681,7 +680,7 @@ conn_contact_info_new_edit (const VCardField *field, if (!used) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s vCard field does not support type-parameter %s", field->xmpp_name, *p); gabble_vcard_manager_edit_info_free (edit_info); @@ -703,7 +702,7 @@ _set_contact_info_cb (GabbleVCardManager *vcard_manager, if (vcard_node == NULL) { - GError tp_error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError tp_error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, vcard_error->message }; if (vcard_error->domain == WOCKY_XMPP_ERROR) @@ -763,7 +762,7 @@ gabble_connection_set_contact_info (TpSvcConnectionInterfaceContactInfo *iface, if (field == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "unknown vCard field from D-Bus: %s", field_name); goto finally; } @@ -771,7 +770,7 @@ gabble_connection_set_contact_info (TpSvcConnectionInterfaceContactInfo *iface, if (!gabble_vcard_manager_can_use_vcard_field (self->vcard_manager, field->xmpp_name)) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s vCard field is not supported by this server", field->xmpp_name); goto finally; @@ -784,7 +783,7 @@ gabble_connection_set_contact_info (TpSvcConnectionInterfaceContactInfo *iface, { if (n_field_values != 1) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s vCard field expects one value but got %u", field->xmpp_name, n_field_values); goto finally; @@ -808,7 +807,7 @@ gabble_connection_set_contact_info (TpSvcConnectionInterfaceContactInfo *iface, if (n_field_values != n_elements) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s vCard field expects %u values but got %u", field->xmpp_name, n_elements, n_field_values); goto finally; @@ -834,7 +833,7 @@ gabble_connection_set_contact_info (TpSvcConnectionInterfaceContactInfo *iface, if (n_field_values == 0) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "ORG vCard field expects at least one value but got 0"); goto finally; } @@ -865,7 +864,7 @@ gabble_connection_set_contact_info (TpSvcConnectionInterfaceContactInfo *iface, if (n_field_values != 1) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s vCard field expects one value but got %u", field->xmpp_name, n_field_values); goto finally; diff --git a/src/conn-location.c b/src/conn-location.c index b9ac05474..ae78d68be 100644 --- a/src/conn-location.c +++ b/src/conn-location.c @@ -8,8 +8,8 @@ #define DEBUG_FLAG GABBLE_DEBUG_LOCATION -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> #include <gabble/gabble.h> @@ -263,7 +263,7 @@ add_to_geoloc_node (const gchar *tp_name, { if (G_VALUE_TYPE (value) != G_TYPE_STRING) { - g_set_error (err, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (err, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "expecting string for language value, but got %s", G_VALUE_TYPE_NAME (value)); return FALSE; @@ -286,7 +286,7 @@ add_to_geoloc_node (const gchar *tp_name, if (G_VALUE_TYPE (value) != mapping->type) { - g_set_error (err, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (err, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "'%s' is supposed to be of type %s but is %s", (const char *) tp_name, g_type_name (mapping->type), G_VALUE_TYPE_NAME (value)); @@ -364,7 +364,7 @@ location_set_location (TpSvcConnectionInterfaceLocation *iface, if (!(conn->features & GABBLE_CONNECTION_FEATURES_PEP)) { - GError error = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + GError error = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Server does not support PEP, cannot publish geolocation" }; dbus_g_method_return_error (context, &error); @@ -395,7 +395,7 @@ location_set_location (TpSvcConnectionInterfaceLocation *iface, if (!_gabble_connection_send_with_reply (conn, msg, set_location_sent_cb, G_OBJECT (conn), context, NULL)) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send msg" }; dbus_g_method_return_error (context, &error); @@ -511,7 +511,7 @@ conn_location_properties_setter (GObject *object, if (access_control_type != TP_RICH_PRESENCE_ACCESS_CONTROL_TYPE_PUBLISH_LIST) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Access control type not implemented"); return FALSE; } @@ -642,14 +642,11 @@ location_pep_node_changed (WockyPepService *pep, return; } - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) /* Ignore echoed pubsub notifications */ - goto out; + return; update_location_from_item (conn, handle, item_node); - -out: - tp_handle_unref (contact_repo, handle); } static void diff --git a/src/conn-mail-notif.c b/src/conn-mail-notif.c index 2fe12e41e..0bc7169f8 100644 --- a/src/conn-mail-notif.c +++ b/src/conn-mail-notif.c @@ -33,11 +33,9 @@ #include <string.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/svc-connection.h> -#include <telepathy-glib/util.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -90,12 +88,12 @@ return_from_request_inbox_url (GabbleConnection *conn) if (priv->inbox_url != NULL && priv->inbox_url[0] == '\0') { - error = g_error_new (TP_ERRORS, TP_ERROR_NETWORK_ERROR, + error = g_error_new (TP_ERROR, TP_ERROR_NETWORK_ERROR, "Server did not provide base URL."); } else if (priv->inbox_url == NULL) { - error = g_error_new (TP_ERRORS, TP_ERROR_DISCONNECTED, + error = g_error_new (TP_ERROR, TP_ERROR_DISCONNECTED, "Connection was disconnected during request."); } else @@ -141,9 +139,11 @@ static inline gboolean check_supported_or_dbus_return (GabbleConnection *conn, DBusGMethodInvocation *context) { - if (TP_BASE_CONNECTION (conn)->status != TP_CONNECTION_STATUS_CONNECTED) + TpBaseConnection *base = TP_BASE_CONNECTION (conn); + + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) { - GError e = { TP_ERRORS, TP_ERROR_DISCONNECTED, "Not connected" }; + GError e = { TP_ERROR, TP_ERROR_DISCONNECTED, "Not connected" }; dbus_g_method_return_error (context, &e); return TRUE; } @@ -220,7 +220,7 @@ gabble_mail_notification_request_mail_url ( } else { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to retrieve URL from server."}; dbus_g_method_return_error (context, &error); } @@ -521,11 +521,11 @@ query_unread_mails_cb (GObject *source_object, static void update_unread_mails (GabbleConnection *conn) { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (conn); + TpBaseConnection *base = TP_BASE_CONNECTION (conn); WockyStanza *query; WockyPorter *porter = wocky_session_get_porter (conn->session); - if (base_conn->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) return; if (!(conn->features & GABBLE_CONNECTION_FEATURES_GOOGLE_MAIL_NOTIFY)) @@ -606,14 +606,14 @@ new_mail_handler (WockyPorter *porter, static void ensure_google_settings (GabbleConnection *self) { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (self); + TpBaseConnection *base = TP_BASE_CONNECTION (self); WockyStanza *query; WockyPorter *porter; if (!self->mail_priv->should_set_google_settings) return; - if (base_conn->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) return; porter = wocky_session_get_porter (self->session); diff --git a/src/conn-olpc.c b/src/conn-olpc.c index 243d2dff0..46fef4b0d 100644 --- a/src/conn-olpc.c +++ b/src/conn-olpc.c @@ -23,8 +23,7 @@ #include <string.h> #include <stdlib.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_OLPC @@ -97,13 +96,12 @@ activity_info_contribute_properties (GabbleOlpcActivity *activity, if (only_public && !gabble_olpc_activity_is_visible (activity)) return FALSE; - props_node = wocky_node_add_child_with_content (parent, - "properties", ""); + props_node = wocky_node_add_child_ns (parent, + "properties", NS_OLPC_ACTIVITY_PROPS); wocky_node_set_attributes (props_node, "room", gabble_olpc_activity_get_room (activity), "activity", activity->id, NULL); - props_node->ns = g_quark_from_string (NS_OLPC_ACTIVITY_PROPS); lm_message_node_add_children_from_properties (props_node, activity->properties, "property"); @@ -129,7 +127,7 @@ check_pep (GabbleConnection *conn, { if (!(conn->features & GABBLE_CONNECTION_FEATURES_PEP)) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Server does not support PEP" }; DEBUG ("%s", error.message); @@ -277,7 +275,7 @@ get_properties_reply_cb (GObject *source, NULL, &error); if (reply_msg == NULL) { - GError err = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError err = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property request to server" }; DEBUG ("Query failed: %s", error->message); @@ -379,7 +377,7 @@ transmit_properties (GabbleConnection *conn, if (!_gabble_connection_send_with_reply (conn, msg, set_properties_reply_cb, NULL, context, NULL)) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property change request to server" }; DEBUG ("%s", error.message); @@ -433,10 +431,10 @@ olpc_buddy_info_set_properties (GabbleSvcOLPCBuddyInfo *iface, DBusGMethodInvocation *context) { GabbleConnection *conn = GABBLE_CONNECTION (iface); - TpBaseConnection *base_conn = (TpBaseConnection *) conn; + TpBaseConnection *base = (TpBaseConnection *) conn; DEBUG ("called"); - if (base_conn->status == TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_CONNECTED) { transmit_properties (conn, properties, context); } @@ -493,9 +491,9 @@ olpc_buddy_props_pep_node_changed (WockyPepService *pep, return; } - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) /* Ignore echoed pubsub notifications */ - goto out; + return; node = search_for_child ( wocky_stanza_get_top_node (stanza), "properties", NULL); @@ -503,8 +501,6 @@ olpc_buddy_props_pep_node_changed (WockyPepService *pep, gabble_svc_olpc_buddy_info_emit_properties_changed (conn, handle, properties); g_hash_table_unref (properties); -out: - tp_handle_unref (contact_repo, handle); } static void @@ -575,7 +571,7 @@ static GPtrArray * get_buddy_activities (GabbleConnection *conn, TpHandle buddy) { - TpIntSet *all; + TpIntset *all; gboolean free_all = FALSE; GPtrArray *activities = g_ptr_array_new (); TpHandleSet *invited_activities, *pep_activities; @@ -612,18 +608,21 @@ get_buddy_activities (GabbleConnection *conn, if (all != NULL) { - TpIntSetIter iter = TP_INTSET_ITER_INIT (all); + TpIntsetFastIter iter; + guint element; + + tp_intset_fast_iter_init (&iter, all); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { GabbleOlpcActivity *activity = g_hash_table_lookup ( - conn->olpc_activities_info, GUINT_TO_POINTER (iter.element)); + conn->olpc_activities_info, GUINT_TO_POINTER (element)); GValue gvalue = { 0 }; g_assert (activity != NULL); if (activity->id == NULL) { - DEBUG ("... activity #%u has no ID, skipping", iter.element); + DEBUG ("... activity #%u has no ID, skipping", element); continue; } @@ -707,7 +706,6 @@ extract_activities (GabbleConnection *conn, if (tp_handle_set_is_member (activities_set, room_handle)) { NODE_DEBUG (node, "Room advertised twice, skipping"); - tp_handle_unref (room_repo, room_handle); continue; } @@ -719,7 +717,6 @@ extract_activities (GabbleConnection *conn, } /* pass ownership to the activities_set */ tp_handle_set_add (activities_set, room_handle); - tp_handle_unref (room_repo, room_handle); if (tp_strdiff (activity->id, act_id)) { @@ -824,7 +821,7 @@ get_activities_reply_cb (GObject *source, NULL, &err); if (reply_msg == NULL) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property request to server" }; DEBUG ("Query failed: %s", err->message); @@ -838,7 +835,7 @@ get_activities_reply_cb (GObject *source, wocky_stanza_get_top_node (reply_msg), "from"); if (from == NULL) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Error in pubsub reply: no sender" }; dbus_g_method_return_error (ctx->context, &error); @@ -848,7 +845,7 @@ get_activities_reply_cb (GObject *source, from_handle = tp_handle_lookup (contact_repo, from, NULL, NULL); if (from_handle == 0) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Error in pubsub reply: unknown sender" }; dbus_g_method_return_error (ctx->context, &error); @@ -926,8 +923,8 @@ upload_activities_pep (GabbleConnection *conn, TpBaseConnection *base = (TpBaseConnection *) conn; WockyNode *item, *activities; WockyStanza *msg; - TpHandleSet *my_activities = g_hash_table_lookup - (conn->olpc_pep_activities, GUINT_TO_POINTER (base->self_handle)); + TpHandleSet *my_activities = g_hash_table_lookup (conn->olpc_pep_activities, + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); GError *e = NULL; gboolean ret; @@ -938,13 +935,15 @@ upload_activities_pep (GabbleConnection *conn, if (my_activities != NULL) { - TpIntSetIter iter = TP_INTSET_ITER_INIT (tp_handle_set_peek - (my_activities)); + TpIntsetFastIter iter; + guint element; - while (tp_intset_iter_next (&iter)) + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (my_activities)); + + while (tp_intset_fast_iter_next (&iter, &element)) { GabbleOlpcActivity *activity = g_hash_table_lookup ( - conn->olpc_activities_info, GUINT_TO_POINTER (iter.element)); + conn->olpc_activities_info, GUINT_TO_POINTER (element)); WockyNode *activity_node; g_assert (activity != NULL); @@ -965,7 +964,7 @@ upload_activities_pep (GabbleConnection *conn, if (!ret) { - g_set_error (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR, + g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property change request to server: %s", e->message); g_error_free (e); } @@ -1001,7 +1000,7 @@ add_activity (GabbleConnection *self, TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( base, TP_HANDLE_TYPE_ROOM); TpHandleSet *old_activities = g_hash_table_lookup (self->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); GabbleOlpcActivity *activity; if (!tp_handle_is_valid (room_repo, channel, error)) @@ -1012,7 +1011,7 @@ add_activity (GabbleConnection *self, if (old_activities != NULL && tp_handle_set_is_member (old_activities, channel)) { - *error = g_error_new (TP_ERRORS, + *error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Can't set twice the same activity: %s", id); @@ -1109,7 +1108,7 @@ olpc_buddy_info_set_activities (GabbleSvcOLPCBuddyInfo *iface, { if (tp_handle_set_is_member (activities_set, channel)) { - error = g_error_new (TP_ERRORS, + error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Can't set twice the same activity: %s", room); @@ -1145,7 +1144,7 @@ olpc_buddy_info_set_activities (GabbleSvcOLPCBuddyInfo *iface, } old_activities = g_hash_table_lookup (conn->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); if (old_activities != NULL) { @@ -1157,11 +1156,12 @@ olpc_buddy_info_set_activities (GabbleSvcOLPCBuddyInfo *iface, /* Update the list of activities associated with our own contact. */ g_hash_table_insert (conn->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle), activities_set); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base)), + activities_set); if (!upload_activities_pep (conn, set_activities_reply_cb, context, NULL)) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property request to server" }; dbus_g_method_return_error (context, &error); @@ -1195,7 +1195,7 @@ olpc_activities_pep_node_changed (WockyPepService *pep, return; } - if (handle != base->self_handle) + if (handle != tp_base_connection_get_self_handle (base)) extract_activities (conn, stanza, handle); activities = get_buddy_activities (conn, handle); @@ -1302,8 +1302,6 @@ extract_current_activity (GabbleConnection *conn, conn->olpc_pep_activities); } - tp_handle_unref (room_repo, room_handle); - /* update current-activity cache */ if (activity != NULL) { @@ -1336,7 +1334,7 @@ get_current_activity_reply_cb (GObject *source, NULL, &error); if (reply_msg == NULL) { - GError err = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError err = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property request to server" }; DEBUG ("Query failed: %s", error->message); @@ -1463,7 +1461,7 @@ activity_in_own_set (GabbleConnection *conn, return FALSE; activities_set = g_hash_table_lookup (conn->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); if (activities_set == NULL || !tp_handle_set_is_member (activities_set, room_handle)) @@ -1501,7 +1499,7 @@ olpc_buddy_info_set_current_activity (GabbleSvcOLPCBuddyInfo *iface, if (!activity_in_own_set (conn, room)) { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Can't set an activity as current if you're not announcing it" }; dbus_g_method_return_error (context, &error); @@ -1522,7 +1520,7 @@ olpc_buddy_info_set_current_activity (GabbleSvcOLPCBuddyInfo *iface, if (!_gabble_connection_send_with_reply (conn, msg, set_current_activity_reply_cb, NULL, context, NULL)) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property change request to server" }; dbus_g_method_return_error (context, &error); @@ -1554,9 +1552,9 @@ olpc_current_act_pep_node_changed (WockyPepService *pep, return; } - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) /* Ignore echoed pubsub notifications */ - goto out; + return; node = search_for_child (wocky_stanza_get_top_node (stanza), "activity", NULL); @@ -1576,9 +1574,6 @@ olpc_current_act_pep_node_changed (WockyPepService *pep, gabble_svc_olpc_buddy_info_emit_current_activity_changed (conn, handle, "", 0); } - -out: - tp_handle_unref (contact_repo, handle); } static void @@ -1607,7 +1602,7 @@ olpc_buddy_info_add_activity (GabbleSvcOLPCBuddyInfo *iface, GabbleConnection *self = GABBLE_CONNECTION (iface); TpBaseConnection *base = (TpBaseConnection *) self; TpHandleSet *activities_set = g_hash_table_lookup (self->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); TpHandleRepoIface *room_repo = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_ROOM); GError *error = NULL; @@ -1627,14 +1622,15 @@ olpc_buddy_info_add_activity (GabbleSvcOLPCBuddyInfo *iface, if (activities_set == NULL) { activities_set = tp_handle_set_new (room_repo); g_hash_table_insert (self->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle), activities_set); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base)), + activities_set); } tp_handle_set_add (activities_set, channel); if (!upload_activities_pep (self, add_activity_reply_cb, context, NULL)) { - error = g_error_new (TP_ERRORS, TP_ERROR_NETWORK_ERROR, + error = g_error_new (TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property request to server"); dbus_g_method_return_error (context, error); @@ -1672,7 +1668,7 @@ upload_activity_properties_pep (GabbleConnection *conn, GError *e = NULL; gboolean ret; TpHandleSet *my_activities = g_hash_table_lookup (conn->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); msg = wocky_pep_service_make_publish_stanza (conn->pep_olpc_act_props, &item); publish = wocky_node_add_child_ns (item, "activities", @@ -1680,13 +1676,15 @@ upload_activity_properties_pep (GabbleConnection *conn, if (my_activities != NULL) { - TpIntSetIter iter = TP_INTSET_ITER_INIT (tp_handle_set_peek - (my_activities)); + TpIntsetFastIter iter; + guint element; + + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (my_activities)); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { GabbleOlpcActivity *activity = g_hash_table_lookup ( - conn->olpc_activities_info, GUINT_TO_POINTER (iter.element)); + conn->olpc_activities_info, GUINT_TO_POINTER (element)); activity_info_contribute_properties (activity, publish, TRUE); } @@ -1697,7 +1695,7 @@ upload_activity_properties_pep (GabbleConnection *conn, if (!ret) { - g_set_error (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR, + g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property change request to server: %s", e->message); g_error_free (e); } @@ -1793,12 +1791,14 @@ refresh_invitations (GabbleConnection *conn, if (invitees != NULL && tp_handle_set_size (invitees) > 0) { - TpIntSetIter iter = TP_INTSET_ITER_INIT (tp_handle_set_peek - (invitees)); + TpIntsetFastIter iter; + guint element; + + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (invitees)); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { - const gchar *to = tp_handle_inspect (contact_repo, iter.element); + const gchar *to = tp_handle_inspect (contact_repo, element); WockyStanza *msg = wocky_stanza_build ( WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, NULL, to, NULL); @@ -1853,7 +1853,7 @@ olpc_activity_properties_set_properties (GabbleSvcOLPCActivityProperties *iface, if (!activity_in_own_set (conn, jid)) { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Can't set properties on an activity if you're not announcing it" }; dbus_g_method_return_error (context, &error); @@ -1870,7 +1870,7 @@ olpc_activity_properties_set_properties (GabbleSvcOLPCActivityProperties *iface, } if (muc_channel == NULL || state != MUC_STATE_JOINED) { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Can't set properties on an activity if you're not in it" }; dbus_g_method_return_error (context, &error); @@ -1898,7 +1898,7 @@ olpc_activity_properties_set_properties (GabbleSvcOLPCActivityProperties *iface, wocky_stanza_get_top_node (msg), FALSE); if (!_gabble_connection_send (conn, msg, NULL)) { - GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR, + GError error = { TP_ERROR, TP_ERROR_NETWORK_ERROR, "Failed to send property change notification to chatroom" }; g_object_unref (msg); @@ -2093,8 +2093,6 @@ update_activity_properties (GabbleConnection *conn, } } - tp_handle_unref (room_repo, room_handle); - if (activity == NULL) return; @@ -2175,13 +2173,11 @@ olpc_act_props_pep_node_changed (WockyPepService *pep, return; } - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) /* Ignore echoed pubsub notifications */ - goto out; + return; update_activities_properties (conn, jid, stanza); -out: - tp_handle_unref (contact_repo, handle); } static void @@ -2364,7 +2360,6 @@ conn_olpc_process_activity_properties_message (GabbleConnection *conn, g_object_ref (activity); tp_handle_set_add (their_invites, room_handle); } - tp_handle_unref (room_repo, room_handle); } else { @@ -2432,7 +2427,7 @@ conn_olpc_process_activity_properties_message (GabbleConnection *conn, if (pep_properties_changed) { our_activities = g_hash_table_lookup (conn->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); if (our_activities != NULL && tp_handle_set_is_member (our_activities, room_handle)) { @@ -2448,7 +2443,7 @@ conn_olpc_process_activity_properties_message (GabbleConnection *conn, if (is_visible != was_visible) { our_activities = g_hash_table_lookup (conn->olpc_pep_activities, - GUINT_TO_POINTER (base->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); if (our_activities != NULL && tp_handle_set_is_member (our_activities, room_handle)) { @@ -2496,13 +2491,15 @@ revoke_invitations (GabbleConnection *conn, if (invitees != NULL && tp_handle_set_size (invitees) > 0) { - TpIntSetIter iter = TP_INTSET_ITER_INIT (tp_handle_set_peek - (invitees)); + TpIntsetFastIter iter; + guint element; + + tp_intset_fast_iter_init (&iter, tp_handle_set_peek (invitees)); DEBUG ("revoke invitations for activity %s", activity->id); - while (tp_intset_iter_next (&iter)) + while (tp_intset_fast_iter_next (&iter, &element)) { - const gchar *to = tp_handle_inspect (contact_repo, iter.element); + const gchar *to = tp_handle_inspect (contact_repo, element); WockyStanza *msg = wocky_stanza_build ( WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, NULL, to, @@ -2628,10 +2625,16 @@ muc_channel_closed_cb (GabbleMucChannel *chan, GabbleOlpcActivity *activity) { GabbleConnection *conn; + TpBaseConnection *base; TpHandleSet *my_activities; gboolean was_in_our_pep = FALSE; + /* is the muc channel /actually/ disappearing */ + if (!tp_base_channel_is_destroyed (TP_BASE_CHANNEL (chan))) + return; + g_object_get (activity, "connection", &conn, NULL); + base = TP_BASE_CONNECTION (conn); /* Revoke invitations we sent for this activity */ revoke_invitations (conn, chan, activity, NULL); @@ -2639,7 +2642,7 @@ muc_channel_closed_cb (GabbleMucChannel *chan, /* remove it from our advertised activities list, unreffing it in the * process if it was in fact advertised */ my_activities = g_hash_table_lookup (conn->olpc_pep_activities, - GUINT_TO_POINTER (TP_BASE_CONNECTION (conn)->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base))); if (my_activities != NULL) { if (tp_handle_set_remove (my_activities, activity->room)) @@ -2723,7 +2726,6 @@ muc_channel_pre_invite_cb (GabbleMucChannel *chan, } tp_handle_set_add (invitees, handle); - tp_handle_unref (contact_repo, handle); g_object_unref (conn); } @@ -2784,10 +2786,12 @@ muc_channel_contact_join_cb (GabbleMucChannel *chan, GabbleOlpcActivity *activity) { GabbleConnection *conn; + TpBaseConnection *base; g_object_get (activity, "connection", &conn, NULL); + base = TP_BASE_CONNECTION (conn); - if (contact == TP_BASE_CONNECTION (conn)->self_handle) + if (contact == tp_base_connection_get_self_handle (base)) { /* We join the channel, forget about all invites we received about * this activity */ @@ -3046,7 +3050,7 @@ olpc_activity_properties_get_activity (GabbleSvcOLPCActivityProperties *iface, activity = find_activity_by_id (self, activity_id); if (activity == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Activity unknown: %s", activity_id); goto error; } diff --git a/src/conn-presence.c b/src/conn-presence.c index cc197643f..e06062f56 100644 --- a/src/conn-presence.c +++ b/src/conn-presence.c @@ -24,11 +24,8 @@ #include <string.h> #include <stdlib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/presence-mixin.h> -#include <telepathy-glib/svc-connection.h> -#include <telepathy-glib/util.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -122,13 +119,15 @@ static TpPresenceStatusSpec *gabble_statuses = NULL; /* prototypes */ -static void set_xep0186_invisible_cb (GabbleConnection *conn, - WockyStanza *sent_msg, WockyStanza *reply_msg, GObject *obj, +static void set_xep0186_invisible_cb ( + GObject *source, + GAsyncResult *set_result, gpointer user_data); static void activate_current_privacy_list_cb ( - GabbleConnection *conn, WockyStanza *sent_msg, WockyStanza *reply_msg, - GObject *obj, gpointer user_data); + GObject *source, + GAsyncResult *activate_result, + gpointer user_data); static void setup_invisible_privacy_list_async (GabbleConnection *self, GAsyncReadyCallback callback, gpointer user_data); @@ -139,8 +138,9 @@ static gboolean iq_privacy_list_push_cb ( gpointer user_data); static void verify_invisible_privacy_list_cb ( - GabbleConnection *conn, WockyStanza *sent_msg, WockyStanza *reply_msg, - GObject *obj, gpointer user_data); + GObject *source, + GAsyncResult *verify_result, + gpointer user_data); static void toggle_presence_visibility_async (GabbleConnection *self, GAsyncReadyCallback callback, @@ -196,7 +196,7 @@ construct_contact_statuses_cb (GObject *obj, { handle = g_array_index (contact_handles, TpHandle, i); - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) presence = self->self_presence; else presence = gabble_presence_cache_get (self->presence_cache, handle); @@ -271,8 +271,10 @@ emit_presences_changed_for_self (GabbleConnection *self) { TpBaseConnection *base = TP_BASE_CONNECTION (self); GArray *handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); + TpHandle self_handle; - g_array_insert_val (handles, 0, base->self_handle); + self_handle = tp_base_connection_get_self_handle (base); + g_array_insert_val (handles, 0, self_handle); conn_presence_emit_presence_update (self, handles); g_array_unref (handles); } @@ -490,15 +492,11 @@ set_xep0186_invisible (GabbleConnection *self, TpBaseConnection *base = (TpBaseConnection *) self; GabbleConnectionPresencePrivate *priv = self->presence_priv; GError *error = NULL; - const gchar *element = invisible ? "invisible" : "visible"; - WockyStanza *iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, - WOCKY_STANZA_SUB_TYPE_SET, NULL, NULL, - '(', element, ':', NS_INVISIBLE, ')', - NULL); g_object_ref (result); - if (!invisible && base->status != TP_CONNECTION_STATUS_CONNECTED) + if (!invisible && + tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) { if (priv->privacy_statuses != NULL) { @@ -513,30 +511,31 @@ set_xep0186_invisible (GabbleConnection *self, g_object_unref (result); } } - else if (!_gabble_connection_send_with_reply (self, (WockyStanza *) iq, - set_xep0186_invisible_cb, NULL, result, &error)) + else { - g_simple_async_result_set_from_error (result, error); - g_simple_async_result_complete_in_idle (result); + const gchar *element = invisible ? "invisible" : "visible"; + WockyStanza *iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, + WOCKY_STANZA_SUB_TYPE_SET, NULL, NULL, + '(', element, ':', NS_INVISIBLE, ')', + NULL); - g_object_unref (result); - g_error_free (error); - } + conn_util_send_iq_async (self, iq, NULL, set_xep0186_invisible_cb, result); - g_object_unref (iq); + g_object_unref (iq); + } } static void -set_xep0186_invisible_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, +set_xep0186_invisible_cb ( + GObject *source, + GAsyncResult *set_result, gpointer user_data) { + GabbleConnection *conn = GABBLE_CONNECTION (source); GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); GError *error = NULL; - if (wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) + if (!conn_util_send_iq_finish (conn, set_result, NULL, &error)) { g_simple_async_result_set_error (result, CONN_PRESENCE_ERROR, CONN_PRESENCE_ERROR_SET_INVISIBLE, @@ -590,21 +589,10 @@ activate_current_privacy_list (GabbleConnection *self, gabble_statuses[presence->status].name, list_name ? list_name : "(no list)"); - iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, - WOCKY_STANZA_SUB_TYPE_SET, NULL, NULL, - '(', "query", ':', NS_PRIVACY, - '(', "active", - '*', &active_node, - ')', - ')', - NULL); - - if (list_name != NULL) - wocky_node_set_attribute (active_node, "name", list_name); - g_object_ref (result); - if (base->status == TP_CONNECTION_STATUS_CONNECTED && invisible) + if (tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_CONNECTED && + invisible) { if (!gabble_connection_send_presence (self, WOCKY_STANZA_SUB_TYPE_UNAVAILABLE, NULL, NULL, &error)) @@ -614,7 +602,7 @@ activate_current_privacy_list (GabbleConnection *self, * need to bother with removing the active list; just shortcut to * signalling our presence. */ else if (list_name == NULL && - base->status != TP_CONNECTION_STATUS_CONNECTED) + tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) { if (!conn_presence_signal_own_presence (self, NULL, &error)) goto ERROR; @@ -622,11 +610,25 @@ activate_current_privacy_list (GabbleConnection *self, g_simple_async_result_complete_in_idle (result); g_object_unref (result); - goto OUT; + return; } - _gabble_connection_send_with_reply (self, (WockyStanza *) iq, - activate_current_privacy_list_cb, NULL, result, &error); + iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, + WOCKY_STANZA_SUB_TYPE_SET, NULL, NULL, + '(', "query", ':', NS_PRIVACY, + '(', "active", + '*', &active_node, + ')', + ')', + NULL); + + if (list_name != NULL) + wocky_node_set_attribute (active_node, "name", list_name); + + conn_util_send_iq_async (self, iq, NULL, + activate_current_privacy_list_cb, result); + g_object_unref (iq); + return; ERROR: if (error != NULL) @@ -636,22 +638,19 @@ activate_current_privacy_list (GabbleConnection *self, g_error_free (error); g_object_unref (result); } - - OUT: - g_object_unref (iq); } static void -activate_current_privacy_list_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, +activate_current_privacy_list_cb ( + GObject *source, + GAsyncResult *activate_result, gpointer user_data) { + GabbleConnection *conn = GABBLE_CONNECTION (source); GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); GError *error = NULL; - if (wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) + if (!conn_util_send_iq_finish (conn, activate_result, NULL, &error)) { g_simple_async_result_set_error (result, CONN_PRESENCE_ERROR, CONN_PRESENCE_ERROR_SET_PRIVACY_LIST, @@ -696,20 +695,19 @@ disable_invisible_privacy_list (GabbleConnection *self) } static void -create_invisible_privacy_list_reply_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, +create_invisible_privacy_list_reply_cb ( + GObject *source, + GAsyncResult *create_result, gpointer user_data) { + GabbleConnection *conn = GABBLE_CONNECTION (source); GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); GError *error = NULL; - if (wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) + if (!conn_util_send_iq_finish (conn, create_result, NULL, &error)) g_simple_async_result_take_error (result, error); - g_simple_async_result_complete_in_idle (result); - + g_simple_async_result_complete (result); g_object_unref (result); } @@ -718,7 +716,6 @@ create_invisible_privacy_list_async (GabbleConnection *self, GAsyncReadyCallback callback, gpointer user_data) { - GError *error = NULL; GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, create_invisible_privacy_list_async); WockyStanza *iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, @@ -738,16 +735,8 @@ create_invisible_privacy_list_async (GabbleConnection *self, DEBUG ("Creating '%s'", self->presence_priv->invisible_list_name); - if (!_gabble_connection_send_with_reply (self, (WockyStanza *) iq, - create_invisible_privacy_list_reply_cb, NULL, result, &error)) - { - g_simple_async_result_set_from_error (result, error); - g_simple_async_result_complete_in_idle (result); - - g_object_unref (result); - g_error_free (error); - } - + conn_util_send_iq_async (self, iq, NULL, + create_invisible_privacy_list_reply_cb, result); g_object_unref (iq); } @@ -885,7 +874,7 @@ store_shared_statuses (GabbleConnection *self, presence_id = GABBLE_PRESENCE_AVAILABLE; } - if (base->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) { /* Not connected, override with the local status. */ rv = TRUE; @@ -1076,28 +1065,32 @@ get_shared_status_finish (GabbleConnection *self, } static void -get_existing_privacy_lists_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, +get_existing_privacy_lists_cb ( + GObject *source, + GAsyncResult *get_result, gpointer user_data) { + GabbleConnection *conn = GABBLE_CONNECTION (source); GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data); - WockyNode *query_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (reply_msg), "query", NS_PRIVACY); + WockyStanza *reply_msg = NULL; + WockyNode *query_node; GError *error = NULL; - if (wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) + if (!conn_util_send_iq_finish (conn, get_result, &reply_msg, &error)) { DEBUG ("Error getting privacy lists: %s", error->message); g_simple_async_result_set_from_error (result, error); g_error_free (error); + goto out; } - else if (query_node == NULL) + + query_node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (reply_msg), "query", NS_PRIVACY); + if (query_node == NULL) { g_simple_async_result_set_error (result, - TP_ERRORS, TP_ERROR_NETWORK_ERROR, + TP_ERROR, TP_ERROR_NETWORK_ERROR, "no <query/> node in 'list privacy lists' reply"); } else @@ -1136,8 +1129,10 @@ get_existing_privacy_lists_cb (GabbleConnection *conn, } } - g_simple_async_result_complete_in_idle (result); +out: + g_simple_async_result_complete (result); g_object_unref (result); + g_clear_object (&reply_msg); } static void @@ -1145,7 +1140,6 @@ get_existing_privacy_lists_async (GabbleConnection *self, GAsyncReadyCallback callback, gpointer user_data) { - GError *error = NULL; GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, get_existing_privacy_lists_async); WockyStanza *iq; @@ -1157,16 +1151,8 @@ get_existing_privacy_lists_async (GabbleConnection *self, ')', NULL); - if (!_gabble_connection_send_with_reply (self, (WockyStanza *) iq, - get_existing_privacy_lists_cb, NULL, result, &error)) - { - g_simple_async_result_set_from_error (result, error); - g_simple_async_result_complete_in_idle (result); - - g_object_unref (result); - g_error_free (error); - } - + conn_util_send_iq_async (self, iq, NULL, get_existing_privacy_lists_cb, + result); g_object_unref (iq); } @@ -1185,7 +1171,6 @@ setup_invisible_privacy_list_async (GabbleConnection *self, gpointer user_data) { GabbleConnectionPresencePrivate *priv = self->presence_priv; - GError *error = NULL; GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, setup_invisible_privacy_list_async); WockyStanza *iq; @@ -1203,16 +1188,8 @@ setup_invisible_privacy_list_async (GabbleConnection *self, ')', NULL); - if (!_gabble_connection_send_with_reply (self, (WockyStanza *) iq, - verify_invisible_privacy_list_cb, NULL, result, &error)) - { - g_simple_async_result_set_from_error (result, error); - g_simple_async_result_complete_in_idle (result); - - g_object_unref (result); - g_error_free (error); - } - + wocky_porter_send_iq_async (wocky_session_get_porter (self->session), + iq, NULL, verify_invisible_privacy_list_cb, result); g_object_unref (iq); } @@ -1271,23 +1248,30 @@ is_valid_invisible_list (WockyNode *list_node) } static void -verify_invisible_privacy_list_cb (GabbleConnection *conn, - WockyStanza *sent_msg, - WockyStanza *reply_msg, - GObject *obj, +verify_invisible_privacy_list_cb ( + GObject *source, + GAsyncResult *verify_result, gpointer user_data) { + GabbleConnection *conn = GABBLE_CONNECTION ( + g_async_result_get_source_object (G_ASYNC_RESULT (user_data))); GabbleConnectionPresencePrivate *priv = conn->presence_priv; - WockyNode *query_node, *list_node = NULL; + WockyStanza *reply_msg = NULL; + WockyNode *query_node = NULL, *list_node = NULL; GError *error = NULL; - query_node = wocky_node_get_child_ns (wocky_stanza_get_top_node (reply_msg), - "query", NS_PRIVACY); + reply_msg = wocky_porter_send_iq_finish (WOCKY_PORTER (source), + verify_result, &error); + + if (reply_msg != NULL) + query_node = wocky_node_get_child_ns (wocky_stanza_get_top_node (reply_msg), + "query", NS_PRIVACY); if (query_node != NULL) list_node = wocky_node_get_child (query_node, "list"); - if (!wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) + if (reply_msg != NULL && + !wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) { if (list_node == NULL || !is_valid_invisible_list (list_node)) @@ -1309,7 +1293,8 @@ verify_invisible_privacy_list_cb (GabbleConnection *conn, toggle_initial_presence_visibility_cb, user_data); } } - else if (error->code == WOCKY_XMPP_ERROR_ITEM_NOT_FOUND) + else if (error->domain == WOCKY_XMPP_ERROR && + error->code == WOCKY_XMPP_ERROR_ITEM_NOT_FOUND) { create_invisible_privacy_list_async (conn, create_invisible_privacy_list_cb, user_data); @@ -1324,6 +1309,9 @@ verify_invisible_privacy_list_cb (GabbleConnection *conn, if (error != NULL) g_error_free (error); + + g_clear_object (&reply_msg); + g_clear_object (&conn); } static void @@ -1588,7 +1576,8 @@ conn_presence_signal_own_presence (GabbleConnection *self, * previously sent directed presence to? (Perhaps also GC them after a * while?) */ - if (to == NULL && base->status == TP_CONNECTION_STATUS_CONNECTED) + if (to == NULL && + tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_CONNECTED) gabble_muc_factory_broadcast_presence (self->muc_factory); return ret; @@ -1761,7 +1750,7 @@ set_own_status_cb (GObject *obj, * with the check enabled). Assumes PresenceId value ordering. */ if (i < GABBLE_PRESENCE_HIDDEN) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Status '%s' can not be requested in this connection", gabble_statuses[i].name); retval = FALSE; @@ -1779,7 +1768,7 @@ set_own_status_cb (GObject *obj, if (!G_VALUE_HOLDS_STRING (message)) { DEBUG ("got a status message which was not a string"); - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Status argument 'message' requires a string"); retval = FALSE; goto OUT; @@ -1792,7 +1781,7 @@ set_own_status_cb (GObject *obj, if (!G_VALUE_HOLDS_INT (priority)) { DEBUG ("got a priority value which was not a signed integer"); - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Status argument 'priority' requires a signed integer"); retval = FALSE; goto OUT; @@ -1812,7 +1801,8 @@ set_own_status_cb (GObject *obj, if (gabble_presence_update (conn->self_presence, resource, i, message_str, prio, NULL, time (NULL))) { - if (base->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) != + TP_CONNECTION_STATUS_CONNECTED) { retval = TRUE; } @@ -1881,7 +1871,7 @@ status_available_cb (GObject *obj, guint status) TpConnectionPresenceType presence_type = gabble_statuses[status].presence_type; - if (base->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) { /* we just don't know yet */ return TRUE; diff --git a/src/conn-sidecars.c b/src/conn-sidecars.c index eb47bad0a..d2dd57eca 100644 --- a/src/conn-sidecars.c +++ b/src/conn-sidecars.c @@ -22,7 +22,7 @@ #include "conn-sidecars.h" -#include <telepathy-glib/dbus.h> +#include <telepathy-glib/telepathy-glib.h> #include "extensions/extensions.h" @@ -65,10 +65,12 @@ make_sidecar_path ( GabbleConnection *conn, const gchar *sidecar_iface) { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (conn); + TpBaseConnection *base = TP_BASE_CONNECTION (conn); return g_strdelimit ( - g_strdup_printf ("%s/Sidecar/%s", base_conn->object_path, sidecar_iface), + g_strdup_printf ("%s/Sidecar/%s", + tp_base_connection_get_object_path (base), + sidecar_iface), ".", '/'); } @@ -157,7 +159,7 @@ create_sidecar_cb ( { /* TODO: maybe this lives in the loader? It knows what the plugin is * called. */ - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "A buggy plugin created a %s sidecar when asked to create %s", actual_iface, ctx->sidecar_iface); } @@ -203,14 +205,14 @@ gabble_connection_ensure_sidecar ( DBusGMethodInvocation *context) { GabbleConnection *conn = GABBLE_CONNECTION (iface); - TpBaseConnection *base_conn = TP_BASE_CONNECTION (conn); + TpBaseConnection *base = TP_BASE_CONNECTION (conn); GabbleSidecar *sidecar; gpointer key, value; GError *error = NULL; - if (base_conn->status == TP_CONNECTION_STATUS_DISCONNECTED) + if (tp_base_connection_is_destroyed (base)) { - GError e = { TP_ERRORS, TP_ERROR_DISCONNECTED, + GError e = { TP_ERROR, TP_ERROR_DISCONNECTED, "This connection has already disconnected" }; DEBUG ("already disconnected, declining request for %s", sidecar_iface); @@ -220,7 +222,7 @@ gabble_connection_ensure_sidecar ( if (!tp_dbus_check_valid_interface_name (sidecar_iface, &error)) { - error->domain = TP_ERRORS; + error->domain = TP_ERROR; error->code = TP_ERROR_INVALID_ARGUMENT; DEBUG ("%s is malformed: %s", sidecar_iface, error->message); dbus_g_method_return_error (context, error); @@ -262,7 +264,7 @@ gabble_connection_ensure_sidecar ( g_hash_table_insert (conn->pending_sidecars, g_strdup (sidecar_iface), g_list_prepend (NULL, context)); - if (base_conn->status == TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_CONNECTED) { GabblePluginLoader *loader = gabble_plugin_loader_dup (); @@ -305,7 +307,7 @@ sidecars_conn_status_changed_cb ( { const gchar *sidecar_iface = key; GList *contexts = value; - GError *error = g_error_new (TP_ERRORS, TP_ERROR_CANCELLED, + GError *error = g_error_new (TP_ERROR, TP_ERROR_CANCELLED, "Disconnected before %s could be created", sidecar_iface); DEBUG ("failing all %u requests for %s", g_list_length (contexts), diff --git a/src/connection-manager.c b/src/connection-manager.c index b2a0edb15..349cdafff 100644 --- a/src/connection-manager.c +++ b/src/connection-manager.c @@ -25,8 +25,10 @@ #include <dbus/dbus-protocol.h> #include <dbus/dbus-glib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/errors.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> + #include <wocky/wocky.h> #include "connection.h" @@ -80,9 +82,7 @@ gabble_connection_manager_class_init (GabbleConnectionManagerClass *klass) TpBaseConnectionManagerClass *base_class = (TpBaseConnectionManagerClass *) klass; - base_class->new_connection = NULL; base_class->cm_dbus_name = "gabble"; - base_class->protocol_params = NULL; object_class->constructed = gabble_connection_manager_constructed; object_class->finalize = gabble_connection_manager_finalize; } diff --git a/src/connection-manager.h b/src/connection-manager.h index 775bba79b..fc269e8d8 100644 --- a/src/connection-manager.h +++ b/src/connection-manager.h @@ -22,7 +22,7 @@ #define __GABBLE_CONNECTION_MANAGER_H__ #include <glib-object.h> -#include <telepathy-glib/base-connection-manager.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/connection.c b/src/connection.c index e53b3de1d..cc15a0adc 100644 --- a/src/connection.c +++ b/src/connection.c @@ -30,14 +30,8 @@ #include <dbus/dbus-glib-lowlevel.h> #include <glib-object.h> #include <wocky/wocky.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/handle-repo-dynamic.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-generic.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "extensions/extensions.h" @@ -83,7 +77,6 @@ #ifdef ENABLE_VOIP #include "media-channel.h" -#include "jingle-factory.h" #include "media-factory.h" #endif @@ -332,7 +325,7 @@ _gabble_connection_create_channel_managers (TpBaseConnection *conn) { GabbleConnection *self = GABBLE_CONNECTION (conn); GabblePluginConnection *plugin_connection = GABBLE_PLUGIN_CONNECTION (self); - GPtrArray *channel_managers = g_ptr_array_sized_new (5); + GPtrArray *channel_managers = g_ptr_array_sized_new (10); GabblePluginLoader *loader; GPtrArray *tmp; @@ -934,6 +927,21 @@ gabble_connection_get_guaranteed_interfaces (void) return interfaces_always_present; } +static GPtrArray * +_gabble_connection_get_interfaces_always_present (TpBaseConnection *base) +{ + GPtrArray *interfaces; + const gchar **iter; + + interfaces = TP_BASE_CONNECTION_CLASS ( + gabble_connection_parent_class)->get_interfaces_always_present (base); + + for (iter = interfaces_always_present; *iter != NULL; iter++) + g_ptr_array_add (interfaces, (gchar *) *iter); + + return interfaces; +} + static void gabble_connection_class_init (GabbleConnectionClass *gabble_connection_class) { @@ -1012,7 +1020,8 @@ gabble_connection_class_init (GabbleConnectionClass *gabble_connection_class) _gabble_connection_create_channel_managers; parent_class->shut_down = connection_shut_down; parent_class->start_connecting = _gabble_connection_connect; - parent_class->interfaces_always_present = interfaces_always_present; + parent_class->get_interfaces_always_present = + _gabble_connection_get_interfaces_always_present; g_type_class_add_private (gabble_connection_class, sizeof (GabbleConnectionPrivate)); @@ -1267,8 +1276,10 @@ gabble_connection_dispose (GObject *object) DEBUG ("called"); - g_assert ((base->status == TP_CONNECTION_STATUS_DISCONNECTED) || - (base->status == TP_INTERNAL_CONNECTION_STATUS_NEW)); + g_assert ((tp_base_connection_get_status (base) == + TP_CONNECTION_STATUS_DISCONNECTED) || + (tp_base_connection_get_status (base) == + TP_INTERNAL_CONNECTION_STATUS_NEW)); tp_clear_object (&self->bytestream_factory); tp_clear_object (&self->disco); @@ -1398,7 +1409,7 @@ _gabble_connection_set_properties_from_account (GabbleConnection *conn, if (!wocky_decode_jid (account, &username, &server, &resource)) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "unable to extract JID from account name"); result = FALSE; goto OUT; @@ -1484,7 +1495,7 @@ _gabble_connection_send (GabbleConnection *conn, WockyStanza *msg, GError **erro if (conn->priv->porter == NULL) { - g_set_error_literal (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR, + g_set_error_literal (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "connection is disconnected"); return FALSE; } @@ -1600,7 +1611,7 @@ _gabble_connection_send_with_reply (GabbleConnection *conn, if (priv->porter == NULL) { - g_set_error_literal (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR, + g_set_error_literal (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "connection is disconnected"); return FALSE; } @@ -1647,7 +1658,7 @@ gabble_connection_disconnect_with_tp_error (GabbleConnection *self, "debug-message", G_TYPE_STRING, tp_error->message, NULL); - g_assert (tp_error->domain == TP_ERRORS); + g_assert (tp_error->domain == TP_ERROR); tp_base_connection_disconnect_with_dbus_error (base, tp_error_get_dbus_name (tp_error->code), details, reason); g_hash_table_unref (details); @@ -1658,10 +1669,10 @@ remote_closed_cb (WockyPorter *porter, GabbleConnection *self) { TpBaseConnection *base = TP_BASE_CONNECTION (self); - GError e = { TP_ERRORS, TP_ERROR_CONNECTION_LOST, + GError e = { TP_ERROR, TP_ERROR_CONNECTION_LOST, "server closed its XMPP stream" }; - if (base->status == TP_CONNECTION_STATUS_DISCONNECTED) + if (tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_DISCONNECTED) /* Ignore if we are already disconnecting/disconnected */ return; @@ -1708,12 +1719,13 @@ remote_error_cb (WockyPorter *porter, GError e = { domain, code, msg }; GError *error = NULL; - if (base->status == TP_CONNECTION_STATUS_DISCONNECTED) + if (tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_DISCONNECTED) /* Ignore if we are already disconnecting/disconnected */ return; - gabble_set_tp_conn_error_from_wocky (&e, base->status, &reason, &error); - g_assert (error->domain == TP_ERRORS); + gabble_set_tp_conn_error_from_wocky (&e, tp_base_connection_get_status (base), + &reason, &error); + g_assert (error->domain == TP_ERROR); DEBUG ("Force closing of the connection %p", self); priv->closing = TRUE; @@ -1767,10 +1779,10 @@ connector_error_disconnect (GabbleConnection *self, return; } - gabble_set_tp_conn_error_from_wocky (error, base->status, &reason, - &tp_error); + gabble_set_tp_conn_error_from_wocky (error, + tp_base_connection_get_status (base), &reason, &tp_error); DEBUG ("connection failed: %s", tp_error->message); - g_assert (tp_error->domain == TP_ERRORS); + g_assert (tp_error->domain == TP_ERROR); gabble_connection_disconnect_with_tp_error (self, tp_error, reason); g_error_free (tp_error); @@ -1956,15 +1968,16 @@ connector_connected (GabbleConnection *self, * components (Roster, presence-manager, etc) for now */ wocky_porter_start (priv->porter); - base->self_handle = tp_handle_ensure (contact_handles, jid, NULL, &error); + tp_base_connection_set_self_handle (base, + tp_handle_ensure (contact_handles, jid, NULL, &error)); - if (base->self_handle == 0) + if (tp_base_connection_get_self_handle (base) == 0) { DEBUG ("couldn't get our self handle: %s", error->message); - if (error->domain != TP_ERRORS) + if (error->domain != TP_ERROR) { - error->domain = TP_ERRORS; + error->domain = TP_ERROR; error->code = TP_ERROR_INVALID_HANDLE; } @@ -1980,9 +1993,9 @@ connector_connected (GabbleConnection *self, { DEBUG ("couldn't parse our own JID: %s", error->message); - if (error->domain != TP_ERRORS) + if (error->domain != TP_ERROR) { - error->domain = TP_ERRORS; + error->domain = TP_ERROR; error->code = TP_ERROR_INVALID_ARGUMENT; } @@ -1993,7 +2006,8 @@ connector_connected (GabbleConnection *self, return; } - DEBUG ("Created self handle %d, our JID is %s", base->self_handle, jid); + DEBUG ("Created self handle %d, our JID is %s", + tp_base_connection_get_self_handle (base), jid); /* set initial capabilities */ gabble_connection_refresh_capabilities (self, NULL); @@ -2008,9 +2022,9 @@ connector_connected (GabbleConnection *self, DEBUG ("sending disco request failed: %s", error->message); - if (error->domain != TP_ERRORS) + if (error->domain != TP_ERROR) { - error->domain = TP_ERRORS; + error->domain = TP_ERROR; error->code = TP_ERROR_NETWORK_ERROR; } @@ -2027,9 +2041,9 @@ connector_connected (GabbleConnection *self, DEBUG ("Sending disco request to our own bare jid failed: %s", error->message); - if (error->domain != TP_ERRORS) + if (error->domain != TP_ERROR) { - error->domain = TP_ERRORS; + error->domain = TP_ERROR; error->code = TP_ERROR_NETWORK_ERROR; } @@ -2374,14 +2388,13 @@ gabble_connection_fill_in_caps (GabbleConnection *self, /* XEP-0115 version 1.5 uses a verification string in the 'ver' attribute */ caps_hash = caps_hash_compute_from_self_presence (self); - node = wocky_node_add_child_with_content (node, "c", NULL); + node = wocky_node_add_child_ns (node, "c", NS_CAPS); wocky_node_set_attributes ( node, "hash", "sha-1", "node", NS_GABBLE_CAPS, "ver", caps_hash, NULL); - node->ns = g_quark_from_string (NS_CAPS); /* Ensure this set of capabilities is in the cache. */ gabble_presence_cache_add_own_caps (self->presence_cache, caps_hash, @@ -2463,9 +2476,8 @@ gabble_connection_request_decloak (GabbleConnection *self, gabble_connection_fill_in_caps (self, message); - decloak = wocky_node_add_child_with_content (wocky_stanza_get_top_node (message), - "temppres", NULL); - decloak->ns = g_quark_from_string (NS_TEMPPRES); + decloak = wocky_node_add_child_ns (wocky_stanza_get_top_node (message), + "temppres", NS_TEMPPRES); if (reason != NULL && *reason != '\0') { @@ -2538,7 +2550,7 @@ gabble_connection_refresh_capabilities (GabbleConnection *self, } /* don't signal presence unless we're already CONNECTED */ - if (base->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTED) { gabble_capability_set_free (save_set); g_ptr_array_unref (data_forms); @@ -2780,7 +2792,7 @@ set_status_to_connected (GabbleConnection *conn) { TpBaseConnection *base = (TpBaseConnection *) conn; - if (base->status == TP_CONNECTION_STATUS_DISCONNECTED) + if (tp_base_connection_get_status (base) == TP_CONNECTION_STATUS_DISCONNECTED) { /* We already failed to connect, but at the time an async thing was * still pending, and now it has finished. Do nothing special. */ @@ -2827,6 +2839,115 @@ decrement_waiting_connected (GabbleConnection *conn) } static void +conn_wlm_jid_lookup_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GabbleConnection *conn = (GabbleConnection *) source; + GSimpleAsyncResult *my_result = user_data; + WockyStanza *iq = NULL; + WockyNode *node; + const gchar *jid = NULL; + GError *error = NULL; + + if (!conn_util_send_iq_finish (conn, result, &iq, &error)) + { + g_simple_async_result_take_error (my_result, error); + goto out; + } + + node = wocky_node_get_child_ns (wocky_stanza_get_top_node (iq), + "getjid", NS_WLM_JID_LOOKUP); + + if (node != NULL) + { + jid = wocky_node_get_content_from_child (node, "jid"); + } + + if (!tp_str_empty (jid)) + { + g_simple_async_result_set_op_res_gpointer (my_result, + g_strdup (jid), g_free); + } + else + { + g_simple_async_result_set_error (my_result, + TP_ERROR, TP_ERROR_INVALID_HANDLE, + "jid not found in getjid reply"); + } + +out: + g_simple_async_result_complete (my_result); + g_object_unref (my_result); +} + +static void +conn_wlm_jid_lookup_async (TpHandleRepoIface *repo, + TpBaseConnection *base, + const gchar *id, + gpointer context, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GabbleConnection *self = GABBLE_CONNECTION (base); + WockyStanza *iq; + GSimpleAsyncResult *result; + gchar *normal_id; + GError *error = NULL; + + result = g_simple_async_result_new ((GObject *) repo, callback, user_data, + conn_wlm_jid_lookup_async); + + /* First, do local normalization */ + normal_id = gabble_normalize_contact (repo, id, context, &error); + if (normal_id == NULL) + { + g_simple_async_result_take_error (result, error); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); + return; + } + + /* If it is already a WLM jid, return it */ + if (g_str_has_suffix (normal_id, "@messenger.live.com")) + { + g_simple_async_result_set_op_res_gpointer (result, normal_id, g_free); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); + return; + } + + /* Ask the server to give a WLM jid */ + iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET, + conn_util_get_bare_self_jid (self), normal_id, + '(', "getjid", + ':', NS_WLM_JID_LOOKUP, + ')', + NULL); + + conn_util_send_iq_async (self, iq, NULL, conn_wlm_jid_lookup_cb, result); + + g_object_unref (iq); + g_free (normal_id); +} + +static gchar * +conn_wlm_jid_lookup_finish (TpHandleRepoIface *repo, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = (GSimpleAsyncResult *) result; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, + G_OBJECT (repo), conn_wlm_jid_lookup_async), NULL); + + if (g_simple_async_result_propagate_error (simple, error)) + return NULL; + + return g_strdup (g_simple_async_result_get_op_res_gpointer (simple)); +} + +static void connection_disco_cb (GabbleDisco *disco, GabbleDiscoRequest *request, const gchar *jid, @@ -2838,9 +2959,10 @@ connection_disco_cb (GabbleDisco *disco, GabbleConnection *conn = GABBLE_CONNECTION (user_data); TpBaseConnection *base = (TpBaseConnection *) conn; - if (base->status != TP_CONNECTION_STATUS_CONNECTING) + if (tp_base_connection_get_status (base) != TP_CONNECTION_STATUS_CONNECTING) { - g_assert (base->status == TP_CONNECTION_STATUS_DISCONNECTED); + g_assert (tp_base_connection_get_status (base) == + TP_CONNECTION_STATUS_DISCONNECTED); return; } @@ -2903,12 +3025,25 @@ connection_disco_cb (GabbleDisco *disco, conn->features |= GABBLE_CONNECTION_FEATURES_GOOGLE_QUEUE; else if (0 == strcmp (var, NS_GOOGLE_SETTING)) conn->features |= GABBLE_CONNECTION_FEATURES_GOOGLE_SETTING; + else if (0 == strcmp (var, NS_WLM_JID_LOOKUP)) + conn->features |= GABBLE_CONNECTION_FEATURES_WLM_JID_LOOKUP; } } DEBUG ("set features flags to %d", conn->features); } + if ((conn->features & GABBLE_CONNECTION_FEATURES_WLM_JID_LOOKUP) != 0) + { + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, + TP_HANDLE_TYPE_CONTACT); + + tp_dynamic_handle_repo_set_normalize_async ( + (TpDynamicHandleRepo *) contact_repo, + conn_wlm_jid_lookup_async, + conn_wlm_jid_lookup_finish); + } + conn_presence_set_initial_presence_async (conn, connection_initial_presence_cb, NULL); @@ -2943,7 +3078,8 @@ connection_initial_presence_cb (GObject *source_object, { DEBUG ("error setting up initial presence: %s", error->message); - if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) + if (tp_base_connection_get_status (base) != + TP_CONNECTION_STATUS_DISCONNECTED) tp_base_connection_change_status (base, TP_CONNECTION_STATUS_DISCONNECTED, TP_CONNECTION_STATUS_REASON_NETWORK_ERROR); @@ -3099,11 +3235,11 @@ gabble_connection_get_handle_contact_capabilities ( GabbleConnection *self, TpHandle handle) { - TpBaseConnection *base_conn = TP_BASE_CONNECTION (self); + TpBaseConnection *base = TP_BASE_CONNECTION (self); GabblePresence *p; const GabbleCapabilitySet *caps; - if (handle == base_conn->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) p = self->self_presence; else p = gabble_presence_cache_get (self->presence_cache, handle); @@ -3211,8 +3347,8 @@ gabble_connection_advertise_capabilities (TpSvcConnectionInterfaceCapabilities * if (gabble_connection_refresh_capabilities (self, &save_set)) { - _emit_capabilities_changed (self, base->self_handle, save_set, - priv->all_caps); + _emit_capabilities_changed (self, + tp_base_connection_get_self_handle (base), save_set, priv->all_caps); gabble_capability_set_free (save_set); } @@ -3475,7 +3611,8 @@ gabble_connection_update_capabilities ( if (gabble_connection_refresh_capabilities (self, &old_caps)) { - _emit_capabilities_changed (self, base->self_handle, old_caps, + _emit_capabilities_changed (self, + tp_base_connection_get_self_handle (base), old_caps, self->priv->all_caps); gabble_capability_set_free (old_caps); } @@ -3512,7 +3649,7 @@ gabble_connection_get_handle_capabilities (GabbleConnection *self, return; } - if (handle == base->self_handle) + if (handle == tp_base_connection_get_self_handle (base)) pres = self->self_presence; else pres = gabble_presence_cache_get (self->presence_cache, handle); @@ -3842,6 +3979,7 @@ gabble_connection_update_sidecar_capabilities (GabbleConnection *self, const GabbleCapabilitySet *add_set, const GabbleCapabilitySet *remove_set) { + TpBaseConnection *base = TP_BASE_CONNECTION (self); GabbleConnectionPrivate *priv = self->priv; GabbleCapabilitySet *save_set; @@ -3874,8 +4012,8 @@ gabble_connection_update_sidecar_capabilities (GabbleConnection *self, if (gabble_connection_refresh_capabilities (self, &save_set)) { - _emit_capabilities_changed (self, TP_BASE_CONNECTION (self)->self_handle, - save_set, priv->all_caps); + _emit_capabilities_changed (self, + tp_base_connection_get_self_handle (base), save_set, priv->all_caps); gabble_capability_set_free (save_set); } } diff --git a/src/connection.h b/src/connection.h index 50734b777..c3e9138b0 100644 --- a/src/connection.h +++ b/src/connection.h @@ -25,11 +25,7 @@ #include <dbus/dbus-glib.h> #include <glib-object.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/contacts-mixin.h> -#include <telepathy-glib/presence-mixin.h> -#include <telepathy-glib/dbus-properties-mixin.h> -#include <telepathy-glib/dbus.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> @@ -43,9 +39,6 @@ #include "muc-factory.h" #include "types.h" -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/base-contact-list.h> - #include <gabble/capabilities-set.h> #include <gabble/types.h> #include <gabble/plugin-connection.h> @@ -143,6 +136,7 @@ typedef enum GABBLE_CONNECTION_FEATURES_GOOGLE_SHARED_STATUS = 1 << 7, GABBLE_CONNECTION_FEATURES_GOOGLE_QUEUE = 1 << 8, GABBLE_CONNECTION_FEATURES_GOOGLE_SETTING = 1 << 9, + GABBLE_CONNECTION_FEATURES_WLM_JID_LOOKUP = 1 << 10, } GabbleConnectionFeatures; typedef struct _GabbleConnectionPrivate GabbleConnectionPrivate; diff --git a/src/debug.c b/src/debug.c index a7616f712..8e3dd0c50 100644 --- a/src/debug.c +++ b/src/debug.c @@ -16,8 +16,8 @@ #include <errno.h> #include <glib/gstdio.h> -#include <telepathy-glib/debug.h> -#include <telepathy-glib/debug-sender.h> + +#include <telepathy-glib/telepathy-glib.h> static GabbleDebugFlags flags = 0; diff --git a/src/disco.c b/src/disco.c index 6f142a4e1..20726dd31 100644 --- a/src/disco.c +++ b/src/disco.c @@ -28,7 +28,7 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/dbus.h> +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_DISCO diff --git a/src/error.c b/src/error.c index e79ddef32..ad3bf7b14 100644 --- a/src/error.c +++ b/src/error.c @@ -344,7 +344,7 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, klass = g_type_class_ref (WOCKY_TYPE_XMPP_ERROR); name = get_error_prefix (klass, wocky_error->code, "unknown WockyXmppError code"); - g_set_error (error, TP_ERRORS, + g_set_error (error, TP_ERROR, map_wocky_xmpp_error (wocky_error, conn_reason), "%s (#%d): %s", name, wocky_error->code, wocky_error->message); g_type_class_unref (klass); @@ -356,7 +356,7 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, "unknown GIOError code"); /* FIXME: is it safe to assume that every GIOError we encounter from * Wocky is a NetworkError? */ - g_set_error (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR, + g_set_error (error, TP_ERROR, TP_ERROR_NETWORK_ERROR, "%s (#%d): %s", name, wocky_error->code, wocky_error->message); g_type_class_unref (klass); @@ -368,7 +368,7 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, klass = g_type_class_ref (WOCKY_TYPE_AUTH_ERROR); name = get_error_prefix (klass, wocky_error->code, "unknown WockyAuthError code"); - g_set_error (error, TP_ERRORS, + g_set_error (error, TP_ERROR, map_wocky_auth_error (wocky_error, conn_reason), "%s (#%d): %s", name, wocky_error->code, wocky_error->message); g_type_class_unref (klass); @@ -378,7 +378,7 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, klass = g_type_class_ref (WOCKY_TYPE_CONNECTOR_ERROR); name = get_error_prefix (klass, wocky_error->code, "unknown WockyConnectorError code"); - g_set_error (error, TP_ERRORS, + g_set_error (error, TP_ERROR, map_wocky_connector_error (wocky_error, conn_reason), "%s (#%d): %s", name, wocky_error->code, wocky_error->message); g_type_class_unref (klass); @@ -388,7 +388,7 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, klass = g_type_class_ref (WOCKY_TYPE_XMPP_STREAM_ERROR); name = get_error_prefix (klass, wocky_error->code, "unknown WockyXmppStreamError code"); - g_set_error (error, TP_ERRORS, + g_set_error (error, TP_ERROR, map_wocky_stream_error (wocky_error, previous_status, conn_reason), "%s (#%d): %s", name, wocky_error->code, wocky_error->message); g_type_class_unref (klass); @@ -398,7 +398,7 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, klass = g_type_class_ref (WOCKY_TYPE_TLS_CERT_STATUS); name = get_error_prefix (klass, wocky_error->code, "unknown WockyTLSCertStatus code"); - g_set_error (error, TP_ERRORS, + g_set_error (error, TP_ERROR, map_wocky_tls_cert_error (wocky_error, conn_reason), "%s (#%d): %s", name, wocky_error->code, wocky_error->message); g_type_class_unref (klass); @@ -406,14 +406,14 @@ gabble_set_tp_conn_error_from_wocky (const GError *wocky_error, else if (wocky_error->domain == WOCKY_XMPP_CONNECTION_ERROR) { /* FIXME: there's no GEnum for WockyXmppConnectionError. */ - g_set_error_literal (error, TP_ERRORS, + g_set_error_literal (error, TP_ERROR, map_connection_error (wocky_error), wocky_error->message); } else { /* best we can do... */ - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "%s (#%d): %s", g_quark_to_string (wocky_error->domain), wocky_error->code, wocky_error->message); } diff --git a/src/ft-channel.c b/src/ft-channel.c index 57b891205..fd82405c5 100644 --- a/src/ft-channel.c +++ b/src/ft-channel.c @@ -48,14 +48,8 @@ #include "presence-cache.h" #include "util.h" -#include <telepathy-glib/base-channel.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/svc-generic.h> -#include <telepathy-glib/svc-channel.h> - +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> static void file_transfer_iface_init (gpointer g_iface, gpointer iface_data); static void transferred_chunk (GabbleFileTransferChannel *self, guint64 count); @@ -79,8 +73,6 @@ G_DEFINE_TYPE_WITH_CODE (GabbleFileTransferChannel, gabble_file_transfer_channel #define GABBLE_UNDEFINED_FILE_SIZE G_MAXUINT64 -static const char *gabble_file_transfer_channel_interfaces[] = { NULL }; - /* properties */ enum { @@ -481,21 +473,21 @@ file_transfer_channel_properties_setter (GObject *object, if (self->priv->uri != NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "URI has already be set"); return FALSE; } if (tp_base_channel_is_requested (base)) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Channel is not an incoming transfer"); return FALSE; } if (self->priv->state != TP_FILE_TRANSFER_STATE_PENDING) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "State is not pending; cannot set URI"); return FALSE; } @@ -548,6 +540,20 @@ gabble_file_transfer_channel_get_object_path_suffix (TpBaseChannel *chan) return g_strdup_printf ("FileTransferChannel/%p", chan); } +static GPtrArray * +gabble_file_transfer_channel_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_file_transfer_channel_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, GABBLE_IFACE_CHANNEL_TYPE_FILETRANSFER_FUTURE); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA); + + return interfaces; +} + static void gabble_file_transfer_channel_class_init ( GabbleFileTransferChannelClass *gabble_file_transfer_channel_class) @@ -614,8 +620,8 @@ gabble_file_transfer_channel_class_init ( object_class->set_property = gabble_file_transfer_channel_set_property; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER; - base_class->interfaces = gabble_file_transfer_channel_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; + base_class->get_interfaces = gabble_file_transfer_channel_get_interfaces; base_class->close = gabble_file_transfer_channel_close; base_class->fill_immutable_properties = gabble_file_transfer_channel_fill_immutable_properties; @@ -931,7 +937,7 @@ check_address_and_access_control (GabbleFileTransferChannel *self, GUINT_TO_POINTER (address_type)); if (access_arr == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "AddressType %u is not implemented", address_type); return FALSE; } @@ -946,7 +952,7 @@ check_address_and_access_control (GabbleFileTransferChannel *self, return TRUE; } - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "AccesControl %u is not implemented with AddressType %u", access_control, address_type); @@ -1073,7 +1079,6 @@ set_gtalk_file_collection ( static void bytestream_negotiate_cb (GabbleBytestreamIface *bytestream, - const gchar *stream_id, WockyStanza *msg, GObject *object, gpointer user_data) @@ -1127,8 +1132,7 @@ add_metadata_forms (GabbleFileTransferChannel *self, { if (!tp_str_empty (self->priv->service_name)) { - WockyStanza *tmp = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, - WOCKY_STANZA_SUB_TYPE_RESULT, NULL, NULL, + wocky_node_add_build (file, '(', "x", ':', NS_X_DATA, '@', "type", "result", @@ -1147,21 +1151,19 @@ add_metadata_forms (GabbleFileTransferChannel *self, ')', ')', NULL); - WockyNode *x = wocky_node_get_first_child (wocky_stanza_get_top_node (tmp)); - WockyNodeTree *tree = wocky_node_tree_new_from_node (x); - - wocky_node_add_node_tree (file, tree); - g_object_unref (tree); - g_object_unref (tmp); } if (self->priv->metadata != NULL && g_hash_table_size (self->priv->metadata) > 0) { - WockyStanza *tmp = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, - WOCKY_STANZA_SUB_TYPE_RESULT, NULL, NULL, + WockyNode *x; + GHashTableIter iter; + gpointer key, val; + + wocky_node_add_build (file, '(', "x", ':', NS_X_DATA, + '*', &x, '@', "type", "result", '(', "field", '@', "var", "FORM_TYPE", @@ -1172,10 +1174,6 @@ add_metadata_forms (GabbleFileTransferChannel *self, ')', ')', NULL); - WockyNode *x = wocky_node_get_first_child (wocky_stanza_get_top_node (tmp)); - WockyNodeTree *tree; - GHashTableIter iter; - gpointer key, val; g_hash_table_iter_init (&iter, self->priv->metadata); while (g_hash_table_iter_next (&iter, &key, &val)) @@ -1190,21 +1188,15 @@ add_metadata_forms (GabbleFileTransferChannel *self, wocky_node_add_child_with_content (field, "value", *values); } } - - tree = wocky_node_tree_new_from_node (x); - wocky_node_add_node_tree (file, tree); - g_object_unref (tree); - g_object_unref (tmp); } } -static gboolean +static void offer_bytestream (GabbleFileTransferChannel *self, const gchar *jid, - const gchar *resource, GError **error) + const gchar *resource) { GabbleConnection *conn = GABBLE_CONNECTION (tp_base_channel_get_connection ( TP_BASE_CHANNEL (self))); - gboolean result; WockyStanza *msg; WockyNode *si_node, *file_node; gchar *stream_id, *size_str, *full_jid; @@ -1232,8 +1224,7 @@ offer_bytestream (GabbleFileTransferChannel *self, const gchar *jid, size_str = g_strdup_printf ("%" G_GUINT64_FORMAT, self->priv->size); - file_node = wocky_node_add_child_with_content (si_node, "file", NULL); - file_node->ns = g_quark_from_string (NS_FILE_TRANSFER); + file_node = wocky_node_add_child_ns (si_node, "file", NS_FILE_TRANSFER); wocky_node_set_attributes (file_node, "name", self->priv->filename, "size", size_str, @@ -1266,18 +1257,16 @@ offer_bytestream (GabbleFileTransferChannel *self, const gchar *jid, wocky_node_add_child_with_content (file_node, "desc", self->priv->description); /* we support resume */ - wocky_node_add_child_with_content (file_node, "range", NULL); + wocky_node_add_child (file_node, "range"); - result = gabble_bytestream_factory_negotiate_stream ( + gabble_bytestream_factory_negotiate_stream ( conn->bytestream_factory, msg, stream_id, - bytestream_negotiate_cb, self, G_OBJECT (self), error); + bytestream_negotiate_cb, self, G_OBJECT (self)); g_object_unref (msg); g_free (stream_id); g_free (size_str); g_free (full_jid); - - return result; } #ifdef ENABLE_JINGLE_FILE_TRANSFER @@ -1349,7 +1338,7 @@ offer_gtalk_file_transfer (GabbleFileTransferChannel *self, TpBaseChannel *base = TP_BASE_CHANNEL (self); GabbleConnection *conn = GABBLE_CONNECTION ( tp_base_channel_get_connection (base)); - GabbleJingleFactory *jf; + WockyJingleFactory *jf; GTalkFileCollection *gtalk_file_collection; DEBUG ("Offering Gtalk file transfer to %s", full_jid); @@ -1410,7 +1399,7 @@ gabble_file_transfer_channel_offer_file (GabbleFileTransferChannel *self, if (presence == NULL) { DEBUG ("can't find contact's presence"); - g_set_error (error, TP_ERRORS, TP_ERROR_OFFLINE, + g_set_error (error, TP_ERROR, TP_ERROR_OFFLINE, "can't find contact's presence"); return FALSE; @@ -1422,7 +1411,7 @@ gabble_file_transfer_channel_offer_file (GabbleFileTransferChannel *self, { DEBUG ("trying to use Metadata properties on a contact " "who doesn't support it"); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_CAPABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "The specified contact does not support the " "Metadata extension; you should ensure both ServiceName and " "Metadata properties are not present in the channel " @@ -1468,7 +1457,7 @@ gabble_file_transfer_channel_offer_file (GabbleFileTransferChannel *self, #ifdef ENABLE_JINGLE_FILE_TRANSFER use_si = si && (!jingle_share || - gabble_jingle_info_get_google_relay_token ( + wocky_jingle_info_get_google_relay_token ( gabble_jingle_mint_get_info (conn->jingle_mint)) == NULL); #else use_si = si; @@ -1476,7 +1465,8 @@ gabble_file_transfer_channel_offer_file (GabbleFileTransferChannel *self, if (use_si) { - result = offer_bytestream (self, jid, si_resource, error); + offer_bytestream (self, jid, si_resource); + result = TRUE; } #ifdef ENABLE_JINGLE_FILE_TRANSFER else if (jingle_share) @@ -1490,7 +1480,7 @@ gabble_file_transfer_channel_offer_file (GabbleFileTransferChannel *self, else { DEBUG ("contact doesn't have file transfer capabilities"); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_CAPABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "contact doesn't have file transfer capabilities"); result = FALSE; } @@ -1658,15 +1648,14 @@ augment_si_reply (WockyNode *si, GabbleFileTransferChannel *self = GABBLE_FILE_TRANSFER_CHANNEL (user_data); WockyNode *file; - file = wocky_node_add_child_with_content (si, "file", NULL); - file->ns = g_quark_from_string (NS_FILE_TRANSFER); + file = wocky_node_add_child_ns (si, "file", NS_FILE_TRANSFER); if (self->priv->initial_offset != 0) { WockyNode *range; gchar *offset_str; - range = wocky_node_add_child_with_content (file, "range", NULL); + range = wocky_node_add_child (file, "range"); offset_str = g_strdup_printf ("%" G_GUINT64_FORMAT, self->priv->initial_offset); wocky_node_set_attribute (range, "offset", offset_str); @@ -1698,7 +1687,7 @@ gabble_file_transfer_channel_accept_file (TpSvcChannelTypeFileTransfer *iface, if (tp_base_channel_is_requested (base)) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Channel is not an incoming transfer"); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1707,7 +1696,7 @@ gabble_file_transfer_channel_accept_file (TpSvcChannelTypeFileTransfer *iface, if (self->priv->state != TP_FILE_TRANSFER_STATE_PENDING) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "State is not pending; cannot accept file"); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1726,7 +1715,7 @@ gabble_file_transfer_channel_accept_file (TpSvcChannelTypeFileTransfer *iface, access_control_param)) { DEBUG ("Could not set up local socket"); - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Could not set up local socket"); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1798,7 +1787,7 @@ gabble_file_transfer_channel_provide_file ( if (!tp_base_channel_is_requested (TP_BASE_CHANNEL (self))) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Channel is not an outgoing transfer"); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1808,7 +1797,7 @@ gabble_file_transfer_channel_provide_file ( if (self->priv->state != TP_FILE_TRANSFER_STATE_PENDING && self->priv->state != TP_FILE_TRANSFER_STATE_ACCEPTED) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "State is not pending or accepted; cannot provide file"); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1817,7 +1806,7 @@ gabble_file_transfer_channel_provide_file ( if (self->priv->socket_address != NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "ProvideFile has already been called for this channel"); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1836,7 +1825,7 @@ gabble_file_transfer_channel_provide_file ( access_control_param)) { DEBUG ("Could not set up local socket"); - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Could not set up local socket"); dbus_g_method_return_error (context, error); g_error_free (error); diff --git a/src/ft-channel.h b/src/ft-channel.h index 323c1e651..87943646b 100644 --- a/src/ft-channel.h +++ b/src/ft-channel.h @@ -26,7 +26,7 @@ #include <glib-object.h> #include <extensions/extensions.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> typedef struct _GabbleFileTransferChannel GabbleFileTransferChannel; diff --git a/src/ft-manager.c b/src/ft-manager.c index a6bb13090..a4266b5a0 100644 --- a/src/ft-manager.c +++ b/src/ft-manager.c @@ -31,7 +31,6 @@ #include <glib/gstdio.h> #ifdef ENABLE_JINGLE_FILE_TRANSFER -#include "jingle-session.h" #include "jingle-share.h" #endif #include "gabble/caps-channel-manager.h" @@ -45,14 +44,8 @@ #include <wocky/wocky.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/base-channel.h> -#include <telepathy-glib/channel-factory-iface.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_FT #include "debug.h" @@ -346,24 +339,24 @@ gabble_ft_manager_channel_created (GabbleFtManager *self, #ifdef ENABLE_JINGLE_FILE_TRANSFER static void new_jingle_session_cb (GabbleJingleMint *jm, - GabbleJingleSession *sess, + WockyJingleSession *sess, gpointer data) { GabbleFtManager *self = GABBLE_FT_MANAGER (data); GTalkFileCollection *gtalk_fc = NULL; - GabbleJingleContent *content = NULL; + WockyJingleContent *content = NULL; GabbleJingleShareManifest *manifest = NULL; GList *channels = NULL; GList *cs, *i; - if (gabble_jingle_session_get_content_type (sess) == + if (wocky_jingle_session_get_content_type (sess) == GABBLE_TYPE_JINGLE_SHARE) { - cs = gabble_jingle_session_get_contents (sess); + cs = wocky_jingle_session_get_contents (sess); if (cs != NULL) { - content = GABBLE_JINGLE_CONTENT (cs->data); + content = WOCKY_JINGLE_CONTENT (cs->data); g_list_free (cs); } @@ -393,7 +386,7 @@ new_jingle_session_cb (GabbleJingleMint *jm, TP_BASE_CONNECTION (self->priv->connection), TP_HANDLE_TYPE_CONTACT); TpHandle peer = tp_handle_ensure (contacts, - gabble_jingle_session_get_peer_jid (sess), NULL, NULL); + wocky_jingle_session_get_peer_jid (sess), NULL, NULL); filename = g_strdup_printf ("%s%s", entry->name, entry->folder? ".tar":""); @@ -457,10 +450,9 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, { GabbleFtManager *self = GABBLE_FT_MANAGER (manager); GabbleFileTransferChannel *chan; - TpBaseConnection *base_connection = TP_BASE_CONNECTION ( - self->priv->connection); + TpBaseConnection *base_conn = TP_BASE_CONNECTION (self->priv->connection); TpHandleRepoIface *contact_repo = - tp_base_connection_get_handles (base_connection, TP_HANDLE_TYPE_CONTACT); + tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_CONTACT); TpHandle handle; const gchar *content_type, *filename, *content_hash, *description; const gchar *file_uri, *service_name; @@ -491,9 +483,9 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, goto error; /* Don't support opening a channel to our self handle */ - if (handle == base_connection->self_handle) + if (handle == tp_base_connection_get_self_handle (base_conn)) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Can't open a file transfer channel to yourself"); goto error; } @@ -502,7 +494,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentType"); if (content_type == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "ContentType property is mandatory"); goto error; } @@ -511,7 +503,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Filename"); if (filename == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Filename property is mandatory"); goto error; } @@ -520,7 +512,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Size", NULL); if (size == 0) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Size property is mandatory"); goto error; } @@ -536,7 +528,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, { if (content_hash_type >= NUM_TP_FILE_HASH_TYPES) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u is not a valid ContentHashType", content_hash_type); goto error; } @@ -548,7 +540,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHash"); if (content_hash == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "ContentHash property is mandatory if ContentHashType is " "not None"); goto error; @@ -580,7 +572,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, if (metadata != NULL && g_hash_table_lookup ((GHashTable *) metadata, "FORM_TYPE")) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Metadata cannot contain an item with key 'FORM_TYPE'"); goto error; } @@ -589,7 +581,8 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, tp_handle_inspect (contact_repo, handle)); chan = gabble_file_transfer_channel_new (self->priv->connection, - handle, base_connection->self_handle, TP_FILE_TRANSFER_STATE_PENDING, + handle, tp_base_connection_get_self_handle (base_conn), + TP_FILE_TRANSFER_STATE_PENDING, content_type, filename, size, content_hash_type, content_hash, description, date, initial_offset, TRUE, NULL, NULL, NULL, file_uri, service_name, metadata); diff --git a/src/gabble.c b/src/gabble.c index 31ca34201..bd5056dfd 100644 --- a/src/gabble.c +++ b/src/gabble.c @@ -29,11 +29,8 @@ #include <glib/gstdio.h> -#include <telepathy-glib/debug.h> -#include <telepathy-glib/debug-sender.h> -#include <telepathy-glib/run.h> -#include <telepathy-glib/util.h> -#include <wocky/wocky.h> +#include <telepathy-glib/telepathy-glib.h> + #include <wocky/wocky.h> #include "debug.h" diff --git a/src/google-relay.c b/src/google-relay.c deleted file mode 100644 index 472ef3781..000000000 --- a/src/google-relay.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * google-relay.c - Support for Google relays for Jingle - * - * Copyright (C) 2006-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "google-relay.h" - -#include <string.h> - -#ifdef ENABLE_GOOGLE_RELAY -#include <libsoup/soup.h> -#endif - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#ifdef G_OS_WIN32 -#undef ERROR -#endif - -#include "debug.h" - -#define RELAY_HTTP_TIMEOUT 5 - -struct _GabbleGoogleRelayResolver { -#ifdef ENABLE_GOOGLE_RELAY - SoupSession *soup; -#else - GObject *soup; -#endif -}; - -typedef struct -{ - GPtrArray *relays; - guint component; - guint requests_to_do; - GabbleJingleInfoRelaySessionCb callback; - gpointer user_data; -} RelaySessionData; - -static RelaySessionData * -relay_session_data_new (guint requests_to_do, - GabbleJingleInfoRelaySessionCb callback, - gpointer user_data) -{ - RelaySessionData *rsd = g_slice_new0 (RelaySessionData); - - rsd->relays = g_ptr_array_sized_new (requests_to_do); - g_ptr_array_set_free_func (rsd->relays, (GDestroyNotify) gabble_jingle_relay_free); - rsd->component = 1; - rsd->requests_to_do = requests_to_do; - rsd->callback = callback; - rsd->user_data = user_data; - - return rsd; -} - -/* This is a GSourceFunc */ -static gboolean -relay_session_data_call (gpointer p) -{ - RelaySessionData *rsd = p; - - g_assert (rsd->callback != NULL); - - rsd->callback (rsd->relays, rsd->user_data); - - return FALSE; -} - -/* This is a GDestroyNotify */ -static void -relay_session_data_destroy (gpointer p) -{ - RelaySessionData *rsd = p; - - g_ptr_array_unref (rsd->relays); - - g_slice_free (RelaySessionData, rsd); -} - -#ifdef ENABLE_GOOGLE_RELAY - -static void -translate_relay_info (GPtrArray *relays, - const gchar *relay_ip, - const gchar *username, - const gchar *password, - GabbleJingleRelayType relay_type, - const gchar *port_string, - guint component) -{ - guint64 portll; - guint port; - - if (port_string == NULL) - { - DEBUG ("no relay port for %u found", relay_type); - return; - } - - portll = g_ascii_strtoull (port_string, NULL, 10); - - if (portll == 0 || portll > G_MAXUINT16) - { - DEBUG ("failed to parse relay port '%s' for %u", port_string, - relay_type); - return; - } - port = (guint) portll; - - DEBUG ("type=%u ip=%s port=%u username=%s password=%s component=%u", - relay_type, relay_ip, port, username, password, component); - - g_ptr_array_add (relays, - gabble_jingle_relay_new (relay_type, relay_ip, port, username, password, - component)); -} - -static void -on_http_response (SoupSession *soup, - SoupMessage *msg, - gpointer user_data) -{ - RelaySessionData *rsd = user_data; - - if (msg->status_code != 200) - { - DEBUG ("Google session creation failed, relaying not used: %d %s", - msg->status_code, msg->reason_phrase); - } - else - { - /* parse a=b lines into GHashTable - * (key, value both borrowed from items of the strv 'lines') */ - GHashTable *map = g_hash_table_new (g_str_hash, g_str_equal); - gchar **lines; - guint i; - const gchar *relay_ip; - const gchar *relay_udp_port; - const gchar *relay_tcp_port; - const gchar *relay_ssltcp_port; - const gchar *username; - const gchar *password; - gchar *escaped_str; - - escaped_str = g_strescape (msg->response_body->data, "\r\n"); - DEBUG ("Response from Google:\n====\n%s\n====", escaped_str); - g_free (escaped_str); - - lines = g_strsplit (msg->response_body->data, "\n", 0); - - if (lines != NULL) - { - for (i = 0; lines[i] != NULL; i++) - { - gchar *delim = strchr (lines[i], '='); - size_t len; - - if (delim == NULL || delim == lines[i]) - { - /* ignore empty keys or lines without '=' */ - continue; - } - - len = strlen (lines[i]); - - if (lines[i][len - 1] == '\r') - { - lines[i][len - 1] = '\0'; - } - - *delim = '\0'; - g_hash_table_insert (map, lines[i], delim + 1); - } - } - - relay_ip = g_hash_table_lookup (map, "relay.ip"); - relay_udp_port = g_hash_table_lookup (map, "relay.udp_port"); - relay_tcp_port = g_hash_table_lookup (map, "relay.tcp_port"); - relay_ssltcp_port = g_hash_table_lookup (map, "relay.ssltcp_port"); - username = g_hash_table_lookup (map, "username"); - password = g_hash_table_lookup (map, "password"); - - if (relay_ip == NULL) - { - DEBUG ("No relay.ip found"); - } - else if (username == NULL) - { - DEBUG ("No username found"); - } - else if (password == NULL) - { - DEBUG ("No password found"); - } - else - { - translate_relay_info (rsd->relays, relay_ip, username, password, - GABBLE_JINGLE_RELAY_TYPE_UDP, relay_udp_port, rsd->component); - translate_relay_info (rsd->relays, relay_ip, username, password, - GABBLE_JINGLE_RELAY_TYPE_TCP, relay_tcp_port, rsd->component); - translate_relay_info (rsd->relays, relay_ip, username, password, - GABBLE_JINGLE_RELAY_TYPE_TLS, relay_ssltcp_port, rsd->component); - } - - g_strfreev (lines); - g_hash_table_unref (map); - } - - rsd->component++; - - if ((--rsd->requests_to_do) == 0) - { - relay_session_data_call (rsd); - relay_session_data_destroy (rsd); - } -} - -#endif /* ENABLE_GOOGLE_RELAY */ - -GabbleGoogleRelayResolver * -gabble_google_relay_resolver_new (void) -{ - GabbleGoogleRelayResolver *resolver = - g_slice_new0 (GabbleGoogleRelayResolver); - -#ifdef ENABLE_GOOGLE_RELAY - - resolver->soup = soup_session_async_new (); - - /* If we don't get answer in a few seconds, relay won't do - * us much help anyways. */ - g_object_set (resolver->soup, "timeout", RELAY_HTTP_TIMEOUT, NULL); - -#endif - - return resolver; -} - -void -gabble_google_relay_resolver_destroy (GabbleGoogleRelayResolver *self) -{ - g_clear_object (&self->soup); - - g_slice_free (GabbleGoogleRelayResolver, self); -} - -void -gabble_google_relay_resolver_resolve (GabbleGoogleRelayResolver *self, - guint components, - const gchar *server, - guint16 port, - const gchar *token, - GabbleJingleInfoRelaySessionCb callback, - gpointer user_data) -{ - RelaySessionData *rsd = - relay_session_data_new (components, callback, user_data); - -#ifdef ENABLE_GOOGLE_RELAY - - gchar *url; - guint i; - - if (server == NULL) - { - DEBUG ("No relay server provided, not creating google relay session"); - g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd, - relay_session_data_destroy); - return; - } - - if (token == NULL) - { - DEBUG ("No relay token provided, not creating google relay session"); - g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd, - relay_session_data_destroy); - return; - } - - url = g_strdup_printf ("http://%s:%u/create_session", server, (guint) port); - - for (i = 0; i < components; i++) - { - SoupMessage *msg = soup_message_new ("GET", url); - - DEBUG ("Trying to create a new relay session on %s", url); - - /* libjingle sets both headers, so shall we */ - soup_message_headers_append (msg->request_headers, - "X-Talk-Google-Relay-Auth", token); - soup_message_headers_append (msg->request_headers, - "X-Google-Relay-Auth", token); - - soup_session_queue_message (self->soup, msg, on_http_response, rsd); - } - - g_free (url); - -#else /* !ENABLE_GOOGLE_RELAY */ - - DEBUG ("Google relay service is not supported"); - - g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd, - relay_session_data_destroy); - -#endif -} diff --git a/src/google-relay.h b/src/google-relay.h deleted file mode 100644 index fc737a7c6..000000000 --- a/src/google-relay.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * google-relay.h - Header for GabbleGoogleRelaySession - * - * Copyright (C) 2006-2008 Collabora Ltd. - * Copyright (C) 2011 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __GABBLE_GOOGLE_RELAY_H__ -#define __GABBLE_GOOGLE_RELAY_H__ - -#include <glib.h> - -#include "jingle-info.h" - -G_BEGIN_DECLS - -typedef struct _GabbleGoogleRelayResolver GabbleGoogleRelayResolver; - -GabbleGoogleRelayResolver * gabble_google_relay_resolver_new (void); -void gabble_google_relay_resolver_destroy (GabbleGoogleRelayResolver *self); -void gabble_google_relay_resolver_resolve (GabbleGoogleRelayResolver *self, - guint requests_to_do, - const gchar *server, - guint16 port, - const gchar *token, - GabbleJingleInfoRelaySessionCb callback, - gpointer user_data); - -G_END_DECLS - -#endif /* __GABBLE_GOOGLE_RELAY_H__ */ diff --git a/src/gtalk-file-collection.c b/src/gtalk-file-collection.c index e13180fe0..6626fd0e3 100644 --- a/src/gtalk-file-collection.c +++ b/src/gtalk-file-collection.c @@ -29,8 +29,6 @@ #define DEBUG_FLAG GABBLE_DEBUG_SHARE #include "debug.h" -#include "jingle-factory.h" -#include "jingle-session.h" #include "jingle-share.h" #include "namespaces.h" #include "util.h" @@ -66,7 +64,7 @@ * | \ * | \ * ref | \ - * GabbleJingleSession \ + * WockyJingleSession \ * | \ (one at a time) * | \ * ref | \ @@ -74,7 +72,7 @@ * | | * | | * ref | ref | - * GabbleTransportGoogle ----------------*- JingleCandidate PseudoTCP + * GabbleTransportGoogle ----------------*- WockyJingleCandidate PseudoTCP * * The protocol works like this : * Once you receive an invitation, the manifest will contain a number of files @@ -183,8 +181,8 @@ struct _GTalkFileCollectionPrivate /* the weakref to the channel here is held through the GList *channels */ GHashTable *channels_usable; GabbleFileTransferChannel *current_channel; - GabbleJingleFactory *jingle_factory; - GabbleJingleSession *jingle; + WockyJingleFactory *jingle_factory; + WockyJingleSession *jingle; /* ICE component id to jingle share channel association GINT_TO_POINTER (candidate->component) => g_slice_new (ShareChannel) */ GHashTable *share_channels; @@ -249,8 +247,8 @@ gtalk_file_collection_dispose (GObject *object) self->priv->dispose_has_run = TRUE; if (self->priv->jingle != NULL) - gabble_jingle_session_terminate (self->priv->jingle, - JINGLE_REASON_UNKNOWN, NULL, NULL); + wocky_jingle_session_terminate (self->priv->jingle, + WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); tp_clear_object (&self->priv->jingle); @@ -412,11 +410,11 @@ del_channel (GTalkFileCollection * self, GabbleFileTransferChannel *channel) } static void -jingle_session_state_changed_cb (GabbleJingleSession *session, +jingle_session_state_changed_cb (WockyJingleSession *session, GParamSpec *arg1, GTalkFileCollection *self) { - JingleState state; + WockyJingleState state; GList *i; DEBUG ("called"); @@ -427,11 +425,11 @@ jingle_session_state_changed_cb (GabbleJingleSession *session, switch (state) { - case JINGLE_STATE_INVALID: - case JINGLE_STATE_PENDING_CREATED: + case WOCKY_JINGLE_STATE_INVALID: + case WOCKY_JINGLE_STATE_PENDING_CREATED: break; - case JINGLE_STATE_PENDING_INITIATE_SENT: - case JINGLE_STATE_PENDING_INITIATED: + case WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT: + case WOCKY_JINGLE_STATE_PENDING_INITIATED: for (i = self->priv->channels; i;) { GabbleFileTransferChannel *channel = i->data; @@ -441,8 +439,8 @@ jingle_session_state_changed_cb (GabbleJingleSession *session, channel, GTALK_FILE_COLLECTION_STATE_PENDING, FALSE); } break; - case JINGLE_STATE_PENDING_ACCEPT_SENT: - case JINGLE_STATE_ACTIVE: + case WOCKY_JINGLE_STATE_PENDING_ACCEPT_SENT: + case WOCKY_JINGLE_STATE_ACTIVE: /* Do not set the channels to OPEN unless we're ready to send/receive data from them */ if (self->priv->status == GTALK_FT_STATUS_INITIATED) @@ -461,7 +459,7 @@ jingle_session_state_changed_cb (GabbleJingleSession *session, channel, GTALK_FILE_COLLECTION_STATE_ACCEPTED, FALSE); } break; - case JINGLE_STATE_ENDED: + case WOCKY_JINGLE_STATE_ENDED: /* Do nothing, let the terminated signal set the correct state depending on the termination reason */ default: @@ -470,9 +468,9 @@ jingle_session_state_changed_cb (GabbleJingleSession *session, } static void -jingle_session_terminated_cb (GabbleJingleSession *session, +jingle_session_terminated_cb (WockyJingleSession *session, gboolean local_terminator, - JingleReason reason, + WockyJingleReason reason, const gchar *text, gpointer user_data) { @@ -494,7 +492,7 @@ jingle_session_terminated_cb (GabbleJingleSession *session, } static void -content_new_remote_candidates_cb (GabbleJingleContent *content, +content_new_remote_candidates_cb (WockyJingleContent *content, GList *clist, gpointer user_data) { GTalkFileCollection *self = GTALK_FILE_COLLECTION (user_data); @@ -504,12 +502,12 @@ content_new_remote_candidates_cb (GabbleJingleContent *content, for (li = clist; li; li = li->next) { - JingleCandidate *candidate = li->data; + WockyJingleCandidate *candidate = li->data; NiceCandidate *cand = NULL; ShareChannel *share_channel = NULL; GSList *candidates = NULL; - if (candidate->protocol != JINGLE_TRANSPORT_PROTOCOL_UDP) + if (candidate->protocol != WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP) { DEBUG ("Ignoring candidate %s because of non-UDP protocol : %d", candidate->username, candidate->protocol); @@ -526,14 +524,14 @@ content_new_remote_candidates_cb (GabbleJingleContent *content, } cand = nice_candidate_new ( - candidate->type == JINGLE_CANDIDATE_TYPE_LOCAL? + candidate->type == WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL? NICE_CANDIDATE_TYPE_HOST: - candidate->type == JINGLE_CANDIDATE_TYPE_STUN? + candidate->type == WOCKY_JINGLE_CANDIDATE_TYPE_STUN? NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: NICE_CANDIDATE_TYPE_RELAYED); - cand->transport = JINGLE_TRANSPORT_PROTOCOL_UDP; + cand->transport = WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP; nice_address_init (&cand->addr); if (!nice_address_set_from_string (&cand->addr, candidate->address)) @@ -577,7 +575,7 @@ nice_candidate_gathering_done (NiceAgent *agent, guint stream_id, { GTalkFileCollection *self = GTALK_FILE_COLLECTION (user_data); ShareChannel *share_channel = get_share_channel (self, agent); - GabbleJingleContent *content = GABBLE_JINGLE_CONTENT (share_channel->content); + WockyJingleContent *content = WOCKY_JINGLE_CONTENT (share_channel->content); GList *candidates = NULL; GList *remote_candidates = NULL; GSList *local_candidates; @@ -586,7 +584,7 @@ nice_candidate_gathering_done (NiceAgent *agent, guint stream_id, DEBUG ("libnice candidate gathering done!!!!"); /* Send remote candidates to libnice and listen to new signal */ - remote_candidates = gabble_jingle_content_get_remote_candidates (content); + remote_candidates = wocky_jingle_content_get_remote_candidates (content); content_new_remote_candidates_cb (content, remote_candidates, self); gabble_signal_connect_weak (content, "new-candidates", @@ -599,22 +597,22 @@ nice_candidate_gathering_done (NiceAgent *agent, guint stream_id, for (li = local_candidates; li; li = li->next) { NiceCandidate *cand = li->data; - JingleCandidate *candidate; + WockyJingleCandidate *candidate; gchar ip[NICE_ADDRESS_STRING_LEN]; nice_address_to_string (&cand->addr, ip); - candidate = jingle_candidate_new ( + candidate = wocky_jingle_candidate_new ( /* protocol */ cand->transport == NICE_CANDIDATE_TRANSPORT_UDP? - JINGLE_TRANSPORT_PROTOCOL_UDP: - JINGLE_TRANSPORT_PROTOCOL_TCP, + WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP: + WOCKY_JINGLE_TRANSPORT_PROTOCOL_TCP, /* candidate type */ cand->type == NICE_CANDIDATE_TYPE_HOST? - JINGLE_CANDIDATE_TYPE_LOCAL: + WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL: cand->type == NICE_CANDIDATE_TYPE_RELAYED? - JINGLE_CANDIDATE_TYPE_RELAY: - JINGLE_CANDIDATE_TYPE_STUN, + WOCKY_JINGLE_CANDIDATE_TYPE_RELAY: + WOCKY_JINGLE_CANDIDATE_TYPE_STUN, /* id */ cand->foundation, /* component */ @@ -637,7 +635,7 @@ nice_candidate_gathering_done (NiceAgent *agent, guint stream_id, candidates = g_list_prepend (candidates, candidate); } - gabble_jingle_content_add_candidates (content, candidates); + wocky_jingle_content_add_candidates (content, candidates); } static void @@ -646,8 +644,8 @@ nice_component_state_changed (NiceAgent *agent, guint stream_id, { GTalkFileCollection *self = GTALK_FILE_COLLECTION (user_data); ShareChannel *share_channel = get_share_channel (self, agent); - GabbleJingleContent *content = GABBLE_JINGLE_CONTENT (share_channel->content); - JingleTransportState ts = JINGLE_TRANSPORT_STATE_DISCONNECTED; + WockyJingleContent *content = WOCKY_JINGLE_CONTENT (share_channel->content); + WockyJingleTransportState ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED; DEBUG ("libnice component state changed %d!!!!", state); @@ -655,14 +653,14 @@ nice_component_state_changed (NiceAgent *agent, guint stream_id, { case NICE_COMPONENT_STATE_DISCONNECTED: case NICE_COMPONENT_STATE_GATHERING: - ts = JINGLE_TRANSPORT_STATE_DISCONNECTED; + ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED; break; case NICE_COMPONENT_STATE_CONNECTING: - ts = JINGLE_TRANSPORT_STATE_CONNECTING; + ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTING; break; case NICE_COMPONENT_STATE_CONNECTED: case NICE_COMPONENT_STATE_READY: - ts = JINGLE_TRANSPORT_STATE_CONNECTED; + ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED; break; case NICE_COMPONENT_STATE_FAILED: { @@ -682,7 +680,7 @@ nice_component_state_changed (NiceAgent *agent, guint stream_id, return; } } - gabble_jingle_content_set_transport_state (content, ts); + wocky_jingle_content_set_transport_state (content, ts); } static void @@ -700,11 +698,11 @@ get_next_manifest_entry (GTalkFileCollection *self, { if (g_list_length (self->priv->channels) == 1) { - GabbleJingleContent *content = \ - GABBLE_JINGLE_CONTENT (share_channel->content); + WockyJingleContent *content = \ + WOCKY_JINGLE_CONTENT (share_channel->content); DEBUG ("Received all the files. Transfer is complete"); - gabble_jingle_content_send_complete (content); + wocky_jingle_content_send_complete (content); } g_hash_table_replace (self->priv->channels_usable, @@ -765,7 +763,7 @@ get_next_manifest_entry (GTalkFileCollection *self, "User-Agent: %s\r\n\r\n", (source_url != NULL ? source_url : ""), separator, filename, - gabble_jingle_session_get_initiator (self->priv->jingle), + wocky_jingle_session_get_initiator (self->priv->jingle), PACKAGE_STRING); g_free (filename); @@ -852,19 +850,19 @@ typedef struct } GoogleRelaySessionData; static const NiceRelayType relay_type_map[] = { - /* GABBLE_JINGLE_RELAY_TYPE_UDP */ NICE_RELAY_TYPE_TURN_UDP, - /* GABBLE_JINGLE_RELAY_TYPE_TCP */ NICE_RELAY_TYPE_TURN_TCP, - /* GABBLE_JINGLE_RELAY_TYPE_TLS */ NICE_RELAY_TYPE_TURN_TLS, + /* WOCKY_JINGLE_RELAY_TYPE_UDP */ NICE_RELAY_TYPE_TURN_UDP, + /* WOCKY_JINGLE_RELAY_TYPE_TCP */ NICE_RELAY_TYPE_TURN_TCP, + /* WOCKY_JINGLE_RELAY_TYPE_TLS */ NICE_RELAY_TYPE_TURN_TLS, }; static void set_relay_info (gpointer item, gpointer user_data) { GoogleRelaySessionData *data = user_data; - GabbleJingleRelay *relay = item; + WockyJingleRelay *relay = item; NiceRelayType type; - g_return_if_fail (relay->type < GABBLE_N_JINGLE_RELAY_TYPES); + g_return_if_fail (relay->type < WOCKY_N_JINGLE_RELAY_TYPES); type = relay_type_map[relay->type]; nice_agent_set_relay_info (data->share_channel->agent, @@ -896,7 +894,7 @@ google_relay_session_cb (GPtrArray *relays, gpointer user_data) static void -content_new_share_channel_cb (GabbleJingleContent *content, const gchar *name, +content_new_share_channel_cb (WockyJingleContent *content, const gchar *name, guint share_channel_id, gpointer user_data) { GTalkFileCollection *self = GTALK_FILE_COLLECTION (user_data); @@ -904,8 +902,7 @@ content_new_share_channel_cb (GabbleJingleContent *content, const gchar *name, NiceAgent *agent = nice_agent_new_reliable (g_main_context_default (), NICE_COMPATIBILITY_GOOGLE); guint stream_id = nice_agent_add_stream (agent, 1); - gchar *stun_server; - guint stun_port; + GList *stun_servers; GoogleRelaySessionData *relay_data = NULL; DEBUG ("New Share channel %s was created and linked to id %d", name, @@ -945,15 +942,18 @@ content_new_share_channel_cb (GabbleJingleContent *content, const gchar *name, nice_agent_attach_recv (agent, stream_id, share_channel->component_id, g_main_context_default (), nice_data_received_cb, self); - if (gabble_jingle_info_get_stun_server ( - gabble_jingle_factory_get_jingle_info (self->priv->jingle_factory), - &stun_server, &stun_port)) + stun_servers = wocky_jingle_info_get_stun_servers ( + wocky_jingle_factory_get_jingle_info (self->priv->jingle_factory)); + if (stun_servers != NULL) { + WockyStunServer *stun_server = stun_servers->data; + g_object_set (agent, - "stun-server", stun_server, - "stun-server-port", stun_port, + "stun-server", stun_server->address, + "stun-server-port", (guint) stun_server->port, NULL); - g_free (stun_server); + + g_list_free (stun_servers); } relay_data = g_slice_new0 (GoogleRelaySessionData); @@ -961,13 +961,13 @@ content_new_share_channel_cb (GabbleJingleContent *content, const gchar *name, relay_data->share_channel = share_channel; g_object_add_weak_pointer (G_OBJECT (relay_data->u.self), &relay_data->u.ptr); - gabble_jingle_info_create_google_relay_session ( - gabble_jingle_factory_get_jingle_info (self->priv->jingle_factory), 1, + wocky_jingle_info_create_google_relay_session ( + wocky_jingle_factory_get_jingle_info (self->priv->jingle_factory), 1, google_relay_session_cb, relay_data); } static void -content_completed (GabbleJingleContent *content, gpointer user_data) +content_completed (WockyJingleContent *content, gpointer user_data) { GTalkFileCollection *self = GTALK_FILE_COLLECTION (user_data); GList *i; @@ -1381,7 +1381,7 @@ nice_data_received_cb (NiceAgent *agent, static void set_session (GTalkFileCollection * self, - GabbleJingleSession *session, GabbleJingleContent *content) + WockyJingleSession *session, WockyJingleContent *content) { self->priv->jingle = g_object_ref (session); @@ -1400,19 +1400,19 @@ set_session (GTalkFileCollection * self, GTalkFileCollection * gtalk_file_collection_new (GabbleFileTransferChannel *channel, - GabbleJingleFactory *jingle_factory, TpHandle handle, const gchar *jid) + WockyJingleFactory *jingle_factory, TpHandle handle, const gchar *jid) { GTalkFileCollection * self = g_object_new (GTALK_TYPE_FILE_COLLECTION, NULL); - GabbleJingleSession *session = NULL; - GabbleJingleContent *content = NULL; + WockyJingleSession *session = NULL; + WockyJingleContent *content = NULL; gchar *filename; guint64 size; self->priv->jingle_factory = jingle_factory; self->priv->requested = TRUE; - session = gabble_jingle_factory_create_session (jingle_factory, - jid, JINGLE_DIALECT_GTALK4, FALSE); + session = wocky_jingle_factory_create_session (jingle_factory, + jid, WOCKY_JINGLE_DIALECT_GTALK4, FALSE); if (session == NULL) { @@ -1420,8 +1420,8 @@ gtalk_file_collection_new (GabbleFileTransferChannel *channel, return NULL; } - content = gabble_jingle_session_add_content (session, - JINGLE_MEDIA_TYPE_NONE, JINGLE_CONTENT_SENDERS_BOTH, "share", + content = wocky_jingle_session_add_content (session, + WOCKY_JINGLE_MEDIA_TYPE_NONE, WOCKY_JINGLE_CONTENT_SENDERS_BOTH, "share", NS_GOOGLE_SESSION_SHARE, NS_GOOGLE_TRANSPORT_P2P); if (content == NULL) @@ -1449,22 +1449,22 @@ gtalk_file_collection_new (GabbleFileTransferChannel *channel, } GTalkFileCollection * -gtalk_file_collection_new_from_session (GabbleJingleFactory *jingle_factory, - GabbleJingleSession *session) +gtalk_file_collection_new_from_session (WockyJingleFactory *jingle_factory, + WockyJingleSession *session) { GTalkFileCollection * self = NULL; - GabbleJingleContent *content = NULL; + WockyJingleContent *content = NULL; GList *cs; - if (gabble_jingle_session_get_content_type (session) != + if (wocky_jingle_session_get_content_type (session) != GABBLE_TYPE_JINGLE_SHARE) return NULL; - cs = gabble_jingle_session_get_contents (session); + cs = wocky_jingle_session_get_contents (session); if (cs != NULL) { - content = GABBLE_JINGLE_CONTENT (cs->data); + content = WOCKY_JINGLE_CONTENT (cs->data); g_list_free (cs); } @@ -1502,7 +1502,7 @@ gtalk_file_collection_initiate (GTalkFileCollection *self, if (self->priv->status == GTALK_FT_STATUS_PENDING) { - gabble_jingle_session_accept (self->priv->jingle); + wocky_jingle_session_accept (self->priv->jingle); self->priv->status = GTALK_FT_STATUS_INITIATED; } else @@ -1517,7 +1517,7 @@ void gtalk_file_collection_accept (GTalkFileCollection *self, GabbleFileTransferChannel * channel) { - GList *cs = gabble_jingle_session_get_contents (self->priv->jingle); + GList *cs = wocky_jingle_session_get_contents (self->priv->jingle); DEBUG ("called"); @@ -1531,11 +1531,11 @@ gtalk_file_collection_accept (GTalkFileCollection *self, { if (cs != NULL) { - GabbleJingleContent *content = GABBLE_JINGLE_CONTENT (cs->data); + WockyJingleContent *content = WOCKY_JINGLE_CONTENT (cs->data); guint initial_id = 0; guint share_channel_id; - gabble_jingle_session_accept (self->priv->jingle); + wocky_jingle_session_accept (self->priv->jingle); self->priv->status = GTALK_FT_STATUS_ACCEPTED; /* The new-share-channel signal will take care of the rest.. */ @@ -1544,7 +1544,7 @@ gtalk_file_collection_accept (GTalkFileCollection *self, gchar *share_channel_name = NULL; share_channel_name = g_strdup_printf ("gabble-%d", ++initial_id); - share_channel_id = gabble_jingle_content_create_share_channel ( + share_channel_id = wocky_jingle_content_create_share_channel ( content, share_channel_name); g_free (share_channel_name); } while (share_channel_id == 0 && initial_id < 10); @@ -1683,8 +1683,8 @@ gtalk_file_collection_terminate (GTalkFileCollection *self, terminate all channels which should unref us which will unref the jingle session */ self->priv->status = GTALK_FT_STATUS_TERMINATED; - gabble_jingle_session_terminate (self->priv->jingle, - JINGLE_REASON_UNKNOWN, NULL, NULL); + wocky_jingle_session_terminate (self->priv->jingle, + WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); return; } return; @@ -1695,7 +1695,7 @@ gtalk_file_collection_terminate (GTalkFileCollection *self, /* If this was the last channel, it will cause it to unref us and the dispose will be called, which will call - gabble_jingle_session_terminate */ + wocky_jingle_session_terminate */ gabble_file_transfer_channel_gtalk_file_collection_state_changed (channel, GTALK_FILE_COLLECTION_STATE_TERMINATED, TRUE); } @@ -1724,8 +1724,8 @@ channel_disposed (gpointer data, GObject *object) terminate all channels which should unref us which will unref the jingle session */ self->priv->status = GTALK_FT_STATUS_TERMINATED; - gabble_jingle_session_terminate (self->priv->jingle, - JINGLE_REASON_UNKNOWN, NULL, NULL); + wocky_jingle_session_terminate (self->priv->jingle, + WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); return; } } diff --git a/src/gtalk-file-collection.h b/src/gtalk-file-collection.h index 895a77d43..b1e784fc2 100644 --- a/src/gtalk-file-collection.h +++ b/src/gtalk-file-collection.h @@ -21,7 +21,7 @@ #define __GTALK_FILE_COLLECTION_H__ #include <glib-object.h> -#include "jingle-session.h" +#include <wocky/wocky.h> #include "connection.h" typedef struct _GTalkFileCollection GTalkFileCollection; @@ -73,11 +73,11 @@ struct _GTalkFileCollection { }; GTalkFileCollection *gtalk_file_collection_new ( - GabbleFileTransferChannel *channel, GabbleJingleFactory *jingle_factory, + GabbleFileTransferChannel *channel, WockyJingleFactory *jingle_factory, TpHandle handle, const gchar *jid); GTalkFileCollection *gtalk_file_collection_new_from_session ( - GabbleJingleFactory *jingle_factory, GabbleJingleSession *session); + WockyJingleFactory *jingle_factory, WockyJingleSession *session); void gtalk_file_collection_add_channel (GTalkFileCollection *self, GabbleFileTransferChannel *channel); diff --git a/src/im-channel.c b/src/im-channel.c index d294c3a04..9cbdbfaab 100644 --- a/src/im-channel.c +++ b/src/im-channel.c @@ -24,14 +24,9 @@ #include <string.h> #include <dbus/dbus-glib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_IM #include "connection.h" @@ -44,7 +39,6 @@ #include "roster.h" #include "util.h" -static void chat_state_iface_init (gpointer, gpointer); static void destroyable_iface_init (gpointer, gpointer); G_DEFINE_TYPE_WITH_CODE (GabbleIMChannel, gabble_im_channel, @@ -54,20 +48,16 @@ G_DEFINE_TYPE_WITH_CODE (GabbleIMChannel, gabble_im_channel, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGES, tp_message_mixin_messages_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CHAT_STATE, - chat_state_iface_init); + tp_message_mixin_chat_state_iface_init) G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE, destroyable_iface_init)); static void _gabble_im_channel_send_message (GObject *object, TpMessage *message, TpMessageSendingFlags flags); static void gabble_im_channel_close (TpBaseChannel *base_chan); - -static const gchar *gabble_im_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE, - TP_IFACE_CHANNEL_INTERFACE_MESSAGES, - TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE, - NULL -}; +static gboolean _gabble_im_channel_send_chat_state (GObject *object, + TpChannelChatState state, + GError **error); /* private structure */ @@ -84,13 +74,6 @@ struct _GabbleIMChannelPrivate 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 - * opening a channel and closing it immediately sending a spurious <gone/> to - * the peer. - */ - gboolean send_gone; - gboolean dispose_has_run; }; @@ -98,8 +81,24 @@ typedef struct { GabbleIMChannel *channel; TpMessage *message; gchar *token; + TpMessageSendingFlags flags; } _GabbleIMSendMessageCtx; +static GPtrArray * +gabble_im_channel_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_im_channel_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_MESSAGES); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE); + + return interfaces; +} + static void gabble_im_channel_init (GabbleIMChannel *self) { @@ -143,15 +142,21 @@ gabble_im_channel_constructed (GObject *obj) else priv->send_nick = TRUE; - priv->chat_states_supported = CHAT_STATES_UNKNOWN; - tp_message_mixin_init (obj, G_STRUCT_OFFSET (GabbleIMChannel, message_mixin), base_conn); + /* We deliberately do not include + * TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_SUCCESSES here, even though we + * support requesting receipts, because XEP-0184 provides no guarantees. + */ tp_message_mixin_implement_sending (obj, _gabble_im_channel_send_message, G_N_ELEMENTS (types), types, 0, TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES, supported_content_types); + + priv->chat_states_supported = CHAT_STATES_UNKNOWN; + tp_message_mixin_implement_send_chat_state (obj, + _gabble_im_channel_send_chat_state); } static void gabble_im_channel_dispose (GObject *object); @@ -197,7 +202,7 @@ gabble_im_channel_class_init (GabbleIMChannelClass *gabble_im_channel_class) object_class->finalize = gabble_im_channel_finalize; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_TEXT; - base_class->interfaces = gabble_im_channel_interfaces; + base_class->get_interfaces = gabble_im_channel_get_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; base_class->close = gabble_im_channel_close; base_class->fill_immutable_properties = @@ -237,22 +242,26 @@ chat_states_supported (GabbleIMChannel *self, } } -static void -im_channel_send_gone (GabbleIMChannel *self) +static gboolean +receipts_conceivably_supported ( + GabbleIMChannel *self) { - GabbleIMChannelPrivate *priv = self->priv; TpBaseChannel *base = (TpBaseChannel *) self; + GabbleConnection *conn = + GABBLE_CONNECTION (tp_base_channel_get_connection (base)); + GabblePresence *presence; - if (priv->send_gone) - { - if (chat_states_supported (self, FALSE)) - gabble_message_util_send_chat_state (G_OBJECT (self), - GABBLE_CONNECTION (tp_base_channel_get_connection (base)), - WOCKY_STANZA_SUB_TYPE_CHAT, TP_CHANNEL_CHAT_STATE_GONE, - priv->peer_jid, NULL); + presence = gabble_presence_cache_get (conn->presence_cache, + tp_base_channel_get_target_handle (base)); - priv->send_gone = FALSE; - } + /* ...except it's never null because _parse_message_message() in + * presence-cache.c. I hate this exactly as much as I did when I wrote the + * FIXME on that function. */ + if (presence != NULL) + return gabble_presence_has_cap (presence, NS_RECEIPTS); + + /* Otherwise ... who knows. Why not ask for one? */ + return TRUE; } static void @@ -282,7 +291,7 @@ gabble_im_channel_dispose (GObject *object) } } - im_channel_send_gone (self); + tp_message_mixin_maybe_send_gone (object); if (G_OBJECT_CLASS (gabble_im_channel_parent_class)->dispose) G_OBJECT_CLASS (gabble_im_channel_parent_class)->dispose (object); @@ -318,7 +327,7 @@ _gabble_im_channel_message_sent_cb (GObject *source, if (wocky_porter_send_finish (porter, res, &error)) { - tp_message_mixin_sent ((GObject *) chan, message, 0, + tp_message_mixin_sent ((GObject *) chan, message, context->flags, context->token, NULL); } else @@ -340,9 +349,10 @@ _gabble_im_channel_send_message (GObject *object, { GabbleIMChannel *self = GABBLE_IM_CHANNEL (object); TpBaseChannel *base = (TpBaseChannel *) self; + TpBaseConnection *base_conn; GabbleConnection *gabble_conn; GabbleIMChannelPrivate *priv; - gint state = -1; + TpChannelChatState state = -1; WockyStanza *stanza = NULL; gchar *id = NULL; GError *error = NULL; @@ -352,29 +362,40 @@ _gabble_im_channel_send_message (GObject *object, g_assert (GABBLE_IS_IM_CHANNEL (self)); priv = self->priv; + base_conn = tp_base_channel_get_connection (base); + gabble_conn = GABBLE_CONNECTION (base_conn); + if (chat_states_supported (self, TRUE)) { state = TP_CHANNEL_CHAT_STATE_ACTIVE; - priv->send_gone = TRUE; + tp_message_mixin_change_chat_state (object, + tp_base_connection_get_self_handle (base_conn), state); } - /* We don't support providing successful delivery reports. */ - flags = 0; - gabble_conn = - GABBLE_CONNECTION (tp_base_channel_get_connection (base)); - stanza = gabble_message_util_build_stanza (message, gabble_conn, 0, state, priv->peer_jid, priv->send_nick, &id, &error); - if (stanza != NULL) { + if ((flags & TP_MESSAGE_SENDING_FLAG_REPORT_DELIVERY) && + receipts_conceivably_supported (self)) + { + wocky_node_add_child_ns (wocky_stanza_get_top_node (stanza), + "request", NS_RECEIPTS); + flags = TP_MESSAGE_SENDING_FLAG_REPORT_DELIVERY; + } + else + { + flags = 0; + } + porter = gabble_connection_dup_porter (gabble_conn); context = g_slice_new0 (_GabbleIMSendMessageCtx); context->channel = g_object_ref (base); context->message = g_object_ref (message); context->token = id; + context->flags = flags; wocky_porter_send_async (porter, stanza, NULL, _gabble_im_channel_message_sent_cb, context); g_object_unref (porter); @@ -382,7 +403,7 @@ _gabble_im_channel_send_message (GObject *object, } else { - tp_message_mixin_sent (object, message, flags, NULL, error); + tp_message_mixin_sent (object, message, 0, NULL, error); g_error_free (error); } @@ -415,29 +436,61 @@ build_message ( return msg; } +static void +maybe_send_delivery_report ( + GabbleIMChannel *self, + WockyStanza *message, + const gchar *jid, + const gchar *id) +{ + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpHandle target = tp_base_channel_get_target_handle (base); + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); + GabbleConnection *conn = GABBLE_CONNECTION (base_conn); + WockyStanza *report; + + if (id == NULL) + return; + + if (wocky_node_get_child_ns (wocky_stanza_get_top_node (message), + "request", NS_RECEIPTS) == NULL) + return; + + if (conn->self_presence->status == GABBLE_PRESENCE_HIDDEN || + !gabble_roster_handle_gets_presence_from_us (conn->roster, target)) + return; + + report = wocky_stanza_build ( + WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, + NULL, jid, + '(', "received", ':', NS_RECEIPTS, + '@', "id", id, + ')', NULL); + + _gabble_connection_send (conn, report, NULL); + g_object_unref (report); +} + /* * _gabble_im_channel_receive: * @chan: a channel + * @message: the <message> stanza, from which all the following arguments were + * extracted. * @type: the message type * @from: the full JID we received the message from * @timestamp: the time at which the message was sent (not the time it was * received) * @id: the id='' attribute from the <message/> stanza, if any * @text: the plaintext body of the message - * @send_error: the reason why sending @text to @sender failed, or - * GABBLE_TEXT_CHANNEL_SEND_NO_ERROR if this call is not to report - * a failure to send. - * @delivery_status: if @send_error is GABBLE_TEXT_CHANNEL_SEND_NO_ERROR, - * ignored; else the delivery status to attach to the report. * @state: a #TpChannelChatState, or -1 if there was no chat state in the * message. * * Shoves an incoming message into @chan, possibly updating the chat state at - * the same time; or maybe this is a delivery report? Who knows! It's a magical - * adventure. + * the same time. */ void _gabble_im_channel_receive (GabbleIMChannel *chan, + WockyStanza *message, TpChannelTextMessageType type, const char *from, time_t timestamp, @@ -475,6 +528,7 @@ _gabble_im_channel_receive (GabbleIMChannel *chan, tp_message_set_string (msg, 0, "message-token", id); tp_message_mixin_take_received (G_OBJECT (chan), msg); + maybe_send_delivery_report (chan, message, from, id); } void @@ -491,7 +545,7 @@ _gabble_im_channel_report_delivery ( TpBaseChannel *base_chan = (TpBaseChannel *) self; TpBaseConnection *base_conn; TpHandle peer; - TpMessage *msg, *delivery_report; + TpMessage *delivery_report; gchar *tmp; g_return_if_fail (GABBLE_IS_IM_CHANNEL (self)); @@ -510,7 +564,6 @@ _gabble_im_channel_report_delivery ( priv->chat_states_supported = CHAT_STATES_UNKNOWN; } - msg = build_message (self, type, timestamp, text); delivery_report = tp_cm_message_new (base_conn, 1); tp_message_set_uint32 (delivery_report, 0, "message-type", TP_CHANNEL_TEXT_MESSAGE_TYPE_DELIVERY_REPORT); @@ -529,15 +582,20 @@ _gabble_im_channel_report_delivery ( if (id != NULL) tp_message_set_string (delivery_report, 0, "delivery-token", id); - /* This is a delivery report, so the original sender of the echoed message - * must be us! */ - tp_cm_message_set_sender (msg, base_conn->self_handle); + if (text != NULL) + { + TpMessage *msg = build_message (self, type, timestamp, text); + /* This is a delivery report, so the original sender of the echoed message + * must be us! */ + tp_cm_message_set_sender (msg, tp_base_connection_get_self_handle (base_conn)); - /* Since this is a delivery report, we can trust the id on the message. */ - if (id != NULL) - tp_message_set_string (msg, 0, "message-token", id); + /* Since this is a delivery report, we can trust the id on the message. */ + if (id != NULL) + tp_message_set_string (msg, 0, "message-token", id); + + tp_cm_message_take_message (delivery_report, 0, "delivery-echo", msg); + } - tp_cm_message_take_message (delivery_report, 0, "delivery-echo", msg); tp_message_mixin_take_received (G_OBJECT (self), delivery_report); } @@ -555,24 +613,32 @@ _gabble_im_channel_state_receive (GabbleIMChannel *chan, GabbleIMChannelPrivate *priv; TpBaseChannel *base_chan; - g_assert (state < NUM_TP_CHANNEL_CHAT_STATES); g_assert (GABBLE_IS_IM_CHANNEL (chan)); base_chan = (TpBaseChannel *) chan; priv = chan->priv; priv->chat_states_supported = CHAT_STATES_SUPPORTED; - tp_svc_channel_interface_chat_state_emit_chat_state_changed ( - (TpSvcChannelInterfaceChatState *) chan, + tp_message_mixin_change_chat_state ((GObject *) chan, tp_base_channel_get_target_handle (base_chan), state); } +void +gabble_im_channel_receive_receipt ( + GabbleIMChannel *self, + const gchar *receipt_id) +{ + _gabble_im_channel_report_delivery (self, + TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, 0, receipt_id, NULL, + GABBLE_TEXT_CHANNEL_SEND_NO_ERROR, TP_DELIVERY_STATUS_DELIVERED); +} + static void gabble_im_channel_close (TpBaseChannel *base_chan) { GabbleIMChannel *self = GABBLE_IM_CHANNEL (base_chan); - im_channel_send_gone (self); + tp_message_mixin_maybe_send_gone ((GObject *) self); /* The IM factory will resurrect the channel if we have pending * messages. When we're resurrected, we want the initiator @@ -610,76 +676,24 @@ gabble_im_channel_destroy (TpSvcChannelInterfaceDestroyable *iface, tp_svc_channel_interface_destroyable_return_from_destroy (context); } - -/** - * gabble_im_channel_set_chat_state - * - * Implements D-Bus method SetChatState - * on interface org.freedesktop.Telepathy.Channel.Interface.ChatState - */ -static void -gabble_im_channel_set_chat_state (TpSvcChannelInterfaceChatState *iface, - guint state, - DBusGMethodInvocation *context) +static gboolean +_gabble_im_channel_send_chat_state (GObject *object, + TpChannelChatState state, + GError **error) { - GabbleIMChannel *self = GABBLE_IM_CHANNEL (iface); + GabbleIMChannel *self = GABBLE_IM_CHANNEL (object); + GabbleIMChannelPrivate *priv = self->priv; TpBaseChannel *base = (TpBaseChannel *) self; - GabbleIMChannelPrivate *priv; - GError *error = NULL; - - g_assert (GABBLE_IS_IM_CHANNEL (self)); - priv = self->priv; + TpBaseConnection *base_conn = tp_base_channel_get_connection (base); - if (state >= NUM_TP_CHANNEL_CHAT_STATES) - { - 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)) - { - TpBaseConnection *base_conn = tp_base_channel_get_connection (base); - - if (gabble_message_util_send_chat_state (G_OBJECT (self), - GABBLE_CONNECTION (base_conn), - WOCKY_STANZA_SUB_TYPE_CHAT, state, priv->peer_jid, &error)) - { - priv->send_gone = TRUE; - - /* Send the ChatStateChanged signal for the local user */ - tp_svc_channel_interface_chat_state_emit_chat_state_changed (iface, - base_conn->self_handle, state); - } - } - - 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); - } -} + * states. */ + if (!chat_states_supported (self, FALSE)) + return TRUE; -static void -chat_state_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceChatStateClass *klass = - (TpSvcChannelInterfaceChatStateClass *) g_iface; -#define IMPLEMENT(x) tp_svc_channel_interface_chat_state_implement_##x (\ - klass, gabble_im_channel_##x) - IMPLEMENT(set_chat_state); -#undef IMPLEMENT + return gabble_message_util_send_chat_state (G_OBJECT (self), + GABBLE_CONNECTION (base_conn), + WOCKY_STANZA_SUB_TYPE_CHAT, state, priv->peer_jid, error); } static void diff --git a/src/im-channel.h b/src/im-channel.h index fdbae19bf..c09408484 100644 --- a/src/im-channel.h +++ b/src/im-channel.h @@ -24,9 +24,8 @@ #include <glib-object.h> #include <time.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/message-mixin.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> G_BEGIN_DECLS @@ -65,6 +64,7 @@ GType gabble_im_channel_get_type (void); GabbleIMChannelClass)) void _gabble_im_channel_receive (GabbleIMChannel *chan, + WockyStanza *message, TpChannelTextMessageType type, const char *from, time_t timestamp, @@ -73,6 +73,9 @@ void _gabble_im_channel_receive (GabbleIMChannel *chan, gint state); void _gabble_im_channel_state_receive (GabbleIMChannel *chan, TpChannelChatState state); +void gabble_im_channel_receive_receipt ( + GabbleIMChannel *self, + const gchar *receipt_id); void _gabble_im_channel_report_delivery ( GabbleIMChannel *self, diff --git a/src/im-factory.c b/src/im-factory.c index 0459c2dc0..4170d1012 100644 --- a/src/im-factory.c +++ b/src/im-factory.c @@ -24,10 +24,8 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_IM @@ -62,6 +60,7 @@ struct _GabbleImFactoryPrivate { GabbleConnection *conn; guint message_cb_id; + guint delivery_report_cb_id; GHashTable *channels; gulong status_changed_id; @@ -258,7 +257,8 @@ im_factory_message_cb ( } else if (body != NULL) { - _gabble_im_channel_receive (chan, msgtype, from, stamp, id, body, state); + _gabble_im_channel_receive (chan, message, msgtype, from, stamp, id, + body, state); } else if (state != -1) { @@ -268,6 +268,42 @@ im_factory_message_cb ( return TRUE; } +/* Signals incoming delivery receipts. http://xmpp.org/extensions/xep-0184.html + */ +static gboolean +im_factory_receipt_cb ( + WockyPorter *porter, + WockyStanza *message, + gpointer user_data) +{ + GabbleImFactory *self = GABBLE_IM_FACTORY (user_data); + WockyNode *received; + const gchar *from, *received_id; + GabbleIMChannel *channel; + + received = wocky_node_get_child_ns (wocky_stanza_get_top_node (message), + "received", NS_RECEIPTS); + g_return_val_if_fail (received != NULL, FALSE); + + received_id = wocky_node_get_attribute (received, "id"); + if (received_id == NULL) + { + STANZA_DEBUG (message, "but *what* did you receive?!"); + return TRUE; + } + + from = wocky_stanza_get_from (message); + channel = get_channel_for_incoming_message (self, from, FALSE); + if (channel == NULL) + { + DEBUG ("no existing channel with '%s'; ignoring receipt", from); + return TRUE; + } + + gabble_im_channel_receive_receipt (channel, received_id); + return TRUE; +} + /** * im_channel_closed_cb: * @@ -281,35 +317,39 @@ im_channel_closed_cb (GabbleIMChannel *chan, gpointer user_data) { GabbleImFactory *self = GABBLE_IM_FACTORY (user_data); GabbleImFactoryPrivate *priv = self->priv; - TpHandle contact_handle; - gboolean really_destroyed; + TpBaseChannel *base = TP_BASE_CHANNEL (chan); + TpHandle contact_handle = tp_base_channel_get_target_handle (base); DEBUG ("%p, channel %p", self, chan); - tp_channel_manager_emit_channel_closed_for_object (self, - (TpExportableChannel *) chan); + if (tp_base_channel_is_registered (base)) + { + tp_channel_manager_emit_channel_closed_for_object (self, + (TpExportableChannel *) chan); + } if (priv->channels != NULL) { - g_object_get (chan, - "handle", &contact_handle, - "channel-destroyed", &really_destroyed, - NULL); - - if (really_destroyed) + if (tp_base_channel_is_destroyed (base)) { DEBUG ("removing channel with handle %u", contact_handle); g_hash_table_remove (priv->channels, GUINT_TO_POINTER (contact_handle)); } - else + else if (tp_base_channel_is_respawning (base)) { - DEBUG ("reopening channel with handle %u due to pending messages", contact_handle); tp_channel_manager_emit_new_channel (self, (TpExportableChannel *) chan, NULL); } + else + { + /* this basically means tp_base_channel_disappear() must + * have been called; this doesn't have any meaning in this + * channel manager. */ + g_assert_not_reached (); + } } } @@ -339,7 +379,7 @@ new_im_channel (GabbleImFactory *fac, g_return_val_if_fail (handle != 0, NULL); if (request_token != NULL) - initiator = conn->self_handle; + initiator = tp_base_connection_get_self_handle (conn); else initiator = handle; @@ -431,6 +471,10 @@ gabble_im_factory_close_all (GabbleImFactory *self) wocky_porter_unregister_handler (porter, self->priv->message_cb_id); self->priv->message_cb_id = 0; + + wocky_porter_unregister_handler (porter, self->priv->delivery_report_cb_id); + self->priv->delivery_report_cb_id = 0; + g_object_unref (porter); } } @@ -517,6 +561,12 @@ porter_available_cb ( WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, WOCKY_PORTER_HANDLER_PRIORITY_MIN, im_factory_message_cb, self, NULL); + self->priv->delivery_report_cb_id = wocky_porter_register_handler_from_anyone (porter, + WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, + WOCKY_PORTER_HANDLER_PRIORITY_MIN, im_factory_receipt_cb, self, + '(', + "received", ':', NS_RECEIPTS, + ')', NULL); g_object_get (conn, "stream-server", &stream_server, NULL); @@ -704,7 +754,7 @@ gabble_im_factory_requestotron (GabbleImFactory *self, if (require_new) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Already chatting with contact #%u in another channel", handle); goto error; } diff --git a/src/jingle-content.c b/src/jingle-content.c deleted file mode 100644 index 4989a3280..000000000 --- a/src/jingle-content.c +++ /dev/null @@ -1,1409 +0,0 @@ -/* - * gabble-jingle-content.c - Source for GabbleJingleContent - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-content.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "connection.h" -#include "debug.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "jingle-transport-iface.h" -#include "jingle-transport-google.h" -#include "jingle-media-rtp.h" -#include "namespaces.h" -#include "gabble-signals-marshal.h" - -/* signal enum */ -enum -{ - READY, - NEW_CANDIDATES, - REMOVED, - NEW_SHARE_CHANNEL, - COMPLETED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_SESSION = 1, - PROP_CONTENT_NS, - PROP_TRANSPORT_NS, - PROP_NAME, - PROP_SENDERS, - PROP_STATE, - PROP_DISPOSITION, - PROP_LOCALLY_CREATED, - LAST_PROPERTY -}; - -struct _GabbleJingleContentPrivate -{ - gchar *name; - gchar *creator; - gboolean created_by_us; - JingleContentState state; - JingleContentSenders senders; - - gchar *content_ns; - gchar *transport_ns; - gchar *disposition; - - GabbleJingleTransportIface *transport; - - /* Whether we've got the codecs (intersection) ready. */ - gboolean media_ready; - - /* Whether we have at least one local candidate. */ - gboolean have_local_candidates; - - guint gtalk4_event_id; - guint last_share_channel_component_id; - - gboolean dispose_has_run; -}; - -#define DEFAULT_CONTENT_TIMEOUT 60000 - -/* lookup tables */ - -G_DEFINE_TYPE(GabbleJingleContent, gabble_jingle_content, G_TYPE_OBJECT); - -static void new_transport_candidates_cb (GabbleJingleTransportIface *trans, - GList *candidates, GabbleJingleContent *content); -static void _maybe_ready (GabbleJingleContent *self); -static void transport_created (GabbleJingleContent *c); - -static void -gabble_jingle_content_init (GabbleJingleContent *obj) -{ - GabbleJingleContentPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_CONTENT, - GabbleJingleContentPrivate); - obj->priv = priv; - - DEBUG ("%p", obj); - - priv->state = JINGLE_CONTENT_STATE_EMPTY; - priv->created_by_us = TRUE; - priv->media_ready = FALSE; - priv->have_local_candidates = FALSE; - priv->gtalk4_event_id = 0; - priv->dispose_has_run = FALSE; - - obj->session = NULL; -} - -static void -gabble_jingle_content_dispose (GObject *object) -{ - GabbleJingleContent *content = GABBLE_JINGLE_CONTENT (object); - GabbleJingleContentPrivate *priv = content->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("%p", object); - priv->dispose_has_run = TRUE; - - if (priv->gtalk4_event_id != 0) - { - g_source_remove (priv->gtalk4_event_id); - priv->gtalk4_event_id = 0; - } - - g_free (priv->name); - priv->name = NULL; - - g_free (priv->creator); - priv->creator = NULL; - - g_free (priv->content_ns); - priv->content_ns = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - g_free (priv->disposition); - priv->disposition = NULL; - - if (G_OBJECT_CLASS (gabble_jingle_content_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_content_parent_class)->dispose (object); -} - -static void -gabble_jingle_content_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleContent *self = GABBLE_JINGLE_CONTENT (object); - GabbleJingleContentPrivate *priv = self->priv; - - switch (property_id) { - case PROP_SESSION: - g_value_set_object (value, self->session); - break; - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_SENDERS: - g_value_set_uint (value, priv->senders); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_CONTENT_NS: - g_value_set_string (value, priv->content_ns); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_DISPOSITION: - g_value_set_string (value, priv->disposition); - break; - case PROP_LOCALLY_CREATED: - g_value_set_boolean (value, priv->created_by_us); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_content_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleContent *self = GABBLE_JINGLE_CONTENT (object); - GabbleJingleContentPrivate *priv = self->priv; - - switch (property_id) { - case PROP_SESSION: - self->session = g_value_get_object (value); - break; - case PROP_CONTENT_NS: - g_free (priv->content_ns); - priv->content_ns = g_value_dup_string (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - - /* We can't switch transports. */ - g_assert (priv->transport == NULL); - - if (priv->transport_ns != NULL) - { - GType transport_type = gabble_jingle_factory_lookup_transport ( - gabble_jingle_session_get_factory (self->session), - priv->transport_ns); - - g_assert (transport_type != 0); - - priv->transport = gabble_jingle_transport_iface_new (transport_type, - self, priv->transport_ns); - - g_signal_connect (priv->transport, "new-candidates", - (GCallback) new_transport_candidates_cb, self); - - transport_created (self); - } - break; - case PROP_NAME: - /* can't rename */ - g_assert (priv->name == NULL); - - priv->name = g_value_dup_string (value); - break; - case PROP_SENDERS: - priv->senders = g_value_get_uint (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - case PROP_DISPOSITION: - g_assert (priv->disposition == NULL); - priv->disposition = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static JingleContentSenders -get_default_senders_real (GabbleJingleContent *c) -{ - return JINGLE_CONTENT_SENDERS_BOTH; -} - - -static void -gabble_jingle_content_class_init (GabbleJingleContentClass *cls) -{ - GParamSpec *param_spec; - GObjectClass *object_class = G_OBJECT_CLASS (cls); - - g_type_class_add_private (cls, sizeof (GabbleJingleContentPrivate)); - - object_class->get_property = gabble_jingle_content_get_property; - object_class->set_property = gabble_jingle_content_set_property; - object_class->dispose = gabble_jingle_content_dispose; - - cls->get_default_senders = get_default_senders_real; - - /* property definitions */ - param_spec = g_param_spec_object ("session", "GabbleJingleSession object", - "Jingle session object that owns this content.", - GABBLE_TYPE_JINGLE_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SESSION, param_spec); - - param_spec = g_param_spec_string ("name", "Content name", - "A unique content name in the session.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAME, param_spec); - - param_spec = g_param_spec_string ("content-ns", "Content namespace", - "Namespace identifying the content type.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONTENT_NS, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("senders", "Stream senders", - "Valid senders for the stream.", - 0, G_MAXUINT32, JINGLE_CONTENT_SENDERS_NONE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SENDERS, param_spec); - - param_spec = g_param_spec_uint ("state", "Content state", - "The current state that the content is in.", - 0, G_MAXUINT32, JINGLE_CONTENT_STATE_EMPTY, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - param_spec = g_param_spec_string ("disposition", "Content disposition", - "Distinguishes between 'session' and other contents.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DISPOSITION, param_spec); - - param_spec = g_param_spec_boolean ("locally-created", "Locally created", - "True if the content was created by the local client.", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCALLY_CREATED, param_spec); - - /* signal definitions */ - - signals[READY] = g_signal_new ("ready", - G_OBJECT_CLASS_TYPE (cls), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[NEW_SHARE_CHANNEL] = g_signal_new ( - "new-share-channel", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - gabble_marshal_VOID__STRING_UINT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, G_TYPE_UINT); - - signals[COMPLETED] = g_signal_new ( - "completed", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - /* This signal serves as notification that the GabbleJingleContent is now - * meaningless; everything holding a reference should drop it after receiving - * 'removed'. - */ - signals[REMOVED] = g_signal_new ("removed", - G_OBJECT_CLASS_TYPE (cls), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - - -static JingleContentSenders -get_default_senders (GabbleJingleContent *c) -{ - JingleContentSenders (*virtual_method)(GabbleJingleContent *) = \ - GABBLE_JINGLE_CONTENT_GET_CLASS (c)->get_default_senders; - - g_assert (virtual_method != NULL); - return virtual_method (c); -} - - -static JingleContentSenders -parse_senders (const gchar *txt) -{ - if (txt == NULL) - return JINGLE_CONTENT_SENDERS_NONE; - - if (!wocky_strdiff (txt, "initiator")) - return JINGLE_CONTENT_SENDERS_INITIATOR; - else if (!wocky_strdiff (txt, "responder")) - return JINGLE_CONTENT_SENDERS_RESPONDER; - else if (!wocky_strdiff (txt, "both")) - return JINGLE_CONTENT_SENDERS_BOTH; - - return JINGLE_CONTENT_SENDERS_NONE; -} - -static const gchar * -produce_senders (JingleContentSenders senders) -{ - switch (senders) { - case JINGLE_CONTENT_SENDERS_INITIATOR: - return "initiator"; - case JINGLE_CONTENT_SENDERS_RESPONDER: - return "responder"; - case JINGLE_CONTENT_SENDERS_BOTH: - return "both"; - default: - DEBUG ("invalid content senders %u", senders); - g_assert_not_reached (); - } - - /* to make gcc not complain */ - return NULL; -} - - -#define SET_BAD_REQ(txt) \ - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, txt) - -static void -new_transport_candidates_cb (GabbleJingleTransportIface *trans, - GList *candidates, GabbleJingleContent *content) -{ - /* just pass the signal on */ - g_signal_emit (content, signals[NEW_CANDIDATES], 0, candidates); -} - -static void -transport_created (GabbleJingleContent *c) -{ - void (*virtual_method)(GabbleJingleContent *, GabbleJingleTransportIface *) = \ - GABBLE_JINGLE_CONTENT_GET_CLASS (c)->transport_created; - - if (virtual_method != NULL) - virtual_method (c, c->priv->transport); -} - - -static void -parse_description (GabbleJingleContent *c, WockyNode *desc_node, - GError **error) -{ - void (*virtual_method)(GabbleJingleContent *, WockyNode *, - GError **) = GABBLE_JINGLE_CONTENT_GET_CLASS (c)->parse_description; - - g_assert (virtual_method != NULL); - virtual_method (c, desc_node, error); -} - -static gboolean -send_gtalk4_transport_accept (gpointer user_data) -{ - GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (user_data); - GabbleJingleContentPrivate *priv = c->priv; - WockyNode *sess_node, *tnode; - WockyStanza *msg = gabble_jingle_session_new_message (c->session, - JINGLE_ACTION_TRANSPORT_ACCEPT, &sess_node); - - DEBUG ("Sending Gtalk4 'transport-accept' message to peer"); - tnode = wocky_node_add_child_with_content (sess_node, "transport", NULL); - tnode->ns = g_quark_from_string (priv->transport_ns); - - gabble_jingle_session_send (c->session, msg); - - return FALSE; -} - -void -gabble_jingle_content_parse_add (GabbleJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error) -{ - GabbleJingleContentPrivate *priv = c->priv; - const gchar *name, *creator, *senders, *disposition; - WockyNode *trans_node, *desc_node; - GType transport_type = 0; - GabbleJingleTransportIface *trans = NULL; - JingleDialect dialect = gabble_jingle_session_get_dialect (c->session); - - priv->created_by_us = FALSE; - - desc_node = wocky_node_get_child (content_node, "description"); - trans_node = wocky_node_get_child (content_node, "transport"); - creator = wocky_node_get_attribute (content_node, "creator"); - name = wocky_node_get_attribute (content_node, "name"); - senders = wocky_node_get_attribute (content_node, "senders"); - - g_assert (priv->transport_ns == NULL); - - if (google_mode) - { - if (creator == NULL) - creator = "initiator"; - - /* the google protocols don't give the contents names, so put in a dummy - * value if none was set by the session*/ - if (priv->name == NULL) - name = priv->name = g_strdup ("gtalk"); - else - name = priv->name; - - if (trans_node == NULL) - { - /* gtalk lj0.3 assumes google-p2p transport */ - DEBUG ("detected GTalk3 dialect"); - - dialect = JINGLE_DIALECT_GTALK3; - g_object_set (c->session, "dialect", JINGLE_DIALECT_GTALK3, NULL); - transport_type = gabble_jingle_factory_lookup_transport ( - gabble_jingle_session_get_factory (c->session), - ""); - - /* in practice we do support gtalk-p2p, so this can't happen */ - if (G_UNLIKELY (transport_type == 0)) - { - SET_BAD_REQ ("gtalk-p2p transport unsupported"); - return; - } - - priv->transport_ns = g_strdup (""); - } - } - else - { - if (creator == NULL && - gabble_jingle_session_peer_has_cap (c->session, - QUIRK_GOOGLE_WEBMAIL_CLIENT)) - { - if (gabble_jingle_content_creator_is_initiator (c)) - creator = "initiator"; - else - creator = "responder"; - - DEBUG ("Working around GMail omitting creator=''; assuming '%s'", - creator); - } - - if ((trans_node == NULL) || (creator == NULL) || (name == NULL)) - { - SET_BAD_REQ ("missing required content attributes or elements"); - return; - } - - /* In proper protocols the name comes from the stanza */ - g_assert (priv->name == NULL); - priv->name = g_strdup (name); - } - - /* if we didn't set it to google-p2p implicitly already, detect it */ - if (transport_type == 0) - { - const gchar *ns = wocky_node_get_ns (trans_node); - - transport_type = gabble_jingle_factory_lookup_transport ( - gabble_jingle_session_get_factory (c->session), ns); - - if (transport_type == 0) - { - SET_BAD_REQ ("unsupported content transport"); - return; - } - - priv->transport_ns = g_strdup (ns); - } - - if (senders == NULL) - priv->senders = get_default_senders (c); - else - priv->senders = parse_senders (senders); - - if (priv->senders == JINGLE_CONTENT_SENDERS_NONE) - { - SET_BAD_REQ ("invalid content senders"); - return; - } - - parse_description (c, desc_node, error); - if (*error != NULL) - return; - - disposition = wocky_node_get_attribute (content_node, "disposition"); - if (disposition == NULL) - disposition = "session"; - - if (wocky_strdiff (disposition, priv->disposition)) - { - g_free (priv->disposition); - priv->disposition = g_strdup (disposition); - } - - DEBUG ("content creating new transport type %s", g_type_name (transport_type)); - - trans = gabble_jingle_transport_iface_new (transport_type, - c, priv->transport_ns); - - g_signal_connect (trans, "new-candidates", - (GCallback) new_transport_candidates_cb, c); - - /* Depending on transport, there may be initial candidates specified here */ - if (trans_node != NULL) - { - gabble_jingle_transport_iface_parse_candidates (trans, trans_node, error); - if (*error) - { - g_object_unref (trans); - return; - } - } - - g_assert (priv->transport == NULL); - priv->transport = trans; - transport_created (c); - - g_assert (priv->creator == NULL); - priv->creator = g_strdup (creator); - - priv->state = JINGLE_CONTENT_STATE_NEW; - - /* GTalk4 seems to require "transport-accept" for acknowledging - * the transport type. wjt confirms that this is apparently necessary for - * incoming calls to work. - */ - if (dialect == JINGLE_DIALECT_GTALK4) - priv->gtalk4_event_id = g_idle_add (send_gtalk4_transport_accept, c); - - return; -} - -static guint -new_share_channel (GabbleJingleContent *c, const gchar *name) -{ - GabbleJingleContentPrivate *priv = c->priv; - GabbleJingleTransportGoogle *gtrans = NULL; - - if (priv->transport && - GABBLE_IS_JINGLE_TRANSPORT_GOOGLE (priv->transport)) - { - guint id = priv->last_share_channel_component_id + 1; - - gtrans = GABBLE_JINGLE_TRANSPORT_GOOGLE (priv->transport); - - if (!jingle_transport_google_set_component_name (gtrans, name, id)) - return 0; - - priv->last_share_channel_component_id++; - - DEBUG ("New Share channel '%s' with id : %d", name, id); - - g_signal_emit (c, signals[NEW_SHARE_CHANNEL], 0, name, id); - - return priv->last_share_channel_component_id; - } - return 0; -} - -guint -gabble_jingle_content_create_share_channel (GabbleJingleContent *self, - const gchar *name) -{ - GabbleJingleContentPrivate *priv = self->priv; - WockyNode *sess_node, *channel_node; - WockyStanza *msg = NULL; - - /* Send the info action before creating the channel, in case candidates need - to be sent on the signal emit. It doesn't matter if the channel already - exists anyways... */ - msg = gabble_jingle_session_new_message (self->session, - JINGLE_ACTION_INFO, &sess_node); - - DEBUG ("Sending 'info' message to peer : channel %s", name); - channel_node = wocky_node_add_child_with_content (sess_node, "channel", NULL); - channel_node->ns = g_quark_from_string (priv->content_ns); - wocky_node_set_attribute (channel_node, "name", name); - - gabble_jingle_session_send (self->session, msg); - - return new_share_channel (self, name); -} - -void -gabble_jingle_content_send_complete (GabbleJingleContent *self) -{ - GabbleJingleContentPrivate *priv = self->priv; - WockyNode *sess_node, *complete_node; - WockyStanza *msg = NULL; - - msg = gabble_jingle_session_new_message (self->session, - JINGLE_ACTION_INFO, &sess_node); - - DEBUG ("Sending 'info' message to peer : complete"); - complete_node = wocky_node_add_child_with_content (sess_node, "complete", NULL); - complete_node->ns = g_quark_from_string (priv->content_ns); - - gabble_jingle_session_send (self->session, msg); - -} - -void -gabble_jingle_content_parse_info (GabbleJingleContent *c, - WockyNode *content_node, GError **error) -{ - WockyNode *channel_node; - WockyNode *complete_node; - - channel_node = wocky_node_get_child (content_node, "channel"); - complete_node = wocky_node_get_child (content_node, "complete"); - - DEBUG ("parsing info message : %p - %p", channel_node, complete_node); - if (channel_node) - { - const gchar *name; - name = wocky_node_get_attribute (channel_node, "name"); - if (name != NULL) - new_share_channel (c, name); - } - else if (complete_node) - { - g_signal_emit (c, signals[COMPLETED], 0); - } - -} - -void -gabble_jingle_content_parse_accept (GabbleJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error) -{ - GabbleJingleContentPrivate *priv = c->priv; - const gchar *senders; - WockyNode *trans_node, *desc_node; - JingleDialect dialect = gabble_jingle_session_get_dialect (c->session); - JingleContentSenders newsenders; - - desc_node = wocky_node_get_child (content_node, "description"); - trans_node = wocky_node_get_child (content_node, "transport"); - senders = wocky_node_get_attribute (content_node, "senders"); - - if (GABBLE_IS_JINGLE_MEDIA_RTP (c) && - JINGLE_IS_GOOGLE_DIALECT (dialect) && trans_node == NULL) - { - DEBUG ("no transport node, assuming GTalk3 dialect"); - /* gtalk lj0.3 assumes google-p2p transport */ - g_object_set (c->session, "dialect", JINGLE_DIALECT_GTALK3, NULL); - } - - if (senders == NULL) - newsenders = get_default_senders (c); - else - newsenders = parse_senders (senders); - - if (newsenders == JINGLE_CONTENT_SENDERS_NONE) - { - SET_BAD_REQ ("invalid content senders"); - return; - } - - if (newsenders != priv->senders) - { - DEBUG ("changing senders from %s to %s", produce_senders (priv->senders), - produce_senders (newsenders)); - priv->senders = newsenders; - g_object_notify ((GObject *) c, "senders"); - } - - parse_description (c, desc_node, error); - if (*error != NULL) - return; - - priv->state = JINGLE_CONTENT_STATE_ACKNOWLEDGED; - g_object_notify ((GObject *) c, "state"); - - if (trans_node != NULL) - { - gabble_jingle_transport_iface_parse_candidates (priv->transport, - trans_node, NULL); - } -} - -void -gabble_jingle_content_parse_description_info (GabbleJingleContent *c, - WockyNode *content_node, GError **error) -{ - GabbleJingleContentPrivate *priv = c->priv; - WockyNode *desc_node; - desc_node = wocky_node_get_child (content_node, "description"); - if (desc_node == NULL) - { - SET_BAD_REQ ("invalid description-info action"); - return; - } - - if (priv->created_by_us && priv->state < JINGLE_CONTENT_STATE_ACKNOWLEDGED) - { - /* The stream was created by us and the other side didn't acknowledge it - * yet, thus we don't have their codec information, thus the - * description-info isn't meaningful and can be ignored */ - DEBUG ("Ignoring description-info as we didn't receive the codecs yet"); - return; - } - - parse_description (c, desc_node, error); -} - - -void -gabble_jingle_content_produce_node (GabbleJingleContent *c, - WockyNode *parent, - gboolean include_description, - gboolean include_transport, - WockyNode **trans_node_out) -{ - GabbleJingleContentPrivate *priv = c->priv; - WockyNode *content_node, *trans_node; - JingleDialect dialect = gabble_jingle_session_get_dialect (c->session); - void (*produce_desc)(GabbleJingleContent *, WockyNode *) = - GABBLE_JINGLE_CONTENT_GET_CLASS (c)->produce_description; - - if ((dialect == JINGLE_DIALECT_GTALK3) || - (dialect == JINGLE_DIALECT_GTALK4)) - { - content_node = parent; - } - else - { - content_node = wocky_node_add_child_with_content (parent, "content", NULL); - wocky_node_set_attributes (content_node, - "name", priv->name, - "senders", produce_senders (priv->senders), - NULL); - - if (gabble_jingle_content_creator_is_initiator (c)) - wocky_node_set_attribute (content_node, "creator", "initiator"); - else - wocky_node_set_attribute (content_node, "creator", "responder"); - } - - if (include_description) - produce_desc (c, content_node); - - if (include_transport) - { - if (dialect == JINGLE_DIALECT_GTALK3) - { - /* GTalk 03 doesn't use a transport, but assumes gtalk-p2p */ - trans_node = parent; - } - else - { - trans_node = wocky_node_add_child_with_content (content_node, "transport", NULL); - trans_node->ns = g_quark_from_string (priv->transport_ns); - } - - if (trans_node_out != NULL) - *trans_node_out = trans_node; - } -} - -void -gabble_jingle_content_update_senders (GabbleJingleContent *c, - WockyNode *content_node, GError **error) -{ - GabbleJingleContentPrivate *priv = c->priv; - JingleContentSenders senders; - - senders = parse_senders (wocky_node_get_attribute (content_node, "senders")); - - if (senders == JINGLE_CONTENT_SENDERS_NONE) - { - SET_BAD_REQ ("invalid content senders in stream"); - return; - } - - priv->senders = senders; - g_object_notify ((GObject *) c, "senders"); -} - -void -gabble_jingle_content_parse_transport_info (GabbleJingleContent *self, - WockyNode *trans_node, GError **error) -{ - GabbleJingleContentPrivate *priv = self->priv; - - gabble_jingle_transport_iface_parse_candidates (priv->transport, trans_node, error); -} - -/* Takes in a list of slice-allocated JingleCandidate structs */ -void -gabble_jingle_content_add_candidates (GabbleJingleContent *self, GList *li) -{ - GabbleJingleContentPrivate *priv = self->priv; - - DEBUG ("called content: %s created_by_us: %d", priv->name, - priv->created_by_us); - - if (li == NULL) - return; - - gabble_jingle_transport_iface_new_local_candidates (priv->transport, li); - - if (!priv->have_local_candidates) - { - priv->have_local_candidates = TRUE; - /* Maybe we were waiting for at least one candidate? */ - _maybe_ready (self); - } - - /* If the content exists on the wire, let the transport send this candidate - * if it wants to. - */ - if (priv->state > JINGLE_CONTENT_STATE_EMPTY) - gabble_jingle_transport_iface_send_candidates (priv->transport, FALSE); -} - -/* Returns whether the content is ready to be signalled (initiated, for local - * streams, or acknowledged, for remote streams. */ -gboolean -gabble_jingle_content_is_ready (GabbleJingleContent *self) -{ - GabbleJingleContentPrivate *priv = self->priv; - - if (priv->created_by_us) - { - /* If it's created by us, media ready, not signalled, and we have - * at least one local candidate, it's ready to be added. */ - if (priv->media_ready && priv->state == JINGLE_CONTENT_STATE_EMPTY && - (!GABBLE_IS_JINGLE_MEDIA_RTP (self) || priv->have_local_candidates)) - return TRUE; - } - else - { - /* If it's created by peer, media and transports ready, - * and not acknowledged yet, it's ready for acceptance. */ - if (priv->media_ready && priv->state == JINGLE_CONTENT_STATE_NEW && - (!GABBLE_IS_JINGLE_MEDIA_RTP (self) || - gabble_jingle_transport_iface_can_accept (priv->transport))) - return TRUE; - } - - return FALSE; -} - -static void -send_content_add_or_accept (GabbleJingleContent *self) -{ - GabbleJingleContentPrivate *priv = self->priv; - WockyStanza *msg; - WockyNode *sess_node, *transport_node; - JingleAction action; - JingleContentState new_state = JINGLE_CONTENT_STATE_EMPTY; - - g_assert (gabble_jingle_content_is_ready (self)); - - if (priv->created_by_us) - { - /* TODO: set a timer for acknowledgement */ - action = JINGLE_ACTION_CONTENT_ADD; - new_state = JINGLE_CONTENT_STATE_SENT; - } - else - { - action = JINGLE_ACTION_CONTENT_ACCEPT; - new_state = JINGLE_CONTENT_STATE_ACKNOWLEDGED; - } - - msg = gabble_jingle_session_new_message (self->session, - action, &sess_node); - gabble_jingle_content_produce_node (self, sess_node, TRUE, TRUE, - &transport_node); - gabble_jingle_transport_iface_inject_candidates (priv->transport, - transport_node); - gabble_jingle_session_send (self->session, msg); - - priv->state = new_state; - g_object_notify (G_OBJECT (self), "state"); -} - -static void -_maybe_ready (GabbleJingleContent *self) -{ - GabbleJingleContentPrivate *priv = self->priv; - JingleState state; - - if (!gabble_jingle_content_is_ready (self)) - return; - - /* If content disposition is session and session - * is not yet acknowledged/active, we signall - * the readiness to the session and let it take - * care of it. Otherwise, we can deal with it - * ourselves. */ - - g_object_get (self->session, "state", &state, NULL); - - if (!wocky_strdiff (priv->disposition, "session") && - (state < JINGLE_STATE_PENDING_ACCEPT_SENT)) - { - /* Notify the session that we're ready for - * session-initiate/session-accept */ - g_signal_emit (self, signals[READY], 0); - } - else - { - if (state >= JINGLE_STATE_PENDING_INITIATE_SENT) - { - send_content_add_or_accept (self); - - /* if neccessary, transmit the candidates */ - gabble_jingle_transport_iface_send_candidates (priv->transport, - FALSE); - } - else - { - /* non session-disposition content ready without session - * being initiated at all? */ - DEBUG ("session not initiated yet, ignoring non-session ready content"); - return; - } - } -} - -void -gabble_jingle_content_maybe_send_description (GabbleJingleContent *self) -{ - GabbleJingleContentPrivate *priv = self->priv; - - /* If we didn't send the content yet there is no reason to send a - * description-info to update it */ - if (priv->state < JINGLE_CONTENT_STATE_SENT) - return; - - if (gabble_jingle_session_defines_action (self->session, - JINGLE_ACTION_DESCRIPTION_INFO)) - { - WockyNode *sess_node; - WockyStanza *msg = gabble_jingle_session_new_message (self->session, - JINGLE_ACTION_DESCRIPTION_INFO, &sess_node); - - gabble_jingle_content_produce_node (self, sess_node, TRUE, FALSE, NULL); - gabble_jingle_session_send (self->session, msg); - } - else - { - DEBUG ("not sending description-info, speaking an old dialect"); - } -} - - -/* Used when session-initiate is sent (so all initial contents transmit their - * candidates), and when we detect gtalk3 after we've transmitted some - * candidates. */ -void -gabble_jingle_content_retransmit_candidates (GabbleJingleContent *self, - gboolean all) -{ - gabble_jingle_transport_iface_send_candidates (self->priv->transport, all); -} - -void -gabble_jingle_content_inject_candidates (GabbleJingleContent *self, - WockyNode *transport_node) -{ - gabble_jingle_transport_iface_inject_candidates (self->priv->transport, - transport_node); -} - - -/* Called by a subclass when the media is ready (e.g. we got local codecs) */ -void -_gabble_jingle_content_set_media_ready (GabbleJingleContent *self) -{ - GabbleJingleContentPrivate *priv = self->priv; - - DEBUG ("media ready on content: %s created_by_us: %d", priv->name, - priv->created_by_us); - - priv->media_ready = TRUE; - - _maybe_ready (self); -} - -void -gabble_jingle_content_set_transport_state (GabbleJingleContent *self, - JingleTransportState state) -{ - GabbleJingleContentPrivate *priv = self->priv; - - g_object_set (priv->transport, "state", state, NULL); - - _maybe_ready (self); -} - -GList * -gabble_jingle_content_get_remote_candidates (GabbleJingleContent *c) -{ - GabbleJingleContentPrivate *priv = c->priv; - - return gabble_jingle_transport_iface_get_remote_candidates (priv->transport); -} - -GList * -gabble_jingle_content_get_local_candidates (GabbleJingleContent *c) -{ - GabbleJingleContentPrivate *priv = c->priv; - - return gabble_jingle_transport_iface_get_local_candidates (priv->transport); -} - -gboolean -gabble_jingle_content_get_credentials (GabbleJingleContent *c, - gchar **ufrag, gchar **pwd) -{ - GabbleJingleContentPrivate *priv = c->priv; - - return jingle_transport_get_credentials (priv->transport, ufrag, pwd); -} - -gboolean -gabble_jingle_content_change_direction (GabbleJingleContent *c, - JingleContentSenders senders) -{ - GabbleJingleContentPrivate *priv = c->priv; - WockyStanza *msg; - WockyNode *sess_node; - JingleDialect dialect = gabble_jingle_session_get_dialect (c->session); - - if (senders == priv->senders) - return TRUE; - - priv->senders = senders; - g_object_notify (G_OBJECT (c), "senders"); - - if (JINGLE_IS_GOOGLE_DIALECT (dialect)) - { - DEBUG ("ignoring direction change request for GTalk stream"); - return FALSE; - } - - if (priv->state >= JINGLE_CONTENT_STATE_SENT) - { - msg = gabble_jingle_session_new_message (c->session, - JINGLE_ACTION_CONTENT_MODIFY, &sess_node); - gabble_jingle_content_produce_node (c, sess_node, FALSE, FALSE, NULL); - gabble_jingle_session_send (c->session, msg); - } - - /* FIXME: actually check whether remote end accepts our content-modify */ - return TRUE; -} - -static void -_on_remove_reply ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (user_data); - GabbleJingleContentPrivate *priv = c->priv; - - g_assert (priv->state == JINGLE_CONTENT_STATE_REMOVING); - - DEBUG ("%p", c); - - /* Everything holding a reference to a content should drop it after receiving - * 'removed'. - */ - g_signal_emit (c, signals[REMOVED], 0); - g_object_unref (c); -} - -static void -_content_remove (GabbleJingleContent *c, - gboolean signal_peer, - JingleReason reason) -{ - GabbleJingleContentPrivate *priv = c->priv; - WockyStanza *msg; - WockyNode *sess_node; - - DEBUG ("called for %p (%s)", c, priv->name); - - /* If we were already signalled and removal is not a side-effect of - * something else (sesssion termination, or removal by peer), - * we have to signal removal to the peer. */ - if (signal_peer && (priv->state != JINGLE_CONTENT_STATE_EMPTY)) - { - if (priv->state == JINGLE_CONTENT_STATE_REMOVING) - { - DEBUG ("ignoring request to remove content which is already being removed"); - return; - } - - priv->state = JINGLE_CONTENT_STATE_REMOVING; - g_object_notify ((GObject *) c, "state"); - - msg = gabble_jingle_session_new_message (c->session, - reason == JINGLE_REASON_UNKNOWN ? - JINGLE_ACTION_CONTENT_REMOVE : JINGLE_ACTION_CONTENT_REJECT, - &sess_node); - - if (reason != JINGLE_REASON_UNKNOWN) - { - WockyNode *reason_node = wocky_node_add_child_with_content (sess_node, - "reason", NULL); - wocky_node_add_child_with_content (reason_node, - gabble_jingle_session_get_reason_name (reason), NULL); - } - - gabble_jingle_content_produce_node (c, sess_node, FALSE, FALSE, NULL); - wocky_porter_send_iq_async (gabble_jingle_session_get_porter (c->session), - msg, NULL, _on_remove_reply, g_object_ref (c)); - g_object_unref (msg); - } - else - { - DEBUG ("signalling removed with %u refs", G_OBJECT (c)->ref_count); - /* Everything holding a reference to a content should drop it after receiving - * 'removed'. - */ - g_signal_emit (c, signals[REMOVED], 0); - } -} - -void -gabble_jingle_content_remove (GabbleJingleContent *c, - gboolean signal_peer) -{ - _content_remove (c, signal_peer, JINGLE_REASON_UNKNOWN); -} - -void -gabble_jingle_content_reject (GabbleJingleContent *c, - JingleReason reason) -{ - _content_remove (c, TRUE, reason); -} - -gboolean -gabble_jingle_content_is_created_by_us (GabbleJingleContent *c) -{ - return c->priv->created_by_us; -} - -gboolean -gabble_jingle_content_creator_is_initiator (GabbleJingleContent *c) -{ - gboolean session_created_by_us; - - g_object_get (c->session, "local-initiator", &session_created_by_us, NULL); - - return (c->priv->created_by_us == session_created_by_us); -} - -const gchar * -gabble_jingle_content_get_name (GabbleJingleContent *self) -{ - return self->priv->name; -} - -const gchar * -gabble_jingle_content_get_ns (GabbleJingleContent *self) -{ - return self->priv->content_ns; -} - -const gchar * -gabble_jingle_content_get_transport_ns (GabbleJingleContent *self) -{ - return self->priv->transport_ns; -} - -const gchar * -gabble_jingle_content_get_disposition (GabbleJingleContent *self) -{ - return self->priv->disposition; -} - -JingleTransportType -gabble_jingle_content_get_transport_type (GabbleJingleContent *c) -{ - return gabble_jingle_transport_iface_get_transport_type (c->priv->transport); -} - -static gboolean -jingle_content_has_direction (GabbleJingleContent *self, - gboolean sending) -{ - GabbleJingleContentPrivate *priv = self->priv; - gboolean initiated_by_us; - - g_object_get (self->session, "local-initiator", - &initiated_by_us, NULL); - - switch (priv->senders) - { - case JINGLE_CONTENT_SENDERS_BOTH: - return TRUE; - case JINGLE_CONTENT_SENDERS_NONE: - return FALSE; - case JINGLE_CONTENT_SENDERS_INITIATOR: - return sending ? initiated_by_us : !initiated_by_us; - case JINGLE_CONTENT_SENDERS_RESPONDER: - return sending ? !initiated_by_us : initiated_by_us; - } - - return FALSE; -} - -gboolean -gabble_jingle_content_sending (GabbleJingleContent *self) -{ - return jingle_content_has_direction (self, TRUE); -} - -gboolean -gabble_jingle_content_receiving (GabbleJingleContent *self) -{ - return jingle_content_has_direction (self, FALSE); -} - -void -gabble_jingle_content_set_sending (GabbleJingleContent *self, - gboolean send) -{ - GabbleJingleContentPrivate *priv = self->priv; - JingleContentSenders senders; - gboolean initiated_by_us; - - if (send == gabble_jingle_content_sending (self)) - return; - - g_object_get (self->session, "local-initiator", - &initiated_by_us, NULL); - - if (send) - { - if (priv->senders == JINGLE_CONTENT_SENDERS_NONE) - senders = (initiated_by_us ? JINGLE_CONTENT_SENDERS_INITIATOR : - JINGLE_CONTENT_SENDERS_RESPONDER); - else - senders = JINGLE_CONTENT_SENDERS_BOTH; - } - else - { - if (priv->senders == JINGLE_CONTENT_SENDERS_BOTH) - senders = (initiated_by_us ? JINGLE_CONTENT_SENDERS_RESPONDER : - JINGLE_CONTENT_SENDERS_INITIATOR); - else - senders = JINGLE_CONTENT_SENDERS_NONE; - } - - if (senders == JINGLE_CONTENT_SENDERS_NONE) - gabble_jingle_content_remove (self, TRUE); - else - gabble_jingle_content_change_direction (self, senders); -} - - -void -gabble_jingle_content_request_receiving (GabbleJingleContent *self, - gboolean receive) -{ - GabbleJingleContentPrivate *priv = self->priv; - JingleContentSenders senders; - gboolean initiated_by_us; - - if (receive == gabble_jingle_content_receiving (self)) - return; - - g_object_get (self->session, "local-initiator", - &initiated_by_us, NULL); - - if (receive) - { - if (priv->senders == JINGLE_CONTENT_SENDERS_NONE) - senders = (initiated_by_us ? JINGLE_CONTENT_SENDERS_RESPONDER : - JINGLE_CONTENT_SENDERS_INITIATOR); - else - senders = JINGLE_CONTENT_SENDERS_BOTH; - } - else - { - if (priv->senders == JINGLE_CONTENT_SENDERS_BOTH) - senders = (initiated_by_us ? JINGLE_CONTENT_SENDERS_INITIATOR : - JINGLE_CONTENT_SENDERS_RESPONDER); - else - senders = JINGLE_CONTENT_SENDERS_NONE; - } - - - if (senders == JINGLE_CONTENT_SENDERS_NONE) - gabble_jingle_content_remove (self, TRUE); - else - gabble_jingle_content_change_direction (self, senders); -} diff --git a/src/jingle-content.h b/src/jingle-content.h deleted file mode 100644 index 1c337efb5..000000000 --- a/src/jingle-content.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * jingle-content.h - Header for GabbleJingleContent - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_CONTENT_H__ -#define __JINGLE_CONTENT_H__ - -#include <glib-object.h> - -#include "jingle-factory.h" -#include "jingle-transport-iface.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef enum { - JINGLE_MEDIA_TYPE_NONE = 0, - JINGLE_MEDIA_TYPE_AUDIO, - JINGLE_MEDIA_TYPE_VIDEO, -} JingleMediaType; - -typedef enum { - JINGLE_CONTENT_STATE_EMPTY = 0, - JINGLE_CONTENT_STATE_NEW, - JINGLE_CONTENT_STATE_SENT, - JINGLE_CONTENT_STATE_ACKNOWLEDGED, - JINGLE_CONTENT_STATE_REMOVING -} JingleContentState; - -struct _JingleCandidate { - JingleTransportProtocol protocol; - JingleCandidateType type; - - gchar *id; - gchar *address; - int port; - int component; - int generation; - - int preference; - gchar *username; - gchar *password; - int network; -}; - -typedef struct _GabbleJingleContentClass GabbleJingleContentClass; - -GType gabble_jingle_content_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_CONTENT \ - (gabble_jingle_content_get_type ()) -#define GABBLE_JINGLE_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_CONTENT, \ - GabbleJingleContent)) -#define GABBLE_JINGLE_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_CONTENT, \ - GabbleJingleContentClass)) -#define GABBLE_IS_JINGLE_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_CONTENT)) -#define GABBLE_IS_JINGLE_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_CONTENT)) -#define GABBLE_JINGLE_CONTENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_CONTENT, \ - GabbleJingleContentClass)) - -struct _GabbleJingleContentClass { - GObjectClass parent_class; - - void (*parse_description) (GabbleJingleContent *, WockyNode *, - GError **); - void (*produce_description) (GabbleJingleContent *, WockyNode *); - void (*transport_created) (GabbleJingleContent *, - GabbleJingleTransportIface *); - JingleContentSenders (*get_default_senders) (GabbleJingleContent *); -}; - -typedef struct _GabbleJingleContentPrivate GabbleJingleContentPrivate; - -struct _GabbleJingleContent { - GObject parent; - GabbleJingleContentPrivate *priv; - - GabbleJingleSession *session; -}; - -void gabble_jingle_content_parse_add (GabbleJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error); -void gabble_jingle_content_update_senders (GabbleJingleContent *c, - WockyNode *content_node, GError **error); -void gabble_jingle_content_produce_node (GabbleJingleContent *c, - WockyNode *parent, - gboolean include_description, - gboolean include_transport, - WockyNode **trans_node_out); -void gabble_jingle_content_parse_accept (GabbleJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error); - -void gabble_jingle_content_parse_info (GabbleJingleContent *c, - WockyNode *content_node, GError **error); -void gabble_jingle_content_parse_transport_info (GabbleJingleContent *self, - WockyNode *trans_node, GError **error); -void gabble_jingle_content_parse_description_info (GabbleJingleContent *self, - WockyNode *trans_node, GError **error); -guint gabble_jingle_content_create_share_channel (GabbleJingleContent *self, - const gchar *name); -void gabble_jingle_content_add_candidates (GabbleJingleContent *self, GList *li); -void _gabble_jingle_content_set_media_ready (GabbleJingleContent *self); -gboolean gabble_jingle_content_is_ready (GabbleJingleContent *self); -void gabble_jingle_content_set_transport_state (GabbleJingleContent *content, - JingleTransportState state); -void gabble_jingle_content_remove (GabbleJingleContent *c, gboolean signal_peer); -void gabble_jingle_content_reject (GabbleJingleContent *c, - JingleReason reason); - -GList *gabble_jingle_content_get_remote_candidates (GabbleJingleContent *c); -GList *gabble_jingle_content_get_local_candidates (GabbleJingleContent *c); -gboolean gabble_jingle_content_get_credentials (GabbleJingleContent *c, - gchar **ufrag, gchar **pwd); -gboolean gabble_jingle_content_change_direction (GabbleJingleContent *c, - JingleContentSenders senders); -void gabble_jingle_content_retransmit_candidates (GabbleJingleContent *self, - gboolean all); -void gabble_jingle_content_inject_candidates (GabbleJingleContent *self, - WockyNode *transport_node); -gboolean gabble_jingle_content_is_created_by_us (GabbleJingleContent *c); -gboolean gabble_jingle_content_creator_is_initiator (GabbleJingleContent *c); - -const gchar *gabble_jingle_content_get_name (GabbleJingleContent *self); -const gchar *gabble_jingle_content_get_ns (GabbleJingleContent *self); -const gchar *gabble_jingle_content_get_disposition (GabbleJingleContent *self); -JingleTransportType gabble_jingle_content_get_transport_type (GabbleJingleContent *c); -const gchar *gabble_jingle_content_get_transport_ns (GabbleJingleContent *self); - -void gabble_jingle_content_maybe_send_description (GabbleJingleContent *self); - -gboolean gabble_jingle_content_sending (GabbleJingleContent *self); -gboolean gabble_jingle_content_receiving (GabbleJingleContent *self); - -void gabble_jingle_content_set_sending (GabbleJingleContent *self, - gboolean send); -void gabble_jingle_content_request_receiving (GabbleJingleContent *self, - gboolean receive); - -void gabble_jingle_content_send_complete (GabbleJingleContent *self); - -#endif /* __JINGLE_CONTENT_H__ */ - diff --git a/src/jingle-factory.c b/src/jingle-factory.c deleted file mode 100644 index 0e9f6f73f..000000000 --- a/src/jingle-factory.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * jingle-factory.c - Support for XEP-0166 (Jingle) - * - * Copyright (C) 2006-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-factory.h" - -#include <stdio.h> -#include <string.h> -#include <glib.h> - -#include <wocky/wocky.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "gabble-signals-marshal.h" -#include "jingle-share.h" -#include "jingle-media-rtp.h" -#include "jingle-session.h" -#include "jingle-transport-google.h" -#include "jingle-transport-rawudp.h" -#include "jingle-transport-iceudp.h" -#include "namespaces.h" - -#include "google-relay.h" - -G_DEFINE_TYPE(GabbleJingleFactory, gabble_jingle_factory, G_TYPE_OBJECT); - -/* signal enum */ -enum -{ - NEW_SESSION, - QUERY_CAP, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_SESSION = 1, - LAST_PROPERTY -}; - -struct _GabbleJingleFactoryPrivate -{ - WockySession *session; - WockyPorter *porter; - guint jingle_handler_id; - GHashTable *content_types; - GHashTable *transports; - - /* instances of SESSION_MAP_KEY_FORMAT => GabbleJingleSession. */ - GHashTable *sessions; - - GabbleJingleInfo *jingle_info; - - gboolean dispose_has_run; -}; - -static gboolean jingle_cb ( - WockyPorter *porter, - WockyStanza *msg, - gpointer user_data); -static GabbleJingleSession *create_session (GabbleJingleFactory *fac, - const gchar *sid, - const gchar *jid, - JingleDialect dialect, - gboolean local_hold); - -static gboolean session_query_cap_cb ( - GabbleJingleSession *session, - WockyContact *contact, - const gchar *cap_or_quirk, - gpointer user_data); -static void session_terminated_cb (GabbleJingleSession *sess, - gboolean local_terminator, - JingleReason reason, - const gchar *text, - GabbleJingleFactory *fac); - -static void attach_to_wocky_session (GabbleJingleFactory *self); - -static void -gabble_jingle_factory_init (GabbleJingleFactory *obj) -{ - GabbleJingleFactoryPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_FACTORY, - GabbleJingleFactoryPrivate); - obj->priv = priv; - - priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - priv->transports = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, NULL); - - priv->content_types = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, NULL); - - priv->dispose_has_run = FALSE; -} - -static void -gabble_jingle_factory_dispose (GObject *object) -{ - GabbleJingleFactory *fac = GABBLE_JINGLE_FACTORY (object); - GabbleJingleFactoryPrivate *priv = fac->priv; - GHashTableIter iter; - gpointer val; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - gabble_jingle_factory_stop (fac); - g_clear_object (&priv->session); - g_clear_object (&priv->porter); - - g_hash_table_iter_init (&iter, priv->sessions); - while (g_hash_table_iter_next (&iter, NULL, &val)) - g_signal_handlers_disconnect_by_func (val, session_query_cap_cb, fac); - g_hash_table_unref (priv->sessions); - priv->sessions = NULL; - - g_hash_table_unref (priv->content_types); - priv->content_types = NULL; - g_hash_table_unref (priv->transports); - priv->transports = NULL; - g_clear_object (&priv->jingle_info); - - if (G_OBJECT_CLASS (gabble_jingle_factory_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_factory_parent_class)->dispose (object); -} - -static void -gabble_jingle_factory_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleFactory *chan = GABBLE_JINGLE_FACTORY (object); - GabbleJingleFactoryPrivate *priv = chan->priv; - - switch (property_id) { - case PROP_SESSION: - g_value_set_object (value, priv->session); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_factory_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleFactory *chan = GABBLE_JINGLE_FACTORY (object); - GabbleJingleFactoryPrivate *priv = chan->priv; - - switch (property_id) { - case PROP_SESSION: - priv->session = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_factory_constructed (GObject *obj) -{ - GabbleJingleFactory *self = GABBLE_JINGLE_FACTORY (obj); - GObjectClass *parent = G_OBJECT_CLASS (gabble_jingle_factory_parent_class); - - if (parent->constructed != NULL) - parent->constructed (obj); - - attach_to_wocky_session (self); - - jingle_share_register (self); - jingle_media_rtp_register (self); - jingle_transport_google_register (self); - jingle_transport_rawudp_register (self); - jingle_transport_iceudp_register (self); -} - -static void -gabble_jingle_factory_class_init (GabbleJingleFactoryClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (GabbleJingleFactoryPrivate)); - - object_class->constructed = gabble_jingle_factory_constructed; - object_class->get_property = gabble_jingle_factory_get_property; - object_class->set_property = gabble_jingle_factory_set_property; - object_class->dispose = gabble_jingle_factory_dispose; - - param_spec = g_param_spec_object ("session", "WockySession object", - "WockySession to listen for Jingle sessions on", - WOCKY_TYPE_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SESSION, param_spec); - - /* signal definitions */ - - /* - * @session: a fresh new Jingle session for your listening pleasure - * @initiated_locally: %TRUE if this is a new outgoing session; %FALSE if it - * is a new incoming session - */ - signals[NEW_SESSION] = g_signal_new ("new-session", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__OBJECT_BOOL, - G_TYPE_NONE, 2, GABBLE_TYPE_JINGLE_SESSION, G_TYPE_BOOLEAN); - - /* - * @contact: the peer in a call - * @cap: the XEP-0115 feature string the session is interested in. - * - * Emitted when a Jingle session wants to check whether the peer has a - * particular capability. The handler should return %TRUE if @contact has - * @cap. - */ - signals[QUERY_CAP] = g_signal_new ("query-cap", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, g_signal_accumulator_first_wins, NULL, - gabble_marshal_BOOLEAN__OBJECT_STRING, - G_TYPE_BOOLEAN, 2, WOCKY_TYPE_CONTACT, G_TYPE_STRING); -} - -GabbleJingleFactory * -gabble_jingle_factory_new ( - WockySession *session) -{ - return g_object_new (GABBLE_TYPE_JINGLE_FACTORY, - "session", session, - NULL); -} - -static void -attach_to_wocky_session (GabbleJingleFactory *self) -{ - GabbleJingleFactoryPrivate *priv = self->priv; - - g_assert (priv->session != NULL); - - g_assert (priv->porter == NULL); - priv->porter = g_object_ref (wocky_session_get_porter (priv->session)); - - /* TODO: we could match different dialects here maybe? */ - priv->jingle_handler_id = wocky_porter_register_handler_from_anyone ( - priv->porter, - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, jingle_cb, self, - NULL); - - priv->jingle_info = gabble_jingle_info_new (priv->porter); -} - -void -gabble_jingle_factory_stop (GabbleJingleFactory *self) -{ - GabbleJingleFactoryPrivate *priv = self->priv; - - if (priv->porter != NULL && - priv->jingle_handler_id != 0) - { - wocky_porter_unregister_handler (priv->porter, priv->jingle_handler_id); - priv->jingle_handler_id = 0; - } -} - -/* The 'session' map is keyed by: - * "<peer's jid>\n<session id>" - */ -#define SESSION_MAP_KEY_FORMAT "%s\n%s" - -static gchar * -make_session_map_key ( - const gchar *jid, - const gchar *sid) -{ - return g_strdup_printf (SESSION_MAP_KEY_FORMAT, jid, sid); -} - -static gchar * -get_unique_sid_for (GabbleJingleFactory *factory, - const gchar *jid, - gchar **key) -{ - guint32 val; - gchar *sid = NULL; - gchar *key_ = NULL; - - do - { - val = g_random_int_range (1000000, G_MAXINT); - - g_free (sid); - g_free (key_); - sid = g_strdup_printf ("%u", val); - key_ = make_session_map_key (jid, sid); - } - while (g_hash_table_lookup (factory->priv->sessions, key_) != NULL); - - *key = key_; - return sid; -} - -static GabbleJingleSession * -ensure_session (GabbleJingleFactory *self, - const gchar *sid, - const gchar *from, - JingleAction action, - JingleDialect dialect, - gboolean *new_session, - GError **error) -{ - GabbleJingleFactoryPrivate *priv = self->priv; - gchar *key; - GabbleJingleSession *sess; - - if (!wocky_decode_jid (from, NULL, NULL, NULL)) - { - g_prefix_error (error, "Couldn't parse sender '%s': ", from); - return NULL; - } - - /* If we can ensure the handle, we can decode the jid */ - key = make_session_map_key (from, sid); - sess = g_hash_table_lookup (priv->sessions, key); - g_free (key); - - if (sess == NULL) - { - if (action == JINGLE_ACTION_SESSION_INITIATE) - { - sess = create_session (self, sid, from, dialect, FALSE); - *new_session = TRUE; - } - else - { - g_set_error (error, WOCKY_XMPP_ERROR, - WOCKY_JINGLE_ERROR_UNKNOWN_SESSION, - "session %s is unknown", sid); - return NULL; - } - } - else - { - *new_session = FALSE; - } - - return sess; -} - -static gboolean -jingle_cb ( - WockyPorter *porter, - WockyStanza *msg, - gpointer user_data) -{ - GabbleJingleFactory *self = GABBLE_JINGLE_FACTORY (user_data); - GError *error = NULL; - const gchar *sid, *from; - GabbleJingleSession *sess; - gboolean new_session = FALSE; - JingleAction action; - JingleDialect dialect; - - /* see if it's a jingle message and detect dialect */ - sid = gabble_jingle_session_detect (msg, &action, &dialect); - from = wocky_stanza_get_from (msg); - - if (sid == NULL || from == NULL) - return FALSE; - - sess = ensure_session (self, sid, from, action, dialect, &new_session, - &error); - - if (sess == NULL) - goto REQUEST_ERROR; - - /* now act on the message */ - if (!gabble_jingle_session_parse (sess, action, msg, &error)) - goto REQUEST_ERROR; - - /* This has to be after the call to parse(), not inside create_session(): - * until the session has parsed the session-initiate stanza, it does not know - * about its own contents, and we don't even know if the content types are - * something we understand. So it's essentially half-alive and useless to - * signal listeners. - */ - if (new_session) - g_signal_emit (self, signals[NEW_SESSION], 0, sess, FALSE); - - /* all went well, we can acknowledge the IQ */ - wocky_porter_acknowledge_iq (porter, msg, NULL); - - return TRUE; - -REQUEST_ERROR: - g_assert (error != NULL); - DEBUG ("NAKing with error: %s", error->message); - wocky_porter_send_iq_gerror (porter, msg, error); - g_error_free (error); - - if (sess != NULL && new_session) - gabble_jingle_session_terminate (sess, JINGLE_REASON_UNKNOWN, NULL, NULL); - - return TRUE; -} - -static gboolean -session_query_cap_cb ( - GabbleJingleSession *session, - WockyContact *contact, - const gchar *cap_or_quirk, - gpointer user_data) -{ - GabbleJingleFactory *self = GABBLE_JINGLE_FACTORY (user_data); - gboolean ret; - - /* Propagate the query out to the application. We can't depend on the - * application connecting to ::query-cap on the session because caps queries - * may happen while parsing the session-initiate stanza, which must happen - * before the session is announced to the application. - */ - g_signal_emit (self, signals[QUERY_CAP], 0, contact, cap_or_quirk, &ret); - return ret; -} - -/* - * If sid is set to NULL a unique sid is generated and - * the "local-initiator" property of the newly created - * GabbleJingleSession is set to true. - */ -static GabbleJingleSession * -create_session (GabbleJingleFactory *fac, - const gchar *sid, - const gchar *jid, - JingleDialect dialect, - gboolean local_hold) -{ - GabbleJingleFactoryPrivate *priv = fac->priv; - GabbleJingleSession *sess; - gboolean local_initiator; - gchar *sid_, *key; - gpointer contact; - WockyContactFactory *factory; - - factory = wocky_session_get_contact_factory (priv->session); - g_assert (jid != NULL); - - if (strchr (jid, '/') != NULL) - contact = wocky_contact_factory_ensure_resource_contact (factory, jid); - else - contact = wocky_contact_factory_ensure_bare_contact (factory, jid); - - g_return_val_if_fail (contact != NULL, NULL); - g_return_val_if_fail (WOCKY_IS_CONTACT (contact), NULL); - - if (sid != NULL) - { - key = make_session_map_key (jid, sid); - sid_ = g_strdup (sid); - - local_initiator = FALSE; - } - else - { - sid_ = get_unique_sid_for (fac, jid, &key); - - local_initiator = TRUE; - } - - /* Either we should have found the existing session when the IQ arrived, or - * get_unique_sid_for should have ensured the key is fresh. */ - g_assert (NULL == g_hash_table_lookup (priv->sessions, key)); - - sess = gabble_jingle_session_new ( - fac, - priv->porter, - sid_, local_initiator, contact, dialect, local_hold); - g_signal_connect (sess, "terminated", - (GCallback) session_terminated_cb, fac); - - /* Takes ownership of key */ - g_hash_table_insert (priv->sessions, key, sess); - - DEBUG ("new session (%s, %s) @ %p", jid, sid_, sess); - - g_free (sid_); - g_object_unref (contact); - - g_signal_connect (sess, "query-cap", - (GCallback) session_query_cap_cb, (GObject *) fac); - - return sess; -} - -GabbleJingleSession * -gabble_jingle_factory_create_session (GabbleJingleFactory *fac, - const gchar *jid, - JingleDialect dialect, - gboolean local_hold) -{ - GabbleJingleSession *session = create_session (fac, NULL, jid, dialect, local_hold); - - g_signal_emit (fac, signals[NEW_SESSION], 0, session, TRUE); - return session; -} - -void -gabble_jingle_factory_register_transport (GabbleJingleFactory *self, - gchar *xmlns, - GType transport_type) -{ - g_return_if_fail (g_type_is_a (transport_type, - GABBLE_TYPE_JINGLE_TRANSPORT_IFACE)); - - g_hash_table_insert (self->priv->transports, xmlns, - GSIZE_TO_POINTER (transport_type)); -} - -GType -gabble_jingle_factory_lookup_transport (GabbleJingleFactory *self, - const gchar *xmlns) -{ - return GPOINTER_TO_SIZE (g_hash_table_lookup (self->priv->transports, - xmlns)); -} - -void -gabble_jingle_factory_register_content_type (GabbleJingleFactory *self, - gchar *xmlns, - GType content_type) -{ - g_return_if_fail (g_type_is_a (content_type, GABBLE_TYPE_JINGLE_CONTENT)); - - g_hash_table_insert (self->priv->content_types, xmlns, - GSIZE_TO_POINTER (content_type)); -} - -GType -gabble_jingle_factory_lookup_content_type (GabbleJingleFactory *self, - const gchar *xmlns) -{ - return GPOINTER_TO_SIZE (g_hash_table_lookup (self->priv->content_types, - xmlns)); -} - -static void -session_terminated_cb (GabbleJingleSession *session, - gboolean local_terminator G_GNUC_UNUSED, - JingleReason reason G_GNUC_UNUSED, - const gchar *text G_GNUC_UNUSED, - GabbleJingleFactory *factory) -{ - gchar *key = make_session_map_key ( - gabble_jingle_session_get_peer_jid (session), - gabble_jingle_session_get_sid (session)); - - DEBUG ("removing terminated session with key %s", key); - - g_signal_handlers_disconnect_by_func (session, session_query_cap_cb, factory); - g_warn_if_fail (g_hash_table_remove (factory->priv->sessions, key)); - - g_free (key); -} - -GabbleJingleInfo * -gabble_jingle_factory_get_jingle_info ( - GabbleJingleFactory *self) -{ - return self->priv->jingle_info; -} diff --git a/src/jingle-factory.h b/src/jingle-factory.h deleted file mode 100644 index d254dbf20..000000000 --- a/src/jingle-factory.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * jingle-factory.h - Header for GabbleJingleFactory - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_FACTORY_H__ -#define __JINGLE_FACTORY_H__ - -#include <glib-object.h> - -#include "jingle-info.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _GabbleJingleFactoryClass GabbleJingleFactoryClass; - -GType gabble_jingle_factory_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_FACTORY \ - (gabble_jingle_factory_get_type ()) -#define GABBLE_JINGLE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_FACTORY, \ - GabbleJingleFactory)) -#define GABBLE_JINGLE_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_FACTORY, \ - GabbleJingleFactoryClass)) -#define GABBLE_IS_JINGLE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_FACTORY)) -#define GABBLE_IS_JINGLE_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_FACTORY)) -#define GABBLE_JINGLE_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_FACTORY, \ - GabbleJingleFactoryClass)) - -struct _GabbleJingleFactoryClass { - GObjectClass parent_class; -}; - -typedef struct _GabbleJingleFactoryPrivate GabbleJingleFactoryPrivate; - -struct _GabbleJingleFactory { - GObject parent; - - GabbleJingleFactoryPrivate *priv; -}; - -GabbleJingleFactory *gabble_jingle_factory_new ( - WockySession *session); - -void gabble_jingle_factory_stop (GabbleJingleFactory *self); - -void gabble_jingle_factory_register_content_type (GabbleJingleFactory *self, - gchar *xmlns, GType content_type); -GType gabble_jingle_factory_lookup_content_type (GabbleJingleFactory *self, - const gchar *xmlns); - -void gabble_jingle_factory_register_transport (GabbleJingleFactory *self, - gchar *xmlns, GType transport_type); -GType gabble_jingle_factory_lookup_transport (GabbleJingleFactory *self, - const gchar *xmlns); - -GabbleJingleSession *gabble_jingle_factory_create_session ( - GabbleJingleFactory *fac, - const gchar *jid, - JingleDialect dialect, - gboolean local_hold); - -GabbleJingleInfo *gabble_jingle_factory_get_jingle_info ( - GabbleJingleFactory *fac); - -G_END_DECLS; - -#endif /* __JINGLE_FACTORY_H__ */ - diff --git a/src/jingle-info.c b/src/jingle-info.c deleted file mode 100644 index 4048fa3b3..000000000 --- a/src/jingle-info.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * jingle-info.c - exciting times with Google's jingleinfo extension - * Copyright © 2008–2012 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-info.h" - -#include <stdlib.h> -#include <telepathy-glib/util.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA -#include "debug.h" -#include "google-relay.h" -#include "gabble-signals-marshal.h" -#include "namespaces.h" - -static gboolean jingle_info_cb ( - WockyPorter *porter, - WockyStanza *stanza, - gpointer user_data); - -struct _GabbleJingleInfoPrivate { - WockyPorter *porter; - guint jingle_info_handler_id; - - GabbleGoogleRelayResolver *google_resolver; - - gchar *stun_server; - guint16 stun_port; - gchar *fallback_stun_server; - guint16 fallback_stun_port; - gchar *relay_token; - - /* TRUE if the user has not explicitly specified a STUN server, and hence - * we should ask the XMPP server for one; FALSE if not. - */ - gboolean get_stun_from_jingle; - - gchar *relay_server; - guint16 relay_http_port; - guint16 relay_udp; - guint16 relay_tcp; - guint16 relay_ssltcp; - -}; - -enum { - PROP_PORTER = 1, -}; - -enum { - STUN_SERVER_CHANGED = 0, - N_SIGNALS -}; - -static guint signals[N_SIGNALS]; - -static gboolean test_mode = FALSE; - -void -gabble_jingle_info_set_test_mode (void) -{ - test_mode = TRUE; -} - -G_DEFINE_TYPE (GabbleJingleInfo, gabble_jingle_info, G_TYPE_OBJECT) - -static void -gabble_jingle_info_init (GabbleJingleInfo *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_JINGLE_INFO, - GabbleJingleInfoPrivate); - - self->priv->relay_http_port = 80; - self->priv->get_stun_from_jingle = TRUE; -} - -static void -gabble_jingle_info_get_property ( - GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleInfo *self = GABBLE_JINGLE_INFO (object); - GabbleJingleInfoPrivate *priv = self->priv; - - switch (property_id) - { - case PROP_PORTER: - g_value_set_object (value, priv->porter); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -gabble_jingle_info_set_property ( - GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleInfo *self = GABBLE_JINGLE_INFO (object); - GabbleJingleInfoPrivate *priv = self->priv; - - switch (property_id) - { - case PROP_PORTER: - g_assert (priv->porter == NULL); - priv->porter = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -gabble_jingle_info_constructed (GObject *object) -{ - GabbleJingleInfo *self = GABBLE_JINGLE_INFO (object); - GabbleJingleInfoPrivate *priv = self->priv; - GObjectClass *parent_class = gabble_jingle_info_parent_class; - - if (parent_class->constructed != NULL) - parent_class->constructed (object); - - g_assert (priv->porter != NULL); - priv->jingle_info_handler_id = wocky_c2s_porter_register_handler_from_server ( - WOCKY_C2S_PORTER (priv->porter), - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, jingle_info_cb, self, - '(', "query", ':', NS_GOOGLE_JINGLE_INFO, ')', NULL); -} - -static void -gabble_jingle_info_dispose (GObject *object) -{ - GabbleJingleInfo *self = GABBLE_JINGLE_INFO (object); - GabbleJingleInfoPrivate *priv = self->priv; - GObjectClass *parent_class = gabble_jingle_info_parent_class; - - if (priv->porter != NULL) - { - g_assert (priv->jingle_info_handler_id != 0); - wocky_porter_unregister_handler (priv->porter, priv->jingle_info_handler_id); - g_clear_object (&priv->porter); - } - - if (priv->google_resolver != NULL) - { - gabble_google_relay_resolver_destroy (priv->google_resolver); - priv->google_resolver = NULL; - } - - g_free (priv->stun_server); - priv->stun_server = NULL; - g_free (priv->fallback_stun_server); - priv->fallback_stun_server = NULL; - g_free (priv->relay_token); - priv->relay_token = NULL; - g_free (priv->relay_server); - priv->relay_server = NULL; - - if (parent_class->dispose != NULL) - parent_class->dispose (object); -} - -static void -gabble_jingle_info_class_init (GabbleJingleInfoClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - object_class->get_property = gabble_jingle_info_get_property; - object_class->set_property = gabble_jingle_info_set_property; - object_class->constructed = gabble_jingle_info_constructed; - object_class->dispose = gabble_jingle_info_dispose; - - g_type_class_add_private (klass, sizeof (GabbleJingleInfoPrivate)); - - param_spec = g_param_spec_object ("porter", "WockyC2SPorter", - "Porter for the current connection", - WOCKY_TYPE_C2S_PORTER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PORTER, param_spec); - - signals[STUN_SERVER_CHANGED] = g_signal_new ("stun-server-changed", - G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__STRING_UINT, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); -} - -GabbleJingleInfo * -gabble_jingle_info_new ( - WockyPorter *porter) -{ - return g_object_new (GABBLE_TYPE_JINGLE_INFO, - "porter", porter, - NULL); -} - -typedef struct { - GabbleJingleInfo *factory; - gchar *stun_server; - guint16 stun_port; - gboolean fallback; - GCancellable *cancellable; -} PendingStunServer; - -static void -pending_stun_server_free (gpointer p) -{ - PendingStunServer *data = p; - - if (data->factory != NULL) - g_object_remove_weak_pointer (G_OBJECT (data->factory), - (gpointer)&data->factory); - - g_object_unref (data->cancellable); - g_free (data->stun_server); - g_slice_free (PendingStunServer, p); -} - -static void -stun_server_resolved_cb (GObject *resolver, - GAsyncResult *result, - gpointer user_data) -{ - PendingStunServer *data = user_data; - GabbleJingleInfo *self = data->factory; - GError *e = NULL; - gchar *stun_server; - GList *entries; - - if (self != NULL) - g_object_weak_unref (G_OBJECT (self), - (GWeakNotify)g_cancellable_cancel, data->cancellable); - - entries = g_resolver_lookup_by_name_finish ( - G_RESOLVER (resolver), result, &e); - - if (entries == NULL) - { - DEBUG ("Failed to resolve STUN server %s:%u: %s", - data->stun_server, data->stun_port, e->message); - g_error_free (e); - goto out; - } - - stun_server = g_inet_address_to_string (entries->data); - g_resolver_free_addresses (entries); - - DEBUG ("Resolved STUN server %s:%u to %s:%u", data->stun_server, - data->stun_port, stun_server, data->stun_port); - - if (self == NULL) - { - g_free (stun_server); - goto out; - } - - if (data->fallback) - { - g_free (self->priv->fallback_stun_server); - self->priv->fallback_stun_server = stun_server; - self->priv->fallback_stun_port = data->stun_port; - } - else - { - g_free (self->priv->stun_server); - self->priv->stun_server = stun_server; - self->priv->stun_port = data->stun_port; - - g_signal_emit (self, signals[STUN_SERVER_CHANGED], 0, - stun_server, data->stun_port); - } - -out: - pending_stun_server_free (data); - g_object_unref (resolver); -} - -void -gabble_jingle_info_take_stun_server ( - GabbleJingleInfo *self, - gchar *stun_server, - guint16 stun_port, - gboolean is_fallback) -{ - GResolver *resolver; - PendingStunServer *data; - - if (stun_server == NULL) - return; - - if (!is_fallback) - self->priv->get_stun_from_jingle = FALSE; - - resolver = g_resolver_get_default (); - data = g_slice_new0 (PendingStunServer); - - DEBUG ("Resolving %s STUN server %s:%u", - is_fallback ? "fallback" : "primary", stun_server, stun_port); - data->factory = self; - g_object_add_weak_pointer (G_OBJECT (self), (gpointer *) &data->factory); - data->stun_server = stun_server; - data->stun_port = stun_port; - data->fallback = is_fallback; - - data->cancellable = g_cancellable_new (); - g_object_weak_ref (G_OBJECT (self), (GWeakNotify)g_cancellable_cancel, - data->cancellable); - - g_resolver_lookup_by_name_async (resolver, stun_server, - data->cancellable, stun_server_resolved_cb, data); -} - -static void -got_jingle_info_stanza ( - GabbleJingleInfo *self, - WockyStanza *stanza) -{ - WockyNode *node, *query_node; - - query_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (stanza), "query", NS_GOOGLE_JINGLE_INFO); - - if (query_node == NULL) - return; - - if (self->priv->get_stun_from_jingle) - node = wocky_node_get_child (query_node, "stun"); - else - node = NULL; - - if (node != NULL) - { - node = wocky_node_get_child (node, "server"); - - if (node != NULL) - { - const gchar *server; - const gchar *port_attr; - guint port = 0; - - server = wocky_node_get_attribute (node, "host"); - port_attr = wocky_node_get_attribute (node, "udp"); - - if (port_attr != NULL) - port = atoi (port_attr); - - if (server != NULL && - port_attr != NULL && port > 0 && port <= G_MAXUINT16) - { - DEBUG ("jingle info: got stun server %s, port %u", server, - port); - gabble_jingle_info_take_stun_server (self, - g_strdup (server), port, FALSE); - } - } - } - -#ifdef ENABLE_GOOGLE_RELAY - node = wocky_node_get_child (query_node, "relay"); - - if (node != NULL) - { - WockyNode *subnode = wocky_node_get_child (node, "token"); - - if (subnode != NULL) - { - const gchar *token = subnode->content; - - if (token != NULL) - { - DEBUG ("jingle info: got Google relay token %s", token); - g_free (self->priv->relay_token); - self->priv->relay_token = g_strdup (token); - } - } - - subnode = wocky_node_get_child (node, "server"); - - if (subnode != NULL) - { - const gchar *server; - const gchar *port; - - server = wocky_node_get_attribute (subnode, "host"); - - if (server != NULL) - { - DEBUG ("jingle info: got relay server %s", server); - g_free (self->priv->relay_server); - self->priv->relay_server = g_strdup (server); - } - - if (test_mode) - { - /* this is not part of the real protocol, but we can't listen on - * port 80 in an unprivileged regression test */ - port = wocky_node_get_attribute (subnode, - "gabble-test-http-port"); - - if (port != NULL) - { - DEBUG ("jingle info: diverting 'Google' HTTP requests to " - "port %s", port); - self->priv->relay_http_port = atoi (port); - } - } - - /* FIXME: these are not really actually used anywhere at - * the moment, because we get the same info when creating - * relay session. */ - port = wocky_node_get_attribute (subnode, "udp"); - - if (port != NULL) - { - DEBUG ("jingle info: got relay udp port %s", port); - self->priv->relay_udp = atoi (port); - } - - port = wocky_node_get_attribute (subnode, "tcp"); - - if (port != NULL) - { - DEBUG ("jingle info: got relay tcp port %s", port); - self->priv->relay_tcp = atoi (port); - } - - port = wocky_node_get_attribute (subnode, "tcpssl"); - - if (port != NULL) - { - DEBUG ("jingle info: got relay tcpssl port %s", port); - self->priv->relay_ssltcp = atoi (port); - } - - } - - } -#endif /* ENABLE_GOOGLE_RELAY */ -} - -static gboolean -jingle_info_cb ( - WockyPorter *porter, - WockyStanza *stanza, - gpointer user_data) -{ - GabbleJingleInfo *self = GABBLE_JINGLE_INFO (user_data); - - got_jingle_info_stanza (self, stanza); - wocky_porter_acknowledge_iq (porter, stanza, NULL); - - return TRUE; -} - -static void -jingle_info_reply_cb ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source); - GabbleJingleInfo *self = GABBLE_JINGLE_INFO (user_data); - WockyStanza *reply = NULL; - GError *error = NULL; - - reply = wocky_porter_send_iq_finish (porter, result, &error); - if (reply != NULL && - !wocky_stanza_extract_errors (reply, NULL, &error, NULL, NULL)) - { - got_jingle_info_stanza (self, reply); - } - else - { - DEBUG ("jingle info request failed: %s", error->message); - g_clear_error (&error); - } - - g_clear_object (&reply); - g_object_unref (self); -} - -void -gabble_jingle_info_send_request (GabbleJingleInfo *self) -{ - GabbleJingleInfoPrivate *priv = self->priv; - WockyStanza *stanza = wocky_stanza_build ( - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET, NULL, - wocky_porter_get_bare_jid (priv->porter), - '(', "query", ':', NS_GOOGLE_JINGLE_INFO, ')', NULL); - - wocky_porter_send_iq_async (priv->porter, stanza, NULL, jingle_info_reply_cb, - g_object_ref (self)); - g_object_unref (stanza); -} - -gboolean -gabble_jingle_info_get_stun_server ( - GabbleJingleInfo *self, - gchar **stun_server, - guint *stun_port) -{ - if (self->priv->stun_server == NULL || self->priv->stun_port == 0) - { - if (self->priv->fallback_stun_server == NULL || - self->priv->fallback_stun_port == 0) - return FALSE; - - if (stun_server != NULL) - *stun_server = g_strdup (self->priv->fallback_stun_server); - - if (stun_port != NULL) - *stun_port = self->priv->fallback_stun_port; - - return TRUE; - } - - if (stun_server != NULL) - *stun_server = g_strdup (self->priv->stun_server); - - if (stun_port != NULL) - *stun_port = self->priv->stun_port; - - return TRUE; -} - -const gchar * -gabble_jingle_info_get_google_relay_token ( - GabbleJingleInfo *self) -{ - return self->priv->relay_token; -} - -GabbleJingleRelay * -gabble_jingle_relay_new ( - GabbleJingleRelayType type, - const gchar *ip, - guint port, - const gchar *username, - const gchar *password, - guint component) -{ - GabbleJingleRelay ret = { type, g_strdup (ip), port, g_strdup (username), - g_strdup (password), component }; - - return g_slice_dup (GabbleJingleRelay, &ret); -} - -void -gabble_jingle_relay_free (GabbleJingleRelay *relay) -{ - g_free (relay->ip); - g_free (relay->username); - g_free (relay->password); - g_slice_free (GabbleJingleRelay, relay); -} - -void -gabble_jingle_info_create_google_relay_session ( - GabbleJingleInfo *self, - guint components, - GabbleJingleInfoRelaySessionCb callback, - gpointer user_data) -{ - GabbleJingleInfoPrivate *priv = self->priv; - - g_return_if_fail (callback != NULL); - - if (priv->google_resolver == NULL) - { - priv->google_resolver = gabble_google_relay_resolver_new (); - } - - gabble_google_relay_resolver_resolve (priv->google_resolver, - components, priv->relay_server, priv->relay_http_port, priv->relay_token, - callback, user_data); -} diff --git a/src/jingle-info.h b/src/jingle-info.h deleted file mode 100644 index 2ce8111c6..000000000 --- a/src/jingle-info.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * jingle-info.h - exciting times with Google's jingleinfo extension - * Copyright © 2008–2012 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef GABBLE_JINGLE_INFO_H -#define GABBLE_JINGLE_INFO_H - -#include <glib-object.h> -#include <wocky/wocky.h> - -typedef struct _GabbleJingleInfo GabbleJingleInfo; -typedef struct _GabbleJingleInfoClass GabbleJingleInfoClass; -typedef struct _GabbleJingleInfoPrivate GabbleJingleInfoPrivate; - -struct _GabbleJingleInfoClass { - GObjectClass parent_class; -}; - -struct _GabbleJingleInfo { - GObject parent; - - GabbleJingleInfoPrivate *priv; -}; - -GType gabble_jingle_info_get_type (void); - -GabbleJingleInfo *gabble_jingle_info_new ( - WockyPorter *porter); - -void gabble_jingle_info_take_stun_server ( - GabbleJingleInfo *self, - gchar *stun_server, - guint16 stun_port, - gboolean is_fallback); -void gabble_jingle_info_send_request (GabbleJingleInfo *self); - -gboolean gabble_jingle_info_get_stun_server ( - GabbleJingleInfo *self, - gchar **stun_server, - guint *stun_port); - -const gchar *gabble_jingle_info_get_google_relay_token ( - GabbleJingleInfo *self); - -typedef enum { - GABBLE_JINGLE_RELAY_TYPE_UDP, - GABBLE_JINGLE_RELAY_TYPE_TCP, - GABBLE_JINGLE_RELAY_TYPE_TLS -} GabbleJingleRelayType; -#define GABBLE_N_JINGLE_RELAY_TYPES 3 - -typedef struct { - GabbleJingleRelayType type; - gchar *ip; - guint port; - gchar *username; - gchar *password; - guint component; -} GabbleJingleRelay; - -GabbleJingleRelay *gabble_jingle_relay_new ( - GabbleJingleRelayType type, - const gchar *ip, - guint port, - const gchar *username, - const gchar *password, - guint component); -void gabble_jingle_relay_free (GabbleJingleRelay *relay); - -/* - * @relays: (element-type GabbleJingleRelay) (transfer none): a possibly-empty - * array of GabbleJingleRelay structs. - */ -typedef void (*GabbleJingleInfoRelaySessionCb) ( - GPtrArray *relays, - gpointer user_data); -void gabble_jingle_info_create_google_relay_session ( - GabbleJingleInfo *self, - guint components, - GabbleJingleInfoRelaySessionCb callback, - gpointer user_data); - -void gabble_jingle_info_set_test_mode (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_INFO \ - (gabble_jingle_info_get_type ()) -#define GABBLE_JINGLE_INFO(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_INFO, GabbleJingleInfo)) -#define GABBLE_JINGLE_INFO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_INFO,\ - GabbleJingleInfoClass)) -#define GABBLE_IS_JINGLE_INFO(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_INFO)) -#define GABBLE_IS_JINGLE_INFO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_INFO)) -#define GABBLE_JINGLE_INFO_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_INFO, \ - GabbleJingleInfoClass)) - -#endif /* GABBLE_JINGLE_INFO_H */ diff --git a/src/jingle-media-rtp.c b/src/jingle-media-rtp.c deleted file mode 100644 index 45a14191a..000000000 --- a/src/jingle-media-rtp.c +++ /dev/null @@ -1,1516 +0,0 @@ -/* - * jingle-media-rtp.c - Source for GabbleJingleMediaRtp - * - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Media/RTP content type deals with audio/video content, ie. jingle calls. It - * supports standard Jingle drafts (v0.15, v0.26) and Google's jingle variants - * (libjingle 0.3/0.4). */ - -#include "config.h" -#include "jingle-media-rtp.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "connection.h" -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" -#include "presence-cache.h" -#include "jingle-transport-google.h" - -G_DEFINE_TYPE (GabbleJingleMediaRtp, - gabble_jingle_media_rtp, GABBLE_TYPE_JINGLE_CONTENT); - -/* signal enum */ -enum -{ - REMOTE_MEDIA_DESCRIPTION, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_MEDIA_TYPE = 1, - PROP_REMOTE_MUTE, - LAST_PROPERTY -}; - -typedef enum { - JINGLE_MEDIA_PROFILE_RTP_AVP, -} JingleMediaProfile; - -struct _GabbleJingleMediaRtpPrivate -{ - JingleMediaDescription *local_media_description; - - /* Holds (JingleCodec *)'s borrowed from local_media_description, - * namely codecs which have changed from local_media_description's - * previous value. Since the contents are borrowed, this must be - * freed with g_list_free, not jingle_media_rtp_free_codecs(). - */ - GList *local_codec_updates; - - JingleMediaDescription *remote_media_description; - JingleMediaType media_type; - gboolean remote_mute; - - gboolean has_rtcp_fb; - gboolean has_rtp_hdrext; - - gboolean dispose_has_run; -}; - -static void -gabble_jingle_media_rtp_init (GabbleJingleMediaRtp *obj) -{ - GabbleJingleMediaRtpPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_MEDIA_RTP, - GabbleJingleMediaRtpPrivate); - obj->priv = priv; - priv->dispose_has_run = FALSE; -} - -JingleCodec * -jingle_media_rtp_codec_new (guint id, const gchar *name, - guint clockrate, guint channels, GHashTable *params) -{ - JingleCodec *p = g_slice_new0 (JingleCodec); - - p->id = id; - p->name = g_strdup (name); - p->clockrate = clockrate; - p->channels = channels; - p->trr_int = G_MAXUINT; - - if (params != NULL) - { - g_hash_table_ref (params); - p->params = params; - } - else - { - p->params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - g_free); - } - - return p; -} - - -static GList * -jingle_feedback_message_list_copy (GList *fbs) -{ - GQueue new = G_QUEUE_INIT; - GList *li; - - for (li = fbs; li; li = li->next) - { - JingleFeedbackMessage *fb = li->data; - - g_queue_push_tail (&new, jingle_feedback_message_new (fb->type, - fb->subtype)); - } - - return new.head; -} - -static void -jingle_feedback_message_list_free (GList *fbs) -{ - while (fbs != NULL) - { - jingle_feedback_message_free (fbs->data); - fbs = g_list_delete_link (fbs, fbs); - } -} - -void -jingle_media_rtp_codec_free (JingleCodec *p) -{ - g_hash_table_unref (p->params); - g_free (p->name); - jingle_feedback_message_list_free (p->feedback_msgs); - g_slice_free (JingleCodec, p); -} - -static void -add_codec_to_table (JingleCodec *codec, - GHashTable *table) -{ - g_hash_table_insert (table, GUINT_TO_POINTER ((guint) codec->id), codec); -} - -static GHashTable * -build_codec_table (GList *codecs) -{ - GHashTable *table = g_hash_table_new (NULL, NULL); - - g_list_foreach (codecs, (GFunc) add_codec_to_table, table); - return table; -} - -GList * -jingle_media_rtp_copy_codecs (GList *codecs) -{ - GList *ret = NULL, *l; - - for (l = codecs; l != NULL; l = g_list_next (l)) - { - JingleCodec *c = l->data; - JingleCodec *newc = jingle_media_rtp_codec_new (c->id, - c->name, c->clockrate, c->channels, c->params); - newc->trr_int = c->trr_int; - ret = g_list_append (ret, newc); - } - - return ret; -} - -void -jingle_media_rtp_free_codecs (GList *codecs) -{ - while (codecs != NULL) - { - jingle_media_rtp_codec_free (codecs->data); - codecs = g_list_delete_link (codecs, codecs); - } -} - -static void -gabble_jingle_media_rtp_dispose (GObject *object) -{ - GabbleJingleMediaRtp *trans = GABBLE_JINGLE_MEDIA_RTP (object); - GabbleJingleMediaRtpPrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - if (priv->remote_media_description != NULL) - jingle_media_description_free (priv->remote_media_description); - priv->remote_media_description = NULL; - - if (priv->local_media_description != NULL) - jingle_media_description_free (priv->local_media_description); - priv->local_media_description = NULL; - - if (priv->local_codec_updates != NULL) - { - DEBUG ("We have an unsent codec parameter update! Weird."); - - g_list_free (priv->local_codec_updates); - priv->local_codec_updates = NULL; - } - - if (G_OBJECT_CLASS (gabble_jingle_media_rtp_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_media_rtp_parent_class)->dispose (object); -} - -static void -gabble_jingle_media_rtp_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleMediaRtp *trans = GABBLE_JINGLE_MEDIA_RTP (object); - GabbleJingleMediaRtpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_MEDIA_TYPE: - g_value_set_uint (value, priv->media_type); - break; - case PROP_REMOTE_MUTE: - g_value_set_boolean (value, priv->remote_mute); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_media_rtp_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleMediaRtp *trans = GABBLE_JINGLE_MEDIA_RTP (object); - GabbleJingleMediaRtpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_MEDIA_TYPE: - priv->media_type = g_value_get_uint (value); - break; - case PROP_REMOTE_MUTE: - priv->remote_mute = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void parse_description (GabbleJingleContent *content, - WockyNode *desc_node, GError **error); -static void produce_description (GabbleJingleContent *obj, - WockyNode *content_node); -static void transport_created (GabbleJingleContent *obj, - GabbleJingleTransportIface *transport); - -static void -gabble_jingle_media_rtp_class_init (GabbleJingleMediaRtpClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GabbleJingleContentClass *content_class = GABBLE_JINGLE_CONTENT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (GabbleJingleMediaRtpPrivate)); - - object_class->get_property = gabble_jingle_media_rtp_get_property; - object_class->set_property = gabble_jingle_media_rtp_set_property; - object_class->dispose = gabble_jingle_media_rtp_dispose; - - content_class->parse_description = parse_description; - content_class->produce_description = produce_description; - content_class->transport_created = transport_created; - - param_spec = g_param_spec_uint ("media-type", "RTP media type", - "Media type.", - JINGLE_MEDIA_TYPE_NONE, G_MAXUINT32, JINGLE_MEDIA_TYPE_NONE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); - - param_spec = g_param_spec_boolean ("remote-mute", "Remote mute", - "TRUE if the peer has muted this stream", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REMOTE_MUTE, param_spec); - - /* signal definitions */ - - signals[REMOTE_MEDIA_DESCRIPTION] = g_signal_new ("remote-media-description", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} - -static void transport_created (GabbleJingleContent *content, - GabbleJingleTransportIface *transport) -{ - GabbleJingleMediaRtp *self = GABBLE_JINGLE_MEDIA_RTP (content); - GabbleJingleMediaRtpPrivate *priv = self->priv; - GabbleJingleTransportGoogle *gtrans = NULL; - JingleDialect dialect; - - if (GABBLE_IS_JINGLE_TRANSPORT_GOOGLE (transport)) - { - gtrans = GABBLE_JINGLE_TRANSPORT_GOOGLE (transport); - dialect = gabble_jingle_session_get_dialect (content->session); - - if (priv->media_type == JINGLE_MEDIA_TYPE_VIDEO && - (JINGLE_IS_GOOGLE_DIALECT (dialect) || - gabble_jingle_session_peer_has_cap (content->session, - QUIRK_GOOGLE_WEBMAIL_CLIENT) || - gabble_jingle_session_peer_has_cap (content->session, - QUIRK_ANDROID_GTALK_CLIENT))) - { - jingle_transport_google_set_component_name (gtrans, "video_rtp", 1); - jingle_transport_google_set_component_name (gtrans, "video_rtcp", 2); - } - else - { - jingle_transport_google_set_component_name (gtrans, "rtp", 1); - jingle_transport_google_set_component_name (gtrans, "rtcp", 2); - } - } -} - - -static JingleMediaType -extract_media_type (WockyNode *desc_node, - GError **error) -{ - if (wocky_node_has_ns (desc_node, NS_JINGLE_RTP)) - { - const gchar *type = wocky_node_get_attribute (desc_node, "media"); - - if (type == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "missing required media type attribute"); - return JINGLE_MEDIA_TYPE_NONE; - } - - if (!wocky_strdiff (type, "audio")) - return JINGLE_MEDIA_TYPE_AUDIO; - - if (!wocky_strdiff (type, "video")) - return JINGLE_MEDIA_TYPE_VIDEO; - - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "unknown media type %s", type); - return JINGLE_MEDIA_TYPE_NONE; - } - - if (wocky_node_has_ns (desc_node, NS_JINGLE_DESCRIPTION_AUDIO)) - return JINGLE_MEDIA_TYPE_AUDIO; - - if (wocky_node_has_ns (desc_node, NS_JINGLE_DESCRIPTION_VIDEO)) - return JINGLE_MEDIA_TYPE_VIDEO; - - if (wocky_node_has_ns (desc_node, NS_GOOGLE_SESSION_PHONE)) - return JINGLE_MEDIA_TYPE_AUDIO; - - if (wocky_node_has_ns (desc_node, NS_GOOGLE_SESSION_VIDEO)) - return JINGLE_MEDIA_TYPE_VIDEO; - - /* If we get here, namespace in use is not one of namespaces we signed up - * with, so obviously a bug somewhere. - */ - g_assert_not_reached (); -} - -static JingleFeedbackMessage * -parse_rtcp_fb (GabbleJingleContent *content, WockyNode *node) -{ - const gchar *pt_ns = wocky_node_get_ns (node); - const gchar *type; - const gchar *subtype; - - if (wocky_strdiff (pt_ns, NS_JINGLE_RTCP_FB)) - return NULL; - - type = wocky_node_get_attribute (node, "type"); - if (type == NULL) - return NULL; - - subtype = wocky_node_get_attribute (node, "subtype"); - - /* This is optional, defaults to "" */ - if (subtype == NULL) - subtype = ""; - - return jingle_feedback_message_new (type, subtype); -} - - -/* - * Returns G_MAXUINT on error - */ -static guint -parse_rtcp_fb_trr_int (GabbleJingleContent *content, WockyNode *node) -{ - const gchar *pt_ns = wocky_node_get_ns (node); - const gchar *txt; - guint trr_int; - gchar *endptr = NULL; - - if (wocky_strdiff (pt_ns, NS_JINGLE_RTCP_FB)) - return G_MAXUINT; - - txt = wocky_node_get_attribute (node, "value"); - if (txt == NULL) - return G_MAXUINT; - - trr_int = strtol (txt, &endptr, 10); - if (endptr == NULL || endptr == txt) - return G_MAXUINT; - - return trr_int; -} - - -/** - * parse_payload_type: - * @node: a <payload-type> node. - * - * Returns: a newly-allocated JingleCodec if parsing succeeds, or %NULL - * otherwise. - */ -static JingleCodec * -parse_payload_type (GabbleJingleContent *content, - WockyNode *node) -{ - GabbleJingleMediaRtp *self = GABBLE_JINGLE_MEDIA_RTP (content); - GabbleJingleMediaRtpPrivate *priv = self->priv; - JingleCodec *p; - const char *txt; - guint8 id; - const gchar *name; - guint clockrate = 0; - guint channels = 0; - WockyNode *param; - WockyNodeIter i; - - txt = wocky_node_get_attribute (node, "id"); - if (txt == NULL) - return NULL; - - id = atoi (txt); - - name = wocky_node_get_attribute (node, "name"); - if (name == NULL) - name = ""; - - /* xep-0167 v0.22, gtalk libjingle 0.3/0.4 use "clockrate" */ - txt = wocky_node_get_attribute (node, "clockrate"); - /* older jingle rtp used "rate" ? */ - if (txt == NULL) - txt = wocky_node_get_attribute (node, "rate"); - - if (txt != NULL) - clockrate = atoi (txt); - - txt = wocky_node_get_attribute (node, "channels"); - if (txt != NULL) - channels = atoi (txt); - - p = jingle_media_rtp_codec_new (id, name, clockrate, channels, NULL); - - wocky_node_iter_init (&i, node, NULL, NULL); - while (wocky_node_iter_next (&i, ¶m)) - { - if (!wocky_strdiff (param->name, "parameter")) - { - const gchar *param_name, *param_value; - - param_name = wocky_node_get_attribute (param, "name"); - param_value = wocky_node_get_attribute (param, "value"); - - if (param_name == NULL || param_value == NULL) - continue; - - g_hash_table_insert (p->params, g_strdup (param_name), - g_strdup (param_value)); - } - else if (!wocky_strdiff (param->name, "rtcp-fb")) - { - JingleFeedbackMessage *fb = parse_rtcp_fb (content, param); - - if (fb != NULL) - { - p->feedback_msgs = g_list_append (p->feedback_msgs, fb); - priv->has_rtcp_fb = TRUE; - } - } - else if (!wocky_strdiff (param->name, - "rtcp-fb-trr-int")) - { - guint trr_int = parse_rtcp_fb_trr_int (content, param); - - if (trr_int != G_MAXUINT) - { - p->trr_int = trr_int; - priv->has_rtcp_fb = TRUE; - } - } - } - - DEBUG ("new remote codec: id = %u, name = %s, clockrate = %u, channels = %u", - p->id, p->name, p->clockrate, p->channels); - - return p; -} - -static JingleRtpHeaderExtension * -parse_rtp_header_extension (WockyNode *node) -{ - guint id; - JingleContentSenders senders; - const gchar *uri; - const char *txt; - - txt = wocky_node_get_attribute (node, "id"); - if (txt == NULL) - return NULL; - - id = atoi (txt); - - /* Only valid ranges are 1-256 and 4096-4351 */ - if ((id < 1 || id > 256) && (id < 4096 || id > 4351)) - return NULL; - - txt = wocky_node_get_attribute (node, "senders"); - - if (txt == NULL || !g_ascii_strcasecmp (txt, "both")) - senders = JINGLE_CONTENT_SENDERS_BOTH; - else if (!g_ascii_strcasecmp (txt, "initiator")) - senders = JINGLE_CONTENT_SENDERS_INITIATOR; - else if (!g_ascii_strcasecmp (txt, "responder")) - senders = JINGLE_CONTENT_SENDERS_RESPONDER; - else - return NULL; - - uri = wocky_node_get_attribute (node, "uri"); - - if (uri == NULL) - return NULL; - - return jingle_rtp_header_extension_new (id, senders, uri); -} - - -/** - * codec_update_coherent: - * @old_c: Gabble's old cache of the codec, or %NULL if it hasn't heard of it. - * @new_c: the proposed update, whose id must equal that of @old_c if the - * latter is non-NULL. - * @domain: the error domain to set @e to if necessary - * @code: the error code to set @e to if necessary - * @e: location to hold an error - * - * Compares @old_c and @new_c, which are assumed to have the same id, to check - * that the name, clockrate and number of channels hasn't changed. If they - * have, returns %FALSE and sets @e. - */ -static gboolean -codec_update_coherent (const JingleCodec *old_c, - const JingleCodec *new_c, - GError **e) -{ - const GQuark domain = WOCKY_XMPP_ERROR; - const gint code = WOCKY_XMPP_ERROR_BAD_REQUEST; - - if (old_c == NULL) - { - g_set_error (e, domain, code, "Codec with id %u ('%s') unknown", - new_c->id, new_c->name); - return FALSE; - } - - if (g_ascii_strcasecmp (new_c->name, old_c->name)) - { - g_set_error (e, domain, code, - "tried to change codec %u's name from %s to %s", - new_c->id, old_c->name, new_c->name); - return FALSE; - } - - if (new_c->clockrate != old_c->clockrate) - { - g_set_error (e, domain, code, - "tried to change codec %u (%s)'s clockrate from %u to %u", - new_c->id, new_c->name, old_c->clockrate, new_c->clockrate); - return FALSE; - } - - if (old_c->channels != 0 && - new_c->channels != old_c->channels) - { - g_set_error (e, domain, code, - "tried to change codec %u (%s)'s channels from %u to %u", - new_c->id, new_c->name, new_c->channels, old_c->channels); - return FALSE; - } - - return TRUE; -} - -static void -update_remote_media_description (GabbleJingleMediaRtp *self, - JingleMediaDescription *new_media_description, - GError **error) -{ - GabbleJingleMediaRtpPrivate *priv = self->priv; - GHashTable *rc = NULL; - JingleCodec *old_c, *new_c; - GList *l; - GError *e = NULL; - - if (priv->remote_media_description == NULL) - { - priv->remote_media_description = new_media_description; - new_media_description = NULL; - goto out; - } - - rc = build_codec_table (priv->remote_media_description->codecs); - - /* We already know some remote codecs, so this is just the other end updating - * some parameters. - */ - for (l = new_media_description->codecs; l != NULL; l = l->next) - { - new_c = l->data; - old_c = g_hash_table_lookup (rc, GUINT_TO_POINTER ((guint) new_c->id)); - - if (!codec_update_coherent (old_c, new_c, &e)) - goto out; - } - - /* Okay, all the updates are cool. Let's switch the parameters around. */ - for (l = new_media_description->codecs; l != NULL; l = l->next) - { - GHashTable *params; - - new_c = l->data; - old_c = g_hash_table_lookup (rc, GUINT_TO_POINTER ((guint) new_c->id)); - - params = old_c->params; - old_c->params = new_c->params; - new_c->params = params; - } - -out: - if (new_media_description != NULL) - jingle_media_description_free (new_media_description); - - if (rc != NULL) - g_hash_table_unref (rc); - - if (e != NULL) - { - DEBUG ("Rejecting codec update: %s", e->message); - g_propagate_error (error, e); - } - else - { - DEBUG ("Emitting remote-media-description signal"); - g_signal_emit (self, signals[REMOTE_MEDIA_DESCRIPTION], 0, - priv->remote_media_description); - } -} - -static void -parse_description (GabbleJingleContent *content, - WockyNode *desc_node, GError **error) -{ - GabbleJingleMediaRtp *self = GABBLE_JINGLE_MEDIA_RTP (content); - GabbleJingleMediaRtpPrivate *priv = self->priv; - JingleMediaType mtype; - JingleMediaDescription *md; - JingleCodec *p; - JingleDialect dialect = gabble_jingle_session_get_dialect (content->session); - gboolean video_session = FALSE; - WockyNodeIter i; - WockyNode *node; - gboolean description_error = FALSE; - gboolean is_avpf = FALSE; - - DEBUG ("node: %s", desc_node->name); - - if (priv->media_type == JINGLE_MEDIA_TYPE_NONE) - mtype = extract_media_type (desc_node, error); - else - mtype = priv->media_type; - - if (mtype == JINGLE_MEDIA_TYPE_NONE) - return; - - DEBUG ("detected media type %u", mtype); - - if (dialect == JINGLE_DIALECT_GTALK3) - { - const gchar *desc_ns = - wocky_node_get_ns (desc_node); - video_session = !wocky_strdiff (desc_ns, NS_GOOGLE_SESSION_VIDEO); - } - - md = jingle_media_description_new (); - - wocky_node_iter_init (&i, desc_node, NULL, NULL); - while (wocky_node_iter_next (&i, &node) && !description_error) - { - if (!wocky_strdiff (node->name, "payload-type")) - { - if (dialect == JINGLE_DIALECT_GTALK3) - { - const gchar *pt_ns = wocky_node_get_ns (node); - - if (priv->media_type == JINGLE_MEDIA_TYPE_AUDIO) - { - if (video_session && - wocky_strdiff (pt_ns, NS_GOOGLE_SESSION_PHONE)) - continue; - } - else if (priv->media_type == JINGLE_MEDIA_TYPE_VIDEO) - { - if (!(video_session && pt_ns == NULL) - && wocky_strdiff (pt_ns, NS_GOOGLE_SESSION_VIDEO)) - continue; - } - } - - p = parse_payload_type (content, node); - - if (p == NULL) - { - description_error = TRUE; - } - else - { - md->codecs = g_list_append (md->codecs, p); - if (p->trr_int != G_MAXUINT || p->feedback_msgs) - is_avpf = TRUE; - } - } - else if (!wocky_strdiff (node->name, "rtp-hdrext")) - { - const gchar *pt_ns = wocky_node_get_ns (node); - JingleRtpHeaderExtension *hdrext; - - if (wocky_strdiff (pt_ns, NS_JINGLE_RTP_HDREXT)) - continue; - - hdrext = parse_rtp_header_extension (node); - - if (hdrext == NULL) - { - description_error = TRUE; - } - else - { - md->hdrexts = g_list_append (md->hdrexts, hdrext); - priv->has_rtp_hdrext = TRUE; - } - - } - else if (!wocky_strdiff (node->name, "rtcp-fb")) - { - JingleFeedbackMessage *fb = parse_rtcp_fb (content, node); - - if (fb == NULL) - { - description_error = TRUE; - } - else - { - md->feedback_msgs = g_list_append (md->feedback_msgs, fb); - is_avpf = TRUE; - priv->has_rtcp_fb = TRUE; - } - } - else if (!wocky_strdiff (node->name, "rtcp-fb-trr-int")) - { - guint trr_int = parse_rtcp_fb_trr_int (content, node); - - if (trr_int == G_MAXUINT) - { - description_error = TRUE; - } - else - { - md->trr_int = trr_int; - is_avpf = TRUE; - priv->has_rtcp_fb = TRUE; - } - } - } - - if (description_error) - { - /* rollback these */ - jingle_media_description_free (md); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "invalid description"); - return; - } - - /* If the profile is AVPF, the trr-int default to 0 */ - if (is_avpf && md->trr_int == G_MAXUINT) - md->trr_int = 0; - - priv->media_type = mtype; - - update_remote_media_description (self, md, error); -} - -/* The Google Talk desktop client is picky about the case of codec names, even - * though SDP defines them to be case-insensitive. The particular case that was - * causing problems was ILBC vs iLBC, but it seems safer to special-case the - * lot. This list is taken from the initiate sent by the desktop client on - * 2009-07-01. - */ -static const gchar * const codec_cases[] = { - "CN", - "EG711A", - "EG711U", - "G723", - "IPCMWB", - "ISAC", - "PCMA", - "PCMU", - "iLBC", - "speex", - "telephone-event", - NULL -}; - -static const gchar * -gtalk_case (const gchar *codec) -{ - const gchar * const *ret = codec_cases; - - for (; *ret != NULL; ret++) - if (g_ascii_strcasecmp (*ret, codec) == 0) - return *ret; - - return codec; -} - -static void -_produce_extra_param (gpointer key, gpointer value, gpointer user_data) -{ - WockyNode *pt_node = user_data; - WockyNode *param; - gchar *param_name = key; - gchar *param_value = value; - - param = wocky_node_add_child_with_content (pt_node, "parameter", NULL); - wocky_node_set_attribute (param, "name", param_name); - wocky_node_set_attribute (param, "value", param_value); -} - -static void -produce_rtcp_fb_trr_int (WockyNode *node, - guint trr_int) -{ - WockyNode *trr_int_node; - gchar tmp[10]; - - if (trr_int == G_MAXUINT || trr_int == 0) - return; - - trr_int_node = wocky_node_add_child_ns (node, "rtcp-fb-trr-int", - NS_JINGLE_RTCP_FB); - snprintf (tmp, 9, "%d", trr_int); - wocky_node_set_attribute (trr_int_node, "value", tmp); -} - - -static void -produce_rtcp_fb (JingleFeedbackMessage *fb, WockyNode *node) -{ - WockyNode *fb_node; - - fb_node = wocky_node_add_child (node, "rtcp-fb"); - - wocky_node_set_attribute (fb_node, "xmlns", NS_JINGLE_RTCP_FB); - wocky_node_set_attribute (fb_node, "type", fb->type); - - if (fb->subtype != NULL && fb->subtype[0] != 0) - wocky_node_set_attribute (fb_node, "subtype", fb->subtype); -} - -static void -produce_payload_type (GabbleJingleContent *content, - WockyNode *desc_node, - JingleMediaType type, - JingleCodec *p, - JingleDialect dialect) -{ - GabbleJingleMediaRtp *self = GABBLE_JINGLE_MEDIA_RTP (content); - GabbleJingleMediaRtpPrivate *priv = self->priv; - WockyNode *pt_node; - gchar buf[16]; - - pt_node = wocky_node_add_child_with_content (desc_node, "payload-type", NULL); - - /* id: required */ - sprintf (buf, "%d", p->id); - wocky_node_set_attribute (pt_node, "id", buf); - - if (dialect == JINGLE_DIALECT_GTALK3) - { - if (type == JINGLE_MEDIA_TYPE_AUDIO) - { - /* Gtalk 03 has either an audio or a video session, in case of a - * video session the audio codecs need to set their namespace to - * NS_GOOGLE_SESSION_PHONE. In the case of an audio session it - * doesn't matter, so just always set the namespace on audio - * payloads. - */ - pt_node->ns = g_quark_from_static_string ( - NS_GOOGLE_SESSION_PHONE); - } - else - { - /* If width, height and framerate aren't set the google server ignore - * our initiate.. These are a recv parameters, to it doesn't matter - * for what we're sending, just for what we're getting.. 320x240 - * seems a sane enough default */ - wocky_node_set_attributes (pt_node, - "width", "320", - "height", "240", - "framerate", "30", - NULL); - } - - } - - /* name: optional */ - if (*p->name != '\0') - { - if (JINGLE_IS_GOOGLE_DIALECT (dialect)) - wocky_node_set_attribute (pt_node, "name", gtalk_case (p->name)); - else - wocky_node_set_attribute (pt_node, "name", p->name); - } - - /* clock rate: optional */ - if (p->clockrate != 0) - { - const gchar *attname = "clockrate"; - - if (dialect == JINGLE_DIALECT_V015) - attname = "rate"; - - sprintf (buf, "%u", p->clockrate); - wocky_node_set_attribute (pt_node, attname, buf); - } - - if (p->channels != 0) - { - sprintf (buf, "%u", p->channels); - wocky_node_set_attribute (pt_node, "channels", buf); - } - - if (p->params != NULL) - g_hash_table_foreach (p->params, _produce_extra_param, pt_node); - - - if (priv->has_rtcp_fb) - { - g_list_foreach (p->feedback_msgs, (GFunc) produce_rtcp_fb, pt_node); - produce_rtcp_fb_trr_int (pt_node, p->trr_int); - } -} - -static WockyNode * -produce_description_node (JingleDialect dialect, JingleMediaType media_type, - WockyNode *content_node) -{ - WockyNode *desc_node; - const gchar *xmlns = NULL; - - if (dialect == JINGLE_DIALECT_GTALK3) - return NULL; - - desc_node = wocky_node_add_child_with_content (content_node, "description", NULL); - - switch (dialect) - { - case JINGLE_DIALECT_GTALK4: - g_assert (media_type == JINGLE_MEDIA_TYPE_AUDIO); - xmlns = NS_GOOGLE_SESSION_PHONE; - break; - case JINGLE_DIALECT_V015: - if (media_type == JINGLE_MEDIA_TYPE_AUDIO) - xmlns = NS_JINGLE_DESCRIPTION_AUDIO; - else if (media_type == JINGLE_MEDIA_TYPE_VIDEO) - xmlns = NS_JINGLE_DESCRIPTION_VIDEO; - else - { - DEBUG ("unknown media type %u", media_type); - xmlns = ""; - } - break; - default: - xmlns = NS_JINGLE_RTP; - if (media_type == JINGLE_MEDIA_TYPE_AUDIO) - wocky_node_set_attribute (desc_node, "media", "audio"); - else if (media_type == JINGLE_MEDIA_TYPE_VIDEO) - wocky_node_set_attribute (desc_node, "media", "video"); - else - g_assert_not_reached (); - break; - } - - desc_node->ns = g_quark_from_string (xmlns); - - return desc_node; -} - -static void -produce_hdrext (gpointer data, gpointer user_data) -{ - JingleRtpHeaderExtension *hdrext = data; - WockyNode *desc_node = user_data; - WockyNode *hdrext_node; - gchar buf[16]; - - hdrext_node = wocky_node_add_child (desc_node, "rtp-hdrext"); - - /* id: required */ - sprintf (buf, "%d", hdrext->id); - wocky_node_set_attribute (hdrext_node, "id", buf); - wocky_node_set_attribute (hdrext_node, "uri", hdrext->uri); - - if (hdrext->senders == JINGLE_CONTENT_SENDERS_INITIATOR) - wocky_node_set_attribute (hdrext_node, "senders", "initiator"); - else if (hdrext->senders == JINGLE_CONTENT_SENDERS_RESPONDER) - wocky_node_set_attribute (hdrext_node, "senders", "responder"); - - wocky_node_set_attribute (hdrext_node, "xmlns", NS_JINGLE_RTP_HDREXT); -} - -static void -produce_description (GabbleJingleContent *content, WockyNode *content_node) -{ - GabbleJingleMediaRtp *self = GABBLE_JINGLE_MEDIA_RTP (content); - GabbleJingleMediaRtpPrivate *priv = self->priv; - GList *li; - JingleDialect dialect = gabble_jingle_session_get_dialect (content->session); - WockyNode *desc_node; - - if (gabble_jingle_session_peer_has_cap (content->session, NS_JINGLE_RTCP_FB)) - priv->has_rtcp_fb = TRUE; - - if (gabble_jingle_session_peer_has_cap (content->session, NS_JINGLE_RTP_HDREXT)) - priv->has_rtp_hdrext = TRUE; - - desc_node = produce_description_node (dialect, priv->media_type, - content_node); - - /* For GTalk3 the description is added by the session */ - if (desc_node == NULL) - desc_node = content_node; - - /* If we're only updating our codec parameters, only generate payload-types - * for those. - */ - if (priv->local_codec_updates != NULL) - li = priv->local_codec_updates; - else - li = priv->local_media_description->codecs; - - for (; li != NULL; li = li->next) - produce_payload_type (content, desc_node, priv->media_type, li->data, - dialect); - - if (priv->has_rtp_hdrext && priv->local_media_description->hdrexts) - g_list_foreach (priv->local_media_description->hdrexts, produce_hdrext, - desc_node); - - if (priv->has_rtcp_fb) - { - g_list_foreach (priv->local_media_description->feedback_msgs, - (GFunc) produce_rtcp_fb, desc_node); - produce_rtcp_fb_trr_int (desc_node, - priv->local_media_description->trr_int); - } -} - -/** - * string_string_maps_equal: - * - * Returns: TRUE iff @a and @b contain exactly the same keys and values when - * compared as strings. - */ -static gboolean -string_string_maps_equal (GHashTable *a, - GHashTable *b) -{ - GHashTableIter iter; - gpointer a_key, a_value, b_value; - - if (g_hash_table_size (a) != g_hash_table_size (b)) - return FALSE; - - g_hash_table_iter_init (&iter, a); - - while (g_hash_table_iter_next (&iter, &a_key, &a_value)) - { - if (!g_hash_table_lookup_extended (b, a_key, NULL, &b_value)) - return FALSE; - - if (wocky_strdiff (a_value, b_value)) - return FALSE; - } - - return TRUE; -} - -/** - * compare_codecs: - * @old: previous local codecs - * @new: new local codecs supplied by streaming implementation - * @changed: location at which to store the changed codecs - * @error: location at which to store an error if the update was invalid - * - * Returns: %TRUE if the update made sense, %FALSE with @error set otherwise - */ -gboolean -jingle_media_rtp_compare_codecs (GList *old, - GList *new, - GList **changed, - GError **e) -{ - gboolean ret = FALSE; - GHashTable *old_table = build_codec_table (old); - GList *l; - JingleCodec *old_c, *new_c; - - g_assert (changed != NULL && *changed == NULL); - - for (l = new; l != NULL; l = l->next) - { - new_c = l->data; - old_c = g_hash_table_lookup (old_table, GUINT_TO_POINTER ( - (guint) new_c->id)); - - if (!codec_update_coherent (old_c, new_c, e)) - goto out; - - if (!string_string_maps_equal (old_c->params, new_c->params)) - *changed = g_list_prepend (*changed, new_c); - } - - ret = TRUE; - -out: - if (!ret) - { - g_list_free (*changed); - *changed = NULL; - } - - g_hash_table_unref (old_table); - return ret; -} - -/* - * @self: a content in an RTP session - * @md: (transfer full): new media description for this content - * @ready: whether the codecs can regarded as ready to sent from now on - * @error: used to return a %WOCKY_XMPP_ERROR if the codec update is illegal. - * - * Sets or updates the media description (codecs, feedback messages, etc) for - * @self. - * - * Returns: %TRUE if no description was previously set, or if the update is - * compatible with the existing description; %FALSE if the update is illegal - * (due to adding previously-unknown codecs or renaming an existing codec, for - * example) - */ -gboolean -jingle_media_rtp_set_local_media_description (GabbleJingleMediaRtp *self, - JingleMediaDescription *md, - gboolean ready, - GError **error) -{ - GabbleJingleMediaRtpPrivate *priv = self->priv; - - DEBUG ("setting new local media description"); - - if (priv->local_media_description != NULL) - { - GList *changed = NULL; - GError *err = NULL; - - g_assert (priv->local_codec_updates == NULL); - - if (!jingle_media_rtp_compare_codecs ( - priv->local_media_description->codecs, - md->codecs, &changed, &err)) - { - DEBUG ("codec update was illegal: %s", err->message); - jingle_media_description_free (md); - g_propagate_error (error, err); - return FALSE; - } - - if (changed == NULL) - { - DEBUG ("codec update changed nothing!"); - jingle_media_description_free (md); - goto out; - } - - DEBUG ("%u codecs changed", g_list_length (changed)); - priv->local_codec_updates = changed; - - jingle_media_description_free (priv->local_media_description); - } - - priv->local_media_description = md; - - /* Codecs have changed, sending a fresh description might be necessary */ - gabble_jingle_content_maybe_send_description (GABBLE_JINGLE_CONTENT (self)); - - /* Update done if any, free the changed codecs if any */ - g_list_free (priv->local_codec_updates); - priv->local_codec_updates = NULL; - -out: - if (ready) - _gabble_jingle_content_set_media_ready (GABBLE_JINGLE_CONTENT (self)); - - return TRUE; -} - -void -jingle_media_rtp_register (GabbleJingleFactory *factory) -{ - /* Current (v0.25) Jingle draft URI */ - gabble_jingle_factory_register_content_type (factory, - NS_JINGLE_RTP, GABBLE_TYPE_JINGLE_MEDIA_RTP); - - /* Old Jingle audio/video namespaces */ - gabble_jingle_factory_register_content_type (factory, - NS_JINGLE_DESCRIPTION_AUDIO, - GABBLE_TYPE_JINGLE_MEDIA_RTP); - - gabble_jingle_factory_register_content_type (factory, - NS_JINGLE_DESCRIPTION_VIDEO, - GABBLE_TYPE_JINGLE_MEDIA_RTP); - - /* GTalk audio call namespace */ - gabble_jingle_factory_register_content_type (factory, - NS_GOOGLE_SESSION_PHONE, - GABBLE_TYPE_JINGLE_MEDIA_RTP); - - /* GTalk video call namespace */ - gabble_jingle_factory_register_content_type (factory, - NS_GOOGLE_SESSION_VIDEO, - GABBLE_TYPE_JINGLE_MEDIA_RTP); -} - -/* We can't get remote media description when they're signalled, because - * the signal is emitted immediately upon JingleContent creation, - * and parsing, which is before a corresponding MediaStream is - * created. */ -JingleMediaDescription * -gabble_jingle_media_rtp_get_remote_media_description ( - GabbleJingleMediaRtp *self) -{ - GabbleJingleMediaRtpPrivate *priv = self->priv; - - return priv->remote_media_description; -} - -JingleMediaDescription * -jingle_media_description_new (void) -{ - JingleMediaDescription *md = g_slice_new0 (JingleMediaDescription); - - md->trr_int = G_MAXUINT; - - return md; -} - -void -jingle_media_description_free (JingleMediaDescription *md) -{ - jingle_media_rtp_free_codecs (md->codecs); - - while (md->hdrexts != NULL) - { - jingle_rtp_header_extension_free (md->hdrexts->data); - md->hdrexts = g_list_delete_link (md->hdrexts, md->hdrexts); - } - - g_slice_free (JingleMediaDescription, md); -} - -JingleMediaDescription * -jingle_media_description_copy (JingleMediaDescription *md) -{ - JingleMediaDescription *newmd = g_slice_new0 (JingleMediaDescription); - GList *li; - - newmd->codecs = jingle_media_rtp_copy_codecs (md->codecs); - newmd->feedback_msgs = jingle_feedback_message_list_copy (md->feedback_msgs); - newmd->trr_int = md->trr_int; - - for (li = md->hdrexts; li; li = li->next) - { - JingleRtpHeaderExtension *h = li->data; - - newmd->hdrexts = g_list_append (newmd->hdrexts, - jingle_rtp_header_extension_new (h->id, h->senders, h->uri)); - } - - return newmd; -} - -JingleRtpHeaderExtension * -jingle_rtp_header_extension_new (guint id, JingleContentSenders senders, - const gchar *uri) -{ - JingleRtpHeaderExtension *hdrext = g_slice_new (JingleRtpHeaderExtension); - - hdrext->id = id; - hdrext->senders = senders; - hdrext->uri = g_strdup (uri); - - return hdrext; -} - -void -jingle_rtp_header_extension_free (JingleRtpHeaderExtension *hdrext) -{ - g_free (hdrext->uri); - g_slice_free (JingleRtpHeaderExtension, hdrext); -} - -JingleFeedbackMessage * -jingle_feedback_message_new (const gchar *type, const gchar *subtype) -{ - JingleFeedbackMessage *fb = g_slice_new0 (JingleFeedbackMessage); - - fb->type = g_strdup (type); - fb->subtype = g_strdup (subtype); - - return fb; -} - -void -jingle_feedback_message_free (JingleFeedbackMessage *fb) -{ - g_free (fb->type); - g_free (fb->subtype); - g_slice_free (JingleFeedbackMessage, fb); -} - - -static gint -jingle_feedback_message_compare (const JingleFeedbackMessage *fb1, - const JingleFeedbackMessage *fb2) -{ - if (!g_ascii_strcasecmp (fb1->type, fb2->type) && - !g_ascii_strcasecmp (fb1->subtype, fb2->subtype)) - return 0; - else - return 1; -} - -/** - * jingle_media_description_simplify: - * - * Removes duplicated Feedback message and put them in the global structure - * - * This function will iterate over every codec in a description and look for - * feedback messages that are exactly the same in every codec and will instead - * put the in the list in the description and remove them from the childs. - * This limits the amount of duplication in the resulting XML. - */ - -void -jingle_media_description_simplify (JingleMediaDescription *md) -{ - GList *item; - guint trr_int = 0; - gboolean trr_int_all_same = TRUE; - gboolean init = FALSE; - GList *identical_fbs = NULL; - - for (item = md->codecs; item; item = item->next) - { - JingleCodec *c = item->data; - - if (!init) - { - /* For the first codec, it stores the trr_int and the list - * of feedback messages */ - trr_int = c->trr_int; - identical_fbs = g_list_copy (c->feedback_msgs); - init = TRUE; - } - else - { - GList *item2; - - /* For every subsequent codec, we check if the trr_int is the same */ - - if (trr_int != c->trr_int) - trr_int_all_same = FALSE; - - /* We also intersect the remembered list of feedback messages with - * the list for that codec and remove any feedback message that isn't - * in both - */ - - for (item2 = identical_fbs; item2;) - { - JingleFeedbackMessage *fb = identical_fbs->data; - GList *next = item2->next; - - if (!g_list_find_custom (c->feedback_msgs, fb, - (GCompareFunc) jingle_feedback_message_compare)) - identical_fbs = g_list_delete_link (identical_fbs, item2); - - item2 = next; - } - - /* If the trr_int is not the same everywhere and there are not common - * feedback messages, then stop - */ - if (!trr_int_all_same && identical_fbs == NULL) - break; - } - } - - if (trr_int_all_same && trr_int == G_MAXUINT) - trr_int_all_same = FALSE; - - /* if the trr_int is the same everywhere, lets set it globally */ - if (trr_int_all_same) - md->trr_int = trr_int; - - /* If there are feedback messages that are in every codec, put a copy of them - * in the global structure - */ - if (identical_fbs) - { - md->feedback_msgs = jingle_feedback_message_list_copy (identical_fbs); - g_list_free (identical_fbs); - } - - if (trr_int_all_same || md->feedback_msgs != NULL) - for (item = md->codecs; item; item = item->next) - { - JingleCodec *c = item->data; - GList *item2; - - /* If the trr_int is the same everywhere, lets put the default on - * each codec, we have it in the main structure - */ - if (trr_int_all_same) - c->trr_int = G_MAXUINT; - - /* Find the feedback messages that were put in the main structure and - * remove them from each codec - */ - for (item2 = md->feedback_msgs; item2; item2 = item2->next) - { - GList *duplicated; - JingleFeedbackMessage *fb = item2->data; - - while ((duplicated = g_list_find_custom (c->feedback_msgs, fb, - (GCompareFunc) jingle_feedback_message_compare)) != NULL) - { - jingle_feedback_message_free (duplicated->data); - c->feedback_msgs = g_list_delete_link (c->feedback_msgs, - duplicated); - } - } - } -} diff --git a/src/jingle-media-rtp.h b/src/jingle-media-rtp.h deleted file mode 100644 index d904c8c10..000000000 --- a/src/jingle-media-rtp.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * jingle-media-rtp.h - Header for GabbleJingleMediaRtp - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_MEDIA_RTP_H__ -#define __JINGLE_MEDIA_RTP_H__ - -#include <glib-object.h> - -#include "jingle-content.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _GabbleJingleMediaRtpClass GabbleJingleMediaRtpClass; - -GType gabble_jingle_media_rtp_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_MEDIA_RTP \ - (gabble_jingle_media_rtp_get_type ()) -#define GABBLE_JINGLE_MEDIA_RTP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_MEDIA_RTP, \ - GabbleJingleMediaRtp)) -#define GABBLE_JINGLE_MEDIA_RTP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_MEDIA_RTP, \ - GabbleJingleMediaRtpClass)) -#define GABBLE_IS_JINGLE_MEDIA_RTP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_MEDIA_RTP)) -#define GABBLE_IS_JINGLE_MEDIA_RTP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_MEDIA_RTP)) -#define GABBLE_JINGLE_MEDIA_RTP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_MEDIA_RTP, \ - GabbleJingleMediaRtpClass)) - -struct _GabbleJingleMediaRtpClass { - GabbleJingleContentClass parent_class; -}; - -typedef struct _GabbleJingleMediaRtpPrivate GabbleJingleMediaRtpPrivate; - -struct _GabbleJingleMediaRtp { - GabbleJingleContent parent; - GabbleJingleMediaRtpPrivate *priv; -}; - -typedef struct { - guint id; - gchar *name; - guint clockrate; - guint channels; - GHashTable *params; - guint trr_int; - GList *feedback_msgs; -} JingleCodec; - -typedef struct { - gchar *type; - gchar *subtype; -} JingleFeedbackMessage; - -typedef struct { - guint id; - JingleContentSenders senders; - gchar *uri; -} JingleRtpHeaderExtension; - -typedef struct { - GList *codecs; - GList *hdrexts; - guint trr_int; - GList *feedback_msgs; -} JingleMediaDescription; - -void jingle_media_rtp_register (GabbleJingleFactory *factory); -gboolean jingle_media_rtp_set_local_media_description ( - GabbleJingleMediaRtp *self, JingleMediaDescription *md, gboolean ready, - GError **error); -JingleMediaDescription *gabble_jingle_media_rtp_get_remote_media_description ( - GabbleJingleMediaRtp *self); - -JingleCodec * jingle_media_rtp_codec_new (guint id, const gchar *name, - guint clockrate, guint channels, GHashTable *params); -void jingle_media_rtp_codec_free (JingleCodec *p); -void jingle_media_rtp_free_codecs (GList *codecs); -GList * jingle_media_rtp_copy_codecs (GList *codecs); - -gboolean jingle_media_rtp_compare_codecs (GList *old, - GList *new, - GList **changed, - GError **e); - -JingleMediaDescription *jingle_media_description_new (void); -void jingle_media_description_free (JingleMediaDescription *md); -JingleMediaDescription *jingle_media_description_copy ( - JingleMediaDescription *md); - -JingleRtpHeaderExtension *jingle_rtp_header_extension_new (guint id, - JingleContentSenders senders, const gchar *uri); -void jingle_rtp_header_extension_free (JingleRtpHeaderExtension *hdrext); - - -JingleFeedbackMessage *jingle_feedback_message_new (const gchar *type, - const gchar *subtype); -void jingle_feedback_message_free (JingleFeedbackMessage *fb); -void jingle_media_description_simplify (JingleMediaDescription *md); - -#endif /* __JINGLE_MEDIA_RTP_H__ */ - diff --git a/src/jingle-mint.c b/src/jingle-mint.c index f575cfd39..f41a504ea 100644 --- a/src/jingle-mint.c +++ b/src/jingle-mint.c @@ -1,5 +1,5 @@ /* - * jingle-mint.c - creates and configures a GabbleJingleFactory + * jingle-mint.c - creates and configures a WockyJingleFactory * Copyright ©2012 Collabora Ltd. * * This library is free software; you can redistribute it and/or @@ -32,14 +32,13 @@ #include "connection.h" #include "conn-presence.h" -#include "jingle-factory.h" -#include "jingle-session.h" +#include "jingle-share.h" #include "presence-cache.h" struct _GabbleJingleMintPrivate { GabbleConnection *conn; - GabbleJingleFactory *factory; + WockyJingleFactory *factory; }; enum { @@ -65,12 +64,12 @@ static void connection_porter_available_cb ( gpointer user_data); static void factory_new_session_cb ( - GabbleJingleFactory *factory, - GabbleJingleSession *session, + WockyJingleFactory *factory, + WockyJingleSession *session, gboolean initiated_locally, gpointer user_data); static gboolean factory_query_cap_cb ( - GabbleJingleFactory *factory, + WockyJingleFactory *factory, WockyContact *contact, const gchar *cap_or_quirk, gpointer user_data); @@ -177,7 +176,7 @@ gabble_jingle_mint_class_init (GabbleJingleMintClass *klass) signals[INCOMING_SESSION] = g_signal_new ("incoming-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, GABBLE_TYPE_JINGLE_SESSION); + G_TYPE_NONE, 1, WOCKY_TYPE_JINGLE_SESSION); } GabbleJingleMint * @@ -207,7 +206,7 @@ connection_status_changed_cb ( case TP_CONNECTION_STATUS_CONNECTED: { - GabbleJingleInfo *info = gabble_jingle_mint_get_info (self); + WockyJingleInfo *info = gabble_jingle_mint_get_info (self); gchar *stun_server = NULL; guint stun_port = 0; @@ -217,7 +216,7 @@ connection_status_changed_cb ( NULL); if (stun_server != NULL) - gabble_jingle_info_take_stun_server (info, + wocky_jingle_info_take_stun_server (info, stun_server, stun_port, FALSE); g_object_get (priv->conn, @@ -226,20 +225,21 @@ connection_status_changed_cb ( NULL); if (stun_server != NULL) - gabble_jingle_info_take_stun_server (info, + wocky_jingle_info_take_stun_server (info, stun_server, stun_port, TRUE); - if (priv->conn->features & - GABBLE_CONNECTION_FEATURES_GOOGLE_JINGLE_INFO) - { - gabble_jingle_info_send_request (info); - } + wocky_jingle_info_send_request (info, + /* FIXME: one day Wocky will know about caps and then we won't + * have to pass in a flag here. + */ + !!(priv->conn->features & + GABBLE_CONNECTION_FEATURES_GOOGLE_JINGLE_INFO)); } break; case TP_CONNECTION_STATUS_DISCONNECTED: if (priv->factory != NULL) - gabble_jingle_factory_stop (priv->factory); + wocky_jingle_factory_stop (priv->factory); break; } } @@ -257,7 +257,9 @@ connection_porter_available_cb ( g_assert (conn->session != NULL); g_assert (priv->factory == NULL); - priv->factory = gabble_jingle_factory_new (conn->session); + priv->factory = wocky_jingle_factory_new (conn->session); + + jingle_share_register (priv->factory); tp_g_signal_connect_object (priv->factory, "new-session", (GCallback) factory_new_session_cb, self, 0); @@ -267,12 +269,12 @@ connection_porter_available_cb ( static void session_about_to_initiate_cb ( - GabbleJingleSession *session, + WockyJingleSession *session, gpointer user_data) { GabbleJingleMint *self = GABBLE_JINGLE_MINT (user_data); GabbleJingleMintPrivate *priv = self->priv; - const gchar *peer_jid = gabble_jingle_session_get_peer_jid (session); + const gchar *peer_jid = wocky_jingle_session_get_peer_jid (session); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); TpHandle peer = tp_handle_ensure (contact_repo, peer_jid, NULL, NULL); @@ -285,8 +287,8 @@ session_about_to_initiate_cb ( static void factory_new_session_cb ( - GabbleJingleFactory *factory, - GabbleJingleSession *session, + WockyJingleFactory *factory, + WockyJingleSession *session, gboolean initiated_locally, gpointer user_data) { @@ -303,7 +305,7 @@ factory_new_session_cb ( static gboolean factory_query_cap_cb ( - GabbleJingleFactory *factory, + WockyJingleFactory *factory, WockyContact *contact, const gchar *cap_or_quirk, gpointer user_data) @@ -330,16 +332,16 @@ factory_query_cap_cb ( } } -GabbleJingleFactory * +WockyJingleFactory * gabble_jingle_mint_get_factory ( GabbleJingleMint *self) { return self->priv->factory; } -GabbleJingleInfo * +WockyJingleInfo * gabble_jingle_mint_get_info ( GabbleJingleMint *self) { - return gabble_jingle_factory_get_jingle_info (self->priv->factory); + return wocky_jingle_factory_get_jingle_info (self->priv->factory); } diff --git a/src/jingle-mint.h b/src/jingle-mint.h index 90b52270a..6f7685077 100644 --- a/src/jingle-mint.h +++ b/src/jingle-mint.h @@ -1,5 +1,5 @@ /* - * jingle-mint.h - creates and configures a GabbleJingleFactory + * jingle-mint.h - creates and configures a WockyJingleFactory * Copyright ©2012 Collabora Ltd. * * This library is free software; you can redistribute it and/or @@ -23,8 +23,7 @@ #include <glib-object.h> #include "types.h" -#include "jingle-info.h" -#include "jingle-types.h" +#include <wocky/wocky.h> typedef struct _GabbleJingleMint GabbleJingleMint; typedef struct _GabbleJingleMintClass GabbleJingleMintClass; @@ -45,9 +44,9 @@ GType gabble_jingle_mint_get_type (void); GabbleJingleMint *gabble_jingle_mint_new ( GabbleConnection *connection); -GabbleJingleFactory *gabble_jingle_mint_get_factory ( +WockyJingleFactory *gabble_jingle_mint_get_factory ( GabbleJingleMint *self); -GabbleJingleInfo *gabble_jingle_mint_get_info ( +WockyJingleInfo *gabble_jingle_mint_get_info ( GabbleJingleMint *self); /* TYPE MACROS */ diff --git a/src/jingle-session.c b/src/jingle-session.c deleted file mode 100644 index 0e266b92d..000000000 --- a/src/jingle-session.c +++ /dev/null @@ -1,2457 +0,0 @@ -/* - * gabble-jingle-session.c - Source for GabbleJingleSession - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-session.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#include <wocky/wocky.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "gabble/capabilities.h" -#include "debug.h" -#include "gabble-signals-marshal.h" -#include "gabble-enumtypes.h" -#include "jingle-content.h" -#include "jingle-factory.h" -/* FIXME: the RTP-specific bits of this file should be separated from the - * generic Jingle code. - */ -#include "jingle-media-rtp.h" -#include "namespaces.h" - -G_DEFINE_TYPE(GabbleJingleSession, gabble_jingle_session, G_TYPE_OBJECT); - -/* signal enum */ -enum -{ - NEW_CONTENT, - REMOTE_STATE_CHANGED, - TERMINATED, - CONTENT_REJECTED, - QUERY_CAP, - ABOUT_TO_INITIATE, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_JINGLE_FACTORY = 1, - PROP_PORTER, - PROP_SESSION_ID, - PROP_PEER_CONTACT, - PROP_LOCAL_INITIATOR, - PROP_STATE, - PROP_DIALECT, - PROP_LOCAL_HOLD, - PROP_REMOTE_HOLD, - PROP_REMOTE_RINGING, - LAST_PROPERTY -}; - -struct _GabbleJingleSessionPrivate -{ - /* Borrowed; the factory owns us. */ - GabbleJingleFactory *jingle_factory; - WockyPorter *porter; - - WockyContact *peer_contact; - /* Borrowed from peer_contact if it's a WockyResourceContact. */ - const gchar *peer_resource; - gchar *peer_jid; - /* Either borrowed from 'porter' or equal to peer_jid. */ - const gchar *initiator; - gboolean local_initiator; - - /* GabbleJingleContent objects keyed by content name. - * Table owns references to these objects. */ - GHashTable *initiator_contents; - GHashTable *responder_contents; - - JingleDialect dialect; - JingleState state; - gchar *sid; - - gboolean locally_accepted; - gboolean locally_terminated; - - gboolean local_hold; - - gboolean remote_hold; - gboolean remote_ringing; - - gboolean dispose_has_run; -}; - -typedef struct { - JingleState state; - JingleAction *actions; -} JingleStateActions; - -/* gcc should be able to figure this out from the table below, but.. */ -#define MAX_ACTIONS_PER_STATE 12 - -/* NB: JINGLE_ACTION_UNKNOWN is used as a terminator here. */ -static JingleAction allowed_actions[MAX_JINGLE_STATES][MAX_ACTIONS_PER_STATE] = { - /* JINGLE_STATE_PENDING_CREATED */ - { JINGLE_ACTION_SESSION_INITIATE, JINGLE_ACTION_UNKNOWN }, - /* JINGLE_STATE_PENDING_INITIATE_SENT */ - { JINGLE_ACTION_SESSION_TERMINATE, JINGLE_ACTION_SESSION_ACCEPT, - JINGLE_ACTION_TRANSPORT_ACCEPT, /* required for GTalk4 */ - JINGLE_ACTION_DESCRIPTION_INFO, JINGLE_ACTION_SESSION_INFO, - JINGLE_ACTION_TRANSPORT_INFO, JINGLE_ACTION_INFO, - JINGLE_ACTION_UNKNOWN }, - /* JINGLE_STATE_PENDING_INITIATED */ - { JINGLE_ACTION_SESSION_ACCEPT, JINGLE_ACTION_SESSION_TERMINATE, - JINGLE_ACTION_TRANSPORT_INFO, JINGLE_ACTION_CONTENT_REJECT, - JINGLE_ACTION_CONTENT_MODIFY, JINGLE_ACTION_CONTENT_ACCEPT, - JINGLE_ACTION_CONTENT_REMOVE, JINGLE_ACTION_DESCRIPTION_INFO, - JINGLE_ACTION_TRANSPORT_ACCEPT, JINGLE_ACTION_SESSION_INFO, - JINGLE_ACTION_INFO, - JINGLE_ACTION_UNKNOWN }, - /* JINGLE_STATE_PENDING_ACCEPT_SENT */ - { JINGLE_ACTION_TRANSPORT_INFO, JINGLE_ACTION_DESCRIPTION_INFO, - JINGLE_ACTION_SESSION_TERMINATE, JINGLE_ACTION_SESSION_INFO, - JINGLE_ACTION_INFO, - JINGLE_ACTION_UNKNOWN }, - /* JINGLE_STATE_ACTIVE */ - { JINGLE_ACTION_CONTENT_MODIFY, JINGLE_ACTION_CONTENT_ADD, - JINGLE_ACTION_CONTENT_REMOVE, JINGLE_ACTION_CONTENT_REPLACE, - JINGLE_ACTION_CONTENT_ACCEPT, JINGLE_ACTION_CONTENT_REJECT, - JINGLE_ACTION_SESSION_INFO, JINGLE_ACTION_TRANSPORT_INFO, - JINGLE_ACTION_DESCRIPTION_INFO, JINGLE_ACTION_INFO, - JINGLE_ACTION_SESSION_TERMINATE, JINGLE_ACTION_UNKNOWN }, - /* JINGLE_STATE_ENDED */ - { JINGLE_ACTION_UNKNOWN } -}; - -gboolean -gabble_jingle_session_defines_action (GabbleJingleSession *sess, - JingleAction a) -{ - JingleDialect d = sess->priv->dialect; - - if (a == JINGLE_ACTION_UNKNOWN) - return FALSE; - - switch (d) - { - case JINGLE_DIALECT_V032: - return TRUE; - case JINGLE_DIALECT_V015: - return (a != JINGLE_ACTION_DESCRIPTION_INFO && - a != JINGLE_ACTION_SESSION_INFO); - case JINGLE_DIALECT_GTALK4: - if (a == JINGLE_ACTION_TRANSPORT_ACCEPT || - a == JINGLE_ACTION_INFO ) - return TRUE; - case JINGLE_DIALECT_GTALK3: - return (a == JINGLE_ACTION_SESSION_ACCEPT || - a == JINGLE_ACTION_SESSION_INITIATE || - a == JINGLE_ACTION_SESSION_TERMINATE || - a == JINGLE_ACTION_TRANSPORT_INFO || - a == JINGLE_ACTION_INFO); - default: - return FALSE; - } -} - -static void gabble_jingle_session_send_held (GabbleJingleSession *sess); -static void content_ready_cb (GabbleJingleContent *c, gpointer user_data); -static void content_removed_cb (GabbleJingleContent *c, gpointer user_data); - -static void -gabble_jingle_session_init (GabbleJingleSession *obj) -{ - GabbleJingleSessionPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_SESSION, - GabbleJingleSessionPrivate); - obj->priv = priv; - - DEBUG ("Initializing the jingle session %p", obj); - - priv->initiator_contents = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - priv->responder_contents = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - priv->state = JINGLE_STATE_PENDING_CREATED; - priv->locally_accepted = FALSE; - priv->locally_terminated = FALSE; - priv->dispose_has_run = FALSE; -} - -static void -dispose_content_hash ( - GabbleJingleSession *sess, - GHashTable **contents) -{ - GHashTableIter iter; - gpointer content; - - g_hash_table_iter_init (&iter, *contents); - while (g_hash_table_iter_next (&iter, NULL, &content)) - { - g_signal_handlers_disconnect_by_func (content, content_ready_cb, sess); - g_signal_handlers_disconnect_by_func (content, content_removed_cb, sess); - g_hash_table_iter_remove (&iter); - } - - g_hash_table_unref (*contents); - *contents = NULL; -} - -static void -gabble_jingle_session_dispose (GObject *object) -{ - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (object); - GabbleJingleSessionPrivate *priv = sess->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("called"); - priv->dispose_has_run = TRUE; - - g_assert ((priv->state == JINGLE_STATE_PENDING_CREATED) || - (priv->state == JINGLE_STATE_ENDED)); - - dispose_content_hash (sess, &priv->initiator_contents); - dispose_content_hash (sess, &priv->responder_contents); - - g_clear_object (&priv->peer_contact); - g_clear_object (&priv->porter); - - g_free (priv->sid); - priv->sid = NULL; - - g_free (priv->peer_jid); - priv->peer_jid = NULL; - - if (G_OBJECT_CLASS (gabble_jingle_session_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_session_parent_class)->dispose (object); -} - -static void -gabble_jingle_session_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (object); - GabbleJingleSessionPrivate *priv = sess->priv; - - switch (property_id) { - case PROP_JINGLE_FACTORY: - g_value_set_object (value, priv->jingle_factory); - break; - case PROP_PORTER: - g_value_set_object (value, priv->porter); - break; - case PROP_SESSION_ID: - g_value_set_string (value, priv->sid); - break; - case PROP_LOCAL_INITIATOR: - g_value_set_boolean (value, priv->local_initiator); - break; - case PROP_PEER_CONTACT: - g_value_set_object (value, priv->peer_contact); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_DIALECT: - g_value_set_uint (value, priv->dialect); - break; - case PROP_LOCAL_HOLD: - g_value_set_boolean (value, priv->local_hold); - break; - case PROP_REMOTE_HOLD: - g_value_set_boolean (value, priv->remote_hold); - break; - case PROP_REMOTE_RINGING: - g_value_set_boolean (value, priv->remote_ringing); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_session_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (object); - GabbleJingleSessionPrivate *priv = sess->priv; - - switch (property_id) { - case PROP_JINGLE_FACTORY: - priv->jingle_factory = g_value_get_object (value); - g_assert (priv->jingle_factory != NULL); - break; - case PROP_PORTER: - priv->porter = g_value_dup_object (value); - g_assert (priv->porter != NULL); - break; - case PROP_SESSION_ID: - g_free (priv->sid); - priv->sid = g_value_dup_string (value); - break; - case PROP_LOCAL_INITIATOR: - priv->local_initiator = g_value_get_boolean (value); - break; - case PROP_DIALECT: - priv->dialect = g_value_get_uint (value); - break; - case PROP_PEER_CONTACT: - priv->peer_contact = g_value_dup_object (value); - break; - case PROP_LOCAL_HOLD: - { - gboolean local_hold = g_value_get_boolean (value); - - if (priv->local_hold != local_hold) - { - priv->local_hold = local_hold; - - if (priv->state >= JINGLE_STATE_PENDING_INITIATED && - priv->state < JINGLE_STATE_ENDED) - gabble_jingle_session_send_held (sess); - - /* else, we'll send this in set_state when we move to PENDING_INITIATED or - * better. - */ - } - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - g_assert_not_reached (); - break; - } -} - -static void -gabble_jingle_session_constructed (GObject *object) -{ - void (*chain_up) (GObject *) = - G_OBJECT_CLASS (gabble_jingle_session_parent_class)->constructed; - GabbleJingleSession *self = GABBLE_JINGLE_SESSION (object); - GabbleJingleSessionPrivate *priv = self->priv; - - if (chain_up != NULL) - chain_up (object); - - g_assert (priv->jingle_factory != NULL); - g_assert (priv->porter != NULL); - g_assert (priv->peer_contact != NULL); - g_assert (priv->sid != NULL); - - priv->peer_jid = wocky_contact_dup_jid (priv->peer_contact); - - if (priv->local_initiator) - priv->initiator = wocky_porter_get_full_jid (priv->porter); - else - priv->initiator = priv->peer_jid; - - if (WOCKY_IS_RESOURCE_CONTACT (priv->peer_contact)) - priv->peer_resource = wocky_resource_contact_get_resource ( - WOCKY_RESOURCE_CONTACT (priv->peer_contact)); -} - -GabbleJingleSession * -gabble_jingle_session_new ( - GabbleJingleFactory *factory, - WockyPorter *porter, - const gchar *session_id, - gboolean local_initiator, - WockyContact *peer, - JingleDialect dialect, - gboolean local_hold) -{ - return g_object_new (GABBLE_TYPE_JINGLE_SESSION, - "session-id", session_id, - "jingle-factory", factory, - "porter", porter, - "local-initiator", local_initiator, - "peer-contact", peer, - "dialect", dialect, - "local-hold", local_hold, - NULL); -} - -static void -gabble_jingle_session_class_init (GabbleJingleSessionClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (GabbleJingleSessionPrivate)); - - object_class->constructed = gabble_jingle_session_constructed; - object_class->get_property = gabble_jingle_session_get_property; - object_class->set_property = gabble_jingle_session_set_property; - object_class->dispose = gabble_jingle_session_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("jingle-factory", - "GabbleJingleFactory object", - "The Jingle factory which created this session", - GABBLE_TYPE_JINGLE_FACTORY, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_JINGLE_FACTORY, param_spec); - - param_spec = g_param_spec_object ("porter", "WockyPorter", - "The WockyPorter for the current connection", - WOCKY_TYPE_PORTER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PORTER, param_spec); - - param_spec = g_param_spec_string ("session-id", "Session ID", - "A unique session identifier used throughout all communication.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SESSION_ID, param_spec); - - param_spec = g_param_spec_boolean ("local-initiator", "Session initiator", - "Specifies if local end initiated the session.", - TRUE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCAL_INITIATOR, - param_spec); - - /** - * GabbleJingleSession:peer-contact: - * - * The #WockyContact representing the other party in the session. Note that - * if this is a #WockyBareContact (as opposed to a #WockyResourceContact) the - * session is with the contact's bare JID. - */ - param_spec = g_param_spec_object ("peer-contact", "Session peer", - "The WockyContact representing the other party in the session.", - WOCKY_TYPE_CONTACT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PEER_CONTACT, param_spec); - - param_spec = g_param_spec_uint ("state", "Session state", - "The current state that the session is in.", - 0, G_MAXUINT32, JINGLE_STATE_PENDING_CREATED, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - param_spec = g_param_spec_uint ("dialect", "Jingle dialect", - "Jingle dialect used for this session.", - 0, G_MAXUINT32, JINGLE_DIALECT_ERROR, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DIALECT, param_spec); - - param_spec = g_param_spec_boolean ("local-hold", "Local hold", - "TRUE if we've placed the peer on hold", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCAL_HOLD, param_spec); - - param_spec = g_param_spec_boolean ("remote-hold", "Remote hold", - "TRUE if the peer has placed us on hold", FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REMOTE_HOLD, param_spec); - - param_spec = g_param_spec_boolean ("remote-ringing", "Remote ringing", - "TRUE if the peer's client is ringing", FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REMOTE_RINGING, - param_spec); - - /* signal definitions */ - - signals[NEW_CONTENT] = g_signal_new ("new-content", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - signals[TERMINATED] = g_signal_new ("terminated", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__BOOLEAN_UINT_STRING, - G_TYPE_NONE, 3, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING); - - signals[REMOTE_STATE_CHANGED] = g_signal_new ("remote-state-changed", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[CONTENT_REJECTED] = g_signal_new ("content-rejected", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__OBJECT_UINT_STRING, - G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_STRING); - - /* - * @contact: this call's peer (the artist commonly known as - * gabble_jingle_session_get_peer_contact()) - * @cap: the XEP-0115 feature string the session is interested in. - * - * Emitted when the session wants to check whether the peer has a particular - * capability. The handler should return %TRUE if @contact has @cap. - */ - signals[QUERY_CAP] = g_signal_new ("query-cap", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, g_signal_accumulator_first_wins, NULL, - gabble_marshal_BOOLEAN__OBJECT_STRING, - G_TYPE_BOOLEAN, 2, WOCKY_TYPE_CONTACT, G_TYPE_STRING); - - signals[ABOUT_TO_INITIATE] = g_signal_new ("about-to-initiate", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -typedef void (*HandlerFunc)(GabbleJingleSession *sess, - WockyNode *node, GError **error); -typedef void (*ContentHandlerFunc)(GabbleJingleSession *sess, - GabbleJingleContent *c, WockyNode *content_node, gpointer user_data, - GError **error); - -static gboolean -extract_reason (WockyNode *node, JingleReason *reason, gchar **message) -{ - JingleReason _reason = JINGLE_REASON_UNKNOWN; - WockyNode *child; - WockyNodeIter iter; - - g_return_val_if_fail (node != NULL, FALSE); - - if (message != NULL) - *message = g_strdup (wocky_node_get_content_from_child (node, "text")); - - wocky_node_iter_init (&iter, node, NULL, NULL); - - while (wocky_node_iter_next (&iter, &child)) - { - if (wocky_enum_from_nick ( - jingle_reason_get_type (), child->name, (gint *) &_reason)) - { - if (reason != NULL) - *reason = _reason; - return TRUE; - } - } - - return FALSE; -} - -static JingleAction -parse_action (const gchar *txt) -{ - if (txt == NULL) - return JINGLE_ACTION_UNKNOWN; - - /* synonyms, best deal with them right now */ - if (!wocky_strdiff (txt, "initiate") || - !wocky_strdiff (txt, "session-initiate")) - return JINGLE_ACTION_SESSION_INITIATE; - else if (!wocky_strdiff (txt, "terminate") || - !wocky_strdiff (txt, "session-terminate") || - !wocky_strdiff (txt, "reject")) - return JINGLE_ACTION_SESSION_TERMINATE; - else if (!wocky_strdiff (txt, "accept") || - !wocky_strdiff (txt, "session-accept")) - return JINGLE_ACTION_SESSION_ACCEPT; - else if (!wocky_strdiff (txt, "candidates") || - !wocky_strdiff (txt, "transport-info")) - return JINGLE_ACTION_TRANSPORT_INFO; - else if (!wocky_strdiff (txt, "content-accept")) - return JINGLE_ACTION_CONTENT_ACCEPT; - else if (!wocky_strdiff (txt, "content-add")) - return JINGLE_ACTION_CONTENT_ADD; - else if (!wocky_strdiff (txt, "content-modify")) - return JINGLE_ACTION_CONTENT_MODIFY; - else if (!wocky_strdiff (txt, "content-replace")) - return JINGLE_ACTION_CONTENT_REPLACE; - else if (!wocky_strdiff (txt, "content-reject")) - return JINGLE_ACTION_CONTENT_REJECT; - else if (!wocky_strdiff (txt, "content-remove")) - return JINGLE_ACTION_CONTENT_REMOVE; - else if (!wocky_strdiff (txt, "session-info")) - return JINGLE_ACTION_SESSION_INFO; - else if (!wocky_strdiff (txt, "transport-accept")) - return JINGLE_ACTION_TRANSPORT_ACCEPT; - else if (!wocky_strdiff (txt, "description-info")) - return JINGLE_ACTION_DESCRIPTION_INFO; - else if (!wocky_strdiff (txt, "info")) - return JINGLE_ACTION_INFO; - - return JINGLE_ACTION_UNKNOWN; -} - -static const gchar * -produce_action (JingleAction action, JingleDialect dialect) -{ - gboolean gmode = (dialect == JINGLE_DIALECT_GTALK3) || - (dialect == JINGLE_DIALECT_GTALK4); - - g_return_val_if_fail (action != JINGLE_ACTION_UNKNOWN, NULL); - - switch (action) { - case JINGLE_ACTION_SESSION_INITIATE: - return (gmode) ? "initiate" : "session-initiate"; - case JINGLE_ACTION_SESSION_TERMINATE: - return (gmode) ? "terminate" : "session-terminate"; - case JINGLE_ACTION_SESSION_ACCEPT: - return (gmode) ? "accept" : "session-accept"; - case JINGLE_ACTION_TRANSPORT_INFO: - return (dialect == JINGLE_DIALECT_GTALK3) ? - "candidates" : "transport-info"; - case JINGLE_ACTION_CONTENT_ACCEPT: - return "content-accept"; - case JINGLE_ACTION_CONTENT_ADD: - return "content-add"; - case JINGLE_ACTION_CONTENT_MODIFY: - return "content-modify"; - case JINGLE_ACTION_CONTENT_REMOVE: - return "content-remove"; - case JINGLE_ACTION_CONTENT_REPLACE: - return "content-replace"; - case JINGLE_ACTION_CONTENT_REJECT: - return "content-reject"; - case JINGLE_ACTION_SESSION_INFO: - return "session-info"; - case JINGLE_ACTION_TRANSPORT_ACCEPT: - return "transport-accept"; - case JINGLE_ACTION_DESCRIPTION_INFO: - return "description-info"; - case JINGLE_ACTION_INFO: - return "info"; - default: - /* only reached if g_return_val_if_fail is disabled */ - DEBUG ("unknown action %u", action); - return NULL; - } -} - -static gboolean -action_is_allowed (JingleAction action, JingleState state) -{ - guint i; - - for (i = 0; allowed_actions[state][i] != JINGLE_ACTION_UNKNOWN; i++) - { - if (allowed_actions[state][i] == action) - return TRUE; - } - - return FALSE; -} - -static void gabble_jingle_session_send_rtp_info (GabbleJingleSession *sess, - const gchar *name); -static void set_state (GabbleJingleSession *sess, - JingleState state, JingleReason termination_reason, const gchar *text); -static GabbleJingleContent *_get_any_content (GabbleJingleSession *session); - -gboolean -gabble_jingle_session_peer_has_cap ( - GabbleJingleSession *self, - const gchar *cap_or_quirk) -{ - GabbleJingleSessionPrivate *priv = self->priv; - gboolean ret; - - g_signal_emit (self, signals[QUERY_CAP], 0, - priv->peer_contact, cap_or_quirk, - &ret); - return ret; -} - -static gboolean -lookup_content (GabbleJingleSession *sess, - const gchar *name, - const gchar *creator, - gboolean fail_if_missing, - GabbleJingleContent **c, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - if (name == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "'name' attribute unset"); - return FALSE; - } - - if (JINGLE_IS_GOOGLE_DIALECT (priv->dialect)) - { - /* Only the initiator can create contents on GTalk. */ - *c = g_hash_table_lookup (priv->initiator_contents, name); - } - else - { - /* Versions of Gabble between 0.7.16 and 0.7.28 (inclusive) omitted the - * 'creator' attribute from transport-info (and possibly other) stanzas. - * We try to detect contacts using such a version of Gabble from their - * caps; if 'creator' is missing and the peer has that caps flag, we look - * up the content in both hashes. - * - * While this doesn't deal with the case where the content is found in - * both hashes, this isn't a problem in practice: the versions of Gabble - * we're working around didn't allow this to happen (they'd either reject - * the second stream, or let it replace the first, depending on the phase - * of the moon, and get kind of confused in the process), and we try to - * pick globally-unique content names. - */ - if (creator == NULL && - gabble_jingle_session_peer_has_cap (sess, - QUIRK_OMITS_CONTENT_CREATORS)) - { - DEBUG ("working around missing 'creator' attribute"); - - *c = g_hash_table_lookup (priv->initiator_contents, name); - - if (*c == NULL) - *c = g_hash_table_lookup (priv->responder_contents, name); - } - else if (!wocky_strdiff (creator, "initiator")) - { - *c = g_hash_table_lookup (priv->initiator_contents, name); - } - else if (!wocky_strdiff (creator, "responder")) - { - *c = g_hash_table_lookup (priv->responder_contents, name); - } - else - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "'creator' attribute %s", - (creator == NULL ? "missing" : "invalid")); - return FALSE; - } - } - - if (fail_if_missing && *c == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "Content '%s' (created by %s) does not exist", name, creator); - return FALSE; - } - - return TRUE; -} - -static void -_foreach_content (GabbleJingleSession *sess, - WockyNode *node, - gboolean fail_if_missing, - ContentHandlerFunc func, - gpointer user_data, - GError **error) -{ - GabbleJingleContent *c; - WockyNode *content_node; - WockyNodeIter iter; - - wocky_node_iter_init (&iter, node, "content", NULL); - while (wocky_node_iter_next (&iter, &content_node)) - { - if (!lookup_content (sess, - wocky_node_get_attribute (content_node, "name"), - wocky_node_get_attribute (content_node, "creator"), - fail_if_missing, &c, error)) - return; - - func (sess, c, content_node, user_data, error); - if (*error != NULL) - return; - } -} - -struct idle_content_reject_ctx { - GabbleJingleSession *session; - gchar *creator; - gchar *name; -}; - -static gboolean -idle_content_reject (gpointer data) -{ - WockyStanza *msg; - WockyNode *sess_node, *node; - struct idle_content_reject_ctx *ctx = data; - - msg = gabble_jingle_session_new_message (ctx->session, - JINGLE_ACTION_CONTENT_REJECT, &sess_node); - - g_debug ("name = %s, intiiator = %s", ctx->name, ctx->creator); - - node = wocky_node_add_child_with_content (sess_node, "content", NULL); - wocky_node_set_attributes (node, - "name", ctx->name, "creator", ctx->creator, NULL); - - gabble_jingle_session_send (ctx->session, msg); - - g_object_unref (ctx->session); - g_free (ctx->name); - g_free (ctx->creator); - g_free (ctx); - - return FALSE; -} - -static void -fire_idle_content_reject (GabbleJingleSession *sess, const gchar *name, - const gchar *creator) -{ - struct idle_content_reject_ctx *ctx = g_new0 (struct idle_content_reject_ctx, 1); - - if (creator == NULL) - creator = ""; - - ctx->session = g_object_ref (sess); - ctx->name = g_strdup (name); - ctx->creator = g_strdup (creator); - - /* FIXME: add API for ordering IQs rather than using g_idle_add. */ - g_idle_add (idle_content_reject, ctx); -} - -static GabbleJingleContent * -create_content (GabbleJingleSession *sess, GType content_type, - JingleMediaType type, JingleContentSenders senders, - const gchar *content_ns, const gchar *transport_ns, - const gchar *name, WockyNode *content_node, GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - GabbleJingleContent *c; - GHashTable *contents; - - DEBUG ("session creating new content name %s, type %d", name, type); - - /* FIXME: media-type is introduced by GabbleJingleMediaRTP, not by the - * superclass, so this call is unsafe in the general case */ - c = g_object_new (content_type, - "session", sess, - "content-ns", content_ns, - "transport-ns", transport_ns, - "media-type", type, - "name", name, - "disposition", "session", - "senders", senders, - NULL); - - g_signal_connect (c, "ready", - (GCallback) content_ready_cb, sess); - g_signal_connect (c, "removed", - (GCallback) content_removed_cb, sess); - - /* if we are called by parser, parse content add */ - if (content_node != NULL) - { - gabble_jingle_content_parse_add (c, content_node, - JINGLE_IS_GOOGLE_DIALECT (priv->dialect), error); - - if (*error != NULL) - { - g_object_unref (c); - return NULL; - } - - /* gtalk streams don't have name, so use whatever Content came up with */ - if (name == NULL) - name = gabble_jingle_content_get_name (c); - } - - if (priv->local_initiator == gabble_jingle_content_is_created_by_us (c)) - { - DEBUG ("inserting content %s into initiator_contents", name); - contents = priv->initiator_contents; - } - else - { - DEBUG ("inserting content %s into responder_contents", name); - contents = priv->responder_contents; - } - - /* If the content already existed, either we shouldn't have picked the name - * we did (if we're creating it) or _each_content_add should have already - * said no. - */ - g_assert (g_hash_table_lookup (contents, name) == NULL); - g_hash_table_insert (contents, g_strdup (name), c); - g_signal_emit (sess, signals[NEW_CONTENT], 0, c); - return c; -} - - -static void -_each_content_add (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - const gchar *name = wocky_node_get_attribute (content_node, "name"); - WockyNode *desc_node = wocky_node_get_child (content_node, - "description"); - GType content_type = 0; - const gchar *content_ns = NULL; - - if (desc_node != NULL) - { - content_ns = wocky_node_get_ns (desc_node); - DEBUG ("namespace: %s", content_ns); - content_type = gabble_jingle_factory_lookup_content_type ( - gabble_jingle_session_get_factory (sess), - content_ns); - } - - if (content_type == 0) - { - /* if this is session-initiate, we should return error, otherwise, - * we should respond with content-reject */ - if (priv->state < JINGLE_STATE_PENDING_INITIATED) - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "unsupported content type with ns %s", content_ns); - else - fire_idle_content_reject (sess, name, - wocky_node_get_attribute (content_node, "creator")); - - return; - } - - if (c != NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "content '%s' already exists", name); - return; - } - - create_content (sess, content_type, JINGLE_MEDIA_TYPE_NONE, - JINGLE_CONTENT_SENDERS_BOTH, content_ns, NULL, NULL, content_node, - error); -} - -static void -_each_content_remove (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - g_assert (c != NULL); - - gabble_jingle_content_remove (c, FALSE); -} - -static void -_each_content_rejected (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - JingleReason reason = GPOINTER_TO_UINT (user_data); - g_assert (c != NULL); - - g_signal_emit (sess, signals[CONTENT_REJECTED], 0, c, reason, ""); - - gabble_jingle_content_remove (c, FALSE); -} - -static void -_each_content_modify (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - g_assert (c != NULL); - - gabble_jingle_content_update_senders (c, content_node, error); - - if (*error != NULL) - return; -} - -static void -_each_content_replace (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - _each_content_remove (sess, c, content_node, NULL, error); - - if (*error != NULL) - return; - - _each_content_add (sess, c, content_node, NULL, error); -} - -static void -_each_content_accept (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - JingleContentState state; - - g_assert (c != NULL); - - g_object_get (c, "state", &state, NULL); - if (state != JINGLE_CONTENT_STATE_SENT) - { -#ifdef ENABLE_DEBUG - const gchar *name = wocky_node_get_attribute (content_node, "name"); - DEBUG ("ignoring content \"%s\"s acceptance for content not in SENT state", name); -#endif - return; - } - - gabble_jingle_content_parse_accept (c, content_node, - JINGLE_IS_GOOGLE_DIALECT (priv->dialect), error); -} - -static void -_each_description_info (GabbleJingleSession *sess, GabbleJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - gabble_jingle_content_parse_description_info (c, content_node, error); -} - -static void -on_session_initiate (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - /* we can't call ourselves at the moment */ - if (priv->local_initiator) - { - /* We ignore initiate from us, and terminate the session immediately - * afterwards */ - gabble_jingle_session_terminate (sess, JINGLE_REASON_BUSY, NULL, NULL); - return; - } - - if ((priv->dialect == JINGLE_DIALECT_GTALK3)) - { - const gchar *content_ns = NULL; - WockyNode *desc_node = - wocky_node_get_child (node, "description"); - content_ns = wocky_node_get_ns (desc_node); - - if (!wocky_strdiff (content_ns, NS_GOOGLE_SESSION_VIDEO)) - { - GabbleJingleFactory *factory = - gabble_jingle_session_get_factory (sess); - GType content_type = 0; - - DEBUG ("GTalk v3 session with audio and video"); - - /* audio and video content */ - content_type = gabble_jingle_factory_lookup_content_type ( - factory, content_ns); - create_content (sess, content_type, JINGLE_MEDIA_TYPE_VIDEO, - JINGLE_CONTENT_SENDERS_BOTH, NS_GOOGLE_SESSION_VIDEO, NULL, - "video", node, error); - - content_type = gabble_jingle_factory_lookup_content_type ( - factory, NS_GOOGLE_SESSION_PHONE); - create_content (sess, content_type, JINGLE_MEDIA_TYPE_AUDIO, - JINGLE_CONTENT_SENDERS_BOTH, NS_GOOGLE_SESSION_PHONE, NULL, - "audio", node, error); - } - else - { - _each_content_add (sess, NULL, node, NULL, error); - } - } - else if (priv->dialect == JINGLE_DIALECT_GTALK4) - { - /* in this case we implicitly have just one content */ - _each_content_add (sess, NULL, node, NULL, error); - } - else - { - _foreach_content (sess, node, FALSE, _each_content_add, NULL, error); - } - - if (*error == NULL) - { - /* FIXME: contents defined here should always have "session" content - * disposition; resolve this as soon as the proper procedure is defined - * in XEP-0166. */ - - set_state (sess, JINGLE_STATE_PENDING_INITIATED, JINGLE_REASON_UNKNOWN, - NULL); - - gabble_jingle_session_send_rtp_info (sess, "ringing"); - } -} - -static void -on_content_add (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, FALSE, _each_content_add, NULL, error); -} - -static void -on_content_modify (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_modify, NULL, error); -} - -static void -on_content_remove (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_remove, NULL, error); -} - -static void -on_content_replace (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_replace, NULL, error); -} - -static void -on_content_reject (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - WockyNode *n = wocky_node_get_child (node, "reason"); - JingleReason reason = JINGLE_REASON_UNKNOWN; - - DEBUG (" "); - - if (n != NULL) - extract_reason (n, &reason, NULL); - - if (reason == JINGLE_REASON_UNKNOWN) - reason = JINGLE_REASON_GENERAL_ERROR; - - _foreach_content (sess, node, TRUE, _each_content_rejected, - GUINT_TO_POINTER (reason), error); -} - -static void -on_content_accept (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_accept, NULL, error); -} - -static void -on_session_accept (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - DEBUG ("called"); - - if ((priv->dialect == JINGLE_DIALECT_GTALK3) || - (priv->dialect == JINGLE_DIALECT_GTALK4)) - { - /* Google Talk calls don't have contents per se; they just have - * <payload-type>s in different namespaces for audio and video, in the - * same <description> stanza. So we need to feed the whole stanza to each - * content in turn. - */ - GList *cs = gabble_jingle_session_get_contents (sess); - GList *l; - - for (l = cs; l != NULL; l = l->next) - _each_content_accept (sess, l->data, node, NULL, error); - - g_list_free (cs); - } - else - { - _foreach_content (sess, node, TRUE, _each_content_accept, NULL, error); - } - - if (*error != NULL) - return; - - set_state (sess, JINGLE_STATE_ACTIVE, JINGLE_REASON_UNKNOWN, NULL); - - /* Make sure each content knows the session is active */ - g_list_foreach (gabble_jingle_session_get_contents (sess), - (GFunc) g_object_notify, "state"); - - - if (priv->dialect != JINGLE_DIALECT_V032) - { - /* If this is a dialect that doesn't support <active/>, we treat - * session-accept as the cue to remove the ringing flag. - */ - priv->remote_ringing = FALSE; - g_signal_emit (sess, signals[REMOTE_STATE_CHANGED], 0); - } -} - -static void -mute_all_foreach (gpointer key, - gpointer value, - gpointer mute) -{ - if (G_OBJECT_TYPE (value) == GABBLE_TYPE_JINGLE_MEDIA_RTP) - g_object_set (value, "remote-mute", GPOINTER_TO_INT (mute), NULL); -} - -static void -mute_all (GabbleJingleSession *sess, - gboolean mute) -{ - g_hash_table_foreach (sess->priv->initiator_contents, mute_all_foreach, - GINT_TO_POINTER (mute)); - g_hash_table_foreach (sess->priv->responder_contents, mute_all_foreach, - GINT_TO_POINTER (mute)); -} - -static gboolean -set_mute (GabbleJingleSession *sess, - const gchar *name, - const gchar *creator, - gboolean mute, - GError **error) -{ - GabbleJingleContent *c; - - if (name == NULL) - { - mute_all (sess, mute); - return TRUE; - } - - if (!lookup_content (sess, name, creator, TRUE /* fail if missing */, &c, - error)) - return FALSE; - - if (G_OBJECT_TYPE (c) != GABBLE_TYPE_JINGLE_MEDIA_RTP) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "content '%s' isn't an RTP session", name); - return FALSE; - } - - g_object_set (c, "remote-mute", mute, NULL); - return TRUE; -} - -static void -set_hold (GabbleJingleSession *sess, - gboolean hold) -{ - sess->priv->remote_hold = hold; -} - -static void -set_ringing (GabbleJingleSession *sess, - gboolean ringing) -{ - sess->priv->remote_ringing = ringing; -} - -static gboolean -handle_payload (GabbleJingleSession *sess, - WockyNode *payload, - gboolean *handled, - GError **error) -{ - const gchar *ns = wocky_node_get_ns (payload); - const gchar *elt = payload->name; - const gchar *name = wocky_node_get_attribute (payload, "name"); - const gchar *creator = wocky_node_get_attribute (payload, "creator"); - - if (wocky_strdiff (ns, NS_JINGLE_RTP_INFO)) - { - *handled = FALSE; - return TRUE; - } - - *handled = TRUE; - - if (!wocky_strdiff (elt, "active")) - { - /* Clear all states, we're active */ - mute_all (sess, FALSE); - set_ringing (sess, FALSE); - set_hold (sess, FALSE); - } - else if (!wocky_strdiff (elt, "ringing")) - { - set_ringing (sess, TRUE); - } - else if (!wocky_strdiff (elt, "hold")) - { - set_hold (sess, TRUE); - } - else if (!wocky_strdiff (elt, "unhold")) - { - set_hold (sess, FALSE); - } - /* XEP-0178 says that only <mute/> and <unmute/> can have a name='' - * attribute. - */ - else if (!wocky_strdiff (elt, "mute")) - { - return set_mute (sess, name, creator, TRUE, error); - } - else if (!wocky_strdiff (elt, "unmute")) - { - return set_mute (sess, name, creator, FALSE, error); - } - else - { - g_set_error (error, WOCKY_JINGLE_ERROR, - WOCKY_JINGLE_ERROR_UNSUPPORTED_INFO, - "<%s> is not known in namespace %s", elt, ns); - return FALSE; - } - - return TRUE; -} - -static void -on_session_info (GabbleJingleSession *sess, - WockyNode *node, - GError **error) -{ - gboolean understood_a_payload = FALSE; - gboolean hit_an_error = FALSE; - WockyNodeIter i; - WockyNode *n; - - /* if this is a ping, just ack it. */ - if (wocky_node_get_first_child (node) == NULL) - return; - - wocky_node_iter_init (&i, node, NULL, NULL); - while (wocky_node_iter_next (&i, &n)) - { - gboolean handled; - GError *e = NULL; - - if (handle_payload (sess, n, &handled, &e)) - { - understood_a_payload = understood_a_payload || handled; - } - else if (hit_an_error) - { - DEBUG ("already got another error; ignoring %s", e->message); - g_error_free (e); - } - else - { - DEBUG ("hit an error: %s", e->message); - hit_an_error = TRUE; - g_propagate_error (error, e); - } - } - - /* If we understood something, the remote state (may have) changed. Else, - * return an error to the peer. - */ - if (understood_a_payload) - g_signal_emit (sess, signals[REMOTE_STATE_CHANGED], 0); - else if (!hit_an_error) - g_set_error (error, WOCKY_JINGLE_ERROR, WOCKY_JINGLE_ERROR_UNSUPPORTED_INFO, - "no recognized session-info payloads"); -} - -static void -on_session_terminate (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - gchar *text = NULL; - WockyNode *n = wocky_node_get_child (node, "reason"); - JingleReason jingle_reason = JINGLE_REASON_UNKNOWN; - - if (n != NULL) - extract_reason (n, &jingle_reason, &text); - - DEBUG ("remote end terminated the session with reason %s and text '%s'", - gabble_jingle_session_get_reason_name (jingle_reason), - (text != NULL ? text : "(none)")); - - set_state (sess, JINGLE_STATE_ENDED, jingle_reason, text); - - g_free (text); -} - -static void -on_transport_info (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - GabbleJingleContent *c = NULL; - - if (JINGLE_IS_GOOGLE_DIALECT (priv->dialect)) - { - GHashTableIter iter; - gpointer value; - - if (priv->dialect == JINGLE_DIALECT_GTALK4) - { - if (!wocky_strdiff (wocky_node_get_attribute (node, "type"), - "candidates")) - { - GList *contents = gabble_jingle_session_get_contents (sess); - GList *l; - - DEBUG ("switching to gtalk3 dialect and retransmiting our candidates"); - priv->dialect = JINGLE_DIALECT_GTALK3; - - for (l = contents; l != NULL; l = l->next) - gabble_jingle_content_retransmit_candidates (l->data, TRUE); - - g_list_free (contents); - } - else - { - node = wocky_node_get_child (node, "transport"); - - if (node == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "transport-info stanza without a <transport/>"); - return; - } - } - } - - g_hash_table_iter_init (&iter, priv->initiator_contents); - while (g_hash_table_iter_next (&iter, NULL, &value)) - { - c = value; - gabble_jingle_content_parse_transport_info (c, node, error); - if (error != NULL && *error != NULL) - break; - } - } - else - { - WockyNodeIter i; - WockyNode *content_node; - GError *e = NULL; - - wocky_node_iter_init (&i, node, "content", NULL); - - while (wocky_node_iter_next (&i, &content_node)) - { - WockyNode *transport_node; - - if (lookup_content (sess, - wocky_node_get_attribute (content_node, "name"), - wocky_node_get_attribute (content_node, "creator"), - TRUE /* fail_if_missing */, &c, &e)) - { - /* we need transport child of content node */ - transport_node = wocky_node_get_child ( - content_node, "transport"); - gabble_jingle_content_parse_transport_info (c, - transport_node, &e); - } - - /* Save the first error we encounter, but go through all remaining - * contents anyway to try and recover as much info as we can */ - if (e != NULL && error != NULL && *error == NULL) - { - *error = e; - e = NULL; - } - g_clear_error (&e); - } - } - -} - -static void -on_transport_accept (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - DEBUG ("Ignoring 'transport-accept' action from peer"); -} - -static void -on_description_info (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_description_info, NULL, error); -} - -static void -on_info (GabbleJingleSession *sess, WockyNode *node, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - GabbleJingleContent *c = NULL; - - DEBUG ("received info "); - if (JINGLE_IS_GOOGLE_DIALECT (priv->dialect)) - { - GHashTableIter iter; - g_hash_table_iter_init (&iter, priv->initiator_contents); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &c)) - { - gabble_jingle_content_parse_info (c, node, error); - if (error != NULL && *error != NULL) - break; - } - } -} - -static HandlerFunc handlers[] = { - NULL, /* for unknown action */ - on_content_accept, - on_content_add, - on_content_modify, - on_content_remove, - on_content_replace, - on_content_reject, - on_session_accept, /* jingle_on_session_accept */ - on_session_info, - on_session_initiate, - on_session_terminate, /* jingle_on_session_terminate */ - on_transport_info, /* jingle_on_transport_info */ - on_transport_accept, - on_description_info, - on_info -}; - -static void -jingle_state_machine_dance (GabbleJingleSession *sess, - JingleAction action, - WockyNode *node, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - /* parser should've checked this already */ - g_assert (action_is_allowed (action, priv->state)); - g_assert (handlers[action] != NULL); - - handlers[action] (sess, node, error); -} - -static JingleDialect -detect_google_dialect (WockyNode *session_node) -{ - /* The GTALK3 dialect is the only one that supports video at this time */ - if (wocky_node_get_child_ns (session_node, - "description", NS_GOOGLE_SESSION_VIDEO) != NULL) - return JINGLE_DIALECT_GTALK3; - - /* GTalk4 has a transport item, GTalk3 doesn't */ - if (wocky_node_get_child_ns (session_node, - "transport", NS_GOOGLE_TRANSPORT_P2P) == NULL) - return JINGLE_DIALECT_GTALK3; - - return JINGLE_DIALECT_GTALK4; -} - -const gchar * -gabble_jingle_session_detect ( - WockyStanza *stanza, - JingleAction *action, - JingleDialect *dialect) -{ - const gchar *actxt, *sid; - WockyNode *iq_node, *session_node; - WockyStanzaSubType sub_type; - gboolean google_mode = FALSE; - - /* all jingle actions are sets */ - wocky_stanza_get_type_info (stanza, NULL, &sub_type); - if (sub_type != WOCKY_STANZA_SUB_TYPE_SET) - return NULL; - - iq_node = wocky_stanza_get_top_node (stanza); - - if ((NULL == wocky_stanza_get_from (stanza)) || - (NULL == wocky_stanza_get_to (stanza))) - return NULL; - - /* first, we try standard jingle */ - session_node = wocky_node_get_child_ns (iq_node, "jingle", NS_JINGLE032); - - if (session_node != NULL) - { - *dialect = JINGLE_DIALECT_V032; - } - else - { - /* then, we try a bit older jingle version */ - session_node = wocky_node_get_child_ns (iq_node, "jingle", NS_JINGLE015); - - if (session_node != NULL) - { - *dialect = JINGLE_DIALECT_V015; - } - else - { - /* next, we try googletalk */ - session_node = wocky_node_get_child_ns (iq_node, - "session", NS_GOOGLE_SESSION); - - if (session_node != NULL) - { - *dialect = detect_google_dialect (session_node); - google_mode = TRUE; - } - else - { - return NULL; - } - } - } - - if (google_mode) - { - actxt = wocky_node_get_attribute (session_node, "type"); - sid = wocky_node_get_attribute (session_node, "id"); - } - else - { - actxt = wocky_node_get_attribute (session_node, "action"); - sid = wocky_node_get_attribute (session_node, "sid"); - } - - *action = parse_action (actxt); - - return sid; -} - -gboolean -gabble_jingle_session_parse ( - GabbleJingleSession *sess, - JingleAction action, - WockyStanza *stanza, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - WockyNode *iq_node, *session_node; - const gchar *from, *action_name; - - /* IQ from/to can come in handy */ - from = wocky_stanza_get_from (stanza); - iq_node = wocky_stanza_get_top_node (stanza); - - if (action == JINGLE_ACTION_UNKNOWN) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "unknown session action"); - return FALSE; - } - - action_name = produce_action (action, priv->dialect); - - DEBUG ("jingle action '%s' from '%s' in session '%s' dialect %u state %u", - action_name, from, priv->sid, priv->dialect, priv->state); - - switch (priv->dialect) { - case JINGLE_DIALECT_V032: - session_node = wocky_node_get_child_ns (iq_node, - "jingle", NS_JINGLE032); - break; - case JINGLE_DIALECT_V015: - session_node = wocky_node_get_child_ns (iq_node, - "jingle", NS_JINGLE015); - break; - case JINGLE_DIALECT_GTALK3: - case JINGLE_DIALECT_GTALK4: - session_node = wocky_node_get_child_ns (iq_node, - "session", NS_GOOGLE_SESSION); - break; - default: - /* just to make gcc happy about dealing with default case */ - session_node = NULL; - } - - if (session_node == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "malformed jingle stanza"); - return FALSE; - } - - if (!gabble_jingle_session_defines_action (sess, action)) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "action '%s' unknown (using dialect %u)", action_name, priv->dialect); - return FALSE; - } - - if (!action_is_allowed (action, priv->state)) - { - g_set_error (error, WOCKY_JINGLE_ERROR, WOCKY_JINGLE_ERROR_OUT_OF_ORDER, - "action '%s' not allowed in current state", action_name); - return FALSE; - } - - jingle_state_machine_dance (sess, action, session_node, error); - - if (*error != NULL) - return FALSE; - - return TRUE; -} - -WockyStanza * -gabble_jingle_session_new_message (GabbleJingleSession *sess, - JingleAction action, WockyNode **sess_node) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - WockyStanza *stanza; - WockyNode *session_node; - gchar *el = NULL, *ns = NULL; - gboolean gtalk_mode = FALSE; - - g_return_val_if_fail (action != JINGLE_ACTION_UNKNOWN, NULL); - - g_assert ((action == JINGLE_ACTION_SESSION_INITIATE) || - (priv->state > JINGLE_STATE_PENDING_CREATED)); - g_assert (GABBLE_IS_JINGLE_SESSION (sess)); - - switch (priv->dialect) - { - case JINGLE_DIALECT_V032: - el = "jingle"; - ns = NS_JINGLE032; - break; - case JINGLE_DIALECT_V015: - el = "jingle"; - ns = NS_JINGLE015; - break; - case JINGLE_DIALECT_GTALK3: - case JINGLE_DIALECT_GTALK4: - el = "session"; - ns = NS_GOOGLE_SESSION; - gtalk_mode = TRUE; - break; - case JINGLE_DIALECT_ERROR: - g_assert_not_reached (); - } - - stanza = wocky_stanza_build ( - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - NULL, priv->peer_jid, - '(', el, ':', ns, - '*', &session_node, - ')', NULL); - - wocky_node_set_attributes (session_node, - "initiator", priv->initiator, - (gtalk_mode) ? "id" : "sid", priv->sid, - (gtalk_mode) ? "type" : "action", - produce_action (action, priv->dialect), - NULL); - - if (sess_node != NULL) - *sess_node = session_node; - - return stanza; -} - -typedef void (*ContentMapperFunc) (GabbleJingleSession *sess, - GabbleJingleContent *c, gpointer user_data); - -static void -_map_initial_contents (GabbleJingleSession *sess, ContentMapperFunc mapper, - gpointer user_data) -{ - GList *li; - GList *contents = gabble_jingle_session_get_contents (sess); - - for (li = contents; li; li = li->next) - { - GabbleJingleContent *c = GABBLE_JINGLE_CONTENT (li->data); - const gchar *disposition = gabble_jingle_content_get_disposition (c); - - if (!wocky_strdiff (disposition, "session")) - mapper (sess, c, user_data); - } - - g_list_free (contents); -} - -static void -_check_content_ready (GabbleJingleSession *sess, - GabbleJingleContent *c, gpointer user_data) -{ - gboolean *ready = (gboolean *) user_data; - - if (!gabble_jingle_content_is_ready (c)) - { - *ready = FALSE; - } -} - -static void -_transmit_candidates (GabbleJingleSession *sess, - GabbleJingleContent *c, - gpointer user_data) -{ - gabble_jingle_content_retransmit_candidates (c, FALSE); -} - -static void -_fill_content (GabbleJingleSession *sess, - GabbleJingleContent *c, gpointer user_data) -{ - WockyNode *sess_node = user_data; - WockyNode *transport_node; - JingleContentState state; - - gabble_jingle_content_produce_node (c, sess_node, TRUE, TRUE, - &transport_node); - gabble_jingle_content_inject_candidates (c, transport_node); - - g_object_get (c, "state", &state, NULL); - - if (state == JINGLE_CONTENT_STATE_EMPTY) - { - g_object_set (c, "state", JINGLE_CONTENT_STATE_SENT, NULL); - } - else if (state == JINGLE_CONTENT_STATE_NEW) - { - g_object_set (c, "state", JINGLE_CONTENT_STATE_ACKNOWLEDGED, NULL); - } - else - { - DEBUG ("content %p is in state %u", c, state); - g_assert_not_reached (); - } -} - -/** - * gabble_jingle_session_send: - * @sess: a session - * @stanza: (transfer full): a stanza, of which this function will take ownership - * - * A shorthand for sending a Jingle IQ without waiting for the reply. - */ -void -gabble_jingle_session_send (GabbleJingleSession *sess, - WockyStanza *stanza) -{ - wocky_porter_send_iq_async (sess->priv->porter, - stanza, NULL, NULL, NULL); - g_object_unref (stanza); -} - -static void -_on_initiate_reply ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source); - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (user_data); - GabbleJingleSessionPrivate *priv = sess->priv; - WockyStanza *reply; - - if (priv->state != JINGLE_STATE_PENDING_INITIATE_SENT) - { - DEBUG ("Ignoring session-initiate reply; session %p is in state %u.", - sess, priv->state); - g_object_unref (sess); - return; - } - - reply = wocky_porter_send_iq_finish (porter, result, NULL); - if (reply != NULL && - !wocky_stanza_extract_errors (reply, NULL, NULL, NULL, NULL)) - { - set_state (sess, JINGLE_STATE_PENDING_INITIATED, 0, NULL); - - if (priv->dialect != JINGLE_DIALECT_V032) - { - /* If this is a dialect that doesn't support <ringing/>, we treat the - * session-initiate being acked as the cue to say we're ringing. - */ - priv->remote_ringing = TRUE; - g_signal_emit (sess, signals[REMOTE_STATE_CHANGED], 0); - } - } - else - { - set_state (sess, JINGLE_STATE_ENDED, JINGLE_REASON_UNKNOWN, - NULL); - } - - g_clear_object (&reply); - g_object_unref (sess); -} - -static void -_on_accept_reply ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source); - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (user_data); - GabbleJingleSessionPrivate *priv = sess->priv; - WockyStanza *reply; - - if (priv->state != JINGLE_STATE_PENDING_ACCEPT_SENT) - { - DEBUG ("Ignoring session-accept reply; session %p is in state %u.", - sess, priv->state); - g_object_unref (sess); - return; - } - - reply = wocky_porter_send_iq_finish (porter, result, NULL); - if (reply != NULL && - !wocky_stanza_extract_errors (reply, NULL, NULL, NULL, NULL)) - { - set_state (sess, JINGLE_STATE_ACTIVE, 0, NULL); - gabble_jingle_session_send_rtp_info (sess, "active"); - } - else - { - set_state (sess, JINGLE_STATE_ENDED, JINGLE_REASON_UNKNOWN, - NULL); - } - - g_clear_object (&reply); - g_object_unref (sess); -} - -static void -try_session_initiate_or_accept (GabbleJingleSession *sess) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - WockyStanza *msg; - WockyNode *sess_node; - gboolean contents_ready = TRUE; - JingleAction action; - JingleState new_state; - GAsyncReadyCallback handler; - - DEBUG ("Trying initiate or accept"); - - /* If there are no contents yet, we shouldn't have been called at all. */ - g_assert (g_hash_table_size (priv->initiator_contents) + - g_hash_table_size (priv->responder_contents) > 0); - - if (priv->local_initiator) - { - if (priv->state != JINGLE_STATE_PENDING_CREATED) - { - DEBUG ("session is in state %u, won't try to initiate", priv->state); - return; - } - - if (!priv->locally_accepted) - { - DEBUG ("session not locally accepted yet, not initiating"); - return; - } - - g_signal_emit (sess, signals[ABOUT_TO_INITIATE], 0); - - action = JINGLE_ACTION_SESSION_INITIATE; - new_state = JINGLE_STATE_PENDING_INITIATE_SENT; - handler = _on_initiate_reply; - } - else - { - if (priv->state != JINGLE_STATE_PENDING_INITIATED) - { - DEBUG ("session is in state %u, won't try to accept", priv->state); - return; - } - - if (!priv->locally_accepted) - { - DEBUG ("session not locally accepted yet, not accepting"); - return; - } - - action = JINGLE_ACTION_SESSION_ACCEPT; - new_state = JINGLE_STATE_PENDING_ACCEPT_SENT; - handler = _on_accept_reply; - } - - _map_initial_contents (sess, _check_content_ready, &contents_ready); - - DEBUG ("Contents are ready: %s", contents_ready ? "yes" : "no"); - - if (!contents_ready) - { - DEBUG ("Contents not yet ready, not initiating/accepting now.."); - return; - } - - msg = gabble_jingle_session_new_message (sess, action, &sess_node); - - if (priv->dialect == JINGLE_DIALECT_GTALK3) - { - gboolean has_video = FALSE; - gboolean has_audio = FALSE; - GHashTableIter iter; - gpointer value; - - g_hash_table_iter_init (&iter, priv->initiator_contents); - while (g_hash_table_iter_next (&iter, NULL, &value)) - { - JingleMediaType type; - - g_object_get (value, "media-type", &type, NULL); - - if (type == JINGLE_MEDIA_TYPE_VIDEO) - { - has_video = TRUE; - } - else if (type == JINGLE_MEDIA_TYPE_AUDIO) - { - has_audio = TRUE; - } - } - - if (has_video || has_audio) - { - sess_node = wocky_node_add_child_with_content (sess_node, "description", - NULL); - - sess_node->ns = g_quark_from_static_string ( - has_video ? NS_GOOGLE_SESSION_VIDEO : NS_GOOGLE_SESSION_PHONE); - } - } - - - _map_initial_contents (sess, _fill_content, sess_node); - wocky_porter_send_iq_async (priv->porter, - msg, NULL, handler, g_object_ref (sess)); - g_object_unref (msg); - set_state (sess, new_state, 0, NULL); - - /* now all initial contents can transmit their candidates */ - _map_initial_contents (sess, _transmit_candidates, NULL); -} - -/** - * set_state: - * @sess: a jingle session - * @state: the new state for the session - * @termination_reason: if @state is JINGLE_STATE_ENDED, the reason the session - * ended. Otherwise, must be JINGLE_REASON_UNKNOWN. - * @text: if @state is JINGLE_STATE_ENDED, the human-readable reason the session - * ended. - */ -static void -set_state (GabbleJingleSession *sess, - JingleState state, - JingleReason termination_reason, - const gchar *text) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - if (state <= priv->state) - { - DEBUG ("ignoring request to set state from %u back to %u", priv->state, state); - return; - } - - if (state != JINGLE_STATE_ENDED) - g_assert (termination_reason == JINGLE_REASON_UNKNOWN); - - DEBUG ("Setting state of JingleSession: %p (priv = %p) from %u to %u", sess, priv, priv->state, state); - - priv->state = state; - g_object_notify (G_OBJECT (sess), "state"); - - /* If we have an outstanding "you're on hold notification", send it */ - if (priv->local_hold && - state >= JINGLE_STATE_PENDING_INITIATED && - state < JINGLE_STATE_ENDED) - gabble_jingle_session_send_held (sess); - - if (state == JINGLE_STATE_ENDED) - g_signal_emit (sess, signals[TERMINATED], 0, priv->locally_terminated, - termination_reason, text); -} - -void -gabble_jingle_session_accept (GabbleJingleSession *sess) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - priv->locally_accepted = TRUE; - - try_session_initiate_or_accept (sess); -} - -const gchar * -gabble_jingle_session_get_reason_name (JingleReason reason) -{ - GEnumClass *klass = g_type_class_ref (jingle_reason_get_type ()); - GEnumValue *enum_value = g_enum_get_value (klass, (gint) reason); - - g_return_val_if_fail (enum_value != NULL, NULL); - - return enum_value->value_nick; -} - -gboolean -gabble_jingle_session_terminate (GabbleJingleSession *sess, - JingleReason reason, - const gchar *text, - GError **error) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - const gchar *reason_elt; - - if (priv->state == JINGLE_STATE_ENDED) - { - DEBUG ("session already terminated, ignoring terminate request"); - return TRUE; - } - - if (reason == JINGLE_REASON_UNKNOWN) - reason = (priv->state == JINGLE_STATE_ACTIVE) ? - JINGLE_REASON_SUCCESS : JINGLE_REASON_CANCEL; - - reason_elt = gabble_jingle_session_get_reason_name (reason); - - if (priv->state != JINGLE_STATE_PENDING_CREATED) - { - WockyNode *session_node; - WockyStanza *msg = gabble_jingle_session_new_message (sess, - JINGLE_ACTION_SESSION_TERMINATE, &session_node); - - if (priv->dialect == JINGLE_DIALECT_V032 && reason_elt != NULL) - { - WockyNode *r = wocky_node_add_child_with_content (session_node, "reason", - NULL); - - wocky_node_add_child_with_content (r, reason_elt, NULL); - - if (text != NULL && *text != '\0') - wocky_node_add_child_with_content (r, "text", text); - } - - gabble_jingle_session_send (sess, msg); - } - - /* NOTE: on "terminated", jingle factory and media channel will unref - * it, bringing refcount to 0, so dispose will be called, and it - * takes care of cleanup */ - - DEBUG ("we are terminating this session"); - priv->locally_terminated = TRUE; - set_state (sess, JINGLE_STATE_ENDED, reason, text); - - return TRUE; -} - -static void -_foreach_count_active_contents (gpointer key, gpointer value, gpointer user_data) -{ - GabbleJingleContent *c = value; - guint *n_contents = user_data; - JingleContentState state; - - g_object_get (c, "state", &state, NULL); - if ((state >= JINGLE_CONTENT_STATE_NEW) && - (state < JINGLE_CONTENT_STATE_REMOVING)) - { - *n_contents = *n_contents + 1; - } -} - -static gboolean -count_active_contents (GabbleJingleSession *sess) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - guint n_contents = 0; - - g_hash_table_foreach (priv->initiator_contents, _foreach_count_active_contents, - &n_contents); - g_hash_table_foreach (priv->responder_contents, _foreach_count_active_contents, - &n_contents); - - return n_contents; -} - -static void -content_removed_cb (GabbleJingleContent *c, gpointer user_data) -{ - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (user_data); - GabbleJingleSessionPrivate *priv = sess->priv; - const gchar *name = gabble_jingle_content_get_name (c); - - if (gabble_jingle_content_creator_is_initiator (c)) - g_hash_table_remove (priv->initiator_contents, name); - else - g_hash_table_remove (priv->responder_contents, name); - - if (priv->state == JINGLE_STATE_ENDED) - return; - - if (count_active_contents (sess) == 0) - { - gabble_jingle_session_terminate (sess, - JINGLE_REASON_UNKNOWN, NULL, NULL); - } - else - { - /* It's possible the content now removed was - * blocking us from creating or accepting the - * session, so we might as well try now. */ - try_session_initiate_or_accept (sess); - } -} - - -void -gabble_jingle_session_remove_content (GabbleJingleSession *sess, - GabbleJingleContent *c) -{ - if (count_active_contents (sess) > 1) - { - gabble_jingle_content_remove (c, TRUE); - } - else - { - /* session will be terminated when the content gets marked as removed */ - DEBUG ("called for last active content, doing session-terminate instead"); - gabble_jingle_content_remove (c, FALSE); - } -} - -GabbleJingleContent * -gabble_jingle_session_add_content (GabbleJingleSession *sess, - JingleMediaType mtype, - JingleContentSenders senders, - const gchar *name, - const gchar *content_ns, - const gchar *transport_ns) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - GabbleJingleContent *c; - GType content_type; - GHashTable *contents = priv->local_initiator ? priv->initiator_contents - : priv->responder_contents; - guint id = g_hash_table_size (contents) + 1; - gchar *cname = NULL; - - if (name == NULL || *name == '\0') - name = (mtype == JINGLE_MEDIA_TYPE_AUDIO ? "Audio" : "Video"); - - cname = g_strdup (name); - - while (g_hash_table_lookup (priv->initiator_contents, cname) != NULL - || g_hash_table_lookup (priv->responder_contents, cname) != NULL) - { - g_free (cname); - cname = g_strdup_printf ("%s_%d", name, id++); - } - - content_type = gabble_jingle_factory_lookup_content_type ( - gabble_jingle_session_get_factory (sess), - content_ns); - - g_assert (content_type != 0); - - c = create_content (sess, content_type, mtype, senders, - content_ns, transport_ns, cname, NULL, NULL); - - /* The new content better have ended up in the set we thought it would... */ - g_assert (g_hash_table_lookup (contents, cname) != NULL); - - g_free (cname); - - return c; -} - -/* Get any content. Either we're in google mode (so we only have one content - * anyways), or we just need any content type to figure out what use case - * we're in (media, ft, etc). */ -static GabbleJingleContent * -_get_any_content (GabbleJingleSession *session) -{ - GabbleJingleContent *c; - - GList *li = gabble_jingle_session_get_contents (session); - - if (li == NULL) - return NULL; - - c = li->data; - g_list_free (li); - - return c; -} - -/* Note: if there are multiple content types, not guaranteed which one will - * be returned. Typically, the same GType will know how to handle related - * contents found in a session (e.g. media-rtp for audio/video), so that - * should not be a problem. Returns 0 if there are no contents yet. */ -GType -gabble_jingle_session_get_content_type (GabbleJingleSession *sess) -{ - GabbleJingleContent *c = _get_any_content (sess); - - if (c == NULL) - return 0; - - return G_OBJECT_TYPE (c); -} - -/* FIXME: probably should make this into a property */ -GList * -gabble_jingle_session_get_contents (GabbleJingleSession *sess) -{ - GabbleJingleSessionPrivate *priv = sess->priv; - - return g_list_concat (g_hash_table_get_values (priv->initiator_contents), - g_hash_table_get_values (priv->responder_contents)); -} - -const gchar * -gabble_jingle_session_get_peer_resource (GabbleJingleSession *sess) -{ - return sess->priv->peer_resource; -} - -const gchar * -gabble_jingle_session_get_initiator (GabbleJingleSession *sess) -{ - return sess->priv->initiator; -} - -const gchar * -gabble_jingle_session_get_sid (GabbleJingleSession *sess) -{ - return sess->priv->sid; -} - -static void -content_ready_cb (GabbleJingleContent *c, gpointer user_data) -{ - GabbleJingleSession *sess = GABBLE_JINGLE_SESSION (user_data); - const gchar *disposition; - - DEBUG ("called"); - - disposition = gabble_jingle_content_get_disposition (c); - /* This assertion is actually safe, because 'ready' is only emitted by - * contents with disposition "session". But this is crazy. - */ - g_assert (!wocky_strdiff (disposition, "session")); - - try_session_initiate_or_accept (sess); -} - -static void -gabble_jingle_session_send_rtp_info (GabbleJingleSession *sess, - const gchar *name) -{ - WockyStanza *message; - WockyNode *jingle, *notification; - - if (!gabble_jingle_session_defines_action (sess, JINGLE_ACTION_SESSION_INFO)) - { - DEBUG ("Not sending <%s/>; not using modern Jingle", name); - return; - } - - message = gabble_jingle_session_new_message (sess, - JINGLE_ACTION_SESSION_INFO, &jingle); - - notification = wocky_node_add_child_with_content (jingle, name, NULL); - notification->ns = g_quark_from_static_string (NS_JINGLE_RTP_INFO); - - /* This is just informational, so ignoring the reply. */ - gabble_jingle_session_send (sess, message); -} - -static void -gabble_jingle_session_send_held (GabbleJingleSession *sess) -{ - const gchar *s = (sess->priv->local_hold ? "hold" : "unhold"); - - gabble_jingle_session_send_rtp_info (sess, s); -} - -void -gabble_jingle_session_set_local_hold (GabbleJingleSession *sess, - gboolean held) -{ - g_object_set (sess, "local-hold", held, NULL); -} - -gboolean -gabble_jingle_session_get_remote_hold (GabbleJingleSession *sess) -{ - g_assert (GABBLE_IS_JINGLE_SESSION (sess)); - - return sess->priv->remote_hold; -} - -gboolean -gabble_jingle_session_get_remote_ringing (GabbleJingleSession *sess) -{ - g_assert (GABBLE_IS_JINGLE_SESSION (sess)); - - return sess->priv->remote_ringing; -} - -gboolean -gabble_jingle_session_can_modify_contents (GabbleJingleSession *sess) -{ - return !JINGLE_IS_GOOGLE_DIALECT (sess->priv->dialect) && - !gabble_jingle_session_peer_has_cap (sess, QUIRK_GOOGLE_WEBMAIL_CLIENT); -} - -JingleDialect -gabble_jingle_session_get_dialect (GabbleJingleSession *sess) -{ - return sess->priv->dialect; -} - -WockyContact * -gabble_jingle_session_get_peer_contact (GabbleJingleSession *self) -{ - return self->priv->peer_contact; -} - -/* - * gabble_jingle_session_get_peer_jid: - * @sess: a jingle session - * - * Returns: the full JID of the remote contact. - */ -const gchar * -gabble_jingle_session_get_peer_jid (GabbleJingleSession *sess) -{ - return sess->priv->peer_jid; -} - -GabbleJingleFactory * -gabble_jingle_session_get_factory (GabbleJingleSession *self) -{ - return self->priv->jingle_factory; -} - -WockyPorter * -gabble_jingle_session_get_porter (GabbleJingleSession *self) -{ - return self->priv->porter; -} diff --git a/src/jingle-session.h b/src/jingle-session.h deleted file mode 100644 index 95bc23af1..000000000 --- a/src/jingle-session.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * jingle-session.h - Header for GabbleJingleSession - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_SESSION_H__ -#define __JINGLE_SESSION_H__ - -#include <glib-object.h> -#include <wocky/wocky.h> - -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef enum -{ - MODE_GOOGLE, - MODE_JINGLE -} GabbleMediaSessionMode; - -typedef struct _GabbleJingleSessionClass GabbleJingleSessionClass; - -GType gabble_jingle_session_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_SESSION \ - (gabble_jingle_session_get_type ()) -#define GABBLE_JINGLE_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_SESSION, \ - GabbleJingleSession)) -#define GABBLE_JINGLE_SESSION_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_SESSION, \ - GabbleJingleSessionClass)) -#define GABBLE_IS_JINGLE_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_SESSION)) -#define GABBLE_IS_JINGLE_SESSION_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_SESSION)) -#define GABBLE_JINGLE_SESSION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_SESSION, \ - GabbleJingleSessionClass)) - -struct _GabbleJingleSessionClass { - GObjectClass parent_class; -}; - -typedef struct _GabbleJingleSessionPrivate GabbleJingleSessionPrivate; - -struct _GabbleJingleSession { - GObject parent; - GabbleJingleSessionPrivate *priv; -}; - -GabbleJingleSession *gabble_jingle_session_new ( - GabbleJingleFactory *factory, - WockyPorter *porter, - const gchar *session_id, - gboolean local_initiator, - WockyContact *peer, - JingleDialect dialect, - gboolean local_hold); - -const gchar * gabble_jingle_session_detect (WockyStanza *stanza, - JingleAction *action, JingleDialect *dialect); -gboolean gabble_jingle_session_parse (GabbleJingleSession *sess, - JingleAction action, WockyStanza *stanza, GError **error); -WockyStanza *gabble_jingle_session_new_message (GabbleJingleSession *sess, - JingleAction action, WockyNode **sess_node); - -void gabble_jingle_session_accept (GabbleJingleSession *sess); -gboolean gabble_jingle_session_terminate (GabbleJingleSession *sess, - JingleReason reason, - const gchar *text, - GError **error); -void gabble_jingle_session_remove_content (GabbleJingleSession *sess, - GabbleJingleContent *c); - -GabbleJingleContent * -gabble_jingle_session_add_content (GabbleJingleSession *sess, - JingleMediaType mtype, - JingleContentSenders senders, - const char *name, - const gchar *content_ns, - const gchar *transport_ns); - -GType gabble_jingle_session_get_content_type (GabbleJingleSession *); -GList *gabble_jingle_session_get_contents (GabbleJingleSession *sess); -const gchar *gabble_jingle_session_get_peer_resource ( - GabbleJingleSession *sess); -const gchar *gabble_jingle_session_get_initiator ( - GabbleJingleSession *sess); -const gchar *gabble_jingle_session_get_sid (GabbleJingleSession *sess); -JingleDialect gabble_jingle_session_get_dialect (GabbleJingleSession *sess); - -gboolean gabble_jingle_session_can_modify_contents (GabbleJingleSession *sess); -gboolean gabble_jingle_session_peer_has_cap ( - GabbleJingleSession *self, - const gchar *cap_or_quirk); - -void gabble_jingle_session_send ( - GabbleJingleSession *sess, - WockyStanza *stanza); - -void gabble_jingle_session_set_local_hold (GabbleJingleSession *sess, - gboolean held); - -gboolean gabble_jingle_session_get_remote_hold (GabbleJingleSession *sess); - -gboolean gabble_jingle_session_get_remote_ringing (GabbleJingleSession *sess); - -gboolean gabble_jingle_session_defines_action (GabbleJingleSession *sess, - JingleAction action); - -WockyContact *gabble_jingle_session_get_peer_contact (GabbleJingleSession *self); -const gchar *gabble_jingle_session_get_peer_jid (GabbleJingleSession *sess); - -const gchar *gabble_jingle_session_get_reason_name (JingleReason reason); - -GabbleJingleFactory *gabble_jingle_session_get_factory (GabbleJingleSession *self); -WockyPorter *gabble_jingle_session_get_porter (GabbleJingleSession *self); - -#endif /* __JINGLE_SESSION_H__ */ - diff --git a/src/jingle-share.c b/src/jingle-share.c index 838888c2d..a4909f2b0 100644 --- a/src/jingle-share.c +++ b/src/jingle-share.c @@ -34,9 +34,6 @@ #include "connection.h" #include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" #include "namespaces.h" #include "util.h" @@ -68,7 +65,7 @@ G_DEFINE_TYPE (GabbleJingleShare, - gabble_jingle_share, GABBLE_TYPE_JINGLE_CONTENT); + gabble_jingle_share, WOCKY_TYPE_JINGLE_CONTENT); /* properties */ enum @@ -182,9 +179,9 @@ gabble_jingle_share_dispose (GObject *object) } -static void parse_description (GabbleJingleContent *content, +static void parse_description (WockyJingleContent *content, WockyNode *desc_node, GError **error); -static void produce_description (GabbleJingleContent *obj, +static void produce_description (WockyJingleContent *obj, WockyNode *content_node); @@ -200,7 +197,7 @@ gabble_jingle_share_get_property (GObject *object, switch (property_id) { case PROP_MEDIA_TYPE: - g_value_set_uint (value, JINGLE_MEDIA_TYPE_NONE); + g_value_set_uint (value, WOCKY_JINGLE_MEDIA_TYPE_NONE); break; case PROP_FILENAME: g_value_set_string (value, priv->filename); @@ -232,7 +229,7 @@ gabble_jingle_share_set_property (GObject *object, priv->filename = g_value_dup_string (value); free_manifest (self); /* simulate a media_ready when we know our own filename */ - _gabble_jingle_content_set_media_ready (GABBLE_JINGLE_CONTENT (self)); + _wocky_jingle_content_set_media_ready (WOCKY_JINGLE_CONTENT (self)); break; case PROP_FILESIZE: priv->filesize = g_value_get_uint64 (value); @@ -244,17 +241,17 @@ gabble_jingle_share_set_property (GObject *object, } } -static JingleContentSenders -get_default_senders (GabbleJingleContent *c) +static WockyJingleContentSenders +get_default_senders (WockyJingleContent *c) { - return JINGLE_CONTENT_SENDERS_INITIATOR; + return WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; } static void gabble_jingle_share_class_init (GabbleJingleShareClass *cls) { GObjectClass *object_class = G_OBJECT_CLASS (cls); - GabbleJingleContentClass *content_class = GABBLE_JINGLE_CONTENT_CLASS (cls); + WockyJingleContentClass *content_class = WOCKY_JINGLE_CONTENT_CLASS (cls); g_type_class_add_private (cls, sizeof (GabbleJingleSharePrivate)); @@ -271,8 +268,8 @@ gabble_jingle_share_class_init (GabbleJingleShareClass *cls) g_object_class_install_property (object_class, PROP_MEDIA_TYPE, g_param_spec_uint ("media-type", "media type", "irrelevant media type. Will always be NONE.", - JINGLE_MEDIA_TYPE_NONE, JINGLE_MEDIA_TYPE_NONE, - JINGLE_MEDIA_TYPE_NONE, + WOCKY_JINGLE_MEDIA_TYPE_NONE, WOCKY_JINGLE_MEDIA_TYPE_NONE, + WOCKY_JINGLE_MEDIA_TYPE_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_FILENAME, @@ -290,7 +287,7 @@ gabble_jingle_share_class_init (GabbleJingleShareClass *cls) } static void -parse_description (GabbleJingleContent *content, +parse_description (WockyJingleContent *content, WockyNode *desc_node, GError **error) { GabbleJingleShare *self = GABBLE_JINGLE_SHARE (content); @@ -438,11 +435,11 @@ parse_description (GabbleJingleContent *content, g_free (temp); } } - _gabble_jingle_content_set_media_ready (content); + _wocky_jingle_content_set_media_ready (content); } static void -produce_description (GabbleJingleContent *content, WockyNode *content_node) +produce_description (WockyJingleContent *content, WockyNode *content_node) { GabbleJingleShare *self = GABBLE_JINGLE_SHARE (content); GabbleJingleSharePrivate *priv = self->priv; @@ -458,11 +455,10 @@ produce_description (GabbleJingleContent *content, WockyNode *content_node) ensure_manifest (self); - desc_node = wocky_node_add_child_with_content (content_node, "description", NULL); + desc_node = wocky_node_add_child_ns (content_node, "description", + NS_GOOGLE_SESSION_SHARE); - desc_node->ns = g_quark_from_string (NS_GOOGLE_SESSION_SHARE); - - manifest_node = wocky_node_add_child_with_content (desc_node, "manifest", NULL); + manifest_node = wocky_node_add_child (desc_node, "manifest"); for (i = priv->manifest->entries; i; i = i->next) { @@ -472,9 +468,9 @@ produce_description (GabbleJingleContent *content, WockyNode *content_node) gchar *size_str, *width_str, *height_str; if (m->folder) - file_node = wocky_node_add_child_with_content (manifest_node, "folder", NULL); + file_node = wocky_node_add_child (manifest_node, "folder"); else - file_node = wocky_node_add_child_with_content (manifest_node, "file", NULL); + file_node = wocky_node_add_child (manifest_node, "file"); if (m->size > 0) { @@ -487,7 +483,7 @@ produce_description (GabbleJingleContent *content, WockyNode *content_node) if (m->image && (m->image_width > 0 || m->image_height > 0)) { - image_node = wocky_node_add_child_with_content (file_node, "image", NULL); + image_node = wocky_node_add_child (file_node, "image"); if (m->image_width > 0) { width_str = g_strdup_printf ("%d", m->image_width); @@ -504,8 +500,8 @@ produce_description (GabbleJingleContent *content, WockyNode *content_node) } } - protocol_node = wocky_node_add_child_with_content (desc_node, "protocol", NULL); - http_node = wocky_node_add_child_with_content (protocol_node, "http", NULL); + protocol_node = wocky_node_add_child (desc_node, "protocol"); + http_node = wocky_node_add_child (protocol_node, "http"); url_node = wocky_node_add_child_with_content (http_node, "url", priv->manifest->source_url); wocky_node_set_attribute (url_node, "name", "source-path"); @@ -523,10 +519,10 @@ gabble_jingle_share_get_manifest (GabbleJingleShare *self) } void -jingle_share_register (GabbleJingleFactory *factory) +jingle_share_register (WockyJingleFactory *factory) { /* GTalk video call namespace */ - gabble_jingle_factory_register_content_type (factory, + wocky_jingle_factory_register_content_type (factory, NS_GOOGLE_SESSION_SHARE, GABBLE_TYPE_JINGLE_SHARE); } diff --git a/src/jingle-share.h b/src/jingle-share.h index 27d1ecce8..06066c987 100644 --- a/src/jingle-share.h +++ b/src/jingle-share.h @@ -21,9 +21,7 @@ #define __JINGLE_SHARE_H__ #include <glib-object.h> - -#include "jingle-content.h" -#include "jingle-types.h" +#include <wocky/wocky.h> G_BEGIN_DECLS @@ -49,13 +47,14 @@ GType gabble_jingle_share_get_type (void); GabbleJingleShareClass)) struct _GabbleJingleShareClass { - GabbleJingleContentClass parent_class; + WockyJingleContentClass parent_class; }; typedef struct _GabbleJingleSharePrivate GabbleJingleSharePrivate; +typedef struct _GabbleJingleShare GabbleJingleShare; struct _GabbleJingleShare { - GabbleJingleContent parent; + WockyJingleContent parent; GabbleJingleSharePrivate *priv; }; @@ -75,7 +74,7 @@ typedef struct { GList *entries; } GabbleJingleShareManifest; -void jingle_share_register (GabbleJingleFactory *factory); +void jingle_share_register (WockyJingleFactory *factory); gchar *gabble_jingle_share_get_source_url (GabbleJingleShare *content); gchar *gabble_jingle_share_get_preview_url (GabbleJingleShare *content); diff --git a/src/jingle-tp-util.c b/src/jingle-tp-util.c index d6378f45c..212579f20 100644 --- a/src/jingle-tp-util.c +++ b/src/jingle-tp-util.c @@ -21,28 +21,28 @@ #include "jingle-tp-util.h" -JingleMediaType -jingle_media_type_from_tp (TpMediaStreamType type) +WockyJingleMediaType +wocky_jingle_media_type_from_tp (TpMediaStreamType type) { switch (type) { case TP_MEDIA_STREAM_TYPE_AUDIO: - return JINGLE_MEDIA_TYPE_AUDIO; + return WOCKY_JINGLE_MEDIA_TYPE_AUDIO; case TP_MEDIA_STREAM_TYPE_VIDEO: - return JINGLE_MEDIA_TYPE_VIDEO; + return WOCKY_JINGLE_MEDIA_TYPE_VIDEO; default: - g_return_val_if_reached (JINGLE_MEDIA_TYPE_NONE); + g_return_val_if_reached (WOCKY_JINGLE_MEDIA_TYPE_NONE); } } TpMediaStreamType -jingle_media_type_to_tp (JingleMediaType type) +wocky_jingle_media_type_to_tp (WockyJingleMediaType type) { switch (type) { - case JINGLE_MEDIA_TYPE_AUDIO: + case WOCKY_JINGLE_MEDIA_TYPE_AUDIO: return TP_MEDIA_STREAM_TYPE_AUDIO; - case JINGLE_MEDIA_TYPE_VIDEO: + case WOCKY_JINGLE_MEDIA_TYPE_VIDEO: return TP_MEDIA_STREAM_TYPE_VIDEO; default: g_return_val_if_reached (TP_MEDIA_STREAM_TYPE_AUDIO); @@ -50,9 +50,9 @@ jingle_media_type_to_tp (JingleMediaType type) } static const gchar * const relay_type_map[] = { - /* GABBLE_JINGLE_RELAY_TYPE_UDP */ "udp", - /* GABBLE_JINGLE_RELAY_TYPE_TCP */ "tcp", - /* GABBLE_JINGLE_RELAY_TYPE_TLS */ "tls", + /* WOCKY_JINGLE_RELAY_TYPE_UDP */ "udp", + /* WOCKY_JINGLE_RELAY_TYPE_TCP */ "tcp", + /* WOCKY_JINGLE_RELAY_TYPE_TLS */ "tls", }; GPtrArray * @@ -65,9 +65,9 @@ gabble_build_tp_relay_info (GPtrArray *relays) for (i = 0; i < relays->len; i++) { - GabbleJingleRelay *relay = g_ptr_array_index (relays, i); + WockyJingleRelay *relay = g_ptr_array_index (relays, i); - g_return_val_if_fail (relay->type < GABBLE_N_JINGLE_RELAY_TYPES, tp_relays); + g_return_val_if_fail (relay->type < WOCKY_N_JINGLE_RELAY_TYPES, tp_relays); g_ptr_array_add (tp_relays, tp_asv_new ( "type", G_TYPE_STRING, relay_type_map[relay->type], diff --git a/src/jingle-tp-util.h b/src/jingle-tp-util.h index f573c1132..47091c53a 100644 --- a/src/jingle-tp-util.h +++ b/src/jingle-tp-util.h @@ -21,10 +21,10 @@ #define GABBLE_JINGLE_TP_UTIL_H #include <telepathy-glib/telepathy-glib.h> -#include "jingle-content.h" +#include <wocky/wocky.h> -JingleMediaType jingle_media_type_from_tp (TpMediaStreamType type); -TpMediaStreamType jingle_media_type_to_tp (JingleMediaType type); +WockyJingleMediaType wocky_jingle_media_type_from_tp (TpMediaStreamType type); +TpMediaStreamType wocky_jingle_media_type_to_tp (WockyJingleMediaType type); GPtrArray *gabble_build_tp_relay_info (GPtrArray *relays); diff --git a/src/jingle-transport-google.c b/src/jingle-transport-google.c deleted file mode 100644 index 491036d48..000000000 --- a/src/jingle-transport-google.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * jingle-transport-google.c - Source for GabbleJingleTransportGoogle - * - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-transport-google.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (GabbleJingleTransportGoogle, - gabble_jingle_transport_google, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_JINGLE_TRANSPORT_IFACE, - transport_iface_init)); - -/* signal enum */ -enum -{ - NEW_CANDIDATES, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_CONTENT = 1, - PROP_TRANSPORT_NS, - PROP_STATE, - LAST_PROPERTY -}; - -struct _GabbleJingleTransportGooglePrivate -{ - GabbleJingleContent *content; - JingleTransportState state; - gchar *transport_ns; - - /* Component names or jingle-share transport 'channels' - g_strdup'd component name => GINT_TO_POINTER (component id) */ - GHashTable *component_names; - - GList *local_candidates; - - /* A pointer into "local_candidates" list to mark the - * candidates that are still not transmitted, or NULL - * if all of them are transmitted. */ - - GList *pending_candidates; - GList *remote_candidates; - gboolean dispose_has_run; -}; - -static void -gabble_jingle_transport_google_init (GabbleJingleTransportGoogle *obj) -{ - GabbleJingleTransportGooglePrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE, - GabbleJingleTransportGooglePrivate); - obj->priv = priv; - - priv->component_names = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - - priv->dispose_has_run = FALSE; -} - -static void -gabble_jingle_transport_google_dispose (GObject *object) -{ - GabbleJingleTransportGoogle *trans = GABBLE_JINGLE_TRANSPORT_GOOGLE (object); - GabbleJingleTransportGooglePrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - g_hash_table_unref (priv->component_names); - priv->component_names = NULL; - - jingle_transport_free_candidates (priv->remote_candidates); - priv->remote_candidates = NULL; - - jingle_transport_free_candidates (priv->local_candidates); - priv->local_candidates = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - if (G_OBJECT_CLASS (gabble_jingle_transport_google_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_transport_google_parent_class)->dispose (object); -} - -static void -gabble_jingle_transport_google_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleTransportGoogle *trans = GABBLE_JINGLE_TRANSPORT_GOOGLE (object); - GabbleJingleTransportGooglePrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_transport_google_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleTransportGoogle *trans = GABBLE_JINGLE_TRANSPORT_GOOGLE (object); - GabbleJingleTransportGooglePrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - priv->content = g_value_get_object (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_transport_google_class_init (GabbleJingleTransportGoogleClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (GabbleJingleTransportGooglePrivate)); - - object_class->get_property = gabble_jingle_transport_google_get_property; - object_class->set_property = gabble_jingle_transport_google_set_property; - object_class->dispose = gabble_jingle_transport_google_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("content", "GabbleJingleContent object", - "Jingle content object using this transport.", - GABBLE_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTENT, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - JINGLE_TRANSPORT_STATE_DISCONNECTED, - JINGLE_TRANSPORT_STATE_CONNECTED, - JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* signal definitions */ - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -static void -parse_candidates (GabbleJingleTransportIface *obj, - WockyNode *transport_node, GError **error) -{ - GabbleJingleTransportGoogle *t = GABBLE_JINGLE_TRANSPORT_GOOGLE (obj); - GabbleJingleTransportGooglePrivate *priv = t->priv; - GList *candidates = NULL; - WockyNodeIter i; - WockyNode *node; - - wocky_node_iter_init (&i, transport_node, "candidate", NULL); - while (wocky_node_iter_next (&i, &node)) - { - const gchar *name, *address, *user, *pass, *str; - guint port, net, gen, component; - int pref; - JingleTransportProtocol proto; - JingleCandidateType ctype; - JingleCandidate *c; - - name = wocky_node_get_attribute (node, "name"); - if (name == NULL) - break; - - if (!g_hash_table_lookup_extended (priv->component_names, name, - NULL, NULL)) - { - DEBUG ("component name %s unknown to this transport", name); - continue; - } - - component = GPOINTER_TO_INT (g_hash_table_lookup (priv->component_names, - name)); - address = wocky_node_get_attribute (node, "address"); - if (address == NULL) - break; - - str = wocky_node_get_attribute (node, "port"); - if (str == NULL) - break; - port = atoi (str); - - str = wocky_node_get_attribute (node, "protocol"); - if (str == NULL) - break; - - if (!wocky_strdiff (str, "udp")) - { - proto = JINGLE_TRANSPORT_PROTOCOL_UDP; - } - else if (!wocky_strdiff (str, "tcp")) - { - /* candiates on port 443 must be "ssltcp" */ - if (port == 443) - break; - - proto = JINGLE_TRANSPORT_PROTOCOL_TCP; - } - else if (!wocky_strdiff (str, "ssltcp")) - { - /* "ssltcp" must use port 443 */ - if (port != 443) - break; - - /* we really don't care about "ssltcp" otherwise */ - proto = JINGLE_TRANSPORT_PROTOCOL_TCP; - } - else - { - /* unknown protocol */ - DEBUG ("unknown protocol: %s", str); - break; - } - - str = wocky_node_get_attribute (node, "preference"); - if (str == NULL) - break; - - pref = g_ascii_strtod (str, NULL) * 65536; - - str = wocky_node_get_attribute (node, "type"); - if (str == NULL) - break; - - if (!wocky_strdiff (str, "local")) - { - ctype = JINGLE_CANDIDATE_TYPE_LOCAL; - } - else if (!wocky_strdiff (str, "stun")) - { - ctype = JINGLE_CANDIDATE_TYPE_STUN; - } - else if (!wocky_strdiff (str, "relay")) - { - ctype = JINGLE_CANDIDATE_TYPE_RELAY; - } - else - { - /* unknown candidate type */ - DEBUG ("unknown candidate type: %s", str); - break; - } - - user = wocky_node_get_attribute (node, "username"); - if (user == NULL) - break; - - pass = wocky_node_get_attribute (node, "password"); - if (pass == NULL) - break; - - str = wocky_node_get_attribute (node, "network"); - if (str == NULL) - break; - net = atoi (str); - - str = wocky_node_get_attribute (node, "generation"); - if (str == NULL) - break; - gen = atoi (str); - - str = wocky_node_get_attribute (node, "component"); - if (str != NULL) - component = atoi (str); - - c = jingle_candidate_new (proto, ctype, NULL, component, - address, port, gen, pref, user, pass, net); - - candidates = g_list_append (candidates, c); - } - - if (wocky_node_iter_next (&i, NULL)) - { - DEBUG ("not all nodes were processed, reporting error"); - /* rollback these */ - jingle_transport_free_candidates (candidates); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "invalid candidate"); - return; - } - - DEBUG ("emitting %d new remote candidates", g_list_length (candidates)); - - g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates); - - /* append them to the known remote candidates */ - priv->remote_candidates = g_list_concat (priv->remote_candidates, candidates); -} - -static void -transmit_candidates (GabbleJingleTransportGoogle *transport, - const gchar *name, - GList *candidates) -{ - GabbleJingleTransportGooglePrivate *priv = transport->priv; - GList *li; - WockyStanza *msg; - WockyNode *trans_node, *sess_node; - - if (candidates == NULL) - return; - - msg = gabble_jingle_session_new_message (priv->content->session, - JINGLE_ACTION_TRANSPORT_INFO, &sess_node); - - gabble_jingle_content_produce_node (priv->content, sess_node, FALSE, TRUE, - &trans_node); - - for (li = candidates; li; li = li->next) - { - JingleCandidate *c = (JingleCandidate *) li->data; - gchar port_str[16], pref_str[16], comp_str[16], *type_str, *proto_str; - WockyNode *cnode; - - sprintf (port_str, "%d", c->port); - sprintf (pref_str, "%lf", c->preference / 65536.0); - sprintf (comp_str, "%d", c->component); - - switch (c->type) { - case JINGLE_CANDIDATE_TYPE_LOCAL: - type_str = "local"; - break; - case JINGLE_CANDIDATE_TYPE_STUN: - type_str = "stun"; - break; - case JINGLE_CANDIDATE_TYPE_RELAY: - type_str = "relay"; - break; - default: - g_assert_not_reached (); - } - - switch (c->protocol) { - case JINGLE_TRANSPORT_PROTOCOL_UDP: - proto_str = "udp"; - break; - case JINGLE_TRANSPORT_PROTOCOL_TCP: - if ((c->port == 443) && (c->type == JINGLE_CANDIDATE_TYPE_RELAY)) - proto_str = "ssltcp"; - else - proto_str = "tcp"; - break; - default: - g_assert_not_reached (); - } - - cnode = wocky_node_add_child_with_content (trans_node, "candidate", NULL); - wocky_node_set_attributes (cnode, - "address", c->address, - "port", port_str, - "username", c->username, - "password", c->password != NULL ? c->password : "", - "preference", pref_str, - "protocol", proto_str, - "type", type_str, - "component", comp_str, - "network", "0", - "generation", "0", - NULL); - - wocky_node_set_attribute (cnode, "name", name); - } - - wocky_porter_send_iq_async ( - gabble_jingle_session_get_porter (priv->content->session), msg, - NULL, NULL, NULL); - g_object_unref (msg); -} - -/* Groups @candidates into rtp and rtcp and sends each group in its own - * transport-info. This works around old Gabble, which rejected transport-info - * stanzas containing non-rtp candidates. - */ -static void -group_and_transmit_candidates (GabbleJingleTransportGoogle *transport, - GList *candidates) -{ - GabbleJingleTransportGooglePrivate *priv = transport->priv; - GList *all_candidates = NULL; - JingleMediaType media; - GList *li; - GList *cands; - - for (li = candidates; li != NULL; li = g_list_next (li)) - { - JingleCandidate *c = li->data; - - for (cands = all_candidates; cands != NULL; cands = g_list_next (cands)) - { - JingleCandidate *c2 = ((GList *) cands->data)->data; - - if (c->component == c2->component) - { - break; - } - } - if (cands == NULL) - { - all_candidates = g_list_prepend (all_candidates, NULL); - cands = all_candidates; - } - - cands->data = g_list_prepend (cands->data, c); - } - - g_object_get (priv->content, "media-type", &media, NULL); - - for (cands = all_candidates; cands != NULL; cands = g_list_next (cands)) - { - GHashTableIter iter; - gpointer key, value; - gchar *name = NULL; - JingleCandidate *c = ((GList *) cands->data)->data; - - g_hash_table_iter_init (&iter, priv->component_names); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if (GPOINTER_TO_INT (value) == c->component) - { - name = key; - break; - } - } - if (name) - { - transmit_candidates (transport, name, cands->data); - } - else - { - DEBUG ("Ignoring unknown component %d", c->component); - } - g_list_free (cands->data); - } - - g_list_free (all_candidates); -} - -/* Takes in a list of slice-allocated JingleCandidate structs */ -static void -new_local_candidates (GabbleJingleTransportIface *obj, GList *new_candidates) -{ - GabbleJingleTransportGoogle *transport = - GABBLE_JINGLE_TRANSPORT_GOOGLE (obj); - GabbleJingleTransportGooglePrivate *priv = transport->priv; - - priv->local_candidates = g_list_concat (priv->local_candidates, - new_candidates); - - /* If all previous candidates have been signalled, set the new - * ones as pending. If there are existing pending candidates, - * the new ones will just be appended to that list. */ - if (priv->pending_candidates == NULL) - priv->pending_candidates = new_candidates; -} - -static void -send_candidates (GabbleJingleTransportIface *obj, gboolean all) -{ - GabbleJingleTransportGoogle *transport = - GABBLE_JINGLE_TRANSPORT_GOOGLE (obj); - GabbleJingleTransportGooglePrivate *priv = transport->priv; - - if (all) - { - /* for gtalk3, we might have to retransmit everything */ - group_and_transmit_candidates (transport, priv->local_candidates); - priv->pending_candidates = NULL; - } - else - { - /* If the content became ready after we wanted to transmit - * these originally, we are called to transmit when it them */ - if (priv->pending_candidates != NULL) - { - group_and_transmit_candidates (transport, priv->pending_candidates); - priv->pending_candidates = NULL; - } - } -} - -static GList * -get_local_candidates (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportGoogle *transport = - GABBLE_JINGLE_TRANSPORT_GOOGLE (iface); - GabbleJingleTransportGooglePrivate *priv = transport->priv; - - return priv->local_candidates; -} - -static GList * -get_remote_candidates (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportGoogle *transport = - GABBLE_JINGLE_TRANSPORT_GOOGLE (iface); - GabbleJingleTransportGooglePrivate *priv = transport->priv; - - return priv->remote_candidates; -} - -static JingleTransportType -get_transport_type (void) -{ - return JINGLE_TRANSPORT_GOOGLE_P2P; -} - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data) -{ - GabbleJingleTransportIfaceClass *klass = (GabbleJingleTransportIfaceClass *) g_iface; - - klass->parse_candidates = parse_candidates; - - klass->new_local_candidates = new_local_candidates; - /* Not implementing inject_candidates: gtalk-p2p candidates are always sent - * in transport-info or equivalent. - */ - klass->send_candidates = send_candidates; - - klass->get_remote_candidates = get_remote_candidates; - klass->get_local_candidates = get_local_candidates; - klass->get_transport_type = get_transport_type; -} - -/* Returns FALSE if the component name already exists */ -gboolean -jingle_transport_google_set_component_name ( - GabbleJingleTransportGoogle *transport, - const gchar *name, guint component_id) -{ - GabbleJingleTransportGooglePrivate *priv = transport->priv; - - if (g_hash_table_lookup_extended (priv->component_names, name, NULL, NULL)) - return FALSE; - - g_hash_table_insert (priv->component_names, g_strdup (name), - GINT_TO_POINTER (component_id)); - - return TRUE; -} - -void -jingle_transport_google_register (GabbleJingleFactory *factory) -{ - /* GTalk libjingle0.3 dialect */ - gabble_jingle_factory_register_transport (factory, "", - GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE); - - /* GTalk libjingle0.4 dialect */ - gabble_jingle_factory_register_transport (factory, - NS_GOOGLE_TRANSPORT_P2P, - GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE); -} - diff --git a/src/jingle-transport-google.h b/src/jingle-transport-google.h deleted file mode 100644 index bfab8f0fb..000000000 --- a/src/jingle-transport-google.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * jingle-transport-google.h - Header for GabbleJingleTransportGoogle - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_TRANSPORT_GOOGLE_H__ -#define __JINGLE_TRANSPORT_GOOGLE_H__ - -#include <glib-object.h> - -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _GabbleJingleTransportGoogleClass GabbleJingleTransportGoogleClass; - -GType gabble_jingle_transport_google_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE \ - (gabble_jingle_transport_google_get_type ()) -#define GABBLE_JINGLE_TRANSPORT_GOOGLE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE, \ - GabbleJingleTransportGoogle)) -#define GABBLE_JINGLE_TRANSPORT_GOOGLE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE, \ - GabbleJingleTransportGoogleClass)) -#define GABBLE_IS_JINGLE_TRANSPORT_GOOGLE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE)) -#define GABBLE_IS_JINGLE_TRANSPORT_GOOGLE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE)) -#define GABBLE_JINGLE_TRANSPORT_GOOGLE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_TRANSPORT_GOOGLE, \ - GabbleJingleTransportGoogleClass)) - -struct _GabbleJingleTransportGoogleClass { - GObjectClass parent_class; -}; - -typedef struct _GabbleJingleTransportGooglePrivate GabbleJingleTransportGooglePrivate; - -struct _GabbleJingleTransportGoogle { - GObject parent; - GabbleJingleTransportGooglePrivate *priv; -}; - -void jingle_transport_google_register (GabbleJingleFactory *factory); - -gboolean jingle_transport_google_set_component_name ( - GabbleJingleTransportGoogle *transport, - const gchar *name, guint component_id); - -#endif /* __JINGLE_TRANSPORT_GOOGLE_H__ */ - diff --git a/src/jingle-transport-iceudp.c b/src/jingle-transport-iceudp.c deleted file mode 100644 index cd7f3a1e3..000000000 --- a/src/jingle-transport-iceudp.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - * jingle-transport-iceudp.c - Source for GabbleJingleTransportIceUdp - * - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-transport-iceudp.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (GabbleJingleTransportIceUdp, - gabble_jingle_transport_iceudp, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_JINGLE_TRANSPORT_IFACE, - transport_iface_init)); - -/* signal enum */ -enum -{ - NEW_CANDIDATES, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_CONTENT = 1, - PROP_TRANSPORT_NS, - PROP_STATE, - LAST_PROPERTY -}; - -struct _GabbleJingleTransportIceUdpPrivate -{ - GabbleJingleContent *content; - JingleTransportState state; - gchar *transport_ns; - - GList *local_candidates; - - /* A pointer into "local_candidates" list to mark the - * candidates that are still not transmitted, or NULL - * if all of them are transmitted. */ - - GList *pending_candidates; - GList *remote_candidates; - - gchar *ufrag; - gchar *pwd; - - /* next ID to send with a candidate */ - int id_sequence; - - gboolean dispose_has_run; -}; - -static void -gabble_jingle_transport_iceudp_init (GabbleJingleTransportIceUdp *obj) -{ - GabbleJingleTransportIceUdpPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP, - GabbleJingleTransportIceUdpPrivate); - obj->priv = priv; - - priv->id_sequence = 1; - priv->dispose_has_run = FALSE; -} - -static void -gabble_jingle_transport_iceudp_dispose (GObject *object) -{ - GabbleJingleTransportIceUdp *trans = GABBLE_JINGLE_TRANSPORT_ICEUDP (object); - GabbleJingleTransportIceUdpPrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - jingle_transport_free_candidates (priv->remote_candidates); - priv->remote_candidates = NULL; - - jingle_transport_free_candidates (priv->local_candidates); - priv->local_candidates = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - g_free (priv->ufrag); - priv->ufrag = NULL; - - g_free (priv->pwd); - priv->pwd = NULL; - - if (G_OBJECT_CLASS (gabble_jingle_transport_iceudp_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_transport_iceudp_parent_class)->dispose (object); -} - -static void -gabble_jingle_transport_iceudp_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleTransportIceUdp *trans = GABBLE_JINGLE_TRANSPORT_ICEUDP (object); - GabbleJingleTransportIceUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_transport_iceudp_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleTransportIceUdp *trans = GABBLE_JINGLE_TRANSPORT_ICEUDP (object); - GabbleJingleTransportIceUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - priv->content = g_value_get_object (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_transport_iceudp_class_init (GabbleJingleTransportIceUdpClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (GabbleJingleTransportIceUdpPrivate)); - - object_class->get_property = gabble_jingle_transport_iceudp_get_property; - object_class->set_property = gabble_jingle_transport_iceudp_set_property; - object_class->dispose = gabble_jingle_transport_iceudp_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("content", "GabbleJingleContent object", - "Jingle content object using this transport.", - GABBLE_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTENT, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - JINGLE_TRANSPORT_STATE_DISCONNECTED, - JINGLE_TRANSPORT_STATE_CONNECTED, - JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* signal definitions */ - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -static void -parse_candidates (GabbleJingleTransportIface *obj, - WockyNode *transport_node, GError **error) -{ - GabbleJingleTransportIceUdp *t = GABBLE_JINGLE_TRANSPORT_ICEUDP (obj); - GabbleJingleTransportIceUdpPrivate *priv = t->priv; - gboolean node_contains_a_candidate = FALSE; - GList *candidates = NULL; - WockyNodeIter i; - WockyNode *node; - - DEBUG ("called"); - - wocky_node_iter_init (&i, transport_node, "candidate", NULL); - while (wocky_node_iter_next (&i, &node)) - { - const gchar *id, *address, *user, *pass, *str; - guint port, net, gen, component = 1; - gdouble pref; - JingleTransportProtocol proto; - JingleCandidateType ctype; - JingleCandidate *c; - - node_contains_a_candidate = TRUE; - - id = wocky_node_get_attribute (node, "foundation"); - if (id == NULL) - { - DEBUG ("candidate doesn't contain foundation"); - continue; - } - - address = wocky_node_get_attribute (node, "ip"); - if (address == NULL) - { - DEBUG ("candidate doesn't contain ip"); - continue; - } - - str = wocky_node_get_attribute (node, "port"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain port"); - continue; - } - port = atoi (str); - - str = wocky_node_get_attribute (node, "protocol"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain protocol"); - continue; - } - - if (!wocky_strdiff (str, "udp")) - { - proto = JINGLE_TRANSPORT_PROTOCOL_UDP; - } - else - { - /* unknown protocol */ - DEBUG ("unknown protocol: %s", str); - continue; - } - - str = wocky_node_get_attribute (node, "priority"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain priority"); - continue; - } - pref = g_ascii_strtod (str, NULL); - - str = wocky_node_get_attribute (node, "type"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain type"); - continue; - } - - if (!wocky_strdiff (str, "host")) - { - ctype = JINGLE_CANDIDATE_TYPE_LOCAL; - } - else if (!wocky_strdiff (str, "srflx") || !wocky_strdiff (str, "prflx")) - { - /* FIXME Strictly speaking a prflx candidate should be a different - * type, but the TP spec has now way to distinguish and it doesn't - * matter much anyway.. */ - ctype = JINGLE_CANDIDATE_TYPE_STUN; - } - else if (!wocky_strdiff (str, "relay")) - { - ctype = JINGLE_CANDIDATE_TYPE_RELAY; - } - else - { - /* unknown candidate type */ - DEBUG ("unknown candidate type: %s", str); - continue; - } - - user = wocky_node_get_attribute (transport_node, "ufrag"); - if (user == NULL) - { - DEBUG ("transport doesn't contain ufrag"); - continue; - } - - pass = wocky_node_get_attribute (transport_node, "pwd"); - if (pass == NULL) - { - DEBUG ("transport doesn't contain pwd"); - continue; - } - - str = wocky_node_get_attribute (node, "network"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain network"); - continue; - } - net = atoi (str); - - str = wocky_node_get_attribute (node, "generation"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain generation"); - continue; - } - gen = atoi (str); - - str = wocky_node_get_attribute (node, "component"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain component"); - continue; - } - component = atoi (str); - - if (priv->ufrag == NULL || strcmp (priv->ufrag, user)) - { - g_free (priv->ufrag); - priv->ufrag = g_strdup (user); - } - - if (priv->pwd == NULL || strcmp (priv->pwd, pass)) - { - g_free (priv->pwd); - priv->pwd = g_strdup (pass); - } - - c = jingle_candidate_new (proto, ctype, id, component, - address, port, gen, pref, user, pass, net); - - candidates = g_list_append (candidates, c); - } - - if (candidates == NULL) - { - if (node_contains_a_candidate) - { - NODE_DEBUG (transport_node, - "couldn't parse any of the given candidates"); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "could not parse any of the given candidates"); - } - else - { - DEBUG ("no candidates in this stanza"); - } - } - else - { - DEBUG ("emitting %d new remote candidates", g_list_length (candidates)); - - g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates); - - priv->remote_candidates = g_list_concat (priv->remote_candidates, - candidates); - } -} - -static void -inject_candidates (GabbleJingleTransportIface *obj, - WockyNode *transport_node) -{ - GabbleJingleTransportIceUdp *self = GABBLE_JINGLE_TRANSPORT_ICEUDP (obj); - GabbleJingleTransportIceUdpPrivate *priv = self->priv; - const gchar *username = NULL; - - for (; priv->pending_candidates != NULL; - priv->pending_candidates = priv->pending_candidates->next) - { - JingleCandidate *c = (JingleCandidate *) priv->pending_candidates->data; - gchar port_str[16], pref_str[16], comp_str[16], id_str[16], - *type_str, *proto_str; - WockyNode *cnode; - - if (username == NULL) - { - username = c->username; - } - else if (wocky_strdiff (username, c->username)) - { - DEBUG ("found a candidate with a different username (%s not %s); " - "will send in a separate batch", c->username, username); - break; - } - - sprintf (pref_str, "%d", c->preference); - sprintf (port_str, "%d", c->port); - sprintf (comp_str, "%d", c->component); - sprintf (id_str, "%d", priv->id_sequence++); - - switch (c->type) { - case JINGLE_CANDIDATE_TYPE_LOCAL: - type_str = "host"; - break; - case JINGLE_CANDIDATE_TYPE_STUN: - type_str = "srflx"; - break; - case JINGLE_CANDIDATE_TYPE_RELAY: - type_str = "relay"; - break; - default: - DEBUG ("skipping candidate with unknown type %u", c->type); - continue; - } - - switch (c->protocol) { - case JINGLE_TRANSPORT_PROTOCOL_UDP: - proto_str = "udp"; - break; - case JINGLE_TRANSPORT_PROTOCOL_TCP: - DEBUG ("ignoring TCP candidate"); - continue; - default: - DEBUG ("skipping candidate with unknown protocol %u", c->protocol); - continue; - } - - wocky_node_set_attributes (transport_node, - "ufrag", c->username, - "pwd", c->password, - NULL); - - cnode = wocky_node_add_child_with_content (transport_node, "candidate", NULL); - wocky_node_set_attributes (cnode, - "ip", c->address, - "port", port_str, - "priority", pref_str, - "protocol", proto_str, - "type", type_str, - "component", comp_str, - "foundation", c->id, - "id", id_str, - "network", "0", - "generation", "0", - NULL); - } -} - -/* We never have to retransmit candidates we've already sent, so we ignore - * @all. - */ -static void -send_candidates (GabbleJingleTransportIface *iface, - gboolean all G_GNUC_UNUSED) -{ - GabbleJingleTransportIceUdp *self = GABBLE_JINGLE_TRANSPORT_ICEUDP (iface); - GabbleJingleTransportIceUdpPrivate *priv = self->priv; - - while (priv->pending_candidates != NULL) - { - WockyNode *trans_node, *sess_node; - WockyStanza *msg; - - msg = gabble_jingle_session_new_message (priv->content->session, - JINGLE_ACTION_TRANSPORT_INFO, &sess_node); - - gabble_jingle_content_produce_node (priv->content, sess_node, FALSE, - TRUE, &trans_node); - inject_candidates (iface, trans_node); - - wocky_porter_send_iq_async ( - gabble_jingle_session_get_porter (priv->content->session), msg, - NULL, NULL, NULL); - g_object_unref (msg); - } - - DEBUG ("sent all pending candidates"); -} - -/* Takes in a list of slice-allocated JingleCandidate structs */ -static void -new_local_candidates (GabbleJingleTransportIface *obj, GList *new_candidates) -{ - GabbleJingleTransportIceUdp *transport = - GABBLE_JINGLE_TRANSPORT_ICEUDP (obj); - GabbleJingleTransportIceUdpPrivate *priv = transport->priv; - - priv->local_candidates = g_list_concat (priv->local_candidates, - new_candidates); - - /* If all previous candidates have been signalled, set the new - * ones as pending. If there are existing pending candidates, - * the new ones will just be appended to that list. */ - if (priv->pending_candidates == NULL) - priv->pending_candidates = new_candidates; -} - -static GList * -get_remote_candidates (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportIceUdp *transport = - GABBLE_JINGLE_TRANSPORT_ICEUDP (iface); - GabbleJingleTransportIceUdpPrivate *priv = transport->priv; - - return priv->remote_candidates; -} - -static GList * -get_local_candidates (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportIceUdp *transport = - GABBLE_JINGLE_TRANSPORT_ICEUDP (iface); - GabbleJingleTransportIceUdpPrivate *priv = transport->priv; - - return priv->local_candidates; -} - -static JingleTransportType -get_transport_type (void) -{ - return JINGLE_TRANSPORT_ICE_UDP; -} - -static gboolean -get_credentials (GabbleJingleTransportIface *iface, - gchar **ufrag, gchar **pwd) -{ - GabbleJingleTransportIceUdp *transport = - GABBLE_JINGLE_TRANSPORT_ICEUDP (iface); - GabbleJingleTransportIceUdpPrivate *priv = transport->priv; - - if (!priv->ufrag || !priv->pwd) - return FALSE; - - if (ufrag) - *ufrag = priv->ufrag; - if (pwd) - *pwd = priv->pwd; - - return TRUE; -} - - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data) -{ - GabbleJingleTransportIfaceClass *klass = (GabbleJingleTransportIfaceClass *) g_iface; - - klass->parse_candidates = parse_candidates; - - klass->new_local_candidates = new_local_candidates; - klass->inject_candidates = inject_candidates; - klass->send_candidates = send_candidates; - - klass->get_remote_candidates = get_remote_candidates; - klass->get_local_candidates = get_local_candidates; - klass->get_transport_type = get_transport_type; - klass->get_credentials = get_credentials; -} - -void -jingle_transport_iceudp_register (GabbleJingleFactory *factory) -{ - gabble_jingle_factory_register_transport (factory, - NS_JINGLE_TRANSPORT_ICEUDP, - GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP); -} - diff --git a/src/jingle-transport-iceudp.h b/src/jingle-transport-iceudp.h deleted file mode 100644 index 8f7324371..000000000 --- a/src/jingle-transport-iceudp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * jingle-transport-iceudp.h - Header for GabbleJingleTransportIceUdp - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_TRANSPORT_ICEUDP_H__ -#define __JINGLE_TRANSPORT_ICEUDP_H__ - -#include <glib-object.h> - -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _GabbleJingleTransportIceUdpClass GabbleJingleTransportIceUdpClass; - -GType gabble_jingle_transport_iceudp_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP \ - (gabble_jingle_transport_iceudp_get_type ()) -#define GABBLE_JINGLE_TRANSPORT_ICEUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP, \ - GabbleJingleTransportIceUdp)) -#define GABBLE_JINGLE_TRANSPORT_ICEUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP, \ - GabbleJingleTransportIceUdpClass)) -#define GABBLE_IS_JINGLE_TRANSPORT_ICEUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP)) -#define GABBLE_IS_JINGLE_TRANSPORT_ICEUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP)) -#define GABBLE_JINGLE_TRANSPORT_ICEUDP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_TRANSPORT_ICEUDP, \ - GabbleJingleTransportIceUdpClass)) - -struct _GabbleJingleTransportIceUdpClass { - GObjectClass parent_class; -}; - -typedef struct _GabbleJingleTransportIceUdpPrivate GabbleJingleTransportIceUdpPrivate; - -struct _GabbleJingleTransportIceUdp { - GObject parent; - GabbleJingleTransportIceUdpPrivate *priv; -}; - -void jingle_transport_iceudp_register (GabbleJingleFactory *factory); - -#endif /* __JINGLE_TRANSPORT_ICEUDP_H__ */ - diff --git a/src/jingle-transport-iface.c b/src/jingle-transport-iface.c deleted file mode 100644 index 7a1ca9bf3..000000000 --- a/src/jingle-transport-iface.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * jingle-transport-iface.c - Source for GabbleJingleTransport interface - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-transport-iface.h" - -#include <glib.h> - -#include "connection.h" -#include "jingle-content.h" -#include "jingle-session.h" - -GabbleJingleTransportIface * -gabble_jingle_transport_iface_new (GType type, - GabbleJingleContent *content, - const gchar *transport_ns) -{ - g_return_val_if_fail (g_type_is_a (type, GABBLE_TYPE_JINGLE_TRANSPORT_IFACE), - NULL); - - return g_object_new (type, - "content", content, - "transport-ns", transport_ns, - NULL); -} - -void -gabble_jingle_transport_iface_parse_candidates (GabbleJingleTransportIface *self, - WockyNode *node, GError **error) -{ - void (*virtual_method)(GabbleJingleTransportIface *, - WockyNode *, GError **) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->parse_candidates; - - g_assert (virtual_method != NULL); - return virtual_method (self, node, error); -} - -/* Takes in a list of slice-allocated JingleCandidate structs */ -void -gabble_jingle_transport_iface_new_local_candidates (GabbleJingleTransportIface *self, - GList *candidates) -{ - void (*virtual_method)(GabbleJingleTransportIface *, - GList *) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->new_local_candidates; - - g_assert (virtual_method != NULL); - virtual_method (self, candidates); -} - -/* Inserts candidates into the given <transport/> node, or equivalent, of a - * session-initiate, session-accept, content-add or content-accept action. - */ -void -gabble_jingle_transport_iface_inject_candidates ( - GabbleJingleTransportIface *self, - WockyNode *transport_node) -{ - void (*virtual_method)(GabbleJingleTransportIface *, WockyNode *) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->inject_candidates; - - if (virtual_method != NULL) - virtual_method (self, transport_node); -} - -/* Transmits outstanding or all candidates (if applicable and @all is set). */ -void -gabble_jingle_transport_iface_send_candidates ( - GabbleJingleTransportIface *self, - gboolean all) -{ - void (*virtual_method) (GabbleJingleTransportIface *, gboolean) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->send_candidates; - - if (virtual_method != NULL) - virtual_method (self, all); -} - -/* Returns TRUE if and only if @self has enough candidates to inject into a - * {session,content}-accept, and is connected. - */ -gboolean -gabble_jingle_transport_iface_can_accept (GabbleJingleTransportIface *self) -{ - JingleTransportState state; - gboolean (*m) (GabbleJingleTransportIface *) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->can_accept; - - g_object_get (self, "state", &state, NULL); - - if (state != JINGLE_TRANSPORT_STATE_CONNECTED) - return FALSE; - - /* Only Raw UDP *needs* candidates in order to accept. */ - if (m != NULL) - return m (self); - else - return TRUE; -} - -GList * -gabble_jingle_transport_iface_get_remote_candidates ( - GabbleJingleTransportIface *self) -{ - GList * (*virtual_method)(GabbleJingleTransportIface *) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->get_remote_candidates; - - g_assert (virtual_method != NULL); - return virtual_method (self); -} - -GList * -gabble_jingle_transport_iface_get_local_candidates ( - GabbleJingleTransportIface *self) -{ - GList * (*virtual_method)(GabbleJingleTransportIface *) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->get_local_candidates; - - g_assert (virtual_method != NULL); - return virtual_method (self); -} - -gboolean -jingle_transport_get_credentials (GabbleJingleTransportIface *self, - gchar **ufrag, gchar **pwd) -{ - GabbleJingleTransportIfaceClass *klass = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self); - - if (klass->get_credentials) - return klass->get_credentials (self, ufrag, pwd); - else - return FALSE; -} - -JingleTransportType -gabble_jingle_transport_iface_get_transport_type (GabbleJingleTransportIface *self) -{ - JingleTransportType (*virtual_method)(void) = - GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->get_transport_type; - - g_assert (virtual_method != NULL); - return virtual_method (); -} - -static void -gabble_jingle_transport_iface_base_init (gpointer klass) -{ - static gboolean initialized = FALSE; - - if (!initialized) - { - GParamSpec *param_spec; - - param_spec = g_param_spec_object ( - "content", - "GabbleJingleContent object", - "Jingle content that's using this jingle transport object.", - GABBLE_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_interface_install_property (klass, param_spec); - - param_spec = g_param_spec_string ( - "transport-ns", - "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_interface_install_property (klass, param_spec); - - param_spec = g_param_spec_uint ( - "state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - JINGLE_TRANSPORT_STATE_DISCONNECTED, - JINGLE_TRANSPORT_STATE_CONNECTED, - JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - - g_object_interface_install_property (klass, param_spec); - - initialized = TRUE; - } -} - -GType -gabble_jingle_transport_iface_get_type (void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof (GabbleJingleTransportIfaceClass), - gabble_jingle_transport_iface_base_init, /* base_init */ - NULL, /* base_finalize */ - NULL, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL /* instance_init */ - }; - - type = g_type_register_static (G_TYPE_INTERFACE, "GabbleJingleTransportIface", - &info, 0); - } - - return type; -} - -JingleCandidate * -jingle_candidate_new (JingleTransportProtocol protocol, - JingleCandidateType type, const gchar *id, int component, - const gchar *address, int port, int generation, int preference, - const gchar *username, const gchar *password, int network) -{ - JingleCandidate *c = g_slice_new0 (JingleCandidate); - - c->protocol = protocol; - c->type = type; - c->id = g_strdup (id); - c->address = g_strdup (address); - c->component = component; - c->port = port; - c->generation = generation; - c->preference = preference; - c->username = g_strdup (username); - c->password = g_strdup (password); - c->network = network; - - return c; -} - -void -jingle_candidate_free (JingleCandidate *c) -{ - g_free (c->id); - g_free (c->address); - g_free (c->username); - g_free (c->password); - - g_slice_free (JingleCandidate, c); -} - -void -jingle_transport_free_candidates (GList *candidates) -{ - while (candidates != NULL) - { - JingleCandidate *c = (JingleCandidate *) candidates->data; - jingle_candidate_free (c); - candidates = g_list_remove (candidates, c); - } -} - diff --git a/src/jingle-transport-iface.h b/src/jingle-transport-iface.h deleted file mode 100644 index dc59d5394..000000000 --- a/src/jingle-transport-iface.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * jingle_transport-iface.h - Header for GabbleJingleTransport interface - * Copyright (C) 2007-2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __GABBLE_JINGLE_TRANSPORT_IFACE_H__ -#define __GABBLE_JINGLE_TRANSPORT_IFACE_H__ - -#include <glib-object.h> -#include <wocky/wocky.h> - -#include "jingle-factory.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef enum -{ - JINGLE_TRANSPORT_STATE_DISCONNECTED, - JINGLE_TRANSPORT_STATE_CONNECTING, - JINGLE_TRANSPORT_STATE_CONNECTED -} JingleTransportState; - -typedef struct _GabbleJingleTransportIface GabbleJingleTransportIface; -typedef struct _GabbleJingleTransportIfaceClass GabbleJingleTransportIfaceClass; - -struct _GabbleJingleTransportIfaceClass { - GTypeInterface parent; - - void (*parse_candidates) (GabbleJingleTransportIface *, - WockyNode *, GError **); - - void (*new_local_candidates) (GabbleJingleTransportIface *, GList *); - void (*inject_candidates) (GabbleJingleTransportIface *, - WockyNode *transport_node); - void (*send_candidates) (GabbleJingleTransportIface *, gboolean all); - gboolean (*can_accept) (GabbleJingleTransportIface *); - - GList * (*get_remote_candidates) (GabbleJingleTransportIface *); - GList * (*get_local_candidates) (GabbleJingleTransportIface *); - gboolean (*get_credentials) (GabbleJingleTransportIface *, - gchar **ufrag, gchar **pwd); - - JingleTransportType (*get_transport_type) (void); -}; - -GType gabble_jingle_transport_iface_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_TRANSPORT_IFACE \ - (gabble_jingle_transport_iface_get_type ()) -#define GABBLE_JINGLE_TRANSPORT_IFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_TRANSPORT_IFACE, GabbleJingleTransportIface)) -#define GABBLE_IS_JINGLE_TRANSPORT_IFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_TRANSPORT_IFACE)) -#define GABBLE_JINGLE_TRANSPORT_IFACE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GABBLE_TYPE_JINGLE_TRANSPORT_IFACE,\ - GabbleJingleTransportIfaceClass)) - -void gabble_jingle_transport_iface_parse_candidates (GabbleJingleTransportIface *, - WockyNode *, GError **); - -void gabble_jingle_transport_iface_new_local_candidates ( - GabbleJingleTransportIface *self, - GList *candidates); -void gabble_jingle_transport_iface_inject_candidates ( - GabbleJingleTransportIface *self, - WockyNode *transport_node); -void gabble_jingle_transport_iface_send_candidates ( - GabbleJingleTransportIface *self, - gboolean all); -gboolean gabble_jingle_transport_iface_can_accept ( - GabbleJingleTransportIface *self); - -GList *gabble_jingle_transport_iface_get_remote_candidates (GabbleJingleTransportIface *); -GList *gabble_jingle_transport_iface_get_local_candidates (GabbleJingleTransportIface *); -JingleTransportType gabble_jingle_transport_iface_get_transport_type (GabbleJingleTransportIface *); -gboolean jingle_transport_get_credentials (GabbleJingleTransportIface *, - gchar **ufrag, gchar **pwd); - -GabbleJingleTransportIface *gabble_jingle_transport_iface_new ( - GType type, GabbleJingleContent *content, const gchar *transport_ns); - -JingleCandidate *jingle_candidate_new (JingleTransportProtocol protocol, - JingleCandidateType type, const gchar *id, int component, - const gchar *address, int port, int generation, int preference, - const gchar *username, const gchar *password, int network); - -void jingle_candidate_free (JingleCandidate *c); -void jingle_transport_free_candidates (GList *candidates); - - -G_END_DECLS - -#endif /* #ifndef __GABBLE_JINGLE_TRANSPORT_IFACE_H__ */ diff --git a/src/jingle-transport-rawudp.c b/src/jingle-transport-rawudp.c deleted file mode 100644 index 17b1b1f8f..000000000 --- a/src/jingle-transport-rawudp.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * jingle-transport-rawudp.c - Source for GabbleJingleTransportRawUdp - * - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "jingle-transport-rawudp.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "connection.h" -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (GabbleJingleTransportRawUdp, - gabble_jingle_transport_rawudp, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_JINGLE_TRANSPORT_IFACE, - transport_iface_init)); - -/* signal enum */ -enum -{ - NEW_CANDIDATES, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_CONTENT = 1, - PROP_TRANSPORT_NS, - PROP_STATE, - LAST_PROPERTY -}; - -struct _GabbleJingleTransportRawUdpPrivate -{ - GabbleJingleContent *content; - JingleTransportState state; - gchar *transport_ns; - - GList *local_candidates; - GList *remote_candidates; - gboolean dispose_has_run; -}; - -static void -gabble_jingle_transport_rawudp_init (GabbleJingleTransportRawUdp *obj) -{ - GabbleJingleTransportRawUdpPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, - GabbleJingleTransportRawUdpPrivate); - obj->priv = priv; - - priv->dispose_has_run = FALSE; -} - -static void -gabble_jingle_transport_rawudp_dispose (GObject *object) -{ - GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object); - GabbleJingleTransportRawUdpPrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - jingle_transport_free_candidates (priv->remote_candidates); - priv->remote_candidates = NULL; - - jingle_transport_free_candidates (priv->local_candidates); - priv->local_candidates = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - if (G_OBJECT_CLASS (gabble_jingle_transport_rawudp_parent_class)->dispose) - G_OBJECT_CLASS (gabble_jingle_transport_rawudp_parent_class)->dispose (object); -} - -static void -gabble_jingle_transport_rawudp_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object); - GabbleJingleTransportRawUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_transport_rawudp_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object); - GabbleJingleTransportRawUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - priv->content = g_value_get_object (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_jingle_transport_rawudp_class_init (GabbleJingleTransportRawUdpClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (GabbleJingleTransportRawUdpPrivate)); - - object_class->get_property = gabble_jingle_transport_rawudp_get_property; - object_class->set_property = gabble_jingle_transport_rawudp_set_property; - object_class->dispose = gabble_jingle_transport_rawudp_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("content", "GabbleJingleContent object", - "Jingle content object using this transport.", - GABBLE_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTENT, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - JINGLE_TRANSPORT_STATE_DISCONNECTED, - JINGLE_TRANSPORT_STATE_CONNECTED, - JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* signal definitions */ - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -static void -parse_candidates (GabbleJingleTransportIface *obj, - WockyNode *transport_node, GError **error) -{ - GabbleJingleTransportRawUdp *t = GABBLE_JINGLE_TRANSPORT_RAWUDP (obj); - GabbleJingleTransportRawUdpPrivate *priv = t->priv; - GList *candidates = NULL; - WockyNodeIter i; - WockyNode *node; - - DEBUG ("called"); - - if (priv->remote_candidates != NULL) - { - DEBUG ("already have raw udp candidates, ignoring extra ones"); - return; - } - - wocky_node_iter_init (&i, transport_node, "candidate", NULL); - while (wocky_node_iter_next (&i, &node)) - { - const gchar *id, *ip, *str; - guint port, gen, component = 1; - JingleCandidate *c; - - str = wocky_node_get_attribute (node, "component"); - if (str != NULL) - component = atoi (str); - - if ((component != 1) && (component != 2)) - { - DEBUG ("Ignoring non-RTP/RTCP component %d", component); - continue; - } - - id = wocky_node_get_attribute (node, "id"); - if (id == NULL) - break; - - ip = wocky_node_get_attribute (node, "ip"); - if (ip == NULL) - break; - - str = wocky_node_get_attribute (node, "port"); - if (str == NULL) - break; - port = atoi (str); - - str = wocky_node_get_attribute (node, "generation"); - if (str == NULL) - break; - gen = atoi (str); - - c = jingle_candidate_new (JINGLE_TRANSPORT_PROTOCOL_UDP, - JINGLE_CANDIDATE_TYPE_LOCAL, id, component, ip, port, - gen, 1.0, NULL, NULL, 0); - - candidates = g_list_append (candidates, c); - } - - if (wocky_node_iter_next (&i, NULL)) - { - DEBUG ("not all nodes were processed, reporting error"); - /* rollback these */ - jingle_transport_free_candidates (candidates); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "invalid candidate"); - return; - } - - DEBUG ("emitting %d new remote candidates", g_list_length (candidates)); - g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates); - priv->remote_candidates = candidates; -} - -static void -inject_candidates (GabbleJingleTransportIface *obj, - WockyNode *transport_node) -{ - GabbleJingleTransportRawUdp *self = GABBLE_JINGLE_TRANSPORT_RAWUDP (obj); - GabbleJingleTransportRawUdpPrivate *priv = self->priv; - JingleCandidate *c; - GList *li; - gchar port_str[16], comp_str[16]; - WockyNode *cnode; - - /* If we don't have the local candidates yet, we should've waited with - * the session initiation, or can_accept would have returned FALSE. - */ - g_assert (priv->local_candidates != NULL); - - for (li = priv->local_candidates; li != NULL; li = li->next) - { - c = (JingleCandidate *) li->data; - sprintf (port_str, "%d", c->port); - sprintf (comp_str, "%d", c->component); - - cnode = wocky_node_add_child_with_content (transport_node, "candidate", NULL); - wocky_node_set_attributes (cnode, - "ip", c->address, - "port", port_str, - "generation", "0", - "id", c->id, - "component", comp_str, - NULL); - } -} - -/* Takes in a list of slice-allocated JingleCandidate structs */ -static void -new_local_candidates (GabbleJingleTransportIface *obj, GList *new_candidates) -{ - GabbleJingleTransportRawUdp *transport = - GABBLE_JINGLE_TRANSPORT_RAWUDP (obj); - GabbleJingleTransportRawUdpPrivate *priv = transport->priv; - - if (priv->local_candidates != NULL) - { - DEBUG ("ignoring new local candidates for RAW UDP"); - jingle_transport_free_candidates (new_candidates); - return; - } - - priv->local_candidates = new_candidates; -} - -static gboolean -can_accept (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportRawUdp *self = GABBLE_JINGLE_TRANSPORT_RAWUDP (iface); - - return (self->priv->local_candidates != NULL); -} - -static GList * -get_local_candidates (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportRawUdp *transport = - GABBLE_JINGLE_TRANSPORT_RAWUDP (iface); - GabbleJingleTransportRawUdpPrivate *priv = transport->priv; - - return priv->local_candidates; -} - -static GList * -get_remote_candidates (GabbleJingleTransportIface *iface) -{ - GabbleJingleTransportRawUdp *transport = - GABBLE_JINGLE_TRANSPORT_RAWUDP (iface); - GabbleJingleTransportRawUdpPrivate *priv = transport->priv; - - return priv->remote_candidates; -} - -static JingleTransportType -get_transport_type (void) -{ - DEBUG ("called"); - - return JINGLE_TRANSPORT_RAW_UDP; -} - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data) -{ - GabbleJingleTransportIfaceClass *klass = (GabbleJingleTransportIfaceClass *) g_iface; - - klass->parse_candidates = parse_candidates; - - klass->new_local_candidates = new_local_candidates; - klass->inject_candidates = inject_candidates; - /* Not implementing _send: XEP-0177 says that the candidates live in - * content-{add,accept}, not in transport-info. - */ - klass->can_accept = can_accept; - - klass->get_remote_candidates = get_remote_candidates; - klass->get_local_candidates = get_local_candidates; - klass->get_transport_type = get_transport_type; -} - -void -jingle_transport_rawudp_register (GabbleJingleFactory *factory) -{ - gabble_jingle_factory_register_transport (factory, - NS_JINGLE_TRANSPORT_RAWUDP, - GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP); -} - diff --git a/src/jingle-transport-rawudp.h b/src/jingle-transport-rawudp.h deleted file mode 100644 index 060f854dc..000000000 --- a/src/jingle-transport-rawudp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * jingle-transport-rawudp.h - Header for GabbleJingleTransportRawUdp - * Copyright (C) 2008 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __JINGLE_TRANSPORT_RAWUDP_H__ -#define __JINGLE_TRANSPORT_RAWUDP_H__ - -#include <glib-object.h> - -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _GabbleJingleTransportRawUdpClass GabbleJingleTransportRawUdpClass; - -GType gabble_jingle_transport_rawudp_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP \ - (gabble_jingle_transport_rawudp_get_type ()) -#define GABBLE_JINGLE_TRANSPORT_RAWUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, \ - GabbleJingleTransportRawUdp)) -#define GABBLE_JINGLE_TRANSPORT_RAWUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, \ - GabbleJingleTransportRawUdpClass)) -#define GABBLE_IS_JINGLE_TRANSPORT_RAWUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP)) -#define GABBLE_IS_JINGLE_TRANSPORT_RAWUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP)) -#define GABBLE_JINGLE_TRANSPORT_RAWUDP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_JINGLE_TRANSPORT_RAWUDP, \ - GabbleJingleTransportRawUdpClass)) - -struct _GabbleJingleTransportRawUdpClass { - GObjectClass parent_class; -}; - -typedef struct _GabbleJingleTransportRawUdpPrivate GabbleJingleTransportRawUdpPrivate; - -struct _GabbleJingleTransportRawUdp { - GObject parent; - GabbleJingleTransportRawUdpPrivate *priv; -}; - -void jingle_transport_rawudp_register (GabbleJingleFactory *factory); - -#endif /* __JINGLE_TRANSPORT_RAWUDP_H__ */ - diff --git a/src/jingle-types.h b/src/jingle-types.h deleted file mode 100644 index 14934aae6..000000000 --- a/src/jingle-types.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * jingle-types.h - Header for Jingle-related enums and typedefs - * Copyright © 2008–2012 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef GABBLE_JINGLE_ENUMS_H -#define GABBLE_JINGLE_ENUMS_H - -typedef struct _GabbleJingleFactory GabbleJingleFactory; -typedef struct _GabbleJingleSession GabbleJingleSession; -typedef struct _GabbleJingleContent GabbleJingleContent; -typedef struct _GabbleJingleTransportGoogle GabbleJingleTransportGoogle; -typedef struct _GabbleJingleTransportRawUdp GabbleJingleTransportRawUdp; -typedef struct _GabbleJingleTransportIceUdp GabbleJingleTransportIceUdp; -typedef struct _GabbleJingleMediaRtp GabbleJingleMediaRtp; -typedef struct _GabbleJingleShare GabbleJingleShare; -typedef struct _JingleCandidate JingleCandidate; - -typedef enum { /*< skip >*/ - /* not a jingle message */ - JINGLE_DIALECT_ERROR, - /* old libjingle3 gtalk variant */ - JINGLE_DIALECT_GTALK3, - /* new gtalk variant */ - JINGLE_DIALECT_GTALK4, - /* jingle in the old 0.15 version days */ - JINGLE_DIALECT_V015, - /* current jingle standard */ - JINGLE_DIALECT_V032 -} JingleDialect; - -#define JINGLE_IS_GOOGLE_DIALECT(d)\ - ((d == JINGLE_DIALECT_GTALK3) || (d == JINGLE_DIALECT_GTALK4)) - -typedef enum { /*< skip >*/ - JINGLE_STATE_INVALID = -1, - JINGLE_STATE_PENDING_CREATED = 0, - JINGLE_STATE_PENDING_INITIATE_SENT, - JINGLE_STATE_PENDING_INITIATED, - JINGLE_STATE_PENDING_ACCEPT_SENT, - JINGLE_STATE_ACTIVE, - JINGLE_STATE_ENDED, - MAX_JINGLE_STATES -} JingleState; - -typedef enum { /*< skip >*/ - JINGLE_ACTION_UNKNOWN, - JINGLE_ACTION_CONTENT_ACCEPT, - JINGLE_ACTION_CONTENT_ADD, - JINGLE_ACTION_CONTENT_MODIFY, - JINGLE_ACTION_CONTENT_REMOVE, - JINGLE_ACTION_CONTENT_REPLACE, - JINGLE_ACTION_CONTENT_REJECT, - JINGLE_ACTION_SESSION_ACCEPT, - JINGLE_ACTION_SESSION_INFO, - JINGLE_ACTION_SESSION_INITIATE, - JINGLE_ACTION_SESSION_TERMINATE, - JINGLE_ACTION_TRANSPORT_INFO, - JINGLE_ACTION_TRANSPORT_ACCEPT, - JINGLE_ACTION_DESCRIPTION_INFO, - JINGLE_ACTION_INFO -} JingleAction; - -typedef enum { /*< skip >*/ - JINGLE_CONTENT_SENDERS_NONE, - JINGLE_CONTENT_SENDERS_INITIATOR, - JINGLE_CONTENT_SENDERS_RESPONDER, - JINGLE_CONTENT_SENDERS_BOTH -} JingleContentSenders; - -typedef enum { /*< skip >*/ - JINGLE_TRANSPORT_UNKNOWN, - JINGLE_TRANSPORT_GOOGLE_P2P, - JINGLE_TRANSPORT_RAW_UDP, - JINGLE_TRANSPORT_ICE_UDP, -} JingleTransportType; - -typedef enum { /*< skip >*/ - JINGLE_TRANSPORT_PROTOCOL_UDP, - JINGLE_TRANSPORT_PROTOCOL_TCP -} JingleTransportProtocol; - -typedef enum { /*< skip >*/ - JINGLE_CANDIDATE_TYPE_LOCAL, - JINGLE_CANDIDATE_TYPE_STUN, - JINGLE_CANDIDATE_TYPE_RELAY -} JingleCandidateType; - -typedef enum -{ - JINGLE_REASON_UNKNOWN, - JINGLE_REASON_ALTERNATIVE_SESSION, - JINGLE_REASON_BUSY, - JINGLE_REASON_CANCEL, - JINGLE_REASON_CONNECTIVITY_ERROR, - JINGLE_REASON_DECLINE, - JINGLE_REASON_EXPIRED, - JINGLE_REASON_FAILED_APPLICATION, - JINGLE_REASON_FAILED_TRANSPORT, - JINGLE_REASON_GENERAL_ERROR, - JINGLE_REASON_GONE, - JINGLE_REASON_INCOMPATIBLE_PARAMETERS, - JINGLE_REASON_MEDIA_ERROR, - JINGLE_REASON_SECURITY_ERROR, - JINGLE_REASON_SUCCESS, - JINGLE_REASON_TIMEOUT, - JINGLE_REASON_UNSUPPORTED_APPLICATIONS, - JINGLE_REASON_UNSUPPORTED_TRANSPORTS -} JingleReason; - - -#endif /* GABBLE_JINGLE_ENUMS_H */ diff --git a/src/legacy-caps.c b/src/legacy-caps.c index 3f4ebde5c..827fc15ea 100644 --- a/src/legacy-caps.c +++ b/src/legacy-caps.c @@ -21,7 +21,7 @@ #include "config.h" #include "legacy-caps.h" -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_PRESENCE #include "debug.h" diff --git a/src/media-channel-hold.c b/src/media-channel-hold.c index bb4cb576c..b4dc26c5a 100644 --- a/src/media-channel-hold.c +++ b/src/media-channel-hold.c @@ -19,10 +19,11 @@ */ #include "config.h" + #include "media-channel.h" #include "media-channel-internal.h" -#include <telepathy-glib/channel-iface.h> +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_MEDIA @@ -79,7 +80,7 @@ stream_hold_state_changed (GabbleMediaStream *stream G_GNUC_UNUSED, priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; if (priv->session != NULL) - gabble_jingle_session_set_local_hold (priv->session, FALSE); + wocky_jingle_session_set_local_hold (priv->session, FALSE); break; @@ -173,7 +174,7 @@ stream_hold_state_changed (GabbleMediaStream *stream G_GNUC_UNUSED, /* Tell the peer what's happened. */ if (priv->session != NULL) - gabble_jingle_session_set_local_hold (priv->session, FALSE); + wocky_jingle_session_set_local_hold (priv->session, FALSE); } tp_svc_channel_interface_hold_emit_hold_state_changed (self, @@ -234,7 +235,7 @@ gabble_media_channel_request_hold (TpSvcChannelInterfaceHold *iface, { GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); GabbleMediaChannelPrivate *priv = self->priv; - GabbleJingleSession *session = priv->session; + WockyJingleSession *session = priv->session; guint i; TpLocalHoldState old_state = priv->hold_state; @@ -250,7 +251,7 @@ gabble_media_channel_request_hold (TpSvcChannelInterfaceHold *iface, } if (priv->hold_state == TP_LOCAL_HOLD_STATE_UNHELD && session != NULL) - gabble_jingle_session_set_local_hold (session, TRUE); + wocky_jingle_session_set_local_hold (session, TRUE); priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; } @@ -327,16 +328,16 @@ gabble_media_channel_hold_iface_init (gpointer g_iface, */ static void -remote_state_changed_cb (GabbleJingleSession *session, +remote_state_changed_cb (WockyJingleSession *session, GabbleMediaChannel *self) { GabbleMediaChannelPrivate *priv = self->priv; TpChannelCallStateFlags call_state = 0; - if (gabble_jingle_session_get_remote_hold (session)) + if (wocky_jingle_session_get_remote_hold (session)) call_state |= TP_CHANNEL_CALL_STATE_HELD; - if (gabble_jingle_session_get_remote_ringing (session)) + if (wocky_jingle_session_get_remote_ringing (session)) call_state |= TP_CHANNEL_CALL_STATE_RINGING; DEBUG ("Call state changed to %u (current state %u)", call_state, @@ -393,7 +394,7 @@ gabble_media_channel_call_state_iface_init (gpointer g_iface, void gabble_media_channel_hold_new_stream (GabbleMediaChannel *chan, GabbleMediaStream *stream, - GabbleJingleMediaRtp *content) + WockyJingleMediaRtp *content) { GObject *chan_o = (GObject *) chan; diff --git a/src/media-channel-internal.h b/src/media-channel-internal.h index 9264eac8b..4459df726 100644 --- a/src/media-channel-internal.h +++ b/src/media-channel-internal.h @@ -26,11 +26,10 @@ #include <glib.h> -#include <telepathy-glib/dtmf.h> +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> #include "media-stream.h" -#include "jingle-session.h" -#include "jingle-media-rtp.h" G_BEGIN_DECLS @@ -43,7 +42,7 @@ struct _GabbleMediaChannelPrivate TpHandle peer; gboolean peer_in_rp; - GabbleJingleSession *session; + WockyJingleSession *session; /* array of referenced GabbleMediaStream*. Always non-NULL. */ GPtrArray *streams; @@ -79,7 +78,7 @@ void gabble_media_channel_hold_latch_to_session (GabbleMediaChannel *chan); void gabble_media_channel_hold_new_stream (GabbleMediaChannel *chan, GabbleMediaStream *stream, - GabbleJingleMediaRtp *content); + WockyJingleMediaRtp *content); void gabble_media_channel_hold_stream_closed (GabbleMediaChannel *chan, GabbleMediaStream *stream); diff --git a/src/media-channel.c b/src/media-channel.c index 0721b2908..c4ab89e37 100644 --- a/src/media-channel.c +++ b/src/media-channel.c @@ -26,23 +26,15 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-properties-interface.h> -#include <telepathy-glib/svc-media-interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> + +#include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_MEDIA #include "connection.h" #include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-media-rtp.h" -#include "jingle-session.h" #include "jingle-tp-util.h" #include "media-factory.h" #include "media-stream.h" @@ -148,7 +140,7 @@ const TpPropertySignature channel_property_signatures[NUM_CHAN_PROPS] = { typedef struct { GabbleMediaChannel *self; - GabbleJingleContent *content; + WockyJingleContent *content; gulong removed_id; gchar *name; const gchar *nat_traversal; @@ -208,20 +200,20 @@ gabble_media_channel_init (GabbleMediaChannel *self) G_CONNECT_SWAPPED); } -static void session_state_changed_cb (GabbleJingleSession *session, +static void session_state_changed_cb (WockyJingleSession *session, GParamSpec *arg1, GabbleMediaChannel *channel); -static void session_terminated_cb (GabbleJingleSession *session, - gboolean local_terminator, JingleReason reason, const gchar *text, +static void session_terminated_cb (WockyJingleSession *session, + gboolean local_terminator, WockyJingleReason reason, const gchar *text, gpointer user_data); -static void session_new_content_cb (GabbleJingleSession *session, - GabbleJingleContent *c, gpointer user_data); +static void session_new_content_cb (WockyJingleSession *session, + WockyJingleContent *c, gpointer user_data); static void create_stream_from_content (GabbleMediaChannel *chan, - GabbleJingleContent *c, gboolean initial); + WockyJingleContent *c, gboolean initial); static gboolean contact_is_media_capable (GabbleMediaChannel *chan, TpHandle peer, gboolean *wait, GError **error); static void stream_creation_data_cancel (gpointer p, gpointer unused); -static void session_content_rejected_cb (GabbleJingleSession *session, - GabbleJingleContent *c, JingleReason reason, const gchar *message, +static void session_content_rejected_cb (WockyJingleSession *session, + WockyJingleContent *c, WockyJingleReason reason, const gchar *message, gpointer user_data); static void @@ -230,14 +222,14 @@ create_initial_streams (GabbleMediaChannel *chan) GabbleMediaChannelPrivate *priv = chan->priv; GList *contents, *li; - contents = gabble_jingle_session_get_contents (priv->session); + contents = wocky_jingle_session_get_contents (priv->session); for (li = contents; li; li = li->next) { - GabbleJingleContent *c = li->data; + WockyJingleContent *c = li->data; /* I'm so sorry. */ - if (G_OBJECT_TYPE (c) == GABBLE_TYPE_JINGLE_MEDIA_RTP) + if (G_OBJECT_TYPE (c) == WOCKY_TYPE_JINGLE_MEDIA_RTP) { guint media_type; @@ -245,10 +237,10 @@ create_initial_streams (GabbleMediaChannel *chan) switch (media_type) { - case JINGLE_MEDIA_TYPE_AUDIO: + case WOCKY_JINGLE_MEDIA_TYPE_AUDIO: priv->initial_audio = TRUE; break; - case JINGLE_MEDIA_TYPE_VIDEO: + case WOCKY_JINGLE_MEDIA_TYPE_VIDEO: priv->initial_video = TRUE; break; default: @@ -303,11 +295,11 @@ _latch_to_session (GabbleMediaChannel *chan) static void create_session (GabbleMediaChannel *chan, const gchar *jid, - JingleDialect dialect) + WockyJingleDialect dialect) { GabbleMediaChannelPrivate *priv = chan->priv; gboolean local_hold = (priv->hold_state != TP_LOCAL_HOLD_STATE_UNHELD); - GabbleJingleFactory *jf; + WockyJingleFactory *jf; g_assert (priv->session == NULL); @@ -316,7 +308,7 @@ create_session (GabbleMediaChannel *chan, jf = gabble_jingle_mint_get_factory (priv->conn->jingle_mint); g_return_if_fail (jf != NULL); priv->session = g_object_ref ( - gabble_jingle_factory_create_session (jf, jid, dialect, local_hold)); + wocky_jingle_factory_create_session (jf, jid, dialect, local_hold)); _latch_to_session (chan); } @@ -329,12 +321,11 @@ gabble_media_channel_constructor (GType type, guint n_props, GabbleMediaChannelPrivate *priv; TpBaseConnection *conn; TpDBusDaemon *bus; - TpIntSet *set; + TpIntset *set; TpHandleRepoIface *contact_handles; - GabbleJingleInfo *ji; + WockyJingleInfo *ji; const gchar *relay_token; - gchar *stun_server; - guint stun_port; + GList *stun_servers; obj = G_OBJECT_CLASS (gabble_media_channel_parent_class)-> constructor (type, n_props, props); @@ -349,24 +340,23 @@ gabble_media_channel_constructor (GType type, guint n_props, tp_dbus_daemon_register_object (bus, priv->object_path, obj); tp_group_mixin_init (obj, G_STRUCT_OFFSET (GabbleMediaChannel, group), - contact_handles, conn->self_handle); + contact_handles, tp_base_connection_get_self_handle (conn)); if (priv->session != NULL) { priv->peer = ensure_handle_from_contact (priv->conn, - gabble_jingle_session_get_peer_contact (priv->session)); + wocky_jingle_session_get_peer_contact (priv->session)); g_return_val_if_fail (priv->peer != 0, NULL); priv->creator = priv->peer; } else { - priv->creator = conn->self_handle; + priv->creator = tp_base_connection_get_self_handle (conn); } /* automatically add creator to channel, but also ref them again (because * priv->creator is the InitiatorHandle) */ g_assert (priv->creator != 0); - tp_handle_ref (contact_handles, priv->creator); set = tp_intset_new_containing (priv->creator); tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, 0, @@ -385,18 +375,20 @@ gabble_media_channel_constructor (GType type, guint n_props, /* Set up Google relay related properties */ ji = gabble_jingle_mint_get_info (priv->conn->jingle_mint); - - if (gabble_jingle_info_get_stun_server (ji, &stun_server, - &stun_port)) + stun_servers = wocky_jingle_info_get_stun_servers (ji); + if (stun_servers != NULL) { + WockyStunServer *stun_server = stun_servers->data; + g_object_set (obj, - "stun-server", stun_server, - "stun-port", stun_port, + "stun-server", stun_server->address, + "stun-port", (guint) stun_server->port, NULL); - g_free (stun_server); + + g_list_free (stun_servers); } - relay_token = gabble_jingle_info_get_google_relay_token (ji); + relay_token = wocky_jingle_info_get_google_relay_token (ji); if (relay_token != NULL) { @@ -411,7 +403,7 @@ gabble_media_channel_constructor (GType type, guint n_props, * group flags (all we can do is add or remove ourselves, which is always * valid per the spec) */ - set = tp_intset_new_containing (conn->self_handle); + set = tp_intset_new_containing (tp_base_connection_get_self_handle (conn)); tp_group_mixin_change_members (obj, "", NULL, NULL, set, NULL, priv->peer, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); tp_intset_destroy (set); @@ -435,7 +427,8 @@ gabble_media_channel_constructor (GType type, guint n_props, */ set = tp_intset_new_containing (priv->initial_peer); tp_group_mixin_change_members (obj, "", NULL, NULL, NULL, set, - conn->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); + tp_base_connection_get_self_handle (conn), + TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); tp_intset_destroy (set); } @@ -460,7 +453,7 @@ gabble_media_channel_constructor (GType type, guint n_props, /* If this is a Google session, let's set ImmutableStreams */ if (priv->session != NULL) { - priv->immutable_streams = !gabble_jingle_session_can_modify_contents (priv->session); + priv->immutable_streams = !wocky_jingle_session_can_modify_contents (priv->session); } /* If there's no session yet, but we know who the peer will be, and we have * presence for them, we can set ImmutableStreams using the same algorithm as @@ -565,7 +558,8 @@ gabble_media_channel_get_property (GObject *object, } break; case PROP_REQUESTED: - g_value_set_boolean (value, (priv->creator == base_conn->self_handle)); + g_value_set_boolean (value, + (priv->creator == tp_base_connection_get_self_handle (base_conn))); break; case PROP_INTERFACES: g_value_set_boxed (value, gabble_media_channel_interfaces); @@ -666,15 +660,6 @@ gabble_media_channel_set_property (GObject *object, break; case PROP_INITIAL_PEER: priv->initial_peer = g_value_get_uint (value); - - if (priv->initial_peer != 0) - { - TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; - TpHandleRepoIface *repo = tp_base_connection_get_handles (base_conn, - TP_HANDLE_TYPE_CONTACT); - tp_handle_ref (repo, priv->initial_peer); - } - break; case PROP_PEER_IN_RP: priv->peer_in_rp = g_value_get_boolean (value); @@ -881,9 +866,9 @@ gabble_media_channel_class_init (GabbleMediaChannelClass *gabble_media_channel_c g_object_class_install_property (object_class, PROP_GTALK_P2P_RELAY_TOKEN, param_spec); - param_spec = g_param_spec_object ("session", "GabbleJingleSession object", + param_spec = g_param_spec_object ("session", "WockyJingleSession object", "Jingle session associated with this media channel object.", - GABBLE_TYPE_JINGLE_SESSION, + WOCKY_TYPE_JINGLE_SESSION, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); g_object_class_install_property (object_class, PROP_SESSION, param_spec); @@ -952,9 +937,6 @@ gabble_media_channel_dispose (GObject *object) { GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (object); GabbleMediaChannelPrivate *priv = self->priv; - TpBaseConnection *conn = (TpBaseConnection *) priv->conn; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles ( - conn, TP_HANDLE_TYPE_CONTACT); GList *l; if (priv->dispose_has_run) @@ -990,15 +972,6 @@ gabble_media_channel_dispose (GObject *object) priv->delayed_request_streams = NULL; } - tp_handle_unref (contact_handles, priv->creator); - priv->creator = 0; - - if (priv->initial_peer != 0) - { - tp_handle_unref (contact_handles, priv->initial_peer); - priv->initial_peer = 0; - } - /* All of the streams should have closed in response to the contents being * removed when the call ended. */ @@ -1062,8 +1035,8 @@ gabble_media_channel_close (GabbleMediaChannel *self) priv->closed = TRUE; if (priv->session != NULL) - gabble_jingle_session_terminate (priv->session, - JINGLE_REASON_UNKNOWN, NULL, NULL); + wocky_jingle_session_terminate (priv->session, + WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); tp_svc_channel_emit_closed (self); } @@ -1279,14 +1252,14 @@ _find_stream_by_id (GabbleMediaChannel *chan, return stream; } - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "given stream id %u does not exist", stream_id); return NULL; } static GabbleMediaStream * _find_stream_by_content (GabbleMediaChannel *chan, - GabbleJingleContent *content) + WockyJingleContent *content) { GabbleMediaChannelPrivate *priv; guint i; @@ -1298,7 +1271,7 @@ _find_stream_by_content (GabbleMediaChannel *chan, for (i = 0; i < priv->streams->len; i++) { GabbleMediaStream *stream = g_ptr_array_index (priv->streams, i); - GabbleJingleContent *c = GABBLE_JINGLE_CONTENT ( + WockyJingleContent *c = WOCKY_JINGLE_CONTENT ( gabble_media_stream_get_content (stream)); if (content == c) @@ -1329,9 +1302,9 @@ gabble_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface, priv = obj->priv; - if (!gabble_jingle_session_can_modify_contents (priv->session)) + if (!wocky_jingle_session_can_modify_contents (priv->session)) { - GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + GError e = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Streams can't be removed from Google Talk calls" }; dbus_g_method_return_error (context, &e); return; @@ -1374,7 +1347,7 @@ gabble_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface, if (stream_objs->len > 0) { GabbleMediaStream *stream; - GabbleJingleMediaRtp *c; + WockyJingleMediaRtp *c; for (i = 0; i < stream_objs->len; i++) { @@ -1383,8 +1356,8 @@ gabble_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface, /* FIXME: make sure session emits content-removed, on which we can * delete it from the list */ - gabble_jingle_session_remove_content (priv->session, - (GabbleJingleContent *) c); + wocky_jingle_session_remove_content (priv->session, + (WockyJingleContent *) c); } } @@ -1426,7 +1399,7 @@ gabble_media_channel_request_stream_direction (TpSvcChannelTypeStreamedMedia *if if (stream_direction > TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "given stream direction %u is not valid", stream_direction); dbus_g_method_return_error (context, error); g_error_free (error); @@ -1449,22 +1422,22 @@ gabble_media_channel_request_stream_direction (TpSvcChannelTypeStreamedMedia *if if (stream_direction == TP_MEDIA_STREAM_DIRECTION_NONE) { - if (gabble_jingle_session_can_modify_contents (priv->session)) + if (wocky_jingle_session_can_modify_contents (priv->session)) { - GabbleJingleMediaRtp *c; + WockyJingleMediaRtp *c; DEBUG ("request for NONE direction; removing stream"); c = gabble_media_stream_get_content (stream); - gabble_jingle_session_remove_content (priv->session, - (GabbleJingleContent *) c); + wocky_jingle_session_remove_content (priv->session, + (WockyJingleContent *) c); tp_svc_channel_type_streamed_media_return_from_request_stream_direction ( context); } else { - GError e = { TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + GError e = { TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Stream direction can't be set to None in Google Talk calls" }; DEBUG ("%s", e.message); dbus_g_method_return_error (context, &e); @@ -1489,7 +1462,7 @@ typedef struct { /* number of streams requested == number of content objects */ guint len; /* array of @len borrowed pointers */ - GabbleJingleContent **contents; + WockyJingleContent **contents; /* accumulates borrowed pointers to streams. Initially @len NULL pointers; * when the stream for contents[i] is created, it is stored at streams[i]. */ @@ -1531,7 +1504,7 @@ pending_stream_request_new (GPtrArray *contents, static gboolean pending_stream_request_maybe_satisfy (PendingStreamRequest *p, GabbleMediaChannel *channel, - GabbleJingleContent *content, + WockyJingleContent *content, GabbleMediaStream *stream) { guint i; @@ -1562,7 +1535,7 @@ pending_stream_request_maybe_satisfy (PendingStreamRequest *p, static gboolean pending_stream_request_maybe_fail (PendingStreamRequest *p, GabbleMediaChannel *channel, - GabbleJingleContent *content) + WockyJingleContent *content) { guint i; @@ -1570,7 +1543,7 @@ pending_stream_request_maybe_fail (PendingStreamRequest *p, { if (content == p->contents[i]) { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "A stream was removed before it could be fully set up" }; /* return early */ @@ -1590,7 +1563,7 @@ pending_stream_request_free (gpointer data) if (p->context != NULL) { - GError e = { TP_ERRORS, TP_ERROR_CANCELLED, + GError e = { TP_ERROR, TP_ERROR_CANCELLED, "The session terminated before the requested streams could be added" }; @@ -1612,7 +1585,7 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, { GabbleMediaChannelPrivate *priv = chan->priv; gboolean want_audio, want_video; - JingleDialect dialect; + WockyJingleDialect dialect; guint idx; const gchar *peer_resource; const gchar *transport_ns = NULL; @@ -1635,7 +1608,7 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, } else { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "given media type %u is invalid", media_type); return FALSE; } @@ -1644,7 +1617,7 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, /* existing call; the recipient and the mode has already been decided */ if (priv->session != NULL) { - peer_resource = gabble_jingle_session_get_peer_resource (priv->session); + peer_resource = wocky_jingle_session_get_peer_resource (priv->session); if (peer_resource[0] != '\0') DEBUG ("existing call, using peer resource %s", peer_resource); @@ -1652,9 +1625,9 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, DEBUG ("existing call, using bare JID"); /* is a google call... we have no other option */ - if (!gabble_jingle_session_can_modify_contents (priv->session)) + if (!wocky_jingle_session_can_modify_contents (priv->session)) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Streams can't be added to ongoing Google Talk calls"); return FALSE; } @@ -1663,9 +1636,9 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, * one channel type (video or audio) will be added later */ if (NULL == jingle_pick_best_content_type (priv->conn, peer, peer_resource, - want_audio ? JINGLE_MEDIA_TYPE_AUDIO : JINGLE_MEDIA_TYPE_VIDEO)) + want_audio ? WOCKY_JINGLE_MEDIA_TYPE_AUDIO : WOCKY_JINGLE_MEDIA_TYPE_VIDEO)) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "member does not have the desired audio/video capabilities"); return FALSE; @@ -1674,8 +1647,8 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, /* We assume we already picked the best possible transport ns for the * previous streams, so we just reuse that one */ { - GList *contents = gabble_jingle_session_get_contents (priv->session); - GabbleJingleContent *c; + GList *contents = wocky_jingle_session_get_contents (priv->session); + WockyJingleContent *c; /* If we have a session, we must have at least one content. */ g_assert (contents != NULL); @@ -1683,7 +1656,7 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, c = contents->data; g_list_free (contents); - transport_ns = gabble_jingle_content_get_transport_ns (c); + transport_ns = wocky_jingle_content_get_transport_ns (c); } } /* no existing call; we should choose a recipient and a mode */ @@ -1699,7 +1672,7 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, if (!jingle_pick_best_resource (priv->conn, peer, want_audio, want_video, &transport_ns, &dialect, &peer_resource)) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_CAPABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "member does not have the desired audio/video capabilities"); return FALSE; } @@ -1729,7 +1702,7 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, /* check it's not a ridiculous number of streams */ if ((priv->streams->len + media_types->len) > MAX_STREAMS) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "I think that's quite enough streams already"); return FALSE; } @@ -1741,13 +1714,13 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, for (idx = 0; idx < media_types->len; idx++) { guint media_type = g_array_index (media_types, guint, idx); - GabbleJingleContent *c; + WockyJingleContent *c; const gchar *content_ns; content_ns = jingle_pick_best_content_type (priv->conn, peer, peer_resource, media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? - JINGLE_MEDIA_TYPE_AUDIO : JINGLE_MEDIA_TYPE_VIDEO); + WOCKY_JINGLE_MEDIA_TYPE_AUDIO : WOCKY_JINGLE_MEDIA_TYPE_VIDEO); /* if we got this far, resource should be capable enough, so we * should not fail in choosing ns */ @@ -1756,10 +1729,10 @@ _gabble_media_channel_request_contents (GabbleMediaChannel *chan, DEBUG ("Creating new jingle content with ns %s : %s", content_ns, transport_ns); - c = gabble_jingle_session_add_content (priv->session, + c = wocky_jingle_session_add_content (priv->session, media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? - JINGLE_MEDIA_TYPE_AUDIO : JINGLE_MEDIA_TYPE_VIDEO, - JINGLE_CONTENT_SENDERS_BOTH, NULL, content_ns, transport_ns); + WOCKY_JINGLE_MEDIA_TYPE_AUDIO : WOCKY_JINGLE_MEDIA_TYPE_VIDEO, + WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NULL, content_ns, transport_ns); /* The stream is created in "new-content" callback, and appended to * priv->streams. This is now guaranteed to happen asynchronously (adding @@ -1790,7 +1763,7 @@ destroy_request (struct _delayed_request_streams_ctx *ctx, if (ctx->context != NULL) { GError *error = NULL; - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "cannot add streams: peer has insufficient caps"); ctx->failed_cb (ctx->context, error); g_error_free (error); @@ -1917,7 +1890,7 @@ media_channel_request_streams (GabbleMediaChannel *self, if (priv->peer != 0 && priv->peer != contact_handle) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "cannot add streams for %u: this channel's peer is %u", contact_handle, priv->peer); goto error; @@ -1934,7 +1907,7 @@ media_channel_request_streams (GabbleMediaChannel *self, g_ptr_array_unref (contents); /* signal acceptance */ - gabble_jingle_session_accept (priv->session); + wocky_jingle_session_accept (priv->session); return; @@ -2001,9 +1974,10 @@ gabble_media_channel_request_initial_streams (GabbleMediaChannel *chan, GabbleMediaChannelPrivate *priv = chan->priv; GArray *types = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); guint media_type; + TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); /* This has to be an outgoing call... */ - g_assert (priv->creator == priv->conn->parent.self_handle); + g_assert (priv->creator == tp_base_connection_get_self_handle (base_conn)); /* ...which has just been constructed. */ g_assert (priv->session == NULL); @@ -2080,11 +2054,11 @@ contact_is_media_capable (GabbleMediaChannel *chan, *wait_ret = wait; if (presence == NULL) - g_set_error (error, TP_ERRORS, TP_ERROR_OFFLINE, + g_set_error (error, TP_ERROR, TP_ERROR_OFFLINE, "contact %d (%s) has no presence available", peer, tp_handle_inspect (contact_handles, peer)); else - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_CAPABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, "contact %d (%s) doesn't have sufficient media caps", peer, tp_handle_inspect (contact_handles, peer)); @@ -2100,7 +2074,7 @@ gabble_media_channel_add_member (GObject *obj, GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (obj); GabbleMediaChannelPrivate *priv = chan->priv; TpGroupMixin *mixin = TP_GROUP_MIXIN (obj); - TpIntSet *set; + TpIntset *set; /* did we create this channel? */ if (priv->creator == mixin->self_handle) @@ -2113,7 +2087,7 @@ gabble_media_channel_add_member (GObject *obj, */ if (priv->peer != 0 && priv->peer != handle) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "handle %u cannot be added: this channel's peer is %u", handle, priv->peer); return FALSE; @@ -2160,7 +2134,7 @@ gabble_media_channel_add_member (GObject *obj, /* is the call on hold? */ if (priv->hold_state != TP_LOCAL_HOLD_STATE_UNHELD) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Can't answer a call while it's on hold"); return FALSE; } @@ -2176,13 +2150,13 @@ gabble_media_channel_add_member (GObject *obj, (GFunc) gabble_media_stream_accept_pending_local_send, NULL); /* signal acceptance */ - gabble_jingle_session_accept (priv->session); + wocky_jingle_session_accept (priv->session); return TRUE; } } - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "handle %u cannot be added in the current state", handle); return FALSE; } @@ -2213,33 +2187,33 @@ gabble_media_channel_remove_member (GObject *obj, } else { - JingleReason jingle_reason = JINGLE_REASON_UNKNOWN; + WockyJingleReason wocky_jingle_reason = WOCKY_JINGLE_REASON_UNKNOWN; switch (reason) { case TP_CHANNEL_GROUP_CHANGE_REASON_NONE: - jingle_reason = JINGLE_REASON_UNKNOWN; + wocky_jingle_reason = WOCKY_JINGLE_REASON_UNKNOWN; break; case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE: - jingle_reason = JINGLE_REASON_GONE; + wocky_jingle_reason = WOCKY_JINGLE_REASON_GONE; break; case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: - jingle_reason = JINGLE_REASON_BUSY; + wocky_jingle_reason = WOCKY_JINGLE_REASON_BUSY; break; case TP_CHANNEL_GROUP_CHANGE_REASON_ERROR: - jingle_reason = JINGLE_REASON_GENERAL_ERROR; + wocky_jingle_reason = WOCKY_JINGLE_REASON_GENERAL_ERROR; break; case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: - jingle_reason = JINGLE_REASON_TIMEOUT; + wocky_jingle_reason = WOCKY_JINGLE_REASON_TIMEOUT; break; default: - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u doesn't make sense as a reason to end a call", reason); g_object_unref (chan); return FALSE; } - gabble_jingle_session_terminate (priv->session, jingle_reason, message, + wocky_jingle_session_terminate (priv->session, wocky_jingle_reason, message, error); } @@ -2269,24 +2243,24 @@ copy_stream_list (GabbleMediaChannel *channel) /* return TRUE when the jingle reason is reason enough to raise a * StreamError */ static gboolean -extract_media_stream_error_from_jingle_reason (JingleReason jingle_reason, +extract_media_stream_error_from_jingle_reason (WockyJingleReason wocky_jingle_reason, TpMediaStreamError *stream_error) { TpMediaStreamError _stream_error; /* TODO: Make a better mapping with more distinction of possible errors */ - switch (jingle_reason) + switch (wocky_jingle_reason) { - case JINGLE_REASON_CONNECTIVITY_ERROR: + case WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR: _stream_error = TP_MEDIA_STREAM_ERROR_NETWORK_ERROR; break; - case JINGLE_REASON_MEDIA_ERROR: + case WOCKY_JINGLE_REASON_MEDIA_ERROR: _stream_error = TP_MEDIA_STREAM_ERROR_MEDIA_ERROR; break; - case JINGLE_REASON_FAILED_APPLICATION: + case WOCKY_JINGLE_REASON_FAILED_APPLICATION: _stream_error = TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED; break; - case JINGLE_REASON_GENERAL_ERROR: + case WOCKY_JINGLE_REASON_GENERAL_ERROR: _stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; break; default: @@ -2304,42 +2278,42 @@ extract_media_stream_error_from_jingle_reason (JingleReason jingle_reason, return TRUE; } -static JingleReason +static WockyJingleReason media_stream_error_to_jingle_reason (TpMediaStreamError stream_error) { switch (stream_error) { case TP_MEDIA_STREAM_ERROR_NETWORK_ERROR: - return JINGLE_REASON_CONNECTIVITY_ERROR; + return WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR; case TP_MEDIA_STREAM_ERROR_MEDIA_ERROR: - return JINGLE_REASON_MEDIA_ERROR; + return WOCKY_JINGLE_REASON_MEDIA_ERROR; case TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED: - return JINGLE_REASON_FAILED_APPLICATION; + return WOCKY_JINGLE_REASON_FAILED_APPLICATION; default: - return JINGLE_REASON_GENERAL_ERROR; + return WOCKY_JINGLE_REASON_GENERAL_ERROR; } } static TpChannelGroupChangeReason -jingle_reason_to_group_change_reason (JingleReason jingle_reason) +wocky_jingle_reason_to_group_change_reason (WockyJingleReason wocky_jingle_reason) { - switch (jingle_reason) + switch (wocky_jingle_reason) { - case JINGLE_REASON_BUSY: + case WOCKY_JINGLE_REASON_BUSY: return TP_CHANNEL_GROUP_CHANGE_REASON_BUSY; - case JINGLE_REASON_GONE: + case WOCKY_JINGLE_REASON_GONE: return TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE; - case JINGLE_REASON_TIMEOUT: + case WOCKY_JINGLE_REASON_TIMEOUT: return TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER; - case JINGLE_REASON_CONNECTIVITY_ERROR: - case JINGLE_REASON_FAILED_APPLICATION: - case JINGLE_REASON_FAILED_TRANSPORT: - case JINGLE_REASON_GENERAL_ERROR: - case JINGLE_REASON_MEDIA_ERROR: - case JINGLE_REASON_SECURITY_ERROR: - case JINGLE_REASON_INCOMPATIBLE_PARAMETERS: - case JINGLE_REASON_UNSUPPORTED_APPLICATIONS: - case JINGLE_REASON_UNSUPPORTED_TRANSPORTS: + case WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR: + case WOCKY_JINGLE_REASON_FAILED_APPLICATION: + case WOCKY_JINGLE_REASON_FAILED_TRANSPORT: + case WOCKY_JINGLE_REASON_GENERAL_ERROR: + case WOCKY_JINGLE_REASON_MEDIA_ERROR: + case WOCKY_JINGLE_REASON_SECURITY_ERROR: + case WOCKY_JINGLE_REASON_INCOMPATIBLE_PARAMETERS: + case WOCKY_JINGLE_REASON_UNSUPPORTED_APPLICATIONS: + case WOCKY_JINGLE_REASON_UNSUPPORTED_TRANSPORTS: return TP_CHANNEL_GROUP_CHANGE_REASON_ERROR; default: return TP_CHANNEL_GROUP_CHANGE_REASON_NONE; @@ -2347,9 +2321,9 @@ jingle_reason_to_group_change_reason (JingleReason jingle_reason) } static void -session_terminated_cb (GabbleJingleSession *session, +session_terminated_cb (WockyJingleSession *session, gboolean local_terminator, - JingleReason jingle_reason, + WockyJingleReason wocky_jingle_reason, const gchar *text, gpointer user_data) { @@ -2357,8 +2331,8 @@ session_terminated_cb (GabbleJingleSession *session, GabbleMediaChannelPrivate *priv = channel->priv; TpGroupMixin *mixin = TP_GROUP_MIXIN (channel); guint terminator; - JingleState state; - TpIntSet *set; + WockyJingleState state; + TpIntset *set; DEBUG ("called"); @@ -2379,7 +2353,7 @@ session_terminated_cb (GabbleJingleSession *session, tp_group_mixin_change_members ((GObject *) channel, text, NULL, set, NULL, NULL, terminator, - jingle_reason_to_group_change_reason (jingle_reason)); + wocky_jingle_reason_to_group_change_reason (wocky_jingle_reason)); tp_intset_destroy (set); @@ -2398,7 +2372,7 @@ session_terminated_cb (GabbleJingleSession *session, guint i; TpMediaStreamError stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; gboolean is_error = extract_media_stream_error_from_jingle_reason ( - jingle_reason, &stream_error); + wocky_jingle_reason, &stream_error); for (i = 0; i < tmp->len; i++) { @@ -2437,15 +2411,15 @@ session_terminated_cb (GabbleJingleSession *session, static void -session_state_changed_cb (GabbleJingleSession *session, +session_state_changed_cb (WockyJingleSession *session, GParamSpec *arg1, GabbleMediaChannel *channel) { GObject *as_object = (GObject *) channel; GabbleMediaChannelPrivate *priv = channel->priv; TpGroupMixin *mixin = TP_GROUP_MIXIN (channel); - JingleState state; - TpIntSet *set; + WockyJingleState state; + TpIntset *set; DEBUG ("called"); @@ -2455,8 +2429,8 @@ session_state_changed_cb (GabbleJingleSession *session, set = tp_intset_new_containing (priv->peer); - if (state >= JINGLE_STATE_PENDING_INITIATE_SENT && - state < JINGLE_STATE_ACTIVE && + if (state >= WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT && + state < WOCKY_JINGLE_STATE_ACTIVE && !tp_handle_set_is_member (mixin->members, priv->peer)) { /* The first time we send anything to the other user, they materialise @@ -2471,7 +2445,7 @@ session_state_changed_cb (GabbleJingleSession *session, tp_group_mixin_change_flags (as_object, 0, TP_CHANNEL_GROUP_FLAG_CAN_ADD); } - if (state == JINGLE_STATE_ACTIVE && + if (state == WOCKY_JINGLE_STATE_ACTIVE && priv->creator == mixin->self_handle) { @@ -2536,7 +2510,7 @@ stream_error_cb (GabbleMediaStream *stream, GabbleMediaChannel *chan) { GabbleMediaChannelPrivate *priv = chan->priv; - GabbleJingleMediaRtp *c; + WockyJingleMediaRtp *c; GList *contents; guint id; @@ -2545,9 +2519,9 @@ stream_error_cb (GabbleMediaStream *stream, tp_svc_channel_type_streamed_media_emit_stream_error (chan, id, errno, message); - contents = gabble_jingle_session_get_contents (priv->session); + contents = wocky_jingle_session_get_contents (priv->session); - if (gabble_jingle_session_can_modify_contents (priv->session) && + if (wocky_jingle_session_can_modify_contents (priv->session) && g_list_length (contents) > 1) { /* remove stream from session (removal will be signalled @@ -2556,11 +2530,11 @@ stream_error_cb (GabbleMediaStream *stream, c = gabble_media_stream_get_content (stream); if (errno == TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED) - gabble_jingle_content_reject ((GabbleJingleContent *) c, - JINGLE_REASON_FAILED_APPLICATION); + wocky_jingle_content_reject ((WockyJingleContent *) c, + WOCKY_JINGLE_REASON_FAILED_APPLICATION); else - gabble_jingle_session_remove_content (priv->session, - (GabbleJingleContent *) c); + wocky_jingle_session_remove_content (priv->session, + (WockyJingleContent *) c); } else { @@ -2570,7 +2544,7 @@ stream_error_cb (GabbleMediaStream *stream, * Talk-using peer.) */ DEBUG ("Terminating call in response to stream error"); - gabble_jingle_session_terminate (priv->session, + wocky_jingle_session_terminate (priv->session, media_stream_error_to_jingle_reason (errno), message, NULL); } @@ -2620,7 +2594,7 @@ stream_direction_changed_cb (GabbleMediaStream *stream, static void construct_stream (GabbleMediaChannel *chan, - GabbleJingleContent *c, + WockyJingleContent *c, const gchar *name, const gchar *nat_traversal, const GPtrArray *relays, @@ -2713,7 +2687,7 @@ construct_stream (GabbleMediaChannel *chan, stream_direction_changed_cb (stream, NULL, chan); gabble_media_channel_hold_new_stream (chan, stream, - GABBLE_JINGLE_MEDIA_RTP (c)); + WOCKY_JINGLE_MEDIA_RTP (c)); if (priv->ready) { @@ -2789,7 +2763,7 @@ google_relay_session_cb (GPtrArray *relays, } static void -content_removed_cb (GabbleJingleContent *content, +content_removed_cb (WockyJingleContent *content, StreamCreationData *d) { @@ -2829,7 +2803,7 @@ content_removed_cb (GabbleJingleContent *content, static void create_stream_from_content (GabbleMediaChannel *self, - GabbleJingleContent *c, + WockyJingleContent *c, gboolean initial) { gchar *name; @@ -2839,7 +2813,7 @@ create_stream_from_content (GabbleMediaChannel *self, "name", &name, NULL); - if (G_OBJECT_TYPE (c) != GABBLE_TYPE_JINGLE_MEDIA_RTP) + if (G_OBJECT_TYPE (c) != WOCKY_TYPE_JINGLE_MEDIA_RTP) { DEBUG ("ignoring non MediaRtp content '%s'", name); g_free (name); @@ -2864,7 +2838,7 @@ create_stream_from_content (GabbleMediaChannel *self, self->priv->stream_creation_datas = g_list_prepend ( self->priv->stream_creation_datas, d); - switch (gabble_jingle_content_get_transport_type (c)) + switch (wocky_jingle_content_get_transport_type (c)) { case JINGLE_TRANSPORT_GOOGLE_P2P: /* See if our server is Google, and if it is, ask them for a relay. @@ -2872,7 +2846,7 @@ create_stream_from_content (GabbleMediaChannel *self, * don't yet know whether there will be RTCP. */ d->nat_traversal = "gtalk-p2p"; DEBUG ("Attempting to create Google relay session"); - gabble_jingle_info_create_google_relay_session ( + wocky_jingle_info_create_google_relay_session ( gabble_jingle_mint_get_info (self->priv->conn->jingle_mint), 2, google_relay_session_cb, d); return; @@ -2892,8 +2866,8 @@ create_stream_from_content (GabbleMediaChannel *self, } static void -session_content_rejected_cb (GabbleJingleSession *session, - GabbleJingleContent *c, JingleReason reason, const gchar *message, +session_content_rejected_cb (WockyJingleSession *session, + WockyJingleContent *c, WockyJingleReason reason, const gchar *message, gpointer user_data) { GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (user_data); @@ -2916,8 +2890,8 @@ session_content_rejected_cb (GabbleJingleSession *session, } static void -session_new_content_cb (GabbleJingleSession *session, - GabbleJingleContent *c, gpointer user_data) +session_new_content_cb (WockyJingleSession *session, + WockyJingleContent *c, gpointer user_data) { GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (user_data); @@ -2966,7 +2940,7 @@ gabble_media_channel_ready (TpSvcMediaSessionHandler *iface, * error message describes the only legitimate situation in which this * could arise. */ - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, "call has already ended" }; + GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "call has already ended" }; DEBUG ("no session, returning an error."); dbus_g_method_return_error (context, &e); @@ -2998,7 +2972,7 @@ gabble_media_channel_error (TpSvcMediaSessionHandler *iface, GabbleMediaChannelPrivate *priv; GPtrArray *tmp; guint i; - JingleState state; + WockyJingleState state; g_assert (GABBLE_IS_MEDIA_CHANNEL (self)); @@ -3013,7 +2987,7 @@ gabble_media_channel_error (TpSvcMediaSessionHandler *iface, * error message describes the only legitimate situation in which this * could arise. */ - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, "call has already ended" }; + GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "call has already ended" }; DEBUG ("no session, returning an error."); dbus_g_method_return_error (context, &e); @@ -3025,16 +2999,16 @@ gabble_media_channel_error (TpSvcMediaSessionHandler *iface, g_object_get (priv->session, "state", &state, NULL); - if (state == JINGLE_STATE_ENDED) + if (state == WOCKY_JINGLE_STATE_ENDED) { tp_svc_media_session_handler_return_from_error (context); return; } - else if (state == JINGLE_STATE_PENDING_CREATED) + else if (state == WOCKY_JINGLE_STATE_PENDING_CREATED) { /* shortcut to prevent sending remove actions if we haven't sent an * initiate yet */ - g_object_set (self, "state", JINGLE_STATE_ENDED, NULL); + g_object_set (self, "state", WOCKY_JINGLE_STATE_ENDED, NULL); tp_svc_media_session_handler_return_from_error (context); return; } diff --git a/src/media-channel.h b/src/media-channel.h index b10886ca2..cbe488af2 100644 --- a/src/media-channel.h +++ b/src/media-channel.h @@ -23,8 +23,7 @@ #include <glib-object.h> -#include <telepathy-glib/dbus-properties-mixin.h> -#include <telepathy-glib/group-mixin.h> +#include <telepathy-glib/telepathy-glib.h> #include <telepathy-glib/properties-mixin.h> #include "presence.h" diff --git a/src/media-factory.c b/src/media-factory.c index 8f3e39761..85e4a1c46 100644 --- a/src/media-factory.c +++ b/src/media-factory.c @@ -25,18 +25,17 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> + +#include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_MEDIA #include "gabble/caps-channel-manager.h" #include "connection.h" #include "debug.h" -#include "jingle-factory.h" -#include "jingle-media-rtp.h" -#include "jingle-session.h" #include "call-channel.h" #include "media-channel.h" @@ -261,7 +260,7 @@ media_channel_closed_cb (GabbleMediaChannel *chan, gpointer user_data) */ static GabbleMediaChannel * new_media_channel (GabbleMediaFactory *fac, - GabbleJingleSession *sess, + WockyJingleSession *sess, TpHandle maybe_peer, gboolean peer_in_rp, gboolean initial_audio, @@ -278,7 +277,7 @@ new_media_channel (GabbleMediaFactory *fac, conn = (TpBaseConnection *) priv->conn; object_path = g_strdup_printf ("%s/MediaChannel%u", - conn->object_path, priv->channel_index); + tp_base_connection_get_object_path (conn), priv->channel_index); priv->channel_index += 1; chan = g_object_new (GABBLE_TYPE_MEDIA_CHANNEL, @@ -360,7 +359,7 @@ call_channel_initialized (GObject *source, */ static void new_call_channel (GabbleMediaFactory *self, - GabbleJingleSession *sess, + WockyJingleSession *sess, TpHandle peer, gboolean initial_audio, const gchar *initial_audio_name, @@ -377,10 +376,10 @@ new_call_channel (GabbleMediaFactory *self, if (sess != NULL) initiator = peer; else - initiator = conn->self_handle; + initiator = tp_base_connection_get_self_handle (conn); object_path = g_strdup_printf ("%s/CallChannel%u", - conn->object_path, self->priv->channel_index); + tp_base_connection_get_object_path (conn), self->priv->channel_index); self->priv->channel_index++; channel = g_object_new (GABBLE_TYPE_CALL_CHANNEL, @@ -442,7 +441,7 @@ gabble_media_factory_close_all (GabbleMediaFactory *fac) static void new_jingle_session_cb (GabbleJingleMint *jm, - GabbleJingleSession *sess, + WockyJingleSession *sess, gpointer data) { GabbleMediaFactory *self = GABBLE_MEDIA_FACTORY (data); @@ -450,8 +449,8 @@ new_jingle_session_cb (GabbleJingleMint *jm, TpHandleRepoIface *contacts; TpHandle peer; - if (gabble_jingle_session_get_content_type (sess) != - GABBLE_TYPE_JINGLE_MEDIA_RTP) + if (wocky_jingle_session_get_content_type (sess) != + WOCKY_TYPE_JINGLE_MEDIA_RTP) return; if (gabble_muc_factory_handle_jingle_session (priv->conn->muc_factory, sess)) @@ -462,7 +461,7 @@ new_jingle_session_cb (GabbleJingleMint *jm, contacts = tp_base_connection_get_handles (TP_BASE_CONNECTION (priv->conn), TP_HANDLE_TYPE_CONTACT); - peer = tp_handle_ensure (contacts, gabble_jingle_session_get_peer_jid (sess), + peer = tp_handle_ensure (contacts, wocky_jingle_session_get_peer_jid (sess), NULL, NULL); if (self->priv->use_call_channels) @@ -481,11 +480,11 @@ new_jingle_session_cb (GabbleJingleMint *jm, /* FIXME: we need this detection to properly adjust nat-traversal on * the channel. We hope all contents will have the same transport... */ - cs = gabble_jingle_session_get_contents (sess); + cs = wocky_jingle_session_get_contents (sess); if (cs != NULL) { - GabbleJingleContent *c = cs->data; + WockyJingleContent *c = cs->data; gchar *ns; g_object_get (c, "transport-ns", &ns, NULL); @@ -776,7 +775,7 @@ gabble_media_factory_requestotron (TpChannelManager *manager, if (require_target_handle) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "A valid Contact handle must be provided when requesting a media " "channel"); goto error; @@ -918,7 +917,7 @@ gabble_media_factory_create_call (TpChannelManager *manager, if (!initial_audio && !initial_video) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Call channel must contain at least " "one of InitialAudio or InitialVideo"); goto error; diff --git a/src/media-stream.c b/src/media-stream.c index 75c9ea38f..426aa8a20 100644 --- a/src/media-stream.c +++ b/src/media-stream.c @@ -27,23 +27,15 @@ #include <string.h> #include <dbus/dbus-glib.h> -#include <telepathy-glib/debug-ansi.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-media-interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_MEDIA #include "connection.h" #include "debug.h" #include "gabble-signals-marshal.h" -#include "jingle-content.h" -#include "jingle-session.h" -#include "jingle-media-rtp.h" #include "media-channel.h" #include "namespaces.h" #include "util.h" @@ -95,9 +87,8 @@ enum struct _GabbleMediaStreamPrivate { - GabbleJingleContent *content; + WockyJingleContent *content; - GabbleMediaSessionMode mode; TpDBusDaemon *dbus_daemon; gchar *object_path; guint id; @@ -145,26 +136,26 @@ static void push_remote_candidates (GabbleMediaStream *stream); static void push_playing (GabbleMediaStream *stream); static void push_sending (GabbleMediaStream *stream); -static void new_remote_candidates_cb (GabbleJingleContent *content, +static void new_remote_candidates_cb (WockyJingleContent *content, GList *clist, GabbleMediaStream *stream); -static void new_remote_media_description_cb (GabbleJingleContent *content, - JingleMediaDescription *md, GabbleMediaStream *stream); -static void content_state_changed_cb (GabbleJingleContent *c, +static void new_remote_media_description_cb (WockyJingleContent *content, + WockyJingleMediaDescription *md, GabbleMediaStream *stream); +static void content_state_changed_cb (WockyJingleContent *c, GParamSpec *pspec, GabbleMediaStream *stream); -static void content_senders_changed_cb (GabbleJingleContent *c, +static void content_senders_changed_cb (WockyJingleContent *c, GParamSpec *pspec, GabbleMediaStream *stream); -static void remote_state_changed_cb (GabbleJingleSession *session, +static void remote_state_changed_cb (WockyJingleSession *session, GabbleMediaStream *stream); -static void content_removed_cb (GabbleJingleContent *content, +static void content_removed_cb (WockyJingleContent *content, GabbleMediaStream *stream); -static void update_direction (GabbleMediaStream *stream, GabbleJingleContent *c); +static void update_direction (GabbleMediaStream *stream, WockyJingleContent *c); static void update_sending (GabbleMediaStream *stream, gboolean start_sending); GabbleMediaStream * gabble_media_stream_new ( TpDBusDaemon *dbus_daemon, const gchar *object_path, - GabbleJingleContent *content, + WockyJingleContent *content, const gchar *name, guint id, const gchar *nat_traversal, @@ -174,7 +165,7 @@ gabble_media_stream_new ( GPtrArray *empty = NULL; GabbleMediaStream *result; - g_return_val_if_fail (GABBLE_IS_JINGLE_MEDIA_RTP (content), NULL); + g_return_val_if_fail (WOCKY_IS_JINGLE_MEDIA_RTP (content), NULL); if (relay_info == NULL) { @@ -246,13 +237,13 @@ _get_initial_codecs_and_candidates (gpointer user_data) { GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (user_data); GabbleMediaStreamPrivate *priv = stream->priv; - JingleMediaDescription *md; + WockyJingleMediaDescription *md; priv->initial_getter_id = 0; /* we can immediately get the codecs if we're responder */ - md = gabble_jingle_media_rtp_get_remote_media_description ( - GABBLE_JINGLE_MEDIA_RTP (priv->content)); + md = wocky_jingle_media_rtp_get_remote_media_description ( + WOCKY_JINGLE_MEDIA_RTP (priv->content)); if (md != NULL) new_remote_media_description_cb (priv->content, md, stream); @@ -260,7 +251,7 @@ _get_initial_codecs_and_candidates (gpointer user_data) * us (e.g. specified in session-initiate/content-add), we don't want to * miss them */ new_remote_candidates_cb (priv->content, - gabble_jingle_content_get_remote_candidates (priv->content), stream); + wocky_jingle_content_get_remote_candidates (priv->content), stream); return FALSE; } @@ -272,9 +263,8 @@ gabble_media_stream_constructor (GType type, guint n_props, GObject *obj; GabbleMediaStream *stream; GabbleMediaStreamPrivate *priv; - GabbleJingleFactory *jf; - gchar *stun_server; - guint stun_port; + WockyJingleFactory *jf; + GList *stun_servers; /* call base class constructor */ obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)-> @@ -287,22 +277,20 @@ gabble_media_stream_constructor (GType type, guint n_props, /* STUN servers are needed as soon as the stream appears, so there's little * point in waiting for them - either they've already been resolved, or * we're too late to use them for this stream */ - jf = gabble_jingle_session_get_factory (priv->content->session); - - /* maybe one day we'll support multiple STUN servers */ - if (gabble_jingle_info_get_stun_server ( - gabble_jingle_factory_get_jingle_info (jf), - &stun_server, &stun_port)) + jf = wocky_jingle_session_get_factory (priv->content->session); + stun_servers = wocky_jingle_info_get_stun_servers ( + wocky_jingle_factory_get_jingle_info (jf)); + while (stun_servers != NULL) { - GValueArray *va = g_value_array_new (2); - - g_value_array_append (va, NULL); - g_value_array_append (va, NULL); - g_value_init (va->values + 0, G_TYPE_STRING); - g_value_init (va->values + 1, G_TYPE_UINT); - g_value_take_string (va->values + 0, stun_server); - g_value_set_uint (va->values + 1, stun_port); + WockyStunServer *stun_server = stun_servers->data; + GValueArray *va = tp_value_array_build (2, + G_TYPE_STRING, stun_server->address, + G_TYPE_UINT, (guint) stun_server->port, + G_TYPE_INVALID); + g_ptr_array_add (priv->stun_servers, va); + + stun_servers = g_list_delete_link (stun_servers, stun_servers); } /* go for the bus */ @@ -311,7 +299,7 @@ gabble_media_stream_constructor (GType type, guint n_props, update_direction (stream, priv->content); - /* MediaStream is created as soon as GabbleJingleContent is + /* MediaStream is created as soon as WockyJingleContent is * created, but we want to let it parse the initiation (if * initiated by remote end) before we pick up initial * codecs and candidates. @@ -455,7 +443,7 @@ gabble_media_stream_set_property (GObject *object, "locally-created", &locally_created, NULL); - if (jtype == JINGLE_MEDIA_TYPE_VIDEO) + if (jtype == WOCKY_JINGLE_MEDIA_TYPE_VIDEO) priv->media_type = TP_MEDIA_STREAM_TYPE_VIDEO; else priv->media_type = TP_MEDIA_STREAM_TYPE_AUDIO; @@ -630,9 +618,9 @@ gabble_media_stream_class_init (GabbleMediaStreamClass *gabble_media_stream_clas G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK); g_object_class_install_property (object_class, PROP_LOCAL_HOLD, param_spec); - param_spec = g_param_spec_object ("content", "GabbleJingleContent object", + param_spec = g_param_spec_object ("content", "WockyJingleContent object", "Jingle content signalling this media stream.", - GABBLE_TYPE_JINGLE_CONTENT, + WOCKY_TYPE_JINGLE_CONTENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NICK | @@ -910,7 +898,7 @@ gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, { GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); GabbleMediaStreamPrivate *priv; - JingleState state; + WockyJingleState state; GList *li = NULL; guint i; @@ -922,9 +910,9 @@ gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, /* FIXME: maybe this should be an assertion in case the channel * isn't closed early enough right now? */ - if (state > JINGLE_STATE_ACTIVE) + if (state > WOCKY_JINGLE_STATE_ACTIVE) { - DEBUG ("state > JINGLE_STATE_ACTIVE, doing nothing"); + DEBUG ("state > WOCKY_JINGLE_STATE_ACTIVE, doing nothing"); tp_svc_media_stream_handler_return_from_new_native_candidate (context); return; } @@ -934,7 +922,7 @@ gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, GValueArray *transport; guint component; const gchar *addr; - JingleCandidate *c; + WockyJingleCandidate *c; transport = g_ptr_array_index (transports, i); component = g_value_get_uint (g_value_array_get_nth (transport, 0)); @@ -954,7 +942,7 @@ gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, continue; } - c = jingle_candidate_new ( + c = wocky_jingle_candidate_new ( /* protocol */ g_value_get_uint (g_value_array_get_nth (transport, 3)), /* candidate type, we're relying on 1:1 candidate type mapping */ @@ -982,7 +970,7 @@ gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, } if (li != NULL) - gabble_jingle_content_add_candidates (priv->content, li); + wocky_jingle_content_add_candidates (priv->content, li); tp_svc_media_stream_handler_return_from_new_native_candidate (context); } @@ -1043,7 +1031,7 @@ pass_local_codecs (GabbleMediaStream *stream, { GabbleMediaStreamPrivate *priv = stream->priv; guint i; - JingleMediaDescription *md; + WockyJingleMediaDescription *md; const GPtrArray *hdrexts; GHashTable *fbs; GError *wocky_error = NULL; @@ -1051,7 +1039,7 @@ pass_local_codecs (GabbleMediaStream *stream, DEBUG ("putting list of %d supported codecs from stream-engine into cache", codecs->len); - md = jingle_media_description_new (); + md = wocky_jingle_media_description_new (); fbs = g_value_get_boxed (&priv->local_feedback_messages); @@ -1063,7 +1051,7 @@ pass_local_codecs (GabbleMediaStream *stream, guint id, clock_rate, channels; gchar *name; GHashTable *params; - JingleCodec *c; + WockyJingleCodec *c; GValueArray *fb_codec; g_value_init (&codec, codec_struct_type); @@ -1113,7 +1101,7 @@ pass_local_codecs (GabbleMediaStream *stream, subtype = g_value_get_string (val); c->feedback_msgs = g_list_append (c->feedback_msgs, - jingle_feedback_message_new (type, subtype)); + wocky_jingle_feedback_message_new (type, subtype)); } } } @@ -1139,7 +1127,7 @@ pass_local_codecs (GabbleMediaStream *stream, GValueArray *hdrext; guint id; guint direction; - JingleContentSenders senders; + WockyJingleContentSenders senders; gchar *uri; gchar *params; @@ -1168,37 +1156,37 @@ pass_local_codecs (GabbleMediaStream *stream, switch (direction) { case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: - senders = JINGLE_CONTENT_SENDERS_BOTH; + senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; break; case TP_MEDIA_STREAM_DIRECTION_NONE: - senders = JINGLE_CONTENT_SENDERS_NONE; + senders = WOCKY_JINGLE_CONTENT_SENDERS_NONE; break; case TP_MEDIA_STREAM_DIRECTION_SEND: - senders = initiated_by_us ? JINGLE_CONTENT_SENDERS_INITIATOR : - JINGLE_CONTENT_SENDERS_RESPONDER; + senders = initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : + WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER; break; case TP_MEDIA_STREAM_DIRECTION_RECEIVE: - senders = initiated_by_us ? JINGLE_CONTENT_SENDERS_RESPONDER : - JINGLE_CONTENT_SENDERS_INITIATOR; + senders = initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : + WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; break; default: g_assert_not_reached (); } md->hdrexts = g_list_append (md->hdrexts, - jingle_rtp_header_extension_new (id, senders, uri)); + wocky_jingle_rtp_header_extension_new (id, senders, uri)); } /* Can only be used once */ g_value_reset (&priv->local_rtp_hdrexts); } - jingle_media_description_simplify (md); + wocky_jingle_media_description_simplify (md); if (jingle_media_rtp_set_local_media_description ( - GABBLE_JINGLE_MEDIA_RTP (priv->content), md, ready, &wocky_error)) + WOCKY_JINGLE_MEDIA_RTP (priv->content), md, ready, &wocky_error)) return TRUE; - g_set_error_literal (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, wocky_error->message); g_clear_error (&wocky_error); return FALSE; @@ -1226,7 +1214,7 @@ gabble_media_stream_set_local_codecs (TpSvcMediaStreamHandler *iface, priv->local_codecs_set = TRUE; - if (gabble_jingle_content_is_created_by_us (self->priv->content)) + if (wocky_jingle_content_is_created_by_us (self->priv->content)) { if (!pass_local_codecs (self, codecs, self->priv->created_locally, &error)) @@ -1260,17 +1248,17 @@ gabble_media_stream_stream_state (TpSvcMediaStreamHandler *iface, { GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); GabbleMediaStreamPrivate *priv = self->priv; - JingleTransportState ts = JINGLE_TRANSPORT_STATE_DISCONNECTED; + WockyJingleTransportState ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED; switch (connection_state) { case TP_MEDIA_STREAM_STATE_DISCONNECTED: - ts = JINGLE_TRANSPORT_STATE_DISCONNECTED; + ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED; break; case TP_MEDIA_STREAM_STATE_CONNECTING: - ts = JINGLE_TRANSPORT_STATE_CONNECTING; + ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTING; break; case TP_MEDIA_STREAM_STATE_CONNECTED: - ts = JINGLE_TRANSPORT_STATE_CONNECTED; + ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED; break; default: DEBUG ("ignoring unknown connection state %u", connection_state); @@ -1278,7 +1266,7 @@ gabble_media_stream_stream_state (TpSvcMediaStreamHandler *iface, } g_object_set (self, "connection-state", connection_state, NULL); - gabble_jingle_content_set_transport_state (priv->content, ts); + wocky_jingle_content_set_transport_state (priv->content, ts); OUT: tp_svc_media_stream_handler_return_from_stream_state (context); @@ -1304,7 +1292,7 @@ gabble_media_stream_supported_codecs (TpSvcMediaStreamHandler *iface, if (codecs->len == 0) { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "SupportedCodecs must have a non-empty list of codecs" }; dbus_g_method_return_error (context, &e); @@ -1357,7 +1345,7 @@ gabble_media_stream_codecs_updated (TpSvcMediaStreamHandler *iface, if (!self->priv->local_codecs_set) { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "CodecsUpdated may only be called once an initial set of codecs " "has been set" }; @@ -1440,7 +1428,7 @@ gabble_media_stream_close (GabbleMediaStream *stream) } static void -insert_feedback_message (JingleFeedbackMessage *fb, GPtrArray *fb_msgs) +insert_feedback_message (WockyJingleFeedbackMessage *fb, GPtrArray *fb_msgs) { GValueArray *msg; @@ -1454,8 +1442,8 @@ insert_feedback_message (JingleFeedbackMessage *fb, GPtrArray *fb_msgs) } static void -new_remote_media_description_cb (GabbleJingleContent *content, - JingleMediaDescription *md, GabbleMediaStream *stream) +new_remote_media_description_cb (WockyJingleContent *content, + WockyJingleMediaDescription *md, GabbleMediaStream *stream) { GabbleMediaStreamPrivate *priv; GList *li; @@ -1514,7 +1502,7 @@ new_remote_media_description_cb (GabbleJingleContent *content, for (li = md->codecs; li; li = li->next) { GValue codec = { 0, }; - JingleCodec *c = li->data; + WockyJingleCodec *c = li->data; g_value_init (&codec, codec_struct_type); g_value_take_boxed (&codec, @@ -1565,7 +1553,7 @@ new_remote_media_description_cb (GabbleJingleContent *content, for (li = md->hdrexts; li; li = li->next) { - JingleRtpHeaderExtension *h = li->data; + WockyJingleRtpHeaderExtension *h = li->data; TpMediaStreamDirection direction; if (!have_initiator) @@ -1577,17 +1565,17 @@ new_remote_media_description_cb (GabbleJingleContent *content, switch (h->senders) { - case JINGLE_CONTENT_SENDERS_BOTH: + case WOCKY_JINGLE_CONTENT_SENDERS_BOTH: direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; break; - case JINGLE_CONTENT_SENDERS_NONE: + case WOCKY_JINGLE_CONTENT_SENDERS_NONE: direction = TP_MEDIA_STREAM_DIRECTION_NONE; break; - case JINGLE_CONTENT_SENDERS_INITIATOR: + case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR: direction = initiated_by_us ? TP_MEDIA_STREAM_DIRECTION_SEND : TP_MEDIA_STREAM_DIRECTION_RECEIVE; break; - case JINGLE_CONTENT_SENDERS_RESPONDER: + case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER: direction = initiated_by_us ? TP_MEDIA_STREAM_DIRECTION_RECEIVE : TP_MEDIA_STREAM_DIRECTION_SEND; break; @@ -1645,7 +1633,7 @@ push_remote_media_description (GabbleMediaStream *stream) } static void -new_remote_candidates_cb (GabbleJingleContent *content, +new_remote_candidates_cb (WockyJingleContent *content, GList *clist, GabbleMediaStream *stream) { GabbleMediaStreamPrivate *priv = stream->priv; @@ -1662,7 +1650,7 @@ new_remote_candidates_cb (GabbleJingleContent *content, GValue candidate = { 0, }; GPtrArray *transports; GValue transport = { 0, }; - JingleCandidate *c = li->data; + WockyJingleCandidate *c = li->data; GType transport_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_TRANSPORT; GType candidate_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE; @@ -1674,7 +1662,7 @@ new_remote_candidates_cb (GabbleJingleContent *content, 0, c->component, 1, c->address, 2, c->port, - 3, c->protocol == JINGLE_TRANSPORT_PROTOCOL_UDP ? 0 : 1, + 3, c->protocol == WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP ? 0 : 1, 4, "RTP", 5, "AVP", 6, (gdouble) (c->preference / 65536.0), @@ -1712,19 +1700,19 @@ new_remote_candidates_cb (GabbleJingleContent *content, } static void -content_state_changed_cb (GabbleJingleContent *c, +content_state_changed_cb (WockyJingleContent *c, GParamSpec *pspec, GabbleMediaStream *stream) { GabbleMediaStreamPrivate *priv = stream->priv; - JingleContentState state; + WockyJingleContentState state; g_object_get (c, "state", &state, NULL); DEBUG ("called"); switch (state) { - case JINGLE_CONTENT_STATE_ACKNOWLEDGED: + case WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED: /* connected stream means we can play, but sending is determined * by content senders (in update_senders) */ stream->playing = TRUE; @@ -1732,7 +1720,7 @@ content_state_changed_cb (GabbleJingleContent *c, push_playing (stream); push_sending (stream); break; - case JINGLE_CONTENT_STATE_REMOVING: + case WOCKY_JINGLE_CONTENT_STATE_REMOVING: stream->playing = FALSE; priv->sending = FALSE; push_playing (stream); @@ -1824,12 +1812,12 @@ push_sending (GabbleMediaStream *stream) } static void -update_direction (GabbleMediaStream *stream, GabbleJingleContent *c) +update_direction (GabbleMediaStream *stream, WockyJingleContent *c) { CombinedStreamDirection new_combined_dir; TpMediaStreamDirection requested_dir, current_dir; TpMediaStreamPendingSend pending_send; - JingleContentSenders senders; + WockyJingleContentSenders senders; gboolean local_initiator; DEBUG ("called"); @@ -1838,15 +1826,15 @@ update_direction (GabbleMediaStream *stream, GabbleJingleContent *c) g_object_get (c->session, "local-initiator", &local_initiator, NULL); switch (senders) { - case JINGLE_CONTENT_SENDERS_INITIATOR: + case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR: requested_dir = local_initiator ? TP_MEDIA_STREAM_DIRECTION_SEND : TP_MEDIA_STREAM_DIRECTION_RECEIVE; break; - case JINGLE_CONTENT_SENDERS_RESPONDER: + case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER: requested_dir = local_initiator ? TP_MEDIA_STREAM_DIRECTION_RECEIVE : TP_MEDIA_STREAM_DIRECTION_SEND; break; - case JINGLE_CONTENT_SENDERS_BOTH: + case WOCKY_JINGLE_CONTENT_SENDERS_BOTH: requested_dir = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; break; default: @@ -1878,7 +1866,7 @@ update_direction (GabbleMediaStream *stream, GabbleJingleContent *c) } static void -content_senders_changed_cb (GabbleJingleContent *c, +content_senders_changed_cb (WockyJingleContent *c, GParamSpec *pspec, GabbleMediaStream *stream) { @@ -1886,20 +1874,20 @@ content_senders_changed_cb (GabbleJingleContent *c, } static void -remote_state_changed_cb (GabbleJingleSession *session, +remote_state_changed_cb (WockyJingleSession *session, GabbleMediaStream *stream) { GabbleMediaStreamPrivate *priv = stream->priv; gboolean old_hold = priv->on_hold; - priv->on_hold = gabble_jingle_session_get_remote_hold (session); + priv->on_hold = wocky_jingle_session_get_remote_hold (session); if (old_hold != priv->on_hold) push_sending (stream); } static void -content_removed_cb (GabbleJingleContent *content, GabbleMediaStream *stream) +content_removed_cb (WockyJingleContent *content, GabbleMediaStream *stream) { gabble_media_stream_close (stream); } @@ -1913,7 +1901,7 @@ gabble_media_stream_change_direction (GabbleMediaStream *stream, CombinedStreamDirection new_combined_dir; TpMediaStreamDirection current_dir; TpMediaStreamPendingSend pending_send; - JingleContentSenders senders; + WockyJingleContentSenders senders; gboolean local_initiator; current_dir = COMBINED_DIRECTION_GET_DIRECTION (stream->combined_direction); @@ -1935,7 +1923,7 @@ gabble_media_stream_change_direction (GabbleMediaStream *stream, new_combined_dir = MAKE_COMBINED_DIRECTION (requested_dir, pending_send); if (new_combined_dir != stream->combined_direction) { - JingleContentState state; + WockyJingleContentState state; gboolean start_sending; g_object_set (stream, "combined-direction", new_combined_dir, NULL); @@ -1946,7 +1934,7 @@ gabble_media_stream_change_direction (GabbleMediaStream *stream, * This appears to be the meaning of Acknowledged. :-) */ g_object_get (stream->priv->content, "state", &state, NULL); - start_sending = (state == JINGLE_CONTENT_STATE_ACKNOWLEDGED); + start_sending = (state == WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED); update_sending (stream, start_sending); } @@ -1963,25 +1951,25 @@ gabble_media_stream_change_direction (GabbleMediaStream *stream, { case TP_MEDIA_STREAM_DIRECTION_SEND: senders = local_initiator ? - JINGLE_CONTENT_SENDERS_INITIATOR : JINGLE_CONTENT_SENDERS_RESPONDER; + WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER; break; case TP_MEDIA_STREAM_DIRECTION_RECEIVE: senders = local_initiator ? - JINGLE_CONTENT_SENDERS_RESPONDER : JINGLE_CONTENT_SENDERS_INITIATOR; + WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; break; case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: - senders = JINGLE_CONTENT_SENDERS_BOTH; + senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; break; default: g_assert_not_reached (); } - if (!gabble_jingle_content_change_direction (priv->content, senders)) + if (!wocky_jingle_content_change_direction (priv->content, senders)) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "stream direction invalid for the Jingle dialect in use"); return FALSE; } @@ -2056,13 +2044,13 @@ stream_handler_iface_init (gpointer g_iface, gpointer iface_data) #undef IMPLEMENT } -GabbleJingleMediaRtp * +WockyJingleMediaRtp * gabble_media_stream_get_content (GabbleMediaStream *self) { /* FIXME: we should fix this whole class up. It relies throughout on - * self->priv->content actually secretly being a GabbleJingleMediaRtp. + * self->priv->content actually secretly being a WockyJingleMediaRtp. */ - return GABBLE_JINGLE_MEDIA_RTP (self->priv->content); + return WOCKY_JINGLE_MEDIA_RTP (self->priv->content); } void diff --git a/src/media-stream.h b/src/media-stream.h index c8c50929a..2174f52df 100644 --- a/src/media-stream.h +++ b/src/media-stream.h @@ -22,12 +22,8 @@ #define __GABBLE_MEDIA_STREAM_H__ #include <glib-object.h> - -#include "jingle-types.h" -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/dtmf.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/dbus-properties-mixin.h> +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> G_BEGIN_DECLS @@ -102,7 +98,7 @@ void gabble_media_stream_accept_pending_local_send (GabbleMediaStream *stream); GabbleMediaStream *gabble_media_stream_new ( TpDBusDaemon *dbus_daemon, const gchar *object_path, - GabbleJingleContent *content, + WockyJingleContent *content, const gchar *name, guint id, const gchar *nat_traversal, @@ -113,7 +109,7 @@ TpMediaStreamType gabble_media_stream_get_media_type (GabbleMediaStream *self); void gabble_media_stream_add_dtmf_player (GabbleMediaStream *self, TpDTMFPlayer *dtmf_player); -GabbleJingleMediaRtp *gabble_media_stream_get_content (GabbleMediaStream *self); +WockyJingleMediaRtp *gabble_media_stream_get_content (GabbleMediaStream *self); void gabble_media_stream_start_telephony_event (GabbleMediaStream *self, guchar event); void gabble_media_stream_stop_telephony_event (GabbleMediaStream *self); diff --git a/src/message-util.c b/src/message-util.c index 5001be307..01bb71735 100644 --- a/src/message-util.c +++ b/src/message-util.c @@ -23,12 +23,13 @@ */ #include "config.h" + #include "message-util.h" #include <string.h> #include <time.h> -#include <telepathy-glib/dbus.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_IM @@ -41,30 +42,31 @@ void gabble_message_util_add_chat_state (WockyStanza *stanza, TpChannelChatState state) { - WockyNode *node = NULL; WockyNode *n = wocky_stanza_get_top_node (stanza); + const gchar *node_name = NULL; switch (state) { case TP_CHANNEL_CHAT_STATE_GONE: - node = wocky_node_add_child_with_content (n, "gone", NULL); + node_name = "gone"; break; case TP_CHANNEL_CHAT_STATE_INACTIVE: - node = wocky_node_add_child_with_content (n, "inactive", NULL); + node_name = "inactive"; break; case TP_CHANNEL_CHAT_STATE_ACTIVE: - node = wocky_node_add_child_with_content (n, "active", NULL); + node_name = "active"; break; case TP_CHANNEL_CHAT_STATE_PAUSED: - node = wocky_node_add_child_with_content (n, "paused", NULL); + node_name = "paused"; break; case TP_CHANNEL_CHAT_STATE_COMPOSING: - node = wocky_node_add_child_with_content (n, "composing", NULL); + node_name = "composing"; break; } - if (node != NULL) - node->ns = g_quark_from_static_string (NS_CHAT_STATES); + if (node_name != NULL) + wocky_node_add_child_ns_q (n, node_name, + g_quark_from_static_string (NS_CHAT_STATES)); } /** @@ -103,7 +105,7 @@ gabble_message_util_build_stanza (TpMessage *message, #define RETURN_INVALID_ARGUMENT(msg, ...) \ G_STMT_START { \ DEBUG (msg , ## __VA_ARGS__); \ - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, \ + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, \ msg , ## __VA_ARGS__); \ return NULL; \ } G_STMT_END @@ -239,6 +241,7 @@ gabble_tp_send_error_from_wocky_xmpp_error (WockyXmppError err) case WOCKY_XMPP_ERROR_FORBIDDEN: case WOCKY_XMPP_ERROR_NOT_AUTHORIZED: + case WOCKY_XMPP_ERROR_POLICY_VIOLATION: return TP_CHANNEL_TEXT_SEND_ERROR_PERMISSION_DENIED; case WOCKY_XMPP_ERROR_RESOURCE_CONSTRAINT: diff --git a/src/message-util.h b/src/message-util.h index 80853c890..404d431bc 100644 --- a/src/message-util.h +++ b/src/message-util.h @@ -21,7 +21,7 @@ #ifndef __GABBLE_MESSAGE_UTIL_H__ #define __GABBLE_MESSAGE_UTIL_H__ -#include <telepathy-glib/message-mixin.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #include <wocky/wocky.h> diff --git a/src/muc-channel.c b/src/muc-channel.c index 69fd30a6e..15c337b07 100644 --- a/src/muc-channel.c +++ b/src/muc-channel.c @@ -28,13 +28,8 @@ #include <wocky/wocky.h> #include <dbus/dbus-glib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/debug-ansi.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_MUC #include "connection.h" @@ -51,6 +46,10 @@ #include "presence-cache.h" #include "gabble-signals-marshal.h" #include "gabble-enumtypes.h" +#include "tube-dbus.h" +#include "tube-stream.h" +#include "private-tubes-factory.h" +#include "bytestream-factory.h" #define DEFAULT_JOIN_TIMEOUT 180 #define DEFAULT_LEAVE_TIMEOUT 180 @@ -60,7 +59,6 @@ #define PROPS_POLL_INTERVAL_HIGH 60 static void password_iface_init (gpointer, gpointer); -static void chat_state_iface_init (gpointer, gpointer); static void subject_iface_init (gpointer, gpointer); #ifdef ENABLE_VOIP static void gabble_muc_channel_start_call_creation (GabbleMucChannel *gmuc, @@ -81,7 +79,7 @@ G_DEFINE_TYPE_WITH_CODE (GabbleMucChannel, gabble_muc_channel, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGES, tp_message_mixin_messages_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CHAT_STATE, - chat_state_iface_init); + tp_message_mixin_chat_state_iface_init) G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CONFERENCE, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_ROOM, NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_ROOM_CONFIG, @@ -92,20 +90,11 @@ G_DEFINE_TYPE_WITH_CODE (GabbleMucChannel, gabble_muc_channel, static void gabble_muc_channel_send (GObject *obj, TpMessage *message, TpMessageSendingFlags flags); +static gboolean gabble_muc_channel_send_chat_state (GObject *object, + TpChannelChatState state, + GError **error); static void gabble_muc_channel_close (TpBaseChannel *base); -static const gchar *gabble_muc_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - TP_IFACE_CHANNEL_INTERFACE_PASSWORD, - TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE, - TP_IFACE_CHANNEL_INTERFACE_MESSAGES, - TP_IFACE_CHANNEL_INTERFACE_CONFERENCE, - TP_IFACE_CHANNEL_INTERFACE_ROOM, - TP_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG, - TP_IFACE_CHANNEL_INTERFACE_SUBJECT, - NULL -}; - /* signal enum */ enum { @@ -129,11 +118,11 @@ static guint signals[LAST_SIGNAL] = {0}; enum { PROP_STATE = 1, + PROP_INITIALLY_REGISTER, PROP_INVITED, PROP_INVITATION_MESSAGE, PROP_SELF_JID, PROP_WOCKY_MUC, - PROP_TUBE, PROP_INITIAL_CHANNELS, PROP_INITIAL_INVITEE_HANDLES, PROP_INITIAL_INVITEE_IDS, @@ -163,6 +152,8 @@ struct _GabbleMucChannelPrivate { GabbleMucState state; gboolean closing; + gboolean autoclose; + gboolean initially_register; guint join_timer_id; guint poll_timer_id; @@ -203,7 +194,9 @@ struct _GabbleMucChannelPrivate gchar *invitation_message; WockyMuc *wmuc; - GabbleTubesChannel *tube; + + /* tube ID => owned GabbleTubeIface */ + GHashTable *tubes; #ifdef ENABLE_VOIP /* Current active call */ @@ -221,6 +214,8 @@ struct _GabbleMucChannelPrivate GPtrArray *initial_channels; GArray *initial_handles; char **initial_ids; + + gboolean have_received_error_type_wait; }; typedef struct { @@ -229,6 +224,26 @@ typedef struct { gchar *token; } _GabbleMUCSendMessageCtx; +static GPtrArray * +gabble_muc_channel_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_muc_channel_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_GROUP); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_PASSWORD); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_MESSAGES); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_CONFERENCE); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_ROOM); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_SUBJECT); + + return interfaces; +} + static void gabble_muc_channel_init (GabbleMucChannel *self) { @@ -238,6 +253,9 @@ gabble_muc_channel_init (GabbleMucChannel *self) self->priv = priv; priv->requests_cancellable = g_cancellable_new (); + + priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_object_unref); } static TpHandle create_room_identity (GabbleMucChannel *) @@ -256,8 +274,8 @@ static void handle_renamed (GObject *source, static void handle_error (GObject *source, WockyStanza *stanza, - WockyXmppError errnum, - const gchar *message, + WockyXmppErrorType errtype, + const GError *error, gpointer data); static void handle_join (WockyMuc *muc, @@ -314,8 +332,8 @@ static void handle_errmsg (GObject *source, GDateTime *datetime, WockyMucMember *who, const gchar *text, - WockyXmppError error, WockyXmppErrorType etype, + const GError *error, gpointer data); /* Signatures for some other stuff. */ @@ -323,11 +341,12 @@ static void handle_errmsg (GObject *source, static void _gabble_muc_channel_handle_subject (GabbleMucChannel *chan, TpHandleType handle_type, TpHandle sender, GDateTime *datetime, const gchar *subject, - WockyStanza *msg); + WockyStanza *msg, const GError *error); static void _gabble_muc_channel_receive (GabbleMucChannel *chan, TpChannelTextMessageType msg_type, TpHandleType handle_type, TpHandle sender, GDateTime *datetime, const gchar *id, const gchar *text, - WockyStanza *msg, TpChannelTextSendError send_error, + WockyStanza *msg, + const GError *send_error, TpDeliveryStatus delivery_status); static void @@ -356,8 +375,6 @@ gabble_muc_channel_constructed (GObject *obj) if (chain_up != NULL) chain_up (obj); - priv->tube = NULL; - room_handles = tp_base_connection_get_handles (base_conn, TP_HANDLE_TYPE_ROOM); contact_handles = tp_base_connection_get_handles (base_conn, @@ -416,7 +433,8 @@ gabble_muc_channel_constructed (GObject *obj) } /* register object on the bus */ - tp_base_channel_register (base); + if (priv->initially_register) + tp_base_channel_register (base); /* initialize group mixin */ tp_group_mixin_init (obj, @@ -439,8 +457,11 @@ gabble_muc_channel_constructed (GObject *obj) TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES | TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_SUCCESSES, supported_content_types); + tp_message_mixin_implement_send_chat_state (obj, + gabble_muc_channel_send_chat_state); - tp_group_mixin_add_handle_owner (obj, self_handle, base_conn->self_handle); + tp_group_mixin_add_handle_owner (obj, self_handle, + tp_base_connection_get_self_handle (base_conn)); /* Room interface */ g_object_get (self, @@ -493,8 +514,8 @@ gabble_muc_channel_constructed (GObject *obj) if (priv->invited) { /* invited: add ourself to local pending and the inviter to members */ - TpIntSet *members = tp_intset_new_containing (initiator); - TpIntSet *pending = tp_intset_new_containing (self_handle); + TpIntset *members = tp_intset_new_containing (initiator); + TpIntset *pending = tp_intset_new_containing (self_handle); tp_group_mixin_change_members (obj, priv->invitation_message, members, NULL, pending, NULL, @@ -517,7 +538,7 @@ gabble_muc_channel_constructed (GObject *obj) GError *error = NULL; GArray *members = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1); - g_assert (initiator == base_conn->self_handle); + g_assert (initiator == tp_base_connection_get_self_handle (base_conn)); g_assert (priv->invitation_message == NULL); g_array_append_val (members, self_handle); @@ -525,8 +546,6 @@ gabble_muc_channel_constructed (GObject *obj) g_assert (error == NULL); g_array_unref (members); } - - tp_handle_unref (contact_handles, self_handle); } typedef struct { @@ -741,7 +760,7 @@ create_room_identity (GabbleMucChannel *chan) g_assert (priv->self_jid == NULL); source = _gabble_connection_get_cached_alias (GABBLE_CONNECTION (conn), - conn->self_handle, &alias); + tp_base_connection_get_self_handle (conn), &alias); g_assert (alias != NULL); if (source == GABBLE_CONNECTION_ALIAS_FROM_JID) @@ -776,6 +795,49 @@ send_join_request (GabbleMucChannel *gmuc) wocky_muc_join (priv->wmuc, NULL); } +static void +tube_pre_presence (GabbleMucChannel *gmuc, + WockyStanza *stanza) +{ + GabbleMucChannelPrivate *priv = gmuc->priv; + TpBaseConnection *conn = tp_base_channel_get_connection ( + TP_BASE_CHANNEL (gmuc)); + WockyNode *tubes_node; + GHashTableIter iter; + gpointer value; + + tubes_node = wocky_node_add_child_with_content_ns ( + wocky_stanza_get_top_node (stanza), "tubes", NULL, NS_TUBES); + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + GabbleTubeIface *tube = value; + TpTubeChannelState state; + WockyNode *tube_node; + TpTubeType type; + TpHandle initiator; + + g_object_get (tube, + "state", &state, + "type", &type, + "initiator-handle", &initiator, + NULL); + + if (state != TP_TUBE_CHANNEL_STATE_OPEN) + continue; + + if (type == TP_TUBE_TYPE_STREAM + && initiator != TP_GROUP_MIXIN (gmuc)->self_handle) + /* We only announce stream tubes we initiated */ + continue; + + tube_node = wocky_node_add_child_with_content (tubes_node, + "tube", NULL); + gabble_tube_iface_publish_in_node (tube, conn, tube_node); + } +} + static gboolean timeout_leave (gpointer data) { @@ -798,6 +860,8 @@ send_leave_message (GabbleMucChannel *gmuc, WockyStanza *stanza = wocky_muc_create_presence (priv->wmuc, WOCKY_STANZA_SUB_TYPE_UNAVAILABLE, reason); + tube_pre_presence (gmuc, stanza); + g_signal_emit (gmuc, signals[PRE_PRESENCE], 0, stanza); _gabble_connection_send ( GABBLE_CONNECTION (tp_base_channel_get_connection (base)), stanza, NULL); @@ -821,12 +885,12 @@ gabble_muc_channel_get_property (GObject *object, case PROP_STATE: g_value_set_uint (value, priv->state); break; + case PROP_INITIALLY_REGISTER: + g_value_set_boolean (value, priv->initially_register); + break; case PROP_SELF_JID: g_value_set_string (value, priv->self_jid->str); break; - case PROP_TUBE: - g_value_set_object (value, priv->tube); - break; case PROP_WOCKY_MUC: g_value_set_object (value, priv->wmuc); break; @@ -896,6 +960,9 @@ gabble_muc_channel_set_property (GObject *object, channel_state_changed (chan, prev_state, priv->state); break; + case PROP_INITIALLY_REGISTER: + priv->initially_register = g_value_get_boolean (value); + break; case PROP_INVITED: priv->invited = g_value_get_boolean (value); break; @@ -1012,7 +1079,7 @@ gabble_muc_channel_class_init (GabbleMucChannelClass *gabble_muc_channel_class) base_class->channel_type = TP_IFACE_CHANNEL_TYPE_TEXT; base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; - base_class->interfaces = gabble_muc_channel_interfaces; + base_class->get_interfaces = gabble_muc_channel_get_interfaces; base_class->fill_immutable_properties = gabble_muc_channel_fill_immutable_properties; base_class->close = gabble_muc_channel_close; @@ -1022,6 +1089,12 @@ gabble_muc_channel_class_init (GabbleMucChannelClass *gabble_muc_channel_class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_STATE, param_spec); + param_spec = g_param_spec_boolean ("initially-register", "Initially register", + "whether to register the channel on the bus on creation", + TRUE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (object_class, PROP_INITIALLY_REGISTER, param_spec); + param_spec = g_param_spec_boolean ("invited", "Invited?", "Whether the user has been invited to the channel.", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); @@ -1043,11 +1116,6 @@ 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); @@ -1178,7 +1246,9 @@ gabble_muc_channel_class_init (GabbleMucChannelClass *gabble_muc_channel_class) 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, GABBLE_TYPE_TUBES_CHANNEL); + /* this should be GABBLE_TYPE_TUBE_IFACE but GObject + * wants a value type, not an interface. */ + G_TYPE_NONE, 1, TP_TYPE_BASE_CHANNEL); #ifdef ENABLE_VOIP signals[NEW_CALL] = g_signal_new ("new-call", @@ -1232,6 +1302,8 @@ gabble_muc_channel_dispose (GObject *object) tp_clear_object (&priv->requests_cancellable); tp_clear_object (&priv->room_config); + tp_clear_pointer (&priv->tubes, g_hash_table_unref); + if (G_OBJECT_CLASS (gabble_muc_channel_parent_class)->dispose) G_OBJECT_CLASS (gabble_muc_channel_parent_class)->dispose (object); } @@ -1472,19 +1544,42 @@ close_channel (GabbleMucChannel *chan, const gchar *reason, GabbleMucChannelPrivate *priv = chan->priv; GabbleConnection *conn = GABBLE_CONNECTION ( tp_base_channel_get_connection (base)); - TpIntSet *set; + TpIntset *set; GArray *handles; - GError error = { TP_ERRORS, TP_ERROR_CANCELLED, + GError error = { TP_ERROR, TP_ERROR_CANCELLED, "Muc channel closed below us" }; - if (tp_base_channel_is_destroyed (base) || priv->closing) + if (tp_base_channel_is_destroyed (base)) return; + /* if priv->closing is TRUE, we're waiting for the MUC to echo our + * presence. however, if we're being asked to close again, but this + * time without letting the muc know, let's actually close. if we + * don't then the channel won't disappear from the bus properly. */ + if (priv->closing && !inform_muc) + { + clear_leave_timer (chan); + tp_base_channel_destroyed (base); + return; + } + + /* If inform_muc is TRUE it means that we're closing the channel + * gracefully and we don't mind if the channel doesn't actually + * close behind the scenes if a tube/call is still open. Every call + * to this function has inform_muc=FALSE, except for Channel.Close() + * and RemoveMembers(self_handle) */ + if (inform_muc && !gabble_muc_channel_can_be_closed (chan)) + { + priv->autoclose = TRUE; + tp_base_channel_disappear (base); + return; + } + DEBUG ("Closing"); /* Ensure we stay alive even while telling everyone else to abandon us. */ g_object_ref (chan); - gabble_muc_channel_close_tube (chan); + g_hash_table_remove_all (priv->tubes); #ifdef ENABLE_VOIP muc_call_channel_finish_requests (chan, NULL, &error); @@ -1543,6 +1638,35 @@ _gabble_muc_channel_is_ready (GabbleMucChannel *chan) return priv->ready; } +/* returns TRUE if there are no tube or Call channels open in this MUC */ +gboolean +gabble_muc_channel_can_be_closed (GabbleMucChannel *chan) +{ + GabbleMucChannelPrivate *priv = chan->priv; + + if (g_hash_table_size (priv->tubes) > 0) + return FALSE; + + if (priv->calls != NULL || priv->call_requests != NULL + || priv->call_initiating) + return FALSE; + + return TRUE; +} + +gboolean +gabble_muc_channel_get_autoclose (GabbleMucChannel *chan) +{ + return chan->priv->autoclose; +} + +void +gabble_muc_channel_set_autoclose (GabbleMucChannel *chan, + gboolean autoclose) +{ + chan->priv->autoclose = autoclose; +} + static gboolean handle_nick_conflict (GabbleMucChannel *chan, WockyStanza *stanza, @@ -1554,7 +1678,7 @@ handle_nick_conflict (GabbleMucChannel *chan, TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( tp_base_channel_get_connection (base), TP_HANDLE_TYPE_CONTACT); TpHandle self_handle; - TpIntSet *add_rp, *remove_rp; + TpIntset *add_rp, *remove_rp; const gchar *from = wocky_stanza_get_from (stanza); /* If this is a nick conflict message with a resource in the JID, and the @@ -1578,7 +1702,7 @@ handle_nick_conflict (GabbleMucChannel *chan, if (priv->nick_retry_count >= MAX_NICK_RETRIES) { - g_set_error (tp_error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (tp_error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "nickname already in use and retry count exceeded"); return FALSE; } @@ -1602,7 +1726,6 @@ handle_nick_conflict (GabbleMucChannel *chan, tp_intset_destroy (add_rp); tp_intset_destroy (remove_rp); - tp_handle_unref (contact_repo, self_handle); priv->nick_retry_count++; send_join_request (chan); @@ -1762,8 +1885,8 @@ update_permissions (GabbleMucChannel *chan) static void handle_error (GObject *source, WockyStanza *stanza, - WockyXmppError errnum, - const gchar *message, + WockyXmppErrorType errtype, + const GError *error, gpointer data) { GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data); @@ -1778,7 +1901,7 @@ handle_error (GObject *source, return; } - if (errnum == WOCKY_XMPP_ERROR_NOT_AUTHORIZED) + if (error->code == WOCKY_XMPP_ERROR_NOT_AUTHORIZED) { /* channel can sit requiring a password indefinitely */ clear_join_timer (gmuc); @@ -1798,21 +1921,21 @@ handle_error (GObject *source, { GError *tp_error = NULL; - switch (errnum) + switch (error->code) { case WOCKY_XMPP_ERROR_FORBIDDEN: - tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_BANNED, + tp_error = g_error_new (TP_ERROR, TP_ERROR_CHANNEL_BANNED, "banned from room"); reason = TP_CHANNEL_GROUP_CHANGE_REASON_BANNED; break; case WOCKY_XMPP_ERROR_SERVICE_UNAVAILABLE: - tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_FULL, + tp_error = g_error_new (TP_ERROR, TP_ERROR_CHANNEL_FULL, "room is full"); reason = TP_CHANNEL_GROUP_CHANGE_REASON_BUSY; break; case WOCKY_XMPP_ERROR_REGISTRATION_REQUIRED: - tp_error = g_error_new (TP_ERRORS, TP_ERROR_CHANNEL_INVITE_ONLY, + tp_error = g_error_new (TP_ERROR, TP_ERROR_CHANNEL_INVITE_ONLY, "room is invite only"); break; @@ -1822,8 +1945,8 @@ handle_error (GObject *source, break; default: - tp_error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "%s", wocky_xmpp_error_description (errnum)); + tp_error = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, + "%s", wocky_xmpp_error_description (error->code)); break; } @@ -1835,90 +1958,386 @@ handle_error (GObject *source, } static void -tube_closed_cb (GabbleTubesChannel *chan, gpointer user_data) +tube_closed_cb (GabbleTubeIface *tube, + GabbleMucChannel *gmuc) { - GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (user_data); GabbleMucChannelPrivate *priv = gmuc->priv; - TpHandle room; + guint64 tube_id; - if (priv->tube != NULL) - { - priv->tube = NULL; - g_object_get (chan, "handle", &room, NULL); - DEBUG ("removing MUC tubes channel with handle %d", room); - g_object_unref (chan); - } + g_object_get (tube, "id", &tube_id, NULL); + + g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (tube_id)); } -static GabbleTubesChannel * -new_tube (GabbleMucChannel *gmuc, +static GabbleTubeIface * +create_new_tube (GabbleMucChannel *gmuc, + TpTubeType type, TpHandle initiator, + const gchar *service, + GHashTable *parameters, + const gchar *stream_id, + guint64 tube_id, + GabbleBytestreamIface *bytestream, gboolean requested) { GabbleMucChannelPrivate *priv = gmuc->priv; TpBaseChannel *base = TP_BASE_CHANNEL (gmuc); - TpBaseConnection *conn = tp_base_channel_get_connection (base); - char *object_path; + GabbleConnection *conn = GABBLE_CONNECTION ( + tp_base_channel_get_connection (base)); + TpHandle self_handle = TP_GROUP_MIXIN (gmuc)->self_handle; + TpHandle handle = tp_base_channel_get_target_handle (base); + GabbleTubeIface *tube; - g_assert (priv->tube == NULL); + switch (type) + { + case TP_TUBE_TYPE_DBUS: + tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (conn, + handle, TP_HANDLE_TYPE_ROOM, self_handle, initiator, + service, parameters, stream_id, tube_id, bytestream, gmuc, + requested)); + break; + case TP_TUBE_TYPE_STREAM: + tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (conn, + handle, TP_HANDLE_TYPE_ROOM, self_handle, initiator, + service, parameters, tube_id, gmuc, requested)); + break; + default: + g_return_val_if_reached (NULL); + } - object_path = g_strdup_printf ("%s/MucTubesChannel%u", - conn->object_path, tp_base_channel_get_target_handle (base)); + tp_base_channel_register ((TpBaseChannel *) tube); - DEBUG ("creating new tubes chan, object path %s", object_path); + DEBUG ("create tube %" G_GUINT64_FORMAT, tube_id); + g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), tube); - priv->tube = g_object_new (GABBLE_TYPE_TUBES_CHANNEL, - "connection", tp_base_channel_get_connection (base), - "object-path", object_path, - "handle", tp_base_channel_get_target_handle (base), - "handle-type", TP_HANDLE_TYPE_ROOM, - "muc", gmuc, - "initiator-handle", initiator, - "requested", requested, - NULL); + g_signal_connect (tube, "closed", G_CALLBACK (tube_closed_cb), gmuc); + + return tube; +} + +static guint64 +generate_tube_id (GabbleMucChannel *self) +{ + GabbleMucChannelPrivate *priv = self->priv; + guint64 out; + + /* probably totally overkill */ + do + { + out = g_random_int_range (1, G_MAXINT32); + } + while (g_hash_table_lookup (priv->tubes, + GUINT_TO_POINTER (out)) != NULL); + + return out; +} + +GabbleTubeIface * +gabble_muc_channel_tube_request (GabbleMucChannel *self, + gpointer request_token, + GHashTable *request_properties, + gboolean require_new) +{ + GabbleTubeIface *tube; + const gchar *channel_type; + const gchar *service; + GHashTable *parameters = NULL; + guint64 tube_id; + gchar *stream_id; + TpTubeType type; + + tube_id = generate_tube_id (self); + + channel_type = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_CHANNEL_TYPE); + + if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) + { + type = TP_TUBE_TYPE_STREAM; + service = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); + + } + else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) + { + type = TP_TUBE_TYPE_DBUS; + service = tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); + } + else + /* This assertion is safe: this function's caller only calls it in one of + * the above cases. + * FIXME: but it would be better to pass an enum member or something maybe. + */ + g_assert_not_reached (); + + /* requested tubes have an empty parameters dict */ + parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) tp_g_value_slice_free); + + /* if the service property is missing, the requestotron rejects the request + */ + g_assert (service != NULL); + + DEBUG ("Request a tube channel with type='%s' and service='%s'", + channel_type, service); + + stream_id = gabble_bytestream_factory_generate_stream_id (); + tube = create_new_tube (self, type, TP_GROUP_MIXIN (self)->self_handle, + service, parameters, stream_id, tube_id, NULL, TRUE); + g_free (stream_id); + g_hash_table_unref (parameters); + + return tube; +} + +void +gabble_muc_channel_foreach_tubes (GabbleMucChannel *gmuc, + TpExportableChannelFunc foreach, + gpointer user_data) +{ + GabbleMucChannelPrivate *priv = gmuc->priv; + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + foreach (TP_EXPORTABLE_CHANNEL (value), user_data); + } +} + +void +gabble_muc_channel_handle_si_stream_request (GabbleMucChannel *self, + GabbleBytestreamIface *bytestream, + const gchar *stream_id, + WockyStanza *msg) +{ + GabbleMucChannelPrivate *priv = self->priv; + WockyNode *si_node, *stream_node; + const gchar *tmp; + guint64 tube_id; + GabbleTubeIface *tube; + + si_node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (msg), "si", NS_SI); + g_return_if_fail (si_node != NULL); + + stream_node = wocky_node_get_child_ns (si_node, + "muc-stream", NS_TUBES); + g_return_if_fail (stream_node != NULL); + + tmp = wocky_node_get_attribute (stream_node, "tube"); + if (tmp == NULL) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<muc-stream> has no tube attribute" }; + + NODE_DEBUG (stream_node, e.message); + gabble_bytestream_iface_close (bytestream, &e); + return; + } + tube_id = g_ascii_strtoull (tmp, NULL, 10); + if (tube_id == 0 || tube_id > G_MAXUINT32) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<muc-stream> tube ID attribute non-numeric or out of range" }; - g_signal_connect (priv->tube, "closed", (GCallback) tube_closed_cb, gmuc); + DEBUG ("tube id is non-numeric or out of range: %s", tmp); + gabble_bytestream_iface_close (bytestream, &e); + return; + } + + tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + if (tube == NULL) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<muc-stream> tube attribute points to a nonexistent " + "tube" }; - g_signal_emit (gmuc, signals[NEW_TUBE], 0 , priv->tube); + DEBUG ("tube %" G_GUINT64_FORMAT " doesn't exist", tube_id); + gabble_bytestream_iface_close (bytestream, &e); + return; + } - g_free (object_path); + DEBUG ("received new bytestream request for existing tube: %" G_GUINT64_FORMAT, + tube_id); - return priv->tube; + gabble_tube_iface_add_bytestream (tube, bytestream); +} + +static void +tubes_presence_update (GabbleMucChannel *gmuc, + TpHandle contact, + WockyNode *pnode) +{ + GabbleMucChannelPrivate *priv = gmuc->priv; + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( + tp_base_channel_get_connection (TP_BASE_CHANNEL (gmuc)), + TP_HANDLE_TYPE_CONTACT); + const gchar *presence_type; + WockyNode *tubes_node; + GHashTable *old_dbus_tubes; + GHashTableIter iter; + gpointer key, value; + WockyNodeIter i; + WockyNode *tube_node; + + if (contact == TP_GROUP_MIXIN (gmuc)->self_handle) + /* We don't need to inspect our own presence */ + return; + + presence_type = wocky_node_get_attribute (pnode, "type"); + if (!tp_strdiff (presence_type, "unavailable")) + { + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + GabbleTubeDBus *tube = value; + + if (!GABBLE_IS_TUBE_DBUS (value)) + continue; + + gabble_tube_dbus_remove_name (tube, contact); + } + } + + tubes_node = wocky_node_get_child_ns (pnode, "tubes", NS_TUBES); + + if (tubes_node == NULL) + return; + + /* Fill old_dbus_tubes with D-BUS tubes previously announced by + * the contact */ + old_dbus_tubes = g_hash_table_new (g_direct_hash, g_direct_equal); + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + if (!GABBLE_IS_TUBE_DBUS (value)) + continue; + + if (gabble_tube_dbus_handle_in_names (GABBLE_TUBE_DBUS (value), + contact)) + { + g_hash_table_insert (old_dbus_tubes, + key, value); + } + } + + wocky_node_iter_init (&i, tubes_node, NULL, NULL); + while (wocky_node_iter_next (&i, &tube_node)) + { + const gchar *stream_id; + GabbleTubeIface *tube; + guint64 tube_id; + TpTubeType type; + + stream_id = wocky_node_get_attribute (tube_node, "stream-id"); + + if (!gabble_private_tubes_factory_extract_tube_information ( + contact_repo, tube_node, NULL, NULL, NULL, NULL, &tube_id)) + { + DEBUG ("Bad tube ID, skipping to next child of <tubes>"); + continue; + } + + tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + + if (tube == NULL) + { + /* We don't know yet this tube */ + const gchar *service; + TpHandle initiator_handle; + GHashTable *parameters; + + if (gabble_private_tubes_factory_extract_tube_information ( + contact_repo, tube_node, &type, &initiator_handle, + &service, ¶meters, NULL)) + { + if (type == TP_TUBE_TYPE_DBUS && initiator_handle == 0) + { + DEBUG ("D-Bus tube initiator missing"); + /* skip to the next child of <tubes> */ + continue; + } + else if (type == TP_TUBE_TYPE_STREAM) + { + initiator_handle = contact; + } + + tube = create_new_tube (gmuc, type, initiator_handle, + service, parameters, stream_id, tube_id, NULL, FALSE); + + g_signal_emit (gmuc, signals[NEW_TUBE], 0, tube); + + g_hash_table_unref (parameters); + } + } + else + { + /* The contact is in the tube. + * Remove it from old_dbus_tubes if needed */ + g_hash_table_remove (old_dbus_tubes, GUINT_TO_POINTER (tube_id)); + } + + if (tube == NULL) + /* skip to the next child of <tubes> */ + continue; + + g_object_get (tube, "type", &type, NULL); + + if (type == TP_TUBE_TYPE_DBUS) + { + /* Update mapping of handle -> D-Bus name. */ + if (!gabble_tube_dbus_handle_in_names (GABBLE_TUBE_DBUS (tube), + contact)) + { + /* Contact just joined the tube */ + const gchar *new_name; + + new_name = wocky_node_get_attribute (tube_node, + "dbus-name"); + + if (!new_name) + { + DEBUG ("Contact %u isn't announcing their D-Bus name", + contact); + /* skip to the next child of <tubes> */ + continue; + } + + gabble_tube_dbus_add_name (GABBLE_TUBE_DBUS (tube), + contact, new_name); + } + } + } + + /* Tubes remaining in old_dbus_tubes was left by the contact */ + g_hash_table_iter_init (&iter, old_dbus_tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + gabble_tube_dbus_remove_name (GABBLE_TUBE_DBUS (value), contact); + } + + g_hash_table_unref (old_dbus_tubes); } /* ************************************************************************* */ /* 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 */ +/* not actually a signal handler, but used by them. */ static void handle_tube_presence (GabbleMucChannel *gmuc, TpHandle from, WockyStanza *stanza) { - GabbleMucChannelPrivate *priv = gmuc->priv; WockyNode *node = wocky_stanza_get_top_node (stanza); if (from == 0) return; - if (priv->tube == NULL) - { - WockyNode *tubes; - tubes = wocky_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; - - /* 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); - } - - gabble_tubes_channel_presence_updated (priv->tube, from, node); + tubes_presence_update (gmuc, from, node); } static TpChannelGroupChangeReason @@ -1955,7 +2374,7 @@ handle_parted (GObject *source, TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (tp_base_channel_get_connection (base), TP_HANDLE_TYPE_CONTACT); - TpIntSet *handles = NULL; + TpIntset *handles = NULL; TpHandle member = 0; TpHandle actor = 0; const char *jid = wocky_muc_jid (wmuc); @@ -1999,16 +2418,11 @@ handle_parted (GObject *source, reason = muc_status_codes_to_change_reason (codes); /* handle_tube_presence creates tubes if need be, so bypass it here: */ - if (priv->tube != NULL) - gabble_tubes_channel_presence_updated (priv->tube, member, - wocky_stanza_get_top_node (stanza)); + tubes_presence_update (gmuc, member, wocky_stanza_get_top_node (stanza)); close_channel (gmuc, why, FALSE, actor, reason); - if (actor != 0) - tp_handle_unref (contact_repo, actor); tp_intset_destroy (handles); - tp_handle_unref (contact_repo, member); } @@ -2026,12 +2440,11 @@ handle_left (GObject *source, { GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data); TpBaseChannel *base = TP_BASE_CHANNEL (gmuc); - GabbleMucChannelPrivate *priv = gmuc->priv; TpChannelGroupChangeReason reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (tp_base_channel_get_connection (base), TP_HANDLE_TYPE_CONTACT); - TpIntSet *handles = NULL; + TpIntset *handles = NULL; TpHandle member = 0; TpHandle actor = 0; @@ -2056,17 +2469,14 @@ handle_left (GObject *source, reason = muc_status_codes_to_change_reason (codes); /* handle_tube_presence creates tubes if need be, so bypass it here: */ - if (priv->tube != NULL) - gabble_tubes_channel_presence_updated (priv->tube, member, - wocky_stanza_get_top_node (stanza)); + tubes_presence_update (gmuc, member, wocky_stanza_get_top_node (stanza)); tp_group_mixin_change_members (data, why, NULL, handles, NULL, NULL, actor, reason); + tp_message_mixin_change_chat_state (data, member, + TP_CHANNEL_CHAT_STATE_GONE); - 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 * @@ -2124,6 +2534,8 @@ handle_fill_presence (WockyMuc *muc, conn->self_presence->status_message, 0); + tube_pre_presence (self, stanza); + g_signal_emit (self, signals[PRE_PRESENCE], 0, (WockyStanza *) stanza); } @@ -2141,7 +2553,7 @@ handle_renamed (GObject *source, TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (tp_base_channel_get_connection (base), TP_HANDLE_TYPE_CONTACT); - TpIntSet *old_self = tp_intset_new (); + 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, @@ -2157,8 +2569,6 @@ handle_renamed (GObject *source, handle_tube_presence (gmuc, myself, stanza); tp_intset_destroy (old_self); - tp_handle_unref (contact_repo, userid); - tp_handle_unref (contact_repo, myself); } static void @@ -2194,7 +2604,6 @@ update_roster_presence (GabbleMucChannel *gmuc, GUINT_TO_POINTER (handle), GUINT_TO_POINTER (owner)); - 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) @@ -2202,7 +2611,6 @@ update_roster_presence (GabbleMucChannel *gmuc, tp_group_mixin_change_flags (G_OBJECT (gmuc), 0, TP_CHANNEL_GROUP_FLAG_HANDLE_OWNERS_NOT_AVAILABLE); g_signal_emit (gmuc, signals[CONTACT_JOIN], 0, owner); - tp_handle_unref (contact_repo, owner); } handle_tube_presence (gmuc, handle, member->presence_stanza); @@ -2240,7 +2648,7 @@ handle_join (WockyMuc *muc, g_hash_table_insert (omap, GUINT_TO_POINTER (myself), - GUINT_TO_POINTER (base_conn->self_handle)); + GUINT_TO_POINTER (tp_base_connection_get_self_handle (base_conn))); tp_handle_set_add (members, myself); tp_group_mixin_add_handle_owners (G_OBJECT (gmuc), omap); @@ -2266,7 +2674,6 @@ handle_join (WockyMuc *muc, g_object_set (gmuc, "state", MUC_STATE_JOINED, NULL); - tp_handle_unref (contact_repo, myself); tp_handle_set_destroy (members); tp_handle_set_destroy (owners); g_hash_table_unref (omap); @@ -2341,10 +2748,6 @@ handle_presence (GObject *source, } #endif - /* zap the handle refs we created */ - tp_handle_unref (contact_repo, handle); - if (owner != 0) - tp_handle_unref (contact_repo, owner); tp_handle_set_destroy (handles); } @@ -2391,7 +2794,6 @@ handle_message (GObject *source, handle_type = TP_HANDLE_TYPE_ROOM; repo = tp_base_connection_get_handles (conn, handle_type); from = tp_base_channel_get_target_handle (base); - tp_handle_ref (repo, from); } switch (type) @@ -2409,11 +2811,12 @@ handle_message (GObject *source, if (text != NULL) _gabble_muc_channel_receive (gmuc, msg_type, handle_type, from, datetime, xmpp_id, text, stanza, - GABBLE_TEXT_CHANNEL_SEND_NO_ERROR, TP_DELIVERY_STATUS_DELIVERED); + NULL, + TP_DELIVERY_STATUS_DELIVERED); if (from_member && state != WOCKY_MUC_MSG_STATE_NONE) { - gint tp_msg_state; + TpChannelChatState tp_msg_state; switch (state) { case WOCKY_MUC_MSG_STATE_ACTIVE: @@ -2432,15 +2835,12 @@ handle_message (GObject *source, tp_msg_state = TP_CHANNEL_CHAT_STATE_ACTIVE; } - tp_svc_channel_interface_chat_state_emit_chat_state_changed (gmuc, - from, tp_msg_state); + tp_message_mixin_change_chat_state ((GObject *) gmuc, from, tp_msg_state); } if (subject != NULL) _gabble_muc_channel_handle_subject (gmuc, handle_type, from, - datetime, subject, stanza); - - tp_handle_unref (repo, from); + datetime, subject, stanza, NULL); } static void @@ -2451,8 +2851,8 @@ handle_errmsg (GObject *source, GDateTime *datetime, WockyMucMember *who, const gchar *text, - WockyXmppError error, WockyXmppErrorType etype, + const GError *error, gpointer data) { GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (data); @@ -2460,7 +2860,6 @@ handle_errmsg (GObject *source, TpBaseChannel *base = TP_BASE_CHANNEL (gmuc); TpBaseConnection *conn = tp_base_channel_get_connection (base); gboolean from_member = (who != NULL); - TpChannelTextSendError tp_err = TP_CHANNEL_TEXT_SEND_ERROR_UNKNOWN; TpDeliveryStatus ds = TP_DELIVERY_STATUS_DELIVERED; TpHandleRepoIface *repo = NULL; TpHandleType handle_type; @@ -2485,19 +2884,32 @@ handle_errmsg (GObject *source, handle_type = TP_HANDLE_TYPE_ROOM; repo = tp_base_connection_get_handles (conn, handle_type); from = tp_base_channel_get_target_handle (base); - tp_handle_ref (repo, from); } - tp_err = gabble_tp_send_error_from_wocky_xmpp_error (error); - if (etype == WOCKY_XMPP_ERROR_TYPE_WAIT) - ds = TP_DELIVERY_STATUS_TEMPORARILY_FAILED; + { + ds = TP_DELIVERY_STATUS_TEMPORARILY_FAILED; + /* Some MUCs have very strict rate limiting like "at most one stanza per + * second". Since chat state notifications count towards this, if the + * user types a message very quickly then the typing notification is + * accepted but then the stanza containing the actual message is + * rejected. + * + * So: if we ever get rate-limited, let's just stop sending chat states. + * + * https://bugs.freedesktop.org/show_bug.cgi?id=43166 + */ + DEBUG ("got <error type='wait'>, disabling chat state notifications"); + priv->have_received_error_type_wait = TRUE; + } else - ds = TP_DELIVERY_STATUS_PERMANENTLY_FAILED; + { + ds = TP_DELIVERY_STATUS_PERMANENTLY_FAILED; + } if (text != NULL) _gabble_muc_channel_receive (gmuc, TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE, - handle_type, from, datetime, xmpp_id, text, stanza, tp_err, ds); + handle_type, from, datetime, xmpp_id, text, stanza, error, ds); /* FIXME: this is stupid. WockyMuc gives us the subject for non-errors, but * doesn't bother for errors. @@ -2513,9 +2925,7 @@ handle_errmsg (GObject *source, (priv->set_subject_stanza_id != NULL && !tp_strdiff (xmpp_id, priv->set_subject_stanza_id))) _gabble_muc_channel_handle_subject (gmuc, - handle_type, from, datetime, subject, stanza); - - tp_handle_unref (repo, from); + handle_type, from, datetime, subject, stanza, error); } /* ************************************************************************* */ @@ -2528,11 +2938,11 @@ _gabble_muc_channel_handle_subject (GabbleMucChannel *chan, TpHandle sender, GDateTime *datetime, const gchar *subject, - WockyStanza *msg) + WockyStanza *msg, + const GError *error) { GabbleMucChannelPrivate *priv; const gchar *actor; - GError *error = NULL; gint64 timestamp = datetime != NULL ? g_date_time_to_unix (datetime) : G_MAXINT64; @@ -2540,7 +2950,7 @@ _gabble_muc_channel_handle_subject (GabbleMucChannel *chan, priv = chan->priv; - if (wocky_stanza_extract_errors (msg, NULL, &error, NULL, NULL)) + if (error != NULL) { if (priv->set_subject_context != NULL) { @@ -2557,7 +2967,6 @@ _gabble_muc_channel_handle_subject (GabbleMucChannel *chan, room_properties_update (chan); } - g_clear_error (&error); return; } @@ -2595,7 +3004,7 @@ _gabble_muc_channel_handle_subject (GabbleMucChannel *chan, /** * _gabble_muc_channel_receive: receive MUC messages */ -void +static void _gabble_muc_channel_receive (GabbleMucChannel *chan, TpChannelTextMessageType msg_type, TpHandleType sender_handle_type, @@ -2604,7 +3013,7 @@ _gabble_muc_channel_receive (GabbleMucChannel *chan, const gchar *id, const gchar *text, WockyStanza *msg, - TpChannelTextSendError send_error, + const GError *send_error, TpDeliveryStatus error_status) { TpBaseChannel *base; @@ -2623,7 +3032,7 @@ _gabble_muc_channel_receive (GabbleMucChannel *chan, muc_self_handle = chan->group.self_handle; /* Is this an error report? */ - is_error = (send_error != GABBLE_TEXT_CHANNEL_SEND_NO_ERROR); + is_error = (send_error != NULL); if (is_error && sender == muc_self_handle) { @@ -2655,6 +3064,16 @@ _gabble_muc_channel_receive (GabbleMucChannel *chan, return; } + /* are we actually hidden? */ + if (!tp_base_channel_is_registered (base)) + { + DEBUG ("making MUC channel reappear!"); + tp_base_channel_reopened_with_requested (base, FALSE, sender); + } + + /* let's not autoclose now */ + chan->priv->autoclose = FALSE; + message = tp_cm_message_new (base_conn, 2); /* Header common to normal message and delivery-echo */ @@ -2689,9 +3108,21 @@ _gabble_muc_channel_receive (GabbleMucChannel *chan, if (id != NULL) tp_message_set_string (delivery_report, 0, "delivery-token", id); - if (is_error) - tp_message_set_uint32 (delivery_report, 0, "delivery-error", - send_error); + if (send_error != NULL) + { + tp_message_set_uint32 (delivery_report, 0, "delivery-error", + gabble_tp_send_error_from_wocky_xmpp_error (send_error->code)); + + if (!tp_str_empty (send_error->message)) + { + guint body_part_number = tp_message_append_part (delivery_report); + + tp_message_set_string (delivery_report, body_part_number, + "content-type", "text/plain"); + tp_message_set_string (delivery_report, body_part_number, + "content", send_error->message); + } + } /* We do not set a message-sender on the report: the intended recipient * of the original message was the MUC, so the spec says we should omit @@ -2783,7 +3214,7 @@ gabble_muc_channel_provide_password (TpSvcChannelInterfacePassword *iface, if (!priv->must_provide_password || priv->password_ctx != NULL) { - GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "password cannot be provided in the current state" }; dbus_g_method_return_error (context, &error); } @@ -2839,14 +3270,21 @@ gabble_muc_channel_send (GObject *obj, GabbleMucChannel *self = GABBLE_MUC_CHANNEL (obj); TpBaseChannel *base = TP_BASE_CHANNEL (self); GabbleMucChannelPrivate *priv = self->priv; - GabbleConnection *gabble_conn = - GABBLE_CONNECTION (tp_base_channel_get_connection (base)); + TpBaseConnection *base_conn; + GabbleConnection *gabble_conn; _GabbleMUCSendMessageCtx *context = NULL; WockyStanza *stanza = NULL; WockyPorter *porter = NULL; GError *error = NULL; gchar *id = NULL; + base_conn = tp_base_channel_get_connection (base); + gabble_conn = GABBLE_CONNECTION (base_conn); + + tp_message_mixin_change_chat_state (obj, + tp_base_channel_get_self_handle (base), + TP_CHANNEL_CHAT_STATE_ACTIVE); + stanza = gabble_message_util_build_stanza (message, gabble_conn, WOCKY_STANZA_SUB_TYPE_GROUPCHAT, TP_CHANNEL_CHAT_STATE_ACTIVE, priv->jid, FALSE, &id, &error); @@ -2902,7 +3340,7 @@ gabble_muc_channel_send_invite (GabbleMucChannel *self, if (continue_) { - wocky_node_add_child_with_content (invite_node, "continue", NULL); + wocky_node_add_child (invite_node, "continue"); } DEBUG ("sending MUC invitation for room %s to contact %s with reason " @@ -2932,14 +3370,14 @@ gabble_muc_channel_add_member (GObject *obj, if (handle == mixin->self_handle) { TpBaseConnection *conn = tp_base_channel_get_connection (base); - TpIntSet *set_remove_members, *set_remote_pending; + TpIntset *set_remove_members, *set_remote_pending; GArray *arr_members; /* are we already a member or in remote pending? */ if (tp_handle_set_is_member (mixin->members, handle) || tp_handle_set_is_member (mixin->remote_pending, handle)) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "already a member or in remote pending"); return FALSE; @@ -2961,7 +3399,7 @@ gabble_muc_channel_add_member (GObject *obj, tp_intset_add (set_remote_pending, handle); tp_group_mixin_add_handle_owner (obj, mixin->self_handle, - conn->self_handle); + tp_base_connection_get_self_handle (conn)); tp_group_mixin_change_members (obj, "", NULL, set_remove_members, NULL, set_remote_pending, 0, priv->invited @@ -2983,7 +3421,7 @@ gabble_muc_channel_add_member (GObject *obj, /* check that we're indeed a member when attempting to invite others */ if (priv->state < MUC_STATE_JOINED) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "channel membership is required for inviting others"); return FALSE; @@ -3250,7 +3688,7 @@ request_config_form_reply_cb ( * platforms, so fail at compile time if this is no longer the case */ #if TP_NUM_BASE_ROOM_CONFIG_PROPERTIES > 32 -#error GabbleMUCChannel request_config_form_reply_cb needs porting to TpIntSet +#error GabbleMUCChannel request_config_form_reply_cb needs porting to TpIntset #endif props_left = 0; @@ -3324,8 +3762,7 @@ request_config_form_reply_cb ( { GString *unsubstituted = g_string_new (""); - printf (TP_ANSI_BOLD_ON TP_ANSI_FG_WHITE TP_ANSI_BG_RED - "\n%s: the following properties were not substituted:\n", + printf ("\n%s: the following properties were not substituted:\n", G_STRFUNC); for (i = 0; i < TP_NUM_BASE_ROOM_CONFIG_PROPERTIES; i++) @@ -3345,10 +3782,10 @@ request_config_form_reply_cb ( printf ("\nthis is a MUC server compatibility bug in gabble, please " "report it with a full debug log attached (running gabble " - "with WOCKY_DEBUG=xmpp)" TP_ANSI_RESET "\n\n"); + "with WOCKY_DEBUG=xmpp)\n\n"); fflush (stdout); - error = g_error_new (TP_ERRORS, TP_ERROR_SERVICE_CONFUSED, + error = g_error_new (TP_ERROR, TP_ERROR_SERVICE_CONFUSED, "Couldn't find fields corresponding to %s in the muc#owner form. " "This is a MUC server compatibility bug in Gabble.", unsubstituted->str); @@ -3403,55 +3840,21 @@ request_config_form_submit_reply_cb ( g_object_unref (update_result); } -/** - * gabble_muc_channel_set_chat_state - * - * Implements D-Bus method SetChatState - * on interface org.freedesktop.Telepathy.Channel.Interface.ChatState - */ -static void -gabble_muc_channel_set_chat_state (TpSvcChannelInterfaceChatState *iface, - guint state, - DBusGMethodInvocation *context) +static gboolean +gabble_muc_channel_send_chat_state (GObject *object, + TpChannelChatState state, + GError **error) { - GabbleMucChannel *self = GABBLE_MUC_CHANNEL (iface); + GabbleMucChannel *self = GABBLE_MUC_CHANNEL (object); + GabbleMucChannelPrivate *priv = self->priv; TpBaseChannel *base = TP_BASE_CHANNEL (self); - GabbleMucChannelPrivate *priv; - GError *error = NULL; - - g_assert (GABBLE_IS_MUC_CHANNEL (self)); - - priv = self->priv; - - 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"); - } - - if (error != NULL || - !gabble_message_util_send_chat_state (G_OBJECT (self), - GABBLE_CONNECTION (tp_base_channel_get_connection (base)), - WOCKY_STANZA_SUB_TYPE_GROUPCHAT, state, priv->jid, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - - return; - } + if (priv->have_received_error_type_wait) + return TRUE; - tp_svc_channel_interface_chat_state_return_from_set_chat_state (context); + return gabble_message_util_send_chat_state (G_OBJECT (self), + GABBLE_CONNECTION (tp_base_channel_get_connection (base)), + WOCKY_STANZA_SUB_TYPE_GROUPCHAT, state, priv->jid, error); } void @@ -3473,40 +3876,6 @@ gabble_muc_channel_send_presence (GabbleMucChannel *self) g_object_unref (stanza); } -GabbleTubesChannel * -gabble_muc_channel_open_tube (GabbleMucChannel *gmuc, - TpHandle initiator, - gboolean requested) -{ - GabbleMucChannelPrivate *priv = gmuc->priv; - - 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 = gmuc->priv; - - 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); - } -} - #ifdef ENABLE_VOIP GabbleCallMucChannel * gabble_muc_channel_get_call (GabbleMucChannel *gmuc) @@ -3654,7 +4023,7 @@ gabble_muc_channel_start_call_creation (GabbleMucChannel *gmuc, * address; and finally TpBaseChannel pastes the connection path back on. :) */ prefix = tp_base_channel_get_object_path (base) + - strlen (base_conn->object_path) + 1 /* for the slash */; + strlen (tp_base_connection_get_object_path (base_conn)) + 1 /* for the slash */; /* Keep ourselves reffed while call channels are created */ g_object_ref (gmuc); @@ -3689,7 +4058,7 @@ gabble_muc_channel_request_call (GabbleMucChannel *gmuc, { g_simple_async_report_error_in_idle (G_OBJECT (gmuc), callback, user_data, - TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + TP_ERROR, TP_ERROR_NOT_AVAILABLE, "A request for a call is already in progress"); return; } @@ -3721,7 +4090,7 @@ gabble_muc_channel_request_call_finish (GabbleMucChannel *gmuc, gboolean gabble_muc_channel_handle_jingle_session (GabbleMucChannel *self, - GabbleJingleSession *session) + WockyJingleSession *session) { GabbleMucChannelPrivate *priv = self->priv; @@ -3785,21 +4154,21 @@ gabble_muc_channel_set_subject (TpSvcChannelInterfaceSubject *iface, if (priv->state < MUC_STATE_JOINED) { - GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Steady on. You're not in the room yet" }; dbus_g_method_return_error (context, &error); } else if (priv->state > MUC_STATE_JOINED || priv->closing) { - GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Already left/leaving the room" }; dbus_g_method_return_error (context, &error); } else if (priv->set_subject_context != NULL) { - GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError error = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Hey! Stop changing the subject! (Your last request is still in " "flight.)" }; @@ -3845,18 +4214,6 @@ password_iface_init (gpointer g_iface, gpointer iface_data) } static void -chat_state_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceChatStateClass *klass = - (TpSvcChannelInterfaceChatStateClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_chat_state_implement_##x (\ - klass, gabble_muc_channel_##x) - IMPLEMENT(set_chat_state); -#undef IMPLEMENT -} - -static void subject_iface_init (gpointer g_iface, gpointer iface_data) { TpSvcChannelInterfaceSubjectClass *klass = diff --git a/src/muc-channel.h b/src/muc-channel.h index f28b7a07e..0db129ed3 100644 --- a/src/muc-channel.h +++ b/src/muc-channel.h @@ -27,16 +27,13 @@ #include <glib-object.h> #include <gio/gio.h> -#include <telepathy-glib/base-channel.h> -#include <telepathy-glib/dbus-properties-mixin.h> -#include <telepathy-glib/group-mixin.h> -#include <telepathy-glib/message-mixin.h> +#include <telepathy-glib/telepathy-glib.h> #include "types.h" -#include "tubes-channel.h" #ifdef ENABLE_VOIP #include "call-muc-channel.h" #endif +#include "tube-iface.h" G_BEGIN_DECLS @@ -88,15 +85,29 @@ GType gabble_muc_channel_get_type (void); gboolean _gabble_muc_channel_is_ready (GabbleMucChannel *chan); +void gabble_muc_channel_set_autoclose (GabbleMucChannel *chan, + gboolean autoclose); + +gboolean gabble_muc_channel_get_autoclose (GabbleMucChannel *chan); + +gboolean gabble_muc_channel_can_be_closed (GabbleMucChannel *chan); + void gabble_muc_channel_send_presence (GabbleMucChannel *chan); gboolean gabble_muc_channel_send_invite (GabbleMucChannel *self, const gchar *jid, const gchar *message, gboolean continue_, GError **error); -GabbleTubesChannel * -gabble_muc_channel_open_tube (GabbleMucChannel *gmuc, - TpHandle initiator, - gboolean requested); +GabbleTubeIface * gabble_muc_channel_tube_request (GabbleMucChannel *self, + gpointer request_token, + GHashTable *request_properties, + gboolean require_new); + +void gabble_muc_channel_foreach_tubes (GabbleMucChannel *gmuc, + TpExportableChannelFunc foreach, gpointer user_data); + +void gabble_muc_channel_handle_si_stream_request (GabbleMucChannel *self, + GabbleBytestreamIface *bytestream, const gchar *stream_id, + WockyStanza *msg); #ifdef ENABLE_VOIP GabbleCallMucChannel * gabble_muc_channel_get_call (GabbleMucChannel *gmuc); @@ -114,7 +125,7 @@ gboolean gabble_muc_channel_request_call_finish (GabbleMucChannel *gmuc, GError **error); gboolean gabble_muc_channel_handle_jingle_session (GabbleMucChannel *channel, - GabbleJingleSession *session); + WockyJingleSession *session); #endif void gabble_muc_channel_update_configuration_async ( @@ -128,7 +139,6 @@ gboolean gabble_muc_channel_update_configuration_finish ( GError **error); void gabble_muc_channel_teardown (GabbleMucChannel *gmuc); -void gabble_muc_channel_close_tube (GabbleMucChannel *gmuc); G_END_DECLS diff --git a/src/muc-factory.c b/src/muc-factory.c index f734c13cc..0f1dbcb07 100644 --- a/src/muc-factory.c +++ b/src/muc-factory.c @@ -25,11 +25,9 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> #include <wocky/wocky.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/util.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_MUC @@ -46,7 +44,6 @@ #include "muc-channel.h" #include "namespaces.h" #include "presence-cache.h" -#include "tubes-channel.h" #include "tube-dbus.h" #include "tube-stream.h" #include "util.h" @@ -81,14 +78,10 @@ struct _GabbleMucFactoryPrivate guint message_cb_id; /* GUINT_TO_POINTER(room_handle) => (GabbleMucChannel *) */ GHashTable *text_channels; - /* Tubes channels which will be considered ready when the corresponding - * text channel is created. - * Borrowed GabbleMucChannel => borrowed GabbleTubesChannel */ - GHashTable *text_needed_for_tubes; /* Tube channels which will be considered ready when the corresponding - * tubes channel is created. - * Borrowed GabbleTubesChannel => GSlist of borrowed GabbleTubeIface */ - GHashTable *tubes_needed_for_tube; + * text channel is created. + * Borrowed GabbleMucChannel => owned GQueue of borrowed GabbleTubeIface */ + GHashTable *text_needed_for_tube; /* GabbleDiscoRequest * => NULL (used as a set) */ GHashTable *disco_requests; @@ -103,6 +96,9 @@ struct _GabbleMucFactoryPrivate static GObject *gabble_muc_factory_constructor (GType type, guint n_props, GObjectConstructParam *props); +static void gabble_muc_factory_associate_tube (GabbleMucFactory *self, + GabbleMucChannel *gmuc, GabbleTubeIface *tube); + static void gabble_muc_factory_init (GabbleMucFactory *fac) { @@ -113,13 +109,11 @@ 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->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, - g_direct_equal, NULL, (GDestroyNotify) g_slist_free); + priv->text_needed_for_tube = g_hash_table_new_full (g_direct_hash, + g_direct_equal, NULL, (GDestroyNotify) g_queue_free); priv->disco_requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); + NULL, NULL); priv->queued_requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); @@ -156,8 +150,7 @@ gabble_muc_factory_dispose (GObject *object) gabble_muc_factory_close_all (fac); g_assert (priv->text_channels == NULL); - g_assert (priv->text_needed_for_tubes == NULL); - g_assert (priv->tubes_needed_for_tube == NULL); + g_assert (priv->text_needed_for_tube == NULL); g_assert (priv->queued_requests == NULL); g_hash_table_foreach (priv->disco_requests, cancel_disco_request, @@ -239,19 +232,30 @@ muc_channel_closed_cb (GabbleMucChannel *chan, gpointer user_data) { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data); GabbleMucFactoryPrivate *priv = fac->priv; + TpBaseChannel *base = TP_BASE_CHANNEL (chan); TpHandle room_handle; - tp_channel_manager_emit_channel_closed_for_object (fac, - TP_EXPORTABLE_CHANNEL (chan)); + /* channel is actually reappearing, announce it */ + if (tp_base_channel_is_respawning (base)) + { + tp_channel_manager_emit_new_channel (fac, + TP_EXPORTABLE_CHANNEL (chan), NULL); + return; + } - if (priv->text_channels != NULL) + if (tp_base_channel_is_registered (base)) + { + tp_channel_manager_emit_channel_closed_for_object (fac, + TP_EXPORTABLE_CHANNEL (chan)); + } + + if (tp_base_channel_is_destroyed (base) + && priv->text_channels != NULL) { g_object_get (chan, "handle", &room_handle, NULL); DEBUG ("removing MUC channel with handle %d", room_handle); - gabble_muc_channel_close_tube (chan); - g_hash_table_remove (priv->text_channels, GUINT_TO_POINTER (room_handle)); } } @@ -262,86 +266,56 @@ muc_ready_cb (GabbleMucChannel *text_chan, { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data); GabbleMucFactoryPrivate *priv = fac->priv; - GabbleTubesChannel *tubes_chan; - GSList *requests_satisfied_text, *requests_satisfied_tubes = NULL; - gboolean text_requested; - GSList *tube_channels, *l; + GHashTable *channels; + TpBaseChannel *base = TP_BASE_CHANNEL (text_chan); + + GSList *requests_satisfied_text = NULL; + GQueue *tube_channels; DEBUG ("text chan=%p", text_chan); - g_object_get (text_chan, "requested", &text_requested, NULL); + channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_slist_free); requests_satisfied_text = g_hash_table_lookup ( priv->queued_requests, text_chan); g_hash_table_steal (priv->queued_requests, text_chan); requests_satisfied_text = g_slist_reverse (requests_satisfied_text); - tubes_chan = g_hash_table_lookup (priv->text_needed_for_tubes, text_chan); - g_hash_table_remove (priv->text_needed_for_tubes, text_chan); - - if (tubes_chan != NULL) - { - requests_satisfied_tubes = g_hash_table_lookup ( - priv->queued_requests, tubes_chan); - g_hash_table_steal (priv->queued_requests, tubes_chan); - } - /* Announce tube channels now */ - /* FIXME: we should probably aggregate tube announcement with tubes and text - * ones in some cases. */ - tube_channels = g_hash_table_lookup (priv->tubes_needed_for_tube, - tubes_chan); - - tube_channels = g_slist_reverse (tube_channels); - for (l = tube_channels; l != NULL; l = g_slist_next (l)) + tube_channels = g_hash_table_lookup (priv->text_needed_for_tube, text_chan); + if (tube_channels != NULL) { - GabbleTubeIface *tube_chan = GABBLE_TUBE_IFACE (l->data); - GSList *requests_satisfied_tube; + GList *l; - requests_satisfied_tube = g_hash_table_lookup (priv->queued_requests, - tube_chan); - g_hash_table_steal (priv->queued_requests, tube_chan); - requests_satisfied_tube = g_slist_reverse (requests_satisfied_tube); + for (l = tube_channels->head; l != NULL; l = l->next) + { + GabbleTubeIface *tube_chan = GABBLE_TUBE_IFACE (l->data); + GSList *requests_satisfied_tube; - tp_channel_manager_emit_new_channel (fac, - TP_EXPORTABLE_CHANNEL (tube_chan), requests_satisfied_tube); + requests_satisfied_tube = g_hash_table_lookup ( + priv->queued_requests, tube_chan); + g_hash_table_steal (priv->queued_requests, tube_chan); + requests_satisfied_tube = g_slist_reverse (requests_satisfied_tube); - g_slist_free (requests_satisfied_tube); + g_hash_table_insert (channels, tube_chan, requests_satisfied_tube); + } + + g_hash_table_remove (priv->text_needed_for_tube, text_chan); } - if (tubes_chan == NULL || text_requested) + /* only announce channels which are on the bus (requested or + * requested with an invite, not channels only around because they + * have to be) */ + if (tp_base_channel_is_registered (base)) { - /* There is no tubes channel or the text channel has been explicitely - * requested. In both cases, the text channel has to be announced - * separately. */ - - /* announce text channel */ tp_channel_manager_emit_new_channel (fac, TP_EXPORTABLE_CHANNEL (text_chan), requests_satisfied_text); - - if (tubes_chan != NULL) - { - tp_channel_manager_emit_new_channel (fac, - TP_EXPORTABLE_CHANNEL (tubes_chan), requests_satisfied_tubes); - } } - else - { - /* Announce text and tubes text_chan together */ - GHashTable *channels; - channels = g_hash_table_new (g_direct_hash, g_direct_equal); - g_hash_table_insert (channels, text_chan, requests_satisfied_text); - g_hash_table_insert (channels, tubes_chan, requests_satisfied_tubes); + tp_channel_manager_emit_new_channels (fac, channels); - tp_channel_manager_emit_new_channels (fac, channels); - - g_hash_table_unref (channels); - } - - g_hash_table_remove (priv->tubes_needed_for_tube, tubes_chan); - g_slist_free (requests_satisfied_text); - g_slist_free (requests_satisfied_tubes); + g_hash_table_unref (channels); } static void @@ -351,7 +325,7 @@ muc_join_error_cb (GabbleMucChannel *chan, { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data); GabbleMucFactoryPrivate *priv = fac->priv; - GabbleTubesChannel *tubes_chan; + GQueue *tube_channels; GSList *requests_satisfied; GSList *iter; @@ -369,23 +343,32 @@ muc_join_error_cb (GabbleMucChannel *chan, g_slist_free (requests_satisfied); - tubes_chan = g_hash_table_lookup (priv->text_needed_for_tubes, chan); + /* tube channels */ + tube_channels = g_hash_table_lookup (priv->text_needed_for_tube, chan); - if (tubes_chan != NULL) + if (tube_channels != NULL) { - g_hash_table_remove (priv->text_needed_for_tubes, chan); + GList *l; - requests_satisfied = g_slist_reverse (g_hash_table_lookup ( - priv->queued_requests, tubes_chan)); - g_hash_table_steal (priv->queued_requests, tubes_chan); - - for (iter = requests_satisfied; iter != NULL; iter = iter->next) + for (l = tube_channels->head; l != NULL; l = l->next) { - tp_channel_manager_emit_request_failed (fac, iter->data, - error->domain, error->code, error->message); + GabbleTubeIface *tube_chan = GABBLE_TUBE_IFACE (l->data); + + requests_satisfied = g_hash_table_lookup ( + priv->queued_requests, tube_chan); + g_hash_table_steal (priv->queued_requests, tube_chan); + requests_satisfied = g_slist_reverse (requests_satisfied); + + for (iter = requests_satisfied; iter != NULL; iter = iter->next) + { + tp_channel_manager_emit_request_failed (fac, iter->data, + error->domain, error->code, error->message); + } + + g_slist_free (requests_satisfied); } - g_slist_free (requests_satisfied); + g_hash_table_remove (priv->text_needed_for_tube, chan); } } @@ -394,9 +377,23 @@ muc_sub_channel_closed_cb (TpSvcChannel *chan, gpointer user_data) { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data); + GabbleMucChannel *muc; tp_channel_manager_emit_channel_closed_for_object (fac, TP_EXPORTABLE_CHANNEL (chan)); + + /* GabbleTubeDBus, GabbleTubeStream, and GabbleMucCallChannel all + * have "muc" properties. */ + g_object_get (chan, + "muc", &muc, + NULL); + + if (muc == NULL) + return; + + if (gabble_muc_channel_can_be_closed (muc) + && gabble_muc_channel_get_autoclose (muc)) + tp_base_channel_close (TP_BASE_CHANNEL (muc)); } #ifdef ENABLE_VOIP @@ -420,19 +417,18 @@ muc_channel_new_call (GabbleMucChannel *muc, static void muc_channel_new_tube (GabbleMucChannel *channel, - GabbleTubesChannel *tube, + GabbleTubeIface *tube, gpointer user_data) { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (user_data); - GabbleMucFactoryPrivate *priv = fac->priv; - /* If the muc channel is ready announce the tubes channel right away + /* If the muc channel is ready announce the tube channel right away * otherwise wait for the text channel to be ready */ if (_gabble_muc_channel_is_ready (channel)) tp_channel_manager_emit_new_channel (fac, - TP_EXPORTABLE_CHANNEL (tube), NULL); + TP_EXPORTABLE_CHANNEL (tube), NULL); else - g_hash_table_insert (priv->text_needed_for_tubes, channel, tube); + gabble_muc_factory_associate_tube (fac, channel, tube); g_signal_connect (tube, "closed", G_CALLBACK (muc_sub_channel_closed_cb), fac); @@ -448,6 +444,7 @@ new_muc_channel (GabbleMucFactory *fac, TpHandle inviter, const gchar *message, gboolean requested, + gboolean initially_register, GHashTable *initial_channels, GArray *initial_handles, char **initial_ids, @@ -459,11 +456,10 @@ new_muc_channel (GabbleMucFactory *fac, char *object_path; GPtrArray *initial_channels_array = NULL; - g_assert (g_hash_table_lookup (priv->text_channels, - GUINT_TO_POINTER (handle)) == NULL); + g_assert (gabble_muc_factory_find_text_channel (fac, handle) == NULL); object_path = g_strdup_printf ("%s/MucChannel%u", - conn->object_path, handle); + tp_base_connection_get_object_path (conn), handle); initial_channels_array = g_ptr_array_new (); if (initial_channels != NULL) @@ -490,13 +486,15 @@ new_muc_channel (GabbleMucFactory *fac, "object-path", object_path, "handle", handle, "invited", invited, - "initiator-handle", invited ? inviter : conn->self_handle, + "initiator-handle", + invited ? inviter : tp_base_connection_get_self_handle (conn), "invitation-message", message, "requested", requested, "initial-channels", initial_channels_array, "initial-invitee-handles", initial_handles, "initial-invitee-ids", initial_ids, "room-name", room_name, + "initially-register", initially_register, NULL); g_signal_connect (chan, "closed", (GCallback) muc_channel_closed_cb, fac); @@ -523,8 +521,6 @@ new_muc_channel (GabbleMucFactory *fac, return chan; } -// tubes_channel_closed_cb - static void do_invite (GabbleMucFactory *fac, const gchar *room, @@ -545,18 +541,15 @@ do_invite (GabbleMucFactory *fac, return; } - if (g_hash_table_lookup (priv->text_channels, - GUINT_TO_POINTER (room_handle)) == NULL) + if (gabble_muc_factory_find_text_channel (fac, room_handle) == NULL) { - new_muc_channel (fac, room_handle, TRUE, inviter_handle, reason, FALSE, - NULL, NULL, NULL, NULL); + new_muc_channel (fac, room_handle, TRUE, inviter_handle, reason, + FALSE, TRUE, NULL, NULL, NULL, NULL); } else { DEBUG ("ignoring invite to room \"%s\"; we're already there", room); } - - tp_handle_unref (room_repo, room_handle); } struct DiscoInviteData { @@ -584,8 +577,6 @@ obsolete_invite_disco_cb (GabbleDisco *self, GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data->factory); GabbleMucFactoryPrivate *priv = fac->priv; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); WockyNode *identity; const char *category = NULL, *type = NULL; @@ -617,7 +608,6 @@ obsolete_invite_disco_cb (GabbleDisco *self, do_invite (fac, jid, data->inviter, data->reason); out: - tp_handle_unref (contact_repo, data->inviter); g_free (data->reason); g_slice_free (struct DiscoInviteData, data); } @@ -690,8 +680,6 @@ process_muc_invite (GabbleMucFactory *fac, do_invite (fac, room, inviter_handle, reason); g_free (room); - tp_handle_unref (contact_repo, inviter_handle); - return TRUE; } @@ -769,7 +757,6 @@ process_obsolete_invite (GabbleMucFactory *fac, { DEBUG ("obsolete MUC invite disco failed, freeing info"); - tp_handle_unref (contact_repo, inviter_handle); g_free (disco_udata->reason); g_slice_free (struct DiscoInviteData, disco_udata); } @@ -843,6 +830,25 @@ gabble_muc_factory_broadcast_presence (GabbleMucFactory *self) } static void +gabble_muc_factory_associate_tube (GabbleMucFactory *self, + GabbleMucChannel *gmuc, + GabbleTubeIface *tube) +{ + GabbleMucFactoryPrivate *priv = self->priv; + GQueue *queue; + + queue = g_hash_table_lookup (priv->text_needed_for_tube, gmuc); + + if (queue == NULL) + { + queue = g_queue_new (); + g_hash_table_insert (priv->text_needed_for_tube, gmuc, queue); + } + + g_queue_push_tail (queue, tube); +} + +static void gabble_muc_factory_associate_request (GabbleMucFactory *self, gpointer channel, gpointer request) @@ -858,13 +864,11 @@ gabble_muc_factory_associate_request (GabbleMucFactory *self, } -static gboolean -cancel_queued_requests (gpointer k, - gpointer v, - gpointer d) +static void +cancel_queued_requests ( + GabbleMucFactory *self, + GSList *requests_satisfied) { - GabbleMucFactory *self = GABBLE_MUC_FACTORY (d); - GSList *requests_satisfied = v; GSList *iter; requests_satisfied = g_slist_reverse (requests_satisfied); @@ -872,13 +876,11 @@ cancel_queued_requests (gpointer k, for (iter = requests_satisfied; iter != NULL; iter = iter->next) { tp_channel_manager_emit_request_failed (self, - iter->data, TP_ERRORS, TP_ERROR_DISCONNECTED, + iter->data, TP_ERROR, TP_ERROR_DISCONNECTED, "Unable to complete this channel request, we're disconnecting!"); } g_slist_free (requests_satisfied); - - return TRUE; } @@ -897,16 +899,24 @@ gabble_muc_factory_close_all (GabbleMucFactory *self) } if (priv->queued_requests != NULL) - g_hash_table_foreach_steal (priv->queued_requests, - cancel_queued_requests, self); + { + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, priv->queued_requests); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + cancel_queued_requests (self, value); + g_hash_table_iter_steal (&iter); + } + } tp_clear_pointer (&priv->queued_requests, g_hash_table_unref); - tp_clear_pointer (&priv->text_needed_for_tubes, g_hash_table_unref); - tp_clear_pointer (&priv->tubes_needed_for_tube, g_hash_table_unref); + tp_clear_pointer (&priv->text_needed_for_tube, g_hash_table_unref); /* Use a temporary variable because we don't want - * muc_channel_closed_cb or tubes_channel_closed_cb to remove the channel - * from the hash table a second time */ + * muc_channel_closed_cb remove the channel from the hash table a + * second time */ if (priv->text_channels != NULL) { GHashTable *tmp = priv->text_channels; @@ -979,39 +989,6 @@ gabble_muc_factory_constructor (GType type, guint n_props, return obj; } - -struct _ForeachData -{ - TpExportableChannelFunc foreach; - gpointer user_data; -}; - -static void -_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); - } - -#ifdef ENABLE_VOIP - g_list_foreach (gabble_muc_channel_get_call_channels (gmuc), - (GFunc) data->foreach, data->user_data); -#endif -} - static void gabble_muc_factory_foreach_channel (TpChannelManager *manager, TpExportableChannelFunc foreach, @@ -1019,14 +996,24 @@ gabble_muc_factory_foreach_channel (TpChannelManager *manager, { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (manager); GabbleMucFactoryPrivate *priv = fac->priv; - struct _ForeachData data; + GHashTableIter iter; + gpointer value; - data.user_data = user_data; - data.foreach = foreach; + g_hash_table_iter_init (&iter, priv->text_channels); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + GabbleMucChannel *gmuc = GABBLE_MUC_CHANNEL (value); - g_hash_table_foreach (priv->text_channels, _foreach_slave, &data); -} + foreach (TP_EXPORTABLE_CHANNEL (gmuc), user_data); + + gabble_muc_channel_foreach_tubes (gmuc, foreach, user_data); +#ifdef ENABLE_VOIP + g_list_foreach (gabble_muc_channel_get_call_channels (gmuc), + (GFunc) foreach, user_data); +#endif + } +} /** * ensure_muc_channel: @@ -1042,6 +1029,7 @@ ensure_muc_channel (GabbleMucFactory *fac, TpHandle handle, GabbleMucChannel **ret, gboolean requested, + gboolean export_text, GHashTable *initial_channels, GArray *initial_handles, char **initial_ids, @@ -1049,13 +1037,21 @@ ensure_muc_channel (GabbleMucFactory *fac, { TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; - *ret = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle)); + *ret = gabble_muc_factory_find_text_channel (fac, handle); if (*ret == NULL) { - *ret = new_muc_channel (fac, handle, FALSE, base_conn->self_handle, NULL, - requested, initial_channels, initial_handles, initial_ids, room_name); - return FALSE; + *ret = new_muc_channel (fac, handle, FALSE, + tp_base_connection_get_self_handle (base_conn), + NULL, requested, export_text, initial_channels, + initial_handles, initial_ids, room_name); + + gabble_muc_channel_set_autoclose (*ret, !export_text); + } + else + { + if (export_text) + gabble_muc_channel_set_autoclose (*ret, FALSE); } if (_gabble_muc_channel_is_ready (*ret)) @@ -1076,26 +1072,29 @@ gabble_muc_factory_handle_si_stream_request (GabbleMucFactory *self, TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM); GabbleMucChannel *gmuc = NULL; - GabbleTubesChannel *tube = NULL; + WockyStanzaType stanza_type; + WockyStanzaSubType sub_type; g_return_if_fail (tp_handle_is_valid (room_repo, room_handle, NULL)); - gmuc = g_hash_table_lookup (priv->text_channels, - GUINT_TO_POINTER (room_handle)); - g_object_get (gmuc, "tube", &tube, NULL); + wocky_stanza_get_type_info (msg, &stanza_type, &sub_type); + g_return_if_fail (stanza_type == WOCKY_STANZA_TYPE_IQ); + g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); - if (tube == NULL) + gmuc = gabble_muc_factory_find_text_channel (self, room_handle); + + if (gmuc == NULL) { GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "No tubes channel available for this MUC" }; + "No MUC channel available" }; - DEBUG ("tubes channel doesn't exist for muc %d", room_handle); + DEBUG ("MUC channel doesn't exist handle %d", room_handle); gabble_bytestream_iface_close (bytestream, &e); return; } - gabble_tubes_channel_bytestream_offered (tube, bytestream, msg); - g_object_unref (tube); + gabble_muc_channel_handle_si_stream_request ( + gmuc, bytestream, stream_id, msg); } GabbleMucChannel * @@ -1129,12 +1128,6 @@ static const gchar * const muc_channel_allowed_properties[] = { NULL }; -static const gchar * const muc_tubes_channel_allowed_properties[] = { - TP_PROP_CHANNEL_TARGET_HANDLE, - TP_PROP_CHANNEL_TARGET_ID, - NULL -}; - static void gabble_muc_factory_type_foreach_channel_class (GType type, TpChannelManagerTypeChannelClassFunc func, @@ -1159,11 +1152,6 @@ gabble_muc_factory_type_foreach_channel_class (GType type, func (type, table, muc_channel_allowed_properties, user_data); - /* Channel.Type.Tubes */ - g_value_set_static_string (channel_type_value, TP_IFACE_CHANNEL_TYPE_TUBES); - func (type, table, muc_tubes_channel_allowed_properties, - user_data); - /* Muc Channel.Type.StreamTube */ g_value_set_static_string (channel_type_value, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); @@ -1188,31 +1176,6 @@ gabble_muc_factory_type_foreach_channel_class (GType type, g_hash_table_unref (table); } -/* return TRUE if the text_channel associated is ready */ -static gboolean -ensure_tubes_channel (GabbleMucFactory *self, - TpHandle handle, - GabbleTubesChannel **tubes_chan, - gboolean requested) -{ - GabbleMucFactoryPrivate *priv = self->priv; - 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, - NULL, NULL, NULL, NULL); - - /* 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); - - return result; -} - static gboolean handle_text_channel_request (GabbleMucFactory *self, gpointer request_token, @@ -1225,7 +1188,7 @@ handle_text_channel_request (GabbleMucFactory *self, TpBaseConnection *conn = TP_BASE_CONNECTION (priv->conn); GabbleMucChannel *text_chan; TpHandleSet *handles; - TpIntSet *continue_handles; + TpIntset *continue_handles; guint i; gboolean ret = TRUE; @@ -1279,7 +1242,7 @@ handle_text_channel_request (GabbleMucFactory *self, const char *object_path = g_ptr_array_index (initial_channels, i); GObject *object; TpHandle handle; - GabbleConnection *connection; + TpBaseConnection *connection; object = dbus_g_connection_lookup_g_object (bus, object_path); @@ -1290,19 +1253,19 @@ handle_text_channel_request (GabbleMucFactory *self, continue; } - g_object_get (object, - "connection", &connection, - "handle", &handle, - NULL); - g_object_unref (connection); /* drop the ref immediately */ + connection = tp_base_channel_get_connection ( + TP_BASE_CHANNEL (object)); - if (connection != priv->conn) + if ((GabbleConnection *) connection != priv->conn) { DEBUG ("Channel %s is from a different Connection, ignoring", object_path); continue; } + handle = tp_base_channel_get_target_handle ( + TP_BASE_CHANNEL (object)); + tp_handle_set_add (handles, handle); tp_intset_add (continue_handles, handle); g_hash_table_insert (final_channels, (char *) object_path, NULL); @@ -1343,7 +1306,6 @@ handle_text_channel_request (GabbleMucFactory *self, } tp_handle_set_add (handles, handle); - tp_handle_unref (contact_handles, handle); } } @@ -1418,11 +1380,6 @@ handle_text_channel_request (GabbleMucFactory *self, goto out; } } - else - { - /* ref room here so we can unref it again, below */ - tp_handle_ref (room_handles, room); - } /* Make sure TargetID and RoomName don't conflict. */ if (room_name != NULL && room_name[0] != '\0') @@ -1439,7 +1396,7 @@ handle_text_channel_request (GabbleMucFactory *self, if (!ok) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "TargetID's node part (%s) doesn't match RoomName (%s)", target_room, room_name); ret = FALSE; @@ -1469,7 +1426,7 @@ handle_text_channel_request (GabbleMucFactory *self, if (!ok) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "TargetID's domain part (%s) doesn't match Server (%s)", target_server, server_prop); ret = FALSE; @@ -1482,14 +1439,15 @@ handle_text_channel_request (GabbleMucFactory *self, } - if (ensure_muc_channel (self, priv, room, &text_chan, TRUE, + if (ensure_muc_channel (self, priv, room, &text_chan, TRUE, TRUE, final_channels, final_handles, final_ids, room_name)) { /* channel exists */ - if (require_new) + if (require_new + && tp_base_channel_is_registered (TP_BASE_CHANNEL (text_chan))) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "That channel has already been created (or requested)"); ret = FALSE; } @@ -1499,15 +1457,30 @@ handle_text_channel_request (GabbleMucFactory *self, initial_handles != NULL || initial_ids != NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Cannot set InitialChannels, InitialInviteeHandles or " "InitialInviteIDs for existing channel"); ret = FALSE; } else { - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (text_chan)); + if (tp_base_channel_is_registered (TP_BASE_CHANNEL (text_chan))) + { + tp_channel_manager_emit_request_already_satisfied (self, + request_token, TP_EXPORTABLE_CHANNEL (text_chan)); + } + else + { + GSList *tokens; + + tp_base_channel_register (TP_BASE_CHANNEL (text_chan)); + + tokens = g_slist_append (NULL, request_token); + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (text_chan), tokens); + g_slist_free (tokens); + } + ret = TRUE; } } @@ -1546,9 +1519,6 @@ handle_text_channel_request (GabbleMucFactory *self, } out: - if (room != 0) - tp_handle_unref (room_handles, room); - g_hash_table_unref (final_channels); g_array_unref (final_handles); g_free (final_ids); @@ -1560,62 +1530,6 @@ out: } static gboolean -handle_tubes_channel_request (GabbleMucFactory *self, - gpointer request_token, - GHashTable *request_properties, - gboolean require_new, - TpHandle handle, - GError **error) -{ - GabbleMucFactoryPrivate *priv = self->priv; - GabbleTubesChannel *tube = NULL; - GabbleMucChannel *gmuc = NULL; - - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - muc_tubes_channel_fixed_properties, - muc_tubes_channel_allowed_properties, - error)) - return FALSE; - - gmuc = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle)); - - if (gmuc != NULL) - g_object_get (gmuc, "tube", &tube, NULL); - - if (tube != NULL) - { - if (require_new) - { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "That channel has already been created (or requested)"); - return FALSE; - } - else - { - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (tube)); - } - } - 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 (tube), list); - g_slist_free (list); - } - else - { - gabble_muc_factory_associate_request (self, tube, request_token); - } - - g_object_unref (tube); - - return TRUE; -} - -static gboolean handle_tube_channel_request (GabbleMucFactory *self, gpointer request_token, GHashTable *request_properties, @@ -1625,63 +1539,38 @@ handle_tube_channel_request (GabbleMucFactory *self, { GabbleMucFactoryPrivate *priv = self->priv; - gboolean can_announce_now = TRUE; - gboolean tubes_channel_created = FALSE; - GabbleTubesChannel *tube = NULL; + gboolean can_announce_now; GabbleMucChannel * gmuc; GabbleTubeIface *new_channel; - gmuc = g_hash_table_lookup (priv->text_channels, GUINT_TO_POINTER (handle)); + gmuc = gabble_muc_factory_find_text_channel (self, handle); - if (gmuc != NULL) - g_object_get (gmuc, "tube", &tube, NULL); + if (gmuc == NULL) + ensure_muc_channel (self, priv, handle, &gmuc, FALSE, FALSE, + NULL, NULL, NULL, NULL); - if (tube == NULL) - { - /* Need to create a tubes channel */ - if (!ensure_tubes_channel (self, handle, &tube, FALSE)) - { - /* We have to wait the tubes channel before announcing */ - can_announce_now = FALSE; - } - - tubes_channel_created = TRUE; - } + can_announce_now = _gabble_muc_channel_is_ready (gmuc); - g_assert (tube != NULL); + new_channel = gabble_muc_channel_tube_request (gmuc, request_token, + request_properties, TRUE); - new_channel = gabble_tubes_channel_tube_request (tube, - request_token, request_properties, TRUE); - g_assert (new_channel != NULL); + g_signal_connect (new_channel, "closed", + G_CALLBACK (muc_sub_channel_closed_cb), self); if (can_announce_now) { - GHashTable *channels; GSList *request_tokens; - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); - - if (tubes_channel_created) - g_hash_table_insert (channels, tube, NULL); - request_tokens = g_slist_prepend (NULL, request_token); - g_hash_table_insert (channels, new_channel, request_tokens); - tp_channel_manager_emit_new_channels (self, channels); + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (new_channel), request_tokens); - g_hash_table_unref (channels); g_slist_free (request_tokens); } else { - GSList *l; - - 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, tube, l); + gabble_muc_factory_associate_tube (self, gmuc, new_channel); /* And now finally associate the new stream or dbus tube channel with * the request token so that when the muc channel is ready, the request @@ -1689,8 +1578,6 @@ handle_tube_channel_request (GabbleMucFactory *self, gabble_muc_factory_associate_request (self, new_channel, request_token); } - g_object_unref (tube); - return TRUE; } @@ -1715,7 +1602,7 @@ handle_stream_tube_channel_request (GabbleMucFactory *self, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); if (service == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Request does not contain the mandatory property '%s'", TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); return FALSE; @@ -1746,7 +1633,7 @@ handle_dbus_tube_channel_request (GabbleMucFactory *self, TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); if (service == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Request does not contain the mandatory property '%s'", TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); return FALSE; @@ -1810,12 +1697,12 @@ handle_call_channel_request (GabbleMucFactory *self, if (!initial_audio && !initial_video) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Request didn't set either InitialAudio or InitialVideo"); return FALSE; } - ensure_muc_channel (self, priv, handle, &muc, FALSE, NULL, NULL, NULL, NULL); + ensure_muc_channel (self, priv, handle, &muc, FALSE, FALSE, NULL, NULL, NULL, NULL); call = gabble_muc_channel_get_call (muc); @@ -1823,7 +1710,7 @@ handle_call_channel_request (GabbleMucFactory *self, { if (require_new) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "There is already a call in this muc"); goto error; } @@ -1870,7 +1757,6 @@ typedef struct { static ChannelTypeHandler channel_type_handlers[] = { { TP_IFACE_CHANNEL_TYPE_TEXT, handle_text_channel_request }, - { TP_IFACE_CHANNEL_TYPE_TUBES, handle_tubes_channel_request }, { TP_IFACE_CHANNEL_TYPE_STREAM_TUBE, handle_stream_tube_channel_request }, { TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, handle_dbus_tube_channel_request }, #ifdef ENABLE_VOIP @@ -1980,7 +1866,7 @@ gabble_muc_factory_ensure_channel (TpChannelManager *manager, #ifdef ENABLE_VOIP gboolean gabble_muc_factory_handle_jingle_session (GabbleMucFactory *self, - GabbleJingleSession *session) + WockyJingleSession *session) { GabbleMucFactoryPrivate *priv = self->priv; TpHandleRepoIface *room_repo = tp_base_connection_get_handles ( @@ -1988,14 +1874,13 @@ gabble_muc_factory_handle_jingle_session (GabbleMucFactory *self, TpHandle room; room = gabble_get_room_handle_from_jid (room_repo, - gabble_jingle_session_get_peer_jid (session)); + wocky_jingle_session_get_peer_jid (session)); if (room != 0) { GabbleMucChannel *channel; - channel = g_hash_table_lookup (priv->text_channels, - GUINT_TO_POINTER (room)); + channel = gabble_muc_factory_find_text_channel (self, room); g_assert (GABBLE_IS_MUC_CHANNEL (channel)); if (channel != NULL) diff --git a/src/muc-factory.h b/src/muc-factory.h index 23c635458..507ae5298 100644 --- a/src/muc-factory.h +++ b/src/muc-factory.h @@ -26,9 +26,6 @@ #include <wocky/wocky.h> #include "bytestream-iface.h" -#ifdef ENABLE_VOIP -#include "jingle-types.h" -#endif #include "types.h" G_BEGIN_DECLS @@ -76,7 +73,7 @@ void gabble_muc_factory_broadcast_presence (GabbleMucFactory *self); #ifdef ENABLE_VOIP gboolean gabble_muc_factory_handle_jingle_session (GabbleMucFactory *self, - GabbleJingleSession *session); + WockyJingleSession *session); #endif G_END_DECLS diff --git a/src/muc-tube-dbus.c b/src/muc-tube-dbus.c index 2aa61fc82..6ba1d827f 100644 --- a/src/muc-tube-dbus.c +++ b/src/muc-tube-dbus.c @@ -18,16 +18,24 @@ */ #include "config.h" + #include "muc-tube-dbus.h" G_DEFINE_TYPE (GabbleMucTubeDBus, gabble_muc_tube_dbus, GABBLE_TYPE_TUBE_DBUS) -static const gchar *gabble_muc_tube_dbus_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - TP_IFACE_CHANNEL_INTERFACE_TUBE, - NULL -}; +static GPtrArray * +gabble_muc_tube_dbus_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_muc_tube_dbus_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_GROUP); + + return interfaces; +} static void gabble_muc_tube_dbus_init (GabbleMucTubeDBus *self) @@ -41,6 +49,6 @@ gabble_muc_tube_dbus_class_init ( TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS ( gabble_muc_tube_dbus_class); - base_class->interfaces = gabble_muc_tube_dbus_interfaces; + base_class->get_interfaces = gabble_muc_tube_dbus_get_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; } diff --git a/src/muc-tube-stream.c b/src/muc-tube-stream.c index 3700c46f6..96448ab2b 100644 --- a/src/muc-tube-stream.c +++ b/src/muc-tube-stream.c @@ -18,16 +18,24 @@ */ #include "config.h" + #include "muc-tube-stream.h" G_DEFINE_TYPE (GabbleMucTubeStream, gabble_muc_tube_stream, GABBLE_TYPE_TUBE_STREAM) -static const gchar *gabble_muc_tube_stream_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - TP_IFACE_CHANNEL_INTERFACE_TUBE, - NULL -}; +static GPtrArray * +gabble_muc_tube_stream_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_muc_tube_stream_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_GROUP); + + return interfaces; +} static void gabble_muc_tube_stream_init (GabbleMucTubeStream *self) @@ -41,6 +49,6 @@ gabble_muc_tube_stream_class_init ( TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS ( gabble_muc_tube_stream_class); - base_class->interfaces = gabble_muc_tube_stream_interfaces; + base_class->get_interfaces = gabble_muc_tube_stream_get_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_ROOM; } diff --git a/src/namespaces.h b/src/namespaces.h index 13ae5dbb6..2a2d8f91b 100644 --- a/src/namespaces.h +++ b/src/namespaces.h @@ -103,6 +103,7 @@ #define NS_PRESENCE_INVISIBLE "presence-invisible" #define NS_PRIVACY "jabber:iq:privacy" #define NS_INVISIBLE "urn:xmpp:invisible:0" +#define NS_RECEIPTS "urn:xmpp:receipts" #define NS_REGISTER "jabber:iq:register" #define NS_ROSTER "jabber:iq:roster" #define NS_SEARCH "jabber:iq:search" @@ -135,4 +136,8 @@ #define NS_TP_FT_METADATA_SERVICE "http://telepathy.freedesktop.org/xmpp/file-transfer-service" #define NS_TP_FT_METADATA "http://telepathy.freedesktop.org/xmpp/file-transfer-metadata" +/* This is used by WLM to convert Windows Live ID to XMPP jid. + * See http://msdn.microsoft.com/en-us/library/live/hh550849.aspx */ +#define NS_WLM_JID_LOOKUP "http://messenger.live.com/xmpp/jidlookup" + #endif /* __GABBLE_NAMESPACES__H__ */ diff --git a/src/olpc-activity.c b/src/olpc-activity.c index 1c5f7d3af..a5f34a581 100644 --- a/src/olpc-activity.c +++ b/src/olpc-activity.c @@ -18,6 +18,7 @@ */ #include "config.h" + #include "olpc-activity.h" #include <stdlib.h> @@ -64,26 +65,6 @@ gabble_olpc_activity_init (GabbleOlpcActivity *self) } static void -gabble_olpc_activity_dispose (GObject *object) -{ - GabbleOlpcActivity *self = GABBLE_OLPC_ACTIVITY (object); - GabbleOlpcActivityPrivate *priv = self->priv; - TpHandleRepoIface *room_repo; - - if (priv->dispose_has_run) - return; - - room_repo = tp_base_connection_get_handles ((TpBaseConnection *) priv->conn, - TP_HANDLE_TYPE_ROOM); - tp_handle_unref (room_repo, self->room); - - priv->dispose_has_run = TRUE; - - if (G_OBJECT_CLASS (gabble_olpc_activity_parent_class)->dispose) - G_OBJECT_CLASS (gabble_olpc_activity_parent_class)->dispose (object); -} - -static void gabble_olpc_activity_finalize (GObject *object) { GabbleOlpcActivity *self = GABBLE_OLPC_ACTIVITY (object); @@ -172,23 +153,14 @@ gabble_olpc_activity_constructor (GType type, { GObject *obj; GabbleOlpcActivity *self; - GabbleOlpcActivityPrivate *priv; - TpHandleRepoIface *room_repo; obj = G_OBJECT_CLASS (gabble_olpc_activity_parent_class)-> constructor (type, n_props, props); self = GABBLE_OLPC_ACTIVITY (obj); - priv = self->priv; - - room_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, - TP_HANDLE_TYPE_ROOM); g_assert (self->room != 0); - tp_handle_ref (room_repo, self->room); - DEBUG ("new activity %s (%d)", gabble_olpc_activity_get_room (self), self->room); @@ -209,7 +181,6 @@ gabble_olpc_activity_class_init ( g_type_class_add_private (gabble_olpc_activity_class, sizeof (GabbleOlpcActivityPrivate)); - object_class->dispose = gabble_olpc_activity_dispose; object_class->finalize = gabble_olpc_activity_finalize; param_spec = g_param_spec_object ( diff --git a/src/olpc-activity.h b/src/olpc-activity.h index 47101bd66..4c08df6cf 100644 --- a/src/olpc-activity.h +++ b/src/olpc-activity.h @@ -22,8 +22,7 @@ #include <glib-object.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/handle-repo.h> +#include <telepathy-glib/telepathy-glib.h> #include "connection.h" diff --git a/src/plugin-connection.c b/src/plugin-connection.c index 0d0d95e9f..dcbb74bc6 100644 --- a/src/plugin-connection.c +++ b/src/plugin-connection.c @@ -23,7 +23,7 @@ #include <glib-object.h> #include <gabble/types.h> -#include <telepathy-glib/errors.h> +#include <telepathy-glib/telepathy-glib.h> #include <debug.h> diff --git a/src/plugin-loader.c b/src/plugin-loader.c index dedc724ad..d308437ee 100644 --- a/src/plugin-loader.c +++ b/src/plugin-loader.c @@ -28,8 +28,7 @@ # include <gmodule.h> #endif -#include <telepathy-glib/errors.h> -#include <telepathy-glib/presence-mixin.h> +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_PLUGINS #include "debug.h" @@ -301,7 +300,7 @@ gabble_plugin_loader_create_sidecar ( } g_simple_async_report_error_in_idle (G_OBJECT (self), callback, user_data, - TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, "No plugin implements sidecar '%s'", + TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "No plugin implements sidecar '%s'", sidecar_interface); } diff --git a/src/plugin-loader.h b/src/plugin-loader.h index 15bce505e..985cccbc5 100644 --- a/src/plugin-loader.h +++ b/src/plugin-loader.h @@ -23,8 +23,7 @@ #include <glib-object.h> #include <gio/gio.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/presence-mixin.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #include "gabble/sidecar.h" diff --git a/src/plugin.c b/src/plugin.c index 2003d3e87..2ddd23ea6 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -22,9 +22,7 @@ #include "gabble/plugin.h" -#include <telepathy-glib/errors.h> -#include <telepathy-glib/presence-mixin.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_PLUGINS #include "debug.h" @@ -110,17 +108,17 @@ gabble_plugin_create_sidecar_async ( if (!gabble_plugin_implements_sidecar (plugin, sidecar_interface)) g_simple_async_report_error_in_idle (G_OBJECT (plugin), callback, - user_data, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Gabble is buggy: '%s' doesn't implement sidecar %s", iface->name, sidecar_interface); else if (iface->create_sidecar_async == NULL) g_simple_async_report_error_in_idle (G_OBJECT (plugin), callback, - user_data, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' is buggy: it claims to implement %s, but does not implement " "create_sidecar_async", iface->name, sidecar_interface); else if (iface->create_sidecar_finish == NULL) g_simple_async_report_error_in_idle (G_OBJECT (plugin), callback, - user_data, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + user_data, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "'%s' is buggy: does not imlement create_sidecar_finish", iface->name); else diff --git a/src/presence-cache.c b/src/presence-cache.c index 72901a057..f7d02eecf 100644 --- a/src/presence-cache.c +++ b/src/presence-cache.c @@ -35,8 +35,7 @@ #define DEBUG_FLAG GABBLE_DEBUG_PRESENCE #include <dbus/dbus-glib.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/intset.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_PRESENCE @@ -147,7 +146,6 @@ disco_waiter_new (TpHandleRepoIface *repo, DiscoWaiter *waiter; g_assert (repo); - tp_handle_ref (repo, handle); waiter = g_slice_new0 (DiscoWaiter); waiter->repo = repo; @@ -171,8 +169,6 @@ disco_waiter_free (DiscoWaiter *waiter) DEBUG ("freeing waiter %p for handle %u with serial %u", waiter, waiter->handle, waiter->serial); - tp_handle_unref (waiter->repo, waiter->handle); - g_free (waiter->resource); g_free (waiter->hash); g_free (waiter->ver); @@ -501,49 +497,9 @@ static void gabble_presence_cache_add_bundle_caps (GabblePresenceCache *cache, static void gabble_presence_cache_add_bundles (GabblePresenceCache *cache) { -#define GOOGLE_BUNDLE(cap, features) \ - gabble_presence_cache_add_bundle_caps (cache, \ - "http://www.google.com/xmpp/client/caps#" cap, features); \ - gabble_presence_cache_add_bundle_caps (cache, \ - "http://talk.google.com/xmpp/client/caps#" cap, features); \ - gabble_presence_cache_add_bundle_caps (cache, \ - "http://www.android.com/gtalk/client/caps#" cap, features); \ - gabble_presence_cache_add_bundle_caps (cache, \ - "http://www.android.com/gtalk/client/caps2#" cap, features); \ - gabble_presence_cache_add_bundle_caps (cache, \ - "http://talk.google.com/xmpp/bot/caps#" cap, features); - - /* Cache various bundle from the Google Talk clients as trusted. Some old - * versions of Google Talk do not reply correctly to discovery requests. - * Plus, we know what Google's bundles mean, so it's a waste of time to disco - * them, particularly the ones for features we don't support. The desktop - * client doesn't currently have all of these, but it doesn't hurt to cache - * them anyway. - */ - GOOGLE_BUNDLE ("voice-v1", NS_GOOGLE_FEAT_VOICE); - GOOGLE_BUNDLE ("video-v1", NS_GOOGLE_FEAT_VIDEO); - GOOGLE_BUNDLE ("camera-v1", NS_GOOGLE_FEAT_CAMERA); - - /* File transfer support */ - GOOGLE_BUNDLE ("share-v1", NS_GOOGLE_FEAT_SHARE); - - /* Not really sure what this ones is. */ - GOOGLE_BUNDLE ("sms-v1", NULL); - - /* TODO: remove this when we fix fd.o#22768. */ - GOOGLE_BUNDLE ("pmuc-v1", NULL); - - /* The camera-v1 bundle seems to mean "I have a camera plugged in". Not - * having it doesn't seem to affect anything, and we have no way of exposing - * that information anyway. - */ - GOOGLE_BUNDLE ("camera-v1", NULL); - -#undef GOOGLE_BUNDLE - - /* We should also cache the ext='' bundles Gabble advertises: older Gabbles - * advertise these and don't support hashed caps, and we shouldn't need to - * disco them. + /* We cache the ext='' bundles Gabble advertises: older Gabbles + * advertise these and don't support hashed caps, and we shouldn't + * need to disco them. */ gabble_presence_cache_add_bundle_caps (cache, NS_GABBLE_CAPS "#" BUNDLE_VOICE_V1, NS_GOOGLE_FEAT_VOICE); @@ -839,7 +795,7 @@ self_avatar_resolve_conflict (GabblePresenceCache *cache) GabblePresence *presence = priv->conn->self_presence; GError *error = NULL; - if (base_conn->status != TP_CONNECTION_STATUS_CONNECTED) + if (tp_base_connection_get_status (base_conn) != TP_CONNECTION_STATUS_CONNECTED) { DEBUG ("no longer connected"); return; @@ -885,9 +841,10 @@ self_avatar_resolve_conflict (GabblePresenceCache *cache) } gabble_vcard_manager_invalidate_cache (priv->conn->vcard_manager, - base_conn->self_handle); + tp_base_connection_get_self_handle (base_conn)); gabble_vcard_manager_request (priv->conn->vcard_manager, - base_conn->self_handle, 0, self_vcard_request_cb, cache, + tp_base_connection_get_self_handle (base_conn), 0, + self_vcard_request_cb, cache, NULL); } @@ -903,7 +860,7 @@ _grab_avatar_sha1 (GabblePresenceCache *cache, WockyNode *x_node, *photo_node; GabblePresence *presence; - if (handle == base_conn->self_handle) + if (handle == tp_base_connection_get_self_handle (base_conn)) presence = priv->conn->self_presence; else presence = gabble_presence_cache_get (cache, handle); @@ -949,14 +906,14 @@ _grab_avatar_sha1 (GabblePresenceCache *cache, if (tp_strdiff (presence->avatar_sha1, sha1)) { - if (handle == base_conn->self_handle) + if (handle == tp_base_connection_get_self_handle (base_conn)) { DEBUG ("Avatar conflict! Received hash '%s' and our cache is '%s'", sha1, presence->avatar_sha1 == NULL ? "<NULL>" : presence->avatar_sha1); self_avatar_resolve_conflict (cache); } - else if (base_conn->status == TP_CONNECTION_STATUS_CONNECTED) + else if (tp_base_connection_get_status (base_conn) == TP_CONNECTION_STATUS_CONNECTED) { g_free (presence->avatar_sha1); presence->avatar_sha1 = g_strdup (sha1); @@ -970,9 +927,10 @@ static GSList * _parse_cap_bundles ( WockyNode *lm_node, const gchar **hash, - const gchar **ver) + const gchar **ver, + const gchar **node) { - const gchar *node, *ext; + const gchar *ext; GSList *uris = NULL; WockyNode *cap_node; @@ -986,15 +944,15 @@ _parse_cap_bundles ( *hash = wocky_node_get_attribute (cap_node, "hash"); - node = wocky_node_get_attribute (cap_node, "node"); + *node = wocky_node_get_attribute (cap_node, "node"); - if (NULL == node) + if (NULL == *node) return NULL; *ver = wocky_node_get_attribute (cap_node, "ver"); if (NULL != *ver) - uris = g_slist_prepend (uris, g_strdup_printf ("%s#%s", node, *ver)); + uris = g_slist_prepend (uris, g_strdup (*ver)); /* If there is a hash, the remote contact uses XEP-0115 v1.5 and the 'ext' * attribute MUST be ignored. */ @@ -1010,7 +968,7 @@ _parse_cap_bundles ( exts = g_strsplit (ext, " ", 0); for (i = exts; NULL != *i; i++) - uris = g_slist_prepend (uris, g_strdup_printf ("%s#%s", node, *i)); + uris = g_slist_prepend (uris, g_strdup (*i)); g_strfreev (exts); } @@ -1365,7 +1323,7 @@ _caps_disco_cb (GabbleDisco *disco, if (NULL == waiter_self) { DEBUG ("Ignoring non requested disco reply from %s", jid); - goto OUT; + return; } /* Now onto caps */ @@ -1507,16 +1465,51 @@ _caps_disco_cb (GabbleDisco *disco, gabble_capability_set_free (cap_set); g_ptr_array_unref (data_forms); +} + +static gboolean +get_google_cap (const gchar *fragment, + const gchar **ns) +{ + if (!tp_strdiff (fragment, "voice-v1")) + { + *ns = NS_GOOGLE_FEAT_VOICE; + return TRUE; + } + else if (!tp_strdiff (fragment, "video-v1")) + { + *ns = NS_GOOGLE_FEAT_VIDEO; + return TRUE; + } + else if (!tp_strdiff (fragment, "share-v1")) + { + *ns = NS_GOOGLE_FEAT_SHARE; + return TRUE; + } + else if (!tp_strdiff (fragment, "sms-v1")) + { + *ns = NULL; + return TRUE; + } + else if (!tp_strdiff (fragment, "pmuc-v1")) + { + *ns = NULL; + return TRUE; + } + else if (!tp_strdiff (fragment, "camera-v1")) + { + *ns = NULL; + return TRUE; + } -OUT: - if (handle) - tp_handle_unref (contact_repo, handle); + return FALSE; } static void _process_caps_uri (GabblePresenceCache *cache, const gchar *from, - const gchar *uri, + const gchar *node, + const gchar *fragment, const gchar *hash, const gchar *ver, TpHandle handle, @@ -1529,6 +1522,8 @@ _process_caps_uri (GabblePresenceCache *cache, GabblePresenceCachePrivate *priv; TpHandleRepoIface *contact_repo; WockyCapsCache *caps_cache; + gchar *uri = g_strdup_printf ("%s#%s", node, fragment); + const gchar *ns = NULL; priv = cache->priv; contact_repo = tp_base_connection_get_handles ( @@ -1596,6 +1591,34 @@ _process_caps_uri (GabblePresenceCache *cache, if (cached_caps != NULL) gabble_capability_set_free (cached_caps); } + else if (hash == NULL && get_google_cap (fragment, &ns)) + { + /* if the hash is NULL then are looking at the ext='...' values, + * so this is starting to smell like Google */ + GabblePresence *presence = gabble_presence_cache_get (cache, handle); + + /* we already know about this fragment; apply the known value to + * the (handle, resource) */ + DEBUG ("we know about fragment %s, setting caps for %u (%s)", fragment, handle, + from); + + if (presence != NULL) + { + GabbleCapabilitySet *cap_set = gabble_capability_set_new (); + + if (ns != NULL) + gabble_capability_set_add (cap_set, ns); + + gabble_presence_set_capabilities ( + presence, resource, cap_set, NULL, serial); + + gabble_capability_set_free (cap_set); + } + else + { + DEBUG ("presence not found"); + } + } else { GSList *waiters; @@ -1661,6 +1684,8 @@ _process_caps_uri (GabblePresenceCache *cache, out: if (cached_query_reply != NULL) g_object_unref (cached_query_reply); + + g_free (uri); } static void @@ -1672,10 +1697,11 @@ _process_caps (GabblePresenceCache *cache, { const gchar *resource; GSList *uris, *i; + GabblePresenceCachePrivate *priv; GabbleCapabilitySet *old_cap_set = NULL; guint serial; - const gchar *hash, *ver; + const gchar *hash, *ver, *node; priv = cache->priv; serial = priv->caps_serial++; @@ -1684,7 +1710,7 @@ _process_caps (GabblePresenceCache *cache, if (resource != NULL) resource++; - uris = _parse_cap_bundles (lm_node, &hash, &ver); + uris = _parse_cap_bundles (lm_node, &hash, &ver, &node); if (presence) { @@ -1706,7 +1732,7 @@ _process_caps (GabblePresenceCache *cache, */ for (i = uris; NULL != i; i = i->next) { - _process_caps_uri (cache, from, (gchar *) i->data, hash, ver, handle, + _process_caps_uri (cache, from, node, (gchar *) i->data, hash, ver, handle, resource, serial); g_free (i->data); @@ -2217,6 +2243,7 @@ gabble_presence_cache_add_own_caps ( { gchar *uri = g_strdup_printf ("%s#%s", NS_GABBLE_CAPS, ver); GabbleCapabilityInfo *info = capability_info_get (cache, uri); + TpBaseConnection *base_conn = TP_BASE_CONNECTION (cache->priv->conn); if (info->complete) goto out; @@ -2246,7 +2273,7 @@ gabble_presence_cache_add_own_caps ( info->complete = TRUE; info->trust = CAPABILITY_BUNDLE_ENOUGH_TRUST; - tp_intset_add (info->guys, cache->priv->conn->parent.self_handle); + tp_intset_add (info->guys, tp_base_connection_get_self_handle (base_conn)); replace_data_forms (info, data_forms); @@ -2440,7 +2467,7 @@ gabble_presence_cache_is_unsure (GabblePresenceCache *cache, * Presences with keep_unavailable are the result of caching someone's * nick from <message> stanzas, so they don't count as real presence - if * someone sends us a <message>, their presence might still follow. */ - if (base_conn->status != TP_CONNECTION_STATUS_CONNECTED || + if (tp_base_connection_get_status (base_conn) != TP_CONNECTION_STATUS_CONNECTED || priv->unsure_id != 0) { GabblePresence *presence = gabble_presence_cache_get (cache, handle); diff --git a/src/presence-cache.h b/src/presence-cache.h index 8c765517f..55023447f 100644 --- a/src/presence-cache.h +++ b/src/presence-cache.h @@ -68,7 +68,7 @@ struct _GabbleCapabilityInfo /* array of WockyDataForm or NULL */ GPtrArray *data_forms; - TpIntSet *guys; + TpIntset *guys; guint trust; /* bitfield of GabbleClientType flags */ diff --git a/src/presence.c b/src/presence.c index 704834ca2..db9830c6e 100644 --- a/src/presence.c +++ b/src/presence.c @@ -22,7 +22,7 @@ #include "presence.h" #include <string.h> -#include <telepathy-glib/channel-manager.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #include "gabble/capabilities.h" diff --git a/src/private-tubes-factory.c b/src/private-tubes-factory.c index ea418f262..48b421165 100644 --- a/src/private-tubes-factory.c +++ b/src/private-tubes-factory.c @@ -25,17 +25,15 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/util.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "extensions/extensions.h" #define DEBUG_FLAG GABBLE_DEBUG_TUBES +#include "bytestream-factory.h" #include "gabble/caps-channel-manager.h" #include "connection.h" #include "debug.h" @@ -43,18 +41,18 @@ #include "muc-factory.h" #include "namespaces.h" #include "presence-cache.h" -#include "tubes-channel.h" #include "tube-dbus.h" #include "tube-stream.h" #include "util.h" -static GabbleTubesChannel *new_tubes_channel (GabblePrivateTubesFactory *fac, - TpHandle handle, TpHandle initiator, gpointer request_token, - gboolean send_new_channel_signal); +static GabbleTubeIface * new_channel_from_stanza (GabblePrivateTubesFactory *self, + WockyStanza *stanza, WockyNode *tube_node, guint64 tube_id, + GabbleBytestreamIface *bytestream); -static void tubes_channel_closed_cb (GabbleTubesChannel *chan, +static gboolean private_tubes_factory_tube_close_cb ( + WockyPorter *porter, + WockyStanza *msg, gpointer user_data); - static gboolean private_tubes_factory_msg_tube_cb ( WockyPorter *porter, WockyStanza *msg, @@ -85,7 +83,8 @@ struct _GabblePrivateTubesFactoryPrivate guint msg_tube_cb; guint msg_close_cb; - GHashTable *tubes_channels; + /* guint tube ID => (owned) (GabbleTubeIface *) */ + GHashTable *tubes; gboolean dispose_has_run; }; @@ -104,6 +103,97 @@ static const gchar * const old_tubes_channel_allowed_properties[] = { NULL }; +gboolean +gabble_private_tubes_factory_extract_tube_information ( + TpHandleRepoIface *contact_repo, + WockyNode *tube_node, + TpTubeType *type, + TpHandle *initiator_handle, + const gchar **service, + GHashTable **parameters, + guint64 *tube_id) +{ + if (type != NULL) + { + const gchar *_type; + + _type = wocky_node_get_attribute (tube_node, "type"); + + if (!tp_strdiff (_type, "stream")) + { + *type = TP_TUBE_TYPE_STREAM; + } + else if (!tp_strdiff (_type, "dbus")) + { + *type = TP_TUBE_TYPE_DBUS; + } + else + { + DEBUG ("Unknown tube type: %s", _type); + return FALSE; + } + } + + if (initiator_handle != NULL) + { + const gchar *initiator; + + initiator = wocky_node_get_attribute (tube_node, "initiator"); + + if (initiator != NULL) + { + *initiator_handle = tp_handle_ensure (contact_repo, initiator, + GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL); + + if (*initiator_handle == 0) + { + DEBUG ("invalid initiator JID %s", initiator); + return FALSE; + } + } + else + { + *initiator_handle = 0; + } + } + + if (service != NULL) + { + *service = wocky_node_get_attribute (tube_node, "service"); + } + + if (parameters != NULL) + { + WockyNode *node; + + node = wocky_node_get_child (tube_node, "parameters"); + *parameters = lm_message_node_extract_properties (node, "parameter"); + } + + if (tube_id != NULL) + { + const gchar *str; + guint64 tmp; + + str = wocky_node_get_attribute (tube_node, "id"); + if (str == NULL) + { + DEBUG ("no tube id in SI request"); + return FALSE; + } + + tmp = g_ascii_strtoull (str, NULL, 10); + if (tmp == 0 || tmp > G_MAXUINT32) + { + DEBUG ("tube id is non-numeric or out of range: %s", str); + return FALSE; + } + *tube_id = tmp; + } + + return TRUE; +} + static void gabble_private_tubes_factory_init (GabblePrivateTubesFactory *self) { @@ -112,8 +202,8 @@ gabble_private_tubes_factory_init (GabblePrivateTubesFactory *self) self->priv = priv; - priv->tubes_channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, g_object_unref); + priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify) g_object_unref); priv->conn = NULL; priv->dispose_has_run = FALSE; @@ -141,7 +231,7 @@ porter_available_cb ( priv->msg_close_cb = wocky_porter_register_handler_from_anyone (porter, WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, WOCKY_PORTER_HANDLER_PRIORITY_MAX, - private_tubes_factory_msg_tube_cb, self, + private_tubes_factory_tube_close_cb, self, '(', "close", ':', NS_TUBES, ')', NULL); } @@ -199,7 +289,7 @@ gabble_private_tubes_factory_dispose (GObject *object) priv->dispose_has_run = TRUE; gabble_private_tubes_factory_close_all (fac); - g_assert (priv->tubes_channels == NULL); + g_assert (priv->tubes == NULL); if (G_OBJECT_CLASS (gabble_private_tubes_factory_parent_class)->dispose) G_OBJECT_CLASS (gabble_private_tubes_factory_parent_class)->dispose ( @@ -275,99 +365,6 @@ gabble_private_tubes_factory_class_init ( } - -/** - * tubes_channel_closed_cb: - * - * Signal callback for when an Tubes channel is closed. Removes the references - * that PrivateTubesFactory holds to them. - */ -static void -tubes_channel_closed_cb (GabbleTubesChannel *chan, - gpointer user_data) -{ - GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (user_data); - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); - TpHandle contact_handle; - - if (priv->tubes_channels == NULL) - return; - - g_object_get (chan, "handle", &contact_handle, NULL); - - tp_channel_manager_emit_channel_closed_for_object (self, - TP_EXPORTABLE_CHANNEL (chan)); - - DEBUG ("removing tubes channel with handle %d", contact_handle); - - g_hash_table_remove (priv->tubes_channels, GUINT_TO_POINTER (contact_handle)); -} - -/** - * new_tubes_channel - * - * Creates the GabbleTubes object associated with the given parameters - */ -static GabbleTubesChannel * -new_tubes_channel (GabblePrivateTubesFactory *fac, - TpHandle handle, - TpHandle initiator, - gpointer request_token, - gboolean send_new_channel_signal) -{ - GabblePrivateTubesFactoryPrivate *priv; - TpBaseConnection *conn; - GabbleTubesChannel *chan; - char *object_path; - gboolean requested; - - g_assert (GABBLE_IS_PRIVATE_TUBES_FACTORY (fac)); - g_assert (handle != 0); - g_assert (initiator != 0); - - priv = GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (fac); - conn = (TpBaseConnection *) priv->conn; - - object_path = g_strdup_printf ("%s/SITubesChannel%u", conn->object_path, - handle); - - requested = (request_token != NULL); - - chan = g_object_new (GABBLE_TYPE_TUBES_CHANNEL, - "connection", priv->conn, - "object-path", object_path, - "handle", handle, - "handle-type", TP_HANDLE_TYPE_CONTACT, - "initiator-handle", initiator, - "requested", requested, - NULL); - - DEBUG ("object path %s", object_path); - - g_signal_connect (chan, "closed", G_CALLBACK (tubes_channel_closed_cb), fac); - - g_hash_table_insert (priv->tubes_channels, GUINT_TO_POINTER (handle), chan); - - g_free (object_path); - - if (send_new_channel_signal) - { - GSList *request_tokens; - if (request_token != NULL) - request_tokens = g_slist_prepend (NULL, request_token); - else - request_tokens = NULL; - - tp_channel_manager_emit_new_channel (fac, - TP_EXPORTABLE_CHANNEL (chan), request_tokens); - - g_slist_free (request_tokens); - } - - return chan; -} - static void gabble_private_tubes_factory_close_all (GabblePrivateTubesFactory *fac) { @@ -393,10 +390,7 @@ gabble_private_tubes_factory_close_all (GabblePrivateTubesFactory *fac) priv->msg_close_cb = 0; } - /* Use a temporary variable (the macro does this) because we don't want - * tubes_channel_closed_cb to remove the channel from the hash table a - * second time */ - tp_clear_pointer (&priv->tubes_channels, g_hash_table_unref); + tp_clear_pointer (&priv->tubes, g_hash_table_unref); } static void @@ -567,9 +561,11 @@ gabble_private_tubes_factory_get_contact_caps ( { GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (manager); GetContactCapsClosure closure = { FALSE, arr, handle }; + TpBaseConnection *base_conn = TP_BASE_CONNECTION (self->priv->conn); /* Always claim that we support tubes. */ - closure.supports_tubes = (handle == self->priv->conn->parent.self_handle); + closure.supports_tubes = (handle == + tp_base_connection_get_self_handle (base_conn)); gabble_capability_set_foreach (caps, get_contact_caps_foreach, &closure); @@ -658,16 +654,10 @@ _foreach_slave (gpointer key, gpointer value, gpointer user_data) { - struct _ForeachData *data = (struct _ForeachData *) user_data; + struct _ForeachData *data = user_data; TpExportableChannel *chan = TP_EXPORTABLE_CHANNEL (value); - /* Add channels of type Channel.Type.Tubes */ data->foreach (chan, data->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), data->foreach, - data->user_data); } static void @@ -683,7 +673,7 @@ gabble_private_tubes_factory_foreach_channel (TpChannelManager *manager, data.user_data = user_data; data.foreach = foreach; - g_hash_table_foreach (priv->tubes_channels, _foreach_slave, &data); + g_hash_table_foreach (priv->tubes, _foreach_slave, &data); } void @@ -694,25 +684,54 @@ gabble_private_tubes_factory_handle_si_tube_request ( const gchar *stream_id, WockyStanza *msg) { - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + GabblePrivateTubesFactoryPrivate *priv = self->priv; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - GabbleTubesChannel *chan; + WockyNode *si_node, *tube_node; + WockyStanzaType stanza_type; + WockyStanzaSubType sub_type; + guint64 tube_id; + GabbleTubeIface *tube; DEBUG ("contact#%u stream %s", handle, stream_id); g_return_if_fail (tp_handle_is_valid (contact_repo, handle, NULL)); - chan = g_hash_table_lookup (priv->tubes_channels, GUINT_TO_POINTER (handle)); - if (chan == NULL) + wocky_stanza_get_type_info (msg, &stanza_type, &sub_type); + g_return_if_fail (stanza_type == WOCKY_STANZA_TYPE_IQ); + g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); + si_node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (msg), "si", NS_SI); + g_return_if_fail (si_node != NULL); + tube_node = wocky_node_get_child_ns (si_node, "tube", + NS_TUBES); + g_return_if_fail (tube_node != NULL); + + if (!gabble_private_tubes_factory_extract_tube_information ( + contact_repo, tube_node, NULL, NULL, + NULL, NULL, &tube_id)) { - chan = new_tubes_channel (self, handle, handle, NULL, TRUE); + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<tube> has no id attribute" }; - /* FIXME: Should we close the channel if the request is not properly - * handled by the newly created channel ? */ + NODE_DEBUG (tube_node, e.message); + gabble_bytestream_iface_close (bytestream, &e); + return; } - gabble_tubes_channel_tube_si_offered (chan, bytestream, msg); + tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + if (tube != NULL) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "tube ID already in use" }; + + NODE_DEBUG (tube_node, e.message); + gabble_bytestream_iface_close (bytestream, &e); + return; + } + + /* New tube */ + tube = new_channel_from_stanza (self, msg, tube_node, + tube_id, bytestream); } void @@ -726,48 +745,82 @@ gabble_private_tubes_factory_handle_si_stream_request ( GabblePrivateTubesFactoryPrivate *priv = GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - GabbleTubesChannel *chan; + (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + const gchar *tmp; + guint64 tube_id; + WockyNode *si_node, *stream_node; + GabbleTubeIface *tube; + WockyStanzaType stanza_type; + WockyStanzaSubType sub_type; DEBUG ("contact#%u stream %s", handle, stream_id); g_return_if_fail (tp_handle_is_valid (contact_repo, handle, NULL)); - chan = g_hash_table_lookup (priv->tubes_channels, GUINT_TO_POINTER (handle)); - if (chan == NULL) + wocky_stanza_get_type_info (msg, &stanza_type, &sub_type); + g_return_if_fail (stanza_type == WOCKY_STANZA_TYPE_IQ); + g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); + + si_node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (msg), "si", NS_SI); + g_return_if_fail (si_node != NULL); + + stream_node = wocky_node_get_child_ns (si_node, + "stream", NS_TUBES); + g_return_if_fail (stream_node != NULL); + + tmp = wocky_node_get_attribute (stream_node, "tube"); + if (tmp == NULL) { GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "No tubes channel available for this contact" }; + "<stream> has no tube attribute" }; - DEBUG ("tubes channel with contact %d doesn't exist", handle); + NODE_DEBUG (stream_node, e.message); gabble_bytestream_iface_close (bytestream, &e); return; } + tube_id = g_ascii_strtoull (tmp, NULL, 10); + if (tube_id == 0 || tube_id > G_MAXUINT32) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<stream> tube ID attribute non-numeric or out of range" }; - gabble_tubes_channel_bytestream_offered (chan, bytestream, msg); + DEBUG ("tube id is non-numeric or out of range: %s", tmp); + gabble_bytestream_iface_close (bytestream, &e); + return; + } + + tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + if (tube == NULL) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, + "<stream> tube attribute points to a nonexistent " + "tube" }; + + DEBUG ("tube %" G_GUINT64_FORMAT " doesn't exist", tube_id); + gabble_bytestream_iface_close (bytestream, &e); + return; + } + + DEBUG ("received new bytestream request for existing tube: %" G_GUINT64_FORMAT, + tube_id); + + gabble_tube_iface_add_bytestream (tube, bytestream); } static gboolean -private_tubes_factory_msg_tube_cb ( - WockyPorter *porter, +tube_msg_checks (GabblePrivateTubesFactory *self, WockyStanza *msg, - gpointer user_data) + WockyNode *node, + TpHandle *out_handle, + guint64 *out_tube_id) { - GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (user_data); GabblePrivateTubesFactoryPrivate *priv = GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - WockyNode *tube_node, *close_node; - GabbleTubesChannel *chan; - const gchar *from; + const gchar *from, *tmp; TpHandle handle; - - tube_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (msg), "tube", NS_TUBES); - close_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (msg), "close", NS_TUBES); - - g_return_val_if_fail (tube_node != NULL || close_node != NULL, FALSE); + guint64 tube_id; from = wocky_node_get_attribute ( wocky_stanza_get_top_node (msg), "from"); @@ -784,30 +837,396 @@ private_tubes_factory_msg_tube_cb ( return FALSE; } - /* Tube offer */ - chan = g_hash_table_lookup (priv->tubes_channels, GUINT_TO_POINTER (handle)); + tmp = wocky_node_get_attribute (node, "id"); + if (tmp == NULL) + { + DEBUG ("failed to get the tube ID"); + return FALSE; + } - if (chan == NULL) + tube_id = g_ascii_strtoull (tmp, NULL, 10); + if (tube_id == 0 || tube_id > G_MAXUINT32) { - if (tube_node != NULL) - { - /* We create the tubes channel only if the message is a new tube - * offer */ - chan = new_tubes_channel (self, handle, handle, NULL, TRUE); - } - else - { - DEBUG ("Ignore tube close message as there is no tubes channel" - " to handle it"); - return TRUE; - } + DEBUG ("tube ID is non-numeric or out of range: %s", tmp); + return FALSE; } - gabble_tubes_channel_tube_msg (chan, msg); + if (out_tube_id != NULL) + *out_tube_id = tube_id; + + if (out_handle != NULL) + *out_handle = handle; return TRUE; } +static gboolean +private_tubes_factory_msg_tube_cb ( + WockyPorter *porter, + WockyStanza *msg, + gpointer user_data) +{ + GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (user_data); + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + WockyNode *node; + guint64 tube_id; + GabbleTubeIface *channel; + TpHandle handle; + + node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (msg), "tube", NS_TUBES); + g_return_val_if_fail (node != NULL, FALSE); + + if (!tube_msg_checks (self, msg, node, &handle, &tube_id)) + return FALSE; + + channel = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + + if (channel != NULL) + { + TpHandle tube_handle = 0; + + g_object_get (channel, + "handle", &tube_handle, + NULL); + + DEBUG ("tube ID already in use; do not open the offered tube and close " + "the existing tube if it's to the same contact"); + + /* only close the existing channel if it's the same contact + * otherwise contacts could force close unrelated tubes. */ + if (handle == tube_handle) + gabble_tube_iface_close (channel, FALSE); + + return TRUE; + } + + channel = new_channel_from_stanza (self, msg, node, tube_id, NULL); + + return TRUE; +} + +static gboolean +private_tubes_factory_tube_close_cb ( + WockyPorter *porter, + WockyStanza *msg, + gpointer user_data) +{ + GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (user_data); + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + WockyNode *node; + guint64 tube_id; + GabbleTubeIface *channel; + TpTubeType type; + + node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (msg), "close", NS_TUBES); + g_return_val_if_fail (node != NULL, FALSE); + + if (!tube_msg_checks (self, msg, node, NULL, &tube_id)) + return FALSE; + + channel = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + + if (channel == NULL) + { + DEBUG ("<close> tube attribute points to a nonexistent tube"); + return TRUE; + } + + g_object_get (channel, "type", &type, NULL); + if (type != TP_TUBE_TYPE_STREAM) + { + DEBUG ("Only stream tubes can be closed using a close message"); + return TRUE; + } + + DEBUG ("tube %" G_GUINT64_FORMAT " was closed by remote peer", tube_id); + gabble_tube_iface_close (channel, TRUE); + + return TRUE; +} + +static GabbleTubeIface * +gabble_private_tubes_factory_lookup (GabblePrivateTubesFactory *self, + const gchar *type, + TpHandle handle, + const gchar *service) +{ + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, priv->tubes); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + GabbleTubeIface *tube = value; + gboolean match = FALSE; + + gchar *channel_type, *channel_service; + TpHandle channel_handle; + + g_object_get (tube, + "channel-type", &channel_type, + "handle", &channel_handle, + "service", &channel_service, + NULL); + + if (!tp_strdiff (type, channel_type) + && handle == channel_handle + && !tp_strdiff (service, channel_service)) + match = TRUE; + + g_free (channel_type); + g_free (channel_service); + + if (match) + return tube; + } + + return NULL; +} + +static void +channel_closed_cb (GabbleTubeIface *tube, + GabblePrivateTubesFactory *self) +{ + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + guint id; + + g_object_get (tube, + "id", &id, + NULL); + + tp_channel_manager_emit_channel_closed_for_object (self, + TP_EXPORTABLE_CHANNEL (tube)); + + if (priv->tubes != NULL) + g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (id)); +} + +static guint64 +generate_tube_id (GabblePrivateTubesFactory *self) +{ + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + guint out; + + /* probably totally overkill */ + do + { + out = g_random_int_range (1, G_MAXINT32); + } + while (g_hash_table_lookup (priv->tubes, + GUINT_TO_POINTER (out)) != NULL); + + return out; +} + +/* Returns: (transfer none): new tube channel. the channel manager holds + * the ref to this channel, so don't unref it! */ +static GabbleTubeIface * +new_channel_from_request (GabblePrivateTubesFactory *self, + GHashTable *request) +{ + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + GabbleTubeIface *tube; + TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); + + gchar *stream_id; + + TpHandle handle; + const gchar *ctype, *service; + TpHandleType handle_type; + GHashTable *parameters; + guint64 tube_id; + + ctype = tp_asv_get_string (request, TP_PROP_CHANNEL_CHANNEL_TYPE); + handle = tp_asv_get_uint32 (request, TP_PROP_CHANNEL_TARGET_HANDLE, + NULL); + handle_type = tp_asv_get_uint32 (request, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL); + + tube_id = generate_tube_id (self); + + /* requested tubes have an empty parameters dict */ + parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) tp_g_value_slice_free); + + if (!tp_strdiff (ctype, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) + { + service = tp_asv_get_string (request, + TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); + + tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (priv->conn, + handle, handle_type, + tp_base_connection_get_self_handle (base_conn), + tp_base_connection_get_self_handle (base_conn), + service, parameters, tube_id, NULL, TRUE)); + } + else if (!tp_strdiff (ctype, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) + { + service = tp_asv_get_string (request, + TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); + + stream_id = gabble_bytestream_factory_generate_stream_id (); + + tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (priv->conn, + handle, handle_type, + tp_base_connection_get_self_handle (base_conn), + tp_base_connection_get_self_handle (base_conn), + service, parameters, stream_id, tube_id, NULL, NULL, TRUE)); + + g_free (stream_id); + } + else + { + g_return_val_if_reached (NULL); + } + + tp_base_channel_register ((TpBaseChannel *) tube); + + g_signal_connect (tube, "closed", + G_CALLBACK (channel_closed_cb), self); + + g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), + tube); + + g_hash_table_unref (parameters); + + return tube; +} + +static void +send_tube_close_msg (GabblePrivateTubesFactory *self, + const gchar *jid, + guint64 tube_id) +{ + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + WockyPorter *porter; + WockyStanza *msg; + gchar *id_str; + + id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, tube_id); + + porter = gabble_connection_dup_porter (priv->conn); + + /* Send the close message */ + msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, + NULL, jid, + '(', "close", + ':', NS_TUBES, + '@', "tube", id_str, + ')', + GABBLE_AMP_DO_NOT_STORE_SPEC, + NULL); + g_free (id_str); + + wocky_porter_send (porter, msg); + + g_object_unref (porter); + g_object_unref (msg); +} + +/* Returns: (transfer none): new tube channel. the channel manager holds + * the ref to this channel, so don't unref it! */ +static GabbleTubeIface * +new_channel_from_stanza (GabblePrivateTubesFactory *self, + WockyStanza *stanza, + WockyNode *tube_node, + guint64 tube_id, + GabbleBytestreamIface *bytestream) +{ + GabblePrivateTubesFactoryPrivate *priv = + GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); + GabbleTubeIface *tube; + TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( + (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + + TpTubeType type; + TpHandle handle; + const gchar *service; + GHashTable *parameters; + + /* the validity of this has already been checked by wocky */ + handle = tp_handle_ensure (contact_repo, + wocky_stanza_get_from (stanza), NULL, NULL); + g_return_val_if_fail (handle != 0, NULL); + + if (!gabble_private_tubes_factory_extract_tube_information ( + contact_repo, tube_node, &type, NULL, + &service, ¶meters, NULL)) + { + DEBUG ("can't extract <tube> information from message"); + send_tube_close_msg (self, wocky_stanza_get_from (stanza), tube_id); + return NULL; + } + + if (bytestream == NULL && type != TP_TUBE_TYPE_STREAM) + { + DEBUG ("Only stream tubes are allowed to be created using messages"); + send_tube_close_msg (self, wocky_stanza_get_from (stanza), tube_id); + return NULL; + } + else if (bytestream != NULL && type != TP_TUBE_TYPE_DBUS) + { + GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_FORBIDDEN, + "Only D-Bus tubes are allowed to be created using SI" }; + + DEBUG ("%s", e.message); + gabble_bytestream_iface_close (bytestream, &e); + return NULL; + } + + if (type == TP_TUBE_TYPE_STREAM) + { + tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (priv->conn, + handle, TP_HANDLE_TYPE_CONTACT, + tp_base_connection_get_self_handle (base_conn), + handle, service, parameters, tube_id, NULL, FALSE)); + } + else + { + WockyNode *si_node; + const gchar *stream_id; + + si_node = wocky_node_get_child_ns ( + wocky_stanza_get_top_node (stanza), "si", NS_SI); + g_return_val_if_fail (si_node != NULL, NULL); + + stream_id = wocky_node_get_attribute (si_node, "id"); + g_return_val_if_fail (stream_id != NULL, NULL); + + tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (priv->conn, + handle, TP_HANDLE_TYPE_CONTACT, + tp_base_connection_get_self_handle (base_conn), + handle, service, parameters, + stream_id, tube_id, bytestream, NULL, FALSE)); + } + + tp_base_channel_register ((TpBaseChannel *) tube); + + g_signal_connect (tube, "closed", + G_CALLBACK (channel_closed_cb), self); + + g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), + tube); + + g_hash_table_unref (parameters); + + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (tube), NULL); + + return tube; +} + GabblePrivateTubesFactory * gabble_private_tubes_factory_new (GabbleConnection *conn) { @@ -827,24 +1246,6 @@ gabble_private_tubes_factory_type_foreach_channel_class (GType type, GHashTable *table; GValue *value; - /* 1-1 Channel.Type.Tubes */ - table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, - (GDestroyNotify) tp_g_value_slice_free); - - value = tp_g_value_slice_new (G_TYPE_STRING); - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TUBES); - g_hash_table_insert (table, TP_PROP_CHANNEL_CHANNEL_TYPE, - value); - - value = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); - g_hash_table_insert (table, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, - value); - - func (type, table, old_tubes_channel_allowed_properties, user_data); - - g_hash_table_unref (table); - /* 1-1 Channel.Type.StreamTube */ table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free); @@ -895,7 +1296,8 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, TpHandle handle; GError *error = NULL; const gchar *channel_type; - GabbleTubesChannel *channel; + GabbleTubeIface *channel; + const gchar *service = NULL; if (tp_asv_get_uint32 (request_properties, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL) != TP_HANDLE_TYPE_CONTACT) @@ -904,25 +1306,14 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, channel_type = tp_asv_get_string (request_properties, TP_PROP_CHANNEL_CHANNEL_TYPE); - if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES) && - tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) && + if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE) && tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) return FALSE; - if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) + if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) { if (tp_channel_manager_asv_has_unknown_properties (request_properties, tubes_channel_fixed_properties, - old_tubes_channel_allowed_properties, - &error)) - goto error; - } - else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) - { - const gchar *service; - - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - tubes_channel_fixed_properties, gabble_tube_stream_channel_get_allowed_properties (), &error)) goto error; @@ -932,7 +1323,7 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); if (service == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Request does not contain the mandatory property '%s'", TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); goto error; @@ -940,7 +1331,6 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, } else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) { - const gchar *service; GError *err = NULL; if (tp_channel_manager_asv_has_unknown_properties (request_properties, @@ -954,7 +1344,7 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); if (service == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Request does not contain the mandatory property '%s'", TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); goto error; @@ -963,7 +1353,7 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, if (!tp_dbus_check_valid_bus_name (service, TP_DBUS_NAME_TYPE_WELL_KNOWN, &err)) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Invalid ServiceName: %s", err->message); g_error_free (err); goto error; @@ -976,83 +1366,45 @@ gabble_private_tubes_factory_requestotron (GabblePrivateTubesFactory *self, g_assert (handle != 0); /* Don't support opening a channel to our self handle */ - if (handle == base_conn->self_handle) + if (handle == tp_base_connection_get_self_handle (base_conn)) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Can't open a channel to your self handle"); goto error; } - channel = g_hash_table_lookup (self->priv->tubes_channels, - GUINT_TO_POINTER (handle)); + channel = gabble_private_tubes_factory_lookup (self, channel_type, + handle, service); - if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TUBES)) + if (channel == NULL) { - if (channel == NULL) - { - new_tubes_channel (self, handle, base_conn->self_handle, - request_token, TRUE); - return TRUE; - } + GSList *request_tokens = NULL; + + channel = new_channel_from_request (self, request_properties); + if (request_token != NULL) + request_tokens = g_slist_prepend (NULL, request_token); + + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (channel), request_tokens); + + g_slist_free (request_tokens); + } + else + { if (require_new) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Tubes channel with contact #%u already exists", handle); - DEBUG ("Tubes channel with contact #%u already exists", - handle); + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, + "A channel to #%u (service: %s) is already open", + handle, service); goto error; } tp_channel_manager_emit_request_already_satisfied (self, request_token, TP_EXPORTABLE_CHANNEL (channel)); - return TRUE; } - else - { - gboolean tubes_channel_already_existed = (channel != NULL); - GabbleTubeIface *new_channel; - - if (channel == NULL) - { - /* Don't give the request_token to new_tubes_channel() because we - * must emit NewChannels with 2 channels together */ - channel = new_tubes_channel (self, handle, base_conn->self_handle, - NULL, FALSE); - } - g_assert (channel != NULL); - - new_channel = gabble_tubes_channel_tube_request (channel, request_token, - request_properties, require_new); - if (new_channel != NULL) - { - GHashTable *channels; - GSList *request_tokens; - channels = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, NULL); - if (!tubes_channel_already_existed) - g_hash_table_insert (channels, channel, NULL); - - if (request_token != NULL) - request_tokens = g_slist_prepend (NULL, request_token); - else - request_tokens = NULL; - - g_hash_table_insert (channels, new_channel, request_tokens); - tp_channel_manager_emit_new_channels (self, channels); - - g_hash_table_unref (channels); - g_slist_free (request_tokens); - } - else - { - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (channel)); - } - - return TRUE; - } + return TRUE; error: tp_channel_manager_emit_request_failed (self, request_token, diff --git a/src/private-tubes-factory.h b/src/private-tubes-factory.h index d9895199d..d9e01f17a 100644 --- a/src/private-tubes-factory.h +++ b/src/private-tubes-factory.h @@ -22,10 +22,10 @@ #include <glib-object.h> -#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/telepathy-glib.h> + #include "connection.h" #include "bytestream-iface.h" -#include "tubes-channel.h" G_BEGIN_DECLS @@ -75,6 +75,12 @@ void gabble_private_tubes_factory_handle_si_stream_request ( GabblePrivateTubesFactory *fac, GabbleBytestreamIface *bytestream, TpHandle handle, const gchar *stream_id, WockyStanza *msg); +gboolean gabble_private_tubes_factory_extract_tube_information ( + TpHandleRepoIface *contact_repo, WockyNode *tube_node, + TpTubeType *type, TpHandle *initiator_handle, + const gchar **service, GHashTable **parameters, + guint64 *tube_id); + G_END_DECLS #endif /* #ifndef __PRIVATE_TUBES_FACTORY_H__ */ diff --git a/src/protocol.c b/src/protocol.c index a8bceb2ff..deeaa8d9e 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -18,11 +18,13 @@ */ #include "config.h" + #include "protocol.h" #include <string.h> -#include <telepathy-glib/base-connection-manager.h> -#include <telepathy-glib/interfaces.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <dbus/dbus-protocol.h> #include <dbus/dbus-glib.h> @@ -318,15 +320,18 @@ identify_account (TpBaseProtocol *self G_GNUC_UNUSED, return g_strdup (account); } -static GStrv -get_interfaces (TpBaseProtocol *self) +static GPtrArray * +get_interfaces_array (TpBaseProtocol *self) { - const gchar * const interfaces[] = { - TP_IFACE_PROTOCOL_INTERFACE_PRESENCE, - TP_IFACE_PROTOCOL_INTERFACE_ADDRESSING, - NULL }; + GPtrArray *interfaces; + + interfaces = TP_BASE_PROTOCOL_CLASS ( + gabble_jabber_protocol_parent_class)->get_interfaces_array (self); + + g_ptr_array_add (interfaces, TP_IFACE_PROTOCOL_INTERFACE_PRESENCE); + g_ptr_array_add (interfaces, TP_IFACE_PROTOCOL_INTERFACE_ADDRESSING); - return g_strdupv ((GStrv) interfaces); + return interfaces; } static const TpPresenceStatusSpec * @@ -458,7 +463,7 @@ gabble_jabber_protocol_class_init (GabbleJabberProtocolClass *klass) base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; base_class->identify_account = identify_account; - base_class->get_interfaces = get_interfaces; + base_class->get_interfaces_array = get_interfaces_array; base_class->get_connection_details = get_connection_details; base_class->get_statuses = get_presence_statuses; base_class->dup_authentication_types = dup_authentication_types; diff --git a/src/protocol.h b/src/protocol.h index 30809df47..c013d9913 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -21,7 +21,7 @@ #define JABBER_PROTOCOL_H #include <glib-object.h> -#include <telepathy-glib/base-protocol.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/request-pipeline.c b/src/request-pipeline.c index 1bbfe4aa4..7b4eb5cc0 100644 --- a/src/request-pipeline.c +++ b/src/request-pipeline.c @@ -21,7 +21,7 @@ #include "config.h" #include "request-pipeline.h" -#include <telepathy-glib/dbus.h> +#include <telepathy-glib/telepathy-glib.h> #define DEBUG_FLAG GABBLE_DEBUG_PIPELINE @@ -245,7 +245,7 @@ gabble_request_pipeline_flush (GabbleRequestPipeline *self, GSList **list) { GabbleRequestPipelineItem *item; - GError disconnected = { TP_ERRORS, TP_ERROR_DISCONNECTED, + GError disconnected = { TP_ERROR, TP_ERROR_DISCONNECTED, "Request failed because connection became disconnected" }; while (*list != NULL) diff --git a/src/room-config.c b/src/room-config.c index 47489058f..199545ad5 100644 --- a/src/room-config.c +++ b/src/room-config.c @@ -18,6 +18,7 @@ */ #include "config.h" + #include "room-config.h" #include "muc-channel.h" diff --git a/src/room-config.h b/src/room-config.h index a2981c186..ce5247201 100644 --- a/src/room-config.h +++ b/src/room-config.h @@ -21,7 +21,7 @@ #define GABBLE_ROOM_CONFIG_H #include <glib-object.h> -#include <telepathy-glib/base-room-config.h> +#include <telepathy-glib/telepathy-glib.h> typedef struct _GabbleRoomConfig GabbleRoomConfig; typedef struct _GabbleRoomConfigClass GabbleRoomConfigClass; diff --git a/src/roomlist-channel.c b/src/roomlist-channel.c index 642c983d1..070cf5ee3 100644 --- a/src/roomlist-channel.c +++ b/src/roomlist-channel.c @@ -24,14 +24,9 @@ #include <string.h> #include <dbus/dbus-glib.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_ROOMLIST @@ -49,10 +44,6 @@ G_DEFINE_TYPE_WITH_CODE (GabbleRoomlistChannel, gabble_roomlist_channel, roomlist_iface_init); ); -static const gchar *gabble_roomlist_channel_interfaces[] = { - NULL -}; - /* properties */ enum { @@ -192,7 +183,6 @@ gabble_roomlist_channel_class_init (GabbleRoomlistChannelClass *klass) object_class->finalize = gabble_roomlist_channel_finalize; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_ROOM_LIST; - base_class->interfaces = gabble_roomlist_channel_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_NONE; base_class->get_object_path_suffix = gabble_roomlist_channel_get_object_path_suffix; @@ -415,7 +405,6 @@ room_info_cb (gpointer pipeline, GabbleDiscoItem *item, gpointer user_data) /* transfer the room handle ref to signalled_rooms */ tp_handle_set_add (priv->signalled_rooms, handle); - tp_handle_unref (room_handles, handle); g_value_init (&room, room_info_type); g_value_take_boxed (&room, diff --git a/src/roomlist-channel.h b/src/roomlist-channel.h index e86d6b028..5c74f3485 100644 --- a/src/roomlist-channel.h +++ b/src/roomlist-channel.h @@ -23,7 +23,7 @@ #include <glib-object.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> #include "connection.h" diff --git a/src/roomlist-manager.c b/src/roomlist-manager.c index 6f8d499ea..ff2f37fef 100644 --- a/src/roomlist-manager.c +++ b/src/roomlist-manager.c @@ -25,10 +25,9 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/util.h> + +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_MUC @@ -329,7 +328,7 @@ gabble_roomlist_manager_handle_request (TpChannelManager *manager, if (tp_asv_get_uint32 (request_properties, TP_IFACE_CHANNEL ".TargetHandleType", NULL) != 0) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "RoomList channels can't have a target handle"); goto error; } @@ -349,7 +348,7 @@ gabble_roomlist_manager_handle_request (TpChannelManager *manager, if (server == NULL) { - g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Unable to choose a default conference server"); goto error; } diff --git a/src/roster.c b/src/roster.c index 7bd6758f4..d2cc4dae8 100644 --- a/src/roster.c +++ b/src/roster.c @@ -25,9 +25,8 @@ #include <string.h> #include <dbus/dbus-glib.h> -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_ROSTER @@ -214,17 +213,6 @@ gabble_roster_dispose (GObject *object) } static void -item_handle_unref_foreach (gpointer key, gpointer data, gpointer user_data) -{ - TpHandle handle = GPOINTER_TO_UINT (key); - GabbleRosterPrivate *priv = (GabbleRosterPrivate *) user_data; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - - tp_handle_unref (contact_repo, handle); -} - -static void gabble_roster_finalize (GObject *object) { GabbleRoster *self = GABBLE_ROSTER (object); @@ -232,7 +220,6 @@ gabble_roster_finalize (GObject *object) DEBUG ("called with %p", object); - g_hash_table_foreach (priv->items, item_handle_unref_foreach, priv); g_hash_table_unref (priv->items); G_OBJECT_CLASS (gabble_roster_parent_class)->finalize (object); @@ -323,7 +310,6 @@ _parse_item_groups (WockyNode *item_node, TpBaseConnection *conn) if (!handle) continue; tp_handle_set_add (groups, handle); - tp_handle_unref (group_repo, handle); } return groups; @@ -459,7 +445,6 @@ _gabble_roster_item_ensure (GabbleRoster *roster, item->publish = TP_SUBSCRIPTION_STATE_NO; item->name = alias; item->groups = tp_handle_set_new (group_repo); - tp_handle_ref (contact_repo, handle); g_hash_table_insert (priv->items, GUINT_TO_POINTER (handle), item); } @@ -512,7 +497,6 @@ _gabble_roster_item_maybe_remove (GabbleRoster *roster, DEBUG ("removing contact#%u", handle); item = NULL; g_hash_table_remove (priv->items, GUINT_TO_POINTER (handle)); - tp_handle_unref (contact_repo, handle); return TRUE; } @@ -526,7 +510,7 @@ _gabble_roster_item_update (GabbleRoster *roster, GabbleRosterPrivate *priv = roster->priv; GabbleRosterItem *item; const gchar *ask, *name; - TpIntSet *new_groups, *added_to, *removed_from, *removed_from2; + TpIntset *new_groups, *added_to, *removed_from, *removed_from2; TpHandleSet *new_groups_handle_set, *old_groups; TpBaseContactList *base = (TpBaseContactList *) roster; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( @@ -588,7 +572,7 @@ _gabble_roster_item_update (GabbleRoster *roster, if (roster->priv->groups != NULL) { - TpIntSet *created_groups = tp_handle_set_update (roster->priv->groups, + TpIntset *created_groups = tp_handle_set_update (roster->priv->groups, new_groups); /* we don't need to do this work if TpBaseContactList will just be @@ -599,7 +583,7 @@ _gabble_roster_item_update (GabbleRoster *roster, { GPtrArray *strv = g_ptr_array_sized_new (tp_intset_size ( created_groups)); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle group; tp_intset_fast_iter_init (&iter, created_groups); @@ -636,7 +620,7 @@ _gabble_roster_item_update (GabbleRoster *roster, GPtrArray *removed_names = g_ptr_array_sized_new ( tp_intset_size (removed_from)); TpHandleSet *the_contact = tp_handle_set_new (contact_repo); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle group; tp_handle_set_add (the_contact, contact_handle); @@ -1113,7 +1097,6 @@ process_roster ( /* transfer ownership of the reference to referenced_handles */ tp_handle_set_add (referenced_handles, handle); - tp_handle_unref (contact_repo, handle); item = _gabble_roster_item_update (roster, handle, item_node, google_roster, &nickname_updated); @@ -1547,12 +1530,11 @@ gabble_roster_presence_cb (WockyPorter *porter, return FALSE; } - if (handle == conn->self_handle) + if (handle == tp_base_connection_get_self_handle (conn)) { NODE_DEBUG (pres_node, "ignoring presence from ourselves on another " "resource"); - ret = FALSE; - goto OUT; + return FALSE; } g_assert (handle != 0); @@ -1679,8 +1661,6 @@ gabble_roster_presence_cb (WockyPorter *porter, ret = FALSE; } -OUT: - tp_handle_unref (contact_repo, handle); return ret; } @@ -1880,7 +1860,6 @@ item_edit_new (TpHandleRepoIface *contact_repo, { GabbleRosterItemEdit *self = g_slice_new0 (GabbleRosterItemEdit); - tp_handle_ref (contact_repo, handle); self->contact_repo = g_object_ref (contact_repo); self->handle = handle; self->new_subscription = GABBLE_ROSTER_SUBSCRIPTION_INVALID; @@ -1906,7 +1885,6 @@ item_edit_free (GabbleRosterItemEdit *edits) g_slist_free (edits->results); - tp_handle_unref (edits->contact_repo, edits->handle); g_object_unref (edits->contact_repo); tp_clear_pointer (&edits->add_to_groups, tp_handle_set_destroy); tp_clear_pointer (&edits->remove_from_groups, tp_handle_set_destroy); @@ -1969,7 +1947,7 @@ roster_item_apply_edits (GabbleRoster *roster, { gboolean altered = FALSE; GabbleRosterItem edited_item; - TpIntSet *intset; + TpIntset *intset; GabbleRosterPrivate *priv = roster->priv; TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_GROUP); @@ -2658,7 +2636,7 @@ gabble_roster_request_subscription_added_cb (GObject *source, (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); SubscribeContext *context = user_data; GError *error = NULL; - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; /* Now that we've added all the contacts, send off all the subscription @@ -2712,7 +2690,7 @@ gabble_roster_request_subscription_async (TpBaseContactList *base, GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, gabble_roster_request_subscription_added_cb, context, gabble_roster_request_subscription_async, 1); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; /* Before subscribing, add items to the roster @@ -2740,7 +2718,7 @@ gabble_roster_authorize_publication_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GError *error = NULL; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( @@ -2793,7 +2771,7 @@ gabble_roster_store_contacts_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_store_contacts_async, 1); @@ -2814,7 +2792,7 @@ gabble_roster_remove_contacts_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_request_subscription_async, 1); @@ -2839,7 +2817,7 @@ gabble_roster_unsubscribe_async (TpBaseContactList *base, (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpHandleSet *changed = tp_handle_set_new (contact_repo); TpHandleSet *removed = tp_handle_set_new (contact_repo); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GError *error = NULL; @@ -2900,7 +2878,7 @@ gabble_roster_unpublish_async (TpBaseContactList *base, (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); TpHandleSet *changed = tp_handle_set_new (contact_repo); TpHandleSet *removed = tp_handle_set_new (contact_repo); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GError *error = NULL; @@ -3041,7 +3019,7 @@ gabble_roster_block_contacts_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_request_subscription_async, 1); @@ -3062,7 +3040,7 @@ gabble_roster_unblock_contacts_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_request_subscription_async, 1); @@ -3086,7 +3064,7 @@ gabble_roster_dup_groups (TpBaseContactList *base) if (self->priv->groups != NULL) { - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle group; ret = g_ptr_array_sized_new ( @@ -3122,7 +3100,7 @@ gabble_roster_dup_contact_groups (TpBaseContactList *base, { TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle group; ret = g_ptr_array_sized_new (tp_handle_set_size (item->groups) + 1); @@ -3218,7 +3196,6 @@ gabble_roster_set_contact_groups_async (TpBaseContactList *base, g_ptr_array_add (groups_created, (gchar *) groups[i]); } - tp_handle_unref (group_repo, group_handle); } if (groups_created->len > 0) @@ -3273,7 +3250,7 @@ gabble_roster_set_group_members_async (TpBaseContactList *base, /* You can't add people to an invalid group. */ if (G_UNLIKELY (group_handle == 0)) { - g_simple_async_result_set_error (result, TP_ERRORS, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Invalid group name: %s", group); goto finally; } @@ -3300,8 +3277,6 @@ gabble_roster_set_group_members_async (TpBaseContactList *base, result); } - tp_handle_unref (group_repo, group_handle); - finally: gabble_simple_async_countdown_dec (result); g_object_unref (result); @@ -3315,7 +3290,7 @@ gabble_roster_add_to_group_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); @@ -3327,7 +3302,7 @@ gabble_roster_add_to_group_async (TpBaseContactList *base, /* You can't add people to an invalid group. */ if (G_UNLIKELY (group_handle == 0)) { - g_simple_async_result_set_error (result, TP_ERRORS, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Invalid group name: %s", group); goto finally; } @@ -3348,8 +3323,6 @@ gabble_roster_add_to_group_async (TpBaseContactList *base, gabble_roster_handle_add_to_group (self, contact, group_handle, result); } - tp_handle_unref (group_repo, group_handle); - finally: gabble_simple_async_countdown_dec (result); g_object_unref (result); @@ -3363,7 +3336,7 @@ gabble_roster_remove_from_group_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpIntSetFastIter iter; + TpIntsetFastIter iter; TpHandle contact; TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); @@ -3464,8 +3437,6 @@ gabble_roster_remove_group_removed_cb (GObject *source, DEBUG ("contact #%u is still a member of group '%s', not removing", remaining_member, group); } - - tp_handle_unref (group_repo, context->group_handle); } context->callback (source, result, context->user_data); @@ -3495,9 +3466,6 @@ gabble_roster_remove_group_async (TpBaseContactList *base, context->user_data = user_data; context->contacts = tp_handle_set_new (contact_repo); - if (context->group_handle != 0) - tp_handle_ref (group_repo, context->group_handle); - result = gabble_simple_async_countdown_new (self, gabble_roster_remove_group_removed_cb, context, gabble_roster_remove_group_async, 1); @@ -3633,6 +3601,9 @@ gabble_roster_handle_gets_presence_from_us (GabbleRoster *self, if (item == NULL) return FALSE; + if (item->blocked) + return FALSE; + return (item->subscription == GABBLE_ROSTER_SUBSCRIPTION_FROM || item->subscription == GABBLE_ROSTER_SUBSCRIPTION_BOTH); } diff --git a/src/roster.h b/src/roster.h index 185dde514..4cc2b0dcf 100644 --- a/src/roster.h +++ b/src/roster.h @@ -24,7 +24,7 @@ #include <glib-object.h> -#include <telepathy-glib/base-contact-list.h> +#include <telepathy-glib/telepathy-glib.h> #include "types.h" diff --git a/src/search-channel.c b/src/search-channel.c index afbb098ee..0c253ba92 100644 --- a/src/search-channel.c +++ b/src/search-channel.c @@ -23,11 +23,8 @@ #include <string.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -39,10 +36,6 @@ #include "namespaces.h" #include "util.h" -static const gchar *gabble_search_channel_interfaces[] = { - NULL -}; - /* properties */ enum { @@ -234,7 +227,7 @@ parse_unextended_field_response ( } else { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "server is broken: %s is not a field defined in XEP 0055", field->name); g_ptr_array_unref (search_keys); @@ -272,7 +265,7 @@ parse_data_form ( if (tp_strdiff (wocky_node_get_attribute (x_node, "type"), "form")) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "server is broken: <x> not type='form'"); goto fail; } @@ -308,7 +301,7 @@ parse_data_form ( if (tp_strdiff (form_type, NS_SEARCH)) { DEBUG ("<x> form does not have FORM_TYPE %s", NS_SEARCH); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "server is broken: form lacking FORM_TYPE %s", NS_SEARCH); goto fail; } @@ -416,7 +409,7 @@ query_reply_cb (GabbleConnection *conn, } else if (NULL == query_node) { - err = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + err = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "%s is broken: it replied to our <query> with an empty IQ", chan->priv->server); } @@ -461,7 +454,7 @@ request_search_fields (GabbleSearchChannel *chan) * change_search_state: * @chan: a search channel * @state: the new state for the channel - * @reason: an error in the TP_ERRORS domain if the search has failed; NULL + * @reason: an error in the TP_ERROR domain if the search has failed; NULL * otherwise. */ static void @@ -493,7 +486,7 @@ change_search_state (GabbleSearchChannel *chan, if (state == TP_CHANNEL_CONTACT_SEARCH_STATE_FAILED) { g_assert (reason != NULL); - g_assert (reason->domain == TP_ERRORS); + g_assert (reason->domain == TP_ERROR); error_name = tp_error_get_dbus_name (reason->code); g_value_init (&v, G_TYPE_STRING); @@ -737,7 +730,7 @@ parse_extended_search_results (GabbleSearchChannel *chan, x = wocky_node_get_child_ns (query_node, "x", NS_X_DATA); if (x == NULL) { - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "reply doens't contain a <x> node"); return FALSE; } @@ -802,7 +795,7 @@ search_reply_cb (GabbleConnection *conn, } else if (NULL == query_node) { - err = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + err = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "%s is broken: its iq reply didn't contain a <query/>", chan->priv->server); } @@ -848,7 +841,7 @@ validate_terms (GabbleSearchChannel *chan, if (!tp_strv_contains (asks, field)) { DEBUG ("%s is not in AvailableSearchKeys", field); - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s is not in AvailableSearchKeys", field); return FALSE; } @@ -887,12 +880,12 @@ build_extended_query (GabbleSearchChannel *self, GHashTableIter iter; gpointer key, value; - x = wocky_node_add_child_with_content (query, "x", ""); - x->ns = g_quark_from_static_string (NS_X_DATA); + x = wocky_node_add_child_ns_q (query, "x", + g_quark_from_static_string (NS_X_DATA)); wocky_node_set_attribute (x, "type", "submit"); /* add FORM_TYPE */ - field = wocky_node_add_child_with_content (x, "field", ""); + field = wocky_node_add_child (x, "field"); wocky_node_set_attributes (field, "type", "hidden", "var", "FORM_TYPE", @@ -909,7 +902,7 @@ build_extended_query (GabbleSearchChannel *self, g_assert (xmpp_field != NULL); - field = wocky_node_add_child_with_content (x, "field", ""); + field = wocky_node_add_child (x, "field"); wocky_node_set_attribute (field, "var", xmpp_field); wocky_node_add_child_with_content (field, "value", value); @@ -922,7 +915,7 @@ build_extended_query (GabbleSearchChannel *self, { xmpp_field = g_ptr_array_index (self->priv->boolean_keys, i); - field = wocky_node_add_child_with_content (x, "field", ""); + field = wocky_node_add_child (x, "field"); wocky_node_set_attributes (field, "var", xmpp_field, "type", "boolean", @@ -1159,7 +1152,6 @@ gabble_search_channel_class_init (GabbleSearchChannelClass *klass) object_class->set_property = gabble_search_channel_set_property; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH; - base_class->interfaces = gabble_search_channel_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_NONE; base_class->fill_immutable_properties = gabble_search_channel_fill_immutable_properties; @@ -1204,7 +1196,7 @@ gabble_search_channel_class_init (GabbleSearchChannelClass *klass) * server gave us a set of search keys, and they were sane, all components * will be 0 or %NULL, indicating that this channel can be announced and * used; if the server doesn't actually speak XEP 0055 or is full of bees, - * they'll be an error in either the GABBLE_XMPP_ERROR or the TP_ERRORS + * they'll be an error in either the GABBLE_XMPP_ERROR or the TP_ERROR * domain. */ signals[READY_OR_NOT] = @@ -1235,7 +1227,7 @@ gabble_search_channel_search (TpSvcChannelTypeContactSearch *self, if (priv->state != TP_CHANNEL_CONTACT_SEARCH_STATE_NOT_STARTED) { - error = g_error_new (TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + error = g_error_new (TP_ERROR, TP_ERROR_NOT_AVAILABLE, "SearchState is %s", states[priv->state]); goto err; } @@ -1262,7 +1254,7 @@ gabble_search_channel_stop (TpSvcChannelTypeContactSearch *self, { case TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS: { - GError e = { TP_ERRORS, TP_ERROR_CANCELLED, "Stop() called" }; + GError e = { TP_ERROR, TP_ERROR_CANCELLED, "Stop() called" }; change_search_state (chan, TP_CHANNEL_CONTACT_SEARCH_STATE_FAILED, &e); @@ -1274,7 +1266,7 @@ gabble_search_channel_stop (TpSvcChannelTypeContactSearch *self, break; case TP_CHANNEL_CONTACT_SEARCH_STATE_NOT_STARTED: { - GError e = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Search() hasn't been called yet" }; dbus_g_method_return_error (context, &e); diff --git a/src/search-channel.h b/src/search-channel.h index 9b6c748ab..066fd8535 100644 --- a/src/search-channel.h +++ b/src/search-channel.h @@ -23,7 +23,7 @@ #include <glib-object.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/search-manager.c b/src/search-manager.c index c78598fb1..e0af6eb4a 100644 --- a/src/search-manager.c +++ b/src/search-manager.c @@ -21,9 +21,8 @@ #include "config.h" #include "search-manager.h" -#include <telepathy-glib/channel-manager.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/interfaces.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -149,7 +148,7 @@ disco_done_cb (GabbleDisco *disco, else { tp_channel_manager_emit_request_failed (self, request_token, - TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No Server has been specified and no server has been " "discovered on the connection"); } @@ -408,7 +407,7 @@ search_channel_ready_or_not_cb (GabbleSearchChannel *chan, { if (domain == WOCKY_XMPP_ERROR) { - domain = TP_ERRORS; + domain = TP_ERROR; switch (code) { @@ -424,7 +423,7 @@ search_channel_ready_or_not_cb (GabbleSearchChannel *chan, } else { - g_assert (domain == TP_ERRORS); + g_assert (domain == TP_ERROR); } tp_channel_manager_emit_request_failed (ctx->self, @@ -442,13 +441,14 @@ new_search_channel (GabbleSearchManager *self, { GabbleSearchManagerPrivate *priv = self->priv; GabbleSearchChannel *chan; + TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); g_assert (server != NULL); chan = g_object_new (GABBLE_TYPE_SEARCH_CHANNEL, "connection", priv->conn, "server", server, - "initiator-handle", priv->conn->parent.self_handle, + "initiator-handle", tp_base_connection_get_self_handle (base_conn), NULL); g_hash_table_insert (priv->channels, chan, priv->channels); g_signal_connect (chan, "closed", (GCallback) search_channel_closed_cb, self); @@ -490,7 +490,7 @@ gabble_search_manager_create_channel (TpChannelManager *manager, else if (!wocky_decode_jid (server, NULL, NULL, NULL)) { /* On the other hand, if the JID's invalid, blow up. */ - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Specified server '%s' is not a valid JID", server); goto error; } @@ -501,7 +501,7 @@ gabble_search_manager_create_channel (TpChannelManager *manager, { if (self->priv->disco_done) { - error = g_error_new (TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + error = g_error_new (TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "No Server has been specified and no server has been " "discovered on the connection"); goto error; diff --git a/src/server-sasl-channel.c b/src/server-sasl-channel.c index 961d6d491..3eb4f66f2 100644 --- a/src/server-sasl-channel.c +++ b/src/server-sasl-channel.c @@ -36,15 +36,8 @@ #include <dbus/dbus-glib.h> #include <wocky/wocky.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_AUTH @@ -66,12 +59,6 @@ G_DEFINE_TYPE_WITH_CODE (GabbleServerSaslChannel, gabble_server_sasl_channel, TP_TYPE_SVC_CHANNEL_INTERFACE_SASL_AUTHENTICATION, sasl_auth_iface_init)); -static const gchar *gabble_server_sasl_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION, - TP_IFACE_CHANNEL_INTERFACE_SECURABLE, - NULL -}; - enum { /* server authentication channel */ @@ -106,10 +93,25 @@ struct _GabbleServerSaslChannelPrivate GHashTable *sasl_error_details; /* Given to the Connection on request */ TpConnectionStatusReason disconnect_reason; + GError *wocky_auth_error /* = NULL */; GSimpleAsyncResult *result; }; +static GPtrArray * +gabble_server_sasl_channel_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_server_sasl_channel_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION); + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_SECURABLE); + + return interfaces; +} + static void gabble_server_sasl_channel_init (GabbleServerSaslChannel *self) { @@ -274,6 +276,7 @@ gabble_server_sasl_channel_finalize (GObject *object) g_free (priv->sasl_error); g_hash_table_unref (priv->sasl_error_details); + g_clear_error (&priv->wocky_auth_error); if (G_OBJECT_CLASS (gabble_server_sasl_channel_parent_class)->finalize) G_OBJECT_CLASS (gabble_server_sasl_channel_parent_class)->finalize (object); @@ -337,7 +340,7 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass) channel_class->channel_type = TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION; - channel_class->interfaces = gabble_server_sasl_channel_interfaces; + channel_class->get_interfaces = gabble_server_sasl_channel_get_interfaces; channel_class->target_handle_type = TP_HANDLE_TYPE_NONE; channel_class->fill_immutable_properties = gabble_server_sasl_channel_fill_immutable_properties; @@ -431,13 +434,12 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass) } static void -change_current_state (GabbleServerSaslChannel *self, - TpSASLStatus status, +set_errors ( + GabbleServerSaslChannel *self, const gchar *dbus_error, - const gchar *debug_message) + const gchar *debug_message, + const GError *error) { - self->priv->sasl_status = status; - g_free (self->priv->sasl_error); self->priv->sasl_error = g_strdup (dbus_error); @@ -446,12 +448,41 @@ change_current_state (GabbleServerSaslChannel *self, tp_asv_set_string (self->priv->sasl_error_details, "debug-message", debug_message); + g_clear_error (&self->priv->wocky_auth_error); + self->priv->wocky_auth_error = g_error_copy (error); +} + +static void +change_current_state (GabbleServerSaslChannel *self, + TpSASLStatus status) +{ + self->priv->sasl_status = status; + tp_svc_channel_interface_sasl_authentication_emit_sasl_status_changed ( self, self->priv->sasl_status, self->priv->sasl_error, self->priv->sasl_error_details); } +static void +complete_operation ( + GabbleServerSaslChannel *self, + gboolean in_idle) +{ + GabbleServerSaslChannelPrivate *priv = self->priv; + GSimpleAsyncResult *r = priv->result; + + g_return_if_fail (priv->result != NULL); + priv->result = NULL; + + if (in_idle) + g_simple_async_result_complete_in_idle (r); + else + g_simple_async_result_complete (r); + + g_object_unref (r); +} + /** * SASL Authentication Channel Interface */ @@ -470,7 +501,7 @@ gabble_server_sasl_channel_raise (DBusGMethodInvocation *context, GError *error = NULL; va_start (ap, message); - error = g_error_new_valist (TP_ERRORS, code, message, ap); + error = g_error_new_valist (TP_ERROR, code, message, ap); va_end (ap); dbus_g_method_return_error (context, error); @@ -489,7 +520,6 @@ gabble_server_sasl_channel_start_mechanism_with_data ( GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (iface); GabbleServerSaslChannelPrivate *priv = self->priv; WockyAuthRegistryStartData *start_data; - GSimpleAsyncResult *r = priv->result; GString *initial_data = NULL; if (self->priv->sasl_status != TP_SASL_STATUS_NOT_STARTED) @@ -503,15 +533,13 @@ gabble_server_sasl_channel_start_mechanism_with_data ( /* NotStarted state is entered by creating the channel: the caller must * call start_auth_async immediately */ - g_assert (r != NULL); - g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (r), + g_assert (priv->result != NULL); + g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (priv->result), G_OBJECT (self), gabble_server_sasl_channel_start_auth_async)); if (tp_strv_contains ((const gchar * const *) priv->available_mechanisms, in_Mechanism)) { - priv->result = NULL; - if (in_InitialData != NULL) { /* The initial data might be secret (for PLAIN etc.), and also might @@ -527,16 +555,15 @@ gabble_server_sasl_channel_start_mechanism_with_data ( in_Mechanism); } - change_current_state (self, TP_SASL_STATUS_IN_PROGRESS, NULL, NULL); + change_current_state (self, TP_SASL_STATUS_IN_PROGRESS); dbus_g_method_return (context); start_data = wocky_auth_registry_start_data_new (in_Mechanism, initial_data); - g_simple_async_result_set_op_res_gpointer (r, + g_simple_async_result_set_op_res_gpointer (priv->result, start_data, (GDestroyNotify) wocky_auth_registry_start_data_free); - g_simple_async_result_complete_in_idle (r); - g_object_unref (r); + complete_operation (self, TRUE); if (initial_data != NULL) g_string_free (initial_data, TRUE); @@ -567,8 +594,8 @@ gabble_server_sasl_channel_respond ( { GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (channel); + GabbleServerSaslChannelPrivate *priv = self->priv; GString *response_data; - GSimpleAsyncResult *r = self->priv->result; if (self->priv->sasl_status != TP_SASL_STATUS_IN_PROGRESS) { @@ -580,7 +607,7 @@ gabble_server_sasl_channel_respond ( return; } - if (r == NULL) + if (priv->result == NULL) { gabble_server_sasl_channel_raise (context, TP_ERROR_NOT_AVAILABLE, "You already responded to the most recent challenge"); @@ -588,26 +615,22 @@ gabble_server_sasl_channel_respond ( return; } - g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (r), + g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (priv->result), G_OBJECT (self), gabble_server_sasl_channel_challenge_async)); /* The response might be secret (for PLAIN etc.), and also might * not be UTF-8 or even text, so we just output the length */ DEBUG ("responding with %u bytes", in_Response_Data->len); - self->priv->result = NULL; - if (in_Response_Data->len > 0) response_data = g_string_new_len (in_Response_Data->data, in_Response_Data->len); else response_data = NULL; - g_simple_async_result_set_op_res_gpointer (r, response_data, + g_simple_async_result_set_op_res_gpointer (priv->result, response_data, (GDestroyNotify) wocky_g_string_free); - - g_simple_async_result_complete_in_idle (r); - g_object_unref (r); + complete_operation (self, TRUE); tp_svc_channel_interface_sasl_authentication_return_from_respond ( context); @@ -619,10 +642,9 @@ gabble_server_sasl_channel_accept_sasl ( DBusGMethodInvocation *context) { GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (channel); - GSimpleAsyncResult *r = self->priv->result; + GabbleServerSaslChannelPrivate *priv = self->priv; const gchar *message = NULL; - switch (self->priv->sasl_status) { case TP_SASL_STATUS_NOT_STARTED: @@ -633,7 +655,7 @@ gabble_server_sasl_channel_accept_sasl ( /* In this state, the only valid time to call this method is in response * to a challenge, to indicate that, actually, that challenge was * additional data for a successful authentication. */ - if (r == NULL) + if (priv->result == NULL) { message = "In_Progress, but you already responded to the last " "challenge"; @@ -642,10 +664,9 @@ gabble_server_sasl_channel_accept_sasl ( { DEBUG ("client says the last challenge was actually final data " "and has accepted it"); - g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (r), + g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (priv->result), G_OBJECT (self), gabble_server_sasl_channel_challenge_async)); - change_current_state (self, TP_SASL_STATUS_CLIENT_ACCEPTED, NULL, - NULL); + change_current_state (self, TP_SASL_STATUS_CLIENT_ACCEPTED); } break; @@ -654,9 +675,9 @@ gabble_server_sasl_channel_accept_sasl ( * success_async(), i.e. waiting for the UI to check whether it's * happy too. AcceptSASL means that it is. */ DEBUG ("client has accepted server's success"); - g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (r), + g_assert (g_simple_async_result_is_valid (G_ASYNC_RESULT (priv->result), G_OBJECT (self), gabble_server_sasl_channel_success_async)); - change_current_state (self, TP_SASL_STATUS_SUCCEEDED, NULL, NULL); + change_current_state (self, TP_SASL_STATUS_SUCCEEDED); break; case TP_SASL_STATUS_CLIENT_ACCEPTED: @@ -687,20 +708,18 @@ gabble_server_sasl_channel_accept_sasl ( return; } - if (r != NULL) + if (priv->result != NULL) { /* This is a bit weird - this code is run for two different async * results. In the In_Progress case, this code results in * success with the GSimpleAsyncResult's op_res left as NULL, which * is what Wocky wants for an empty response. In the Server_Succeeded * response, the async result is just success or error - we succeed. */ - self->priv->result = NULL; /* We want want to complete not in an idle because if we do we * will hit fd.o#32278. This is safe because we're being called * from dbus-glib in the main loop. */ - g_simple_async_result_complete (r); - g_object_unref (r); + complete_operation (self, FALSE); } tp_svc_channel_interface_sasl_authentication_return_from_accept_sasl ( @@ -715,8 +734,7 @@ gabble_server_sasl_channel_abort_sasl ( DBusGMethodInvocation *context) { GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (channel); - GSimpleAsyncResult *r = self->priv->result; - guint code; + GabbleServerSaslChannelPrivate *priv = self->priv; const gchar *dbus_error; switch (self->priv->sasl_status) @@ -736,49 +754,53 @@ gabble_server_sasl_channel_abort_sasl ( case TP_SASL_STATUS_NOT_STARTED: case TP_SASL_STATUS_IN_PROGRESS: case TP_SASL_STATUS_SERVER_SUCCEEDED: + { + GError *error = NULL; + switch (in_Reason) { case TP_SASL_ABORT_REASON_INVALID_CHALLENGE: - DEBUG ("invalid challenge (%s)", in_Debug_Message); - code = WOCKY_AUTH_ERROR_INVALID_REPLY; + g_set_error (&error, WOCKY_AUTH_ERROR, + WOCKY_AUTH_ERROR_INVALID_REPLY, + "invalid challenge (%s)", in_Debug_Message); dbus_error = TP_ERROR_STR_SERVICE_CONFUSED; break; case TP_SASL_ABORT_REASON_USER_ABORT: - DEBUG ("user aborted auth (%s)", in_Debug_Message); - code = WOCKY_AUTH_ERROR_FAILURE; + g_set_error (&error, WOCKY_AUTH_ERROR, + WOCKY_AUTH_ERROR_FAILURE, + "user aborted auth (%s)", in_Debug_Message); dbus_error = TP_ERROR_STR_CANCELLED; break; default: - DEBUG ("unknown reason code %u, treating as User_Abort (%s)", + g_set_error (&error, WOCKY_AUTH_ERROR, + WOCKY_AUTH_ERROR_FAILURE, + "unknown reason code %u, treating as User_Abort (%s)", in_Reason, in_Debug_Message); - code = WOCKY_AUTH_ERROR_FAILURE; dbus_error = TP_ERROR_STR_CANCELLED; break; } - if (r != NULL) - { - self->priv->result = NULL; + DEBUG ("%s", error->message); + set_errors (self, dbus_error, in_Debug_Message, error); + change_current_state (self, TP_SASL_STATUS_CLIENT_FAILED); + + if (priv->result != NULL) + { /* If Not_Started, we're returning failure from start_auth_async. * If In_Progress, we might be returning failure from * challenge_async, if one is outstanding. * If Server_Succeeded, we're returning failure from success_async. */ - - g_simple_async_result_set_error (r, WOCKY_AUTH_ERROR, code, - "Authentication aborted: %s", in_Debug_Message); - - g_simple_async_result_complete_in_idle (r); - g_object_unref (r); + g_simple_async_result_set_from_error (priv->result, error); + complete_operation (self, TRUE); } - change_current_state (self, TP_SASL_STATUS_CLIENT_FAILED, - dbus_error, in_Debug_Message); + g_error_free (error); break; - + } default: g_assert_not_reached (); } @@ -840,7 +862,7 @@ gabble_server_sasl_channel_challenge_async (GabbleServerSaslChannel *self, g_assert (!tp_base_channel_is_destroyed ((TpBaseChannel *) self)); g_assert (priv->result == NULL); - g_assert (priv->sasl_status == TP_SASL_STATUS_IN_PROGRESS); + /* it might be sensitive, and also might not be UTF-8 text, so just print * the length */ DEBUG ("New challenge, %" G_GSIZE_FORMAT " bytes", challenge_data->len); @@ -848,13 +870,26 @@ gabble_server_sasl_channel_challenge_async (GabbleServerSaslChannel *self, priv->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gabble_server_sasl_channel_challenge_async); - challenge_ay = g_array_sized_new (FALSE, FALSE, sizeof (gchar), - challenge_data->len); - g_array_append_vals (challenge_ay, challenge_data->str, - challenge_data->len); + switch (priv->sasl_status) + { + case TP_SASL_STATUS_IN_PROGRESS: + challenge_ay = g_array_sized_new (FALSE, FALSE, sizeof (gchar), + challenge_data->len); + g_array_append_vals (challenge_ay, challenge_data->str, + challenge_data->len); - tp_svc_channel_interface_sasl_authentication_emit_new_challenge ( - self, challenge_ay); + tp_svc_channel_interface_sasl_authentication_emit_new_challenge ( + self, challenge_ay); + break; + case TP_SASL_STATUS_CLIENT_FAILED: + g_return_if_fail (priv->wocky_auth_error != NULL); + g_simple_async_result_set_from_error (priv->result, + priv->wocky_auth_error); + complete_operation (self, TRUE); + return; + default: + g_assert_not_reached (); + } } gboolean @@ -874,12 +909,11 @@ gabble_server_sasl_channel_success_async (GabbleServerSaslChannel *self, gpointer user_data) { GabbleServerSaslChannelPrivate *priv = self->priv; - GSimpleAsyncResult *r; g_assert (!tp_base_channel_is_destroyed ((TpBaseChannel *) self)); g_assert (priv->result == NULL); - r = g_simple_async_result_new (G_OBJECT (self), + priv->result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gabble_server_sasl_channel_success_async); @@ -887,16 +921,12 @@ gabble_server_sasl_channel_success_async (GabbleServerSaslChannel *self, if (self->priv->sasl_status != TP_SASL_STATUS_CLIENT_ACCEPTED) { - priv->result = r; - change_current_state (self, TP_SASL_STATUS_SERVER_SUCCEEDED, - NULL, NULL); + change_current_state (self, TP_SASL_STATUS_SERVER_SUCCEEDED); } else { - change_current_state (self, TP_SASL_STATUS_SUCCEEDED, NULL, - NULL); - g_simple_async_result_complete_in_idle (r); - g_object_unref (r); + change_current_state (self, TP_SASL_STATUS_SUCCEEDED); + complete_operation (self, TRUE); } } @@ -924,11 +954,12 @@ gabble_server_sasl_channel_fail (GabbleServerSaslChannel *self, gabble_set_tp_conn_error_from_wocky (error, TP_CONNECTION_STATUS_CONNECTING, &conn_reason, &tp_error); - g_assert (tp_error->domain == TP_ERRORS); + g_assert (tp_error->domain == TP_ERROR); DEBUG ("auth failed: %s", tp_error->message); - change_current_state (self, TP_SASL_STATUS_SERVER_FAILED, - tp_error_get_dbus_name (tp_error->code), tp_error->message); + set_errors (self, + tp_error_get_dbus_name (tp_error->code), tp_error->message, error); + change_current_state (self, TP_SASL_STATUS_SERVER_FAILED); self->priv->disconnect_reason = conn_reason; } @@ -961,21 +992,37 @@ gabble_server_sasl_channel_close (TpBaseChannel *channel) { GabbleServerSaslChannel *self = GABBLE_SERVER_SASL_CHANNEL (channel); GabbleServerSaslChannelPrivate *priv = self->priv; + GError error = { WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE, + "Client aborted authentication." }; DEBUG ("called on %p", self); - if (priv->result != NULL) + switch (priv->sasl_status) { - GSimpleAsyncResult *r = priv->result; + case TP_SASL_STATUS_NOT_STARTED: + case TP_SASL_STATUS_IN_PROGRESS: + case TP_SASL_STATUS_SERVER_SUCCEEDED: + set_errors (self, TP_ERROR_STR_AUTHENTICATION_FAILED, "Close() called", + &error); + break; + + case TP_SASL_STATUS_CLIENT_ACCEPTED: + case TP_SASL_STATUS_SUCCEEDED: + /* Hooray! */ + break; + case TP_SASL_STATUS_SERVER_FAILED: + case TP_SASL_STATUS_CLIENT_FAILED: + g_warn_if_fail (priv->sasl_error != NULL); + break; + } + + if (priv->result != NULL) + { DEBUG ("closed channel"); - priv->result = NULL; - g_simple_async_result_set_error (r, WOCKY_AUTH_ERROR, - WOCKY_AUTH_ERROR_FAILURE, - "%s", "Client aborted authentication."); - g_simple_async_result_complete_in_idle (r); - g_object_unref (r); + g_simple_async_result_set_from_error (priv->result, &error); + complete_operation (self, TRUE); } tp_base_channel_destroyed (channel); @@ -986,6 +1033,8 @@ gabble_server_sasl_channel_close (TpBaseChannel *channel) * @details: (out) (transfer full) (element-type utf8 GObject.Value): the * error details * @reason: (out): the reason with which to disconnect + * @error: (out): an error in a domain Wocky understands describing what went + * wrong * * Returns: %TRUE if an error was copied; %FALSE leaving the 'out' parameters * untouched if there is no error @@ -994,7 +1043,8 @@ gboolean gabble_server_sasl_channel_get_failure_details (GabbleServerSaslChannel *self, gchar **dbus_error, GHashTable **details, - TpConnectionStatusReason *reason) + TpConnectionStatusReason *reason, + GError **error) { if (self->priv->sasl_error != NULL) { @@ -1007,6 +1057,9 @@ gabble_server_sasl_channel_get_failure_details (GabbleServerSaslChannel *self, if (reason != NULL) *reason = self->priv->disconnect_reason; + if (error != NULL) + *error = g_error_copy (self->priv->wocky_auth_error); + return TRUE; } else diff --git a/src/server-sasl-channel.h b/src/server-sasl-channel.h index 69b469974..83e41bd56 100644 --- a/src/server-sasl-channel.h +++ b/src/server-sasl-channel.h @@ -22,7 +22,7 @@ #include <glib-object.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> #include "types.h" @@ -94,7 +94,8 @@ void gabble_server_sasl_channel_fail (GabbleServerSaslChannel *self, gboolean gabble_server_sasl_channel_get_failure_details ( GabbleServerSaslChannel *self, gchar **dbus_error, GHashTable **details, - TpConnectionStatusReason *reason); + TpConnectionStatusReason *reason, + GError **error); G_END_DECLS diff --git a/src/server-tls-channel.c b/src/server-tls-channel.c index a82842d77..aae0aadc8 100644 --- a/src/server-tls-channel.c +++ b/src/server-tls-channel.c @@ -22,10 +22,8 @@ #include "server-tls-channel.h" -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/channel-iface.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -41,10 +39,6 @@ G_DEFINE_TYPE_WITH_CODE (GabbleServerTLSChannel, gabble_server_tls_channel, static void gabble_server_tls_channel_close (TpBaseChannel *base); -static const gchar *gabble_server_tls_channel_interfaces[] = { - NULL -}; - enum { /* server TLS channel iface */ PROP_SERVER_CERTIFICATE = 1, @@ -262,7 +256,6 @@ gabble_server_tls_channel_class_init (GabbleServerTLSChannelClass *klass) oclass->constructed = gabble_server_tls_channel_constructed; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION; - base_class->interfaces = gabble_server_tls_channel_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_NONE; base_class->fill_immutable_properties = gabble_server_tls_channel_fill_immutable_properties; diff --git a/src/server-tls-channel.h b/src/server-tls-channel.h index 45afbf2a3..a21f1e358 100644 --- a/src/server-tls-channel.h +++ b/src/server-tls-channel.h @@ -23,7 +23,7 @@ #include <glib-object.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> #include <extensions/extensions.h> diff --git a/src/server-tls-manager.c b/src/server-tls-manager.c index c28d2d4d2..4e961cdde 100644 --- a/src/server-tls-manager.c +++ b/src/server-tls-manager.c @@ -21,7 +21,8 @@ #include "config.h" #include "server-tls-manager.h" -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_TLS #include "debug.h" @@ -345,7 +346,7 @@ gabble_server_tls_manager_verify_async (WockyTLSHandler *handler, if (self->priv->connection == NULL) { DEBUG ("connection already went away; failing immediately"); - g_simple_async_result_set_error (result, TP_ERRORS, TP_ERROR_CANCELLED, + g_simple_async_result_set_error (result, TP_ERROR, TP_ERROR_CANCELLED, "The Telepathy connection has already been disconnected"); g_simple_async_result_complete_in_idle (result); g_object_unref (result); diff --git a/src/server-tls-manager.h b/src/server-tls-manager.h index e8f10af1b..816866b5e 100644 --- a/src/server-tls-manager.h +++ b/src/server-tls-manager.h @@ -23,8 +23,7 @@ #include <glib-object.h> #include <wocky/wocky.h> - -#include <telepathy-glib/enums.h> +#include <telepathy-glib/telepathy-glib.h> #include "extensions/extensions.h" diff --git a/src/tls-certificate.c b/src/tls-certificate.c index 6d5748568..303b70644 100644 --- a/src/tls-certificate.c +++ b/src/tls-certificate.c @@ -22,7 +22,7 @@ #include "tls-certificate.h" #include <telepathy-glib/telepathy-glib.h> -#include <telepathy-glib/svc-tls.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_TLS #include "debug.h" @@ -266,7 +266,7 @@ gabble_tls_certificate_accept (TpSvcAuthenticationTLSCertificate *cert, if (self->priv->cert_state != TP_TLS_CERTIFICATE_STATE_PENDING) { GError error = - { TP_ERRORS, + { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Calling Accept() on a certificate with state != PENDING " "doesn't make sense." @@ -295,7 +295,7 @@ gabble_tls_certificate_reject (TpSvcAuthenticationTLSCertificate *cert, if (rejections->len < 1) { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Calling Reject() with a zero-length rejection list." }; dbus_g_method_return_error (context, &error); @@ -305,7 +305,7 @@ gabble_tls_certificate_reject (TpSvcAuthenticationTLSCertificate *cert, if (self->priv->cert_state != TP_TLS_CERTIFICATE_STATE_PENDING) { GError error = - { TP_ERRORS, + { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Calling Reject() on a certificate with state != PENDING " "doesn't make sense." diff --git a/src/tls-certificate.h b/src/tls-certificate.h index e71245d1c..271ce09d7 100644 --- a/src/tls-certificate.h +++ b/src/tls-certificate.h @@ -23,7 +23,7 @@ #include <glib-object.h> -#include <telepathy-glib/dbus-properties-mixin.h> +#include <telepathy-glib/telepathy-glib.h> G_BEGIN_DECLS diff --git a/src/tube-dbus.c b/src/tube-dbus.c index 424bf3dc5..d982e7902 100644 --- a/src/tube-dbus.c +++ b/src/tube-dbus.c @@ -27,18 +27,13 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> #include <wocky/wocky.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/group-mixin.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "extensions/extensions.h" #define DEBUG_FLAG GABBLE_DEBUG_TUBES -#include "base64.h" #include "bytestream-factory.h" #include "bytestream-ibb.h" #include "bytestream-iface.h" @@ -75,11 +70,6 @@ G_DEFINE_TYPE_WITH_CODE (GabbleTubeDBus, gabble_tube_dbus, tp_external_group_mixin_iface_init); ); -static const gchar *gabble_tube_dbus_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_TUBE, - NULL -}; - static const gchar * const gabble_tube_dbus_channel_allowed_properties[] = { TP_IFACE_CHANNEL ".TargetHandle", TP_IFACE_CHANNEL ".TargetID", @@ -120,7 +110,7 @@ enum struct _GabbleTubeDBusPrivate { TpHandle self_handle; - guint id; + guint64 id; GabbleBytestreamIface *bytestream; gchar *stream_id; gchar *service; @@ -165,6 +155,19 @@ struct _GabbleTubeDBusPrivate #define GABBLE_TUBE_DBUS_GET_PRIVATE(obj) ((obj)->priv) +static GPtrArray * +gabble_tube_dbus_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_tube_dbus_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_TUBE); + + return interfaces; +} + static void data_received_cb (GabbleBytestreamIface *stream, TpHandle sender, GString *data, gpointer user_data); @@ -394,7 +397,7 @@ create_dbus_server (GabbleTubeDBus *self, g_free (priv->socket_path); priv->socket_path = NULL; - g_set_error (err, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (err, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "Can't create D-Bus server"); return FALSE; } @@ -411,6 +414,8 @@ static void tube_dbus_open (GabbleTubeDBus *self) { GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); g_signal_connect (priv->bytestream, "data-received", G_CALLBACK (data_received_cb), self); @@ -424,6 +429,15 @@ tube_dbus_open (GabbleTubeDBus *self) { dbus_server_setup_with_g_main (priv->dbus_srv, NULL); } + + if (cls->target_handle_type == TP_HANDLE_TYPE_ROOM) + { + /* add yourself in dbus names */ + gabble_tube_dbus_add_name (self, priv->self_handle, + priv->dbus_local_name); + + gabble_muc_channel_send_presence (priv->muc); + } } static void @@ -435,17 +449,6 @@ gabble_tube_dbus_init (GabbleTubeDBus *self) self->priv = priv; } -static void -unref_handle_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - TpHandle handle = GPOINTER_TO_UINT (key); - TpHandleRepoIface *contact_repo = (TpHandleRepoIface *) user_data; - - tp_handle_unref (contact_repo, handle); -} - static TpTubeChannelState get_tube_state (GabbleTubeDBus *self) { @@ -485,11 +488,16 @@ bytestream_state_changed_cb (GabbleBytestreamIface *bytestream, { GabbleTubeDBus *self = GABBLE_TUBE_DBUS (user_data); GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self); + TpBaseChannel *base = TP_BASE_CHANNEL (self); + TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); if (state == GABBLE_BYTESTREAM_STATE_CLOSED) { tp_clear_object (&priv->bytestream); g_signal_emit (G_OBJECT (self), signals[CLOSED], 0); + + if (cls->target_handle_type == TP_HANDLE_TYPE_ROOM) + gabble_muc_channel_send_presence (priv->muc); } else if (state == GABBLE_BYTESTREAM_STATE_OPEN) { @@ -507,10 +515,6 @@ gabble_tube_dbus_dispose (GObject *object) { GabbleTubeDBus *self = GABBLE_TUBE_DBUS (object); GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self); - TpBaseConnection *base_conn = tp_base_channel_get_connection ( - TP_BASE_CHANNEL (self)); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); DEBUG ("called"); @@ -556,13 +560,6 @@ gabble_tube_dbus_dispose (GObject *object) tp_clear_pointer (&priv->dbus_srv_addr, g_free); tp_clear_pointer (&priv->socket_path, g_free); tp_clear_pointer (&priv->dbus_local_name, g_free); - - if (priv->dbus_names != NULL) - { - g_hash_table_foreach (priv->dbus_names, unref_handle_foreach, - contact_repo); - } - tp_clear_pointer (&priv->dbus_names, g_hash_table_unref); tp_clear_pointer (&priv->dbus_name_to_handle, g_hash_table_unref); @@ -605,7 +602,7 @@ gabble_tube_dbus_get_property (GObject *object, g_value_set_uint (value, priv->self_handle); break; case PROP_ID: - g_value_set_uint (value, priv->id); + g_value_set_uint64 (value, priv->id); break; case PROP_BYTESTREAM: g_value_set_object (value, priv->bytestream); @@ -661,7 +658,7 @@ gabble_tube_dbus_set_property (GObject *object, priv->self_handle = g_value_get_uint (value); break; case PROP_ID: - priv->id = g_value_get_uint (value); + priv->id = g_value_get_uint64 (value); break; case PROP_BYTESTREAM: if (priv->bytestream == NULL) @@ -839,7 +836,7 @@ gabble_tube_dbus_get_object_path_suffix (TpBaseChannel *base) { GabbleTubeDBus *self = GABBLE_TUBE_DBUS (base); - return g_strdup_printf ("DBusTubeChannel/%u/%u", + return g_strdup_printf ("DBusTubeChannel/%u/%" G_GUINT64_FORMAT, tp_base_channel_get_target_handle (base), self->priv->id); } @@ -882,7 +879,7 @@ gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class) object_class->finalize = gabble_tube_dbus_finalize; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_DBUS_TUBE; - base_class->interfaces = gabble_tube_dbus_interfaces; + base_class->get_interfaces = gabble_tube_dbus_get_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; base_class->close = gabble_tube_dbus_close; base_class->fill_immutable_properties = @@ -1003,7 +1000,6 @@ gabble_tube_dbus_class_init (GabbleTubeDBusClass *gabble_tube_dbus_class) static void bytestream_negotiate_cb (GabbleBytestreamIface *bytestream, - const gchar *stream_id, WockyStanza *msg, GObject *object, gpointer user_data) @@ -1038,7 +1034,7 @@ gabble_tube_dbus_offer (GabbleTubeDBus *tube, if (priv->offered) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube has already been offered"); return FALSE; } @@ -1052,7 +1048,6 @@ gabble_tube_dbus_offer (GabbleTubeDBus *tube, GabblePresence *presence; WockyNode *tube_node, *si_node; WockyStanza *msg; - gboolean result; jid = tp_handle_inspect (contact_repo, tp_base_channel_get_target_handle (base)); @@ -1062,7 +1057,7 @@ gabble_tube_dbus_offer (GabbleTubeDBus *tube, if (presence == NULL) { DEBUG ("can't find contact %s's presence", jid); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "can't find contact %s's presence", jid); return FALSE; } @@ -1073,7 +1068,7 @@ gabble_tube_dbus_offer (GabbleTubeDBus *tube, if (resource == NULL) { DEBUG ("contact %s doesn't have tubes capabilities", jid); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "contact %s doesn't have tubes capabilities", jid); return FALSE; } @@ -1085,28 +1080,22 @@ gabble_tube_dbus_offer (GabbleTubeDBus *tube, wocky_stanza_get_top_node (msg), "si", NS_SI); g_assert (si_node != NULL); - tube_node = wocky_node_add_child_with_content (si_node, "tube", NULL); - tube_node->ns = g_quark_from_string (NS_TUBES); + tube_node = wocky_node_add_child_ns (si_node, "tube", NS_TUBES); gabble_tube_iface_publish_in_node (GABBLE_TUBE_IFACE (tube), base_conn, tube_node); tube->priv->offered = TRUE; - result = gabble_bytestream_factory_negotiate_stream ( + gabble_bytestream_factory_negotiate_stream ( conn->bytestream_factory, msg, priv->stream_id, - bytestream_negotiate_cb, tube, G_OBJECT (tube), error); + bytestream_negotiate_cb, tube, G_OBJECT (tube)); /* We don't create the bytestream of private D-Bus tube yet. * It will be when we'll receive the answer of the SI request */ - g_object_unref (msg); g_free (full_jid); - if (!result) - return FALSE; - tp_svc_channel_interface_tube_emit_tube_channel_state_changed (tube, TP_TUBE_CHANNEL_STATE_REMOTE_PENDING); - } else { @@ -1114,6 +1103,8 @@ gabble_tube_dbus_offer (GabbleTubeDBus *tube, g_object_set (priv->bytestream, "state", GABBLE_BYTESTREAM_STATE_OPEN, NULL); + + gabble_muc_channel_send_presence (priv->muc); } if (!create_dbus_server (tube, error)) @@ -1348,7 +1339,7 @@ gabble_tube_dbus_new (GabbleConnection *conn, const gchar *service, GHashTable *parameters, const gchar *stream_id, - guint id, + guint64 id, GabbleBytestreamIface *bytestream, GabbleMucChannel *muc, gboolean requested) @@ -1382,10 +1373,7 @@ static void augment_si_accept_iq (WockyNode *si, gpointer user_data) { - WockyNode *tube_node; - - tube_node = wocky_node_add_child_with_content (si, "tube", ""); - tube_node->ns = g_quark_from_string (NS_TUBES); + wocky_node_add_child_ns (si, "tube", NS_TUBES); } /* @@ -1518,7 +1506,6 @@ gabble_tube_dbus_add_name (GabbleTubeDBus *self, name_copy = g_strdup (name); g_hash_table_insert (priv->dbus_names, GUINT_TO_POINTER (handle), name_copy); - tp_handle_ref (contact_repo, handle); g_hash_table_insert (priv->dbus_name_to_handle, name_copy, GUINT_TO_POINTER (handle)); @@ -1545,9 +1532,6 @@ gabble_tube_dbus_remove_name (GabbleTubeDBus *self, GabbleTubeDBusPrivate *priv = GABBLE_TUBE_DBUS_GET_PRIVATE (self); TpBaseChannel *base = TP_BASE_CHANNEL (self); TpBaseChannelClass *cls = TP_BASE_CHANNEL_GET_CLASS (base); - TpBaseConnection *base_conn = tp_base_channel_get_connection (base); - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); const gchar *name; GHashTable *added; GArray *removed; @@ -1575,7 +1559,6 @@ gabble_tube_dbus_remove_name (GabbleTubeDBus *self, g_hash_table_unref (added); g_array_unref (removed); - tp_handle_unref (contact_repo, handle); return TRUE; } @@ -1603,7 +1586,7 @@ _gabble_generate_dbus_unique_name (const gchar *nick) if (len <= 186) { - encoded = base64_encode (len, nick, FALSE); + encoded = g_base64_encode ((const guchar *) nick, len); } else { @@ -1616,7 +1599,7 @@ _gabble_generate_dbus_unique_name (const gchar *nick) g_string_append_len (tmp, nick, 169); g_string_append_len (tmp, (const gchar *) sha1, 20); - encoded = base64_encode (tmp->len, tmp->str, FALSE); + encoded = g_base64_encode ((const guchar *) tmp->str, tmp->len); g_string_free (tmp, TRUE); } @@ -1661,7 +1644,7 @@ gabble_tube_dbus_check_access_control (GabbleTubeDBus *self, break; default: - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u socket access control is not supported", access_control); return FALSE; } diff --git a/src/tube-dbus.h b/src/tube-dbus.h index 35073ce3f..b3020a9f4 100644 --- a/src/tube-dbus.h +++ b/src/tube-dbus.h @@ -22,10 +22,8 @@ #include <glib-object.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/group-mixin.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "connection.h" #include "bytestream-iface.h" @@ -73,7 +71,7 @@ GType gabble_tube_dbus_get_type (void); GabbleTubeDBus *gabble_tube_dbus_new (GabbleConnection *conn, TpHandle handle, TpHandleType handle_type, TpHandle self_handle, TpHandle initiator, const gchar *service, GHashTable *parameters, const gchar *stream_id, - guint id, GabbleBytestreamIface *bytestream, GabbleMucChannel *muc, + guint64 id, GabbleBytestreamIface *bytestream, GabbleMucChannel *muc, gboolean requested); gboolean gabble_tube_dbus_add_name (GabbleTubeDBus *tube, TpHandle handle, diff --git a/src/tube-iface.c b/src/tube-iface.c index 62585eb33..7faf514ea 100644 --- a/src/tube-iface.c +++ b/src/tube-iface.c @@ -20,7 +20,8 @@ #include "config.h" #include "tube-iface.h" -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "connection.h" #include "util.h" @@ -72,7 +73,7 @@ gabble_tube_iface_base_init (gpointer klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (klass, param_spec); - param_spec = g_param_spec_uint ( + param_spec = g_param_spec_uint64 ( "id", "id", "The unique identifier of this tube", @@ -151,7 +152,7 @@ gabble_tube_iface_publish_in_node (GabbleTubeIface *tube, GHashTable *parameters; TpTubeType type; gchar *service, *id_str; - guint tube_id; + guint64 tube_id; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( conn, TP_HANDLE_TYPE_CONTACT); TpHandle initiator_handle; @@ -164,7 +165,7 @@ gabble_tube_iface_publish_in_node (GabbleTubeIface *tube, "id", &tube_id, NULL); - id_str = g_strdup_printf ("%u", tube_id); + id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, tube_id); wocky_node_set_attributes (node, "service", service, diff --git a/src/tube-iface.h b/src/tube-iface.h index 311bf65bc..b727f391d 100644 --- a/src/tube-iface.h +++ b/src/tube-iface.h @@ -21,7 +21,7 @@ #define __GABBLE_TUBE_IFACE_H__ #include <glib-object.h> -#include <telepathy-glib/base-connection.h> +#include <telepathy-glib/telepathy-glib.h> #include "bytestream-iface.h" diff --git a/src/tube-stream.c b/src/tube-stream.c index a505ef1a1..e1d2289de 100644 --- a/src/tube-stream.c +++ b/src/tube-stream.c @@ -31,12 +31,8 @@ #endif #include <glib/gstdio.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/group-mixin.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "extensions/extensions.h" @@ -86,11 +82,6 @@ static const gchar * const gabble_tube_stream_channel_allowed_properties[] = { NULL }; -static const gchar *gabble_tube_stream_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_TUBE, - NULL -}; - /* Linux glibc bits/socket.h suggests that struct sockaddr_storage is * not guaranteed to be big enough for AF_UNIX addresses */ typedef union @@ -136,7 +127,7 @@ enum struct _GabbleTubeStreamPrivate { TpHandle self_handle; - guint id; + guint64 id; /* Bytestreams for tubes. One tube can have several bytestreams. The * mapping between the tube bytestream and the transport to the local @@ -179,6 +170,19 @@ struct _GabbleTubeStreamPrivate gboolean dispose_has_run; }; +static GPtrArray * +gabble_tube_stream_get_interfaces (TpBaseChannel *base) +{ + GPtrArray *interfaces; + + interfaces = TP_BASE_CHANNEL_CLASS ( + gabble_tube_stream_parent_class)->get_interfaces (base); + + g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_TUBE); + + return interfaces; +} + typedef struct { GabbleTubeStream *self; @@ -402,7 +406,6 @@ extra_bytestream_state_changed_cb (GabbleBytestreamIface *bytestream, static void extra_bytestream_negotiate_cb (GabbleBytestreamIface *bytestream, - const gchar *stream_id, WockyStanza *msg, GObject *object, gpointer user_data) @@ -453,7 +456,6 @@ start_stream_initiation (GabbleTubeStream *self, TpHandleRepoIface *contact_repo; const gchar *jid; gchar *full_jid, *stream_id, *id_str; - gboolean result; contact_repo = tp_base_connection_get_handles ( base_conn, TP_HANDLE_TYPE_CONTACT); @@ -471,7 +473,7 @@ start_stream_initiation (GabbleTubeStream *self, if (presence == NULL) { DEBUG ("can't find initiator's presence"); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "can't find initiator's presence"); return FALSE; } @@ -481,7 +483,7 @@ start_stream_initiation (GabbleTubeStream *self, if (resource == NULL) { DEBUG ("initiator doesn't have tubes capabilities"); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "initiator doesn't have tubes capabilities"); return FALSE; } @@ -503,37 +505,31 @@ start_stream_initiation (GabbleTubeStream *self, wocky_stanza_get_top_node (msg), "si", NS_SI); g_assert (si_node != NULL); - id_str = g_strdup_printf ("%u", priv->id); + id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->id); if (cls->target_handle_type == TP_HANDLE_TYPE_CONTACT) { - node = wocky_node_add_child_with_content (si_node, "stream", NULL); + node = wocky_node_add_child_ns (si_node, "stream", NS_TUBES); } else { - node = wocky_node_add_child_with_content (si_node, "muc-stream", NULL); + node = wocky_node_add_child_ns (si_node, "muc-stream", NS_TUBES); } - node->ns = g_quark_from_static_string (NS_TUBES); wocky_node_set_attribute (node, "tube", id_str); - result = gabble_bytestream_factory_negotiate_stream ( + gabble_bytestream_factory_negotiate_stream ( conn->bytestream_factory, msg, stream_id, - extra_bytestream_negotiate_cb, g_object_ref (transport), G_OBJECT (self), - error); + extra_bytestream_negotiate_cb, g_object_ref (transport), G_OBJECT (self)); /* FIXME: data and one ref on data->transport are leaked if the tube is * closed before we got the SI reply. */ - - if (!result) - g_object_unref (transport); - g_object_unref (msg); g_free (stream_id); g_free (full_jid); g_free (id_str); - return result; + return TRUE; } static guint @@ -1235,7 +1231,7 @@ gabble_tube_stream_get_property (GObject *object, g_value_set_uint (value, priv->self_handle); break; case PROP_ID: - g_value_set_uint (value, priv->id); + g_value_set_uint64 (value, priv->id); break; case PROP_TYPE: g_value_set_uint (value, TP_TUBE_TYPE_STREAM); @@ -1289,7 +1285,7 @@ gabble_tube_stream_set_property (GObject *object, priv->self_handle = g_value_get_uint (value); break; case PROP_ID: - priv->id = g_value_get_uint (value); + priv->id = g_value_get_uint64 (value); break; case PROP_SERVICE: g_free (priv->service); @@ -1401,7 +1397,7 @@ gabble_tube_stream_get_object_path_suffix (TpBaseChannel *base) { GabbleTubeStream *self = GABBLE_TUBE_STREAM (base); - return g_strdup_printf ("StreamTubeChannel/%u/%u", + return g_strdup_printf ("StreamTubeChannel/%u/%" G_GUINT64_FORMAT, tp_base_channel_get_target_handle (base), self->priv->id); } @@ -1449,7 +1445,7 @@ gabble_tube_stream_class_init (GabbleTubeStreamClass *gabble_tube_stream_class) object_class->finalize = gabble_tube_stream_finalize; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_STREAM_TUBE; - base_class->interfaces = gabble_tube_stream_interfaces; + base_class->get_interfaces = gabble_tube_stream_get_interfaces; base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; base_class->close = gabble_tube_stream_close; base_class->fill_immutable_properties = @@ -1620,7 +1616,7 @@ gabble_tube_stream_new (GabbleConnection *conn, TpHandle initiator, const gchar *service, GHashTable *parameters, - guint id, + guint64 id, GabbleMucChannel *muc, gboolean requested) { @@ -1665,7 +1661,7 @@ gabble_tube_stream_accept (GabbleTubeIface *tube, if (priv->state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube is not in the local pending state"); goto fail; } @@ -1725,7 +1721,7 @@ gabble_tube_iface_stream_close (GabbleTubeIface *tube, jid = tp_handle_inspect (contact_repo, tp_base_channel_get_target_handle (base)); - id_str = g_strdup_printf ("%u", priv->id); + id_str = g_strdup_printf ("%" G_GUINT64_FORMAT, priv->id); /* Send the close message */ msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, @@ -1750,6 +1746,9 @@ gabble_tube_iface_stream_close (GabbleTubeIface *tube, * disappear when we finally remove the Tubes channel type.. */ g_object_ref (self); + if (cls->target_handle_type == TP_HANDLE_TYPE_ROOM) + gabble_muc_channel_send_presence (priv->muc); + g_signal_emit (G_OBJECT (self), signals[CLOSED], 0); tp_base_channel_destroyed (base); @@ -1761,10 +1760,7 @@ static void augment_si_accept_iq (WockyNode *si, gpointer user_data) { - WockyNode *tube_node; - - tube_node = wocky_node_add_child_with_content (si, "tube", ""); - tube_node->ns = g_quark_from_string (NS_TUBES); + wocky_node_add_child_ns (si, "tube", NS_TUBES); } /** @@ -1861,7 +1857,7 @@ check_unix_params (TpSocketAddressType address_type, { if (G_VALUE_TYPE (address) != DBUS_TYPE_G_UCHAR_ARRAY) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unix socket address is supposed to be ay"); return FALSE; } @@ -1870,7 +1866,7 @@ check_unix_params (TpSocketAddressType address_type, if (array->len > sizeof (dummy.sun_path) - 1) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unix socket path is too long (max length allowed: %" G_GSIZE_FORMAT ")", sizeof (dummy.sun_path) - 1); @@ -1881,7 +1877,7 @@ check_unix_params (TpSocketAddressType address_type, { if (g_array_index (array, gchar , i) == '\0') { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Unix socket path can't contain zero bytes"); return FALSE; } @@ -1893,7 +1889,7 @@ check_unix_params (TpSocketAddressType address_type, { DEBUG ("Error calling stat on socket: %s", g_strerror (errno)); - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "%s: %s", + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s: %s", socket_address->str, g_strerror (errno)); g_string_free (socket_address, TRUE); return FALSE; @@ -1903,7 +1899,7 @@ check_unix_params (TpSocketAddressType address_type, { DEBUG ("%s is not a socket", socket_address->str); - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%s is not a socket", socket_address->str); g_string_free (socket_address, TRUE); return FALSE; @@ -1919,7 +1915,7 @@ check_unix_params (TpSocketAddressType address_type, return TRUE; } - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u socket access control is not supported", access_control); return FALSE; } @@ -1944,7 +1940,7 @@ check_ip_params (TpSocketAddressType address_type, { if (G_VALUE_TYPE (address) != TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "IPv4 socket address is supposed to be sq"); return FALSE; } @@ -1953,7 +1949,7 @@ check_ip_params (TpSocketAddressType address_type, { if (G_VALUE_TYPE (address) != TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV6) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "IPv6 socket address is supposed to be sq"); return FALSE; } @@ -1981,7 +1977,7 @@ check_ip_params (TpSocketAddressType address_type, ret = getaddrinfo (ip, NULL, &req, &result); if (ret != 0) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Invalid address: %s", gai_strerror (ret)); g_free (ip); return FALSE; @@ -2002,7 +1998,7 @@ check_ip_params (TpSocketAddressType address_type, if (G_VALUE_TYPE (access_control_param) != TP_STRUCT_TYPE_SOCKET_ADDRESS_IPV4) { - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Port access param is supposed to be sq"); return FALSE; } @@ -2010,7 +2006,7 @@ check_ip_params (TpSocketAddressType address_type, return TRUE; } - g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u socket access control is not supported", access_control); return FALSE; } @@ -2040,7 +2036,7 @@ gabble_tube_stream_check_params (TpSocketAddressType address_type, access_control_param, error); default: - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, "Address type %d not implemented", address_type); return FALSE; } @@ -2077,7 +2073,7 @@ send_tube_offer (GabbleTubeStream *self, if (presence == NULL) { DEBUG ("can't find tube recipient's presence"); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "can't find tube recipient's presence"); return FALSE; } @@ -2087,7 +2083,7 @@ send_tube_offer (GabbleTubeStream *self, if (resource == NULL) { DEBUG ("tube recipient doesn't have tubes capabilities"); - g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE, + g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, "tube recipient doesn't have tubes capabilities"); return FALSE; } @@ -2141,6 +2137,8 @@ gabble_tube_stream_offer (GabbleTubeStream *self, /* muc tube is open as soon it's offered */ priv->state = TP_TUBE_CHANNEL_STATE_OPEN; g_signal_emit (G_OBJECT (self), signals[OPENED], 0); + + gabble_muc_channel_send_presence (priv->muc); } g_signal_emit (G_OBJECT (self), signals[OFFERED], 0); @@ -2239,7 +2237,7 @@ gabble_tube_stream_offer_async (TpSvcChannelTypeStreamTube *iface, if (priv->state != TP_TUBE_CHANNEL_STATE_NOT_OFFERED) { - g_set_error (&error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, + g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Tube is not in the not offered state"); dbus_g_method_return_error (context, error); g_error_free (error); diff --git a/src/tube-stream.h b/src/tube-stream.h index 991116238..5b26fcced 100644 --- a/src/tube-stream.h +++ b/src/tube-stream.h @@ -22,9 +22,8 @@ #include <glib-object.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/base-channel.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "connection.h" #include "extensions/extensions.h" @@ -69,7 +68,7 @@ GType gabble_tube_stream_get_type (void); GabbleTubeStream *gabble_tube_stream_new (GabbleConnection *conn, TpHandle handle, TpHandleType handle_type, TpHandle self_handle, TpHandle initiator, const gchar *service, GHashTable *parameters, - guint id, GabbleMucChannel *muc, gboolean requested); + guint64 id, GabbleMucChannel *muc, gboolean requested); gboolean gabble_tube_stream_check_params (TpSocketAddressType address_type, const GValue *address, TpSocketAccessControl access_control, diff --git a/src/tubes-channel.c b/src/tubes-channel.c deleted file mode 100644 index 7d7cab984..000000000 --- a/src/tubes-channel.c +++ /dev/null @@ -1,2398 +0,0 @@ -/* - * tubes-channel.c - Source for GabbleTubesChannel - * Copyright (C) 2007 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "tubes-channel.h" - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#include <glib/gstdio.h> -#include <dbus/dbus-glib.h> -#include <telepathy-glib/channel-iface.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/errors.h> -#include <telepathy-glib/exportable-channel.h> -#include <telepathy-glib/group-mixin.h> -#include <telepathy-glib/gtypes.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/svc-channel.h> -#include <telepathy-glib/svc-generic.h> - -#define DEBUG_FLAG GABBLE_DEBUG_TUBES - -#include "bytestream-factory.h" -#include "connection.h" -#include "debug.h" -#include "namespaces.h" -#include "presence-cache.h" -#include "presence.h" -#include "private-tubes-factory.h" -#include "tube-iface.h" -#include "tube-dbus.h" -#include "tube-stream.h" -#include "tube-dbus.h" -#include "util.h" - -static void channel_iface_init (gpointer, gpointer); -static void tubes_iface_init (gpointer, gpointer); - -G_DEFINE_TYPE_WITH_CODE (GabbleTubesChannel, gabble_tubes_channel, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TUBES, tubes_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, - tp_external_group_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); - -static const gchar *gabble_tubes_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_GROUP, - /* If more interfaces are added, either keep Group as the first, or change - * the implementations of gabble_tubes_channel_get_interfaces () and - * gabble_tubes_channel_get_property () too */ - NULL -}; - - -enum -{ - PROP_OBJECT_PATH = 1, - PROP_CHANNEL_TYPE, - PROP_HANDLE_TYPE, - PROP_HANDLE, - PROP_TARGET_ID, - PROP_REQUESTED, - PROP_CONNECTION, - PROP_INTERFACES, - PROP_MUC, - PROP_INITIATOR_HANDLE, - PROP_INITIATOR_ID, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - LAST_PROPERTY, -}; - -/* private structure */ - -struct _GabbleTubesChannelPrivate -{ - GabbleConnection *conn; - char *object_path; - TpHandle handle; - TpHandleType handle_type; - TpHandle self_handle; - TpHandle initiator; - gboolean requested; - - GHashTable *tubes; - - gulong pre_presence_signal; - gboolean closed; - gboolean dispose_has_run; -}; - -static void update_tubes_presence (GabbleTubesChannel *self); - -static void pre_presence_cb (GabbleMucChannel *muc, WockyStanza *msg, - GabbleTubesChannel *self); - -static void -gabble_tubes_channel_init (GabbleTubesChannel *self) -{ - GabbleTubesChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_TUBES_CHANNEL, GabbleTubesChannelPrivate); - - self->priv = priv; - - priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) g_object_unref); -} - -static GObject * -gabble_tubes_channel_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - GabbleTubesChannel *self; - GabbleTubesChannelPrivate *priv; - TpDBusDaemon *bus; - TpHandleRepoIface *handle_repo, *contact_repo; - - DEBUG ("Called"); - - obj = G_OBJECT_CLASS (gabble_tubes_channel_parent_class)-> - constructor (type, n_props, props); - - self = GABBLE_TUBES_CHANNEL (obj); - priv = self->priv; - contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - handle_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, priv->handle_type); - - tp_handle_ref (handle_repo, priv->handle); - - if (priv->initiator != 0) - tp_handle_ref (contact_repo, priv->initiator); - - switch (priv->handle_type) - { - case TP_HANDLE_TYPE_CONTACT: - g_assert (self->muc == NULL); - g_assert (priv->initiator != 0); - priv->self_handle = ((TpBaseConnection *) (priv->conn))->self_handle; - break; - case TP_HANDLE_TYPE_ROOM: - g_assert (self->muc != NULL); - - priv->pre_presence_signal = g_signal_connect (self->muc, "pre-presence", - G_CALLBACK (pre_presence_cb), self); - - priv->self_handle = self->muc->group.self_handle; - tp_external_group_mixin_init (obj, (GObject *) self->muc); - break; - default: - g_return_val_if_reached (NULL); - } - - bus = tp_base_connection_get_dbus_daemon ((TpBaseConnection *) priv->conn); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); - - DEBUG ("Registering at '%s'", priv->object_path); - - return obj; -} - -static void -gabble_tubes_channel_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleTubesChannel *chan = GABBLE_TUBES_CHANNEL (object); - GabbleTubesChannelPrivate *priv = chan->priv; - TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; - - switch (property_id) - { - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_CHANNEL_TYPE: - g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TUBES); - break; - case PROP_HANDLE_TYPE: - g_value_set_uint (value, priv->handle_type); - break; - case PROP_HANDLE: - g_value_set_uint (value, priv->handle); - break; - case PROP_TARGET_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, priv->handle_type); - - g_value_set_string (value, - tp_handle_inspect (repo, priv->handle)); - } - break; - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_INTERFACES: - if (chan->muc) - { - /* MUC tubes */ - g_value_set_boxed (value, gabble_tubes_channel_interfaces); - } - else - { - /* 1-1 tubes - omit the Group interface */ - g_value_set_boxed (value, gabble_tubes_channel_interfaces + 1); - } - break; - case PROP_MUC: - g_value_set_object (value, chan->muc); - break; - case PROP_INITIATOR_HANDLE: - g_value_set_uint (value, priv->initiator); - break; - case PROP_INITIATOR_ID: - if (priv->initiator == 0) - { - g_value_set_static_string (value, ""); - } - else - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - g_value_set_string (value, - tp_handle_inspect (repo, priv->initiator)); - } - break; - case PROP_REQUESTED: - g_value_set_boolean (value, priv->requested); - break; - case PROP_CHANNEL_DESTROYED: - g_value_set_boolean (value, priv->closed); - break; - case PROP_CHANNEL_PROPERTIES: - g_value_take_boxed (value, - tp_dbus_properties_mixin_make_properties_hash (object, - TP_IFACE_CHANNEL, "TargetHandle", - TP_IFACE_CHANNEL, "TargetHandleType", - TP_IFACE_CHANNEL, "ChannelType", - TP_IFACE_CHANNEL, "TargetID", - TP_IFACE_CHANNEL, "InitiatorHandle", - TP_IFACE_CHANNEL, "InitiatorID", - TP_IFACE_CHANNEL, "Requested", - TP_IFACE_CHANNEL, "Interfaces", - NULL)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_tubes_channel_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleTubesChannel *chan = GABBLE_TUBES_CHANNEL (object); - GabbleTubesChannelPrivate *priv = chan->priv; - - switch (property_id) - { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - DEBUG ("Setting object_path: %s", priv->object_path); - break; - case PROP_CHANNEL_TYPE: - /* this property is writable in the interface, but not actually - * meaningfully changeable on this channel, so we do nothing */ - break; - case PROP_HANDLE: - priv->handle = g_value_get_uint (value); - break; - case PROP_HANDLE_TYPE: - priv->handle_type = g_value_get_uint (value); - break; - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - case PROP_MUC: - chan->muc = g_value_get_object (value); - break; - case PROP_INITIATOR_HANDLE: - priv->initiator = g_value_get_uint (value); - break; - case PROP_REQUESTED: - priv->requested = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -d_bus_names_changed_added (GabbleTubesChannel *self, - guint tube_id, - TpHandle contact, - const gchar *new_name) -{ - GPtrArray *added = g_ptr_array_sized_new (1); - GArray *removed = g_array_new (FALSE, FALSE, sizeof (guint)); - GValue tmp = {0,}; - guint i; - - g_value_init (&tmp, TP_STRUCT_TYPE_DBUS_TUBE_MEMBER); - g_value_take_boxed (&tmp, - dbus_g_type_specialized_construct (TP_STRUCT_TYPE_DBUS_TUBE_MEMBER)); - dbus_g_type_struct_set (&tmp, - 0, contact, - 1, new_name, - G_MAXUINT); - g_ptr_array_add (added, g_value_get_boxed (&tmp)); - - tp_svc_channel_type_tubes_emit_d_bus_names_changed (self, - tube_id, added, removed); - - for (i = 0; i < added->len; i++) - g_boxed_free (TP_STRUCT_TYPE_DBUS_TUBE_MEMBER, added->pdata[i]); - g_ptr_array_unref (added); - g_array_unref (removed); -} - -static void -d_bus_names_changed_removed (GabbleTubesChannel *self, - guint tube_id, - TpHandle contact) -{ - GabbleTubesChannelPrivate *priv = self->priv; - GPtrArray *added; - GArray *removed; - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - return; - - added = g_ptr_array_new (); - removed = g_array_new (FALSE, FALSE, sizeof (guint)); - - g_array_append_val (removed, contact); - - tp_svc_channel_type_tubes_emit_d_bus_names_changed (self, - tube_id, added, removed); - - g_ptr_array_unref (added); - g_array_unref (removed); -} - -static void -add_name_in_dbus_names (GabbleTubesChannel *self, - guint tube_id, - TpHandle handle, - const gchar *dbus_name) -{ - GabbleTubesChannelPrivate *priv = self->priv; - GabbleTubeDBus *tube; - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - return; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - return; - - if (gabble_tube_dbus_add_name (tube, handle, dbus_name)) - { - /* Emit the DBusNamesChanged signal */ - d_bus_names_changed_added (self, tube_id, handle, dbus_name); - } -} - -static void -add_yourself_in_dbus_names (GabbleTubesChannel *self, - guint tube_id) -{ - GabbleTubesChannelPrivate *priv = self->priv; - GabbleTubeDBus *tube; - gchar *dbus_name; - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - return; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - return; - - g_object_get (tube, - "dbus-name", &dbus_name, - NULL); - - add_name_in_dbus_names (self, tube_id, priv->self_handle, dbus_name); - - g_free (dbus_name); -} - -static void -tube_closed_cb (GabbleTubeIface *tube, - gpointer user_data) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (user_data); - GabbleTubesChannelPrivate *priv = self->priv; - guint tube_id; - - if (priv->closed) - return; - - g_object_get (tube, "id", &tube_id, NULL); - if (!g_hash_table_remove (priv->tubes, GUINT_TO_POINTER (tube_id))) - { - DEBUG ("Can't find tube having this id: %d", tube_id); - } - DEBUG ("tube %d removed", tube_id); - - /* Emit the DBusNamesChanged signal if muc tube */ - d_bus_names_changed_removed (self, tube_id, priv->self_handle); - - update_tubes_presence (self); - - tp_svc_channel_type_tubes_emit_tube_closed (self, tube_id); - - /* Ideally, this should be done in the factory directly but the private - * tubes factory and the muc factory are not aware of tube channels. - * This design is a legacy of the old tube API and we can't really change it - * without big refactoring. */ - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - { - tp_channel_manager_emit_channel_closed_for_object ( - priv->conn->private_tubes_factory, TP_EXPORTABLE_CHANNEL (tube)); - } - else - { - tp_channel_manager_emit_channel_closed_for_object ( - priv->conn->muc_factory, TP_EXPORTABLE_CHANNEL (tube)); - } - -} - -static void -tube_opened_cb (GabbleTubeIface *tube, - gpointer user_data) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (user_data); - guint tube_id; - TpTubeType type; - - g_object_get (tube, - "id", &tube_id, - "type", &type, - NULL); - - if (type == TP_TUBE_TYPE_DBUS) - { - add_yourself_in_dbus_names (self, tube_id); - } - - update_tubes_presence (self); - - tp_svc_channel_type_tubes_emit_tube_state_changed (self, tube_id, - TP_TUBE_CHANNEL_STATE_OPEN); -} - -static void -tube_offered_cb (GabbleTubeIface *tube, - gpointer user_data) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (user_data); - guint tube_id; - TpHandle initiator; - TpTubeType type; - gchar *service; - GHashTable *parameters; - TpTubeChannelState state; - - g_object_get (tube, - "id", &tube_id, - "initiator-handle", &initiator, - "type", &type, - "service", &service, - "parameters", ¶meters, - "state", &state, - NULL); - - /* tube has been offered and so can be announced using the old API; - * TpTubeState and TpTubeChannelState are numerically equal for - * values other than NOT_OFFERED */ - g_assert (state < NUM_TP_TUBE_STATES); - tp_svc_channel_type_tubes_emit_new_tube (self, - tube_id, - initiator, - type, - service, - parameters, - state); - - update_tubes_presence (self); - - g_free (service); - g_hash_table_unref (parameters); -} - -static GabbleTubeIface * -create_new_tube (GabbleTubesChannel *self, - TpTubeType type, - TpHandle initiator, - const gchar *service, - GHashTable *parameters, - const gchar *stream_id, - guint tube_id, - GabbleBytestreamIface *bytestream, - gboolean requested) -{ - GabbleTubesChannelPrivate *priv = self->priv; - GabbleTubeIface *tube; - TpTubeChannelState state; - - switch (type) - { - case TP_TUBE_TYPE_DBUS: - tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (priv->conn, - priv->handle, priv->handle_type, priv->self_handle, initiator, - service, parameters, stream_id, tube_id, bytestream, self->muc, - requested)); - break; - case TP_TUBE_TYPE_STREAM: - tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (priv->conn, - priv->handle, priv->handle_type, priv->self_handle, initiator, - service, parameters, tube_id, self->muc, requested)); - break; - default: - g_return_val_if_reached (NULL); - } - - tp_base_channel_register ((TpBaseChannel *) tube); - - DEBUG ("create tube %u", tube_id); - g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), tube); - - g_object_get (tube, "state", &state, NULL); - - /* The old API doesn't know the "not offered" state, so we have to wait that - * the tube is offered before announcing it. - * TpTubeState and TpTubeChannelState are numerically equal for - * values other than NOT_OFFERED */ - if (state != TP_TUBE_CHANNEL_STATE_NOT_OFFERED) - { - tp_svc_channel_type_tubes_emit_new_tube (self, - tube_id, - initiator, - type, - service, - parameters, - state); - } - - g_signal_connect (tube, "tube-opened", G_CALLBACK (tube_opened_cb), self); - g_signal_connect (tube, "tube-closed", G_CALLBACK (tube_closed_cb), self); - g_signal_connect (tube, "tube-offered", G_CALLBACK (tube_offered_cb), self); - - return tube; -} - -static gboolean -extract_tube_information (GabbleTubesChannel *self, - WockyNode *tube_node, - TpTubeType *type, - TpHandle *initiator_handle, - const gchar **service, - GHashTable **parameters, - guint *tube_id) -{ - GabbleTubesChannelPrivate *priv = self->priv; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - - if (type != NULL) - { - const gchar *_type; - - _type = wocky_node_get_attribute (tube_node, "type"); - - if (!tp_strdiff (_type, "stream")) - { - *type = TP_TUBE_TYPE_STREAM; - } - else if (!tp_strdiff (_type, "dbus")) - { - *type = TP_TUBE_TYPE_DBUS; - } - else - { - DEBUG ("Unknown tube type: %s", _type); - return FALSE; - } - } - - if (initiator_handle != NULL) - { - const gchar *initiator; - - initiator = wocky_node_get_attribute (tube_node, "initiator"); - - if (initiator != NULL) - { - *initiator_handle = tp_handle_ensure (contact_repo, initiator, - GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL); - - if (*initiator_handle == 0) - { - DEBUG ("invalid initiator JID %s", initiator); - return FALSE; - } - } - else - { - *initiator_handle = 0; - } - } - - if (service != NULL) - { - *service = wocky_node_get_attribute (tube_node, "service"); - } - - if (parameters != NULL) - { - WockyNode *node; - - node = wocky_node_get_child (tube_node, "parameters"); - *parameters = lm_message_node_extract_properties (node, "parameter"); - } - - if (tube_id != NULL) - { - const gchar *str; - gchar *endptr; - unsigned long tmp; - - str = wocky_node_get_attribute (tube_node, "id"); - if (str == NULL) - { - DEBUG ("no tube id in SI request"); - return FALSE; - } - - tmp = strtoul (str, &endptr, 10); - if (!endptr || *endptr || tmp > G_MAXUINT32) - { - DEBUG ("tube id is not numeric or > 2**32: %s", str); - return FALSE; - } - *tube_id = (guint) tmp; - } - - return TRUE; -} - -struct _add_in_old_dbus_tubes_data -{ - GHashTable *old_dbus_tubes; - TpHandle contact; -}; - -static void -add_in_old_dbus_tubes (gpointer key, - gpointer value, - gpointer user_data) -{ - guint tube_id = GPOINTER_TO_UINT (key); - GabbleTubeIface *tube = GABBLE_TUBE_IFACE (value); - struct _add_in_old_dbus_tubes_data *data = - (struct _add_in_old_dbus_tubes_data *) user_data; - TpTubeType type; - - g_object_get (tube, "type", &type, NULL); - - if (type != TP_TUBE_TYPE_DBUS) - return; - - if (gabble_tube_dbus_handle_in_names (GABBLE_TUBE_DBUS (tube), - data->contact)) - { - /* contact was in this tube */ - g_hash_table_insert (data->old_dbus_tubes, GUINT_TO_POINTER (tube_id), - tube); - } -} - -struct -_emit_d_bus_names_changed_foreach_data -{ - GabbleTubesChannel *self; - TpHandle contact; -}; - -struct _ForeachData -{ - TpExportableChannelFunc foreach; - gpointer user_data; -}; - -static void -foreach_slave (gpointer key, - gpointer value, - gpointer user_data) -{ - GabbleTubeIface *tube = GABBLE_TUBE_IFACE (value); - struct _ForeachData *data = (struct _ForeachData *) user_data; - TpTubeType type; - - g_object_get (tube, "type", &type, NULL); - data->foreach (TP_EXPORTABLE_CHANNEL (tube), data->user_data); -} - -void gabble_tubes_channel_foreach (GabbleTubesChannel *self, - TpExportableChannelFunc foreach, gpointer user_data) -{ - struct _ForeachData data; - GabbleTubesChannelPrivate *priv = self->priv; - - data.user_data = user_data; - data.foreach = foreach; - - g_hash_table_foreach (priv->tubes, foreach_slave, &data); -} - -static void -emit_d_bus_names_changed_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - guint tube_id = GPOINTER_TO_UINT (key); - GabbleTubeDBus *tube = GABBLE_TUBE_DBUS (value); - struct _emit_d_bus_names_changed_foreach_data *data = - (struct _emit_d_bus_names_changed_foreach_data *) user_data; - - /* Remove from the D-Bus names mapping */ - if (gabble_tube_dbus_remove_name (tube, data->contact)) - { - /* Emit the DBusNamesChanged signal */ - d_bus_names_changed_removed (data->self, tube_id, data->contact); - } -} - -static void -contact_left_muc (GabbleTubesChannel *self, - TpHandle contact) -{ - GabbleTubesChannelPrivate *priv = self->priv; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - GHashTable *old_dbus_tubes; - struct _add_in_old_dbus_tubes_data add_data; - struct _emit_d_bus_names_changed_foreach_data emit_data; - - DEBUG ("%s left muc and so left all its tube", tp_handle_inspect ( - contact_repo, contact)); - - /* Fill old_dbus_tubes with D-BUS tubes previoulsy announced by - * the contact */ - old_dbus_tubes = g_hash_table_new (g_direct_hash, g_direct_equal); - add_data.old_dbus_tubes = old_dbus_tubes; - add_data.contact = contact; - g_hash_table_foreach (priv->tubes, add_in_old_dbus_tubes, &add_data); - - /* contact left the muc so he left all its tubes */ - emit_data.contact = contact; - emit_data.self = self; - g_hash_table_foreach (old_dbus_tubes, emit_d_bus_names_changed_foreach, - &emit_data); - - g_hash_table_unref (old_dbus_tubes); -} - -/* Called when we receive a presence from a contact who is - * in the muc associated with this tubes channel */ -void -gabble_tubes_channel_presence_updated (GabbleTubesChannel *self, - TpHandle contact, - WockyNode *pnode) -{ - GabbleTubesChannelPrivate *priv = self->priv; - WockyNode *tubes_node; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - WockyNodeIter i; - WockyNode *tube_node; - const gchar *presence_type; - GHashTable *old_dbus_tubes; - struct _add_in_old_dbus_tubes_data add_data; - struct _emit_d_bus_names_changed_foreach_data emit_data; - - if (contact == priv->self_handle) - /* We don't need to inspect our own presence */ - return; - - /* We are interested by this presence only if it contains tube information - * or indicates someone left the muc */ - presence_type = wocky_node_get_attribute (pnode, "type"); - if (!tp_strdiff (presence_type, "unavailable")) - { - contact_left_muc (self, contact); - return; - } - - tubes_node = wocky_node_get_child_ns (pnode, "tubes", NS_TUBES); - - if (tubes_node == NULL) - return; - - /* Fill old_dbus_tubes with D-BUS tubes previoulsy announced by - * the contact */ - old_dbus_tubes = g_hash_table_new (g_direct_hash, g_direct_equal); - add_data.old_dbus_tubes = old_dbus_tubes; - add_data.contact = contact; - g_hash_table_foreach (priv->tubes, add_in_old_dbus_tubes, &add_data); - - wocky_node_iter_init (&i, tubes_node, NULL, NULL); - while (wocky_node_iter_next (&i, &tube_node)) - { - const gchar *stream_id; - GabbleTubeIface *tube; - guint tube_id; - TpTubeType type; - - stream_id = wocky_node_get_attribute (tube_node, "stream-id"); - - if (!extract_tube_information (self, tube_node, NULL, - NULL, NULL, NULL, &tube_id)) - { - DEBUG ("Bad tube ID, skipping to next child of <tubes>"); - continue; - } - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - - if (tube == NULL) - { - /* We don't know yet this tube */ - const gchar *service; - TpHandle initiator_handle; - GHashTable *parameters; - - if (extract_tube_information (self, tube_node, &type, - &initiator_handle, &service, ¶meters, NULL)) - { - switch (type) - { - case TP_TUBE_TYPE_DBUS: - { - if (initiator_handle == 0) - { - DEBUG ("D-Bus tube initiator missing"); - /* skip to the next child of <tubes> */ - continue; - } - } - break; - case TP_TUBE_TYPE_STREAM: - { - if (initiator_handle != 0) - /* ignore it */ - tp_handle_unref (contact_repo, initiator_handle); - - initiator_handle = contact; - tp_handle_ref (contact_repo, initiator_handle); - } - break; - default: - { - g_return_if_reached (); - } - } - - tube = create_new_tube (self, type, initiator_handle, - service, parameters, stream_id, tube_id, NULL, FALSE); - - tp_channel_manager_emit_new_channel (priv->conn->muc_factory, - TP_EXPORTABLE_CHANNEL (tube), NULL); - - /* the tube has reffed its initiator, no need to keep a ref */ - tp_handle_unref (contact_repo, initiator_handle); - g_hash_table_unref (parameters); - } - } - else - { - /* The contact is in the tube. - * Remove it from old_dbus_tubes if needed */ - g_hash_table_remove (old_dbus_tubes, GUINT_TO_POINTER (tube_id)); - } - - if (tube == NULL) - /* skip to the next child of <tubes> */ - continue; - - g_object_get (tube, "type", &type, NULL); - - if (type == TP_TUBE_TYPE_DBUS) - { - /* Update mapping of handle -> D-Bus name. */ - if (!gabble_tube_dbus_handle_in_names (GABBLE_TUBE_DBUS (tube), - contact)) - { - /* Contact just joined the tube */ - const gchar *new_name; - - new_name = wocky_node_get_attribute (tube_node, - "dbus-name"); - - if (!new_name) - { - DEBUG ("Contact %u isn't announcing their D-Bus name", - contact); - /* skip to the next child of <tubes> */ - continue; - } - - add_name_in_dbus_names (self, tube_id, contact, new_name); - } - } - } - - /* Tubes remaining in old_dbus_tubes was left by the contact */ - emit_data.contact = contact; - emit_data.self = self; - g_hash_table_foreach (old_dbus_tubes, emit_d_bus_names_changed_foreach, - &emit_data); - - g_hash_table_unref (old_dbus_tubes); -} - -static void -copy_tube_in_ptr_array (gpointer key, - gpointer value, - gpointer user_data) -{ - GabbleTubeIface *tube = (GabbleTubeIface *) value; - guint tube_id = GPOINTER_TO_UINT (key); - TpHandle initiator; - gchar *service; - GHashTable *parameters; - TpTubeChannelState state; - TpTubeType type; - GPtrArray *array = (GPtrArray *) user_data; - GValue entry = {0,}; - - g_object_get (tube, - "state", &state, - NULL); - - /* The old interface has no way to represent unoffered tubes, so they - * shouldn't appear in the result of ListTubes() - */ - if (state == TP_TUBE_CHANNEL_STATE_NOT_OFFERED) - return; - - g_object_get (tube, - "type", &type, - "initiator-handle", &initiator, - "service", &service, - "parameters", ¶meters, - NULL); - - g_value_init (&entry, TP_STRUCT_TYPE_TUBE_INFO); - g_value_take_boxed (&entry, - dbus_g_type_specialized_construct (TP_STRUCT_TYPE_TUBE_INFO)); - dbus_g_type_struct_set (&entry, - 0, tube_id, - 1, initiator, - 2, type, - 3, service, - 4, parameters, - 5, state, - G_MAXUINT); - - g_ptr_array_add (array, g_value_get_boxed (&entry)); - g_free (service); - g_hash_table_unref (parameters); -} - -static GPtrArray * -make_tubes_ptr_array (GabbleTubesChannel *self, - GHashTable *tubes) -{ - GPtrArray *ret; - - ret = g_ptr_array_sized_new (g_hash_table_size (tubes)); - - g_hash_table_foreach (tubes, copy_tube_in_ptr_array, ret); - - return ret; -} - -/** - * gabble_tubes_channel_get_available_tube_types - * - * Implements D-Bus method GetAvailableTubeTypes - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_get_available_tube_types (TpSvcChannelTypeTubes *iface, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GArray *ret; - TpTubeType type; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - ret = g_array_sized_new (FALSE, FALSE, sizeof (TpTubeType), 1); - type = TP_TUBE_TYPE_DBUS; - g_array_append_val (ret, type); - type = TP_TUBE_TYPE_STREAM; - g_array_append_val (ret, type); - - tp_svc_channel_type_tubes_return_from_get_available_tube_types (context, - ret); - - g_array_unref (ret); -} - -/** - * gabble_tubes_channel_list_tubes - * - * Implements D-Bus method ListTubes - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_list_tubes (TpSvcChannelTypeTubes *iface, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - GPtrArray *ret; - guint i; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - ret = make_tubes_ptr_array (self, priv->tubes); - tp_svc_channel_type_tubes_return_from_list_tubes (context, ret); - - for (i = 0; i < ret->len; i++) - g_boxed_free (TP_STRUCT_TYPE_TUBE_INFO, ret->pdata[i]); - - g_ptr_array_unref (ret); -} - -struct _i_hate_g_hash_table_foreach -{ - GabbleTubesChannel *self; - WockyNode *tubes_node; -}; - -static void -publish_tubes_in_node (gpointer key, - gpointer value, - gpointer user_data) -{ - GabbleTubeIface *tube = (GabbleTubeIface *) value; - struct _i_hate_g_hash_table_foreach *data = - (struct _i_hate_g_hash_table_foreach *) user_data; - GabbleTubesChannelPrivate *priv = data->self->priv; - TpTubeChannelState state; - WockyNode *tube_node; - TpTubeType type; - TpHandle initiator; - - if (tube == NULL) - return; - - g_object_get (tube, - "state", &state, - "type", &type, - "initiator-handle", &initiator, - NULL); - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - return; - - if (type == TP_TUBE_TYPE_STREAM && initiator != priv->self_handle) - /* We only announce stream tubes we initiated */ - return; - - tube_node = wocky_node_add_child_with_content (data->tubes_node, "tube", NULL); - gabble_tube_iface_publish_in_node (tube, (TpBaseConnection *) priv->conn, - tube_node); -} - -static void -pre_presence_cb (GabbleMucChannel *muc, - WockyStanza *msg, - GabbleTubesChannel *self) -{ - GabbleTubesChannelPrivate *priv = self->priv; - struct _i_hate_g_hash_table_foreach data; - WockyNode *node; - - /* Augment the muc presence with tubes information */ - node = wocky_node_add_child_with_content ( - wocky_stanza_get_top_node (msg), "tubes", NULL); - node->ns = g_quark_from_string (NS_TUBES); - data.self = self; - data.tubes_node = node; - - g_hash_table_foreach (priv->tubes, publish_tubes_in_node, &data); -} - -static void -update_tubes_presence (GabbleTubesChannel *self) -{ - GabbleTubesChannelPrivate *priv = self->priv; - - if (priv->handle_type != TP_HANDLE_TYPE_ROOM) - return; - - gabble_muc_channel_send_presence (self->muc); -} - -/* Called when we receive a SI request, - * via gabble_tubes_factory_handle_si_tube_request - */ -void -gabble_tubes_channel_tube_si_offered (GabbleTubesChannel *self, - GabbleBytestreamIface *bytestream, - WockyStanza *msg) -{ - GabbleTubesChannelPrivate *priv = self->priv; - const gchar *service, *stream_id; - GHashTable *parameters; - TpTubeType type; - WockyNode *si_node, *tube_node; - guint tube_id; - GabbleTubeIface *tube; - WockyStanzaType stanza_type; - WockyStanzaSubType sub_type; - - /* Caller is expected to have checked that we have a SI node with - * a stream ID, the TUBES profile and a <tube> element - */ - wocky_stanza_get_type_info (msg, &stanza_type, &sub_type); - g_return_if_fail (stanza_type == WOCKY_STANZA_TYPE_IQ); - g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); - si_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (msg), "si", NS_SI); - g_return_if_fail (si_node != NULL); - stream_id = wocky_node_get_attribute (si_node, "id"); - g_return_if_fail (stream_id != NULL); - tube_node = wocky_node_get_child_ns (si_node, "tube", - NS_TUBES); - g_return_if_fail (tube_node != NULL); - - if (!extract_tube_information (self, tube_node, NULL, NULL, - NULL, NULL, &tube_id)) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<tube> has no id attribute" }; - - NODE_DEBUG (tube_node, e.message); - gabble_bytestream_iface_close (bytestream, &e); - return; - } - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube != NULL) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "tube ID already in use" }; - - NODE_DEBUG (tube_node, e.message); - gabble_bytestream_iface_close (bytestream, &e); - return; - } - - /* New tube */ - if (!extract_tube_information (self, tube_node, &type, NULL, - &service, ¶meters, NULL)) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "can't extract <tube> information from SI request" }; - - NODE_DEBUG (tube_node, e.message); - gabble_bytestream_iface_close (bytestream, &e); - g_hash_table_unref (parameters); - return; - } - - if (type != TP_TUBE_TYPE_DBUS) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_FORBIDDEN, - "Only D-Bus tubes are allowed to be created using SI" }; - - DEBUG ("%s", e.message); - gabble_bytestream_iface_close (bytestream, &e); - return; - } - - tube = create_new_tube (self, type, priv->handle, service, - parameters, stream_id, tube_id, (GabbleBytestreamIface *) bytestream, - FALSE); - - tp_channel_manager_emit_new_channel (priv->conn->private_tubes_factory, - TP_EXPORTABLE_CHANNEL (tube), NULL); - - g_hash_table_unref (parameters); -} - -/* Called when we receive a SI request, - * via either gabble_muc_factory_handle_si_stream_request or - * gabble_tubes_factory_handle_si_stream_request - */ -void -gabble_tubes_channel_bytestream_offered (GabbleTubesChannel *self, - GabbleBytestreamIface *bytestream, - WockyStanza *msg) -{ - GabbleTubesChannelPrivate *priv = self->priv; - const gchar *stream_id, *tmp; - gchar *endptr; - WockyNode *si_node, *stream_node; - guint tube_id; - unsigned long tube_id_tmp; - GabbleTubeIface *tube; - WockyStanzaType stanza_type; - WockyStanzaSubType sub_type; - - /* Caller is expected to have checked that we have a stream or muc-stream - * node with a stream ID and the TUBES profile - */ - wocky_stanza_get_type_info (msg, &stanza_type, &sub_type); - g_return_if_fail (stanza_type == WOCKY_STANZA_TYPE_IQ); - g_return_if_fail (sub_type == WOCKY_STANZA_SUB_TYPE_SET); - - si_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (msg), "si", NS_SI); - g_return_if_fail (si_node != NULL); - - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - stream_node = wocky_node_get_child_ns (si_node, - "stream", NS_TUBES); - else - stream_node = wocky_node_get_child_ns (si_node, - "muc-stream", NS_TUBES); - g_return_if_fail (stream_node != NULL); - - stream_id = wocky_node_get_attribute (si_node, "id"); - g_return_if_fail (stream_id != NULL); - - tmp = wocky_node_get_attribute (stream_node, "tube"); - if (tmp == NULL) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<stream> or <muc-stream> has no tube attribute" }; - - NODE_DEBUG (stream_node, e.message); - gabble_bytestream_iface_close (bytestream, &e); - return; - } - tube_id_tmp = strtoul (tmp, &endptr, 10); - if (!endptr || *endptr || tube_id_tmp > G_MAXUINT32) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<stream> or <muc-stream> tube attribute not numeric or > 2**32" }; - - DEBUG ("tube id is not numeric or > 2**32: %s", tmp); - gabble_bytestream_iface_close (bytestream, &e); - return; - } - tube_id = (guint) tube_id_tmp; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - { - GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "<stream> or <muc-stream> tube attribute points to a nonexistent " - "tube" }; - - DEBUG ("tube %u doesn't exist", tube_id); - gabble_bytestream_iface_close (bytestream, &e); - return; - } - - DEBUG ("received new bytestream request for existing tube: %u", tube_id); - - gabble_tube_iface_add_bytestream (tube, bytestream); -} - - -static void -send_tube_close_msg (GabbleTubesChannel *self, - guint tube_id) -{ - GabbleTubesChannelPrivate *priv = self->priv; - WockyStanza *msg; - const gchar *jid; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - gchar *id_str; - - jid = tp_handle_inspect (contact_repo, priv->handle); - id_str = g_strdup_printf ("%u", tube_id); - - /* Send the close message */ - msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, - NULL, jid, - '(', "close", - ':', NS_TUBES, - '@', "tube", id_str, - ')', - GABBLE_AMP_DO_NOT_STORE_SPEC, - NULL); - g_free (id_str); - - _gabble_connection_send (priv->conn, msg, NULL); - - g_object_unref (msg); -} - -static void -tube_msg_offered (GabbleTubesChannel *self, - WockyStanza *msg, - WockyNode *tube_node) -{ - GabbleTubesChannelPrivate *priv = self->priv; - const gchar *service; - GHashTable *parameters; - TpTubeType type; - guint tube_id; - GabbleTubeIface *tube; - WockyStanzaType stanza_type; - - wocky_stanza_get_type_info (msg, &stanza_type, NULL); - g_return_if_fail (stanza_type == WOCKY_STANZA_TYPE_MESSAGE); - - if (!extract_tube_information (self, tube_node, NULL, NULL, - NULL, NULL, &tube_id)) - { - DEBUG ("<tube> has no id attribute"); - /* We can't send a close message as reply so just ignore it */ - return; - } - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube != NULL) - { - DEBUG ("tube ID already in use. Do not open the offered tube and close " - "the existing tube id %u", tube_id); - gabble_tube_iface_close (tube, FALSE); - return; - } - - /* New tube */ - if (!extract_tube_information (self, tube_node, &type, NULL, - &service, ¶meters, NULL)) - { - DEBUG ("can't extract <tube> information from message"); - send_tube_close_msg (self, tube_id); - return; - } - - if (type != TP_TUBE_TYPE_STREAM) - { - DEBUG ("Only stream tubes are allowed to be created using messages"); - send_tube_close_msg (self, tube_id); - return; - } - - tube = create_new_tube (self, type, priv->handle, service, - parameters, NULL, tube_id, NULL, FALSE); - - tp_channel_manager_emit_new_channel (priv->conn->private_tubes_factory, - TP_EXPORTABLE_CHANNEL (tube), NULL); - - g_hash_table_unref (parameters); -} - -static void -tube_msg_close (GabbleTubesChannel *self, - WockyStanza *msg, - WockyNode *close_node) -{ - GabbleTubesChannelPrivate *priv = self->priv; - guint tube_id; - const gchar *tmp; - gchar *endptr; - GabbleTubeIface *tube; - TpTubeType type; - - tmp = wocky_node_get_attribute (close_node, "tube"); - if (tmp == NULL) - { - DEBUG ("no tube id in close message"); - return; - } - - tube_id = (guint) strtoul (tmp, &endptr, 10); - if (!endptr || *endptr || tube_id > G_MAXUINT32) - { - DEBUG ("tube id is not numeric or > 2**32: %s", tmp); - return; - } - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); - if (tube == NULL) - { - DEBUG ("<close> tube attribute points to a nonexistent tube"); - return; - } - - g_object_get (tube, "type", &type, NULL); - if (type != TP_TUBE_TYPE_STREAM) - { - DEBUG ("Only stream tubes can be closed using a close message"); - return; - } - - DEBUG ("tube %u was closed by remote peer", tube_id); - gabble_tube_iface_close (tube, TRUE); -} - -void -gabble_tubes_channel_tube_msg (GabbleTubesChannel *self, - WockyStanza *msg) -{ - WockyNode *node; - - node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (msg), "tube", NS_TUBES); - if (node != NULL) - { - tube_msg_offered (self, msg, node); - return; - } - - node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (msg), "close", NS_TUBES); - if (node != NULL) - { - tube_msg_close (self, msg, node); - return; - } -} - -static guint -generate_tube_id (void) -{ - /* We don't generate IDs in the top half of the range, to be nice to - * older Gabble versions. */ - return g_random_int_range (0, G_MAXINT); -} - -GabbleTubeIface *gabble_tubes_channel_tube_request (GabbleTubesChannel *self, - gpointer request_token, GHashTable *request_properties, - gboolean require_new) -{ - GabbleTubesChannelPrivate *priv = self->priv; - GabbleTubeIface *tube; - const gchar *channel_type; - const gchar *service; - GHashTable *parameters = NULL; - guint tube_id; - gchar *stream_id; - TpTubeType type; - - tube_id = generate_tube_id (); - - channel_type = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL ".ChannelType"); - - if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) - { - type = TP_TUBE_TYPE_STREAM; - service = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL_TYPE_STREAM_TUBE ".Service"); - - } - else if (! tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE)) - { - type = TP_TUBE_TYPE_DBUS; - service = tp_asv_get_string (request_properties, - TP_IFACE_CHANNEL_TYPE_DBUS_TUBE ".ServiceName"); - } - else - /* This assertion is safe: this function's caller only calls it in one of - * the above cases. - * FIXME: but it would be better to pass an enum member or something maybe. - */ - g_assert_not_reached (); - - /* requested tubes have an empty parameters dict */ - parameters = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - (GDestroyNotify) tp_g_value_slice_free); - - /* if the service property is missing, the requestotron rejects the request - */ - g_assert (service != NULL); - - DEBUG ("Request a tube channel with type='%s' and service='%s'", - channel_type, service); - - stream_id = gabble_bytestream_factory_generate_stream_id (); - tube = create_new_tube (self, type, priv->self_handle, service, - parameters, stream_id, tube_id, NULL, TRUE); - g_free (stream_id); - g_hash_table_unref (parameters); - - return tube; -} - -/** - * gabble_tubes_channel_offer_d_bus_tube - * - * Implements D-Bus method OfferDBusTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_offer_d_bus_tube (TpSvcChannelTypeTubes *iface, - const gchar *service, - GHashTable *parameters, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - guint tube_id; - GabbleTubeIface *tube; - gchar *stream_id; - GError *error = NULL; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - stream_id = gabble_bytestream_factory_generate_stream_id (); - tube_id = generate_tube_id (); - - tube = create_new_tube (self, TP_TUBE_TYPE_DBUS, priv->self_handle, - service, parameters, (const gchar *) stream_id, tube_id, NULL, TRUE); - - if (!gabble_tube_dbus_offer (GABBLE_TUBE_DBUS (tube), &error)) - { - gabble_tube_iface_close (tube, TRUE); - dbus_g_method_return_error (context, error); - - g_error_free (error); - g_free (stream_id); - return; - } - - tp_svc_channel_type_tubes_return_from_offer_d_bus_tube (context, tube_id); - - g_free (stream_id); -} - -static void -stream_unix_tube_new_connection_cb (GabbleTubeIface *tube, - guint contact, - gpointer user_data) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (user_data); - guint tube_id; - TpTubeType type; - - g_object_get (tube, - "id", &tube_id, - "type", &type, - NULL); - - g_assert (type == TP_TUBE_TYPE_STREAM); - - tp_svc_channel_type_tubes_emit_stream_tube_new_connection (self, - tube_id, contact); -} - -/** - * gabble_tubes_channel_offer_stream_tube - * - * Implements D-Bus method OfferStreamTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_offer_stream_tube (TpSvcChannelTypeTubes *iface, - const gchar *service, - GHashTable *parameters, - guint address_type, - const GValue *address, - guint access_control, - const GValue *access_control_param, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - guint tube_id; - GabbleTubeIface *tube; - gchar *stream_id; - GError *error = NULL; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - if (!gabble_tube_stream_check_params (address_type, address, - access_control, access_control_param, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - stream_id = gabble_bytestream_factory_generate_stream_id (); - tube_id = generate_tube_id (); - - tube = create_new_tube (self, TP_TUBE_TYPE_STREAM, priv->self_handle, - service, parameters, (const gchar *) stream_id, tube_id, NULL, TRUE); - - g_object_set (tube, - "address-type", address_type, - "address", address, - "access-control", access_control, - "access-control-param", access_control_param, - NULL); - - /* Tube was created using the old API so is already offered */ - if (!gabble_tube_stream_offer (GABBLE_TUBE_STREAM (tube), &error)) - { - gabble_tube_iface_close (tube, TRUE); - - dbus_g_method_return_error (context, error); - - g_error_free (error); - g_free (stream_id); - return; - } - - g_signal_connect (tube, "tube-new-connection", - G_CALLBACK (stream_unix_tube_new_connection_cb), self); - - /* announce the new tube channel we just created (new tube API) */ - if (priv->handle_type == TP_HANDLE_TYPE_CONTACT) - { - tp_channel_manager_emit_new_channel (priv->conn->private_tubes_factory, - TP_EXPORTABLE_CHANNEL (tube), NULL); - } - else - { - tp_channel_manager_emit_new_channel (priv->conn->muc_factory, - TP_EXPORTABLE_CHANNEL (tube), NULL); - } - - tp_svc_channel_type_tubes_return_from_offer_stream_tube (context, - tube_id); - - g_free (stream_id); -} - -/** - * gabble_tubes_channel_accept_d_bus_tube - * - * Implements D-Bus method AcceptDBusTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_accept_d_bus_tube (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - GabbleTubeIface *tube; - TpTubeChannelState state; - TpTubeType type; - gchar *addr; - GError *error = NULL; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &e); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_DBUS) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a D-Bus tube" }; - - dbus_g_method_return_error (context, &e); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Tube is not in the local pending state" }; - - dbus_g_method_return_error (context, &e); - return; - } - - if (!gabble_tube_iface_accept (tube, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - g_object_get (tube, "dbus-address", &addr, NULL); - tp_svc_channel_type_tubes_return_from_accept_d_bus_tube (context, addr); - g_free (addr); -} - -/** - * gabble_tubes_channel_accept_stream_tube - * - * Implements D-Bus method AcceptStreamTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_accept_stream_tube (TpSvcChannelTypeTubes *iface, - guint id, - guint address_type, - guint access_control, - const GValue *access_control_param, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - GabbleTubeIface *tube; - TpTubeChannelState state; - TpTubeType type; - GValue *address; - GError *error = NULL; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &e); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_STREAM) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a stream tube" }; - - dbus_g_method_return_error (context, &e); - return; - } - - /* most parameters sanity checks are done in gabble_tube_stream_accept, - * but at least check that they fit the properties requirements */ - if (address_type != TP_SOCKET_ADDRESS_TYPE_UNIX && - address_type != TP_SOCKET_ADDRESS_TYPE_IPV4 && - address_type != TP_SOCKET_ADDRESS_TYPE_IPV6) - { - GError e = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Address type not implemented" }; - - dbus_g_method_return_error (context, &e); - return; - } - g_object_set (tube, - "address-type", address_type, - "access-control", access_control, - "access-control-param", access_control_param, - NULL); - - if (!gabble_tube_iface_accept (tube, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - update_tubes_presence (self); - - g_object_get (tube, "address", &address, NULL); - - tp_svc_channel_type_tubes_return_from_accept_stream_tube (context, - address); -} - -/** - * gabble_tubes_channel_close_tube - * - * Implements D-Bus method CloseTube - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_close_tube (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - GabbleTubeIface *tube; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - - if (tube == NULL) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - gabble_tube_iface_close (tube, FALSE); - - tp_svc_channel_type_tubes_return_from_close_tube (context); -} - -/** - * gabble_tubes_channel_get_d_bus_tube_address - * - * Implements D-Bus method GetDBusTubeAddress - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_get_d_bus_tube_address (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - GabbleTubeIface *tube; - gchar *addr; - TpTubeType type; - TpTubeChannelState state; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - priv = self->priv; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - - if (tube == NULL) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_DBUS) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a D-Bus tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, "dbus-address", &addr, NULL); - tp_svc_channel_type_tubes_return_from_get_d_bus_tube_address (context, - addr); - g_free (addr); -} - -static void -get_d_bus_names_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - GPtrArray *ret = user_data; - GValue tmp = {0,}; - - g_value_init (&tmp, TP_STRUCT_TYPE_DBUS_TUBE_MEMBER); - g_value_take_boxed (&tmp, - dbus_g_type_specialized_construct (TP_STRUCT_TYPE_DBUS_TUBE_MEMBER)); - dbus_g_type_struct_set (&tmp, - 0, key, - 1, value, - G_MAXUINT); - g_ptr_array_add (ret, g_value_get_boxed (&tmp)); -} - -/** - * gabble_tubes_channel_get_d_bus_names - * - * Implements D-Bus method GetDBusNames - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_get_d_bus_names (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv = self->priv; - GabbleTubeIface *tube; - GHashTable *names; - GPtrArray *ret; - TpTubeType type; - TpTubeChannelState state; - guint i; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - - if (tube == NULL) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_DBUS || - priv->handle_type != TP_HANDLE_TYPE_ROOM) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a Muc D-Bus tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - { - GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Tube is not open" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, "dbus-names", &names, NULL); - g_assert (names); - - ret = g_ptr_array_sized_new (g_hash_table_size (names)); - g_hash_table_foreach (names, get_d_bus_names_foreach, ret); - - tp_svc_channel_type_tubes_return_from_get_d_bus_names (context, ret); - - for (i = 0; i < ret->len; i++) - g_boxed_free (TP_STRUCT_TYPE_DBUS_TUBE_MEMBER, ret->pdata[i]); - g_hash_table_unref (names); - g_ptr_array_unref (ret); -} - -/** - * gabble_tubes_channel_get_stream_tube_socket_address - * - * Implements D-Bus method GetStreamTubeSocketAddress - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_get_stream_tube_socket_address (TpSvcChannelTypeTubes *iface, - guint id, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv = self->priv; - GabbleTubeIface *tube; - TpTubeType type; - TpTubeChannelState state; - TpSocketAddressType address_type; - GValue *address; - - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (id)); - if (tube == NULL) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, "Unknown tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "type", &type, - "state", &state, - NULL); - - if (type != TP_TUBE_TYPE_STREAM) - { - GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT, - "Tube is not a Stream tube" }; - - dbus_g_method_return_error (context, &error); - return; - } - - if (state != TP_TUBE_CHANNEL_STATE_OPEN) - { - GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, - "Tube is not open" }; - - dbus_g_method_return_error (context, &error); - return; - } - - g_object_get (tube, - "address-type", &address_type, - "address", &address, - NULL); - - tp_svc_channel_type_tubes_return_from_get_stream_tube_socket_address ( - context, address_type, address); -} - -/** - * gabble_tubes_channel_get_available_stream_tube_types - * - * Implements D-Bus method GetAvailableStreamTubeTypes - * on org.freedesktop.Telepathy.Channel.Type.Tubes - */ -static void -gabble_tubes_channel_get_available_stream_tube_types (TpSvcChannelTypeTubes *iface, - DBusGMethodInvocation *context) -{ - GHashTable *ret; - - ret = gabble_tube_stream_get_supported_socket_types (); - - tp_svc_channel_type_tubes_return_from_get_available_stream_tube_types ( - context, ret); - - g_hash_table_unref (ret); -} - -static void -emit_tube_closed_signal (gpointer key, - gpointer value, - gpointer user_data) -{ - guint id = GPOINTER_TO_UINT (key); - GabbleTubesChannel *self = (GabbleTubesChannel *) user_data; - - tp_svc_channel_type_tubes_emit_tube_closed (self, id); -} - -void -gabble_tubes_channel_close (GabbleTubesChannel *self) -{ - GabbleTubesChannelPrivate *priv; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - DEBUG ("called on %p", self); - - priv = self->priv; - - if (priv->closed) - { - return; - } - - priv->closed = TRUE; - - g_hash_table_foreach (priv->tubes, emit_tube_closed_signal, self); - g_hash_table_unref (priv->tubes); - - priv->tubes = NULL; - - tp_svc_channel_emit_closed (self); -} - -/** - * gabble_tubes_channel_close_async: - * - * Implements D-Bus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_tubes_channel_close_async (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - - gabble_tubes_channel_close (self); - tp_svc_channel_return_from_close (context); -} - -/** - * gabble_tubes_channel_get_channel_type - * - * Implements D-Bus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_tubes_channel_get_channel_type (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_TUBES); -} - -/** - * gabble_tubes_channel_get_handle - * - * Implements D-Bus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_tubes_channel_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - GabbleTubesChannelPrivate *priv; - - g_assert (GABBLE_IS_TUBES_CHANNEL (self)); - priv = self->priv; - - tp_svc_channel_return_from_get_handle (context, priv->handle_type, - priv->handle); -} - -/** - * gabble_tubes_channel_get_interfaces - * - * Implements D-Bus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_tubes_channel_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (iface); - - if (self->muc) - { - tp_svc_channel_return_from_get_interfaces (context, - gabble_tubes_channel_interfaces); - } - else - { - /* omit the Group interface */ - tp_svc_channel_return_from_get_interfaces (context, - gabble_tubes_channel_interfaces + 1); - } -} - -static void gabble_tubes_channel_dispose (GObject *object); -static void gabble_tubes_channel_finalize (GObject *object); - -static void -gabble_tubes_channel_class_init ( - GabbleTubesChannelClass *gabble_tubes_channel_class) -{ - static TpDBusPropertiesMixinPropImpl channel_props[] = { - { "TargetHandleType", "handle-type", NULL }, - { "TargetHandle", "handle", NULL }, - { "TargetID", "target-id", NULL }, - { "ChannelType", "channel-type", NULL }, - { "Interfaces", "interfaces", NULL }, - { "Requested", "requested", NULL }, - { "InitiatorHandle", "initiator-handle", NULL }, - { "InitiatorID", "initiator-id", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, - { NULL } - }; - GObjectClass *object_class = G_OBJECT_CLASS (gabble_tubes_channel_class); - GParamSpec *param_spec; - - g_type_class_add_private (gabble_tubes_channel_class, - sizeof (GabbleTubesChannelPrivate)); - - object_class->constructor = gabble_tubes_channel_constructor; - - object_class->get_property = gabble_tubes_channel_get_property; - object_class->set_property = gabble_tubes_channel_set_property; - - object_class->dispose = gabble_tubes_channel_dispose; - object_class->finalize = gabble_tubes_channel_finalize; - - g_object_class_override_property (object_class, PROP_OBJECT_PATH, - "object-path"); - g_object_class_override_property (object_class, PROP_CHANNEL_TYPE, - "channel-type"); - g_object_class_override_property (object_class, PROP_HANDLE_TYPE, - "handle-type"); - g_object_class_override_property (object_class, PROP_HANDLE, "handle"); - - g_object_class_override_property (object_class, PROP_CHANNEL_DESTROYED, - "channel-destroyed"); - g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES, - "channel-properties"); - - param_spec = g_param_spec_object ( - "connection", - "GabbleConnection object", - "Gabble connection object that owns this Tubes channel object.", - GABBLE_TYPE_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); - - param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces", - "Additional Channel.Interface.* interfaces", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INTERFACES, param_spec); - - param_spec = g_param_spec_object ( - "muc", - "GabbleMucChannel object", - "Gabble text MUC channel corresponding to this Tubes channel object, " - "if the handle type is ROOM.", - GABBLE_TYPE_MUC_CHANNEL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MUC, param_spec); - - param_spec = g_param_spec_string ("target-id", "Target JID", - "The string obtained by inspecting the target handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec); - - param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle", - "The contact who initiated the channel", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE, - param_spec); - - param_spec = g_param_spec_string ("initiator-id", "Initiator's bare JID", - "The string obtained by inspecting the initiator-handle", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIATOR_ID, - param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, param_spec); - - gabble_tubes_channel_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleTubesChannelClass, dbus_props_class)); - - tp_external_group_mixin_init_dbus_properties (object_class); -} - -void -gabble_tubes_channel_dispose (GObject *object) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (object); - GabbleTubesChannelPrivate *priv = self->priv; - TpHandleRepoIface *handle_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, priv->handle_type); - - if (priv->dispose_has_run) - return; - - priv->dispose_has_run = TRUE; - - tp_handle_unref (handle_repo, priv->handle); - - if (self->muc != NULL) - { - g_signal_handler_disconnect (self->muc, priv->pre_presence_signal); - - tp_external_group_mixin_finalize (object); - } - gabble_tubes_channel_close (self); - - g_assert (priv->closed); - g_assert (priv->tubes == NULL); - - if (G_OBJECT_CLASS (gabble_tubes_channel_parent_class)->dispose) - G_OBJECT_CLASS (gabble_tubes_channel_parent_class)->dispose (object); -} - -void -gabble_tubes_channel_finalize (GObject *object) -{ - GabbleTubesChannel *self = GABBLE_TUBES_CHANNEL (object); - GabbleTubesChannelPrivate *priv = self->priv; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - - g_free (priv->object_path); - - if (priv->initiator != 0) - tp_handle_unref (contact_handles, priv->initiator); - - G_OBJECT_CLASS (gabble_tubes_channel_parent_class)->finalize (object); -} - -static void -tubes_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelTypeTubesClass *klass = (TpSvcChannelTypeTubesClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_type_tubes_implement_##x (\ - klass, gabble_tubes_channel_##x) - IMPLEMENT(get_available_tube_types); - IMPLEMENT(list_tubes); - IMPLEMENT(close_tube); - IMPLEMENT(offer_d_bus_tube); - IMPLEMENT(accept_d_bus_tube); - IMPLEMENT(get_d_bus_tube_address); - IMPLEMENT(get_d_bus_names); - IMPLEMENT(offer_stream_tube); - IMPLEMENT(accept_stream_tube); - IMPLEMENT(get_stream_tube_socket_address); - IMPLEMENT(get_available_stream_tube_types); -#undef IMPLEMENT -} - -static void -channel_iface_init (gpointer g_iface, - gpointer iface_data) -{ - TpSvcChannelClass *klass = (TpSvcChannelClass *) g_iface; - -#define IMPLEMENT(x, suffix) tp_svc_channel_implement_##x (\ - klass, gabble_tubes_channel_##x##suffix) - IMPLEMENT(close,_async); - IMPLEMENT(get_channel_type,); - IMPLEMENT(get_handle,); - IMPLEMENT(get_interfaces,); -#undef IMPLEMENT -} diff --git a/src/tubes-channel.h b/src/tubes-channel.h deleted file mode 100644 index dbf7d5fd4..000000000 --- a/src/tubes-channel.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * tubes-channel.h - Header for GabbleTubesChannel - * Copyright (C) 2007 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __GABBLE_TUBES_CHANNEL_H__ -#define __GABBLE_TUBES_CHANNEL_H__ - -#include <glib-object.h> -#include <wocky/wocky.h> -#include <telepathy-glib/base-connection.h> -#include <telepathy-glib/exportable-channel.h> - -#include "bytestream-iface.h" -#include "muc-channel.h" -#include "tube-iface.h" -#include "types.h" - -G_BEGIN_DECLS - -typedef struct _GabbleTubesChannelPrivate GabbleTubesChannelPrivate; -typedef struct _GabbleTubesChannelClass GabbleTubesChannelClass; - -struct _GabbleTubesChannelClass { - GObjectClass parent_class; - - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _GabbleTubesChannel { - GObject parent; - - GabbleMucChannel *muc; - - GabbleTubesChannelPrivate *priv; -}; - -GType gabble_tubes_channel_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_TUBES_CHANNEL \ - (gabble_tubes_channel_get_type ()) -#define GABBLE_TUBES_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_TUBES_CHANNEL,\ - GabbleTubesChannel)) -#define GABBLE_TUBES_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_TUBES_CHANNEL,\ - GabbleTubesChannelClass)) -#define GABBLE_IS_TUBES_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_TUBES_CHANNEL)) -#define GABBLE_IS_TUBES_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_TUBES_CHANNEL)) -#define GABBLE_TUBES_CHANNEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_TUBES_CHANNEL,\ - GabbleTubesChannelClass)) - -void gabble_tubes_channel_foreach (GabbleTubesChannel *self, - TpExportableChannelFunc foreach, gpointer user_data); - -GabbleTubeIface *gabble_tubes_channel_tube_request (GabbleTubesChannel *self, - gpointer request_token, GHashTable *request_properties, - gboolean require_new); - -void gabble_tubes_channel_presence_updated (GabbleTubesChannel *chan, - TpHandle contact, WockyNode *presence); - -void gabble_tubes_channel_tube_si_offered (GabbleTubesChannel *chan, - GabbleBytestreamIface *bytestream, WockyStanza *msg); - -void gabble_tubes_channel_bytestream_offered (GabbleTubesChannel *chan, - GabbleBytestreamIface *bytestream, WockyStanza *msg); - -void gabble_tubes_channel_tube_msg (GabbleTubesChannel *chan, WockyStanza *msg); - -void gabble_tubes_channel_close (GabbleTubesChannel *self); - -G_END_DECLS - -#endif /* #ifndef __GABBLE_TUBES_CHANNEL_H__*/ diff --git a/src/types.h b/src/types.h index 1c9de3f1a..977ff3fb7 100644 --- a/src/types.h +++ b/src/types.h @@ -24,7 +24,7 @@ #include "config.h" -#include <telepathy-glib/handle.h> +#include <telepathy-glib/telepathy-glib.h> #include "gabble/types.h" diff --git a/src/util.c b/src/util.c index 4102f2194..b36f5745a 100644 --- a/src/util.c +++ b/src/util.c @@ -31,13 +31,11 @@ #include <gobject/gvaluecollector.h> #include <wocky/wocky.h> -#include <telepathy-glib/handle-repo-dynamic.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/gtypes.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #define DEBUG_FLAG GABBLE_DEBUG_JID -#include "base64.h" #include "conn-aliasing.h" #include "connection.h" #include "debug.h" @@ -134,16 +132,6 @@ gabble_generate_id (void) return str; } - -static void -lm_message_node_add_nick (WockyNode *node, const gchar *nick) -{ - WockyNode *nick_node; - - nick_node = wocky_node_add_child_with_content (node, "nick", nick); - nick_node->ns = g_quark_from_string (NS_NICK); -} - void lm_message_node_add_own_nick (WockyNode *node, GabbleConnection *connection) @@ -153,10 +141,11 @@ lm_message_node_add_own_nick (WockyNode *node, TpBaseConnection *base = (TpBaseConnection *) connection; source = _gabble_connection_get_cached_alias (connection, - base->self_handle, &nick); + tp_base_connection_get_self_handle (base), &nick); if (source > GABBLE_CONNECTION_ALIAS_FROM_JID) - lm_message_node_add_nick (node, nick); + wocky_node_add_child_with_content_ns_q (node, "nick", nick, + g_quark_from_static_string (NS_NICK)); g_free (nick); } @@ -193,7 +182,7 @@ gabble_get_room_handle_from_jid (TpHandleRepoIface *room_repo, #define INVALID_HANDLE(e, f, ...) \ G_STMT_START { \ DEBUG (f, ##__VA_ARGS__); \ - g_set_error (e, TP_ERRORS, TP_ERROR_INVALID_HANDLE, f, ##__VA_ARGS__);\ + g_set_error (e, TP_ERROR, TP_ERROR_INVALID_HANDLE, f, ##__VA_ARGS__);\ } G_STMT_END gchar * @@ -404,19 +393,20 @@ lm_message_node_extract_properties (WockyNode *node, if (0 == strcmp (type, "bytes")) { GArray *arr; - GString *decoded; + guchar *st; + gsize outlen; - decoded = base64_decode (value); - if (!decoded) + st = g_base64_decode (value, &outlen); + if (!st) continue; arr = g_array_new (FALSE, FALSE, sizeof (guchar)); - g_array_append_vals (arr, decoded->str, decoded->len); + g_array_append_vals (arr, st, outlen); gvalue = g_slice_new0 (GValue); g_value_init (gvalue, DBUS_TYPE_G_UCHAR_ARRAY); g_value_take_boxed (gvalue, arr); g_hash_table_insert (properties, g_strdup (name), gvalue); - g_string_free (decoded, TRUE); + g_free (st); } else if (0 == strcmp (type, "str")) { @@ -512,7 +502,7 @@ set_child_from_property (gpointer key, return; } - child = wocky_node_add_child_with_content (data->node, data->prop, ""); + child = wocky_node_add_child (data->node, data->prop); if (G_VALUE_TYPE (gvalue) == G_TYPE_STRING) { @@ -526,7 +516,7 @@ set_child_from_property (gpointer key, type = "bytes"; arr = g_value_get_boxed (gvalue); - str = base64_encode (arr->len, arr->data, FALSE); + str = g_base64_encode ((guchar *) arr->data, arr->len); wocky_node_set_content (child, str); g_free (str); @@ -824,7 +814,7 @@ jingle_pick_best_resource (GabbleConnection *conn, gboolean want_audio, gboolean want_video, const char **transport_ns, - JingleDialect *dialect, + WockyJingleDialect *dialect, const gchar **resource_out) { /* We prefer gtalk-p2p to ice, because it can use tcp and https relays (if @@ -848,7 +838,7 @@ jingle_pick_best_resource (GabbleConnection *conn, return FALSE; } - *dialect = JINGLE_DIALECT_ERROR; + *dialect = WOCKY_JINGLE_DIALECT_ERROR; *transport_ns = NULL; g_return_val_if_fail (want_audio || want_video, FALSE); @@ -866,7 +856,7 @@ jingle_pick_best_resource (GabbleConnection *conn, if (jingle_pick_resource_or_bare_jid (presence, caps, &resource)) { - *dialect = JINGLE_DIALECT_V032; + *dialect = WOCKY_JINGLE_DIALECT_V032; goto CHOOSE_TRANSPORT; } @@ -880,7 +870,7 @@ jingle_pick_best_resource (GabbleConnection *conn, if (jingle_pick_resource_or_bare_jid (presence, caps, &resource)) { - *dialect = JINGLE_DIALECT_V015; + *dialect = WOCKY_JINGLE_DIALECT_V015; goto CHOOSE_TRANSPORT; } @@ -900,7 +890,7 @@ jingle_pick_best_resource (GabbleConnection *conn, if (jingle_pick_resource_or_bare_jid (presence, caps, &resource)) { - *dialect = JINGLE_DIALECT_GTALK3; + *dialect = WOCKY_JINGLE_DIALECT_GTALK3; goto CHOOSE_TRANSPORT; } @@ -917,7 +907,7 @@ jingle_pick_best_resource (GabbleConnection *conn, if (jingle_pick_resource_or_bare_jid (presence, caps, &resource)) { - *dialect = JINGLE_DIALECT_GTALK4; + *dialect = WOCKY_JINGLE_DIALECT_GTALK4; goto CHOOSE_TRANSPORT; } @@ -931,7 +921,7 @@ CHOOSE_TRANSPORT: success = TRUE; - if (*dialect == JINGLE_DIALECT_GTALK4 || *dialect == JINGLE_DIALECT_GTALK3) + if (*dialect == WOCKY_JINGLE_DIALECT_GTALK4 || *dialect == WOCKY_JINGLE_DIALECT_GTALK3) { /* the GTalk dialects only support google p2p as transport protocol. */ *transport_ns = NS_GOOGLE_TRANSPORT_P2P; @@ -959,20 +949,20 @@ const gchar * jingle_pick_best_content_type (GabbleConnection *conn, TpHandle peer, const gchar *resource, - JingleMediaType type) + WockyJingleMediaType type) { GabblePresence *presence; const GabbleFeatureFallback content_types[] = { /* if $thing is supported, then use it */ { TRUE, TWICE (NS_JINGLE_RTP) }, - { type == JINGLE_MEDIA_TYPE_VIDEO, + { type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO, TWICE (NS_JINGLE_DESCRIPTION_VIDEO) }, - { type == JINGLE_MEDIA_TYPE_AUDIO, + { type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO, TWICE (NS_JINGLE_DESCRIPTION_AUDIO) }, /* odd Google ones: if $thing is supported, use $other_thing */ - { type == JINGLE_MEDIA_TYPE_AUDIO, + { type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO, NS_GOOGLE_FEAT_VOICE, NS_GOOGLE_SESSION_PHONE }, - { type == JINGLE_MEDIA_TYPE_VIDEO, + { type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO, NS_GOOGLE_FEAT_VIDEO, NS_GOOGLE_SESSION_VIDEO }, { FALSE, NULL, NULL } }; @@ -998,23 +988,23 @@ jingle_pick_best_content_type (GabbleConnection *conn, } static TpCallStreamCandidateType -tp_candidate_type_from_jingle (JingleCandidateType type) +tp_candidate_type_from_jingle (WockyJingleCandidateType type) { switch (type) { default: /* Consider UNKNOWN as LOCAL/HOST */ - case JINGLE_CANDIDATE_TYPE_LOCAL: + case WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL: return TP_CALL_STREAM_CANDIDATE_TYPE_HOST; - case JINGLE_CANDIDATE_TYPE_STUN: + case WOCKY_JINGLE_CANDIDATE_TYPE_STUN: return TP_CALL_STREAM_CANDIDATE_TYPE_SERVER_REFLEXIVE; - case JINGLE_CANDIDATE_TYPE_RELAY: + case WOCKY_JINGLE_CANDIDATE_TYPE_RELAY: return TP_CALL_STREAM_CANDIDATE_TYPE_RELAY; } } /** - * @candidates: (element-type JingleCandidate): candidates + * @candidates: (element-type WockyJingleCandidate): candidates * * Returns: (transfer full): a GABBLE_ARRAY_TYPE_CANDIDATE_LIST, i.e. * a(usqa{sv}) @@ -1029,7 +1019,7 @@ gabble_call_candidates_to_array (GList *candidates) for (c = candidates; c != NULL; c = g_list_next (c)) { - JingleCandidate *cand = (JingleCandidate *) c->data; + WockyJingleCandidate *cand = (WockyJingleCandidate *) c->data; GValueArray *a; GHashTable *info; diff --git a/src/util.h b/src/util.h index 10b2b6eec..e01ff7e50 100644 --- a/src/util.h +++ b/src/util.h @@ -25,15 +25,9 @@ #include <config.h> #include <glib.h> -#include <telepathy-glib/handle-repo.h> -#include <telepathy-glib/util.h> +#include <telepathy-glib/telepathy-glib.h> #include <wocky/wocky.h> -#ifdef ENABLE_VOIP -#include "jingle-factory.h" -#include "jingle-content.h" -#endif - #include "types.h" /* Guarantees that the resulting hash is in lower-case */ @@ -84,13 +78,13 @@ gboolean jingle_pick_best_resource (GabbleConnection *conn, gboolean want_audio, gboolean want_video, const char **transport_ns, - JingleDialect *dialect, + WockyJingleDialect *dialect, const gchar **resource_out); const gchar *jingle_pick_best_content_type (GabbleConnection *conn, TpHandle peer, const gchar *resource, - JingleMediaType type); + WockyJingleMediaType type); GPtrArray *gabble_call_candidates_to_array (GList *candidates); #endif diff --git a/src/vcard-manager.c b/src/vcard-manager.c index 67466be01..74e933e9c 100644 --- a/src/vcard-manager.c +++ b/src/vcard-manager.c @@ -24,13 +24,12 @@ #include <string.h> -#include <telepathy-glib/dbus.h> -#include <telepathy-glib/heap.h> +#include <telepathy-glib/telepathy-glib.h> + #include <wocky/wocky.h> #define DEBUG_FLAG GABBLE_DEBUG_VCARD -#include "base64.h" #include "conn-aliasing.h" #include "conn-contact-info.h" #include "connection.h" @@ -49,53 +48,29 @@ static guint request_wait_delay = 5 * 60; static const gchar *NO_ALIAS = "none"; -typedef struct { - gchar *key; - gchar *value; -} GabbleVCardChild; - -static GabbleVCardChild * -gabble_vcard_child_new (const gchar *key, - const gchar *value) -{ - GabbleVCardChild *child = g_slice_new (GabbleVCardChild); - - child->key = g_strdup (key); - child->value = g_strdup (value); - return child; -} - -static void -gabble_vcard_child_free (GabbleVCardChild *child) -{ - g_free (child->key); - g_free (child->value); - g_slice_free (GabbleVCardChild, child); -} - struct _GabbleVCardManagerEditInfo { /* name of element to edit */ gchar *element_name; - /* value of element to edit or NULL if no value should be used */ - gchar *element_value; - - /* list of GabbleVCardChild */ - GList *children; - /* If REPLACE, the first element with this name (if any) will be updated; * if APPEND, an element with this name will be added; * if DELETE, all elements with this name will be removed; * if CLEAR, everything except PHOTO and NICKNAME will be deleted, in * preparation for a SetContactInfo operation - * if SET_ALIAS and element_value is NULL, set the best alias we have + * if SET_ALIAS and new_alias is NULL, set the best alias we have * as the NICKNAME or FN (as appropriate) if that field doesn't already * have a value - * if SET_ALIAS and element_value is non-NULL, set that + * if SET_ALIAS and new_alias is non-NULL, set that * as the NICKNAME or FN (as appropriate), overriding anything already * there */ GabbleVCardEditType edit_type; + + /* the element to fill in, if edit_type is REPLACE or APPEND. */ + WockyNodeTree *element; + + /* only meaningful if edit_type is SET_ALIAS; see above. */ + gchar *new_alias; }; /* signal enum */ @@ -155,7 +130,7 @@ struct _GabbleVCardManagerPrivate /* Patched vCard that we sent to the server to update, but haven't * got confirmation yet. We don't want to store it in cache (visible * to others) before we're sure the server accepts it. */ - WockyNode *patched_vcard; + WockyNodeTree *patched_vcard; }; struct _GabbleVCardManagerRequest @@ -209,7 +184,7 @@ struct _GabbleVCardCacheEntry guint suspended_timer_id; /* VCard node for this entry (owned reference), or NULL if there's no node */ - WockyNode *vcard_node; + WockyNodeTree *vcard_node; /* If @vcard_node is not NULL, the time the message will expire */ time_t expires; @@ -351,42 +326,6 @@ gabble_vcard_manager_set_property (GObject *object, } } -static gboolean -copy_attribute (const gchar *key, - const gchar *value, - const gchar *prefix, - const gchar *ns, - gpointer user_data) -{ - WockyNode *copy = (WockyNode *) user_data; - - wocky_node_set_attribute_ns (copy, key, value, ns); - return TRUE; -} - -static WockyNode * -copy_node (WockyNode *node) -{ - WockyNode *copy; - GSList *l; - - copy = wocky_node_new (node->name, wocky_node_get_ns (node)); - wocky_node_set_content (copy, node->content); - wocky_node_set_language (copy, wocky_node_get_language (node)); - - wocky_node_each_attribute (node, copy_attribute, copy); - - for (l = node->children; l != NULL; l = g_slist_next (l)) - { - WockyNode *child = l->data; - - copy->children = g_slist_prepend (copy->children, copy_node (child)); - } - copy->children = g_slist_reverse (copy->children); - - return copy; -} - static void delete_request (GabbleVCardManagerRequest *request); static void cancel_request (GabbleVCardManagerRequest *request); static void cancel_all_edit_requests (GabbleVCardManager *manager); @@ -403,9 +342,6 @@ static void cache_entry_free (gpointer data) { GabbleVCardCacheEntry *entry = data; - GabbleVCardManagerPrivate *priv = entry->manager->priv; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles - ((TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_CONTACT); g_assert (entry != NULL); @@ -419,9 +355,7 @@ cache_entry_free (gpointer data) gabble_request_pipeline_item_cancel (entry->pipeline_item); } - tp_clear_pointer (&entry->vcard_node, wocky_node_free); - - tp_handle_unref (contact_repo, entry->handle); + g_clear_object (&entry->vcard_node); g_slice_free (GabbleVCardCacheEntry, entry); } @@ -430,8 +364,6 @@ static GabbleVCardCacheEntry * cache_entry_get (GabbleVCardManager *manager, TpHandle handle) { GabbleVCardManagerPrivate *priv = manager->priv; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->connection, TP_HANDLE_TYPE_CONTACT); GabbleVCardCacheEntry *entry; entry = g_hash_table_lookup (priv->cache, GUINT_TO_POINTER (handle)); @@ -442,7 +374,6 @@ cache_entry_get (GabbleVCardManager *manager, TpHandle handle) entry->manager = manager; entry->handle = handle; - tp_handle_ref (contact_repo, handle); g_hash_table_insert (priv->cache, GUINT_TO_POINTER (handle), entry); return entry; @@ -511,7 +442,7 @@ cache_entry_attempt_to_free (GabbleVCardCacheEntry *entry) */ g_assert (entry->suspended_timer_id == 0); - if (entry->handle == base->self_handle) + if (entry->handle == tp_base_connection_get_self_handle (base)) { /* if we do have some pending edits, we should also have * some pipeline items or pending requests */ @@ -540,7 +471,7 @@ gabble_vcard_manager_invalidate_cache (GabbleVCardManager *manager, tp_heap_remove (priv->timed_cache, entry); - tp_clear_pointer (&entry->vcard_node, wocky_node_free); + g_clear_object (&entry->vcard_node); cache_entry_attempt_to_free (entry); } @@ -552,14 +483,18 @@ static void cache_entry_complete_requests (GabbleVCardCacheEntry *entry, GError *error) { GSList *cur, *tmp; + WockyNode *vcard_node = NULL; tmp = g_slist_copy (entry->pending_requests); + if (entry->vcard_node != NULL) + vcard_node = wocky_node_tree_get_top_node (entry->vcard_node); + for (cur = tmp; cur != NULL; cur = cur->next) { GabbleVCardManagerRequest *request = cur->data; - complete_one_request (request, error ? NULL : entry->vcard_node, error); + complete_one_request (request, error ? NULL : vcard_node, error); } g_slist_free (tmp); @@ -582,7 +517,7 @@ complete_one_request (GabbleVCardManagerRequest *request, static void disconnect_entry_foreach (gpointer handle, gpointer value, gpointer unused) { - GError err = { TP_ERRORS, TP_ERROR_DISCONNECTED, "Connection closed" }; + GError err = { TP_ERROR, TP_ERROR_DISCONNECTED, "Connection closed" }; GabbleVCardCacheEntry *entry = value; if (entry->suspended_timer_id) @@ -650,7 +585,8 @@ vcard_get_avatar_sha1 (WockyNode *vcard) { gchar *sha1; const gchar *binval_value; - GString *avatar; + guchar *avatar; + gsize outlen; WockyNode *node; WockyNode *binval; @@ -670,12 +606,12 @@ vcard_get_avatar_sha1 (WockyNode *vcard) if (!binval_value) return g_strdup (""); - avatar = base64_decode (binval_value); + avatar = g_base64_decode (binval_value, &outlen); if (avatar) { - sha1 = sha1_hex (avatar->str, avatar->len); - g_string_free (avatar, TRUE); + sha1 = sha1_hex ((gchar *) avatar, outlen); + g_free (avatar); DEBUG ("Successfully decoded PHOTO.BINVAL, SHA-1 %s", sha1); } else @@ -738,8 +674,7 @@ status_changed_cb (GObject *object, /* if we have a better alias, patch it into our vCard on the server */ alias_src = _gabble_connection_get_cached_alias (conn, - base->self_handle, - &alias); + tp_base_connection_get_self_handle (base), &alias); if (alias_src >= GABBLE_CONNECTION_ALIAS_FROM_VCARD) { @@ -751,7 +686,8 @@ status_changed_cb (GObject *object, g_free (alias); /* FIXME: we happen to know that synchronous errors can't happen */ - gabble_vcard_manager_request (self, base->self_handle, 0, + gabble_vcard_manager_request (self, + tp_base_connection_get_self_handle (base), 0, initial_request_cb, NULL, (GObject *) self); } } @@ -948,25 +884,28 @@ replace_reply_cb (GabbleConnection *conn, if (error) { /* We won't need our patched vcard after all */ - tp_clear_pointer (&priv->patched_vcard, wocky_node_free); + g_clear_object (&priv->patched_vcard); } else { - GabbleVCardCacheEntry *entry = cache_entry_get (self, base->self_handle); + GabbleVCardCacheEntry *entry = cache_entry_get (self, + tp_base_connection_get_self_handle (base)); /* We must have patched vcard by now */ g_assert (priv->patched_vcard != NULL); /* Finally we may put the new vcard in the cache. */ - tp_clear_pointer (&entry->vcard_node, wocky_node_free); + g_clear_object (&entry->vcard_node); entry->vcard_node = priv->patched_vcard; priv->patched_vcard = NULL; + node = wocky_node_tree_get_top_node (entry->vcard_node); + /* observe it so we pick up alias updates */ - observe_vcard (conn, self, base->self_handle, entry->vcard_node); + observe_vcard (conn, self, tp_base_connection_get_self_handle (base), + node); - node = entry->vcard_node; } /* Scan all edit requests, call and remove ones whose data made it @@ -1015,66 +954,27 @@ gabble_vcard_manager_replace_is_significant (GabbleVCardManagerEditInfo *info, { gboolean seen = FALSE; WockyNodeIter i; - WockyNode *node; + WockyNode *node, *replacement_node; + + g_return_val_if_fail (info->element != NULL, FALSE); + replacement_node = wocky_node_tree_get_top_node (info->element); /* Find the first node matching the one we want to edit */ wocky_node_iter_init (&i, old_vcard, info->element_name, NULL); while (wocky_node_iter_next (&i, &node)) { - const gchar *value; - const gchar *new_value; - /* if there are >= 2 copies of this field, we're going to reduce that * to 1 */ if (seen) return TRUE; - /* consider NULL and "" to be different representations for the - * same thing */ - value = node->content; - new_value = info->element_value; - - if (value == NULL) - value = ""; + seen = TRUE; - if (new_value == NULL) - new_value = ""; - - if (tp_strdiff (value, new_value)) + /* This depends on PHOTO's children being TYPE, BINVAL in the correct + * order—which is required by the vcard-temp schema, soooo... + */ + if (!wocky_node_equal (node, replacement_node)) return TRUE; - - /* we assume that a change to child nodes is always significant, - * unless it's the <PHOTO/> */ - if (!tp_strdiff (node->name, "PHOTO")) - { - /* For the special case of PHOTO, we know that the child nodes - * are only meant to appear once, so we can be more aggressive - * about avoiding unnecessary edits: assume that the PHOTO on - * the server doesn't have extra children, and that one matching - * child is enough. */ - GList *child_iter; - - for (child_iter = info->children; - child_iter != NULL; - child_iter = child_iter->next) - { - GabbleVCardChild *child = child_iter->data; - WockyNode *child_node = wocky_node_get_child (node, - child->key); - - if (child_node == NULL || - tp_strdiff (child_node->content, - child->value)) - { - return TRUE; - } - } - } - else - { - if (info->children != NULL) - return TRUE; - } } /* if there are no copies of this field, we're going to add one; otherwise, @@ -1083,76 +983,38 @@ gabble_vcard_manager_replace_is_significant (GabbleVCardManagerEditInfo *info, return !seen; } -static WockyNode *vcard_copy (WockyNode *parent, WockyNode *src, - const gchar *exclude, gboolean *exclude_mattered); - -static WockyStanza * -gabble_vcard_manager_edit_info_apply (GabbleVCardManagerEditInfo *info, - WockyNode *old_vcard, - GabbleVCardManager *vcard_manager) +static gboolean +remove_all_children_named ( + WockyNode *node, + const gchar *name) { - WockyStanza *msg; - WockyNode *vcard_node; - WockyNode *node; - GList *iter; - gboolean maybe_changed = FALSE; - GabbleConnection *conn = vcard_manager->priv->connection; - TpBaseConnection *base = (TpBaseConnection *) conn; + WockyNodeIter iter; + gboolean changed = FALSE; - if (info->edit_type == GABBLE_VCARD_EDIT_SET_ALIAS) + wocky_node_iter_init (&iter, node, name, NULL); + while (wocky_node_iter_next (&iter, NULL)) { - /* SET_ALIAS is shorthand for a REPLACE operation or nothing */ - - g_assert (info->element_name == NULL); - - if (gabble_vcard_manager_can_use_vcard_field (vcard_manager, "NICKNAME")) - { - info->element_name = g_strdup ("NICKNAME"); - } - else - { - /* Google Talk servers won't let us set a NICKNAME; recover by - * setting the FN */ - info->element_name = g_strdup ("FN"); - } - - if (info->element_value == NULL) - { - /* We're just trying to fix a possibly-incomplete SetContactInfo() - - * */ - gchar *alias; - - node = wocky_node_get_child (old_vcard, info->element_name); - - /* If the user has set this field explicitly via SetContactInfo(), - * that takes precedence */ - if (node != NULL) - return NULL; - - if (_gabble_connection_get_cached_alias (conn, base->self_handle, - &alias) < GABBLE_CONNECTION_ALIAS_FROM_VCARD) - { - /* not good enough to want to put it in the vCard */ - g_free (alias); - return NULL; - } + wocky_node_iter_remove (&iter); + changed = TRUE; + } - info->element_value = alias; - } + return changed; +} - info->edit_type = GABBLE_VCARD_EDIT_REPLACE; - } +static gboolean +gabble_vcard_manager_edit_info_apply_replace ( + GabbleVCardManagerEditInfo *info, + WockyNode *vcard_node, + GabbleVCardManager *vcard_manager) +{ + g_return_val_if_fail (info->edit_type == GABBLE_VCARD_EDIT_REPLACE, FALSE); - if (info->edit_type == GABBLE_VCARD_EDIT_APPEND || - info->edit_type == GABBLE_VCARD_EDIT_REPLACE) + if (!gabble_vcard_manager_can_use_vcard_field (vcard_manager, + info->element_name)) { - if (!gabble_vcard_manager_can_use_vcard_field (vcard_manager, - info->element_name)) - { - DEBUG ("ignoring vcard node %s because this server doesn't " - "support it", info->element_name); - return NULL; - } + DEBUG ("ignoring vcard node %s because this server doesn't " + "support it", info->element_name); + return FALSE; } /* A special case for replacing one field with another: we detect no-op @@ -1160,156 +1022,177 @@ gabble_vcard_manager_edit_info_apply (GabbleVCardManagerEditInfo *info, * frequently (on every login), and as well as wasting bandwidth, setting * the vCard too often can cause a memory leak in OpenFire (see fd.o#25341). */ - if (info->edit_type == GABBLE_VCARD_EDIT_REPLACE && - ! gabble_vcard_manager_replace_is_significant (info, old_vcard)) + if (! gabble_vcard_manager_replace_is_significant (info, vcard_node)) { DEBUG ("ignoring no-op vCard %s replacement", info->element_name); - return NULL; + return FALSE; } - msg = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - NULL, NULL, NULL); + remove_all_children_named (vcard_node, info->element_name); + wocky_node_add_node_tree (vcard_node, info->element); + + return TRUE; +} - if (info->edit_type == GABBLE_VCARD_EDIT_CLEAR) +static gboolean +gabble_vcard_manager_edit_info_apply_append ( + GabbleVCardManagerEditInfo *info, + WockyNode *vcard_node, + GabbleVCardManager *vcard_manager) +{ + if (!gabble_vcard_manager_can_use_vcard_field (vcard_manager, + info->element_name)) { - /* start from a clean slate... */ - vcard_node = wocky_node_add_child_with_content ( - wocky_stanza_get_top_node (msg), "vCard", ""); - vcard_node->ns = g_quark_from_string ("vcard-temp"); + DEBUG ("ignoring vcard node %s because this server doesn't " + "support it", info->element_name); + return FALSE; + } - /* ... but as a special case, the photo gets copied in from the old - * vCard, because SetContactInfo doesn't touch photos */ - node = wocky_node_get_child (old_vcard, "PHOTO"); + wocky_node_add_node_tree (vcard_node, info->element); - if (node != NULL) - vcard_copy (vcard_node, node, NULL, NULL); + return TRUE; +} + +static gboolean +gabble_vcard_manager_edit_info_apply_delete ( + GabbleVCardManagerEditInfo *info, + WockyNode *vcard_node, + GabbleVCardManager *vcard_manager) +{ + return remove_all_children_named (vcard_node, info->element_name); +} + +static gboolean +gabble_vcard_manager_edit_info_apply_clear ( + GabbleVCardManagerEditInfo *info, + WockyNode *vcard_node, + GabbleVCardManager *vcard_manager) +{ + /* Blow almost everything away! As a special case, the photo gets left in + * place from the old vCard, because SetContactInfo doesn't touch + * photos, and CLEAR is only used by SetContactInfo */ + WockyNodeIter iter; + WockyNode *node; + gboolean changed = FALSE; - /* Yes, we can do this: "WockyNode" is really a WockyNode */ - if (wocky_node_equal (old_vcard, vcard_node)) + wocky_node_iter_init (&iter, vcard_node, NULL, NULL); + while (wocky_node_iter_next (&iter, &node)) + { + if (tp_strdiff (node->name, "PHOTO")) { - /* nothing actually happened, forget it */ - g_object_unref (msg); - return NULL; + wocky_node_iter_remove (&iter); + changed = TRUE; } - - return msg; } - if (info->edit_type == GABBLE_VCARD_EDIT_APPEND) + return changed; +} + +/* SET_ALIAS is shorthand for a REPLACE operation or nothing */ +static gboolean +gabble_vcard_manager_edit_info_apply_set_alias ( + GabbleVCardManagerEditInfo *info, + WockyNode *old_vcard, + GabbleVCardManager *vcard_manager) +{ + GabbleConnection *conn = vcard_manager->priv->connection; + TpBaseConnection *base = (TpBaseConnection *) conn; + + g_assert (info->element_name == NULL); + + if (gabble_vcard_manager_can_use_vcard_field (vcard_manager, "NICKNAME")) { - /* appending: keep all child nodes */ - vcard_node = vcard_copy ( - wocky_stanza_get_top_node (msg), old_vcard, NULL, NULL); + info->element_name = g_strdup ("NICKNAME"); } else { - /* replacing or deleting: exclude all matching child nodes from - * copying */ - vcard_node = vcard_copy ( - wocky_stanza_get_top_node (msg), old_vcard, info->element_name, - &maybe_changed); + /* Google Talk servers won't let us set a NICKNAME; recover by + * setting the FN */ + info->element_name = g_strdup ("FN"); } - if (info->edit_type != GABBLE_VCARD_EDIT_DELETE) + if (info->new_alias == NULL) { - maybe_changed = TRUE; + /* We're just trying to fix a possibly-incomplete SetContactInfo() */ + WockyNode *node = wocky_node_get_child (old_vcard, info->element_name); + gchar *alias; - node = wocky_node_add_child_with_content (vcard_node, - info->element_name, info->element_value); + /* If the user has set this field explicitly via SetContactInfo(), + * that takes precedence */ + if (node != NULL) + return FALSE; - for (iter = info->children; iter != NULL; iter = iter->next) + if (_gabble_connection_get_cached_alias (conn, + tp_base_connection_get_self_handle (base), + &alias) < GABBLE_CONNECTION_ALIAS_FROM_VCARD) { - GabbleVCardChild *child = iter->data; - - wocky_node_add_child_with_content (node, child->key, child->value); + /* not good enough to want to put it in the vCard */ + g_free (alias); + return FALSE; } - } - if ((!maybe_changed) || wocky_node_equal (old_vcard, vcard_node)) - { - /* nothing actually happened, forget it */ - g_object_unref (msg); - return NULL; + info->new_alias = alias; } - return msg; + info->element = wocky_node_tree_new (info->element_name, NS_VCARD_TEMP, + '$', info->new_alias, NULL); + info->edit_type = GABBLE_VCARD_EDIT_REPLACE; + return gabble_vcard_manager_edit_info_apply_replace (info, old_vcard, + vcard_manager); } -/* Loudmouth hates me. The feelings are mutual. - * - * Note that this function doesn't copy any attributes other than - * xmlns, because LM provides no way to iterate over attributes. Thanks, LM. */ -static WockyNode * -vcard_copy (WockyNode *parent, - WockyNode *src, - const gchar *exclude, - gboolean *exclude_mattered) -{ - WockyNode *new = wocky_node_add_child_with_content (parent, src->name, - src->content); - const gchar *xmlns; - WockyNodeIter i; - WockyNode *child; - - xmlns = wocky_node_get_ns (src); - if (xmlns != NULL) - new->ns = g_quark_from_string (xmlns); - - wocky_node_iter_init (&i, src, NULL, NULL); - while (wocky_node_iter_next (&i, &child)) - { - - if (tp_strdiff (child->name, exclude)) - { - vcard_copy (new, child, NULL, NULL); - } - else - { - if (exclude_mattered != NULL) - *exclude_mattered = TRUE; - } - } +typedef gboolean (*EditFunction) ( + GabbleVCardManagerEditInfo *info, + WockyNode *vcard_node, + GabbleVCardManager *vcard_manager); + +static const EditFunction edit_functions[] = { + gabble_vcard_manager_edit_info_apply_replace, + gabble_vcard_manager_edit_info_apply_append, + gabble_vcard_manager_edit_info_apply_delete, + gabble_vcard_manager_edit_info_apply_clear, + gabble_vcard_manager_edit_info_apply_set_alias, +}; - return new; +static gboolean +gabble_vcard_manager_edit_info_apply (GabbleVCardManagerEditInfo *info, + WockyNode *vcard_node, + GabbleVCardManager *vcard_manager) +{ + return edit_functions[info->edit_type] (info, vcard_node, vcard_manager); } static void manager_patch_vcard (GabbleVCardManager *self, - WockyNode *vcard_node) + WockyNode *old_vcard_node) { GabbleVCardManagerPrivate *priv = self->priv; - WockyStanza *msg = NULL; + WockyNodeTree *vcard_node_tree; + WockyNode *vcard_node; + WockyStanza *msg; GList *li; + gboolean changed = FALSE; /* Bail out if we don't have outstanding edits to make, or if we already * have a set request in progress. */ if (priv->edits == NULL || priv->edit_pipeline_item != NULL) - return; + return; + + vcard_node_tree = wocky_node_tree_new_from_node (old_vcard_node); + vcard_node = wocky_node_tree_get_top_node (vcard_node_tree); /* Apply any unsent edits to the patched vCard */ for (li = priv->edits; li != NULL; li = li->next) { - WockyStanza *new_msg = gabble_vcard_manager_edit_info_apply ( - li->data, vcard_node, self); - - /* edit_info_apply returns NULL if nothing happened */ - if (new_msg == NULL) - continue; - - tp_clear_pointer (&msg, g_object_unref); - - msg = new_msg; - /* gabble_vcard_manager_edit_info_apply always returns an IQ message - * with one vCard child */ - vcard_node = wocky_node_get_child ( - wocky_stanza_get_top_node (msg), "vCard"); - g_assert (vcard_node != NULL); + if (gabble_vcard_manager_edit_info_apply (li->data, vcard_node, self)) + changed = TRUE; } - if (msg == NULL) + if (!changed) { DEBUG ("nothing really changed, not updating vCard"); + g_clear_object (&vcard_node_tree); goto out; } @@ -1318,7 +1201,11 @@ manager_patch_vcard (GabbleVCardManager *self, /* We'll save the patched vcard, and if the server says * we're ok, put it into the cache. But we want to leave the * original vcard in the cache until that happens. */ - priv->patched_vcard = copy_node (vcard_node); + priv->patched_vcard = vcard_node_tree; + + msg = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, + NULL, NULL, NULL); + wocky_node_add_node_tree (wocky_stanza_get_top_node (msg), vcard_node_tree); priv->edit_pipeline_item = gabble_request_pipeline_enqueue ( priv->connection->req_pipeline, msg, default_request_timeout, @@ -1425,7 +1312,8 @@ pipeline_reply_cb (GabbleConnection *conn, /* If request for our own vCard failed, and we do have * pending edits to make, cancel those and return error * to the user */ - if (entry->handle == base->self_handle && priv->edits != NULL) + if (entry->handle == tp_base_connection_get_self_handle (base) && + priv->edits != NULL) { /* We won't have a chance to apply those, might as well forget them */ g_list_foreach (priv->edits, @@ -1452,14 +1340,13 @@ pipeline_reply_cb (GabbleConnection *conn, DEBUG ("successful lookup response contained no <vCard> node, " "creating an empty one"); - vcard_node = wocky_node_add_child_with_content ( + vcard_node = wocky_node_add_child_ns ( wocky_stanza_get_top_node (reply_msg), "vCard", - NULL); - vcard_node->ns = g_quark_from_string (NS_VCARD_TEMP); + NS_VCARD_TEMP); } /* Put the message in the cache */ - entry->vcard_node = copy_node (vcard_node); + entry->vcard_node = wocky_node_tree_new_from_node (vcard_node); entry->expires = time (NULL) + VCARD_CACHE_ENTRY_TTL; tp_heap_add (priv->timed_cache, entry); @@ -1475,7 +1362,7 @@ pipeline_reply_cb (GabbleConnection *conn, /* We have freshly updated cache for our vCard, edit it if * there are any pending edits and no outstanding set request. */ - if (entry->handle == base->self_handle) + if (entry->handle == tp_base_connection_get_self_handle (base)) { manager_patch_vcard (self, vcard_node); } @@ -1523,7 +1410,7 @@ request_send (GabbleVCardManagerRequest *request, guint timeout) request->timer_id = g_timeout_add_seconds (request->timeout, timeout_request, request); - if (entry->handle == base->self_handle) + if (entry->handle == tp_base_connection_get_self_handle (base)) { DEBUG ("Cache entry %p is my own, not setting @to", entry); jid = NULL; @@ -1576,14 +1463,14 @@ gabble_vcard_manager_request (GabbleVCardManager *self, GObject *object) { GabbleVCardManagerPrivate *priv = self->priv; - TpBaseConnection *connection = (TpBaseConnection *) priv->connection; - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - connection, TP_HANDLE_TYPE_CONTACT); + TpBaseConnection *base = (TpBaseConnection *) priv->connection; + TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (base, + TP_HANDLE_TYPE_CONTACT); GabbleVCardManagerRequest *request; GabbleVCardCacheEntry *entry = cache_entry_get (self, handle); - g_return_val_if_fail (connection->status == TP_CONNECTION_STATUS_CONNECTED, - NULL); + g_return_val_if_fail (tp_base_connection_get_status (base) == + TP_CONNECTION_STATUS_CONNECTED, NULL); g_return_val_if_fail (tp_handle_is_valid (contact_repo, handle, NULL), NULL); g_assert (entry->vcard_node == NULL); @@ -1630,20 +1517,22 @@ gabble_vcard_manager_edit (GabbleVCardManager *self, GabbleVCardManagerEditRequest *req; GabbleVCardCacheEntry *entry; - g_return_val_if_fail (base->status == TP_CONNECTION_STATUS_CONNECTED, NULL); + g_return_val_if_fail (tp_base_connection_get_status (base) == + TP_CONNECTION_STATUS_CONNECTED, NULL); /* Invalidate our current vCard and ensure that we're going to get * it in the near future */ DEBUG ("called; invalidating cache"); - gabble_vcard_manager_invalidate_cache (self, base->self_handle); + gabble_vcard_manager_invalidate_cache (self, + tp_base_connection_get_self_handle (base)); DEBUG ("checking if we have pending requests already"); - entry = cache_entry_get (self, base->self_handle); + entry = cache_entry_get (self, tp_base_connection_get_self_handle (base)); if (!priv->edit_pipeline_item && !entry->pending_requests) { DEBUG ("we don't, create one"); /* create dummy GET request if neccessary */ - gabble_vcard_manager_request (self, base->self_handle, 0, NULL, - NULL, NULL); + gabble_vcard_manager_request (self, + tp_base_connection_get_self_handle (base), 0, NULL, NULL, NULL); } priv->edits = g_list_concat (priv->edits, edits); @@ -1745,7 +1634,7 @@ gabble_vcard_manager_get_cached (GabbleVCardManager *self, return FALSE; if (node != NULL) - *node = entry->vcard_node; + *node = wocky_node_tree_get_top_node (entry->vcard_node); return TRUE; } @@ -1826,36 +1715,49 @@ gabble_vcard_manager_edit_info_new (const gchar *element_name, { GabbleVCardManagerEditInfo *info; va_list ap; - const gchar *key; - const gchar *value; - - if (edit_type == GABBLE_VCARD_EDIT_DELETE) - { - const gchar *first_edit = NULL; - g_return_val_if_fail (element_value == NULL, NULL); - - va_start (ap, edit_type); - first_edit = va_arg (ap, const gchar *); - va_end (ap); - g_return_val_if_fail (first_edit == NULL, NULL); - } - - info = g_slice_new (GabbleVCardManagerEditInfo); + info = g_slice_new0 (GabbleVCardManagerEditInfo); info->element_name = g_strdup (element_name); - info->element_value = g_strdup (element_value); info->edit_type = edit_type; - info->children = NULL; va_start (ap, edit_type); - while ((key = va_arg (ap, const gchar *))) + switch (edit_type) { - value = va_arg (ap, const gchar *); - gabble_vcard_manager_edit_info_add_child (info, key, value); - } + case GABBLE_VCARD_EDIT_REPLACE: + case GABBLE_VCARD_EDIT_APPEND: + g_return_val_if_fail (element_name != NULL, NULL); + + info->element = wocky_node_tree_new_va (element_name, NS_VCARD_TEMP, + ap); + va_end (ap); - va_end (ap); + if (element_value != NULL) + wocky_node_set_content (wocky_node_tree_get_top_node (info->element), + element_value); + + break; + + case GABBLE_VCARD_EDIT_SET_ALIAS: + g_return_val_if_fail (element_name == NULL, NULL); + + info->new_alias = g_strdup (element_value); + element_value = NULL; + + /* deliberate fall-through to check the varargs... */ + case GABBLE_VCARD_EDIT_DELETE: + case GABBLE_VCARD_EDIT_CLEAR: + { + const gchar *first_edit = NULL; + + g_return_val_if_fail (element_value == NULL, NULL); + + first_edit = va_arg (ap, const gchar *); + va_end (ap); + g_return_val_if_fail (first_edit == NULL, NULL); + break; + } + } return info; } @@ -1866,17 +1768,19 @@ gabble_vcard_manager_edit_info_add_child ( const gchar *key, const gchar *value) { - edit_info->children = g_list_append (edit_info->children, - gabble_vcard_child_new (key, value)); + g_return_if_fail (edit_info->element != NULL); + + wocky_node_add_child_with_content ( + wocky_node_tree_get_top_node (edit_info->element), + key, value); } void gabble_vcard_manager_edit_info_free (GabbleVCardManagerEditInfo *info) { g_free (info->element_name); - g_free (info->element_value); - g_list_foreach (info->children, (GFunc) gabble_vcard_child_free, NULL); - g_list_free (info->children); + g_free (info->new_alias); + g_clear_object (&info->element); g_slice_free (GabbleVCardManagerEditInfo, info); } @@ -1897,10 +1801,11 @@ gabble_vcard_manager_can_use_vcard_field (GabbleVCardManager *self, if (self->priv->connection->features & GABBLE_CONNECTION_FEATURES_GOOGLE_ROSTER) { - /* Google's server only allows N, FN and PHOTO */ + /* Google's server only allows N, FN, PHOTO and URL */ if (tp_strdiff (field_name, "N") && tp_strdiff (field_name, "FN") && - tp_strdiff (field_name, "PHOTO")) + tp_strdiff (field_name, "PHOTO") && + tp_strdiff (field_name, "URL")) { return FALSE; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2d2860e08..c97e5d114 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,6 @@ SUBDIRS = twisted suppressions tests_list = \ - test-base64 \ test-dtube-unique-names \ test-gabble-idle-weak \ test-handles \ @@ -53,7 +52,6 @@ check-valgrind: $(TESTS) check_c_sources = \ $(dbus_test_sources) \ - test-base64.c \ test-dtube-unique-names.c \ test-presence.c \ test-jid-decode.c \ diff --git a/tests/README b/tests/README index 6f96f0b23..7cbb7277a 100644 --- a/tests/README +++ b/tests/README @@ -77,6 +77,11 @@ To debug an individual test you can set one of the following env variable: bus daemon. The logs are saved to tools/*bustle-logs. export GABBLE_TEST_BUSTLE=1 + * GABBLE_NODELAY : to run any Gabble test with TCP_NODELAY set on + both Wocky and Twisted's socket. This can speed up tests + significantly. + export GABBLE_NODELAY=1 + == Jingle tests == Various jingle tests run the same tests with different dialects. To only test diff --git a/tests/test-base64.c b/tests/test-base64.c deleted file mode 100644 index 49ebbf37d..000000000 --- a/tests/test-base64.c +++ /dev/null @@ -1,106 +0,0 @@ - -#include "config.h" - -#include <stdio.h> -#include <string.h> - -#include <glib-object.h> - -#include "src/base64.h" - -struct test { - gchar *str; - size_t len; - gchar *encoded; -}; - -struct test tests[] = { - { "c", 0, "Yw==" }, - { "ca", 0, "Y2E=" }, - { "car", 0, "Y2Fy" }, - { "carnal pleasure.", 0, "Y2FybmFsIHBsZWFzdXJlLg==" }, - { "carnal pleasure", 0, "Y2FybmFsIHBsZWFzdXJl" }, - { "carnal pleasur", 0, "Y2FybmFsIHBsZWFzdXI=" }, - { "carnal pleasu", 0, "Y2FybmFsIHBsZWFzdQ==" }, - /* test long (> 76 / 4 * 3) string */ - { - "1234567890" - "1234567890" - "1234567890" - "1234567890" - "1234567890" - "1234567890", - 0, - "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM" - "0NTY3\nODkw" }, - /* regression test: formerly we assumed that there was a NUL immediately - * after the data */ - { "hello", 5, "aGVsbG8=" }, - { "hello\xff\xff", 5, "aGVsbG8=" }, - - { NULL, 0, NULL } -}; - -int -main (void) -{ - gchar *s; - GString *tmp1, *tmp2; - struct test *t; - - g_type_init (); - - for (t = tests; t->str != NULL; t++) - { - if (t->len == 0) - t->len = strlen (t->str); - s = base64_encode (t->len, t->str, TRUE); - g_assert (0 == strcmp (s, t->encoded)); - g_free (s); - } - - /* test string with valid characters but invalid length */ - tmp1 = base64_decode ("AAA"); - g_assert (tmp1 == NULL); - - /* test string with valid length but invalid characters */ - tmp1 = base64_decode ("????"); - g_assert (tmp1 == NULL); - - /* test string with embedded newline */ - tmp1 = base64_decode ("bWF6\ndWxlbQ=="); - tmp2 = g_string_new ("mazulem"); - g_assert (tmp1); - g_assert (g_string_equal (tmp1, tmp2)); - g_string_free (tmp1, TRUE); - g_string_free (tmp2, TRUE); - - /* test string with misc whitespace */ - tmp1 = base64_decode ("bW F\r6\r\ndW\nxlbQ==\r\n"); - tmp2 = g_string_new ("mazulem"); - g_assert (tmp1); - g_assert (g_string_equal (tmp1, tmp2)); - g_string_free (tmp1, TRUE); - g_string_free (tmp2, TRUE); - - /* test string with embedded NULL */ - tmp1 = base64_decode ("Zm9vAGJhcg=="); - tmp2 = g_string_new_len ("foo\0bar", 7); - g_assert (tmp1); - g_assert (g_string_equal (tmp1, tmp2)); - g_string_free (tmp1, TRUE); - g_string_free (tmp2, TRUE); - - for (t = tests; t->str != NULL; t++) - { - tmp1 = base64_decode (t->encoded); - g_assert (tmp1); - tmp2 = g_string_new_len (t->str, t->len); - g_assert (g_string_equal (tmp1, tmp2)); - g_string_free (tmp1, TRUE); - g_string_free (tmp2, TRUE); - } - - return 0; -} - diff --git a/tests/test-handles.c b/tests/test-handles.c index 7439a6882..a0d60be49 100644 --- a/tests/test-handles.c +++ b/tests/test-handles.c @@ -4,9 +4,8 @@ #include <string.h> #include <glib.h> #include <glib-object.h> -#include <telepathy-glib/enums.h> -#include <telepathy-glib/interfaces.h> -#include <telepathy-glib/errors.h> +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "src/connection.h" @@ -65,9 +64,6 @@ test_handles (guint handle_type) return_jid = tp_handle_inspect (tp_repo, handle); g_assert (!strcmp (return_jid, jid)); - /* Now unref it */ - tp_handle_unref (tp_repo, handle); - for (i = 0; i < NUM_TP_HANDLE_TYPES; i++) { if (repos[i]) diff --git a/tests/tp-error-from-wocky.c b/tests/tp-error-from-wocky.c index 207ec5952..729af31a4 100644 --- a/tests/tp-error-from-wocky.c +++ b/tests/tp-error-from-wocky.c @@ -19,7 +19,7 @@ test_remap (GQuark domain, &conn_reason, &error); g_assert (error != NULL); g_assert_cmpstr (g_quark_to_string (error->domain), ==, - g_quark_to_string (TP_ERRORS)); + g_quark_to_string (TP_ERROR)); g_assert_cmpint (error->code, ==, exp_code); g_assert_cmpint (conn_reason, ==, exp_reason); diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index ae24bd110..fdc6d612a 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -113,6 +113,7 @@ TWISTED_TESTS = \ text/facebook-own-message.py \ text/initiate.py \ text/initiate-requestotron.py \ + text/receipts.py \ text/respawn.py \ text/send-error.py \ text/send-to-correct-resource.py \ @@ -132,10 +133,8 @@ TWISTED_TUBE_TESTS = \ tubes/accept-private-stream-tube.py \ tubes/check-create-tube-return.py \ tubes/close-muc-with-closed-tube.py \ - tubes/crash-on-list-channels.py \ tubes/create-invalid-tube-channels.py \ tubes/ensure-si-tube.py \ - tubes/muc-presence.py \ tubes/offer-muc-dbus-tube.py \ tubes/offer-muc-stream-tube.py \ tubes/offer-no-caps.py \ @@ -147,12 +146,14 @@ TWISTED_TUBE_TESTS = \ $(NULL) TWISTED_VCARD_TESTS = \ + vcard/clear-avatar.py \ vcard/disconnect-during-pep.py \ vcard/get-contact-info.py \ vcard/item-not-found.py \ vcard/overlapping-sets.py \ vcard/redundant-set.py \ vcard/refresh-contact-info.py \ + vcard/set-avatar.py \ vcard/set-contact-info.py \ vcard/set-set-disconnect.py \ vcard/supported-fields.py \ @@ -217,6 +218,7 @@ TWISTED_JINGLE_TESTS = \ jingle/test-wait-for-caps-incomplete.py \ jingle/test-wait-for-caps.py \ jingle/transport-info-parsing.py \ + jingle/unknown-session.py \ $(NULL) TWISTED_FT_TESTS = \ @@ -263,12 +265,12 @@ TWISTED_OTHER_FILES = \ jingle/callutils.py \ jingle/__init__.py \ jingle/jingletest2.py \ - jingle/jingletest.py \ jingle-share/file_transfer_helper.py \ jingle-share/jingleshareutils.py \ mucutil.py \ ns.py \ olpc/util.py \ + presence/__init__.py \ presence/invisible_helper.py \ rostertest.py \ sasl/saslutil.py \ @@ -276,7 +278,6 @@ TWISTED_OTHER_FILES = \ test-helper.py \ tls-cert.pem \ tls-key.pem \ - tubes/muctubeutil.py \ tubes/tubetestutil.py \ $(NULL) diff --git a/tests/twisted/caps/advertise-contact-caps.py b/tests/twisted/caps/advertise-contact-caps.py index 9200e1626..ab40277fd 100644 --- a/tests/twisted/caps/advertise-contact-caps.py +++ b/tests/twisted/caps/advertise-contact-caps.py @@ -2,6 +2,7 @@ Test UpdateCapabilities. """ +from functools import partial import dbus from twisted.words.xish import xpath, domish @@ -247,14 +248,20 @@ def run_mixed_test (q, bus, conn, stream): check_caps(namespaces, JINGLE_CAPS) if __name__ == '__main__': - exec_test(lambda q, b, c, s: - run_test (q, b, c, s, - cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.CHANNEL_IFACE_MEDIA_SIGNALLING, - cs.INITIAL_AUDIO, cs.INITIAL_VIDEO), do_connect=False) + exec_test( + partial(run_test, + media_channel_type=cs.CHANNEL_TYPE_STREAMED_MEDIA, + media_interface=cs.CHANNEL_IFACE_MEDIA_SIGNALLING, + initial_audio=cs.INITIAL_AUDIO, + initial_video=cs.INITIAL_VIDEO), + do_connect=False) - exec_test(lambda q, b, c, s: - run_test (q, b, c, s, - cs.CHANNEL_TYPE_CALL, cs.CHANNEL_TYPE_CALL, - cs.CALL_INITIAL_AUDIO, cs.CALL_INITIAL_VIDEO), do_connect=False) + exec_test( + partial(run_test, + media_channel_type=cs.CHANNEL_TYPE_CALL, + media_interface=cs.CHANNEL_TYPE_CALL, + initial_audio=cs.CALL_INITIAL_AUDIO, + initial_video=cs.CALL_INITIAL_VIDEO), + do_connect=False) exec_test(run_mixed_test, do_connect=False) diff --git a/tests/twisted/caps/jingle-caps.py b/tests/twisted/caps/jingle-caps.py index 0ab26c6f6..42f69cf1d 100644 --- a/tests/twisted/caps/jingle-caps.py +++ b/tests/twisted/caps/jingle-caps.py @@ -4,14 +4,16 @@ and/or video capable """ from functools import partial +from itertools import permutations from gabbletest import exec_test, make_presence, sync_stream from servicetest import ( - assertContains, assertEquals, EventPattern, make_channel_proxy + assertContains, assertDoesNotContain, assertEquals, EventPattern, + make_channel_proxy ) import constants as cs import ns -from caps_helper import presence_and_disco, compute_caps_hash +from caps_helper import presence_and_disco, compute_caps_hash, send_presence from jingle.jingletest2 import JingleTest2, JingleProtocol031 from config import VOIP_ENABLED @@ -197,6 +199,49 @@ def test_prefer_phones(q, bus, conn, stream, expect_disco): # ...then calls should go there, even though the laptop is more available. make_call(expected_recipient=phone_jid) +def test_google_caps(q, bus, conn, stream): + i = 1 + + # we want to make sure all permutations of voice-v1 and video-v1 + # result in the correct caps, so let's do exactly that. + for j in (1, 2): + for ext_set in permutations(['voice-v1', 'video-v1'], j): + jid = 'larry%s@page/mountainview' % i + i += 1 + + # order of these ext values shouldn't matter + gcaps = { 'node': 'blahblahthiskeepsonchanging', + 'ver': '1.1', + 'ext': ' '.join(ext_set) } + + handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + + send_presence(q, conn, stream, jid, gcaps, initial=True) + + e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: handle in e.args[0]) + + assertEquals(1, len(e.args[0])) + rccs = e.args[0][handle] + + found = False + for fixed, allowed in rccs: + if fixed[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_CALL: + continue + + # we should only have InitialAudio or InitialVideo if + # voice-v1 or video-v1 is present respectively + for a, b in [('voice-v1' in ext_set, cs.CALL_INITIAL_AUDIO), + ('video-v1' in ext_set, cs.CALL_INITIAL_VIDEO)]: + if a: + assertContains(b, allowed) + else: + assertDoesNotContain(b, allowed) + + found = True + + assert found + if __name__ == '__main__': exec_test(test) @@ -204,3 +249,5 @@ if __name__ == '__main__': # And again, this time pulling the caps from the cache. This tests that the # quirk is cached! exec_test(partial(test_prefer_phones, expect_disco=False)) + + exec_test(test_google_caps) diff --git a/tests/twisted/cm/protocol.py b/tests/twisted/cm/protocol.py index 3320bfb22..e9c0b1c3b 100644 --- a/tests/twisted/cm/protocol.py +++ b/tests/twisted/cm/protocol.py @@ -53,7 +53,10 @@ def test(q, bus, conn, stream): 'hidden' : (cs.PRESENCE_HIDDEN, True, True)} presences = proto_prop_iface.Get(cs.PROTOCOL_IFACE_PRESENCES, 'Statuses'); - assertEquals(expected_status, unwrap(presences)) + # Plugins could add additional statuses, so we check if expected_status is + # included in presences rather than equality. + for k, v in expected_status.iteritems(): + assertEquals(expected_status[k], unwrap(presences[k])) # (Only) 'account' is mandatory for IdentifyAccount() call_async(q, proto_iface, 'IdentifyAccount', {}) diff --git a/tests/twisted/console.py b/tests/twisted/console.py index f6a6336c9..95c76a30e 100644 --- a/tests/twisted/console.py +++ b/tests/twisted/console.py @@ -9,6 +9,7 @@ from servicetest import ( from gabbletest import exec_test, acknowledge_iq, elem, elem_iq from config import PLUGINS_ENABLED from twisted.words.xish import domish +import ns CONSOLE_PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Console" STACY = 'stacy@pilgrim.lit' @@ -77,10 +78,15 @@ def test(q, bus, conn, stream): </message>''' % { 'stacy': STACY }) e = q.expect('stream-message', to=STACY, message_type='headline') - # Wocky fills in xmlns='' for us if we don't specify a namespace... great. - # So this means <message/> gets sent as <message xmlns=''/> and the server - # kicks us off. - assertNotEquals('', e.stanza.uri) + + # Make sure that Wocky has filled in the jabber:client namespace we + # carelessly omitted. + message = e.stanza + assertEquals('message', message.name) + assertEquals(ns.CLIENT, message.uri) + body = message.firstChildElement() + assertEquals('body', body.name) + assertEquals(ns.CLIENT, body.uri) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py index 0ea9d5b7f..d541c75fe 100644 --- a/tests/twisted/constants.py +++ b/tests/twisted/constants.py @@ -463,6 +463,20 @@ MT_NOTICE = 2 MT_AUTO_REPLY = 3 MT_DELIVERY_REPORT = 4 +class MessageFlag(object): + TRUNCATED = 1 + NON_TEXT_CONTENT = 2 + SCROLLBACK = 4 + RESCUED = 8 + +class SendError(object): + UNKNOWN = 0 + OFFLINE = 1 + INVALID_CONTACT = 2 + PERMISSION_DENIED = 3 + TOO_LONG = 4 + NOT_IMPLEMENTED = 5 + PROTOCOL = 'org.freedesktop.Telepathy.Protocol' PROTOCOL_IFACE_PRESENCES = PROTOCOL + '.Interface.Presence' PROTOCOL_IFACE_ADDRESSING = PROTOCOL + '.Interface.Addressing' diff --git a/tests/twisted/file-transfer/file_transfer_helper.py b/tests/twisted/file-transfer/file_transfer_helper.py index 4b72379da..79b3acf92 100644 --- a/tests/twisted/file-transfer/file_transfer_helper.py +++ b/tests/twisted/file-transfer/file_transfer_helper.py @@ -5,7 +5,7 @@ import time import datetime import os -from servicetest import EventPattern, assertEquals, call_async +from servicetest import EventPattern, assertEquals, assertSameSets, call_async from gabbletest import exec_test, sync_stream, make_result_iq import ns from bytestream import create_from_si_offer, announce_socks5_proxy @@ -218,7 +218,10 @@ class ReceiveFileTest(FileTransferTest): # check channel properties # org.freedesktop.Telepathy.Channel D-Bus properties assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER - assert props[cs.INTERFACES] == [] + assertSameSets( + [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA, + cs.CHANNEL_TYPE_FILE_TRANSFER + '.FUTURE', + ], props[cs.INTERFACES]) assert props[cs.TARGET_HANDLE] == self.handle assert props[cs.TARGET_ID] == self.contact_name assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT @@ -408,7 +411,10 @@ class SendFileTest(FileTransferTest): # org.freedesktop.Telepathy.Channel D-Bus properties assertEquals(cs.CHANNEL_TYPE_FILE_TRANSFER, props[cs.CHANNEL_TYPE]) - assertEquals([], props[cs.INTERFACES]) + assertSameSets( + [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA, + cs.CHANNEL_TYPE_FILE_TRANSFER + '.FUTURE', + ], props[cs.INTERFACES]) assertEquals(self.handle, props[cs.TARGET_HANDLE]) assertEquals(self.contact_name, props[cs.TARGET_ID]) assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE]) diff --git a/tests/twisted/gabbletest.py b/tests/twisted/gabbletest.py index aa63c6ddf..0985cd422 100644 --- a/tests/twisted/gabbletest.py +++ b/tests/twisted/gabbletest.py @@ -130,6 +130,7 @@ class JabberAuthenticator(GabbleAuthenticator): def streamStarted(self, root=None): if root: self.xmlstream.sid = '%x' % random.randint(1, sys.maxint) + self.xmlstream.domain = root.getAttribute('to') self.xmlstream.sendHeader() self.xmlstream.addOnetimeObserver( @@ -175,7 +176,7 @@ class JabberAuthenticator(GabbleAuthenticator): if self.resource is not None: assertEquals(self.resource, str(resource[0])) - self.bare_jid = '%s@localhost' % self.username + self.bare_jid = '%s@%s' % (self.username, self.xmlstream.domain) self.full_jid = '%s/%s' % (self.bare_jid, resource) result = IQ(self.xmlstream, "result") @@ -188,9 +189,12 @@ class XmppAuthenticator(GabbleAuthenticator): GabbleAuthenticator.__init__(self, username, password, resource) self.authenticated = False + self._mechanisms = ['PLAIN'] + def streamInitialize(self, root): if root: self.xmlstream.sid = root.getAttribute('id') + self.xmlstream.domain = root.getAttribute('to') if self.xmlstream.sid is None: self.xmlstream.sid = '%x' % random.randint(1, sys.maxint) @@ -212,7 +216,8 @@ class XmppAuthenticator(GabbleAuthenticator): def streamSASL(self): features = domish.Element((xmlstream.NS_STREAMS, 'features')) mechanisms = features.addElement((ns.NS_XMPP_SASL, 'mechanisms')) - mechanism = mechanisms.addElement('mechanism', content='PLAIN') + for mechanism in self._mechanisms: + mechanisms.addElement('mechanism', content=mechanism) self.xmlstream.send(features) self.xmlstream.addOnetimeObserver("/auth", self.auth) @@ -245,7 +250,7 @@ class XmppAuthenticator(GabbleAuthenticator): result = IQ(self.xmlstream, "result") result["id"] = iq["id"] bind = result.addElement((ns.NS_XMPP_BIND, 'bind')) - self.bare_jid = '%s@localhost' % self.username + self.bare_jid = '%s@%s' % (self.username, self.xmlstream.domain) self.full_jid = '%s/%s' % (self.bare_jid, resource) jid = bind.addElement('jid', content=self.full_jid) self.xmlstream.send(result) @@ -397,6 +402,12 @@ class BaseXmlStream(xmlstream.XmlStream): self.addObserver("/iq/query[@xmlns='%s']" % ns.PRIVACY, self._cb_priv_list) + def connectionMade(self): + xmlstream.XmlStream.connectionMade(self) + + if 'GABBLE_NODELAY' in os.environ: + self.transport.setTcpNoDelay(True) + def _cb_priv_list(self, iq): send_error_reply(self, iq) @@ -406,7 +417,7 @@ class BaseXmlStream(xmlstream.XmlStream): assert self.authenticator.bare_jid is not None self.addObserver( - "/iq[@to='localhost']/query[@xmlns='http://jabber.org/protocol/disco#info']", + "/iq[@to='%s']/query[@xmlns='http://jabber.org/protocol/disco#info']" % self.domain, self._cb_disco_iq) self.addObserver( "/iq[@to='%s']/query[@xmlns='http://jabber.org/protocol/disco#info']" @@ -446,6 +457,10 @@ class BaseXmlStream(xmlstream.XmlStream): # disconnect the TCP connection making tests as # connect/disconnect-timeout.py not working + def connectionLost(self, reason): + self.event_func(servicetest.Event('stream-connection-lost')) + xmlstream.XmlStream.connectionLost(self, reason) + def send_stream_error(self, error='system-shutdown'): # Yes, there are meant to be two different STREAMS namespaces. go_away = \ @@ -540,17 +555,29 @@ def disconnect_conn(q, conn, stream, expected_before=[], expected_after=[]): return before_events[:-2], after_events[:-1] +def element_repr(element): + """__repr__ cannot safely return non-ASCII: see + <http://bugs.python.org/issue5876>. So we print non-ASCII characters as + \uXXXX escapes in debug output + + """ + return element.toXml().encode('unicode-escape') + def exec_test_deferred(fun, params, protocol=None, timeout=None, authenticator=None, num_instances=1, do_connect=True): # hack to ease debugging - domish.Element.__repr__ = domish.Element.toXml + domish.Element.__repr__ = element_repr colourer = None if sys.stdout.isatty() or 'CHECK_FORCE_COLOR' in os.environ: colourer = servicetest.install_colourer() - bus = dbus.SessionBus() + try: + bus = dbus.SessionBus() + except dbus.exceptions.DBusException as e: + print e + os._exit(1) queue = servicetest.IteratingEventQueue(timeout) queue.verbose = ( diff --git a/tests/twisted/jingle-share/file_transfer_helper.py b/tests/twisted/jingle-share/file_transfer_helper.py index 2fe008795..19a45ca57 100644 --- a/tests/twisted/jingle-share/file_transfer_helper.py +++ b/tests/twisted/jingle-share/file_transfer_helper.py @@ -4,7 +4,7 @@ import hashlib import time import datetime -from servicetest import EventPattern, TimeoutError, assertEquals, assertLength +from servicetest import EventPattern, assertEquals, assertLength, assertSameSets from gabbletest import exec_test, sync_stream, make_result_iq, elem_iq, elem import ns @@ -273,7 +273,10 @@ class ReceiveFileTest(FileTransferTest): # check channel properties # org.freedesktop.Telepathy.Channel D-Bus properties assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, props - assert props[cs.INTERFACES] == [], props + assertSameSets( + [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA, + cs.CHANNEL_TYPE_FILE_TRANSFER + '.FUTURE', + ], props[cs.INTERFACES]) assert props[cs.TARGET_HANDLE] == self.handle, props assert props[cs.TARGET_ID] == self.target, props assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT, props @@ -425,7 +428,10 @@ class SendFileTest(FileTransferTest): # org.freedesktop.Telepathy.Channel D-Bus properties assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER - assert props[cs.INTERFACES] == [] + assertSameSets( + [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA, + cs.CHANNEL_TYPE_FILE_TRANSFER + '.FUTURE', + ], props[cs.INTERFACES]) assert props[cs.TARGET_HANDLE] == self.handle assert props[cs.TARGET_ID] == self.target assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT diff --git a/tests/twisted/jingle-share/jingleshareutils.py b/tests/twisted/jingle-share/jingleshareutils.py index 16c75fbda..6ade4f50d 100644 --- a/tests/twisted/jingle-share/jingleshareutils.py +++ b/tests/twisted/jingle-share/jingleshareutils.py @@ -64,19 +64,18 @@ def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, cli c = presence.addElement((ns.CAPS, 'c')) c['node'] = client c['ext'] = "share-v1" - c['ver'] = compute_caps_hash([], [], {}) + c['ver'] = '1.1' stream.send(presence) # Gabble looks up our capabilities event = q.expect('stream-iq', to=contact, query_ns=ns.DISCO_INFO) query_node = xpath.queryForNodes('/iq/query', event.stanza)[0] - assert query_node.attributes['node'] == \ - client + '#' + c['ext'] + assertEquals(client + '#' + c['ver'], query_node.attributes['node']) # send good reply result = make_result_iq(stream, event.stanza) query = result.firstChildElement() - query['node'] = client + '#' + c['ext'] + query['node'] = client + '#' + c['ver'] feature = query.addElement('feature') feature['var'] = ns.GOOGLE_FEAT_SHARE stream.send(result) diff --git a/tests/twisted/jingle-share/test-multift.py b/tests/twisted/jingle-share/test-multift.py index 7916281e6..d318e427d 100644 --- a/tests/twisted/jingle-share/test-multift.py +++ b/tests/twisted/jingle-share/test-multift.py @@ -1,22 +1,13 @@ import dbus -from twisted.words.xish import xpath from twisted.words.protocols.jabber.client import IQ -from servicetest import (assertEquals, EventPattern, TimeoutError) -from gabbletest import exec_test, make_result_iq, sync_stream, make_presence +from servicetest import assertEquals, assertSameSets, EventPattern +from gabbletest import exec_test, sync_stream import constants as cs -from caps_helper import compute_caps_hash, \ - text_fixed_properties, text_allowed_properties, \ - stream_tube_fixed_properties, stream_tube_allowed_properties, \ - dbus_tube_fixed_properties, dbus_tube_allowed_properties, \ - ft_fixed_properties, ft_allowed_properties - from jingleshareutils import test_ft_caps_from_contact -import ns - from config import JINGLE_FILE_TRANSFER_ENABLED if not JINGLE_FILE_TRANSFER_ENABLED: @@ -102,7 +93,10 @@ def test(q, bus, conn, stream): assert props[cs.FT_SIZE] == size, props assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, props - assert props[cs.INTERFACES] == [], props + assertSameSets( + [ cs.CHANNEL_IFACE_FILE_TRANSFER_METADATA, + cs.CHANNEL_TYPE_FILE_TRANSFER + '.FUTURE', + ], props[cs.INTERFACES]) assert props[cs.TARGET_HANDLE] == 2L, props assert props[cs.TARGET_ID] == contact.replace("/Resource", ""), props assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT, props @@ -128,34 +122,34 @@ def test(q, bus, conn, stream): event = q.expect('stream-iq', to=contact, iq_type='set', query_name='session') - stanza = event.stanza - session_node = xpath.queryForNodes('/iq/session', event.stanza)[0] + session_node = event.query assert session_node.attributes['type'] == 'transport-accept' - # Lower the timeout because we will do a q.expect where we expect it to - # timeout since we check for the *not* reception of the terminate - q.timeout = 2 + # Close all but one of the channels, and make sure Gabble doesn't cancel + # the multi-FT yet. + terminate_pattern = EventPattern('stream-iq', to=contact, iq_type='set', + query_name='session', + predicate=lambda event: event.query['type'] == 'terminate') - # Cancel all the channels and make sure gabble cancels the multiFT only - # once the last channel has been closed - last_path, props = channels[-1] - for i in range(len(channels)): - path, props = channels[i] + q.forbid_events([terminate_pattern]) + + for path, props in channels[:-1]: ft_chan = bus.get_object(conn.object.bus_name, path) channel = dbus.Interface(ft_chan, cs.CHANNEL) channel.Close() - try: - event = q.expect('stream-iq', to=contact, - iq_type='set', query_name='session') - # If the iq is received, it must be for the last channel closed - assert path == last_path, event - # Make sure it's a terminate message - stanza = event.stanza - session_node = xpath.queryForNodes('/iq/session', event.stanza)[0] - assert session_node.attributes['type'] == 'terminate' - except TimeoutError, e: - # Timeout only for the non last channel getting closed - assert path != last_path + q.expect('dbus-signal', signal='Closed', path=path) + + sync_stream(q, stream) + q.unforbid_all() + + # Now close the final channel, and make sure Gabble terminates the session. + last_path, props = channels[-1] + + ft_chan = bus.get_object(conn.object.bus_name, last_path) + channel = dbus.Interface(ft_chan, cs.CHANNEL) + channel.Close() + + q.expect_many(terminate_pattern) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/jingle/call-muc-cancel.py b/tests/twisted/jingle/call-muc-cancel.py index 62fa006c3..36fb23891 100644 --- a/tests/twisted/jingle/call-muc-cancel.py +++ b/tests/twisted/jingle/call-muc-cancel.py @@ -2,7 +2,7 @@ Test closing the muc channel while a muji request is in flight """ -from gabbletest import exec_test +from gabbletest import exec_test, disconnect_conn from servicetest import call_async import constants as cs @@ -25,7 +25,7 @@ def run_cancel_test(q, bus, conn, stream): q.expect('stream-presence', to = muc + "/test") - conn.Disconnect() + disconnect_conn(q, conn, stream) if __name__ == '__main__': exec_test (run_cancel_test) diff --git a/tests/twisted/jingle/call-muc-re-re-request.py b/tests/twisted/jingle/call-muc-re-re-request.py index 087c63f2c..1f72db4c8 100644 --- a/tests/twisted/jingle/call-muc-re-re-request.py +++ b/tests/twisted/jingle/call-muc-re-re-request.py @@ -36,16 +36,20 @@ def run_cancel_test(q, bus, conn, stream): # Accept the channel channel.Accept() - e = q.expect('stream-presence', to = muc + "/test") - mujinode = xpath.queryForNodes("/presence/muji/preparing", e.stanza) - assertNotEquals(None, mujinode) + def preparing(e): + node = xpath.queryForNodes("/presence/muji/preparing", e.stanza) + return node is not None + + q.expect('stream-presence', to = muc + "/test", predicate=preparing) channel.Hangup(0, "", "", dbus_interface=cs.CHANNEL_TYPE_CALL) - e = q.expect('stream-presence', to = muc + "/test") - mujinode = xpath.queryForNodes("/presence/muji/preparing", e.stanza) - assertEquals(None, mujinode) + def notpreparing(e): + node = xpath.queryForNodes("/presence/muji/preparing", e.stanza) + return node is None + + q.expect('stream-presence', to = muc + "/test", predicate=notpreparing) if x % 2 == 0: channel.Close() diff --git a/tests/twisted/jingle/decloak-peer.py b/tests/twisted/jingle/decloak-peer.py index d7c50b254..fa8f1ee50 100644 --- a/tests/twisted/jingle/decloak-peer.py +++ b/tests/twisted/jingle/decloak-peer.py @@ -6,10 +6,9 @@ should ask them to "de-cloak". from gabbletest import exec_test from servicetest import (make_channel_proxy, call_async, sync_dbus, assertEquals, assertLength) -import jingletest +from jingletest2 import JingleProtocol031, JingleTest2 import dbus -from twisted.words.xish import xpath import constants as cs import ns @@ -21,8 +20,10 @@ if not VOIP_ENABLED: raise SystemExit(77) def test(q, bus, conn, stream): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') - jt2 = jingletest.JingleTest(stream, 'test@localhost', 'foo2@bar.com/Foo') + jp = JingleProtocol031() + jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') + jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', + 'foo2@bar.com/Foo') # Make gabble think this is a different client jt2.remote_caps['node'] = 'http://example.com/fake-client1' @@ -37,7 +38,7 @@ def run_test(q, bus, conn, stream, jt, decloak_allowed): request = dbus.Dictionary({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: jt.remote_jid + cs.TARGET_ID: jt.peer, }, signature='sv') path, props = conn.CreateChannel(request, dbus_interface=cs.CONN_IFACE_REQUESTS) media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') @@ -47,18 +48,13 @@ def run_test(q, bus, conn, stream, jt, decloak_allowed): [cs.MEDIA_STREAM_TYPE_AUDIO]) e = q.expect('stream-presence', - to=jt.remote_bare_jid, presence_type=None) - nodes = xpath.queryForNodes('/presence/temppres[@xmlns="%s"]' - % ns.TEMPPRES, e.stanza) + to=jt.peer_bare_jid, presence_type=None) + nodes = [ node for node in e.stanza.elements(uri=ns.TEMPPRES, name='temppres') ] assertLength(1, nodes) assertEquals('media', nodes[0].getAttribute('reason')) if decloak_allowed: - jt.send_remote_presence() - info_event = q.expect('stream-iq', query_ns=ns.DISCO_INFO, - to=jt.remote_jid) - - jt.send_remote_disco_reply(info_event.stanza) + jt.send_presence_and_caps() # RequestStreams should now happily complete q.expect('dbus-return', method='RequestStreams') diff --git a/tests/twisted/jingle/google-relay.py b/tests/twisted/jingle/google-relay.py index 2ac72a2dd..18940fa16 100644 --- a/tests/twisted/jingle/google-relay.py +++ b/tests/twisted/jingle/google-relay.py @@ -14,7 +14,7 @@ from gabbletest import exec_test, make_result_iq, sync_stream, \ GoogleXmlStream, disconnect_conn from servicetest import make_channel_proxy, \ EventPattern, call_async, sync_dbus, assertEquals, assertLength -import jingletest +import jingletest2 import gabbletest import constants as cs import dbus @@ -85,7 +85,9 @@ TOO_SLOW_DISCONNECT = 3 TOO_SLOW_DISCONNECT_IMMEDIATELY = 4 def test(q, bus, conn, stream, incoming=True, too_slow=None, use_call=False): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') + jp = jingletest2.JingleProtocol031() + jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', + 'foo@bar.com/Foo') if use_call: # wjt only updated just about enough of this test for Call to check for @@ -108,7 +110,7 @@ def test(q, bus, conn, stream, incoming=True, too_slow=None, use_call=False): ]) # See: http://code.google.com/apis/talk/jep_extensions/jingleinfo.html - ji_event = q.expect('stream-iq', query_ns='google:jingleinfo', + ji_event = q.expect('stream-iq', query_ns=ns.GOOGLE_JINGLE_INFO, to='test@localhost') # Regression test for a bug where Gabble would crash if it disconnected @@ -181,17 +183,7 @@ def test(q, bus, conn, stream, incoming=True, too_slow=None, use_call=False): stream.send(iq) - # We need remote end's presence for capabilities - jt.send_remote_presence() - - # Gabble doesn't trust it, so makes a disco - event = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info', - to='foo@bar.com/Foo') - - jt.send_remote_disco_reply(event.stanza) - - # Force Gabble to process the capabilities - sync_stream(q, stream) + jt.send_presence_and_caps() remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] self_handle = conn.GetSelfHandle() diff --git a/tests/twisted/jingle/incoming-gmail-modern-jingle.py b/tests/twisted/jingle/incoming-gmail-modern-jingle.py index 34691306d..033a9975d 100644 --- a/tests/twisted/jingle/incoming-gmail-modern-jingle.py +++ b/tests/twisted/jingle/incoming-gmail-modern-jingle.py @@ -31,7 +31,8 @@ def test(q, bus, conn, stream): jt.prepare(send_roster=False) sid = 'c1025763497' - si = elem_iq(stream, 'set', from_=peer, to=self)( + iq_id = 'session_init_iq' + si = elem_iq(stream, 'set', from_=peer, to=self, id=iq_id)( elem(ns.JINGLE, 'jingle', action='session-initiate', sid=sid, initiator=peer)( elem('content', name='video')( elem(ns.JINGLE_RTP, 'description', media='video')( @@ -73,7 +74,11 @@ def test(q, bus, conn, stream): ) stream.send(si) - nc, nsh = q.expect_many( + ok, nc, nsh = q.expect_many( + # fd.o #65131: we have to tell Google which dialect we're speaking + EventPattern('stream-iq', iq_type='result', + query_name='jingle', query_ns=ns.JINGLE, + iq_id=iq_id), EventPattern('dbus-signal', signal='NewChannels'), EventPattern('dbus-signal', signal='NewSessionHandler'), ) diff --git a/tests/twisted/jingle/jingletest.py b/tests/twisted/jingle/jingletest.py deleted file mode 100644 index 104805032..000000000 --- a/tests/twisted/jingle/jingletest.py +++ /dev/null @@ -1,227 +0,0 @@ -""" -Jingle (XEP-0166) testing support. -""" - -import random -from gabbletest import make_presence -from twisted.words.xish import domish -from twisted.words.protocols.jabber.client import IQ -import dbus -from caps_helper import send_disco_reply - -class JingleTest: - - def __init__(self, stream, local_jid, remote_jid): - self.stream = stream - self.local_jid = local_jid - self.remote_jid = remote_jid - self.remote_bare_jid = remote_jid.split('/', 1)[0] - self.session_id = 'sess' + str(int(random.random() * 10000)) - self.google_mode = False - - # Default caps for the remote end - self.remote_caps = { 'ext': '', 'ver': '0.0.0', - 'node': 'http://example.com/fake-client0' } - - # Default feats for remote end - self.remote_feats = [ 'http://www.google.com/xmpp/protocol/session', - 'http://www.google.com/transport/p2p', - 'http://jabber.org/protocol/jingle', - # was previously in bundles: - 'http://jabber.org/protocol/jingle/description/audio', - 'http://jabber.org/protocol/jingle/description/video', - 'http://www.google.com/xmpp/protocol/voice/v1'] - - # Default audio codecs for the remote end - self.audio_codecs = [ ('GSM', 3, 8000), ('PCMA', 8, 8000), ('PCMU', 0, 8000) ] - - # Default video codecs for the remote end. I have no idea what's - # a suitable value here... - self.video_codecs = [ ('WTF', 42, 80000) ] - - # Default candidates for the remote end - self.remote_transports = [ - ( "192.168.0.1", # host - 666, # port - 0, # protocol = TP_MEDIA_STREAM_BASE_PROTO_UDP - "RTP", # protocol subtype - "AVP", # profile - 1.0, # preference - 0, # transport type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL, - "username", - "password" ) ] - - - def get_video_codecs_dbus(self): - return dbus.Array([ (id, name, 0, rate, 0, {} ) for (name, id, rate) in self.video_codecs ], - signature='(usuuua{ss})') - - - def get_audio_codecs_dbus(self): - return dbus.Array([ (id, name, 0, rate, 0, {} ) for (name, id, rate) in self.audio_codecs ], - signature='(usuuua{ss})') - - - def get_remote_transports_dbus(self): - return dbus.Array([ - (dbus.UInt32(1 + i), host, port, proto, subtype, - profile, pref, transtype, user, pwd) - for i, (host, port, proto, subtype, profile, - pref, transtype, user, pwd) - in enumerate(self.remote_transports) ], - signature='(usuussduss)') - - - def _jingle_stanza(self, action): - iq = IQ(self.stream, 'set') - iq['from'] = self.remote_jid - iq['to'] = self.local_jid - jingle = domish.Element(("http://jabber.org/protocol/jingle", 'jingle')) - if self.direction == 'incoming': - jingle['initiator'] = self.remote_jid - elif self.direction == 'outgoing': - jingle['initiator'] = self.local_jid - - jingle['action'] = action - jingle['sid'] = self.session_id - iq.addChild(jingle) - return (iq, jingle) - - def _gtalk_stanza(self, action): - iq = IQ(self.stream, 'set') - iq['from'] = self.remote_jid - iq['to'] = self.local_jid - sess = domish.Element(("http://www.google.com/session", 'session')) - if self.direction == 'incoming': - sess['initiator'] = self.remote_jid - elif self.direction == 'outgoing': - sess['initiator'] = self.local_jid - - sess['type'] = action - sess['id'] = self.session_id - iq.addChild(sess) - return (iq, sess) - - - def send_remote_presence(self): - presence = make_presence(self.remote_jid, self.local_jid, - caps=self.remote_caps) - self.stream.send(presence.toXml()) - - - def send_remote_disco_reply(self, stanza): - send_disco_reply(self.stream, stanza, [], self.remote_feats) - - def incoming_call(self, codec_parameters=None): - self.direction = 'incoming' - - if self.google_mode: - iq, sess = self._gtalk_stanza('initiate') - desc_ns = 'http://www.google.com/session/phone' - else: - iq, jingle = self._jingle_stanza('session-initiate') - desc_ns = 'http://jabber.org/protocol/jingle/description/audio' - - content = domish.Element((None, 'content')) - content['creator'] = 'initiator' - content['name'] = 'audio1' - content['senders'] = 'both' - - desc = domish.Element((desc_ns, 'description')) - for codec, id, rate in self.audio_codecs: - p = domish.Element((None, 'payload-type')) - p['name'] = codec - p['id'] = str(id) - - if self.google_mode: - p['clockrate'] = p['bitrate'] = str(rate) - else: - p['rate'] = str(rate) - - if codec_parameters is not None: - for name, value in codec_parameters.iteritems(): - param = domish.Element((None, 'parameter')) - param['name'] = name - param['value'] = value - p.addChild(param) - - desc.addChild(p) - - xport = domish.Element(("http://www.google.com/transport/p2p", 'transport')) - - if self.google_mode: - sess.addChild(desc) - sess.addChild(xport) - else: - jingle.addChild(content) - content.addChild(desc) - content.addChild(xport) - - self.stream.send(iq.toXml()) - - def create_content_node(self, name, type, codecs): - content = domish.Element((None, 'content')) - content['creator'] = 'initiator' - content['name'] = name - content['senders'] = 'both' - - desc = domish.Element(("http://jabber.org/protocol/jingle/description/" + type, 'description')) - for codec, id, rate in codecs: - p = domish.Element((None, 'payload-type')) - p['name'] = codec - p['id'] = str(id) - p['rate'] = str(rate) - desc.addChild(p) - content.addChild(desc) - - xport = domish.Element(("http://www.google.com/transport/p2p", 'transport')) - content.addChild(xport) - return content - - def outgoing_call_reply(self, session_id, accept, with_video=False): - self.session_id = session_id - self.direction = 'outgoing' - - if not accept: - self.remote_terminate() - return - - iq, jingle = self._jingle_stanza('session-accept') - - jingle.addChild(self.create_content_node('Audio', 'audio', - self.audio_codecs)) - - if with_video: - jingle.addChild(self.create_content_node('Video', 'video', - self.video_codecs)) - - self.stream.send(iq.toXml()) - - - def remote_terminate(self): - if self.google_mode: - iq, _ = self._gtalk_stanza('terminate') - else: - iq, _ = self._jingle_stanza('session-terminate') - self.stream.send(iq.toXml()) - - - def send_remote_candidates(self): - - iq, el = self._gtalk_stanza('candidates') - for t in self.remote_transports: - c = domish.Element((None, 'candidate')) - c['generation'] = '0' - c['network'] = '0' - c['type'] = 'local' - c['protocol'] = 'udp' - c['preference'] = str(t[5]) - c['password'] = t[8] - c['username'] = t[7] - c['port'] = str(t[1]) - c['address'] = t[0] - c['name'] = t[3].lower() - el.addChild(c) - - self.stream.send(iq.toXml()) - diff --git a/tests/twisted/jingle/jingletest2.py b/tests/twisted/jingle/jingletest2.py index 5ca91d428..64eaa40e8 100644 --- a/tests/twisted/jingle/jingletest2.py +++ b/tests/twisted/jingle/jingletest2.py @@ -3,9 +3,6 @@ # unreadable), but to make the expressions denser and more concise. # Helper classes support different dialects so the test can # be invoked for different (possibly all) dialects. -# -# This can be used in parallel with the old API, but should -# obsolete it in time. from functools import partial from twisted.words.xish import domish, xpath @@ -17,7 +14,7 @@ import ns import os import constants as cs -class JingleProtocol: +class JingleProtocol(object): """ Defines a simple DSL for constructing Jingle messages. """ @@ -496,7 +493,7 @@ class JingleProtocol031(JingleProtocol): return (self._extract_session_id(query), audio, video) -class JingleTest2: +class JingleTest2(object): # Default caps for the remote end remote_caps = { 'ext': '', 'ver': '0.0.0', 'node': 'http://example.com/fake-client0' } @@ -621,19 +618,23 @@ class JingleTest2: if send_presence: self.send_presence_and_caps() - def send_presence_and_caps(self): + def send_presence(self): # We need remote end's presence for capabilities self.stream.send(self.jp.xml( self.jp.Presence(self.peer, self.jid, self.remote_caps))) # Gabble doesn't trust it, so makes a disco - event = self.q.expect('stream-iq', query_ns=ns.DISCO_INFO, to=self.peer) + return self.q.expect('stream-iq', query_ns=ns.DISCO_INFO, to=self.peer) - # jt.send_remote_disco_reply(event.stanza) - self.stream.send(self.jp.xml(self.jp.ResultIq(self.jid, event.stanza, + def send_remote_disco_reply(self, query_stanza): + self.stream.send(self.jp.xml(self.jp.ResultIq(self.jid, query_stanza, [ self.jp.Query(None, ns.DISCO_INFO, [ self.jp.Feature(x) for x in self.jp.features ]) ]) )) + def send_presence_and_caps(self): + event = self.send_presence() + self.send_remote_disco_reply(event.stanza) + # Force Gabble to process the caps before doing any more Jingling sync_stream(self.q, self.stream) @@ -850,11 +851,11 @@ class JingleTest2: signature='(usqa{sv})') -def test_dialects(f, dialects): +def test_dialects(f, dialects, params=None, protocol=None): for dialect in dialects: - exec_test(partial(f, dialect())) + exec_test(partial(f, dialect()), params=params, protocol=protocol) -def test_all_dialects(f): +def test_all_dialects(f, params=None, protocol=None): dialectmap = { "jingle015": JingleProtocol015, "jingle031": JingleProtocol031, "gtalk03": GtalkProtocol03, @@ -868,4 +869,4 @@ def test_all_dialects(f): else: for d in jd.split (','): dialects.append(dialectmap[d]) - test_dialects(f, dialects) + test_dialects(f, dialects, params=params, protocol=protocol) diff --git a/tests/twisted/jingle/outgoing-ensure.py b/tests/twisted/jingle/outgoing-ensure.py index f2f1d5560..a5bab23c7 100644 --- a/tests/twisted/jingle/outgoing-ensure.py +++ b/tests/twisted/jingle/outgoing-ensure.py @@ -6,6 +6,7 @@ This also exercises calls to a contact on a SIP gateway, who has no resource, only a bare JID. """ +from functools import partial from gabbletest import exec_test from servicetest import ( wrap_channel, @@ -212,7 +213,5 @@ def test(q, bus, conn, stream, channel_type): chan.Close() if __name__ == '__main__': - exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, cs.CHANNEL_TYPE_STREAMED_MEDIA)) - exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, cs.CHANNEL_TYPE_CALL)) + exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_STREAMED_MEDIA)) + exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_CALL)) diff --git a/tests/twisted/jingle/outgoing-many-streams.py b/tests/twisted/jingle/outgoing-many-streams.py index ecdcf1182..b93ce616c 100644 --- a/tests/twisted/jingle/outgoing-many-streams.py +++ b/tests/twisted/jingle/outgoing-many-streams.py @@ -9,7 +9,7 @@ import dbus from gabbletest import exec_test, sync_stream from servicetest import ( make_channel_proxy, call_async, EventPattern) -import jingletest +import jingletest2 import gabbletest import constants as cs @@ -25,23 +25,13 @@ def test(q, bus, conn, stream): worker(q, bus, conn, stream, 'foo@sip.bar.com') def worker(q, bus, conn, stream, peer): - jt = jingletest.JingleTest(stream, 'test@localhost', peer) + jp = jingletest2.JingleProtocol031() + jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', peer) self_handle = conn.GetSelfHandle() + jt.send_presence_and_caps() - # We need remote end's presence for capabilities - jt.send_remote_presence() - - # Gabble doesn't trust it, so makes a disco - event = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info', - to=jt.remote_jid) - - jt.send_remote_disco_reply(event.stanza) - - # Force Gabble to process the caps before calling RequestChannel - sync_stream(q, stream) - - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.remote_jid])[0] + handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, @@ -77,7 +67,7 @@ def worker(q, bus, conn, stream, peer): assert emitted_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAMED_MEDIA assert emitted_props[cs.TARGET_HANDLE_TYPE] == cs.HT_CONTACT assert emitted_props[cs.TARGET_HANDLE] == handle - assert emitted_props[cs.TARGET_ID] == jt.remote_bare_jid, emitted_props + assert emitted_props[cs.TARGET_ID] == jt.peer_bare_jid, emitted_props assert emitted_props[cs.REQUESTED] == True assert emitted_props[cs.INITIATOR_HANDLE] == self_handle assert emitted_props[cs.INITIATOR_ID] == 'test@localhost' @@ -103,7 +93,7 @@ def worker(q, bus, conn, stream, peer): cs.TP_AWKWARD_PROPERTIES, cs.CHANNEL_IFACE_HOLD]: assert i in interfaces, (i, interfaces) - assert channel_props['TargetID'] == jt.remote_bare_jid, channel_props + assert channel_props['TargetID'] == jt.peer_bare_jid, channel_props assert channel_props['Requested'] == True assert channel_props['InitiatorID'] == 'test@localhost' assert channel_props['InitiatorHandle'] == self_handle @@ -205,8 +195,9 @@ def worker(q, bus, conn, stream, peer): assert e.query.name == 'jingle' assert e.query['action'] == 'session-initiate' stream.send(gabbletest.make_result_iq(stream, e.stanza)) + jt.parse_session_initiate(e.query) - jt.outgoing_call_reply(e.query['sid'], True) + jt.accept() q.expect('stream-iq', iq_type='result') diff --git a/tests/twisted/jingle/payload-types.py b/tests/twisted/jingle/payload-types.py index 10cb837da..64a300ff1 100644 --- a/tests/twisted/jingle/payload-types.py +++ b/tests/twisted/jingle/payload-types.py @@ -4,13 +4,11 @@ Regression test for https://bugs.freedesktop.org/show_bug.cgi?id=18918 import dbus -from gabbletest import exec_test, sync_stream -from servicetest import make_channel_proxy -import jingletest +from gabbletest import exec_test +from servicetest import wrap_channel, make_channel_proxy +import jingletest2 import constants as cs -from twisted.words.xish import domish - from config import VOIP_ENABLED if not VOIP_ENABLED: @@ -18,46 +16,24 @@ if not VOIP_ENABLED: raise SystemExit(77) def test(q, bus, conn, stream): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') + jp = jingletest2.JingleProtocol031() + jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', + 'foo@bar.com/Foo') self_handle = conn.GetSelfHandle() - # We need remote end's presence for capabilities - jt.send_remote_presence() - - # Gabble doesn't trust it, so makes a disco - event = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info', - to='foo@bar.com/Foo') - - jt.send_remote_disco_reply(event.stanza) + jt.send_presence_and_caps() - # Force Gabble to process the caps before calling RequestChannel - sync_stream(q, stream) - - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.remote_jid])[0] + handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] path = conn.RequestChannel( cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, handle, True) - channel = bus.get_object(conn.bus_name, path) - signalling_iface = make_channel_proxy(conn, path, 'Channel.Interface.MediaSignalling') - media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - group_iface = make_channel_proxy(conn, path, 'Channel.Interface.Group') - - # FIXME: Hack to make sure the disco info has been processed - we need to - # send Gabble some XML that will cause an event when processed, and - # wait for that event (until - # https://bugs.freedesktop.org/show_bug.cgi?id=15769 is fixed) - el = domish.Element(('jabber:client', 'presence')) - el['from'] = 'bob@example.com/Bar' - stream.send(el.toXml()) - q.expect('dbus-signal', signal='PresencesChanged') - # OK, now we can continue. End of hack - + channel = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') # Test that codec parameters are correctly sent in <parameter> children of # <payload-type> rather than as attributes of the latter. - media_iface.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) + channel.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) # S-E gets notified about new session handler, and calls Ready on it e = q.expect('dbus-signal', signal='NewSessionHandler') @@ -107,7 +83,8 @@ def test(q, bus, conn, stream): # Test that codec parameters are correctly extracted from <parameter> # children of <payload-type> rather than from attributes of the latter. - jt.incoming_call({'misc': 'other'}) + jt.audio_codecs = [ ('GSM', 3, 8000, {'misc': 'other'}) ] + jt.incoming_call() e = q.expect('dbus-signal', signal='NewSessionHandler') assert e.args[1] == 'rtp' diff --git a/tests/twisted/jingle/stream-handler-error.py b/tests/twisted/jingle/stream-handler-error.py index 8c3943b2b..5b05f6d15 100644 --- a/tests/twisted/jingle/stream-handler-error.py +++ b/tests/twisted/jingle/stream-handler-error.py @@ -8,7 +8,7 @@ from functools import partial from gabbletest import exec_test from servicetest import make_channel_proxy -import jingletest +import jingletest2 import constants as cs @@ -19,9 +19,11 @@ if not VOIP_ENABLED: raise SystemExit(77) def test(q, bus, conn, stream, call_error_on): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') + jp = jingletest2.JingleProtocol031() + jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', + 'foo@bar.com/Foo') - remote_handle = conn.RequestHandles(1, ["foo@bar.com/Foo"])[0] + remote_handle = conn.RequestHandles(1, [jt.peer])[0] # Remote end calls us jt.incoming_call() diff --git a/tests/twisted/jingle/stun-server.py b/tests/twisted/jingle/stun-server.py index 6b69ea3a6..0676993d4 100644 --- a/tests/twisted/jingle/stun-server.py +++ b/tests/twisted/jingle/stun-server.py @@ -2,16 +2,18 @@ Test getting STUN server from Google jingleinfo """ +from functools import partial import dbus import socket -from gabbletest import exec_test, make_result_iq, sync_stream, GoogleXmlStream +from gabbletest import make_result_iq, GoogleXmlStream, elem_iq, elem from servicetest import ( make_channel_proxy, EventPattern, assertEquals, assertLength, assertNotEquals, assertEquals ) -import jingletest +from jingletest2 import test_all_dialects, JingleTest2 import constants as cs +import ns from config import CHANNEL_TYPE_CALL_ENABLED, GOOGLE_RELAY_ENABLED, VOIP_ENABLED @@ -19,70 +21,71 @@ if not VOIP_ENABLED: print "NOTE: built with --disable-voip" raise SystemExit(77) -def test_stun_server(stun_server_prop, - expected_stun_server=None, expected_stun_port=None): - if expected_stun_server == None: - # If there is no stun server set then gabble should fallback on the - # default fallback stunserver (stun.collabora.co.uk) +def test_stun_server(stun_server_prop, expected_stun_servers=None): + if expected_stun_servers is None: + # If there is no stun server set, and it can't discover some from the + # network, then gabble should fallback on the default fallback stun + # server (stun.telepathy.im) + # # This test uses the test-resolver which is set to - # have 'stun.collabora.co.uk' resolve to '6.7.8.9' - expected_stun_server = '6.7.8.9' - expected_stun_port = 3478 - - assertEquals ([(expected_stun_server, expected_stun_port)], - stun_server_prop) - -def init_test(q, conn, stream, google=False): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') + # have 'stun.telepathy.im' resolve to '6.7.8.9' + expected_stun_servers=[('6.7.8.9', 3478)] + + assertEquals(expected_stun_servers, stun_server_prop) + +def add_jingle_info(jingleinfo, stun_server, stun_port): + stun = jingleinfo.firstChildElement().addElement('stun') + server = stun.addElement('server') + server['host'] = stun_server + server['udp'] = stun_port + relay = jingleinfo.firstChildElement().addElement('relay') + relay.addElement('token', content='jingle all the way') + +def handle_jingle_info_query(q, stream, stun_server, stun_port): + # See: http://code.google.com/apis/talk/jep_extensions/jingleinfo.html + event = q.expect('stream-iq', query_ns=ns.GOOGLE_JINGLE_INFO, + to=stream.authenticator.bare_jid) + jingleinfo = make_result_iq(stream, event.stanza) + add_jingle_info(jingleinfo, stun_server, stun_port) + stream.send(jingleinfo) + +def push_jingle_info(q, stream, stun_server, stun_port): + iq = elem_iq(stream, 'set')(elem(ns.GOOGLE_JINGLE_INFO, 'query')) + add_jingle_info(iq, stun_server, stun_port) + stream.send(iq) + q.expect('stream-iq', iq_type='result', iq_id=iq['id']) + +def init_test(jp, q, conn, stream, google=False, google_push_replacements=None): + jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') # If we need to override remote caps, feats, codecs or caps, # this is a good time to do it - # Connecting - conn.Connect() - - expected = [EventPattern('dbus-signal', signal='StatusChanged', - args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED])] - if google: - # See: http://code.google.com/apis/talk/jep_extensions/jingleinfo.html - expected.append(EventPattern('stream-iq', query_ns='google:jingleinfo', - to='test@localhost')) - - events = q.expect_many(*expected) - - if google: - event = events[-1] - jingleinfo = make_result_iq(stream, event.stanza) - stun = jingleinfo.firstChildElement().addElement('stun') - server = stun.addElement('server') - server['host'] = 'resolves-to-1.2.3.4' - server['udp'] = '12345' - relay = jingleinfo.firstChildElement().addElement('relay') - relay.addElement('token', content='jingle all the way') - stream.send(jingleinfo) - - # We need remote end's presence for capabilities - jt.send_remote_presence() + handle_jingle_info_query(q, stream, 'resolves-to-1.2.3.4', '12345') - # Gabble doesn't trust it, so makes a disco - event = q.expect('stream-iq', query_ns='http://jabber.org/protocol/disco#info', - to='foo@bar.com/Foo') - - jt.send_remote_disco_reply(event.stanza) + if google_push_replacements is not None: + # oh no! the server changed its mind! + server, port = google_push_replacements + push_jingle_info(q, stream, server, port) + else: + # We shouldn't be sending google:jingleinfo queries if the server + # doesn't support it. + q.forbid_events([ + EventPattern('stream-iq', query_ns=ns.GOOGLE_JINGLE_INFO), + ]) - # Force Gabble to process the caps before calling RequestChannel - sync_stream(q, stream) + jt.send_presence_and_caps() remote_handle = conn.RequestHandles(1, ["foo@bar.com/Foo"])[0] return jt, remote_handle -def test_streamed_media(q, bus, conn, stream, - expected_stun_server=None, expected_stun_port=None, google=False, +def test_streamed_media(jp, q, bus, conn, stream, + expected_stun_servers=None, google=False, google_push_replacements=None, expected_relays=[]): # Initialize the test values - jt, remote_handle = init_test(q, conn, stream, google) + jt, remote_handle = init_test(jp, q, conn, stream, google, google_push_replacements) # Remote end calls us jt.incoming_call() @@ -127,21 +130,7 @@ def test_streamed_media(q, bus, conn, stream, assert sh_props['NATTraversal'] == 'gtalk-p2p' assert sh_props['CreatedLocally'] == False - if expected_stun_server == None: - # If there is no stun server set then gabble should fallback on the - # default fallback stunserver (stun.telepathy.im) - # This test uses the test-resolver which is set to - # have 'stun.telepathy.im' resolve to '6.7.8.9' - expected_stun_server = '6.7.8.9' - expected_stun_port = 3478 - - if expected_stun_server is None: - assert sh_props['STUNServers'] == [], sh_props['STUNServers'] - else: - assert sh_props['STUNServers'] == \ - [(expected_stun_server, expected_stun_port)], \ - sh_props['STUNServers'] - + test_stun_server(sh_props['STUNServers'], expected_stun_servers) assert sh_props['RelayInfo'] == expected_relays # consistency check, since we currently reimplement Get separately @@ -187,10 +176,9 @@ def test_streamed_media(q, bus, conn, stream, assert tp_props['nat-traversal']['value'] == 'gtalk-p2p' - if expected_stun_server is not None: + if expected_stun_servers is not None: + expected_stun_server, expected_stun_port = expected_stun_servers[0] assert tp_props['stun-server']['value'] == expected_stun_server - - if expected_stun_port is not None: assert tp_props['stun-port']['value'] == expected_stun_port if google: @@ -200,17 +188,15 @@ def test_streamed_media(q, bus, conn, stream, q.expect_many( EventPattern('stream-iq', - predicate=lambda e: e.query is not None and - e.query.name == 'jingle' and - e.query['action'] == 'session-terminate'), + predicate=jp.action_predicate('session-terminate')), EventPattern('dbus-signal', signal='Closed'), ) -def test_call(q, bus, conn, stream, - expected_stun_server=None, expected_stun_port=None, google=False, +def test_call(jp, q, bus, conn, stream, + expected_stun_servers=None, google=False, google_push_replacements=None, expected_relays=[]): # Initialize the test values - jt, remote_handle = init_test(q, conn, stream, google) + jt, remote_handle = init_test(jp, q, conn, stream, google, google_push_replacements) # Advertise that we can do new style calls conn.ContactCapabilities.UpdateCapabilities([ @@ -272,67 +258,76 @@ def test_call(q, bus, conn, stream, dbus_interface=dbus.PROPERTIES_IFACE) assertEquals(cs.CALL_STREAM_TRANSPORT_GTALK_P2P, stream_props['Transport']) - test_stun_server(stream_props['STUNServers'], - expected_stun_server, expected_stun_port) + test_stun_server(stream_props['STUNServers'], expected_stun_servers) assertEquals(expected_relays, stream_props['RelayInfo']) assertEquals(True, stream_props['HasServerInfo']) if __name__ == '__main__': # StreamedMedia tests - exec_test(lambda q, b, c, s: test_streamed_media(q, b, c, s, - google=False), do_connect=False) - exec_test(lambda q, b, c, s: test_streamed_media(q, b, c, s, - google=False, expected_stun_server='5.4.3.2', expected_stun_port=54321), + test_all_dialects(partial(test_streamed_media, + google=False)) + test_all_dialects(partial(test_streamed_media, + google=False, expected_stun_servers=[('5.4.3.2', 54321)]), params={'fallback-stun-server': 'resolves-to-5.4.3.2', - 'fallback-stun-port': dbus.UInt16(54321)}, do_connect=False) + 'fallback-stun-port': dbus.UInt16(54321)}) + test_all_dialects(partial(test_streamed_media, google=False, + expected_stun_servers=[('5.4.3.2', 1)]), + params={'account': 'test@stunning.localhost'}) if GOOGLE_RELAY_ENABLED: - exec_test(lambda q, b, c, s: test_streamed_media(q, b, c, s, - google=True, expected_stun_server='1.2.3.4', expected_stun_port=12345), - protocol=GoogleXmlStream, do_connect=False) - exec_test(lambda q, b, c, s: test_streamed_media(q, b, c, s, - google=True, expected_stun_server='5.4.3.2', expected_stun_port=54321), + test_all_dialects(partial(test_streamed_media, + google=True, expected_stun_servers=[('1.2.3.4', 12345)]), + protocol=GoogleXmlStream) + test_all_dialects(partial(test_streamed_media, + google=True, expected_stun_servers=[('5.4.3.2', 54321)]), protocol=GoogleXmlStream, params={'stun-server': 'resolves-to-5.4.3.2', - 'stun-port': dbus.UInt16(54321)}, do_connect=False) - exec_test(lambda q, b, c, s: test_streamed_media(q, b, c, s, - google=True, expected_stun_server='1.2.3.4', expected_stun_port=12345), + 'stun-port': dbus.UInt16(54321)}) + test_all_dialects(partial(test_streamed_media, + google=True, expected_stun_servers=[('1.2.3.4', 12345)]), protocol=GoogleXmlStream, params={'fallback-stun-server': 'resolves-to-5.4.3.2', - 'fallback-stun-port': dbus.UInt16(54321)}, do_connect=False) + 'fallback-stun-port': dbus.UInt16(54321)}) + test_all_dialects(partial(test_streamed_media, + google=True, google_push_replacements=('resolves-to-5.4.3.2', '3838'), + expected_stun_servers=[('5.4.3.2', 3838)]), + protocol=GoogleXmlStream) else: print "NOTE: built with --disable-google-relay; omitting StreamedMedia tests with Google relay" # Call tests if CHANNEL_TYPE_CALL_ENABLED: - exec_test(lambda q, b, c, s: test_call(q, b, c, s, - google=False), do_connect=False) - exec_test(lambda q, b, c, s: test_call(q, b, c, s, - google=False, expected_stun_server='5.4.3.2', - expected_stun_port=54321), + test_all_dialects(partial(test_call, + google=False)) + test_all_dialects(partial(test_call, + google=False, expected_stun_servers=[('5.4.3.2', 54321)]), params={'fallback-stun-server': 'resolves-to-5.4.3.2', - 'fallback-stun-port': dbus.UInt16(54321)}, do_connect=False) + 'fallback-stun-port': dbus.UInt16(54321)}) + test_all_dialects(partial(test_call, + google=False, expected_stun_servers=[('5.4.3.2', 1)]), + params={'account': 'test@stunning.localhost'}) else: print "NOTE: built with --disable-channel-type-call; omitting Call tests" if CHANNEL_TYPE_CALL_ENABLED and GOOGLE_RELAY_ENABLED: - exec_test(lambda q, b, c, s: test_call(q, b, c, s, - google=True, expected_stun_server='1.2.3.4', - expected_stun_port=12345), - protocol=GoogleXmlStream, do_connect=False) - exec_test(lambda q, b, c, s: test_call(q, b, c, s, - google=True, expected_stun_server='5.4.3.2', - expected_stun_port=54321), + test_all_dialects(partial(test_call, + google=True, expected_stun_servers=[('1.2.3.4', 12345)]), + protocol=GoogleXmlStream) + test_all_dialects(partial(test_call, + google=True, expected_stun_servers=[('5.4.3.2', 54321)]), protocol=GoogleXmlStream, params={'stun-server': 'resolves-to-5.4.3.2', - 'stun-port': dbus.UInt16(54321)}, do_connect=False) - exec_test(lambda q, b, c, s: test_call(q, b, c, s, - google=True, expected_stun_server='1.2.3.4', - expected_stun_port=12345), + 'stun-port': dbus.UInt16(54321)}) + test_all_dialects(partial(test_call, + google=True, expected_stun_servers=[('1.2.3.4', 12345)]), protocol=GoogleXmlStream, params={'fallback-stun-server': 'resolves-to-5.4.3.2', - 'fallback-stun-port': dbus.UInt16(54321)}, do_connect=False) + 'fallback-stun-port': dbus.UInt16(54321)}) + test_all_dialects(partial(test_call, + google=True, google_push_replacements=('resolves-to-5.4.3.2', '3838'), + expected_stun_servers=[('5.4.3.2', 3838)]), + protocol=GoogleXmlStream) else: print "NOTE: built with --disable-channel-type-call or with --disable-google-relay; omitting Call tests with Google relay" diff --git a/tests/twisted/jingle/test-wait-for-caps-incomplete.py b/tests/twisted/jingle/test-wait-for-caps-incomplete.py index 353c33482..e6e97c226 100644 --- a/tests/twisted/jingle/test-wait-for-caps-incomplete.py +++ b/tests/twisted/jingle/test-wait-for-caps-incomplete.py @@ -4,9 +4,9 @@ and returns an error when Disconnect is called and there are incomplete requests. """ +from functools import partial from gabbletest import exec_test, disconnect_conn from servicetest import make_channel_proxy, call_async, sync_dbus, EventPattern -import jingletest import constants as cs @@ -17,13 +17,12 @@ if not VOIP_ENABLED: raise SystemExit(77) def test(q, bus, conn, stream, channel_type): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') - + peer = 'foo@bar.com/Foo' # We intentionally DON'T set remote presence yet. Since Gabble is still # unsure whether to treat contact as offline for this purpose, it # will tentatively allow channel creation and contact handle addition - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.remote_jid])[0] + handle = conn.RequestHandles(cs.HT_CONTACT, [peer])[0] if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, @@ -54,7 +53,7 @@ def test(q, bus, conn, stream, channel_type): call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: channel_type, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: jt.remote_jid, + cs.TARGET_ID: peer, cs.CALL_INITIAL_AUDIO: True }) @@ -66,10 +65,7 @@ def test(q, bus, conn, stream, channel_type): before_events[0].error if __name__ == '__main__': - exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, cs.CHANNEL_TYPE_STREAMED_MEDIA), timeout=10) - print "FIXME: leaks connection, everyone dies" - raise SystemExit(77) - exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, cs.CHANNEL_TYPE_CALL), timeout=10) - + exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_STREAMED_MEDIA), + timeout=10) + exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_CALL), + timeout=10) diff --git a/tests/twisted/jingle/test-wait-for-caps.py b/tests/twisted/jingle/test-wait-for-caps.py index f7eaa96a3..98221ef8e 100644 --- a/tests/twisted/jingle/test-wait-for-caps.py +++ b/tests/twisted/jingle/test-wait-for-caps.py @@ -4,14 +4,14 @@ attempts to call a contact. Gabble should delay the RequestStreams call until caps have arrived. """ +from functools import partial from gabbletest import exec_test from servicetest import make_channel_proxy, call_async, sync_dbus -import jingletest +import jingletest2 import dbus import constants as cs -import ns from config import VOIP_ENABLED @@ -20,8 +20,11 @@ if not VOIP_ENABLED: raise SystemExit(77) def test(q, bus, conn, stream, channel_type): - jt = jingletest.JingleTest(stream, 'test@localhost', 'foo@bar.com/Foo') - jt2 = jingletest.JingleTest(stream, 'test@localhost', 'foo2@bar.com/Foo') + jp = jingletest2.JingleProtocol031() + jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', + 'foo@bar.com/Foo') + jt2 = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', + 'foo2@bar.com/Foo') # Make gabble think this is a different client jt2.remote_caps['node'] = 'http://example.com/fake-client1' @@ -30,7 +33,7 @@ def test(q, bus, conn, stream, channel_type): def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type): """ - Requests streams on a media channel to jt.remote_jid, either before their + Requests streams on a media channel to jt.peer, either before their presence is received (if request_before_presence is True) or after their presence is received but before we've got a disco response for their capabilities (otherwise). @@ -41,7 +44,7 @@ def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type): # will tentatively allow channel creation and contact handle addition request = dbus.Dictionary({ cs.CHANNEL_TYPE: channel_type, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: jt.remote_jid + cs.TARGET_ID: jt.peer, }, signature='sv') if channel_type == cs.CHANNEL_TYPE_CALL: @@ -64,10 +67,6 @@ def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type): else: call_async(q, conn.Requests, 'CreateChannel', request) - def send_presence(): - jt.send_remote_presence() - return q.expect('stream-iq', query_ns=ns.DISCO_INFO, to=jt.remote_jid) - if request_before_presence: # Request streams before either <presence> or caps have arrived. Gabble # should wait for both to arrive before returning from RequestStreams. @@ -77,9 +76,9 @@ def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type): sync_dbus(bus, q, conn) # Now send the presence. - info_event = send_presence() + info_event = jt.send_presence() else: - info_event = send_presence() + info_event = jt.send_presence() # Now call RequestStreams; it should wait for the disco reply. call_request_streams() @@ -93,8 +92,8 @@ def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type): q.expect('dbus-return', method='CreateChannel') if __name__ == '__main__': - exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, cs.CHANNEL_TYPE_STREAMED_MEDIA), timeout=10) - exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, cs.CHANNEL_TYPE_CALL), timeout=10) + exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_STREAMED_MEDIA), + timeout=10) + exec_test(partial(test, channel_type=cs.CHANNEL_TYPE_CALL), + timeout=10) diff --git a/tests/twisted/jingle/unknown-session.py b/tests/twisted/jingle/unknown-session.py new file mode 100644 index 000000000..68c97c662 --- /dev/null +++ b/tests/twisted/jingle/unknown-session.py @@ -0,0 +1,38 @@ +""" +Tests that Gabble doesn't explode if it gets Jingle stanzas for unknown +sessions. +""" + +from gabbletest import exec_test +from servicetest import assertEquals +from jingletest2 import JingleProtocol031 +import ns + +def assertHasChild(node, uri, name): + try: + node.elements(uri=uri, name=name).next() + except StopIteration: + raise AssertionError( + "Expected <%s xmlns='%s'> to be a child of\n %s" % ( + name, uri, node.toXml())) + +def test_send_action_for_unknown_session(q, bus, conn, stream): + jp = JingleProtocol031() + peer = 'guybrush@threepwo.od' + + iq = jp.SetIq(peer, 'test@localhost', + [ jp.Jingle('fine-leather-jackets', peer, 'session-info', []) + ]) + stream.send(jp.xml(iq)) + + e = q.expect('stream-iq', iq_type='error', iq_id=iq[2]['id']) + stanza = e.stanza + error_node = stanza.children[-1] + assertEquals('error', error_node.name) + + # http://xmpp.org/extensions/xep-0166.html#example-29 + assertHasChild(error_node, ns.STANZA, 'item-not-found') + assertHasChild(error_node, ns.JINGLE_ERRORS, 'unknown-session') + +if __name__ == '__main__': + exec_test(test_send_action_for_unknown_session) diff --git a/tests/twisted/main-debug.c b/tests/twisted/main-debug.c index 2e860c17f..8bc16ff90 100644 --- a/tests/twisted/main-debug.c +++ b/tests/twisted/main-debug.c @@ -21,13 +21,16 @@ #include <stdlib.h> +#include <glib.h> + +#ifdef G_OS_UNIX +#include <netinet/in.h> +#include <netinet/tcp.h> +#endif + #include "gabble.h" #include "connection.h" #include "vcard-manager.h" -#ifdef ENABLE_VOIP -#include "jingle-factory.h" -#include "jingle-session.h" -#endif #ifdef ENABLE_JINGLE_FILE_TRANSFER #include "gtalk-file-collection.h" #endif @@ -36,12 +39,43 @@ #include <dbus/dbus.h> +#ifdef G_OS_UNIX +static gboolean +connection_established_cb (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer user_data) +{ + GSocketConnection *conn; + GSocket *sock; + gint flag, ret, fd; + + conn = g_value_get_object (param_values + 1); + sock = g_socket_connection_get_socket (conn); + + flag = 1; + + fd = g_socket_get_fd (sock); + ret = setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, + (const char *) &flag, sizeof (flag)); + + if (ret == -1) + /* not the worst thing ever. */ + g_print ("Couldn't setsockopt(TCP_NODELAY) on the connection; ain't so bad.\n"); + + return TRUE; +} +#endif + int main (int argc, char **argv) { int ret = 1; GResolver *kludged; +#ifdef G_OS_UNIX + gpointer cls; +#endif gabble_init (); @@ -66,20 +100,40 @@ main (int argc, test_resolver_add_A (TEST_RESOLVER (kludged), "stun.telepathy.im", "6.7.8.9"); + test_resolver_add_SRV (TEST_RESOLVER (kludged), + "stun", "udp", "stunning.localhost", "resolves-to-5.4.3.2", 1); + #ifdef ENABLE_VOIP - gabble_jingle_info_set_test_mode (); + wocky_jingle_info_set_test_mode (); #endif #ifdef ENABLE_JINGLE_FILE_TRANSFER gtalk_file_collection_set_test_mode (); #endif +#ifdef G_OS_UNIX + /* We want to set TCP_NODELAY on the socket as soon as possible in + * the connector so let's use ::connection-established. We need to + * ref the class type as it's not loaded yet. */ + cls = g_type_class_ref (WOCKY_TYPE_CONNECTOR); + if (g_getenv ("GABBLE_NODELAY") != NULL) + { + g_signal_add_emission_hook ( + g_signal_lookup ("connection-established", WOCKY_TYPE_CONNECTOR), + 0, connection_established_cb, NULL, NULL); + } +#endif + ret = gabble_main (argc, argv); /* Hack, remove the ref g_resolver has on this object, atm there is no way to * unset a custom resolver */ g_object_unref (kludged); +#ifdef G_OS_UNIX + g_type_class_unref (cls); +#endif + dbus_shutdown (); return ret; diff --git a/tests/twisted/muc/chat-states.py b/tests/twisted/muc/chat-states.py index edcbb3277..4be5f50b2 100644 --- a/tests/twisted/muc/chat-states.py +++ b/tests/twisted/muc/chat-states.py @@ -1,10 +1,10 @@ """ Regression test for <https://bugs.freedesktop.org/show_bug.cgi?id=32952>, -wherein chat states in MUCs were misparsed. +wherein chat states in MUCs were misparsed, and MUC chat states in general. """ -from servicetest import assertEquals -from gabbletest import exec_test, elem +from servicetest import assertEquals, assertLength, EventPattern +from gabbletest import exec_test, elem, make_muc_presence, sync_stream from mucutil import join_muc_and_check import ns import constants as cs @@ -12,10 +12,34 @@ import constants as cs MUC = 'ohai@groupchat.google.com' BOB = MUC + '/bob' +def get_state_notification(stanza): + for x in stanza.elements(): + if x.uri == ns.CHAT_STATES: + return x + + return None + +def check_state_notification(elem, name, allow_body=False): + assertEquals('message', elem.name) + assertEquals('groupchat', elem['type']) + + notification = get_state_notification(elem) + assert notification is not None, elem.toXml() + assert notification.name == name, notification.toXml() + + if not allow_body: + assert len(elem.children) == 1, elem.toXml() + def test(q, bus, conn, stream): (muc_handle, chan, user, bob) = join_muc_and_check(q, bus, conn, stream, MUC) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(user, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(bob, cs.CHAT_STATE_INACTIVE)) + stream.send( elem('message', from_=BOB, to='test@localhost/Resource', type='groupchat', jid='bob@bob.bob')( @@ -29,6 +53,12 @@ def test(q, bus, conn, stream): assertEquals(bob, contact) assertEquals(cs.CHAT_STATE_COMPOSING, state) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(user, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_COMPOSING, + states.get(bob, cs.CHAT_STATE_INACTIVE)) + stream.send( elem('message', from_=BOB, to='test@localhost/Resource', type='groupchat', jid='bob@bob.bob')( @@ -42,5 +72,77 @@ def test(q, bus, conn, stream): assertEquals(bob, contact) assertEquals(cs.CHAT_STATE_PAUSED, state) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(user, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_PAUSED, + states.get(bob, cs.CHAT_STATE_INACTIVE)) + + # Bob leaves + presence = make_muc_presence('owner', 'none', MUC, 'bob') + presence['type'] = 'unavailable' + stream.send(presence) + + e = q.expect('dbus-signal', signal='ChatStateChanged') + contact, state = e.args + assertEquals(bob, contact) + assertEquals(cs.CHAT_STATE_GONE, state) + + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(user, cs.CHAT_STATE_INACTIVE)) + # Bob no longer has any chat state at all + assertEquals(None, states.get(bob, None)) + + # Sending chat states: + + # Composing... + chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING) + + stream_message = q.expect('stream-message') + check_state_notification(stream_message.stanza, 'composing') + + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_COMPOSING, + states.get(user, cs.CHAT_STATE_INACTIVE)) + + # XEP 0085: + # every content message SHOULD contain an <active/> notification. + chan.Text.Send(0, 'hi.') + + stream_message = q.expect('stream-message') + stanza = stream_message.stanza + check_state_notification(stanza, 'active', allow_body=True) + + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_ACTIVE, + states.get(user, cs.CHAT_STATE_INACTIVE)) + + bodies = list(stanza.elements(uri=ns.CLIENT, name='body')) + assertLength(1, bodies) + assertEquals(u'hi.', bodies[0].children[0]) + + # If we get an error with type='wait', stop sending chat states. + stanza['type'] = 'error' + stanza['from'] = MUC + stanza['to'] = 'test@localhost/Resource' + + error = stanza.addElement('error') + error['type'] = 'wait' + error.addElement((ns.STANZA, 'resource-constraint')) + stream.send(stanza) + + q.expect('dbus-signal', signal='MessageReceived', + predicate=lambda e: e.args[0][0]['message-type'] == cs.MT_DELIVERY_REPORT) + + q.forbid_events([ + EventPattern('stream-message', to=MUC, + predicate=lambda e: get_state_notification(e.stanza) is not None) + ]) + + # User starts typing again but nothing should be seen or heard on the stream. + chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING) + sync_stream(q, stream) + if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/muc/only-text-when-needed.py b/tests/twisted/muc/only-text-when-needed.py new file mode 100644 index 000000000..260d26c8a --- /dev/null +++ b/tests/twisted/muc/only-text-when-needed.py @@ -0,0 +1,416 @@ +""" +Test support for creating MUC text channels when necessary, not all +the time. +""" + +import dbus + +from servicetest import call_async, EventPattern, assertEquals, \ + sync_dbus, wrap_channel +from gabbletest import exec_test, acknowledge_iq, make_muc_presence, \ + sync_stream, elem +import constants as cs +import ns + +from mucutil import echo_muc_presence + +def request_stream_tube(q, bus, conn, method, jid): + call_async(q, conn.Requests, method, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: jid, + cs.STREAM_TUBE_SERVICE: 'the.service', + }) + +def stream_tube(q, bus, conn, stream, method, jid, presence=True): + request_stream_tube(q, bus, conn, method, jid) + if presence: + send_muc_presence(q, stream, jid) + e, _ = q.expect_many(EventPattern('dbus-return', method=method), + EventPattern('dbus-signal', signal='NewChannels')) + + # sigh + if method == 'EnsureChannel': + path = e.value[1] + else: + path = e.value[0] + + tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamTube') + + return (tube_chan,) + e.value + +def request_text_channel(q, bus, conn, method, jid): + call_async(q, conn.Requests, method, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: jid, + }) + +def text_channel(q, bus, conn, stream, method, jid, presence=True): + request_text_channel(q, bus, conn, method, jid) + if presence: + send_muc_presence(q, stream, jid) + e, _ = q.expect_many(EventPattern('dbus-return', method=method), + EventPattern('dbus-signal', signal='NewChannels')) + + # sigh + if method == 'EnsureChannel': + path = e.value[1] + else: + path = e.value[0] + + text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') + + return (text_chan,) + e.value + +def send_muc_presence(q, stream, jid): + q.expect('stream-presence', to='%s/test' % jid) + + stream.send(make_muc_presence('owner', 'moderator', jid, 'bob')) + stream.send(make_muc_presence('none', 'participant', jid, 'test')) + +def expect_close(q, path, stream=None, jid=None): + forbid_unavailable = [EventPattern('stream-presence', + presence_type='unavailable', + to='%s/test' % jid)] + + if jid is not None: + e = q.expect_many(*forbid_unavailable)[0] + echo_muc_presence(q, stream, e.stanza, 'none', 'participant') + else: + q.forbid_events(forbid_unavailable) + + q.expect_many(EventPattern('dbus-signal', signal='ChannelClosed', + args=[path]), + EventPattern('dbus-signal', signal='Closed', + path=path)) + + if jid is not None: + q.unforbid_events(forbid_unavailable) + +def assert_on_bus(q, chan): + call_async(q, chan.Properties, 'GetAll', cs.CHANNEL) + e = q.expect('dbus-return', method='GetAll') + props = e.value[0] + assert 'ChannelType' in props + +def assert_not_on_bus(q, chan): + call_async(q, chan.Properties, 'GetAll', cs.CHANNEL) + q.expect('dbus-error', method='GetAll', + name='org.freedesktop.DBus.Error.UnknownMethod') + +# tests start here + +def tube_no_text(q, bus, conn, stream): + jid = 'test@conf.localhost' + + # create a stream tube. + # this will need a MUC channel to be opened, but we want to make + # sure it doesn't get signalled. + request_stream_tube(q, bus, conn, 'CreateChannel', jid) + + send_muc_presence(q, stream, jid) + + ret, new_sig = q.expect_many( + EventPattern('dbus-return', method='CreateChannel'), + EventPattern('dbus-signal', signal='NewChannels')) + + q.forbid_events([EventPattern('dbus-signal', signal='NewChannels')]) + + tube_path, tube_props = ret.value + assertEquals(cs.CHANNEL_TYPE_STREAM_TUBE, tube_props[cs.CHANNEL_TYPE]) + + channels = new_sig.args[0] + assertEquals(1, len(channels)) + path, props = channels[0] + + assertEquals(tube_path, path) + assertEquals(tube_props, props) + + sync_dbus(bus, q, conn) + + q.unforbid_all() + +def tube_then_text(q, bus, conn, stream): + jid = 'test@conf.localhost' + + # first let's get a stream tube + stream_tube(q, bus, conn, stream, 'CreateChannel', jid) + + # now let's try and ensure the text channel which should happen + # immediately + request_text_channel(q, bus, conn, 'EnsureChannel', jid) + + ret = q.expect('dbus-return', method='EnsureChannel') + + yours, text_path, text_props = ret.value + assertEquals(True, yours) + assertEquals(cs.CHANNEL_TYPE_TEXT, text_props[cs.CHANNEL_TYPE]) + + new_sig = q.expect('dbus-signal', signal='NewChannels') + + channels = new_sig.args[0] + assertEquals(1, len(channels)) + path, props = channels[0] + + assertEquals(text_path, path) + assertEquals(text_props, props) + +def tube_remains_text_closes(q, bus, conn, stream): + jid = 'test@conf.localhost' + + text_chan, text_path, _ = text_channel(q, bus, conn, stream, 'CreateChannel', jid) + tube_chan, tube_path, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid, + presence=False) + + # now let's try and close the text channel + # this should happen sucessfully but the tube channel + # should stick around + q.forbid_events([EventPattern('dbus-signal', signal='ChannelClosed', + args=[tube_path])]) + + text_chan.Close() + expect_close(q, text_path) + + sync_dbus(bus, q, conn) + + assert_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + + q.unforbid_all() + +def normally_close_text(q, bus, conn, stream): + jid = 'test@conf.localhost' + + text_chan, text_path, _ = text_channel(q, bus, conn, stream, 'CreateChannel', jid) + + sync_stream(q, stream) + + text_chan.Close() + expect_close(q, text_path, stream, jid) + + assert_not_on_bus(q, text_chan) + +def text_can_automatically_close(q, bus, conn, stream): + jid = 'test@conf.localhost' + + tube_chan, tube_path, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid) + + sync_dbus(bus, q, conn) + + tube_chan.Close() + expect_close(q, tube_path, stream, jid) + + assert_not_on_bus(q, tube_chan) + +def text_remains_after_tube(q, bus, conn, stream): + jid = 'test@conf.localhost' + + tube_chan, tube_path, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid) + text_chan, text_path, _ = text_channel(q, bus, conn, stream, 'CreateChannel', jid, + presence=False) + + sync_dbus(bus, q, conn) + + tube_chan.Close() + expect_close(q, tube_path) + + assert_not_on_bus(q, tube_chan) + assert_on_bus(q, text_chan) + + call_async(q, text_chan.Properties, 'GetAll', cs.CHANNEL_TYPE_TEXT) + q.expect('dbus-return', method='GetAll') + + text_chan.Close() + expect_close(q, text_path, stream, jid) + + assert_not_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + +def recreate_text(q, bus, conn, stream): + jid = 'test@conf.localhost' + + tube_chan, _, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid) + text_chan, text_path, text_props = text_channel(q, bus, conn, stream, + 'CreateChannel', jid, presence=False) + + text_chan.Close() + expect_close(q, text_path) + + assert_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + + # now let's try and create the same text channel and hope we get + # back the same channel + q.forbid_events([EventPattern('stream-presence', to='%s/test' % jid)]) + + request_text_channel(q, bus, conn, 'CreateChannel', jid) + + ret = q.expect('dbus-return', method='CreateChannel') + + path, props = ret.value + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + + new_sig = q.expect('dbus-signal', signal='NewChannels') + + channels = new_sig.args[0] + assertEquals(1, len(channels)) + + assertEquals(path, channels[0][0]) + assertEquals(props, channels[0][1]) + + # the channel should be identical given it's the same MucChannel + assertEquals(text_path, path) + assertEquals(text_props, props) + + assert_on_bus(q, tube_chan) + assert_on_bus(q, text_chan) + + q.unforbid_all() + +def test_channels(q, bus, conn, stream): + jid = 'test@conf.localhost' + + tube_chan, _, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid) + text_chan, text_path, _ = text_channel(q, bus, conn, stream,'CreateChannel', + jid, presence=False) + + text_chan.Close() + expect_close(q, text_path) + + # the following are basically the same as assert_[not_]on_bus() + # but they look pretty. + + # methods on the text channel should fail + call_async(q, text_chan.Properties, 'GetAll', cs.CHANNEL_TYPE_TEXT) + q.expect('dbus-error', method='GetAll') + + # but methods on the tube should pass + call_async(q, tube_chan.Properties, 'GetAll', cs.CHANNEL_TYPE_STREAM_TUBE) + q.expect('dbus-return', method='GetAll') + +def test_message(q, bus, conn, stream): + jid = 'test@conf.localhost' + + tube_chan, tube_path, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid) + + bob_jid = '%s/bob' % jid + bob_handle = conn.RequestHandles(cs.HT_CONTACT, [bob_jid])[0] + + # now let's send a message + stream.send( + elem('message', from_=bob_jid, type='groupchat')( + elem('body')( + u'oh hey i didnt see you there' + ), + ) + ) + + # the text channel appears! + e = q.expect('dbus-signal', signal='NewChannels') + channels = e.args[0] + assertEquals(1, len(channels)) + path, props = channels[0] + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + # make sure we didn't request it + assertEquals(False, props[cs.REQUESTED]) + assertEquals(bob_handle, props[cs.INITIATOR_HANDLE]) + + # and the message is then signalled + e = q.expect('dbus-signal', signal='MessageReceived', path=path) + parts = e.args[0] + + header = parts[0] + assertEquals(bob_handle, header['message-sender']) + assertEquals(bob_jid, header['message-sender-id']) + + body = parts[1] + assertEquals('oh hey i didnt see you there', body['content']) + +def test_requested_message(q, bus, conn, stream): + jid = 'test@conf.localhost' + + self_handle = conn.Properties.Get(cs.CONN, 'SelfHandle') + + text_chan, text_path, _ = text_channel(q, bus, conn, stream,'CreateChannel', jid) + tube_chan, tube_path, _ = stream_tube(q, bus, conn, stream, 'CreateChannel', jid, + presence=False) + + bob_jid = '%s/bob' % jid + bob_handle = conn.RequestHandles(cs.HT_CONTACT, [bob_jid])[0] + + # make sure it says we requested it + props = text_chan.Properties.GetAll(cs.CHANNEL) + assertEquals(True, props['Requested']) + assertEquals(self_handle, props['InitiatorHandle']) + + text_chan.Close() + expect_close(q, text_path) + + assert_on_bus(q, tube_chan) + assert_not_on_bus(q, text_chan) + + # now let's send a message + stream.send( + elem('message', from_=bob_jid, type='groupchat')( + elem('body')( + u'hello again' + ), + ) + ) + + e = q.expect('dbus-signal', signal='NewChannels') + channels = e.args[0] + assertEquals(1, len(channels)) + path, props = channels[0] + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + # now make sure we didn't request it + assertEquals(False, props[cs.REQUESTED]) + assertEquals(bob_handle, props[cs.INITIATOR_HANDLE]) + + e = q.expect('dbus-signal', signal='MessageReceived', path=path) + parts = e.args[0] + + header = parts[0] + assertEquals(bob_handle, header['message-sender']) + assertEquals(bob_jid, header['message-sender-id']) + + body = parts[1] + assertEquals('hello again', body['content']) + + assert_on_bus(q, tube_chan) + assert_on_bus(q, text_chan) + +if __name__ == '__main__': + # request tube, assert no text appears + exec_test(tube_no_text) + + # request tube, request text (no presence), assert both appear + exec_test(tube_then_text) + + # request tube & text, close text, assert tube doesn't close + exec_test(tube_remains_text_closes) + + # request text, close text, assert unavailable presence + exec_test(normally_close_text) + + # request tube, close tube, assert unavailable presence + exec_test(text_can_automatically_close) + + # request tube & text, close tube, assert text doesn't close + exec_test(text_remains_after_tube) + + # request tube & text, close text, request text (no presence), + # assert appears as normal + exec_test(recreate_text) + + # request tube & text, close text, assert GetAll on text fails but + # works on tube + exec_test(test_channels) + + # request tube, incoming message, assert text channel appears + exec_test(test_message) + + # request text & tube, close text, incoming message, assert text + # reappears with correct props + exec_test(test_requested_message) diff --git a/tests/twisted/muc/send-error.py b/tests/twisted/muc/send-error.py index 545d64285..33f376bf5 100644 --- a/tests/twisted/muc/send-error.py +++ b/tests/twisted/muc/send-error.py @@ -2,10 +2,11 @@ Test incoming error messages in MUC channels. """ +import warnings import dbus from gabbletest import exec_test -from servicetest import EventPattern +from servicetest import EventPattern, assertEquals, assertLength, assertContains import constants as cs import ns @@ -18,7 +19,47 @@ def test(q, bus, conn, stream): # Suppose we don't have permission to speak in this MUC. Send a message to # the channel, and have the MUC reject it as unauthorized. - content = u"hi r ther ne warez n this chanel?" + send_message_and_expect_error(q, stream, + text_chan, test_handle, bob_handle, + u"hi r ther ne warez n this chanel?", + '401', 'auth', 'not-authorized', + delivery_status=cs.DELIVERY_STATUS_PERMANENTLY_FAILED, + send_error_value=cs.SendError.PERMISSION_DENIED) + + # This time, we get rate-limited. + # <https://bugs.freedesktop.org/show_bug.cgi?id=43166> + send_message_and_expect_error(q, stream, + text_chan, test_handle, bob_handle, + "faster faster", + '500', 'wait', 'resource-constraint', + delivery_status=cs.DELIVERY_STATUS_TEMPORARILY_FAILED, + # Yuck this isn't a very good name is it? + send_error_value=cs.SendError.TOO_LONG) + + # How about an error message in the reply? This is from Prosody. See + # https://bugs.freedesktop.org/show_bug.cgi?id=43166#c9 + send_message_and_expect_error(q, stream, + text_chan, test_handle, bob_handle, + content=u"fair enough", + code=None, + type_='wait', + element='policy-violation', + error_message='The room is currently overactive, please try again later', + delivery_status=cs.DELIVERY_STATUS_TEMPORARILY_FAILED, + # Maybe we should expand the SendError codes some day, because this one + # is l-a-m-e. + send_error_value=cs.SendError.PERMISSION_DENIED) + + +def send_message_and_expect_error(q, stream, + text_chan, test_handle, bob_handle, + content, + code=None, + type_=None, + element=None, + error_message=None, + delivery_status=None, + send_error_value=None): greeting = [ dbus.Dictionary({ }, signature='sv'), { 'content-type': 'text/plain', @@ -26,8 +67,7 @@ def test(q, bus, conn, stream): } ] - sent_token = dbus.Interface(text_chan, cs.CHANNEL_IFACE_MESSAGES) \ - .SendMessage(greeting, dbus.UInt32(0)) + sent_token = text_chan.Messages.SendMessage(greeting, dbus.UInt32(0)) stream_message, _, _ = q.expect_many( EventPattern('stream-message'), @@ -41,9 +81,14 @@ def test(q, bus, conn, stream): elem['to'] = 'chat@conf.localhost/test' elem['type'] = 'error' error = elem.addElement('error') - error['code'] = '401' - error['type'] = 'auth' - error.addElement((ns.STANZA, 'not-authorized')) + if code is not None: + error['code'] = code + if type_ is not None: + error['type'] = type_ + if element is not None: + error.addElement((ns.STANZA, element)) + if error_message is not None: + error.addElement((ns.STANZA, 'text')).addContent(error_message) stream.send(elem) @@ -54,48 +99,69 @@ def test(q, bus, conn, stream): EventPattern('dbus-signal', signal='MessageReceived'), ) - PERMISSION_DENIED = 3 - err, timestamp, type, text = send_error.args - assert err == PERMISSION_DENIED, send_error.args + assertEquals(send_error_value, err) # there's no way to tell when the original message was sent from the error stanza - assert timestamp == 0, send_error.args + assertEquals(0, timestamp) # Gabble can't determine the type of the original message; see muc/test-muc.py # assert type == 0, send_error.args - assert text == content, send_error.args + assertEquals(content, text) # The Text.Received signal should be a "you're not tall enough" stub id, timestamp, sender, type, flags, text = received.args - assert sender == 0, received.args - assert type == 4, received.args # Message_Type_Delivery_Report - assert flags == 2, received.args # Non_Text_Content - assert text == '', received.args + + assertEquals(0, sender) + assertEquals(type, cs.MT_DELIVERY_REPORT) + + if flags == 0: + warnings.warn("ignoring tp-glib bug #61254") + else: + assertEquals(cs.MessageFlag.NON_TEXT_CONTENT, flags) + + if error_message is None: + assertEquals('', text) + else: + assertEquals(error_message, text) # Check that the Messages.MessageReceived signal was a failed delivery report - assert len(message_received.args) == 1, message_received.args + assertLength(1, message_received.args) parts = message_received.args[0] - # The delivery report should just be a header, no body. - assert len(parts) == 1, parts + + if error_message is None: + # The delivery report should just be a header, no body. + assertLength(1, parts) + else: + assertLength(2, parts) + part = parts[0] # The intended recipient was the MUC, so there's no contact handle # suitable for being 'message-sender'. - assert 'message-sender' not in part or part['message-sender'] == 0, part - assert part['message-type'] == 4, part # Message_Type_Delivery_Report - assert part['delivery-status'] == 3, part # Delivery_Status_Permanently_Failed - assert part['delivery-error'] == PERMISSION_DENIED, part - assert part['delivery-token'] == sent_token, part + assertEquals(0, part.get('message-sender', 0)) + assertEquals(cs.MT_DELIVERY_REPORT, part['message-type']) + assertEquals(delivery_status, part['delivery-status']) + assertEquals(send_error_value, part['delivery-error']) + assertEquals(sent_token, part['delivery-token']) # Check that the included echo is from us, and matches all the keys in the # message we sent. - assert 'delivery-echo' in part, part + assertContains('delivery-echo', part) echo = part['delivery-echo'] - assert len(echo) == len(greeting), (echo, greeting) - assert echo[0]['message-sender'] == test_handle, echo[0] - assert echo[0]['message-token'] == sent_token, echo[0] + assertLength(len(greeting), echo) + echo_header = echo[0] + assertEquals(test_handle, echo_header['message-sender']) + assertEquals(sent_token, echo_header['message-token']) + for i in range(0, len(echo)): for key in greeting[i]: assert key in echo[i], (i, key, echo) assert echo[i][key] == greeting[i][key], (i, key, echo, greeting) + if error_message is not None: + body = parts[1] + + assertEquals('text/plain', body['content-type']) + assertEquals(error_message, body['content']) + + if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/mucutil.py b/tests/twisted/mucutil.py index a7a0671d4..103b68b79 100644 --- a/tests/twisted/mucutil.py +++ b/tests/twisted/mucutil.py @@ -74,7 +74,7 @@ def join_muc(q, bus, conn, stream, muc, request=None, *also_capture) path, props = captured[0].value chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['Messages', 'Subject.DRAFT', 'RoomConfig1']) + ['Messages', 'Subject.DRAFT', 'RoomConfig1', 'ChatState']) return (muc_handle, chan, path, props) + tuple(captured[1:]) diff --git a/tests/twisted/ns.py b/tests/twisted/ns.py index e1e6db977..30f9a8114 100644 --- a/tests/twisted/ns.py +++ b/tests/twisted/ns.py @@ -2,6 +2,7 @@ AMP = "http://jabber.org/protocol/amp" BYTESTREAMS = 'http://jabber.org/protocol/bytestreams' CHAT_STATES = 'http://jabber.org/protocol/chatstates' CAPS = "http://jabber.org/protocol/caps" +CLIENT = "jabber:client" DISCO_INFO = "http://jabber.org/protocol/disco#info" DISCO_ITEMS = "http://jabber.org/protocol/disco#items" FEATURE_NEG = 'http://jabber.org/protocol/feature-neg' @@ -25,6 +26,7 @@ JINGLE_015 = "http://jabber.org/protocol/jingle" JINGLE_015_AUDIO = "http://jabber.org/protocol/jingle/description/audio" JINGLE_015_VIDEO = "http://jabber.org/protocol/jingle/description/video" JINGLE = "urn:xmpp:jingle:1" +JINGLE_ERRORS = "urn:xmpp:jingle:errors:1" JINGLE_RTP = "urn:xmpp:jingle:apps:rtp:1" JINGLE_RTP_AUDIO = "urn:xmpp:jingle:apps:rtp:audio" JINGLE_RTP_VIDEO = "urn:xmpp:jingle:apps:rtp:video" @@ -55,6 +57,7 @@ OLPC_CURRENT_ACTIVITY = "http://laptop.org/xmpp/current-activity" OLPC_CURRENT_ACTIVITY_NOTIFY = "%s+notify" % OLPC_CURRENT_ACTIVITY PUBSUB = "http://jabber.org/protocol/pubsub" PUBSUB_EVENT = "%s#event" % PUBSUB +RECEIPTS = "urn:xmpp:receipts" REGISTER = "jabber:iq:register" ROSTER = "jabber:iq:roster" SEARCH = 'jabber:iq:search' diff --git a/tests/twisted/presence/__init__.py b/tests/twisted/presence/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/twisted/presence/__init__.py diff --git a/tests/twisted/presence/invisible_xep_0126.py b/tests/twisted/presence/invisible_xep_0126.py index a22fe46c3..7dbfb36b7 100644 --- a/tests/twisted/presence/invisible_xep_0126.py +++ b/tests/twisted/presence/invisible_xep_0126.py @@ -8,8 +8,7 @@ XEP-0016 or XEP-0126. Some servers silently support it, like certain version of Ejabberd and all released versions of Prosody (as of 7.0). """ from gabbletest import ( - exec_test, XmppXmlStream, acknowledge_iq, send_error_reply, - disconnect_conn, elem, elem_iq + exec_test, acknowledge_iq, send_error_reply, elem, elem_iq ) from servicetest import ( EventPattern, assertEquals, assertNotEquals, assertContains, @@ -19,6 +18,7 @@ import ns import constants as cs from twisted.words.xish import xpath, domish from invisible_helper import ManualPrivacyListStream +from functools import partial def test_create_invisible_list(q, bus, conn, stream): conn.SimplePresence.SetPresence("away", "") @@ -49,6 +49,35 @@ def test_create_invisible_list(q, bus, conn, stream): assertContains("hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses")) +def test_create_invisible_list_failed(q, bus, conn, stream): + conn.SimplePresence.SetPresence("away", "") + + conn.Connect() + + stream.handle_get_all_privacy_lists(q, bus, conn) + + get_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='get') + list_node = xpath.queryForNodes('//list', get_list.query)[0] + assertEquals('invisible', list_node['name']) + + error = domish.Element((None, 'error')) + error['type'] = 'cancel' + error.addElement((ns.STANZA, 'item-not-found')) + send_error_reply (stream, get_list.stanza, error) + + create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') + list_node = xpath.queryForNodes('//list', create_list.query)[0] + assertEquals('invisible', list_node['name']) + assertNotEquals([], + xpath.queryForNodes('/query/list/item/presence-out', create_list.query)) + send_error_reply(stream, create_list.stanza) + + q.expect('dbus-signal', signal='StatusChanged', + args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) + + assertDoesNotContain("hidden", + conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses")) + def test_invisible_on_connect_fail_no_list(q, bus, conn, stream): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) @@ -83,7 +112,8 @@ def test_invisible_on_connect_fail_no_list(q, bus, conn, stream): assertDoesNotContain("hidden", conn.Properties.Get(cs.CONN_IFACE_SIMPLE_PRESENCE, "Statuses")) -def test_invisible_on_connect_fail_invalid_list(q, bus, conn, stream): +def test_invisible_on_connect_fail_invalid_list(q, bus, conn, stream, + really_invalid=False): props = conn.Properties.GetAll(cs.CONN_IFACE_SIMPLE_PRESENCE) assertNotEquals({}, props['Statuses']) @@ -101,10 +131,15 @@ def test_invisible_on_connect_fail_invalid_list(q, bus, conn, stream): list_node = xpath.queryForNodes('//list', get_list.query)[0] assertEquals('invisible', list_node['name']) - stream.send_privacy_list(get_list.stanza, - [elem('item', type='jid', value='tybalt@example.com', action='allow', - order='1')(elem('presence-out')), - elem('item', action='deny', order='2')(elem('presence-out'))]) + if really_invalid: + # At one point Gabble would crash if the reply was of type 'result' but + # wasn't well-formed. + acknowledge_iq(stream, get_list.stanza) + else: + stream.send_privacy_list(get_list.stanza, + [elem('item', type='jid', value='tybalt@example.com', action='allow', + order='1')(elem('presence-out')), + elem('item', action='deny', order='2')(elem('presence-out'))]) create_list = q.expect('stream-iq', query_ns=ns.PRIVACY, iq_type='set') created = xpath.queryForNodes('//list', create_list.stanza)[0] @@ -267,8 +302,7 @@ def test_privacy_list_push_conflict(q, bus, conn, stream): set_id = stream.send_privacy_list_push_iq("invisible") _, req_list = q.expect_many( - EventPattern('stream-iq', iq_type='result', predicate=lambda event: \ - event.stanza['id'] == set_id), + EventPattern('stream-iq', iq_type='result', iq_id=set_id), EventPattern('stream-iq', query_ns=ns.PRIVACY, iq_type="get")) stream.send_privacy_list(req_list.stanza, @@ -293,8 +327,7 @@ def test_privacy_list_push_valid(q, bus, conn, stream): set_id = stream.send_privacy_list_push_iq("invisible") _, req_list = q.expect_many( - EventPattern('stream-iq', iq_type='result', predicate=lambda event: \ - event.stanza['id'] == set_id), + EventPattern('stream-iq', iq_type='result', iq_id=set_id), EventPattern('stream-iq', query_ns=ns.PRIVACY, iq_type="get")) stream.send_privacy_list(req_list.stanza, @@ -316,10 +349,15 @@ if __name__ == '__main__': do_connect=False) exec_test(test_create_invisible_list, protocol=ManualPrivacyListStream, do_connect=False) + exec_test(test_create_invisible_list_failed, protocol=ManualPrivacyListStream, + do_connect=False) exec_test(test_invisible_on_connect_fail_no_list, protocol=ManualPrivacyListStream, do_connect=False) exec_test(test_invisible_on_connect_fail_invalid_list, protocol=ManualPrivacyListStream, do_connect=False) + exec_test(partial(test_invisible_on_connect_fail_invalid_list, + really_invalid=True), + protocol=ManualPrivacyListStream, do_connect=False) exec_test(test_privacy_list_push_valid, protocol=ManualPrivacyListStream, do_connect=False) exec_test(test_privacy_list_push_conflict, protocol=ManualPrivacyListStream, diff --git a/tests/twisted/run-test.sh.in b/tests/twisted/run-test.sh.in index 311a89d15..e6638553c 100644 --- a/tests/twisted/run-test.sh.in +++ b/tests/twisted/run-test.sh.in @@ -18,11 +18,26 @@ else list=$(cat @gabbletestsdir@/twisted/gabble-twisted-tests.list) fi -for i in $list ; do - echo "Testing $i" +any_failed=0 +for i in $list ; do + echo "Testing $i ..." sh @gabbletestsdir@/twisted/tools/with-session-bus.sh \ --config-file=@gabbletestsdir@/twisted/tools/servicedir/tmp-session-bus.conf \ -- \ @PYTHON@ @gabbletestsdir@/twisted/$i + e=$? + case "$e" in + (0) + echo "PASS: $i" + ;; + (77) + echo "SKIP: $i" + ;; + (*) + any_failed=1 + echo "FAIL: $i ($e)" + ;; + esac done +exit $any_failed diff --git a/tests/twisted/sasl/abort.py b/tests/twisted/sasl/abort.py index 2c906f631..1cb03f311 100644 --- a/tests/twisted/sasl/abort.py +++ b/tests/twisted/sasl/abort.py @@ -21,17 +21,20 @@ def test_abort_early(q, bus, conn, stream): chan, props = connect_and_get_sasl_channel(q, bus, conn) abort_auth(q, chan, 31337, "maybe if I use an undefined code you'll crash") -def test_abort_mid(q, bus, conn, stream): +def start_mechanism(q, bus, conn, + mechanism="ABORT-TEST", initial_response=EXCHANGE[0][1]): chan, props = connect_and_get_sasl_channel(q, bus, conn) - - chan.SASLAuthentication.StartMechanismWithData("ABORT-TEST", EXCHANGE[0][1]) + chan.SASLAuthentication.StartMechanismWithData(mechanism, initial_response) q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]) - e = q.expect('sasl-auth', initial_response=EXCHANGE[0][1]) - authenticator = e.authenticator + e = q.expect('sasl-auth', initial_response=initial_response) + return chan, e.authenticator + +def test_abort_mid(q, bus, conn, stream): + chan, authenticator = start_mechanism(q, bus, conn) authenticator.challenge(EXCHANGE[1][0]) q.expect('dbus-signal', signal='NewChallenge', @@ -42,16 +45,7 @@ def test_abort_mid(q, bus, conn, stream): "wrong data from server") def test_disconnect_mid(q, bus, conn, stream): - chan, props = connect_and_get_sasl_channel(q, bus, conn) - - chan.SASLAuthentication.StartMechanismWithData("ABORT-TEST", EXCHANGE[0][1]) - - q.expect('dbus-signal', signal='SASLStatusChanged', - interface=cs.CHANNEL_IFACE_SASL_AUTH, - args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]) - - e = q.expect('sasl-auth', initial_response=EXCHANGE[0][1]) - authenticator = e.authenticator + chan, authenticator = start_mechanism(q, bus, conn) authenticator.challenge(EXCHANGE[1][0]) q.expect('dbus-signal', signal='NewChallenge', @@ -65,17 +59,10 @@ def test_disconnect_mid(q, bus, conn, stream): EventPattern('dbus-return', method='Disconnect')) def test_abort_connected(q, bus, conn, stream): - chan, props = connect_and_get_sasl_channel(q, bus, conn) - - chan.SASLAuthentication.StartMechanismWithData('PLAIN', - '\0' + JID.split('@')[0] + '\0' + PASSWORD) - e, _ = q.expect_many( - EventPattern('sasl-auth'), - EventPattern('dbus-signal', signal='SASLStatusChanged', - interface=cs.CHANNEL_IFACE_SASL_AUTH, - args=[cs.SASL_STATUS_IN_PROGRESS, '', {}]), - ) - authenticator = e.authenticator + initial_response = '\0' + JID.split('@')[0] + '\0' + PASSWORD + chan, authenticator = start_mechanism(q, bus, conn, + mechanism='PLAIN', + initial_response=initial_response) authenticator.success(None) q.expect('dbus-signal', signal='SASLStatusChanged', @@ -86,31 +73,124 @@ def test_abort_connected(q, bus, conn, stream): q.expect('dbus-signal', signal='SASLStatusChanged', interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) - - e = q.expect('dbus-signal', signal='StatusChanged', - args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) + q.expect('dbus-signal', signal='StatusChanged', + args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) call_async(q, chan.SASLAuthentication, 'AbortSASL', cs.SASL_ABORT_REASON_USER_ABORT, "aborting too late") q.expect('dbus-error', method='AbortSASL', name=cs.NOT_AVAILABLE) chan.Close() +def test_give_up_while_waiting(q, bus, conn, stream, + channel_method, + authenticator_method): + """Regression test for https://bugs.freedesktop.org/show_bug.cgi?id=52146 + where closing the auth channel while waiting for a challenge from the + server would not abort the SASL exchange, and the challenge subsequently + arriving would make Gabble assert. + + """ + chan, authenticator = start_mechanism(q, bus, conn) + + # While Gabble is waiting for waiting for the server to make the next move, + # a Telepathy client does something to try to end the authentication + # process. + channel_method(chan) + + # And then we hear something back from the server. + authenticator_method(authenticator) + + # FIXME: Gabble should probably send <abort/> and wait for the server to + # say <failure><aborted/> rather than unceremoniously closing the + # connection. + # + # In the bug we're testing for, the stream connection would indeed be lost, + # but Gabble would also crash and leave a core dump behind. So this test + # would appear to pass, but 'make check' would fail as we want. + q.expect_many( + EventPattern('stream-connection-lost'), + EventPattern('dbus-signal', signal='ConnectionError'), + EventPattern( + 'dbus-signal', signal="StatusChanged", + args=[cs.CONN_STATUS_DISCONNECTED, + cs.CSR_AUTHENTICATION_FAILED]), + ) + +def test_close_then_challenge(q, bus, conn, stream): + """This is the specific scenario for which 52146 was reported. The channel + was being closed because its handler crashed. + + """ + test_give_up_while_waiting(q, bus, conn, stream, + lambda chan: chan.Close(), + lambda authenticator: authenticator.challenge(EXCHANGE[1][0])) + +def test_close_then_success(q, bus, conn, stream): + test_give_up_while_waiting(q, bus, conn, stream, + lambda chan: chan.Close(), + lambda authenticator: authenticator.success()) + +def test_close_then_failure(q, bus, conn, stream): + test_give_up_while_waiting(q, bus, conn, stream, + lambda chan: chan.Close(), + lambda authenticator: authenticator.not_authorized()) + +def test_abort_then_challenge(q, bus, conn, stream): + test_give_up_while_waiting(q, bus, conn, stream, + lambda chan: chan.SASLAuthentication.AbortSASL( + cs.SASL_ABORT_REASON_USER_ABORT, "bored now"), + lambda authenticator: authenticator.challenge(EXCHANGE[1][0])) + +def test_abort_then_success(q, bus, conn, stream): + """FIXME: this test fails because the channel changes its state from + TP_SASL_STATUS_CLIENT_FAILED to TP_SASL_STATUS_SERVER_SUCCEEDED and waits + for the client to ack it when <success> arrives, which is dumb. + + """ + test_give_up_while_waiting(q, bus, conn, stream, + lambda chan: chan.SASLAuthentication.AbortSASL( + cs.SASL_ABORT_REASON_USER_ABORT, "bored now"), + lambda authenticator: authenticator.success()) + +def test_abort_then_failure(q, bus, conn, stream): + test_give_up_while_waiting(q, bus, conn, stream, + lambda chan: chan.SASLAuthentication.AbortSASL( + cs.SASL_ABORT_REASON_USER_ABORT, "bored now"), + lambda authenticator: authenticator.not_authorized()) + +def abort_and_close(chan): + chan.SASLAuthentication.AbortSASL( + cs.SASL_ABORT_REASON_USER_ABORT, "bored now") + chan.Close() + +def test_abort_and_close_then_challenge(q, bus, conn, stream): + test_give_up_while_waiting(q, bus, conn, stream, + abort_and_close, + lambda authenticator: authenticator.challenge(EXCHANGE[1][0])) + +def test_abort_and_close_then_failure(q, bus, conn, stream): + test_give_up_while_waiting(q, bus, conn, stream, + abort_and_close, + lambda authenticator: authenticator.not_authorized()) + +def exec_test_(func): + # Can't use functools.partial, because the authenticator is stateful. + authenticator = SaslEventAuthenticator(JID.split('@')[0], MECHANISMS) + exec_test(func, do_connect=False, authenticator=authenticator, + params={'password': None, + 'account' : JID, + }) + if __name__ == '__main__': - exec_test(test_abort_early, - {'password': None,'account' : JID}, do_connect=False) - - exec_test(test_abort_mid, - {'password': None,'account' : JID}, - authenticator=SaslEventAuthenticator(JID.split('@')[0], - MECHANISMS), - do_connect=False) - exec_test(test_disconnect_mid, - {'password': None,'account' : JID}, - authenticator=SaslEventAuthenticator(JID.split('@')[0], - MECHANISMS), - do_connect=False) - - exec_test( - test_abort_connected, {'password': None,'account' : JID}, - authenticator=SaslEventAuthenticator(JID.split('@')[0], ['PLAIN']), - do_connect=False) + exec_test_(test_abort_early) + exec_test_(test_abort_mid) + exec_test_(test_disconnect_mid) + exec_test_(test_abort_connected) + exec_test_(test_close_then_challenge) + exec_test_(test_close_then_success) + exec_test_(test_close_then_failure) + exec_test_(test_abort_then_challenge) + # exec_test_(test_abort_then_success) + exec_test_(test_abort_then_failure) + exec_test_(test_abort_and_close_then_challenge) + exec_test_(test_abort_and_close_then_failure) diff --git a/tests/twisted/sasl/saslutil.py b/tests/twisted/sasl/saslutil.py index 5ad78727c..7d146146c 100644 --- a/tests/twisted/sasl/saslutil.py +++ b/tests/twisted/sasl/saslutil.py @@ -1,5 +1,4 @@ # hey, Python: encoding: utf-8 -from twisted.words.protocols.jabber.xmlstream import NS_STREAMS from gabbletest import XmppAuthenticator from base64 import b64decode, b64encode from twisted.words.xish import domish @@ -19,31 +18,11 @@ class SaslEventAuthenticator(XmppAuthenticator): XmppAuthenticator.__init__(self, jid, '') self._mechanisms = mechanisms - def streamStarted(self, root=None): - if root: - self.xmlstream.sid = root.getAttribute('id') + def streamSASL(self): + XmppAuthenticator.streamSASL(self) - self.xmlstream.sendHeader() - - if self.authenticated: - # Initiator authenticated itself, and has started a new stream. - - features = domish.Element((NS_STREAMS, 'features')) - bind = features.addElement((ns.NS_XMPP_BIND, 'bind')) - self.xmlstream.send(features) - - self.xmlstream.addOnetimeObserver( - "/iq/bind[@xmlns='%s']" % ns.NS_XMPP_BIND, self.bindIq) - else: - features = domish.Element((NS_STREAMS, 'features')) - mechanisms = features.addElement((ns.NS_XMPP_SASL, 'mechanisms')) - for mechanism in self._mechanisms: - mechanisms.addElement('mechanism', content=mechanism) - self.xmlstream.send(features) - - self.xmlstream.addOnetimeObserver("/auth", self._auth) - self.xmlstream.addObserver("/response", self._response) - self.xmlstream.addObserver("/abort", self._abort) + self.xmlstream.addObserver("/response", self._response) + self.xmlstream.addObserver("/abort", self._abort) def failure(self, fail_str): reply = domish.Element((ns.NS_XMPP_SASL, 'failure')) @@ -72,7 +51,7 @@ class SaslEventAuthenticator(XmppAuthenticator): reply.addContent(b64encode(data)) self.xmlstream.send(reply) - def _auth(self, auth): + def auth(self, auth): # Special case in XMPP: '=' means a zero-byte blob, whereas an empty # or self-terminating XML element means no initial response. # (RFC 3920 §6.2 (3)) diff --git a/tests/twisted/servicetest.py b/tests/twisted/servicetest.py index 28ed03f5b..31c00f476 100644 --- a/tests/twisted/servicetest.py +++ b/tests/twisted/servicetest.py @@ -8,6 +8,7 @@ from twisted.internet.protocol import Protocol, Factory, ClientFactory glib2reactor.install() import sys import time +import os import pprint import unittest @@ -154,6 +155,12 @@ class BaseEventQueue: """ self.forbidden_events.difference_update(set(patterns)) + def unforbid_all(self): + """ + Remove all patterns from the set of forbidden events. + """ + self.forbidden_events.clear() + def _check_forbidden(self, event): for e in self.forbidden_events: if e.match(event): @@ -647,6 +654,16 @@ def install_colourer(): sys.stdout = Colourer(sys.stdout, patterns) return sys.stdout -if __name__ == '__main__': - unittest.main() +# this is just to shut up unittest. +class DummyStream(object): + def write(self, s): + if 'CHECK_TWISTED_VERBOSE' in os.environ: + print s, + + def flush(self): + pass +if __name__ == '__main__': + stream = DummyStream() + runner = unittest.TextTestRunner(stream=stream) + unittest.main(testRunner=runner) diff --git a/tests/twisted/test-resolver.h b/tests/twisted/test-resolver.h index 3948fdca7..7863135f3 100644 --- a/tests/twisted/test-resolver.h +++ b/tests/twisted/test-resolver.h @@ -42,7 +42,6 @@ GType test_resolver_get_type (void); typedef struct { GResolver parent_instance; - GResolver *real_resolver; GList *fake_A; GList *fake_SRV; } TestResolver; diff --git a/tests/twisted/text/receipts.py b/tests/twisted/text/receipts.py new file mode 100644 index 000000000..45c7d9f89 --- /dev/null +++ b/tests/twisted/text/receipts.py @@ -0,0 +1,197 @@ +# coding=utf-8 +""" +Test XEP-0184 receipts. +""" + +from servicetest import ( + EventPattern, assertEquals, assertLength, sync_dbus, wrap_channel, +) +from gabbletest import exec_test, elem, sync_stream, acknowledge_iq +import constants as cs +import ns + +import caps_helper +import rostertest +from presence.invisible_helper import Xep0186Stream + +GUYBRUSH = 'guybrush@mi.lit' +GUYBRUSH_FULL_JID = GUYBRUSH + '/Sea Cucumber' + +def send_received_report(stream, jid, received_id): + stream.send( + elem('message', from_=jid)( + elem(ns.RECEIPTS, 'received', id=received_id) + )) + +def report_received_on_open_channel(q, bus, conn, stream, chan): + received_id = 'fine-leather-jackets' + + send_received_report(stream, GUYBRUSH, received_id) + e = q.expect('dbus-signal', signal='MessageReceived', path=chan.object_path) + message, = e.args + header, = message + + assertEquals(cs.MT_DELIVERY_REPORT, header['message-type']) + assertEquals(cs.DELIVERY_STATUS_DELIVERED, header['delivery-status']) + assertEquals(received_id, header['delivery-token']) + +def report_ignored_without_channel(q, bus, conn, stream): + q.forbid_events([EventPattern('dbus-signal', signal='MessageReceived')]) + send_received_report(stream, 'marley@mi.gov', 'only-one-candidate') + sync_dbus(bus, q, conn) + q.unforbid_all() + +def not_sending_request_to_contact(q, bus, conn, stream, chan): + message = [ + { 'message-type': cs.MT_NORMAL, + }, + { 'content-type': 'text/plain', + 'content': 'Mancomb Seepgood?', + }] + chan.Messages.SendMessage(message, 0) + + e = q.expect('stream-message', to=GUYBRUSH) + assertLength(0, list(e.stanza.elements(uri=ns.RECEIPTS, name='request'))) + +def sending_request_to_presenceless_contact(q, bus, conn, stream, chan): + """ + Initially we know nothing of Guybrush's presence, so should just try our + level best if asked to. + """ + message = [ + { 'message-type': cs.MT_NORMAL, + }, + { 'content-type': 'text/plain', + 'content': 'Thriftweed?', + }] + chan.Messages.SendMessage(message, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY) + + e = q.expect('stream-message', to=GUYBRUSH) + assertLength(1, list(e.stanza.elements(uri=ns.RECEIPTS, name='request'))) + +def sending_request_to_cappy_contact(q, bus, conn, stream, chan): + """ + Test that Gabble requests a receipt from a contact whom we know supports + this extension, but only if asked. + """ + + # Convince Gabble that Guybrush supports this extension + caps = { 'node': 'http://whatever', + 'ver': caps_helper.compute_caps_hash([], [ns.RECEIPTS], {}), + 'hash': 'sha-1', + } + caps_helper.presence_and_disco(q, conn, stream, GUYBRUSH_FULL_JID, + disco=True, + client=caps['node'], + caps=caps, + features=[ns.RECEIPTS]) + sync_stream(q, stream) + + # Don't ask, don't tell — even if we know Guybrush does support this. + not_sending_request_to_contact(q, bus, conn, stream, chan) + + # Ask, tell. + message = [ + { 'message-type': cs.MT_NORMAL, + }, + { 'content-type': 'text/plain', + 'content': 'Ulysses?', + }] + chan.Messages.SendMessage(message, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY) + + e = q.expect('stream-message', to=GUYBRUSH) + assertLength(1, list(e.stanza.elements(uri=ns.RECEIPTS, name='request'))) + +def replying_to_requests(q, bus, conn, stream): + jid = 'lechuck@lucasarts.lit' + + # We shouldn't send receipts to people who aren't on our roster. + q.forbid_events([EventPattern('stream-message', to=jid)]) + stream.send( + elem('message', from_=jid, type='chat', id='alpha')( + elem('body')( + u"You didn't kill me, you moron!" + ), + elem(ns.RECEIPTS, 'request') + )) + + q.expect('dbus-signal', signal='MessageReceived') + sync_stream(q, stream) + q.unforbid_all() + + # We should send receipts to people on our roster, seeing as we're not + # invisible. + rostertest.send_roster_push(stream, jid, subscription='from') + + stream.send( + elem('message', from_=jid, type='chat', id='beta')( + elem('body')( + u"You've just destroyed my spiritual essences." + ), + elem(ns.RECEIPTS, 'request') + )) + q.expect('dbus-signal', signal='MessageReceived') + e = q.expect('stream-message', to=jid) + receipt = e.stanza.elements(uri=ns.RECEIPTS, name='received').next() + assertEquals('beta', receipt['id']) + + # We would like requests in messages without id=''s not to crash Gabble, + # and also for it not to send a reply. + q.forbid_events([EventPattern('stream-message', to=jid)]) + stream.send( + elem('message', from_=jid, type='chat')( # NB. no id='' attribute + elem('body')( + u"A favor that I shall now return!" + ), + elem(ns.RECEIPTS, 'request') + )) + q.expect('dbus-signal', signal='MessageReceived') + sync_stream(q, stream) + q.unforbid_all() + + # If we're invisible, LeChuck shouldn't get receipts. + conn.SimplePresence.SetPresence("hidden", "") + event = q.expect('stream-iq', query_name='invisible') + acknowledge_iq(stream, event.stanza) + + q.forbid_events([EventPattern('stream-message', to=jid)]) + stream.send( + elem('message', from_=jid, type='chat', id='epsilon')( + elem('body')( + u"… but where am I going to find a duck wearing burlap chaps?" + ), + elem(ns.RECEIPTS, 'request') + )) + q.expect('dbus-signal', signal='MessageReceived') + sync_stream(q, stream) + q.unforbid_all() + +def test(q, bus, conn, stream): + path = conn.Requests.CreateChannel( + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_ID: GUYBRUSH, + })[0] + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', + ['Messages']) + + # Let's start out with an empty roster, eh? + e = q.expect('stream-iq', iq_type='get', query_ns=ns.ROSTER) + e.stanza['type'] = 'result' + stream.send(e.stanza) + + report_received_on_open_channel(q, bus, conn, stream, chan) + report_ignored_without_channel(q, bus, conn, stream) + not_sending_request_to_contact(q, bus, conn, stream, chan) + + # FIXME: This test is disabled because of stupidity in the presence cache. + # See the comment in receipts_conceivably_supported(). + #sending_request_to_presenceless_contact(q, bus, conn, stream, chan) + + sending_request_to_cappy_contact(q, bus, conn, stream, chan) + + replying_to_requests(q, bus, conn, stream) + + +if __name__ == '__main__': + exec_test(test, protocol=Xep0186Stream) diff --git a/tests/twisted/text/test-chat-state.py b/tests/twisted/text/test-chat-state.py index f161fd61d..c129fb7a3 100644 --- a/tests/twisted/text/test-chat-state.py +++ b/tests/twisted/text/test-chat-state.py @@ -6,8 +6,9 @@ channels. from twisted.words.xish import domish -from servicetest import assertEquals, assertNotEquals, \ - assertLength, wrap_channel, EventPattern +from servicetest import (assertEquals, assertNotEquals, + assertLength, wrap_channel, EventPattern, call_async, + sync_dbus) from gabbletest import exec_test, make_result_iq, sync_stream, make_presence import constants as cs import ns @@ -70,24 +71,62 @@ def test(q, bus, conn, stream): sync_stream(q, stream) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(self_handle, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(foo_handle, cs.CHAT_STATE_INACTIVE)) + # Receiving chat states: # Composing... stream.send(make_message(full_jid, state='composing')) - changed = q.expect('dbus-signal', signal='ChatStateChanged') + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) handle, state = changed.args assertEquals(foo_handle, handle) assertEquals(cs.CHAT_STATE_COMPOSING, state) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(self_handle, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_COMPOSING, + states.get(foo_handle, cs.CHAT_STATE_INACTIVE)) + # Message! stream.send(make_message(full_jid, body='hello', state='active')) - changed = q.expect('dbus-signal', signal='ChatStateChanged') + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) handle, state = changed.args assertEquals(foo_handle, handle) assertEquals(cs.CHAT_STATE_ACTIVE, state) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_INACTIVE, + states.get(self_handle, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_ACTIVE, + states.get(foo_handle, cs.CHAT_STATE_INACTIVE)) + + # Assert that a redundant chat-state change doesn't emit a signal + + forbidden = [EventPattern('dbus-signal', signal='ChatStateChanged', + args=[foo_handle, cs.CHAT_STATE_ACTIVE])] + q.forbid_events(forbidden) + + m = domish.Element((None, 'message')) + m['from'] = 'foo@bar.com/Foo' + m['type'] = 'chat' + m.addElement((ns.CHAT_STATES, 'active')) + m.addElement('body', content='hello') + stream.send(m) + + sync_dbus(bus, q, conn) + sync_stream(q, stream) + + q.unforbid_events(forbidden) + # Sending chat states: # Composing... @@ -96,6 +135,12 @@ def test(q, bus, conn, stream): stream_message = q.expect('stream-message') check_state_notification(stream_message.stanza, 'composing') + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_COMPOSING, + states.get(self_handle, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_ACTIVE, + states.get(foo_handle, cs.CHAT_STATE_INACTIVE)) + # XEP 0085: # every content message SHOULD contain an <active/> notification. chan.Text.Send(0, 'hi.') @@ -106,6 +151,12 @@ def test(q, bus, conn, stream): check_state_notification(elem, 'active', allow_body=True) + states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') + assertEquals(cs.CHAT_STATE_ACTIVE, + states.get(self_handle, cs.CHAT_STATE_INACTIVE)) + assertEquals(cs.CHAT_STATE_ACTIVE, + states.get(foo_handle, cs.CHAT_STATE_INACTIVE)) + def is_body(e): if e.name == 'body': assert e.children[0] == u'hi.', e.toXml() @@ -172,7 +223,8 @@ def test(q, bus, conn, stream): stream.send(make_message(full_jid, body='i am invisible', state='active')) - changed = q.expect('dbus-signal', signal='ChatStateChanged') + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) assertEquals(cs.CHAT_STATE_ACTIVE, changed.args[1]) # We've seen them send a chat state notification, so we should send them @@ -181,7 +233,8 @@ def test(q, bus, conn, stream): stream_message = q.expect('stream-message', to=full_jid) check_state_notification(stream_message.stanza, 'composing') - changed = q.expect('dbus-signal', signal='ChatStateChanged') + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) handle, state = changed.args assertEquals(cs.CHAT_STATE_COMPOSING, state) assertEquals(self_handle, handle) @@ -204,11 +257,18 @@ def test(q, bus, conn, stream): ['ChatState']) # We shouldn't send any notifications until we actually send a message. + # But ChatStateChanged is still emitted locally e = EventPattern('stream-message', to=jid) q.forbid_events([e]) - for i in [cs.CHAT_STATE_COMPOSING, cs.CHAT_STATE_INACTIVE, - cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_ACTIVE]: + for i in [cs.CHAT_STATE_ACTIVE, cs.CHAT_STATE_COMPOSING, + cs.CHAT_STATE_PAUSED, cs.CHAT_STATE_INACTIVE ]: chan.ChatState.SetChatState(i) + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) + handle, state = changed.args + assertEquals(i, state) + assertEquals(self_handle, handle) + sync_stream(q, stream) q.unforbid_events([e]) @@ -217,15 +277,23 @@ def test(q, bus, conn, stream): stream_message = q.expect('stream-message', to=jid) check_state_notification(stream_message.stanza, 'active', allow_body=True) + # The D-Bus property changes, too + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) + handle, state = changed.args + assertEquals(cs.CHAT_STATE_ACTIVE, state) + assertEquals(self_handle, handle) + # We get a notification back from our contact. stream.send(make_message(full_jid, state='composing')) # Wait until gabble tells us the chat-state of the remote party has # changed so we know gabble knows chat state notification are supported - changed = q.expect('dbus-signal', signal='ChatStateChanged') + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) handle, state = changed.args assertEquals(cs.CHAT_STATE_COMPOSING, state) - assertNotEquals(self_handle, handle) + assertNotEquals(foo_handle, handle) # So now we know they support notification, so should send notifications. chan.ChatState.SetChatState(cs.CHAT_STATE_COMPOSING) @@ -244,6 +312,13 @@ def test(q, bus, conn, stream): stream_message = q.expect('stream-message') check_state_notification(stream_message.stanza, 'composing') + # The D-Bus property changes, too + changed = q.expect('dbus-signal', signal='ChatStateChanged', + path=chan.object_path) + handle, state = changed.args + assertEquals(cs.CHAT_STATE_COMPOSING, state) + assertEquals(self_handle, handle) + # But! Now they start messaging us from a different client, which *doesn't* # support notifications. other_jid = jid + '/Library' diff --git a/tests/twisted/tls/server-tls-channel.py b/tests/twisted/tls/server-tls-channel.py index 7823eacc5..6528e696d 100644 --- a/tests/twisted/tls/server-tls-channel.py +++ b/tests/twisted/tls/server-tls-channel.py @@ -47,8 +47,6 @@ class TlsAuthenticator(XmppAuthenticator): starttls = features.addElement((ns.NS_XMPP_TLS, 'starttls')) starttls.addElement('required') - mechanisms = features.addElement((ns.NS_XMPP_SASL, 'mechanisms')) - mechanism = mechanisms.addElement('mechanism', content='PLAIN') self.xmlstream.send(features) self.xmlstream.addOnetimeObserver("/starttls", self.tlsAuth) @@ -64,19 +62,13 @@ class TlsAuthenticator(XmppAuthenticator): self.streamTLS() def tlsAuth(self, auth): - try: - file = open(CA_KEY, 'rb') - pem_key = file.read() + with open(CA_KEY, 'rb') as f: + pem_key = f.read() pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, pem_key, "") - finally: - file.close() - try: - file = open(CA_CERT, 'rb') - pem_cert = file.read() + with open(CA_CERT, 'rb') as f: + pem_cert = f.read() cert = crypto.load_certificate(crypto.FILETYPE_PEM, pem_cert) - finally: - file.close() tls_ctx = ssl.CertificateOptions(privateKey=pkey, certificate=cert) diff --git a/tests/twisted/tools/exec-with-log.sh.in b/tests/twisted/tools/exec-with-log.sh.in index 11302e6f6..9210eecc5 100644 --- a/tests/twisted/tools/exec-with-log.sh.in +++ b/tests/twisted/tools/exec-with-log.sh.in @@ -14,6 +14,8 @@ WOCKY_CAPS_CACHE=:memory: export WOCKY_CAPS_CACHE WOCKY_CAPS_CACHE_SIZE=50 export WOCKY_CAPS_CACHE_SIZE +G_MESSAGES_DEBUG=all +export G_MESSAGES_DEBUG ulimit -c unlimited exec >> gabble-testing.log 2>&1 diff --git a/tests/twisted/tubes/accept-muc-dbus-tube.py b/tests/twisted/tubes/accept-muc-dbus-tube.py index fb841c3ca..df5b81ed0 100644 --- a/tests/twisted/tubes/accept-muc-dbus-tube.py +++ b/tests/twisted/tubes/accept-muc-dbus-tube.py @@ -1,6 +1,9 @@ import dbus -from servicetest import assertEquals, assertNotEquals, call_async, EventPattern +from servicetest import ( + assertEquals, assertNotEquals, assertSameSets, + call_async, EventPattern, +) from gabbletest import exec_test, acknowledge_iq, make_muc_presence import constants as cs @@ -37,20 +40,20 @@ def test(q, bus, conn, stream, access_control): parameter.addContent('bar') stream.send(presence) - # tubes channel is created - event = q.expect('dbus-signal', signal='NewChannels') - channels = event.args[0] - path, props = channels[0] - # tube channel is created - event = q.expect('dbus-signal', signal='NewChannels') + def new_chan_predicate(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE + + event = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) channels = event.args[0] path, props = channels[0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals('chat@conf.localhost/bob', props[cs.INITIATOR_ID]) bob_handle = props[cs.INITIATOR_HANDLE] - assertEquals([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], + assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], props[cs.INTERFACES]) assertEquals(False, props[cs.REQUESTED]) assertEquals('chat@conf.localhost', props[cs.TARGET_ID]) diff --git a/tests/twisted/tubes/accept-muc-stream-tube.py b/tests/twisted/tubes/accept-muc-stream-tube.py index 01e65fdb2..7fc4aa0a6 100644 --- a/tests/twisted/tubes/accept-muc-stream-tube.py +++ b/tests/twisted/tubes/accept-muc-stream-tube.py @@ -4,15 +4,14 @@ import sys import dbus -from servicetest import call_async, EventPattern, EventProtocolClientFactory, unwrap, assertEquals -from gabbletest import make_result_iq, acknowledge_iq, make_muc_presence, send_error_reply, disconnect_conn +from servicetest import call_async, EventPattern, assertEquals, assertSameSets +from gabbletest import acknowledge_iq, make_muc_presence, send_error_reply, disconnect_conn import constants as cs import ns import tubetestutil as t from bytestream import create_from_si_offer, announce_socks5_proxy, BytestreamS5BRelay, BytestreamS5BRelayBugged from twisted.words.xish import xpath -from twisted.internet import reactor sample_parameters = dbus.Dictionary({ 's': 'hello', @@ -49,8 +48,10 @@ def test(q, bus, conn, stream, bytestream_cls, room_handle = handles[0] # join the muc - call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, - room_handle, True) + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_HANDLE: room_handle}) _, stream_event = q.expect_many( EventPattern('dbus-signal', signal='MembersChanged', @@ -70,7 +71,7 @@ def test(q, bus, conn, stream, bytestream_cls, assert conn.InspectHandles(1, [3]) == ['chat@conf.localhost/bob'] bob_handle = 3 - event = q.expect('dbus-return', method='RequestChannel') + event = q.expect('dbus-return', method='CreateChannel') # Bob offers a stream tube stream_tube_id = 666 @@ -112,51 +113,13 @@ def test(q, bus, conn, stream, bytestream_cls, path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT - # tubes channel is automatically created - event, new_event = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels')) - - assert event.args[1] == cs.CHANNEL_TYPE_TUBES, event.args - assert event.args[2] == cs.HT_ROOM - assert event.args[3] == room_handle - - tubes_chan = bus.get_object(conn.bus_name, event.args[0]) - tubes_iface = dbus.Interface(tubes_chan, event.args[1]) - - channel_props = tubes_chan.GetAll(cs.CHANNEL, dbus_interface=cs.PROPERTIES_IFACE) - assert channel_props['TargetID'] == 'chat@conf.localhost', channel_props - assert channel_props['Requested'] == False - assert channel_props['InitiatorID'] == '' - assert channel_props['InitiatorHandle'] == 0 - - channels = new_event.args[0] - assert len(channels) == 1 - path, props = channels[0] - assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES - - tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) - - q.expect('dbus-signal', signal='NewTube', - args=[stream_tube_id, bob_handle, 1, 'echo', sample_parameters, 0]) - - expected_tube = (stream_tube_id, bob_handle, cs.TUBE_TYPE_STREAM, 'echo', - sample_parameters, cs.TUBE_STATE_LOCAL_PENDING) - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert tubes == [( - stream_tube_id, - bob_handle, - 1, # Stream - 'echo', - sample_parameters, - cs.TUBE_CHANNEL_STATE_LOCAL_PENDING - )] - - assert len(tubes) == 1, unwrap(tubes) - t.check_tube_in_tubes(expected_tube, tubes) + def new_chan_predicate(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE - # tube channel is also announced (new API) - new_event = q.expect('dbus-signal', signal='NewChannels') + # tube channel is announced + new_event = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) channels = new_event.args[0] assert len(channels) == 1 @@ -164,7 +127,8 @@ def test(q, bus, conn, stream, bytestream_cls, assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE assert props[cs.INITIATOR_HANDLE] == bob_handle assert props[cs.INITIATOR_ID] == 'chat@conf.localhost/bob' - assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE] + assertSameSets([cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE], + props[cs.INTERFACES]) assert props[cs.REQUESTED] == False assert props[cs.TARGET_HANDLE] == room_handle assert props[cs.TARGET_ID] == 'chat@conf.localhost' @@ -176,17 +140,18 @@ def test(q, bus, conn, stream, bytestream_cls, tube_chan = bus.get_object(conn.bus_name, path) tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) + tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) assert tube_props['Parameters'] == sample_parameters assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_LOCAL_PENDING # Accept the tube - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, + call_async(q, tube_iface, 'Accept', address_type, access_control, access_control_param, byte_arrays=True) accept_return_event, _ = q.expect_many( - EventPattern('dbus-return', method='AcceptStreamTube'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, 2])) + EventPattern('dbus-return', method='Accept'), + EventPattern('dbus-signal', signal='TubeChannelStateChanged', + args=[2])) address = accept_return_event.value[0] @@ -260,8 +225,7 @@ def test(q, bus, conn, stream, bytestream_cls, assertEquals(cs.CANCELLED, e.args[1]) # OK, we're done - disconnect_conn(q, conn, stream, - [EventPattern('dbus-signal', signal='TubeClosed', args=[stream_tube_id])]) + disconnect_conn(q, conn, stream) if __name__ == '__main__': t.exec_stream_tube_test(test) diff --git a/tests/twisted/tubes/accept-private-dbus-tube.py b/tests/twisted/tubes/accept-private-dbus-tube.py index 82e81118c..dbbeb3bed 100644 --- a/tests/twisted/tubes/accept-private-dbus-tube.py +++ b/tests/twisted/tubes/accept-private-dbus-tube.py @@ -81,66 +81,21 @@ def test(q, bus, conn, stream, bytestream_cls, access_control): # RequestChannel are the ones we wanted. sync_dbus(bus, q, conn) - # let's try to accept a D-Bus tube using the old API - bytestream = bytestream_cls(stream, q, 'beta', bob_full_jid, - 'test@localhost/Reource', True) - - last_tube_id += 1 - contact_offer_dbus_tube(bytestream, last_tube_id) - - # tubes channel is created - event = q.expect('dbus-signal', signal='NewChannel') - bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@localhost'])[0] - t.check_NewChannel_signal(event.args, cs.CHANNEL_TYPE_TUBES, None, - bob_handle, False) - - tubes_chan = bus.get_object(conn.bus_name, event.args[0]) - tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) - - event = q.expect('dbus-signal', signal='NewTube') - id = event.args[0] - initiator = event.args[1] - type = event.args[2] - service = event.args[3] - parameters = event.args[4] - state = event.args[5] - - assertEquals (last_tube_id, id) - initiator_jid = conn.InspectHandles(1, [initiator])[0] - assert initiator_jid == 'bob@localhost' - assert type == cs.TUBE_TYPE_DBUS - assert service == 'com.example.TestCase2' - assert parameters == {'login': 'TEST'} - assert state == cs.TUBE_STATE_LOCAL_PENDING - - # accept the tube (old API) - call_async(q, tubes_iface, 'AcceptDBusTube', id) - - event = q.expect('stream-iq', iq_type='result') - bytestream.check_si_reply(event.stanza) - tube = xpath.queryForNodes('/iq/si/tube[@xmlns="%s"]' % ns.TUBES, - event.stanza) - assert len(tube) == 1 - - # Init the bytestream - events, _ = bytestream.open_bytestream([EventPattern('dbus-return', method='AcceptDBusTube')], - [EventPattern('dbus-signal', signal='TubeStateChanged', - args=[last_tube_id, 2])]) - - return_event = events[0] - address = return_event.value[0] - assert len(address) > 0 - - # OK, now let's try to accept a D-Bus tube using the new API + # let's try to accept a D-Bus tube using the new API bytestream = bytestream_cls(stream, q, 'gamma', bob_full_jid, self_full_jid, True) last_tube_id += 1 contact_offer_dbus_tube(bytestream, last_tube_id) - e = q.expect('dbus-signal', signal='NewChannels') + def new_chan_predicate(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE + + e = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) channels = e.args[0] assert len(channels) == 1 path, props = channels[0] diff --git a/tests/twisted/tubes/accept-private-stream-tube.py b/tests/twisted/tubes/accept-private-stream-tube.py index 58f3558ae..37ed1693d 100644 --- a/tests/twisted/tubes/accept-private-stream-tube.py +++ b/tests/twisted/tubes/accept-private-stream-tube.py @@ -24,54 +24,37 @@ bob_jid = 'bob@localhost/Bob' stream_tube_id = 49 def receive_tube_offer(q, bus, conn, stream): + global stream_tube_id message = domish.Element(('jabber:client', 'message')) message['to'] = 'test@localhost/Resource' message['from'] = bob_jid tube_node = message.addElement((ns.TUBES, 'tube')) tube_node['type'] = 'stream' tube_node['service'] = 'http' + stream_tube_id += 1 tube_node['id'] = str(stream_tube_id) stream.send(message) - old_sig, new_sig = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) - chan_path = old_sig.args[0] - assert old_sig.args[1] == cs.CHANNEL_TYPE_TUBES, old_sig.args[1] - assert old_sig.args[2] == cs.HT_CONTACT - bob_handle = old_sig.args[3] - assert old_sig.args[2] == 1, old_sig.args[2] # Suppress_Handler - assert len(new_sig.args) == 1 - assert len(new_sig.args[0]) == 1 - assert new_sig.args[0][0][0] == chan_path, new_sig.args[0][0] - assert new_sig.args[0][0][1] is not None - - event = q.expect('dbus-signal', signal='NewTube') - - old_sig, new_sig = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) - new_chan_path = old_sig.args[0] - assert new_chan_path != chan_path - assert old_sig.args[1] == cs.CHANNEL_TYPE_STREAM_TUBE, old_sig.args[1] - assert old_sig.args[2] == cs.HT_CONTACT - bob_handle = old_sig.args[3] - assert old_sig.args[2] == 1, old_sig.args[2] # Suppress_Handler + def new_chan_predicate(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE + + new_sig = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) + assert len(new_sig.args) == 1 assert len(new_sig.args[0]) == 1 - assert new_sig.args[0][0][0] == new_chan_path, new_sig.args[0][0] - assert new_sig.args[0][0][1] is not None - # create channel proxies - tubes_chan = bus.get_object(conn.bus_name, chan_path) - tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) + path, props = new_sig.args[0][0] + assertEquals(cs.CHANNEL_TYPE_STREAM_TUBE, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE]) + assertEquals(False, props[cs.REQUESTED]) - new_tube_chan = bus.get_object(conn.bus_name, new_chan_path) + # create channel proxies + new_tube_chan = bus.get_object(conn.bus_name, path) new_tube_iface = dbus.Interface(new_tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) - return (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) + return (new_tube_chan, new_tube_iface) def expect_tube_activity(q, bus, conn, stream, bytestream_cls, address_type, address, access_control, access_control_param): @@ -157,20 +140,9 @@ def test(q, bus, conn, stream, bytestream_cls, sync_dbus(bus, q, conn) # Receive a tube offer from Bob - (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ + (new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) - # Try bad parameters on the old iface - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id+1, 2, 0, '', - byte_arrays=True) - q.expect('dbus-error', method='AcceptStreamTube') - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, 2, 1, '', - byte_arrays=True) - q.expect('dbus-error', method='AcceptStreamTube') - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, 20, 0, '', - byte_arrays=True) - q.expect('dbus-error', method='AcceptStreamTube') - # Try bad parameters on the new iface call_async(q, new_tube_iface, 'Accept', 20, 0, '', byte_arrays=True) @@ -179,69 +151,8 @@ def test(q, bus, conn, stream, bytestream_cls, byte_arrays=True) q.expect('dbus-error', method='Accept') - # Accept the tube with old iface - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, address_type, - access_control, access_control_param, byte_arrays=True) - - accept_return_event, _ = q.expect_many( - EventPattern('dbus-return', method='AcceptStreamTube'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, 2])) - - socket_address = accept_return_event.value[0] - - bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, - address_type, socket_address, access_control, access_control_param) - - tubes_chan.Close() - bytestream.wait_bytestream_closed() - - # Receive a tube offer from Bob - (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ - receive_tube_offer(q, bus, conn, stream) - - # Accept the tube with old iface, and use UNIX sockets - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, - address_type, access_control, access_control_param, byte_arrays=True) - - accept_return_event, _ = q.expect_many( - EventPattern('dbus-return', method='AcceptStreamTube'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, 2])) - - socket_address = accept_return_event.value[0] - - bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, - address_type, socket_address, access_control, access_control_param) - tubes_chan.Close() - bytestream.wait_bytestream_closed() - - # Receive a tube offer from Bob - (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ - receive_tube_offer(q, bus, conn, stream) - - # Accept the tube with new iface, and use IPv4 - call_async(q, new_tube_iface, 'Accept', address_type, - access_control, access_control_param, byte_arrays=True) - - accept_return_event, _ = q.expect_many( - EventPattern('dbus-return', method='Accept'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, 2])) - - socket_address = accept_return_event.value[0] - - bytestream, conn_id = expect_tube_activity(q, bus, conn, stream, bytestream_cls, - address_type, socket_address, access_control, access_control_param) - tubes_chan.Close() - e, _ = bytestream.wait_bytestream_closed([ - EventPattern('dbus-signal', signal='ConnectionClosed'), - EventPattern('socket-disconnected')]) - assertEquals(conn_id, e.args[0]) - assertEquals(cs.CANCELLED, e.args[1]) - # Receive a tube offer from Bob - (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ + (new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Accept the tube with new iface, and use UNIX sockets @@ -250,8 +161,8 @@ def test(q, bus, conn, stream, bytestream_cls, accept_return_event, _ = q.expect_many( EventPattern('dbus-return', method='Accept'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, 2])) + EventPattern('dbus-signal', signal='TubeChannelStateChanged', + args=[2])) socket_address = accept_return_event.value[0] @@ -274,16 +185,10 @@ def test(q, bus, conn, stream, bytestream_cls, assertEquals(conn_id, e.args[0]) assertEquals(cs.CONNECTION_REFUSED, e.args[1]) - tubes_chan.Close() - - # Receive a tube offer from Bob - (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ - receive_tube_offer(q, bus, conn, stream) - # Just close the tube - tubes_chan.Close() + new_tube_chan.Close() # Receive a tube offer from Bob - (tubes_chan, tubes_iface, new_tube_chan, new_tube_iface) = \ + (new_tube_chan, new_tube_iface) = \ receive_tube_offer(q, bus, conn, stream) # Just close the tube new_tube_chan.Close() diff --git a/tests/twisted/tubes/check-create-tube-return.py b/tests/twisted/tubes/check-create-tube-return.py index 2a3a6304b..46db340c4 100644 --- a/tests/twisted/tubes/check-create-tube-return.py +++ b/tests/twisted/tubes/check-create-tube-return.py @@ -74,29 +74,5 @@ def test(q, bus, conn, stream): assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) assertEquals(props[cs.TARGET_ID], muc) - # Now make sure we can get our Tubes channel if we request it. - muc = 'chat3@conf.localhost' - - call_async(q, conn.Requests, 'CreateChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, - cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_ID: muc}) - - q.expect('stream-presence', to='%s/test' % muc) - stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) - stream.send(make_muc_presence('none', 'participant', muc, 'test')) - - ret, _, _ = q.expect_many( - EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) - - _, props = ret.value - - assertEquals(props[cs.CHANNEL_TYPE], cs.CHANNEL_TYPE_TUBES) - assertEquals(props[cs.TARGET_HANDLE_TYPE], cs.HT_ROOM) - assertEquals(props[cs.TARGET_ID], muc) - if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/tubes/close-muc-with-closed-tube.py b/tests/twisted/tubes/close-muc-with-closed-tube.py index bcebe77f1..ed08add64 100644 --- a/tests/twisted/tubes/close-muc-with-closed-tube.py +++ b/tests/twisted/tubes/close-muc-with-closed-tube.py @@ -2,7 +2,7 @@ import dbus -from servicetest import call_async, EventPattern, unwrap +from servicetest import call_async, EventPattern, unwrap, assertEquals from gabbletest import exec_test, make_result_iq, acknowledge_iq, make_muc_presence import constants as cs import ns @@ -84,43 +84,28 @@ def test(q, bus, conn, stream): stream.send(presence) - # tubes channel is automatically created - event = q.expect('dbus-signal', signal='NewChannel') + def new_chan_predicate(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE - if event.args[1] == cs.CHANNEL_TYPE_TEXT: - # skip this one, try the next one - event = q.expect('dbus-signal', signal='NewChannel') + # tube channel is automatically created + event = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) - assert event.args[1] == cs.CHANNEL_TYPE_TUBES, event.args - assert event.args[2] == cs.HT_ROOM - assert event.args[3] == room_handle + path, props = event.args[0][0] - tubes_chan = bus.get_object(conn.bus_name, event.args[0]) - tubes_iface = dbus.Interface(tubes_chan, event.args[1]) + assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) + assertEquals(room_handle, props[cs.TARGET_HANDLE]) + assertEquals('chat@conf.localhost', props[cs.TARGET_ID]) + assertEquals(False, props[cs.REQUESTED]) - channel_props = tubes_chan.GetAll( - cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) - assert channel_props['TargetID'] == 'chat@conf.localhost', channel_props - assert channel_props['Requested'] == False - assert channel_props['InitiatorID'] == '' - assert channel_props['InitiatorHandle'] == 0 - - tubes_self_handle = tubes_chan.GetSelfHandle( - dbus_interface=cs.CHANNEL_IFACE_GROUP) - - q.expect('dbus-signal', signal='NewTube', - args=[tube_id, bob_handle, 0, 'org.telepathy.freedesktop.test', sample_parameters, 0]) - - expected_tube = (tube_id, bob_handle, cs.TUBE_TYPE_DBUS, - 'org.telepathy.freedesktop.test', sample_parameters, - cs.TUBE_STATE_LOCAL_PENDING) - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert len(tubes) == 1, unwrap(tubes) - t.check_tube_in_tubes(expected_tube, tubes) + tube_chan = bus.get_object(conn.bus_name, path) + tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) # reject the tube - tubes_iface.CloseTube(tube_id) - q.expect('dbus-signal', signal='TubeClosed', args=[tube_id]) + tube_iface.Close(dbus_interface=cs.CHANNEL) + q.expect('dbus-signal', signal='ChannelClosed') # close the text channel text_chan.Close() diff --git a/tests/twisted/tubes/crash-on-list-channels.py b/tests/twisted/tubes/crash-on-list-channels.py deleted file mode 100644 index b2532e515..000000000 --- a/tests/twisted/tubes/crash-on-list-channels.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Regression test for a bug where calling ListChannels with an open old-skool -DBus tube asserted. -""" - -import dbus - -from servicetest import call_async, EventPattern -from gabbletest import exec_test, sync_stream, make_result_iq - -import ns -import constants as cs - -from twisted.words.xish import domish - -jid = 'explosions@in.the.sky' - -def test(q, bus, conn, stream): - roster_event = q.expect('stream-iq', query_ns=ns.ROSTER) - - roster = roster_event.stanza - roster['type'] = 'result' - item = roster_event.query.addElement('item') - item['jid'] = jid - item['subscription'] = 'both' - stream.send(roster) - - presence = domish.Element(('jabber:client', 'presence')) - presence['from'] = '%s/Bob' % jid - presence['to'] = 'test@localhost/Resource' - c = presence.addElement('c') - c['xmlns'] = ns.CAPS - c['node'] = 'http://example.com/ICantBelieveItsNotTelepathy' - c['ver'] = '1.2.3' - stream.send(presence) - - event = q.expect('stream-iq', iq_type='get', - query_ns=ns.DISCO_INFO, - to=('%s/Bob' % jid)) - assert event.query['node'] == \ - 'http://example.com/ICantBelieveItsNotTelepathy#1.2.3' - result = make_result_iq(stream, event.stanza) - query = result.firstChildElement() - feature = query.addElement('feature') - feature['var'] = ns.TUBES - stream.send(result) - - sync_stream(q, stream) - - h = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] - tubes_path = conn.RequestChannel( - cs.CHANNEL_TYPE_TUBES, cs.HT_CONTACT, h, True) - - tubes_chan = bus.get_object(conn.bus_name, tubes_path) - tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) - - tubes_iface.OfferDBusTube('bong.hits', dbus.Dictionary({}, signature='sv')) - - conn.ListChannels() - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/tubes/ensure-si-tube.py b/tests/twisted/tubes/ensure-si-tube.py index 9330fa7c8..dccb337cc 100644 --- a/tests/twisted/tubes/ensure-si-tube.py +++ b/tests/twisted/tubes/ensure-si-tube.py @@ -4,7 +4,7 @@ Test support for creating and retrieving 1-1 tubes with EnsureChannel import dbus -from servicetest import call_async, EventPattern, tp_name_prefix +from servicetest import call_async, EventPattern, tp_name_prefix, unwrap from gabbletest import exec_test, acknowledge_iq import constants as cs import ns @@ -27,12 +27,12 @@ def test(q, bus, conn, stream): properties = conn.GetAll( cs.CONN_IFACE_REQUESTS, dbus_interface=cs.PROPERTIES_IFACE) assert properties.get('Channels') == [], properties['Channels'] - assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, + assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, }, - [cs.TARGET_HANDLE, cs.TARGET_ID] + [cs.TARGET_HANDLE, cs.TARGET_ID, cs.STREAM_TUBE_SERVICE] ) in properties.get('RequestableChannelClasses'),\ - properties['RequestableChannelClasses'] + unwrap(properties['RequestableChannelClasses']) _, vcard_event, roster_event = q.expect_many( EventPattern('dbus-signal', signal='StatusChanged', @@ -72,48 +72,58 @@ def test(q, bus, conn, stream): bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] - call_async(q, conn, 'RequestChannel', - cs.CHANNEL_TYPE_TUBES, cs.HT_CONTACT, bob_handle, True); + def new_chan_predicate(e): + types = [] + for _, props in e.args[0]: + types.append(props[cs.CHANNEL_TYPE]) - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) + return cs.CHANNEL_TYPE_STREAM_TUBE in types + call_async(q, conn.Requests, 'CreateChannel', + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_HANDLE: bob_handle, + cs.STREAM_TUBE_SERVICE: 'the.service', + }) + + ret, _ = q.expect_many( + EventPattern('dbus-return', method='CreateChannel'), + EventPattern('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate), + ) - assert len(ret.value) == 1 - chan_path = ret.value[0] + chan_path, props = ret.value # Ensure a tube to the same person; check it's the same one. - call_async(q, conn.Requests, 'EnsureChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: bob_handle - }) +# call_async(q, conn.Requests, 'EnsureChannel', +# { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, +# cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, +# cs.TARGET_HANDLE: bob_handle, +# cs.STREAM_TUBE_SERVICE: 'the.service', +# }) - ret = q.expect('dbus-return', method='EnsureChannel') - yours, ensured_path, _ = ret.value +# ret = q.expect('dbus-return', method='EnsureChannel') +# yours, ensured_path, _ = ret.value - assert ensured_path == chan_path, (ensured_path, chan_path) - assert not yours +# assert ensured_path == chan_path, (ensured_path, chan_path) +# assert not yours chan = bus.get_object(conn.bus_name, chan_path) chan.Close() - # Now let's try ensuring a new tube. call_async(q, conn.Requests, 'EnsureChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: bob_handle + cs.TARGET_HANDLE: bob_handle, + cs.STREAM_TUBE_SERVICE: 'the.service', }) - ret, old_sig, new_sig = q.expect_many( + ret, new_sig = q.expect_many( EventPattern('dbus-return', method='EnsureChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), + EventPattern('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate), ) yours, path, props = ret.value diff --git a/tests/twisted/tubes/muc-presence.py b/tests/twisted/tubes/muc-presence.py deleted file mode 100644 index 8efcb8780..000000000 --- a/tests/twisted/tubes/muc-presence.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -Regression test for a bug where, if you had any MUC Tubes channels open and -changed your presence, a GabbleMucChannel method was called on a -GabbleTubesChannel, crashing Gabble. -""" - -from gabbletest import exec_test -import constants as cs - -from muctubeutil import get_muc_tubes_channel - -def test(q, bus, conn, stream): - handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, - stream, 'chat@conf.localhost') - - conn.SimplePresence.SetPresence('away', 'Christmas lunch!') - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/tubes/muctubeutil.py b/tests/twisted/tubes/muctubeutil.py deleted file mode 100644 index 61fa41f88..000000000 --- a/tests/twisted/tubes/muctubeutil.py +++ /dev/null @@ -1,89 +0,0 @@ -import dbus - -from servicetest import call_async, EventPattern, tp_name_prefix -from gabbletest import make_result_iq, make_muc_presence -import constants as cs - -def get_muc_tubes_channel(q, bus, conn, stream, muc_jid, anonymous=True): - """ - Returns a singleton list containing the MUC's handle, a proxy for the Tubes - channel, and a proxy for the Tubes iface on that channel. - """ - muc_server = muc_jid.split('@')[1] - test_jid = muc_jid + "/test" - bob_jid = muc_jid + "/bob" - - self_handle = conn.GetSelfHandle() - self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] - - call_async(q, conn, 'RequestHandles', cs.HT_ROOM, [muc_jid]) - - event = q.expect('dbus-return', method='RequestHandles') - handles = event.value[0] - room_handle = handles[0] - - # request tubes channel - call_async(q, conn, 'RequestChannel', - tp_name_prefix + '.Channel.Type.Tubes', cs.HT_ROOM, room_handle, True) - - _, stream_event = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [], [2], 0, 0]), - EventPattern('stream-presence', to=test_jid)) - - # Send presence for other member of room. - if not anonymous: - real_jid = 'bob@localhost' - else: - real_jid = None - - stream.send(make_muc_presence('owner', 'moderator', muc_jid, 'bob', real_jid)) - - # Send presence for own membership of room. - stream.send(make_muc_presence('none', 'participant', muc_jid, 'test')) - - q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [2, 3], [], [], [], 0, 0]) - - assert conn.InspectHandles(cs.HT_CONTACT, [2]) == [test_jid] - assert conn.InspectHandles(cs.HT_CONTACT, [3]) == [bob_jid] - - # text and tubes channels are created - # FIXME: We can't check NewChannel signals (old API) because two of them - # would be fired and we can't catch twice the same signals without specifying - # all their arguments. - new_sig, returned = q.expect_many( - EventPattern('dbus-signal', signal='NewChannels'), - EventPattern('dbus-return', method='RequestChannel')) - - channels = new_sig.args[0] - assert len(channels) == 2 - - for channel in channels: - path, props = channel - type = props[cs.CHANNEL_TYPE] - - if type == cs.CHANNEL_TYPE_TEXT: - # check text channel properties - assert props[cs.TARGET_HANDLE] == room_handle - assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM - assert props[cs.TARGET_ID] == 'chat@conf.localhost' - assert props[cs.REQUESTED] == False - assert props[cs.INITIATOR_HANDLE] == self_handle - assert props[cs.INITIATOR_ID] == self_name - elif type == cs.CHANNEL_TYPE_TUBES: - # check tubes channel properties - assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM - assert props[cs.TARGET_HANDLE] == room_handle - assert props[cs.TARGET_ID] == 'chat@conf.localhost' - assert props[cs.REQUESTED] == True - assert props[cs.INITIATOR_HANDLE] == self_handle - assert props[cs.INITIATOR_ID] == self_name - else: - assert True - - tubes_chan = bus.get_object(conn.bus_name, returned.value[0]) - tubes_iface = dbus.Interface(tubes_chan, - tp_name_prefix + '.Channel.Type.Tubes') - - return (room_handle, tubes_chan, tubes_iface) diff --git a/tests/twisted/tubes/offer-muc-dbus-tube.py b/tests/twisted/tubes/offer-muc-dbus-tube.py index 199fa3d6b..06ccc2804 100644 --- a/tests/twisted/tubes/offer-muc-dbus-tube.py +++ b/tests/twisted/tubes/offer-muc-dbus-tube.py @@ -15,7 +15,6 @@ import tubetestutil as t from twisted.words.xish import xpath from mucutil import join_muc, echo_muc_presence -from muctubeutil import get_muc_tubes_channel sample_parameters = dbus.Dictionary({ 's': 'hello', @@ -24,7 +23,7 @@ sample_parameters = dbus.Dictionary({ 'i': dbus.Int32(-123), }, signature='sv') -def check_tube_in_presence(presence, dbus_tube_id, initiator): +def check_tube_in_presence(presence, initiator): tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' % ns.TUBES, presence) assert tubes_nodes is not None @@ -39,7 +38,7 @@ def check_tube_in_presence(presence, dbus_tube_id, initiator): assert tube['service'] == 'com.example.TestCase' dbus_stream_id = tube['stream-id'] my_bus_name = tube['dbus-name'] - assert tube['id'] == str(dbus_tube_id) + dbus_tube_id = tube['id'] params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) @@ -52,7 +51,7 @@ def check_tube_in_presence(presence, dbus_tube_id, initiator): 'u': ('uint', '123'), } - return dbus_stream_id, my_bus_name + return dbus_stream_id, my_bus_name, dbus_tube_id def fire_signal_on_tube(q, tube, chatroom, dbus_stream_id, my_bus_name): @@ -118,85 +117,6 @@ def test(q, bus, conn, stream, access_control): self_handle = conn.GetSelfHandle() self_name = conn.InspectHandles(1, [self_handle])[0] - handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, - stream, 'chat@conf.localhost') - - # Exercise basic Channel Properties from spec 0.17.7 - channel_props = tubes_chan.GetAll(cs.CHANNEL, - dbus_interface=dbus.PROPERTIES_IFACE) - assert channel_props.get('TargetHandle') == handle,\ - (channel_props.get('TargetHandle'), handle) - assert channel_props.get('TargetHandleType') == 2,\ - channel_props.get('TargetHandleType') - assert channel_props.get('ChannelType') == cs.CHANNEL_TYPE_TUBES,\ - channel_props.get('ChannelType') - assert 'Interfaces' in channel_props, channel_props - assert cs.CHANNEL_IFACE_GROUP in channel_props['Interfaces'], \ - channel_props['Interfaces'] - assert channel_props['TargetID'] == 'chat@conf.localhost', channel_props - assert channel_props['Requested'] == True - assert channel_props['InitiatorID'] == 'test@localhost' - assert channel_props['InitiatorHandle'] == conn.GetSelfHandle() - - # Exercise Group Properties from spec 0.17.6 (in a basic way) - group_props = tubes_chan.GetAll(cs.CHANNEL_IFACE_GROUP, - dbus_interface=dbus.PROPERTIES_IFACE) - assert 'SelfHandle' in group_props, group_props - assert 'HandleOwners' in group_props, group_props - assert 'Members' in group_props, group_props - assert 'LocalPendingMembers' in group_props, group_props - assert 'RemotePendingMembers' in group_props, group_props - assert 'GroupFlags' in group_props, group_props - - tubes_self_handle = tubes_chan.GetSelfHandle( - dbus_interface=cs.CHANNEL_IFACE_GROUP) - assert group_props['SelfHandle'] == tubes_self_handle - - # Offer a D-Bus tube (old API) - call_async(q, tubes_iface, 'OfferDBusTube', - 'com.example.TestCase', sample_parameters) - - new_tube_event, presence_event, offer_return_event, dbus_changed_event = \ - q.expect_many( - EventPattern('dbus-signal', signal='NewTube'), - EventPattern('stream-presence', to='chat@conf.localhost/test'), - EventPattern('dbus-return', method='OfferDBusTube'), - EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_TUBES)) - - # handle new_tube_event - dbus_tube_id = new_tube_event.args[0] - assert new_tube_event.args[1] == tubes_self_handle - assert new_tube_event.args[2] == cs.TUBE_TYPE_DBUS - assert new_tube_event.args[3] == 'com.example.TestCase' - assert new_tube_event.args[4] == sample_parameters - assert new_tube_event.args[5] == cs.TUBE_STATE_OPEN - - # handle offer_return_event - assert offer_return_event.value[0] == dbus_tube_id - - # handle presence_event - # We announce our newly created tube in our muc presence - presence = presence_event.stanza - dbus_stream_id, my_bus_name = check_tube_in_presence(presence, dbus_tube_id, 'chat@conf.localhost/test') - - # handle dbus_changed_event - assert dbus_changed_event.args[0] == dbus_tube_id - assert dbus_changed_event.args[1][0][0] == tubes_self_handle - assert dbus_changed_event.args[1][0][1] == my_bus_name - - # handle offer_return_event - assert dbus_tube_id == offer_return_event.value[0] - - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert len(tubes) == 1 - expected_tube = (dbus_tube_id, tubes_self_handle, cs.TUBE_TYPE_DBUS, - 'com.example.TestCase', sample_parameters, cs.TUBE_STATE_OPEN) - t.check_tube_in_tubes(expected_tube, tubes) - - dbus_tube_adr = tubes_iface.GetDBusTubeAddress(dbus_tube_id) - tube = Connection(dbus_tube_adr) - fire_signal_on_tube(q, tube, 'chat@conf.localhost', dbus_stream_id, my_bus_name) - # offer a D-Bus tube to another room using new API muc = 'chat2@conf.localhost' request = { @@ -207,72 +127,19 @@ def test(q, bus, conn, stream, access_control): } join_muc(q, bus, conn, stream, muc, request=request) - # The order in which the NewChannels signals are fired is - # undefined -- it could be the (tubes, text) channels first, or it - # could be the tube channel first; so let's accept either order - # here. - - first, second = q.expect_many( - EventPattern('dbus-signal', signal='NewChannels'), - EventPattern('dbus-signal', signal='NewChannels')) - - # NewChannels signal with the text and tubes channels together. - def nc_textandtubes(event): - channels = event.args[0] - assert len(channels) == 2 - path1, prop1 = channels[0] - path2, prop2 = channels[1] - assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == \ - [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] - - got_text, got_tubes = False, False - for path, props in channels: - if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: - got_text = True - - text_chan = dbus.Interface(bus.get_object(conn.bus_name, path), - cs.CHANNEL) - elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: - got_tubes = True - - tubes_iface = dbus.Interface(bus.get_object(conn.bus_name, path), - cs.CHANNEL_TYPE_TUBES) - else: - assert False - - assert props[cs.INITIATOR_HANDLE] == self_handle - assert props[cs.INITIATOR_ID] == self_name - assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] - assert props[cs.TARGET_ID] == 'chat2@conf.localhost' - assert props[cs.REQUESTED] == False - - assert (got_text, got_tubes) == (True, True) - - return text_chan - - # NewChannels signal with the tube channel. - def nc_tube(event): - # FIXME: in this case, all channels should probably be announced together - channels = event.args[0] - assert len(channels) == 1 - path, prop = channels[0] - assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE - assert prop[cs.INITIATOR_ID] == 'chat2@conf.localhost/test' - assert prop[cs.REQUESTED] == True - assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM - assert prop[cs.TARGET_ID] == 'chat2@conf.localhost' - assert prop[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' - assert prop[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, - cs.SOCKET_ACCESS_CONTROL_LOCALHOST] - - return path, prop + e = q.expect('dbus-signal', signal='NewChannels') - if len(first.args[0]) == 1: - path, prop = nc_tube(first) - text_chan = nc_textandtubes(second) - else: - text_chan = nc_textandtubes(first) - path, prop = nc_tube(second) + channels = e.args[0] + assert len(channels) == 1 + path, prop = channels[0] + assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE + assert prop[cs.INITIATOR_ID] == 'chat2@conf.localhost/test' + assert prop[cs.REQUESTED] == True + assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM + assert prop[cs.TARGET_ID] == 'chat2@conf.localhost' + assert prop[cs.DBUS_TUBE_SERVICE_NAME] == 'com.example.TestCase' + assert prop[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS] == [cs.SOCKET_ACCESS_CONTROL_CREDENTIALS, + cs.SOCKET_ACCESS_CONTROL_LOCALHOST] # check that the tube channel is in the channels list all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', @@ -298,8 +165,7 @@ def test(q, bus, conn, stream, access_control): # offer the tube call_async(q, dbus_tube_iface, 'Offer', sample_parameters, access_control) - new_tube_event, presence_event, return_event, status_event, dbus_changed_event = q.expect_many( - EventPattern('dbus-signal', signal='NewTube'), + presence_event, return_event, status_event, dbus_changed_event = q.expect_many( EventPattern('stream-presence', to='chat2@conf.localhost/test'), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN]), @@ -308,17 +174,11 @@ def test(q, bus, conn, stream, access_control): tube_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) assert tube_self_handle != 0 - # handle new_tube_event - dbus_tube_id = new_tube_event.args[0] - assert new_tube_event.args[2] == cs.TUBE_TYPE_DBUS - assert new_tube_event.args[3] == 'com.example.TestCase' - assert new_tube_event.args[4] == sample_parameters - assert new_tube_event.args[5] == cs.TUBE_STATE_OPEN - # handle presence_event # We announce our newly created tube in our muc presence presence = presence_event.stanza - dbus_stream_id, my_bus_name = check_tube_in_presence(presence, dbus_tube_id, 'chat2@conf.localhost/test') + dbus_stream_id, my_bus_name, dbus_tube_id = check_tube_in_presence(presence, + 'chat2@conf.localhost/test') # handle dbus_changed_event added, removed = dbus_changed_event.args @@ -330,9 +190,6 @@ def test(q, bus, conn, stream, access_control): bob_bus_name = ':2.Ym9i' bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat2@conf.localhost/bob'])[0] - tubes = tubes_iface.ListTubes(byte_arrays=True) - assertEquals(1, len(tubes)) - def bob_in_tube(): presence = elem('presence', from_='chat2@conf.localhost/bob', to='chat2@conf.localhost')( elem('x', xmlns=ns.MUC_USER), @@ -386,26 +243,18 @@ def test(q, bus, conn, stream, access_control): assert names == {tube_self_handle: my_bus_name} chan_iface.Close() - q.expect_many( + _, _, event = q.expect_many( EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='ChannelClosed')) - - # leave the room - text_chan.Close() + EventPattern('dbus-signal', signal='ChannelClosed'), + EventPattern('stream-presence', to='chat2@conf.localhost/test', + presence_type='unavailable')) # we must echo the MUC presence so the room will actually close # and we should wait to make sure gabble has actually parsed our # echo before trying to rejoin - event = q.expect('stream-presence', to='chat2@conf.localhost/test', - presence_type='unavailable') echo_muc_presence(q, stream, event.stanza, 'none', 'participant') sync_stream(q, stream) - q.expect_many( - EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='ChannelClosed'), - ) - # rejoin the room call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, @@ -420,41 +269,38 @@ def test(q, bus, conn, stream, access_control): # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', muc, 'test')) + def new_tube(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE - # tube is created as well - e = q.expect('dbus-signal', signal='NewChannels') - tube_path, props = e.args[0][0] + def new_text(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT + + # tube and text is created + text_event, tube_event = q.expect_many(EventPattern('dbus-signal', signal='NewChannels', + predicate=new_text), + EventPattern('dbus-signal', signal='NewChannels', + predicate=new_tube)) + + channels = e.args[0] + tube_path, props = tube_event.args[0][0] assertEquals(cs.CHANNEL_TYPE_DBUS_TUBE, props[cs.CHANNEL_TYPE]) assertEquals('chat2@conf.localhost/test', props[cs.INITIATOR_ID]) assertEquals(False, props[cs.REQUESTED]) assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) assertEquals('com.example.TestCase', props[cs.DBUS_TUBE_SERVICE_NAME]) - # text channel is created - e = q.expect('dbus-signal', signal='NewChannels') - path, props = e.args[0][0] + _, props = text_event.args[0][0] assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) assertEquals(True, props[cs.REQUESTED]) - # tubes channel is created - e = q.expect('dbus-signal', signal='NewChannels') - path, props = e.args[0][0] - assertEquals(cs.CHANNEL_TYPE_TUBES, props[cs.CHANNEL_TYPE]) - assertEquals(False, props[cs.REQUESTED]) - - tubes_iface = dbus.Interface(bus.get_object(conn.bus_name, path), - cs.CHANNEL_TYPE_TUBES) - # tube is local-pending tube_chan = bus.get_object(conn.bus_name, tube_path) state = tube_chan.Get(cs.CHANNEL_IFACE_TUBE, 'State', dbus_interface=dbus.PROPERTIES_IFACE) assertEquals(cs.TUBE_STATE_LOCAL_PENDING, state) - # tube is listed on the old interface - tubes = tubes_iface.ListTubes(byte_arrays=True) - assertEquals(1, len(tubes)) - if __name__ == '__main__': # We can't use t.exec_dbus_tube_test() as we can use only the muc bytestream exec_test(lambda q, bus, conn, stream: diff --git a/tests/twisted/tubes/offer-muc-stream-tube.py b/tests/twisted/tubes/offer-muc-stream-tube.py index 433d79c82..2188e82a9 100644 --- a/tests/twisted/tubes/offer-muc-stream-tube.py +++ b/tests/twisted/tubes/offer-muc-stream-tube.py @@ -11,7 +11,6 @@ import constants as cs import ns import tubetestutil as t from mucutil import join_muc -from muctubeutil import get_muc_tubes_channel from bytestream import BytestreamS5BRelay, BytestreamS5BRelayBugged from twisted.words.xish import xpath @@ -73,127 +72,25 @@ def test(q, bus, conn, stream, bytestream_cls, acknowledge_iq(stream, iq_event.stanza) - self_handle = conn.GetSelfHandle() - self_name = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] - t.check_conn_properties(q, conn) - room_handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, - stream, 'chat@conf.localhost') - - tubes_self_handle = tubes_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) - bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat@conf.localhost/bob'])[0] address = t.create_server(q, address_type) - # offer stream tube (old API) using an Unix socket - call_async(q, tubes_iface, 'OfferStreamTube', - 'echo', sample_parameters, address_type, address, - access_control, access_control_param) + def new_chan_predicate(e): + types = [] + for _, props in e.args[0]: + types.append(props[cs.CHANNEL_TYPE]) - new_tube_event, stream_event, _, new_channels_event = q.expect_many( - EventPattern('dbus-signal', signal='NewTube'), - EventPattern('stream-presence', to='chat@conf.localhost/test'), - EventPattern('dbus-return', method='OfferStreamTube'), - EventPattern('dbus-signal', signal='NewChannels')) - - # handle new_tube_event - stream_tube_id = new_tube_event.args[0] - assert new_tube_event.args[1] == tubes_self_handle - assert new_tube_event.args[2] == 1 # Stream - assert new_tube_event.args[3] == 'echo' - assert new_tube_event.args[4] == sample_parameters - assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN - - # handle stream_event - # We announce our newly created tube in our muc presence - presence = stream_event.stanza - tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' - % ns.TUBES, presence) - assert tubes_nodes is not None - assert len(tubes_nodes) == 1 + return cs.CHANNEL_TYPE_STREAM_TUBE in types - tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0]) - assert tube_nodes is not None - assert len(tube_nodes) == 1 - for tube in tube_nodes: - assert tube['type'] == 'stream' - assert not tube.hasAttribute('initiator') - assert tube['service'] == 'echo' - assert not tube.hasAttribute('stream-id') - assert not tube.hasAttribute('dbus-name') - assert tube['id'] == str(stream_tube_id) - - params = {} - parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) - for node in parameter_nodes: - assert node['name'] not in params - params[node['name']] = (node['type'], str(node)) - assert params == {'ay': ('bytes', 'aGVsbG8='), - 's': ('str', 'hello'), - 'i': ('int', '-123'), - 'u': ('uint', '123'), - } - - # tube is also announced using new API - channels = new_channels_event.args[0] - assert len(channels) == 1 - path, props = channels[0] - assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE - assert props[cs.INITIATOR_HANDLE] == tubes_self_handle - assert props[cs.INITIATOR_ID] == 'chat@conf.localhost/test' - assert props[cs.INTERFACES] == [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_TUBE] - assert props[cs.REQUESTED] == True - assert props[cs.TARGET_HANDLE] == room_handle - assert props[cs.TARGET_ID] == 'chat@conf.localhost' - assert props[cs.STREAM_TUBE_SERVICE] == 'echo' - - tube_chan = bus.get_object(conn.bus_name, path) - tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, - byte_arrays=True) - assert tube_props['Parameters'] == sample_parameters - assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_OPEN - - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert tubes == [( - stream_tube_id, - tubes_self_handle, - 1, # Stream - 'echo', - sample_parameters, - cs.TUBE_CHANNEL_STATE_OPEN - )] - - assert len(tubes) == 1, unwrap(tubes) - expected_tube = (stream_tube_id, tubes_self_handle, cs.TUBE_TYPE_STREAM, - 'echo', sample_parameters, cs.TUBE_STATE_OPEN) - t.check_tube_in_tubes(expected_tube, tubes) - - # FIXME: if we use an unknown JID here, everything fails - # (the code uses lookup where it should use ensure) - - bytestream = connect_to_tube(stream, q, bytestream_cls, 'chat@conf.localhost', stream_tube_id) - - iq_event, socket_event, _, conn_event = q.expect_many( - EventPattern('stream-iq', iq_type='result'), - EventPattern('socket-connected'), - EventPattern('dbus-signal', signal='StreamTubeNewConnection', - args=[stream_tube_id, bob_handle], interface=cs.CHANNEL_TYPE_TUBES), - EventPattern('dbus-signal', signal='NewRemoteConnection', - interface=cs.CHANNEL_TYPE_STREAM_TUBE)) - - protocol = socket_event.protocol - - # handle iq_event - bytestream.check_si_reply(iq_event.stanza) - tube = xpath.queryForNodes('/iq//si/tube[@xmlns="%s"]' % ns.TUBES, iq_event.stanza) - assert len(tube) == 1 - - handle, access, conn_id = conn_event.args - assert handle == bob_handle + def find_stream_tube(channels): + for path, props in channels: + if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE: + return path, props - use_tube(q, bytestream, protocol, conn_id) + return None, None # offer a stream tube to another room (new API) address = t.create_server(q, address_type, block_reading=True) @@ -201,68 +98,22 @@ def test(q, bus, conn, stream, bytestream_cls, request = { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_ID: 'chat2@conf.localhost', + cs.TARGET_ID: 'chat@conf.localhost', cs.STREAM_TUBE_SERVICE: 'newecho', } _, _, new_tube_path, new_tube_props = \ - join_muc(q, bus, conn, stream, 'chat2@conf.localhost', request) - - # The order in which the NewChannels signals are fired is - # undefined -- it could be the (tubes, text) channels first, or it - # could be the tube channel first; so let's accept either order - # here. - - first, second = q.expect_many( - EventPattern('dbus-signal', signal='NewChannels'), - EventPattern('dbus-signal', signal='NewChannels')) - - # NewChannels signal with the text and tubes channels together. - def nc_textandtubes(event): - channels = event.args[0] - assert len(channels) == 2 - path1, prop1 = channels[0] - path2, prop2 = channels[1] - assert sorted([prop1[cs.CHANNEL_TYPE], prop2[cs.CHANNEL_TYPE]]) == \ - [cs.CHANNEL_TYPE_TEXT, cs.CHANNEL_TYPE_TUBES] - - got_text, got_tubes = False, False - for path, props in channels: - if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TEXT: - got_text = True - elif props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: - got_tubes = True - else: - assert False - - assert props[cs.INITIATOR_HANDLE] == self_handle - assert props[cs.INITIATOR_ID] == self_name - assert cs.CHANNEL_IFACE_GROUP in props[cs.INTERFACES] - assert props[cs.TARGET_ID] == 'chat2@conf.localhost' - assert props[cs.REQUESTED] == False - - assert (got_text, got_tubes) == (True, True) - - # NewChannels signal with the tube channel. - def nc_tube(event): - # FIXME: in this case, all channels should probably be announced together - channels = event.args[0] - assert len(channels) == 1 - path, prop = channels[0] - assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE - assert prop[cs.INITIATOR_ID] == 'chat2@conf.localhost/test' - assert prop[cs.REQUESTED] == True - assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM - assert prop[cs.TARGET_ID] == 'chat2@conf.localhost' - assert prop[cs.STREAM_TUBE_SERVICE] == 'newecho' - - return path, prop - - if len(first.args[0]) == 1: - path, prop = nc_tube(first) - nc_textandtubes(second) - else: - nc_textandtubes(first) - path, prop = nc_tube(second) + join_muc(q, bus, conn, stream, 'chat@conf.localhost', request) + + e = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) + + path, prop = find_stream_tube(e.args[0]) + assert prop[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE + assert prop[cs.INITIATOR_ID] == 'chat@conf.localhost/test' + assert prop[cs.REQUESTED] == True + assert prop[cs.TARGET_HANDLE_TYPE] == cs.HT_ROOM + assert prop[cs.TARGET_ID] == 'chat@conf.localhost' + assert prop[cs.STREAM_TUBE_SERVICE] == 'newecho' # check that the tube channel is in the channels list all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', @@ -279,21 +130,13 @@ def test(q, bus, conn, stream, bytestream_cls, # offer the tube call_async(q, stream_tube_iface, 'Offer', address_type, address, access_control, {'foo': 'bar'}) - new_tube_event, stream_event, _, status_event = q.expect_many( - EventPattern('dbus-signal', signal='NewTube'), - EventPattern('stream-presence', to='chat2@conf.localhost/test'), + stream_event, _, status_event = q.expect_many( + EventPattern('stream-presence', to='chat@conf.localhost/test'), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN])) tube_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) - assert conn.InspectHandles(cs.HT_CONTACT, [tube_self_handle]) == ['chat2@conf.localhost/test'] - - # handle new_tube_event - stream_tube_id = new_tube_event.args[0] - assert new_tube_event.args[2] == 1 # Stream - assert new_tube_event.args[3] == 'newecho' - assert new_tube_event.args[4] == {'foo': 'bar'} - assert new_tube_event.args[5] == cs.TUBE_CHANNEL_STATE_OPEN + assert conn.InspectHandles(cs.HT_CONTACT, [tube_self_handle]) == ['chat@conf.localhost/test'] presence = stream_event.stanza tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' @@ -301,6 +144,8 @@ def test(q, bus, conn, stream, bytestream_cls, assert tubes_nodes is not None assert len(tubes_nodes) == 1 + stream_tube_id = 666 + tube_nodes = xpath.queryForNodes('/tubes/tube', tubes_nodes[0]) assert tube_nodes is not None assert len(tube_nodes) == 1 @@ -310,7 +155,8 @@ def test(q, bus, conn, stream, bytestream_cls, assert tube['service'] == 'newecho' assert not tube.hasAttribute('stream-id') assert not tube.hasAttribute('dbus-name') - assert tube['id'] == str(stream_tube_id) + + stream_tube_id = int(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) @@ -319,9 +165,9 @@ def test(q, bus, conn, stream, bytestream_cls, params[node['name']] = (node['type'], str(node)) assert params == {'foo': ('str', 'bar')} - bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat2@conf.localhost/bob'])[0] + bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat@conf.localhost/bob'])[0] - bytestream = connect_to_tube(stream, q, bytestream_cls, 'chat2@conf.localhost', stream_tube_id) + bytestream = connect_to_tube(stream, q, bytestream_cls, 'chat@conf.localhost', stream_tube_id) iq_event, socket_event, conn_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), diff --git a/tests/twisted/tubes/offer-no-caps.py b/tests/twisted/tubes/offer-no-caps.py index 09532736a..6aa9f4071 100644 --- a/tests/twisted/tubes/offer-no-caps.py +++ b/tests/twisted/tubes/offer-no-caps.py @@ -65,30 +65,12 @@ def test(q, bus, conn, stream): # caps to appear, just like the StreamedMedia channel does. sync_stream(q, stream) - requests = dbus.Interface(conn, cs.CONN_IFACE_REQUESTS) - - # First, we make an old-style Tubes channel, which should work; calling - # OfferStreamTube or OfferDBusTube on it, however, should fail with - # NotAvailable - path, _ = requests.CreateChannel(props(cs.CHANNEL_TYPE_TUBES)) - tubes = make_channel_proxy(conn, path, 'Channel.Type.Tubes') - - call_async(q, tubes, 'OfferDBusTube', 'com.example.monkeys', {}) - e = q.expect('dbus-error', method='OfferDBusTube').error - assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() - address = t.create_server(q, cs.SOCKET_ADDRESS_TYPE_IPV4) - call_async(q, tubes, 'OfferStreamTube', 'echo', {}, - cs.SOCKET_ADDRESS_TYPE_IPV4, address, - cs.SOCKET_ACCESS_CONTROL_LOCALHOST, "") - e = q.expect('dbus-error', method='OfferStreamTube').error - assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() - # Now we try making new-style DBusTube and StreamTube channels, and calling # the relevant Offer method on them; this should fail with NotAvailable. # FIXME: I think this should be NotCapable - st_path, _ = requests.CreateChannel(props(cs.CHANNEL_TYPE_STREAM_TUBE, + st_path, _ = conn.Requests.CreateChannel(props(cs.CHANNEL_TYPE_STREAM_TUBE, {cs.STREAM_TUBE_SERVICE: "newecho"})) st_chan = bus.get_object(conn.bus_name, st_path) st = dbus.Interface(st_chan, cs.CHANNEL_TYPE_STREAM_TUBE) @@ -97,7 +79,7 @@ def test(q, bus, conn, stream): e = q.expect('dbus-error', method='Offer').error assert e.get_dbus_name() == cs.NOT_AVAILABLE, e.get_dbus_name() - dt_path, _ = requests.CreateChannel(props(cs.CHANNEL_TYPE_DBUS_TUBE, + dt_path, _ = conn.Requests.CreateChannel(props(cs.CHANNEL_TYPE_DBUS_TUBE, { cs.DBUS_TUBE_SERVICE_NAME: "com.newecho" })) dt_chan = bus.get_object(conn.bus_name, dt_path) dt = dbus.Interface(dt_chan, cs.CHANNEL_TYPE_DBUS_TUBE) diff --git a/tests/twisted/tubes/offer-private-dbus-tube.py b/tests/twisted/tubes/offer-private-dbus-tube.py index 181311da7..bb61eb21c 100644 --- a/tests/twisted/tubes/offer-private-dbus-tube.py +++ b/tests/twisted/tubes/offer-private-dbus-tube.py @@ -5,7 +5,7 @@ from dbus.connection import Connection from dbus.lowlevel import SignalMessage from servicetest import call_async, EventPattern, unwrap, watch_tube_signals,\ - assertContains + assertContains, assertEquals from gabbletest import sync_stream, make_presence import constants as cs import tubetestutil as t @@ -57,8 +57,8 @@ def alice_accepts_tube(q, stream, iq_event, dbus_tube_id, bytestream_cls): bytestream.wait_bytestream_open() - q.expect('dbus-signal', signal='TubeStateChanged', - args=[dbus_tube_id, cs.TUBE_STATE_OPEN]) + q.expect('dbus-signal', signal='TubeChannelStateChanged', + args=[cs.TUBE_STATE_OPEN]) return bytestream @@ -98,74 +98,24 @@ def send_dbus_message_to_alice(q, stream, dbus_tube_adr, bytestream): q.expect('tube-signal', signal='baz', args=[42], tube=tube) q.expect('tube-signal', signal='baz', args=[42], tube=tube) -def offer_old_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, bytestream_cls): - # request tubes channel (old API) - tubes_path = conn.RequestChannel(cs.CHANNEL_TYPE_TUBES, cs.HT_CONTACT, - alice_handle, True) - tubes_chan = bus.get_object(conn.bus_name, tubes_path) - tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) - tubes_chan_iface = dbus.Interface(tubes_chan, cs.CHANNEL) - - # Exercise basic Channel Properties from spec 0.17.7 - channel_props = tubes_chan.GetAll(cs.CHANNEL, dbus_interface=cs.PROPERTIES_IFACE) - assert channel_props.get('TargetHandle') == alice_handle,\ - (channel_props.get('TargetHandle'), alice_handle) - assert channel_props.get('TargetHandleType') == cs.HT_CONTACT,\ - channel_props.get('TargetHandleType') - assert channel_props.get('ChannelType') == cs.CHANNEL_TYPE_TUBES,\ - channel_props.get('ChannelType') - assert 'Interfaces' in channel_props, channel_props - assert channel_props['Interfaces'] == [], channel_props['Interfaces'] - assert channel_props['TargetID'] == 'alice@localhost', channel_props['TargetID'] - assert channel_props['Requested'] == True - assert channel_props['InitiatorID'] == 'test@localhost' - assert channel_props['InitiatorHandle'] == conn.GetSelfHandle() - - # Offer a D-Bus tube using old API - call_async(q, tubes_iface, 'OfferDBusTube', - 'com.example.TestCase', sample_parameters) - - new_tube_event, iq_event, offer_return_event = \ - q.expect_many( - EventPattern('dbus-signal', signal='NewTube'), - EventPattern('stream-iq', to='alice@localhost/Test'), - EventPattern('dbus-return', method='OfferDBusTube')) - - # handle new_tube_event - dbus_tube_id = new_tube_event.args[0] - assert new_tube_event.args[1] == self_handle - assert new_tube_event.args[2] == cs.TUBE_TYPE_DBUS - assert new_tube_event.args[3] == 'com.example.TestCase' - assert new_tube_event.args[4] == sample_parameters - assert new_tube_event.args[5] == cs.TUBE_STATE_REMOTE_PENDING - - # handle offer_return_event - assert offer_return_event.value[0] == dbus_tube_id - - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert len(tubes) == 1 - expected_tube = (dbus_tube_id, self_handle, cs.TUBE_TYPE_DBUS, - 'com.example.TestCase', sample_parameters, cs.TUBE_STATE_REMOTE_PENDING) - t.check_tube_in_tubes(expected_tube, tubes) - - bytestream = alice_accepts_tube(q, stream, iq_event, dbus_tube_id, bytestream_cls) - - dbus_tube_adr = tubes_iface.GetDBusTubeAddress(dbus_tube_id) - send_dbus_message_to_alice(q, stream, dbus_tube_adr, bytestream) +def offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, + bytestream_cls, access_control): - # close the tube - tubes_iface.CloseTube(dbus_tube_id) - q.expect('dbus-signal', signal='TubeClosed', args=[dbus_tube_id]) + # Offer a tube to Alice (new API) - # and close the tubes channel - tubes_chan_iface.Close() - q.expect('dbus-signal', signal='Closed') + def new_chan_predicate(e): + types = [] + for _, props in e.args[0]: + types.append(props[cs.CHANNEL_TYPE]) + return cs.CHANNEL_TYPE_DBUS_TUBE in types -def offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, - bytestream_cls, access_control): + def find_dbus_tube(channels): + for path, props in channels: + if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE: + return path, props - # Offer a tube to Alice (new API) + return None, None call_async(q, conn.Requests, 'CreateChannel', {cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_DBUS_TUBE, @@ -175,10 +125,11 @@ def offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, }, byte_arrays=True) cc_ret, nc = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannels'), + EventPattern('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate), ) tube_path, tube_props = cc_ret.value - new_channel_details = nc.args[0] + _, new_channel_props = find_dbus_tube(nc.args[0]) # check tube channel properties assert tube_props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE @@ -200,34 +151,10 @@ def offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, all_channels = conn.Get(cs.CONN_IFACE_REQUESTS, 'Channels', dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) - for path, props in new_channel_details: + for path, props in nc.args[0]: assertContains((path, props), all_channels) - # Under the current implementation, creating a new-style Tube channel - # ensures that an old-style Tubes channel exists, even though Tube channels - # aren't visible on the Tubes channel until they're offered. Another - # correct implementation would have the Tubes channel spring up only when - # the Tube is offered. - # - # Anyway. Given the current implementation, they should be announced together. - assert len(new_channel_details) == 2, unwrap(new_channel_details) - found_tubes = False - found_tube = False - for path, details in new_channel_details: - if details[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_TUBES: - found_tubes = True - tubes_chan = bus.get_object(conn.bus_name, path) - tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) - elif details[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_DBUS_TUBE: - found_tube = True - assert tube_path == path, (tube_path, path) - else: - assert False, (path, details) - assert found_tube and found_tubes, unwrap(new_channel_details) - - # The tube's not offered, so it shouldn't be shown on the old interface. - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert len(tubes) == 0, tubes + assertEquals(tube_props, new_channel_props) tube_chan = bus.get_object(conn.bus_name, tube_path) tube_chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) @@ -248,10 +175,9 @@ def offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, # arrived if it had been sent. sync_stream(q, stream) call_async(q, dbus_tube_iface, 'Offer', sample_parameters, access_control) - offer_return_event, iq_event, new_tube_event, state_event = q.expect_many( + offer_return_event, iq_event, state_event = q.expect_many( EventPattern('dbus-return', method='Offer'), EventPattern('stream-iq', to='alice@localhost/Test'), - EventPattern('dbus-signal', signal='NewTube'), EventPattern('dbus-signal', signal='TubeChannelStateChanged'), ) @@ -260,13 +186,6 @@ def offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, assert state_event.args[0] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING - # Now the tube's been offered, it should be shown on the old interface - tubes = tubes_iface.ListTubes(byte_arrays=True) - assert len(tubes) == 1 - expected_tube = (None, self_handle, cs.TUBE_TYPE_DBUS, 'com.example.TestCase', - sample_parameters, cs.TUBE_STATE_REMOTE_PENDING) - t.check_tube_in_tubes(expected_tube, tubes) - status = tube_chan.Get(cs.CHANNEL_IFACE_TUBE, 'State', dbus_interface=cs.PROPERTIES_IFACE) assert status == cs.TUBE_STATE_REMOTE_PENDING @@ -304,7 +223,6 @@ def test(q, bus, conn, stream, bytestream_cls, access_control): sync_stream(q, stream) - offer_old_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, bytestream_cls) offer_new_dbus_tube(q, bus, conn, stream, self_handle, alice_handle, bytestream_cls, access_control) if __name__ == '__main__': diff --git a/tests/twisted/tubes/offer-private-stream-tube.py b/tests/twisted/tubes/offer-private-stream-tube.py index 71f59be19..de37041c2 100644 --- a/tests/twisted/tubes/offer-private-stream-tube.py +++ b/tests/twisted/tubes/offer-private-stream-tube.py @@ -98,27 +98,6 @@ def test(q, bus, conn, stream, bytestream_cls, # Test tubes with Bob. Bob has tube capabilities. bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] - # old tubes API - call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TUBES, cs.HT_CONTACT, - bob_handle, True) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) - - assert len(ret.value) == 1 - chan_path = ret.value[0] - - t.check_NewChannel_signal(old_sig.args, cs.CHANNEL_TYPE_TUBES, chan_path, - bob_handle, True) - t.check_NewChannels_signal(conn, new_sig.args, cs.CHANNEL_TYPE_TUBES, chan_path, - bob_handle, 'bob@localhost', self_handle) - old_tubes_channel_properties = new_sig.args[0][0] - - t.check_conn_properties(q, conn, [old_tubes_channel_properties]) - # Try CreateChannel with correct properties # Gabble must succeed call_async(q, conn.Requests, 'CreateChannel', @@ -128,15 +107,23 @@ def test(q, bus, conn, stream, bytestream_cls, cs.STREAM_TUBE_SERVICE: "newecho", }) - # the NewTube signal (old API) is not fired now as the tube wasn't offered - # yet - ret, old_sig, new_sig = q.expect_many( + def find_stream_tube(channels): + for path, props in channels: + if props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE: + return path, props + + return None, None + + def new_chan_predicate(e): + path, _ = find_stream_tube(e.args[0]) + return path is not None + + ret, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), + EventPattern('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate), ) - assert len(ret.value) == 2 # CreateChannel returns 2 values: o, a{sv} new_chan_path = ret.value[0] new_chan_prop_asv = ret.value[1] # State and Parameters are mutables so not announced @@ -144,9 +131,6 @@ def test(q, bus, conn, stream, bytestream_cls, assert cs.TUBE_PARAMETERS not in new_chan_prop_asv assert new_chan_path.find("StreamTube") != -1, new_chan_path assert new_chan_path.find("SITubesChannel") == -1, new_chan_path - # The path of the Channel.Type.Tubes object MUST be different to the path - # of the Channel.Type.StreamTube object ! - assert chan_path != new_chan_path new_tube_chan = bus.get_object(conn.bus_name, new_chan_path) new_tube_iface = dbus.Interface(new_tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) @@ -158,110 +142,15 @@ def test(q, bus, conn, stream, bytestream_cls, # the tube created using the new API is in the "not offered" state assert new_tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED - t.check_NewChannel_signal(old_sig.args, cs.CHANNEL_TYPE_STREAM_TUBE, - new_chan_path, bob_handle, True) - t.check_NewChannels_signal(conn, new_sig.args, cs.CHANNEL_TYPE_STREAM_TUBE, - new_chan_path, bob_handle, 'bob@localhost', self_handle) - stream_tube_channel_properties = new_sig.args[0][0] + _, stream_tube_channel_properties = find_stream_tube(new_sig.args[0]) assert cs.TUBE_STATE not in stream_tube_channel_properties assert cs.TUBE_PARAMETERS not in stream_tube_channel_properties - t.check_conn_properties(q, conn, - [old_tubes_channel_properties, stream_tube_channel_properties]) - - tubes_chan = bus.get_object(conn.bus_name, chan_path) - tubes_iface = dbus.Interface(tubes_chan, cs.CHANNEL_TYPE_TUBES) - - t.check_channel_properties(q, bus, conn, tubes_chan, cs.CHANNEL_TYPE_TUBES, - bob_handle, "bob@localhost") - - # Create another tube using old API - call_async(q, tubes_iface, 'OfferStreamTube', - 'echo', sample_parameters, address_type, address1, - access_control, access_control_param) - - event, return_event, new_chan, new_chans = q.expect_many( - EventPattern('stream-message'), - EventPattern('dbus-return', method='OfferStreamTube'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels')) - - message = event.stanza - assert message['to'] == bob_full_jid - tube_nodes = xpath.queryForNodes('/message/tube[@xmlns="%s"]' % ns.TUBES, - message) - assert tube_nodes is not None - assert len(tube_nodes) == 1 - tube = tube_nodes[0] - - assert tube['service'] == 'echo' - assert tube['type'] == 'stream' - assert not tube.hasAttribute('initiator') - stream_tube_id = long(tube['id']) - - params = {} - parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) - for node in parameter_nodes: - assert node['name'] not in params - params[node['name']] = (node['type'], str(node)) - assert params == {'ay': ('bytes', 'aGVsbG8='), - 's': ('str', 'hello'), - 'i': ('int', '-123'), - 'u': ('uint', '123'), - } - - - # the tube channel (new API) is announced - t.check_NewChannel_signal(new_chan.args, cs.CHANNEL_TYPE_STREAM_TUBE, - None, bob_handle, False) - t.check_NewChannels_signal(conn, new_chans.args, cs.CHANNEL_TYPE_STREAM_TUBE, - new_chan.args[0], bob_handle, "bob@localhost", self_handle) - - props = new_chans.args[0][0][1] - assert cs.TUBE_STATE not in props - assert cs.TUBE_PARAMETERS not in props - - # We offered a tube using the old tube API and created one with the new - # API, so there are 2 tubes. Check the new tube API works - assert len(filter(lambda x: - x[1] == cs.CHANNEL_TYPE_TUBES, - conn.ListChannels())) == 1 - channels = filter(lambda x: - x[1] == cs.CHANNEL_TYPE_STREAM_TUBE and - x[0] == new_chan_path, - conn.ListChannels()) - assert len(channels) == 1 - assert new_chan_path == channels[0][0] - - old_tube_chan = bus.get_object(conn.bus_name, new_chan.args[0]) - - tube_basic_props = old_tube_chan.GetAll(cs.CHANNEL, - dbus_interface=cs.PROPERTIES_IFACE) - assert tube_basic_props.get("InitiatorHandle") == self_handle - - stream_tube_props = old_tube_chan.GetAll(cs.CHANNEL_TYPE_STREAM_TUBE, - dbus_interface=cs.PROPERTIES_IFACE) - assert stream_tube_props.get("Service") == "echo", stream_tube_props - - old_tube_props = old_tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, - dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) - assert old_tube_props.get("Parameters") == dbus.Dictionary(sample_parameters) - - # Tube have been created using the old API and so is already offered - assert old_tube_props['State'] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING - - t.check_channel_properties(q, bus, conn, tubes_chan, cs.CHANNEL_TYPE_TUBES, - bob_handle, "bob@localhost") - t.check_channel_properties(q, bus, conn, old_tube_chan, - cs.CHANNEL_TYPE_STREAM_TUBE, bob_handle, "bob@localhost", - cs.TUBE_CHANNEL_STATE_REMOTE_PENDING) - - # Offer the first tube created (new API) + # Offer the first tube created call_async(q, new_tube_iface, 'Offer', address_type, address2, access_control, new_sample_parameters) - msg_event, new_tube_sig, state_event = q.expect_many( + msg_event, state_event = q.expect_many( EventPattern('stream-message'), - EventPattern('dbus-signal', signal='NewTube'), EventPattern('dbus-signal', signal='TubeChannelStateChanged')) assert state_event.args[0] == cs.TUBE_CHANNEL_STATE_REMOTE_PENDING @@ -277,7 +166,7 @@ def test(q, bus, conn, stream, bytestream_cls, assert tube['service'] == 'newecho' assert tube['type'] == 'stream' assert not tube.hasAttribute('initiator') - new_stream_tube_id = long(tube['id']) + stream_tube_id = long(tube['id']) params = {} parameter_nodes = xpath.queryForNodes('/tube/parameters/parameter', tube) @@ -290,17 +179,9 @@ def test(q, bus, conn, stream, bytestream_cls, 'u': ('uint', '123'), } - # check NewTube signal (old API) - id, initiator_handle, type, service, params, state = new_tube_sig.args - assert initiator_handle == self_handle - assert type == 1 # stream - assert service == 'newecho' - assert params == new_sample_parameters - assert state == 1 # remote pending - # The new tube has been offered, the parameters cannot be changed anymore # We need to use call_async to check the error - tube_prop_iface = dbus.Interface(old_tube_chan, cs.PROPERTIES_IFACE) + tube_prop_iface = dbus.Interface(new_tube_chan, cs.PROPERTIES_IFACE) call_async(q, tube_prop_iface, 'Set', cs.CHANNEL_IFACE_TUBE, 'Parameters', dbus.Dictionary( {dbus.String(u'foo2'): dbus.String(u'bar2')}, @@ -323,12 +204,10 @@ def test(q, bus, conn, stream, bytestream_cls, stream_node['tube'] = str(stream_tube_id) stream.send(iq) - si_reply_event, _, _, new_conn_event, socket_event = q.expect_many( + si_reply_event, _, new_conn_event, socket_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, cs.TUBE_STATE_OPEN]), - EventPattern('dbus-signal', signal='StreamTubeNewConnection', - args=[stream_tube_id, bob_handle]), + EventPattern('dbus-signal', signal='TubeChannelStateChanged', + args=[cs.TUBE_STATE_OPEN]), EventPattern('dbus-signal', signal='NewRemoteConnection'), EventPattern('socket-connected')) @@ -348,11 +227,6 @@ def test(q, bus, conn, stream, bytestream_cls, t.check_new_connection_access(q, access_control, access, protocol) protocol.echoed = True - expected_tube = (stream_tube_id, self_handle, cs.TUBE_TYPE_STREAM, 'echo', - sample_parameters, cs.TUBE_STATE_OPEN) - tubes = tubes_iface.ListTubes(byte_arrays=True) - t.check_tube_in_tubes(expected_tube, tubes) - # The CM is the server, so fake a client wanting to talk to it # New API tube bytestream2 = bytestream_cls(stream, q, 'beta', bob_full_jid, @@ -360,13 +234,11 @@ def test(q, bus, conn, stream, bytestream_cls, iq, si = bytestream2.create_si_offer(ns.TUBES) stream_node = si.addElement((ns.TUBES, 'stream')) - stream_node['tube'] = str(new_stream_tube_id) + stream_node['tube'] = str(stream_tube_id) stream.send(iq) - si_reply_event, _, new_conn_event, socket_event = q.expect_many( + si_reply_event, new_conn_event, socket_event = q.expect_many( EventPattern('stream-iq', iq_type='result'), - EventPattern('dbus-signal', signal='TubeChannelStateChanged', - args=[cs.TUBE_STATE_OPEN]), EventPattern('dbus-signal', signal='NewRemoteConnection'), EventPattern('socket-connected')) @@ -386,10 +258,6 @@ def test(q, bus, conn, stream, bytestream_cls, t.check_new_connection_access(q, access_control, access, protocol) protocol.echoed = True - expected_tube = (new_stream_tube_id, self_handle, cs.TUBE_TYPE_STREAM, - 'newecho', new_sample_parameters, cs.TUBE_STATE_OPEN) - t.check_tube_in_tubes (expected_tube, tubes_iface.ListTubes(byte_arrays=True)) - # have the fake client open the stream bytestream1.open_bytestream() diff --git a/tests/twisted/tubes/test-get-available-tubes.py b/tests/twisted/tubes/test-get-available-tubes.py index 1020c0250..7b860ebfd 100644 --- a/tests/twisted/tubes/test-get-available-tubes.py +++ b/tests/twisted/tubes/test-get-available-tubes.py @@ -24,19 +24,14 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, iq_event.stanza) - call_async(q, conn, 'RequestHandles', cs.HT_ROOM, ['chat@conf.localhost']) - - event = q.expect('dbus-return', method='RequestHandles') - handles = event.value[0] + # muc stream tube + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: 'chat@conf.localhost', + cs.STREAM_TUBE_SERVICE: 'test'}) - # request tubes channel (old API) - call_async(q, conn, 'RequestChannel', - tp_name_prefix + '.Channel.Type.Tubes', cs.HT_ROOM, handles[0], True) - - _, stream_event = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [], [2], 0, 0]), - EventPattern('stream-presence', to='chat@conf.localhost/test')) + q.expect('stream-presence', to='chat@conf.localhost/test') # Send presence for other member of room. stream.send(make_muc_presence('owner', 'moderator', 'chat@conf.localhost', 'bob')) @@ -44,34 +39,17 @@ def test(q, bus, conn, stream): # Send presence for own membership of room. stream.send(make_muc_presence('owner', 'moderator', 'chat@conf.localhost', 'test')) - new_chans, members, event = q.expect_many( - EventPattern('dbus-signal', signal='NewChannels'), + members, event = q.expect_many( EventPattern('dbus-signal', signal='MembersChanged', args=[u'', [2, 3], [], [], [], 0, 0]), - EventPattern('dbus-return', method='RequestChannel')) - - channels = new_chans.args[0] - assertLength(2, channels) - - assertEquals(conn.InspectHandles(cs.HT_CONTACT, [2]), ['chat@conf.localhost/test']) - assertEquals(conn.InspectHandles(cs.HT_CONTACT, [3]), ['chat@conf.localhost/bob']) - bob_handle = 3 - - tubes_chan = bus.get_object(conn.bus_name, event.value[0]) - tubes_iface_muc = dbus.Interface(tubes_chan, - tp_name_prefix + '.Channel.Type.Tubes') - - # FIXME: these using a "1-1" tubes channel too + EventPattern('dbus-return', method='CreateChannel')) - # test GetAvailableTubeTypes (old API) - tube_types = tubes_iface_muc.GetAvailableTubeTypes() + path = event.value[0] + props = event.value[1] - assertLength(2, tube_types) - assertContains(cs.TUBE_TYPE_DBUS, tube_types) - assertContains(cs.TUBE_TYPE_STREAM, tube_types) - - # test GetAvailableStreamTubeTypes (old API) - stream_tubes_types = tubes_iface_muc.GetAvailableStreamTubeTypes() + tube = bus.get_object(conn.bus_name, path) + stream_tubes_types = tube.Get(cs.CHANNEL_TYPE_STREAM_TUBE, 'SupportedSocketTypes', + dbus_interface=cs.PROPERTIES_IFACE) if os.name == 'posix': assert cs.SOCKET_ACCESS_CONTROL_LOCALHOST in \ @@ -88,17 +66,5 @@ def test(q, bus, conn, stream): assertEquals([cs.SOCKET_ACCESS_CONTROL_LOCALHOST, cs.SOCKET_ACCESS_CONTROL_PORT], stream_tubes_types[cs.SOCKET_ADDRESS_TYPE_IPV6]) - # muc stream tube (new API) - path, props = conn.Requests.CreateChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, - cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_ID: 'chat@conf.localhost', - cs.STREAM_TUBE_SERVICE: 'test'}) - - tube = bus.get_object(conn.bus_name, path) - sockets = tube.Get(cs.CHANNEL_TYPE_STREAM_TUBE, 'SupportedSocketTypes', - dbus_interface=cs.PROPERTIES_IFACE) - assertEquals(sockets, stream_tubes_types) - if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/tubes/test-socks5-muc.py b/tests/twisted/tubes/test-socks5-muc.py index 5f498a59e..4153801f8 100644 --- a/tests/twisted/tubes/test-socks5-muc.py +++ b/tests/twisted/tubes/test-socks5-muc.py @@ -6,11 +6,13 @@ if os.name != 'posix': # skipped on non-Unix for now, because it uses a Unix socket raise SystemExit(77) +import dbus + from servicetest import call_async, EventPattern, EventProtocolClientFactory from gabbletest import acknowledge_iq, make_muc_presence, exec_test import constants as cs import ns -from muctubeutil import get_muc_tubes_channel +from mucutil import join_muc from bytestream import BytestreamS5BRelay, create_from_si_offer, announce_socks5_proxy from twisted.internet import reactor @@ -25,8 +27,7 @@ def test(q, bus, conn, stream): announce_socks5_proxy(q, stream, disco_event.stanza) - room_handle, tubes_chan, tubes_iface = get_muc_tubes_channel(q, bus, conn, - stream, 'chat@conf.localhost') + text_chan = join_muc(q, bus, conn, stream, 'chat@conf.localhost') # bob offers a stream tube stream_tube_id = 1 @@ -40,20 +41,27 @@ def test(q, bus, conn, stream): parameters = tube.addElement((None, 'parameters')) stream.send(presence) - e = q.expect('dbus-signal', signal='NewChannels') + def new_chan_predicate(e): + path, props = e.args[0][0] + return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE + + e = q.expect('dbus-signal', signal='NewChannels', + predicate=new_chan_predicate) channels = e.args[0] assert len(channels) == 1 path, props = channels[0] assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAM_TUBE tube_chan = bus.get_object(conn.bus_name, path) - call_async(q, tubes_iface, 'AcceptStreamTube', stream_tube_id, 0, 0, '', + tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) + + call_async(q, tube_iface, 'Accept', 0, 0, '', byte_arrays=True) accept_return_event, _ = q.expect_many( - EventPattern('dbus-return', method='AcceptStreamTube'), - EventPattern('dbus-signal', signal='TubeStateChanged', - args=[stream_tube_id, cs.TUBE_CHANNEL_STATE_OPEN])) + EventPattern('dbus-return', method='Accept'), + EventPattern('dbus-signal', signal='TubeChannelStateChanged', + args=[cs.TUBE_CHANNEL_STATE_OPEN])) unix_socket_adr = accept_return_event.value[0] diff --git a/tests/twisted/tubes/tubetestutil.py b/tests/twisted/tubes/tubetestutil.py index 9aeb89ed6..3eb86d9d5 100644 --- a/tests/twisted/tubes/tubetestutil.py +++ b/tests/twisted/tubes/tubetestutil.py @@ -81,24 +81,6 @@ def check_conn_properties(q, conn, channel_list=None): assert i in properties['Channels'], \ (i, properties['Channels']) - # 1-1 tubes channel (old API) - assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - }, - [cs.TARGET_HANDLE, cs.TARGET_ID - ] - ) in properties.get('RequestableChannelClasses'),\ - properties['RequestableChannelClasses'] - - # muc tubes channel (old API) - assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TUBES, - cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - }, - [cs.TARGET_HANDLE, cs.TARGET_ID - ] - ) in properties.get('RequestableChannelClasses'),\ - properties['RequestableChannelClasses'] - # 1-1 StreamTube channel assert ({cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT diff --git a/tests/twisted/vcard/clear-avatar.py b/tests/twisted/vcard/clear-avatar.py new file mode 100644 index 000000000..333c5e8e7 --- /dev/null +++ b/tests/twisted/vcard/clear-avatar.py @@ -0,0 +1,27 @@ +""" +Tests the very simple case of "clearing your own avatar". +""" + +from servicetest import call_async +from gabbletest import ( + exec_test, expect_and_handle_get_vcard, expect_and_handle_set_vcard, current_vcard + ) + +def test(q, bus, conn, stream): + photo = current_vcard.addElement((None, 'PHOTO')) + photo.addElement((None, 'TYPE')).addContent('image/fake') + photo.addElement((None, 'BINVAL')).addContent('NYANYANYANYANYAN') + + call_async(q, conn.Avatars, 'ClearAvatar') + + expect_and_handle_get_vcard(q, stream) + + def check(vcard): + assert len(vcard.children) == 0, vcard.toXml() + + expect_and_handle_set_vcard(q, stream, check=check) + + q.expect('dbus-return', method='ClearAvatar') + +if __name__ == '__main__': + exec_test(test) diff --git a/tests/twisted/vcard/overlapping-sets.py b/tests/twisted/vcard/overlapping-sets.py index d7fe563c5..a57ca9cc4 100644 --- a/tests/twisted/vcard/overlapping-sets.py +++ b/tests/twisted/vcard/overlapping-sets.py @@ -8,7 +8,7 @@ from servicetest import (EventPattern, call_async, sync_dbus, assertEquals, assertLength) from gabbletest import ( acknowledge_iq, exec_test, expect_and_handle_get_vcard, make_result_iq, - sync_stream) + sync_stream, disconnect_conn) import ns def test(q, bus, conn, stream): @@ -51,8 +51,9 @@ def test(q, bus, conn, stream): vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) - assertEquals(hello_binval, xpath.queryForString('/iq/vCard/PHOTO/BINVAL', - vcard_set_event.stanza)) + binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', + vcard_set_event.stanza) + assertEquals(hello_binval, binval.strip()) assertEquals(None, xpath.queryForNodes('/iq/vCard/FN', vcard_set_event.stanza)) assertEquals(None, xpath.queryForNodes('/iq/vCard/N', @@ -80,8 +81,9 @@ def test(q, bus, conn, stream): vcard_set_event.stanza)) assertEquals('image/png', xpath.queryForString('/iq/vCard/PHOTO/TYPE', vcard_set_event.stanza)) - assertEquals(hello_binval, xpath.queryForString('/iq/vCard/PHOTO/BINVAL', - vcard_set_event.stanza)) + binval = xpath.queryForString('/iq/vCard/PHOTO/BINVAL', + vcard_set_event.stanza) + assertEquals(hello_binval, binval.strip()) assertLength(1, xpath.queryForNodes('/iq/vCard/N', vcard_set_event.stanza)) assertEquals('Robert', xpath.queryForString('/iq/vCard/N/GIVEN', @@ -127,8 +129,7 @@ def test(q, bus, conn, stream): # Now Gabble gets disconnected. sync_stream(q, stream) - conn.Disconnect() - q.expect('dbus-signal', signal='StatusChanged', args=[2, 1]) + disconnect_conn(q, conn, stream) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/vcard/set-avatar.py b/tests/twisted/vcard/set-avatar.py new file mode 100644 index 000000000..6ce38a5c1 --- /dev/null +++ b/tests/twisted/vcard/set-avatar.py @@ -0,0 +1,55 @@ +""" +Tests the very simple case of "setting your own avatar". +""" + +from twisted.words.xish import xpath +from servicetest import call_async, assertEquals +from gabbletest import ( + exec_test, expect_and_handle_get_vcard, expect_and_handle_set_vcard, + ) +import base64 +import functools + +def test(q, bus, conn, stream, image_data, mime_type): + call_async(q, conn.Avatars, 'SetAvatar', image_data, mime_type) + + expect_and_handle_get_vcard(q, stream) + + def check(vcard): + assertEquals(mime_type, + xpath.queryForString('/vCard/PHOTO/TYPE', vcard)) + + binval = xpath.queryForString('/vCard/PHOTO/BINVAL', vcard) + + # <http://xmpp.org/extensions/xep-0153.html#bizrules-image> says: + # + # 5. The image data MUST conform to the base64Binary datatype and thus + # be encoded in accordance with Section 6.8 of RFC 2045, which + # recommends that base64 data should have lines limited to at most + # 76 characters in length. + lines = binval.split('\n') + for line in lines: + assert len(line) <= 76, line + + assertEquals(image_data, base64.decodestring(binval)) + + expect_and_handle_set_vcard(q, stream, check=check) + + q.expect('dbus-return', method='SetAvatar') + +def test_little_avatar(q, bus, conn, stream): + test(q, bus, conn, stream, image_data='Guy.brush', + mime_type='image/x-mighty-pirate') + +def test_massive_avatar(q, bus, conn, stream): + """Regression test for + <https://bugs.freedesktop.org/show_bug.cgi?id=57080>, where a too-small + buffer was allocated if the base64-encoded avatar spanned multiple lines. + + """ + avatar = '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\xec\x00\x00\x00\x94\x04\x03\x00\x00\x00b\x8c\xd8\x8b\x00\x00\x00\x18PLTEap\x00\xff\x99\x99\xff\xff\xff\xff3\x99\xff\xcc\x99\x99\x99\x99\xff\x99\xff\x00\x00\x00\xcdt\xca\x11\x00\x00\x00\x01tRNS\x00@\xe6\xd8f\x00\x00\x00\x01bKGD\x00\x88\x05\x1dH\x00\x00\x00\tpHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xdc\x0b\x0e\x0f"%\xd9\xcd\xe5\x8c\x00\x00\x01\x88IDATx\xda\xed\xdb=n\xc20\x14\xc0\xf1l\xcc\x0c\\ K\x0f\x10\t.P\x95\xb9\x95\x10\x07\xa0jW\x96\xe0\xeb\x97\x90 ?\xdb\x0f;\x1f.i\xa3\xff\x9bBb\xfb\x17$\xec\xbc\xd8\xa6(ba\xa6E12`aa\xc7\xb2\xd7z\xaf\xd3\xe2\xda\xc2\x19\x16vN\xd68\xe6\xdb\xd7\xb0\xf8\xb4U\xf7\x83\xfa\x11,,l\x1eVm\xf8TU\xd5\xd6\x1eo\xc3\x12\xb0\xb0\xb03\xb1\n2$`aa\xe7c\xe3\xf1\xdd\xbeU^\xc2[\x14\xec\xaa-t\x86\x85\xfd\x93lC\xd6\x87[\x1c-\xedu \xe3\x16\x82\x85\x85\x9d\xca\xea\xb3\x93QVd\xa8\x82\xedZ\xbd\x84\xec\xc1)\x00\x0b\x0b\x9b\x83\x15\xa7\xee\xf2\x88\xe1\xc2k\xc5\x1d&`a\x9f\xc0\x1a\xf1#\x175\\\xb6ID\xfb\xb0\xf1\x80\x85\x85\xcd\xc1Z\xb9\xf6\xe4\xd8p\xd1\xdc\xc4n )\xbf\x19,\xecrX\x99@\x8aK\x1d\xfbp\xbe\xd1\xeb\xb3\x1feY\xbe\xa87R\xb6W`aa\x97\xc1\xda\xb9W\xd3g\x94\xd2_2\xfd|\xbc\xfb\xa8d\x12\xb0\xb0\xbf\xc7\xfa}Ie\xc5\n\xc4\x9d}_\xdfb\x93z\xce\xae\xbb\x80\x85\x85\xcd\xcf\x86\x9b[\xf4Er\x85=\xba\xd9\xb68\xacaaa\x9f\xc8F7\x93\xea\x8fz%\x06\xadh\xc2\xc2\xe6`\xdd\x9c5\x1d\xfb\x9e\x136\x89\xcd-\xb0\xb0\xb0cYwM\xdb\xe4\x8c\xc4n4X\xd8e\xb1\xb6\xf4\xca}`\x86\x9dO)\xe0e\x8e\xe9\xed\x9c\xb0\xb0\xb0\x13\xd8\xb0\x87\x8b\xb9\xd7\xc7\xd5\x95B\xfd\xffP\x0e\x0b\xfb?\xd9\x1f\xd9\xb2to\xf9Q\xd6\xee\x00\x00\x00\x00IEND\xaeB`\x82' + test(q, bus, conn, stream, image_data=avatar, mime_type='image/png') + +if __name__ == '__main__': + exec_test(test_little_avatar) + exec_test(test_massive_avatar) diff --git a/tests/twisted/vcard/set-set-disconnect.py b/tests/twisted/vcard/set-set-disconnect.py index b7b73151d..e35ee9744 100644 --- a/tests/twisted/vcard/set-set-disconnect.py +++ b/tests/twisted/vcard/set-set-disconnect.py @@ -4,7 +4,7 @@ Regression test for crash when disconnecting in the middle of a set. """ from servicetest import EventPattern, call_async, sync_dbus -from gabbletest import exec_test, acknowledge_iq, expect_and_handle_get_vcard, sync_stream +from gabbletest import exec_test, acknowledge_iq, expect_and_handle_get_vcard, sync_stream, disconnect_conn import constants as cs def test(q, bus, conn, stream): @@ -18,9 +18,9 @@ def test(q, bus, conn, stream): 'stream-iq', iq_type='set', query_ns='vcard-temp', query_name='vCard') call_async( q, conn.Avatars, 'SetAvatar', 'LeChuck.brush', 'image/x-ghost-pirate') - conn.Disconnect() - q.expect('dbus-signal', signal='StatusChanged', - args=[cs.CONN_STATUS_DISCONNECTED, cs.CSR_REQUESTED]), + + disconnect_conn(q, conn, stream) + q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) q.expect('dbus-error', method='SetAvatar', name=cs.NOT_AVAILABLE) sync_dbus(bus, q, conn) diff --git a/tests/twisted/vcard/supported-fields.py b/tests/twisted/vcard/supported-fields.py index 074d2331c..7a7860ce1 100644 --- a/tests/twisted/vcard/supported-fields.py +++ b/tests/twisted/vcard/supported-fields.py @@ -41,6 +41,7 @@ def check_google_props(props): assertEquals([ ('fn', [], PARAMS_EXACT | OVERWRITTEN_BY_NICKNAME, 1), ('n', [], PARAMS_EXACT, 1), + ('url', [], PARAMS_EXACT, UNLIMITED), ], sf) def check_normal_props(props): diff --git a/tests/twisted/vcard/test-vcard-race.py b/tests/twisted/vcard/test-vcard-race.py index 291a0df57..5ecd978e1 100644 --- a/tests/twisted/vcard/test-vcard-race.py +++ b/tests/twisted/vcard/test-vcard-race.py @@ -13,7 +13,7 @@ import base64 from twisted.words.xish import xpath -from servicetest import call_async, sync_dbus +from servicetest import call_async, sync_dbus, assertEquals from gabbletest import ( exec_test, expect_and_handle_get_vcard, expect_and_handle_set_vcard, make_result_iq, sync_stream) @@ -64,9 +64,9 @@ def test(q, bus, conn, stream): assert types is not None and len(types) == 1, repr(types) assert binvals is not None and len(binvals) == 1, repr(binvals) assert str(types[0]) == 'image/png' - got = str(binvals[0]) + got = str(binvals[0]).strip() exp = base64.b64encode('hello') - assert got == exp, (got, exp) + assertEquals(exp, got) # Now Gabble should set a new vCard with both of the above changes. expect_and_handle_set_vcard(q, stream, has_nickname_and_photo) diff --git a/tools/Makefile.am b/tools/Makefile.am index 3cfcfe923..5b78d699c 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,3 +1,21 @@ +abs_top_builddir = @abs_top_builddir@ + +noinst_SCRIPTS = telepathy-glib-env + +telepathy-glib-env: telepathy-glib-env.in Makefile + sed -e 's![@]abs_top_builddir[@]!$(abs_top_builddir)!' $< > $@ + chmod +x $@ + +if ENABLE_INSTALLED_TESTS +toolsdir = @tpglibtestsdir@/tools +tools_SCRIPTS = \ + with-session-bus.sh \ + test-wrapper.sh \ + libglibcodegen.py \ + libtpcodegen.py \ + $(NULL) +endif + EXTRA_DIST = \ c-constants-gen.py \ check-coding-style.mk \ @@ -5,29 +23,50 @@ EXTRA_DIST = \ check-misc.sh \ check-whitespace.sh \ doc-generator.xsl \ + flymake.mk \ + git-which-branch.sh \ + glib-client-gen.py \ + glib-client-marshaller-gen.py \ + glib-errors-check-gen.py \ + glib-errors-str-gen.py \ glib-ginterface-gen.py \ glib-gtypes-generator.py \ glib-interfaces-gen.py \ - glib-signals-marshal-gen.py \ + gobject-foo.py \ lcov.am \ - libglibcodegen.py \ libtpcodegen.py \ + libglibcodegen.py \ make-release-mail.py \ + make-version-script.py \ + manager-file.py \ + shave.mk \ telepathy.am \ + telepathy-glib.supp \ + telepathy-glib-env.in \ + test-wrapper.sh \ + with-session-bus.sh \ xincludator.py -CLEANFILES = *.pyc *.pyo +CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS) all: $(EXTRA_DIST) libglibcodegen.py: libtpcodegen.py - test -e $< - $(AM_V_GEN)touch $@ - -glib-ginterface-gen.py glib-gtypes-generator.py glib-interfaces-gen.py \ -glib-signals-marshal-gen.py c-constants-gen.py: %: libglibcodegen.py - test -e $< - $(AM_V_GEN)touch $@ + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +c-constants-gen.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +glib-client-marshaller-gen.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +glib-errors-enum-body-gen.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +glib-errors-enum-header-gen.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +glib-ginterface-gen.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +glib-gtypes-generator.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ +glib-interfaces-gen.py: libglibcodegen.py + $(AM_V_GEN)test -e ${srcdir}/$@ && touch ${srcdir}/$@ TELEPATHY_GLIB_SRCDIR = $(top_srcdir)/../telepathy-glib maintainer-update-from-telepathy-glib: diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py index ff2a24d47..c7a93d371 100644 --- a/tools/c-constants-gen.py +++ b/tools/c-constants-gen.py @@ -3,6 +3,7 @@ from sys import argv, stdout, stderr import xml.dom.minidom +from libtpcodegen import file_set_contents from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path @@ -11,19 +12,23 @@ class Generator(object): self.prefix = prefix + '_' self.spec = get_by_path(dom, "spec")[0] - self.__header = open(output_base + '.h', 'w') - self.__docs = open(output_base + '-gtk-doc.h', 'w') + self.output_base = output_base + self.__header = [] + self.__docs = [] def __call__(self): self.do_header() self.do_body() self.do_footer() + file_set_contents(self.output_base + '.h', ''.join(self.__header)) + file_set_contents(self.output_base + '-gtk-doc.h', ''.join(self.__docs)) + def write(self, code): - self.__header.write(code.encode('utf-8')) + self.__header.append(code.encode('utf-8')) def d(self, code): - self.__docs.write(code.encode('utf-8')) + self.__docs.append(code.encode('utf-8')) # Header def do_header(self): @@ -62,8 +67,7 @@ extern "C" { flags.getAttribute('name') self.d("""\ /** - * -%s: + * %s: """ % (self.prefix + name).replace('_', '')) for flag in get_by_path(flags, 'flag'): self.do_gtkdoc(flag, value_prefix) @@ -97,8 +101,7 @@ extern "C" { enum.getAttribute('name') + 's' self.d("""\ /** - * -%s: + * %s: """ % (self.prefix + name).replace('_', '')) vals = get_by_path(enum, 'enumvalue') for val in vals: @@ -123,19 +126,29 @@ extern "C" { self.d("""\ /** - * NUM_%(upper-plural)s: (skip) + * %(upper-prefix)sNUM_%(upper-plural)s: + * + * 1 higher than the highest valid value of #%(mixed-name)s. + */ + +/** + * NUM_%(upper-prefix)s%(upper-plural)s: (skip) * * 1 higher than the highest valid value of #%(mixed-name)s. + * In new code, use %(upper-prefix)sNUM_%(upper-plural)s instead. */ """ % {'mixed-name' : (self.prefix + name).replace('_', ''), - 'upper-plural' : (self.prefix + name_plural).upper(), + 'upper-prefix' : self.prefix.upper(), + 'upper-plural' : name_plural.upper(), 'last-val' : vals[-1].getAttribute('value')}) self.write("""\ -#define NUM_%(upper-plural)s (%(last-val)s+1) +#define %(upper-prefix)sNUM_%(upper-plural)s (%(last-val)s+1) +#define NUM_%(upper-prefix)s%(upper-plural)s %(upper-prefix)sNUM_%(upper-plural)s """ % {'mixed-name' : (self.prefix + name).replace('_', ''), - 'upper-plural' : (self.prefix + name_plural).upper(), + 'upper-prefix' : self.prefix.upper(), + 'upper-plural' : name_plural.upper(), 'last-val' : vals[-1].getAttribute('value')}) def do_val(self, val, value_prefix): diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh index 4330b1479..55834207a 100644 --- a/tools/check-c-style.sh +++ b/tools/check-c-style.sh @@ -3,13 +3,6 @@ fail=0 ( . "${tools_dir}"/check-misc.sh ) || fail=$? -if grep -n '^ *GError *\*[[:alpha:]_][[:alnum:]_]* *;' "$@" -then - echo "^^^ The above files contain uninitialized GError*s - they should be" - echo " initialized to NULL" - fail=1 -fi - # The first regex finds function calls like foo() (as opposed to foo ()). # It attempts to ignore string constants (may cause false negatives). # The second and third ignore block comments (gtkdoc uses foo() as markup). diff --git a/tools/flymake.mk b/tools/flymake.mk new file mode 100644 index 000000000..020a7bfbf --- /dev/null +++ b/tools/flymake.mk @@ -0,0 +1,4 @@ +check-syntax: + $(CC) $(AM_CPPFLAGS) $(AM_CFLAGS) -fsyntax-only $(CHK_SOURCES) + +.PHONY: check-syntax diff --git a/tools/git-which-branch.sh b/tools/git-which-branch.sh new file mode 100644 index 000000000..b96b5d5e2 --- /dev/null +++ b/tools/git-which-branch.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# git-which-branch.sh - output the name of the current git branch +# +# The canonical location of this program is the telepathy-spec tools/ +# directory, please synchronize any changes with that copy. +# +# Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/> +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +default="$1" +if { ref="`git symbolic-ref HEAD 2>/dev/null`"; }; then + echo ${ref#refs/heads/} + exit 0 +fi + +if test -n "$default"; then + echo "$default" >/dev/null + exit 0 +fi + +echo "no git branch found" >&2 +exit 1 diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py new file mode 100644 index 000000000..f8465a62b --- /dev/null +++ b/tools/glib-client-gen.py @@ -0,0 +1,1269 @@ +#!/usr/bin/python + +# glib-client-gen.py: "I Can't Believe It's Not dbus-binding-tool" +# +# Generate GLib client wrappers from the Telepathy specification. +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import os.path +import xml.dom.minidom +from getopt import gnu_getopt + +from libtpcodegen import file_set_contents +from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ + get_docstring, xml_escape, get_deprecated + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +class Generator(object): + + def __init__(self, dom, prefix, basename, opts): + self.dom = dom + self.__header = [] + self.__body = [] + self.__docs = [] + + self.prefix_lc = prefix.lower() + self.prefix_uc = prefix.upper() + self.prefix_mc = prefix.replace('_', '') + self.basename = basename + self.group = opts.get('--group', None) + self.iface_quark_prefix = opts.get('--iface-quark-prefix', None) + self.tp_proxy_api = tuple(map(int, + opts.get('--tp-proxy-api', '0').split('.'))) + self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *' + self.proxy_arg = opts.get('--subclass', 'void') + ' *' + self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY') + self.proxy_doc = ('A #%s or subclass' + % opts.get('--subclass', 'TpProxy')) + if self.proxy_arg == 'void *': + self.proxy_arg = 'gpointer ' + + self.reentrant_symbols = set() + try: + filename = opts['--generate-reentrant'] + with open(filename, 'r') as f: + for line in f.readlines(): + self.reentrant_symbols.add(line.strip()) + except KeyError: + pass + + self.deprecate_reentrant = opts.get('--deprecate-reentrant', None) + self.deprecation_attribute = opts.get('--deprecation-attribute', + 'G_GNUC_DEPRECATED') + + self.guard = opts.get('--guard', None) + + def h(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__header.append(s) + + def b(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__body.append(s) + + def d(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__docs.append(s) + + def get_iface_quark(self): + assert self.iface_dbus is not None + assert self.iface_uc is not None + if self.iface_quark_prefix is None: + return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus + else: + return '%s_%s' % (self.iface_quark_prefix, self.iface_uc) + + def do_signal(self, iface, signal): + iface_lc = iface.lower() + + member = signal.getAttribute('name') + member_lc = signal.getAttribute('tp:name-for-bindings') + if member != member_lc.replace('_', ''): + raise AssertionError('Signal %s tp:name-for-bindings (%s) does ' + 'not match' % (member, member_lc)) + member_lc = member_lc.lower() + member_uc = member_lc.upper() + + arg_count = 0 + args = [] + out_args = [] + + for arg in signal.getElementsByTagName('arg'): + name = arg.getAttribute('name') + type = arg.getAttribute('type') + tp_type = arg.getAttribute('tp:type') + + if not name: + name = 'arg%u' % arg_count + arg_count += 1 + else: + name = 'arg_%s' % name + + info = type_to_gtype(type) + args.append((name, info, tp_type, arg)) + + callback_name = ('%s_%s_signal_callback_%s' + % (self.prefix_lc, iface_lc, member_lc)) + collect_name = ('_%s_%s_collect_args_of_%s' + % (self.prefix_lc, iface_lc, member_lc)) + invoke_name = ('_%s_%s_invoke_callback_for_%s' + % (self.prefix_lc, iface_lc, member_lc)) + + # Example: + # + # typedef void (*tp_cli_connection_signal_callback_new_channel) + # (TpConnection *proxy, const gchar *arg_object_path, + # const gchar *arg_channel_type, guint arg_handle_type, + # guint arg_handle, gboolean arg_suppress_handler, + # gpointer user_data, GObject *weak_object); + + self.d('/**') + self.d(' * %s:' % callback_name) + self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()' + % (self.prefix_lc, iface_lc, member_lc)) + self.d(' * was called') + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + docs = get_docstring(elt) or '(Undocumented)' + + if ctype == 'guint ' and tp_type != '': + docs += ' (#%s)' % ('Tp' + tp_type.replace('_', '')) + + self.d(' * @%s: %s' % (name, xml_escape(docs))) + + self.d(' * @user_data: User-supplied data') + self.d(' * @weak_object: User-supplied weakly referenced object') + self.d(' *') + self.d(' * Represents the signature of a callback for the signal %s.' + % member) + self.d(' */') + self.d('') + + self.h('typedef void (*%s) (%sproxy,' + % (callback_name, self.proxy_cls)) + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + + self.h(' gpointer user_data, GObject *weak_object);') + + if args: + self.b('static void') + self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name) + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s%s%s,' % (const, ctype, name)) + + self.b(' TpProxySignalConnection *sc)') + self.b('{') + self.b(' GValueArray *args = g_value_array_new (%d);' % len(args)) + self.b(' GValue blank = { 0 };') + self.b(' guint i;') + self.b('') + self.b(' g_value_init (&blank, G_TYPE_INT);') + self.b('') + self.b(' for (i = 0; i < %d; i++)' % len(args)) + self.b(' g_value_array_append (args, &blank);') + self.b('') + + for i, arg in enumerate(args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' g_value_unset (args->values + %d);' % i) + self.b(' g_value_init (args->values + %d, %s);' % (i, gtype)) + + if gtype == 'G_TYPE_STRING': + self.b(' g_value_set_string (args->values + %d, %s);' + % (i, name)) + elif marshaller == 'BOXED': + self.b(' g_value_set_boxed (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_set_uchar (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_set_boolean (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_set_uint (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_set_uint64 (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_set_double (args->values + %d, %s);' + % (i, name)) + else: + assert False, ("Don't know how to put %s in a GValue" + % gtype) + self.b('') + + self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);') + self.b('}') + + self.b('static void') + self.b('%s (TpProxy *tpproxy,' % invoke_name) + self.b(' GError *error G_GNUC_UNUSED,') + self.b(' GValueArray *args,') + self.b(' GCallback generic_callback,') + self.b(' gpointer user_data,') + self.b(' GObject *weak_object)') + self.b('{') + self.b(' %s callback =' % callback_name) + self.b(' (%s) generic_callback;' % callback_name) + self.b('') + self.b(' if (callback != NULL)') + self.b(' callback (g_object_ref (tpproxy),') + + # FIXME: factor out into a function + for i, arg in enumerate(args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if marshaller == 'BOXED': + self.b(' g_value_get_boxed (args->values + %d),' % i) + elif gtype == 'G_TYPE_STRING': + self.b(' g_value_get_string (args->values + %d),' % i) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_get_uchar (args->values + %d),' % i) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_get_boolean (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_get_uint (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_get_int (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_get_uint64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_get_int64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_get_double (args->values + %d),' % i) + else: + assert False, "Don't know how to get %s from a GValue" % gtype + + self.b(' user_data,') + self.b(' weak_object);') + self.b('') + + if len(args) > 0: + self.b(' g_value_array_free (args);') + else: + self.b(' if (args != NULL)') + self.b(' g_value_array_free (args);') + self.b('') + + self.b(' g_object_unref (tpproxy);') + self.b('}') + + # Example: + # + # TpProxySignalConnection * + # tp_cli_connection_connect_to_new_channel + # (TpConnection *proxy, + # tp_cli_connection_signal_callback_new_channel callback, + # gpointer user_data, + # GDestroyNotify destroy); + # + # destroy is invoked when the signal becomes disconnected. This + # is either because the signal has been disconnected explicitly + # by the user, because the TpProxy has become invalid and + # emitted the 'invalidated' signal, or because the weakly referenced + # object has gone away. + + self.d('/**') + self.d(' * %s_%s_connect_to_%s:' + % (self.prefix_lc, iface_lc, member_lc)) + self.d(' * @proxy: %s' % self.proxy_doc) + self.d(' * @callback: Callback to be called when the signal is') + self.d(' * received') + self.d(' * @user_data: User-supplied data for the callback') + self.d(' * @destroy: Destructor for the user-supplied data, which') + self.d(' * will be called when this signal is disconnected, or') + self.d(' * before this function returns %NULL') + self.d(' * @weak_object: A #GObject which will be weakly referenced; ') + self.d(' * if it is destroyed, this callback will automatically be') + self.d(' * disconnected') + self.d(' * @error: If not %NULL, used to raise an error if %NULL is') + self.d(' * returned') + self.d(' *') + self.d(' * Connect a handler to the signal %s.' % member) + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)')) + self.d(' *') + self.d(' * Returns: a #TpProxySignalConnection containing all of the') + self.d(' * above, which can be used to disconnect the signal; or') + self.d(' * %NULL if the proxy does not have the desired interface') + self.d(' * or has become invalid.') + self.d(' */') + self.d('') + + self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.h(' %s callback,' % callback_name) + self.h(' gpointer user_data,') + self.h(' GDestroyNotify destroy,') + self.h(' GObject *weak_object,') + self.h(' GError **error);') + self.h('') + + self.b('TpProxySignalConnection *') + self.b('%s_%s_connect_to_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.b(' %s callback,' % callback_name) + self.b(' gpointer user_data,') + self.b(' GDestroyNotify destroy,') + self.b(' GObject *weak_object,') + self.b(' GError **error)') + self.b('{') + self.b(' GType expected_types[%d] = {' % (len(args) + 1)) + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' %s,' % gtype) + + self.b(' G_TYPE_INVALID };') + self.b('') + self.b(' g_return_val_if_fail (%s (proxy), NULL);' + % self.proxy_assert) + self.b(' g_return_val_if_fail (callback != NULL, NULL);') + self.b('') + self.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,') + self.b(' %s, \"%s\",' % (self.get_iface_quark(), member)) + self.b(' expected_types,') + + if args: + self.b(' G_CALLBACK (%s),' % collect_name) + else: + self.b(' NULL, /* no args => no collector function */') + + self.b(' %s,' % invoke_name) + self.b(' G_CALLBACK (callback), user_data, destroy,') + self.b(' weak_object, error);') + self.b('}') + self.b('') + + def do_method(self, iface, method): + iface_lc = iface.lower() + + member = method.getAttribute('name') + member_lc = method.getAttribute('tp:name-for-bindings') + if member != member_lc.replace('_', ''): + raise AssertionError('Method %s tp:name-for-bindings (%s) does ' + 'not match' % (member, member_lc)) + member_lc = member_lc.lower() + member_uc = member_lc.upper() + + in_count = 0 + ret_count = 0 + in_args = [] + out_args = [] + + for arg in method.getElementsByTagName('arg'): + name = arg.getAttribute('name') + direction = arg.getAttribute('direction') + type = arg.getAttribute('type') + tp_type = arg.getAttribute('tp:type') + + if direction != 'out': + if not name: + name = 'in%u' % in_count + in_count += 1 + else: + name = 'in_%s' % name + else: + if not name: + name = 'out%u' % ret_count + ret_count += 1 + else: + name = 'out_%s' % name + + info = type_to_gtype(type) + if direction != 'out': + in_args.append((name, info, tp_type, arg)) + else: + out_args.append((name, info, tp_type, arg)) + + # Async reply callback type + + # Example: + # void (*tp_cli_properties_interface_callback_for_get_properties) + # (TpProxy *proxy, + # const GPtrArray *out0, + # const GError *error, + # gpointer user_data, + # GObject *weak_object); + + self.d('/**') + self.d(' * %s_%s_callback_for_%s:' + % (self.prefix_lc, iface_lc, member_lc)) + self.d(' * @proxy: the proxy on which the call was made') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + docs = xml_escape(get_docstring(elt) or '(Undocumented)') + + if ctype == 'guint ' and tp_type != '': + docs += ' (#%s)' % ('Tp' + tp_type.replace('_', '')) + + self.d(' * @%s: Used to return an \'out\' argument if @error is ' + '%%NULL: %s' + % (name, docs)) + + self.d(' * @error: %NULL on success, or an error on failure') + self.d(' * @user_data: user-supplied data') + self.d(' * @weak_object: user-supplied object') + self.d(' *') + self.d(' * Signature of the callback called when a %s method call' + % member) + self.d(' * succeeds or fails.') + + deprecated = method.getElementsByTagName('tp:deprecated') + if deprecated: + d = deprecated[0] + self.d(' *') + self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d))) + + self.d(' */') + self.d('') + + callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc, + member_lc) + + self.h('typedef void (*%s) (%sproxy,' + % (callback_name, self.proxy_cls)) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + + self.h(' const GError *error, gpointer user_data,') + self.h(' GObject *weak_object);') + self.h('') + + # Async callback implementation + + invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc, + iface_lc, + member_lc) + + collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc, + iface_lc, + member_lc) + + # The callback called by dbus-glib; this ends the call and collects + # the results into a GValueArray. + self.b('static void') + self.b('%s (DBusGProxy *proxy,' % collect_callback) + self.b(' DBusGProxyCall *call,') + self.b(' gpointer user_data)') + self.b('{') + self.b(' GError *error = NULL;') + + if len(out_args) > 0: + self.b(' GValueArray *args;') + self.b(' GValue blank = { 0 };') + self.b(' guint i;') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + # "We handle variants specially; the caller is expected to + # have already allocated storage for them". Thanks, + # dbus-glib... + if gtype == 'G_TYPE_VALUE': + self.b(' GValue *%s = g_new0 (GValue, 1);' % name) + else: + self.b(' %s%s;' % (ctype, name)) + + self.b('') + self.b(' dbus_g_proxy_end_call (proxy, call, &error,') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if gtype == 'G_TYPE_VALUE': + self.b(' %s, %s,' % (gtype, name)) + else: + self.b(' %s, &%s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID);') + + if len(out_args) == 0: + self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,' + 'NULL);') + else: + self.b('') + self.b(' if (error != NULL)') + self.b(' {') + self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,') + self.b(' NULL);') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + if gtype == 'G_TYPE_VALUE': + self.b(' g_free (%s);' % name) + + self.b(' return;') + self.b(' }') + self.b('') + self.b(' args = g_value_array_new (%d);' % len(out_args)) + self.b(' g_value_init (&blank, G_TYPE_INT);') + self.b('') + self.b(' for (i = 0; i < %d; i++)' % len(out_args)) + self.b(' g_value_array_append (args, &blank);') + + for i, arg in enumerate(out_args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b('') + self.b(' g_value_unset (args->values + %d);' % i) + self.b(' g_value_init (args->values + %d, %s);' % (i, gtype)) + + if gtype == 'G_TYPE_STRING': + self.b(' g_value_take_string (args->values + %d, %s);' + % (i, name)) + elif marshaller == 'BOXED': + self.b(' g_value_take_boxed (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_set_uchar (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_set_boolean (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_set_uint (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_set_uint (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_set_double (args->values + %d, %s);' + % (i, name)) + else: + assert False, ("Don't know how to put %s in a GValue" + % gtype) + + self.b(' tp_proxy_pending_call_v0_take_results (user_data, ' + 'NULL, args);') + + self.b('}') + + self.b('static void') + self.b('%s (TpProxy *self,' % invoke_callback) + self.b(' GError *error,') + self.b(' GValueArray *args,') + self.b(' GCallback generic_callback,') + self.b(' gpointer user_data,') + self.b(' GObject *weak_object)') + self.b('{') + self.b(' %s callback = (%s) generic_callback;' + % (callback_name, callback_name)) + self.b('') + self.b(' if (error != NULL)') + self.b(' {') + self.b(' callback ((%s) self,' % self.proxy_cls) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if marshaller == 'BOXED' or pointer: + self.b(' NULL,') + elif gtype == 'G_TYPE_DOUBLE': + self.b(' 0.0,') + else: + self.b(' 0,') + + self.b(' error, user_data, weak_object);') + self.b(' g_error_free (error);') + self.b(' return;') + self.b(' }') + + self.b(' callback ((%s) self,' % self.proxy_cls) + + # FIXME: factor out into a function + for i, arg in enumerate(out_args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if marshaller == 'BOXED': + self.b(' g_value_get_boxed (args->values + %d),' % i) + elif gtype == 'G_TYPE_STRING': + self.b(' g_value_get_string (args->values + %d),' % i) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_get_uchar (args->values + %d),' % i) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_get_boolean (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_get_uint (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_get_int (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_get_uint64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_get_int64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_get_double (args->values + %d),' % i) + else: + assert False, "Don't know how to get %s from a GValue" % gtype + + self.b(' error, user_data, weak_object);') + self.b('') + + if len(out_args) > 0: + self.b(' g_value_array_free (args);') + else: + self.b(' if (args != NULL)') + self.b(' g_value_array_free (args);') + + self.b('}') + self.b('') + + # Async stub + + # Example: + # TpProxyPendingCall * + # tp_cli_properties_interface_call_get_properties + # (gpointer proxy, + # gint timeout_ms, + # const GArray *in_properties, + # tp_cli_properties_interface_callback_for_get_properties callback, + # gpointer user_data, + # GDestroyNotify *destructor); + + self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.h(' gint timeout_ms,') + + self.d('/**') + self.d(' * %s_%s_call_%s:' + % (self.prefix_lc, iface_lc, member_lc)) + self.d(' * @proxy: the #TpProxy') + self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the') + self.d(' * default') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + docs = xml_escape(get_docstring(elt) or '(Undocumented)') + + if ctype == 'guint ' and tp_type != '': + docs += ' (#%s)' % ('Tp' + tp_type.replace('_', '')) + + self.d(' * @%s: Used to pass an \'in\' argument: %s' + % (name, docs)) + + self.d(' * @callback: called when the method call succeeds or fails;') + self.d(' * may be %NULL to make a "fire and forget" call with no ') + self.d(' * reply tracking') + self.d(' * @user_data: user-supplied data passed to the callback;') + self.d(' * must be %NULL if @callback is %NULL') + self.d(' * @destroy: called with the user_data as argument, after the') + self.d(' * call has succeeded, failed or been cancelled;') + self.d(' * must be %NULL if @callback is %NULL') + self.d(' * @weak_object: If not %NULL, a #GObject which will be ') + self.d(' * weakly referenced; if it is destroyed, this call ') + self.d(' * will automatically be cancelled. Must be %NULL if ') + self.d(' * @callback is %NULL') + self.d(' *') + self.d(' * Start a %s method call.' % member) + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) + self.d(' *') + self.d(' * Returns: a #TpProxyPendingCall representing the call in') + self.d(' * progress. It is borrowed from the object, and will become') + self.d(' * invalid when the callback is called, the call is') + self.d(' * cancelled or the #TpProxy becomes invalid.') + + deprecated = method.getElementsByTagName('tp:deprecated') + if deprecated: + d = deprecated[0] + self.d(' *') + self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d))) + + self.d(' */') + self.d('') + + self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.b(' gint timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + self.b(' %s%s%s,' % (const, ctype, name)) + + self.h(' %s callback,' % callback_name) + self.h(' gpointer user_data,') + self.h(' GDestroyNotify destroy,') + self.h(' GObject *weak_object);') + self.h('') + + self.b(' %s callback,' % callback_name) + self.b(' gpointer user_data,') + self.b(' GDestroyNotify destroy,') + self.b(' GObject *weak_object)') + self.b('{') + self.b(' GError *error = NULL;') + self.b(' GQuark interface = %s;' % self.get_iface_quark()) + self.b(' DBusGProxy *iface;') + self.b('') + self.b(' g_return_val_if_fail (%s (proxy), NULL);' + % self.proxy_assert) + self.b(' g_return_val_if_fail (callback != NULL || ' + 'user_data == NULL, NULL);') + self.b(' g_return_val_if_fail (callback != NULL || ' + 'destroy == NULL, NULL);') + self.b(' g_return_val_if_fail (callback != NULL || ' + 'weak_object == NULL, NULL);') + self.b('') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') + self.b(' iface = tp_proxy_borrow_interface_by_id (') + self.b(' (TpProxy *) proxy,') + self.b(' interface, &error);') + self.b(' G_GNUC_END_IGNORE_DEPRECATIONS') + self.b('') + self.b(' if (iface == NULL)') + self.b(' {') + self.b(' if (callback != NULL)') + self.b(' callback (proxy,') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if pointer: + self.b(' NULL,') + else: + self.b(' 0,') + + self.b(' error, user_data, weak_object);') + self.b('') + self.b(' if (destroy != NULL)') + self.b(' destroy (user_data);') + self.b('') + self.b(' g_error_free (error);') + self.b(' return NULL;') + self.b(' }') + self.b('') + self.b(' if (callback == NULL)') + self.b(' {') + self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member) + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID);') + self.b(' return NULL;') + self.b(' }') + self.b(' else') + self.b(' {') + self.b(' TpProxyPendingCall *data;') + self.b('') + self.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,') + self.b(' interface, "%s", iface,' % member) + self.b(' %s,' % invoke_callback) + self.b(' G_CALLBACK (callback), user_data, destroy,') + self.b(' weak_object, FALSE);') + self.b(' tp_proxy_pending_call_v0_take_pending_call (data,') + self.b(' dbus_g_proxy_begin_call_with_timeout (iface,') + self.b(' "%s",' % member) + self.b(' %s,' % collect_callback) + self.b(' data,') + self.b(' tp_proxy_pending_call_v0_completed,') + self.b(' timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID));') + self.b('') + self.b(' return data;') + self.b(' }') + self.b('}') + self.b('') + + self.do_method_reentrant(method, iface_lc, member, member_lc, + in_args, out_args, collect_callback) + + # leave a gap for the end of the method + self.d('') + self.b('') + self.h('') + + def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args, + out_args, collect_callback): + # Reentrant blocking calls + # Example: + # gboolean tp_cli_properties_interface_run_get_properties + # (gpointer proxy, + # gint timeout_ms, + # const GArray *in_properties, + # GPtrArray **out0, + # GError **error, + # GMainLoop **loop); + + run_method_name = '%s_%s_run_%s' % (self.prefix_lc, iface_lc, member_lc) + if run_method_name not in self.reentrant_symbols: + return + + self.b('typedef struct {') + self.b(' GMainLoop *loop;') + self.b(' GError **error;') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' %s*%s;' % (ctype, name)) + + self.b(' unsigned success:1;') + self.b(' unsigned completed:1;') + self.b('} _%s_%s_run_state_%s;' + % (self.prefix_lc, iface_lc, member_lc)) + + reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc, + iface_lc, + member_lc) + + self.b('static void') + self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke) + self.b(' GError *error,') + self.b(' GValueArray *args,') + self.b(' GCallback unused G_GNUC_UNUSED,') + self.b(' gpointer user_data G_GNUC_UNUSED,') + self.b(' GObject *unused2 G_GNUC_UNUSED)') + self.b('{') + self.b(' _%s_%s_run_state_%s *state = user_data;' + % (self.prefix_lc, iface_lc, member_lc)) + self.b('') + self.b(' state->success = (error == NULL);') + self.b(' state->completed = TRUE;') + self.b(' g_main_loop_quit (state->loop);') + self.b('') + self.b(' if (error != NULL)') + self.b(' {') + self.b(' if (state->error != NULL)') + self.b(' *state->error = error;') + self.b(' else') + self.b(' g_error_free (error);') + self.b('') + self.b(' return;') + self.b(' }') + self.b('') + + for i, arg in enumerate(out_args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' if (state->%s != NULL)' % name) + if marshaller == 'BOXED': + self.b(' *state->%s = g_value_dup_boxed (' + 'args->values + %d);' % (name, i)) + elif marshaller == 'STRING': + self.b(' *state->%s = g_value_dup_string ' + '(args->values + %d);' % (name, i)) + elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT', + 'INT64', 'UINT64', 'DOUBLE'): + self.b(' *state->%s = g_value_get_%s (args->values + %d);' + % (name, marshaller.lower(), i)) + else: + assert False, "Don't know how to copy %s" % gtype + + self.b('') + + if len(out_args) > 0: + self.b(' g_value_array_free (args);') + else: + self.b(' if (args != NULL)') + self.b(' g_value_array_free (args);') + + self.b('}') + self.b('') + + if self.deprecate_reentrant: + self.h('#ifndef %s' % self.deprecate_reentrant) + + self.h('gboolean %s (%sproxy,' + % (run_method_name, self.proxy_arg)) + self.h(' gint timeout_ms,') + + self.d('/**') + self.d(' * %s:' % run_method_name) + self.d(' * @proxy: %s' % self.proxy_doc) + self.d(' * @timeout_ms: Timeout in milliseconds, or -1 for default') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + docs = xml_escape(get_docstring(elt) or '(Undocumented)') + + if ctype == 'guint ' and tp_type != '': + docs += ' (#%s)' % ('Tp' + tp_type.replace('_', '')) + + self.d(' * @%s: Used to pass an \'in\' argument: %s' + % (name, docs)) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.d(' * @%s: Used to return an \'out\' argument if %%TRUE is ' + 'returned: %s' + % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) + + self.d(' * @error: If not %NULL, used to return errors if %FALSE ') + self.d(' * is returned') + self.d(' * @loop: If not %NULL, set before re-entering ') + self.d(' * the main loop, to point to a #GMainLoop ') + self.d(' * which can be used to cancel this call with ') + self.d(' * g_main_loop_quit(), causing a return of ') + self.d(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED') + self.d(' *') + self.d(' * Call the method %s and run the main loop' % member) + self.d(' * until it returns. Before calling this method, you must') + self.d(' * add a reference to any borrowed objects you need to keep,') + self.d(' * and generally ensure that everything is in a consistent') + self.d(' * state.') + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) + self.d(' *') + self.d(' * Returns: TRUE on success, FALSE and sets @error on error') + + deprecated = method.getElementsByTagName('tp:deprecated') + if deprecated: + d = deprecated[0] + self.d(' *') + self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d))) + + self.d(' */') + self.d('') + + self.b('gboolean\n%s (%sproxy,' + % (run_method_name, self.proxy_arg)) + self.b(' gint timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + self.b(' %s%s%s,' % (const, ctype, name)) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.h(' %s*%s,' % (ctype, name)) + self.b(' %s*%s,' % (ctype, name)) + + self.h(' GError **error,') + + if self.deprecate_reentrant: + self.h(' GMainLoop **loop) %s;' % self.deprecation_attribute) + self.h('#endif /* not %s */' % self.deprecate_reentrant) + else: + self.h(' GMainLoop **loop);') + + self.h('') + + self.b(' GError **error,') + self.b(' GMainLoop **loop)') + self.b('{') + self.b(' DBusGProxy *iface;') + self.b(' GQuark interface = %s;' % self.get_iface_quark()) + self.b(' TpProxyPendingCall *pc;') + self.b(' _%s_%s_run_state_%s state = {' + % (self.prefix_lc, iface_lc, member_lc)) + self.b(' NULL /* loop */, error,') + + for arg in out_args: + name, info, tp_type, elt = arg + + self.b(' %s,' % name) + + self.b(' FALSE /* completed */, FALSE /* success */ };') + self.b('') + self.b(' g_return_val_if_fail (%s (proxy), FALSE);' + % self.proxy_assert) + self.b('') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') + self.b(' iface = tp_proxy_borrow_interface_by_id') + self.b(' ((TpProxy *) proxy, interface, error);') + self.b(' G_GNUC_END_IGNORE_DEPRECATIONS') + self.b('') + self.b(' if (iface == NULL)') + self.b(' return FALSE;') + self.b('') + self.b(' state.loop = g_main_loop_new (NULL, FALSE);') + self.b('') + self.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,') + self.b(' interface, "%s", iface,' % member) + self.b(' %s,' % reentrant_invoke) + self.b(' NULL, &state, NULL, NULL, TRUE);') + self.b('') + self.b(' if (loop != NULL)') + self.b(' *loop = state.loop;') + self.b('') + self.b(' tp_proxy_pending_call_v0_take_pending_call (pc,') + self.b(' dbus_g_proxy_begin_call_with_timeout (iface,') + self.b(' "%s",' % member) + self.b(' %s,' % collect_callback) + self.b(' pc,') + self.b(' tp_proxy_pending_call_v0_completed,') + self.b(' timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID));') + self.b('') + self.b(' if (!state.completed)') + self.b(' g_main_loop_run (state.loop);') + self.b('') + self.b(' if (!state.completed)') + self.b(' tp_proxy_pending_call_cancel (pc);') + self.b('') + self.b(' if (loop != NULL)') + self.b(' *loop = NULL;') + self.b('') + self.b(' g_main_loop_unref (state.loop);') + self.b('') + self.b(' return state.success;') + self.b('}') + self.b('') + + def do_signal_add(self, signal): + marshaller_items = [] + gtypes = [] + + for i in signal.getElementsByTagName('arg'): + name = i.getAttribute('name') + type = i.getAttribute('type') + info = type_to_gtype(type) + # type, GType, STRING, is a pointer + gtypes.append(info[1]) + + self.b(' dbus_g_proxy_add_signal (proxy, "%s",' + % signal.getAttribute('name')) + for gtype in gtypes: + self.b(' %s,' % gtype) + self.b(' G_TYPE_INVALID);') + + def do_interface(self, node): + ifaces = node.getElementsByTagName('interface') + assert len(ifaces) == 1 + iface = ifaces[0] + name = node.getAttribute('name').replace('/', '') + + self.iface = name + self.iface_lc = name.lower() + self.iface_uc = name.upper() + self.iface_mc = name.replace('_', '') + self.iface_dbus = iface.getAttribute('name') + + signals = node.getElementsByTagName('signal') + methods = node.getElementsByTagName('method') + + if signals: + self.b('static inline void') + self.b('%s_add_signals_for_%s (DBusGProxy *proxy)' + % (self.prefix_lc, name.lower())) + self.b('{') + + if self.tp_proxy_api >= (0, 7, 6): + self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding ' + '(proxy))') + self.b(' return;') + + for signal in signals: + self.do_signal_add(signal) + + self.b('}') + self.b('') + self.b('') + + for signal in signals: + self.do_signal(name, signal) + + for method in methods: + self.do_method(name, method) + + self.iface_dbus = None + + def __call__(self): + + if self.guard is not None: + self.h('#ifndef %s' % self.guard) + self.h('#define %s' % self.guard) + self.h('') + + self.h('G_BEGIN_DECLS') + self.h('') + + self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get') + self.b(' * confused by seeing function definitions, so mark it as: */') + self.b('/*<private_header>*/') + self.b('') + + nodes = self.dom.getElementsByTagName('node') + nodes.sort(cmp_by_name) + + for node in nodes: + self.do_interface(node) + + if self.group is not None: + + self.b('/*') + self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group)) + self.b(' * @self: the #TpProxy') + self.b(' * @quark: a quark whose string value is the interface') + self.b(' * name whose signals should be added') + self.b(' * @proxy: the D-Bus proxy to which to add the signals') + self.b(' * @unused: not used for anything') + self.b(' *') + self.b(' * Tell dbus-glib that @proxy has the signatures of all') + self.b(' * signals on the given interface, if it\'s one we') + self.b(' * support.') + self.b(' *') + self.b(' * This function should be used as a signal handler for') + self.b(' * #TpProxy::interface-added.') + self.b(' */') + self.b('static void') + self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,' + % (self.prefix_lc, self.group)) + self.b(' guint quark,') + self.b(' DBusGProxy *proxy,') + self.b(' gpointer unused G_GNUC_UNUSED)') + + self.b('{') + + for node in nodes: + iface = node.getElementsByTagName('interface')[0] + self.iface_dbus = iface.getAttribute('name') + signals = node.getElementsByTagName('signal') + if not signals: + continue + name = node.getAttribute('name').replace('/', '').lower() + self.iface_uc = name.upper() + self.b(' if (quark == %s)' % self.get_iface_quark()) + self.b(' %s_add_signals_for_%s (proxy);' + % (self.prefix_lc, name)) + + self.b('}') + self.b('') + + self.h('G_END_DECLS') + self.h('') + + if self.guard is not None: + self.h('#endif /* defined (%s) */' % self.guard) + self.h('') + + file_set_contents(self.basename + '.h', '\n'.join(self.__header)) + file_set_contents(self.basename + '-body.h', '\n'.join(self.__body)) + file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs)) + +def types_to_gtypes(types): + return [type_to_gtype(t)[1] for t in types] + + +if __name__ == '__main__': + options, argv = gnu_getopt(sys.argv[1:], '', + ['group=', 'subclass=', 'subclass-assert=', + 'iface-quark-prefix=', 'tp-proxy-api=', + 'generate-reentrant=', 'deprecate-reentrant=', + 'deprecation-attribute=', 'guard=']) + + opts = {} + + for option, value in options: + opts[option] = value + + dom = xml.dom.minidom.parse(argv[0]) + + Generator(dom, argv[1], argv[2], opts)() diff --git a/tools/glib-client-marshaller-gen.py b/tools/glib-client-marshaller-gen.py new file mode 100644 index 000000000..cb27d638a --- /dev/null +++ b/tools/glib-client-marshaller-gen.py @@ -0,0 +1,60 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom +from string import ascii_letters, digits + + +from libglibcodegen import signal_to_marshal_name + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +class Generator(object): + + def __init__(self, dom, prefix): + self.dom = dom + self.marshallers = {} + self.prefix = prefix + + def do_signal(self, signal): + marshaller = signal_to_marshal_name(signal, self.prefix) + + assert '__' in marshaller + rhs = marshaller.split('__', 1)[1].split('_') + + self.marshallers[marshaller] = rhs + + def __call__(self): + signals = self.dom.getElementsByTagName('signal') + + for signal in signals: + self.do_signal(signal) + + print 'void' + print '%s_register_dbus_glib_marshallers (void)' % self.prefix + print '{' + + all = self.marshallers.keys() + all.sort() + for marshaller in all: + rhs = self.marshallers[marshaller] + + print ' dbus_g_object_register_marshaller (' + print ' g_cclosure_marshal_generic,' + print ' G_TYPE_NONE, /* return */' + for type in rhs: + print ' G_TYPE_%s,' % type.replace('VOID', 'NONE') + print ' G_TYPE_INVALID);' + + print '}' + + +def types_to_gtypes(types): + return [type_to_gtype(t)[1] for t in types] + +if __name__ == '__main__': + argv = sys.argv[1:] + dom = xml.dom.minidom.parse(argv[0]) + + Generator(dom, argv[1])() diff --git a/tools/glib-errors-check-gen.py b/tools/glib-errors-check-gen.py new file mode 100644 index 000000000..553fc9caf --- /dev/null +++ b/tools/glib-errors-check-gen.py @@ -0,0 +1,58 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom + +from libglibcodegen import NS_TP, get_docstring, get_descendant_text + +class Generator(object): + def __init__(self, dom): + self.dom = dom + self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] + + def __call__(self): + + print '{' + print ' GEnumClass *klass;' + print ' GEnumValue *value_by_name;' + print ' GEnumValue *value_by_nick;' + print '' + print ' g_type_init ();' + print ' klass = g_type_class_ref (TP_TYPE_ERROR);' + + for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): + ns = error.parentNode.getAttribute('namespace') + nick = error.getAttribute('name').replace(' ', '') + enum = ('TP_ERROR_' + + error.getAttribute('name').replace(' ', '_').replace('.', '_').upper()) + s = ('TP_ERROR_STR_' + + error.getAttribute('name').replace(' ', '_').replace('.', '_').upper()) + + print '' + print ' /* %s.%s */' % (ns, nick) + print (' value_by_name = g_enum_get_value_by_name (klass, "%s");' + % enum) + print (' value_by_nick = g_enum_get_value_by_nick (klass, "%s");' + % nick) + print (' g_assert (value_by_name != NULL);') + print (' g_assert (value_by_nick != NULL);') + print (' g_assert_cmpint (value_by_name->value, ==, %s);' + % enum) + print (' g_assert_cmpint (value_by_nick->value, ==, %s);' + % enum) + print (' g_assert_cmpstr (value_by_name->value_name, ==, "%s");' + % enum) + print (' g_assert_cmpstr (value_by_nick->value_name, ==, "%s");' + % enum) + print (' g_assert_cmpstr (value_by_name->value_nick, ==, "%s");' + % nick) + print (' g_assert_cmpstr (value_by_nick->value_nick, ==, "%s");' + % nick) + print (' g_assert_cmpstr (%s, ==, TP_ERROR_PREFIX ".%s");' + % (s, nick)) + + print '}' + +if __name__ == '__main__': + argv = sys.argv[1:] + Generator(xml.dom.minidom.parse(argv[0]))() diff --git a/tools/glib-errors-str-gen.py b/tools/glib-errors-str-gen.py new file mode 100644 index 000000000..b2cf520bd --- /dev/null +++ b/tools/glib-errors-str-gen.py @@ -0,0 +1,83 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom + +from libtpcodegen import file_set_contents +from libglibcodegen import NS_TP, get_docstring, xml_escape + +class Generator(object): + def __init__(self, dom, basename): + self.dom = dom + self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] + self.basename = basename + + self.__header = [] + self.__body = [] + self.__docs = [] + + def h(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__header.append(s) + + def b(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__body.append(s) + + def d(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__docs.append(s) + + def __call__(self): + errors = self.errors.getElementsByTagNameNS(NS_TP, 'error') + + self.b('#include <telepathy-glib/errors.h>') + self.b('') + self.b('const gchar *') + self.b('tp_error_get_dbus_name (TpError error)') + self.b('{') + self.b(' switch (error)') + self.b(' {') + + for error in errors: + ns = error.parentNode.getAttribute('namespace') + nick = error.getAttribute('name').replace(' ', '') + uc_nick = error.getAttribute('name').replace(' ', '_').replace('.', '_').upper() + name = 'TP_ERROR_STR_' + uc_nick + error_name = '%s.%s' % (ns, nick) + + self.d('/**') + self.d(' * %s:' % name) + self.d(' *') + self.d(' * The D-Bus error name %s' % error_name) + self.d(' *') + self.d(' * %s' % xml_escape(get_docstring(error))) + self.d(' */') + self.d('') + + self.h('#define %s "%s"' % (name, error_name)) + + self.b(' case TP_ERROR_%s:' % uc_nick) + self.b(' return %s;' % name) + + self.b(' default:') + self.b(' g_return_val_if_reached (NULL);') + self.b(' }') + self.b('}') + + # make both files end with a newline + self.h('') + self.b('') + + file_set_contents(self.basename + '.h', '\n'.join(self.__header)) + file_set_contents(self.basename + '.c', '\n'.join(self.__body)) + file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs)) + +if __name__ == '__main__': + argv = sys.argv[1:] + basename = argv[0] + + Generator(xml.dom.minidom.parse(argv[1]), basename)() diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py index e277b91f4..6fec0d3c4 100644 --- a/tools/glib-ginterface-gen.py +++ b/tools/glib-ginterface-gen.py @@ -26,9 +26,9 @@ import sys import os.path import xml.dom.minidom +from libtpcodegen import file_set_contents from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ - NS_TP, dbus_gutils_wincaps_to_uscore, \ - signal_to_marshal_name, method_to_glue_marshal_name + NS_TP, dbus_gutils_wincaps_to_uscore NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" @@ -421,8 +421,7 @@ class Generator(object): 'not match' % (method.getAttribute('name'), lc_name)) lc_name = lc_name.lower() - marshaller = method_to_glue_marshal_name(method, - self.signal_marshal_prefix) + marshaller = 'g_cclosure_marshal_generic' wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset)) @@ -717,8 +716,7 @@ class Generator(object): in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,') in_base_init.append(' 0,') in_base_init.append(' NULL, NULL,') - in_base_init.append(' %s,' - % signal_to_marshal_name(signal, self.signal_marshal_prefix)) + in_base_init.append(' g_cclosure_marshal_generic,') in_base_init.append(' G_TYPE_NONE,') tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args] in_base_init.append(' %s);' % ',\n '.join(tmp)) @@ -740,8 +738,9 @@ class Generator(object): self.h('#include <glib-object.h>') self.h('#include <dbus/dbus-glib.h>') - if self.have_properties(nodes): - self.h('#include <telepathy-glib/dbus-properties-mixin.h>') + for header in self.headers: + self.h('#include %s' % header) + self.h('') self.h('') self.h('G_BEGIN_DECLS') @@ -749,9 +748,6 @@ class Generator(object): self.b('#include "%s.h"' % self.basename) self.b('') - for header in self.headers: - self.b('#include %s' % header) - self.b('') for node in nodes: self.do_node(node) @@ -765,10 +761,9 @@ class Generator(object): self.h('') self.b('') - open(self.basename + '.h', 'w').write('\n'.join(self.__header)) - open(self.basename + '.c', 'w').write('\n'.join(self.__body)) - open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs)) - + file_set_contents(self.basename + '.h', '\n'.join(self.__header)) + file_set_contents(self.basename + '.c', '\n'.join(self.__body)) + file_set_contents(self.basename + '-gtk-doc.h', '\n'.join(self.__docs)) def cmdline_error(): print """\ diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py index a49c36e7f..21dfc6aa7 100644 --- a/tools/glib-gtypes-generator.py +++ b/tools/glib-gtypes-generator.py @@ -23,6 +23,7 @@ import sys import xml.dom.minidom +from libtpcodegen import file_set_contents from libglibcodegen import escape_as_identifier, \ get_docstring, \ NS_TP, \ @@ -42,15 +43,16 @@ class GTypesGenerator(object): self.PREFIX_ = self.Prefix.upper() + '_' self.prefix_ = self.Prefix.lower() + '_' - self.header = open(output + '.h', 'w') - self.body = open(output + '-body.h', 'w') - self.docs = open(output + '-gtk-doc.h', 'w') + self.header = [] + self.body = [] + self.docs = [] + self.output = output for f in (self.header, self.body, self.docs): - f.write('/* Auto-generated, do not edit.\n *\n' - ' * This file may be distributed under the same terms\n' - ' * as the specification from which it was generated.\n' - ' */\n\n') + f.append('/* Auto-generated, do not edit.\n *\n' + ' * This file may be distributed under the same terms\n' + ' * as the specification from which it was generated.\n' + ' */\n\n') # keys are e.g. 'sv', values are the key escaped self.need_mappings = {} @@ -66,13 +68,13 @@ class GTypesGenerator(object): self.need_other_arrays = {} def h(self, code): - self.header.write(code.encode("utf-8")) + self.header.append(code.encode("utf-8")) def c(self, code): - self.body.write(code.encode("utf-8")) + self.body.append(code.encode("utf-8")) def d(self, code): - self.docs.write(code.encode('utf-8')) + self.docs.append(code.encode('utf-8')) def do_mapping_header(self, mapping): members = mapping.getElementsByTagNameNS(NS_TP, 'member') @@ -89,7 +91,7 @@ class GTypesGenerator(object): docstring = get_docstring(mapping) or '(Undocumented)' - self.d('/**\n * %s:\n *\n' % name) + self.d('/**\n * %s:\n *\n' % name.strip()) self.d(' * %s\n' % xml_escape(docstring)) self.d(' *\n') self.d(' * This macro expands to a call to a function\n') @@ -290,6 +292,10 @@ class GTypesGenerator(object): self.c(' return t;\n') self.c('}\n\n') + file_set_contents(self.output + '.h', ''.join(self.header)) + file_set_contents(self.output + '-body.h', ''.join(self.body)) + file_set_contents(self.output + '-gtk-doc.h', ''.join(self.docs)) + if __name__ == '__main__': argv = sys.argv[1:] diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py index 69c721be3..410762cde 100644 --- a/tools/glib-interfaces-gen.py +++ b/tools/glib-interfaces-gen.py @@ -3,6 +3,7 @@ from sys import argv, stdout, stderr import xml.dom.minidom +from libtpcodegen import file_set_contents from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path @@ -13,25 +14,33 @@ class Generator(object): assert declfile.endswith('.h') docfile = declfile[:-2] + '-gtk-doc.h' - self.impls = open(implfile, 'w') - self.decls = open(declfile, 'w') - self.docs = open(docfile, 'w') + self.implfile = implfile + self.declfile = declfile + self.docfile = docfile + + self.impls = [] + self.decls = [] + self.docs = [] self.spec = get_by_path(dom, "spec")[0] def h(self, code): - self.decls.write(code.encode('utf-8')) + self.decls.append(code.encode('utf-8')) def c(self, code): - self.impls.write(code.encode('utf-8')) + self.impls.append(code.encode('utf-8')) def d(self, code): - self.docs.write(code.encode('utf-8')) + self.docs.append(code.encode('utf-8')) def __call__(self): for f in self.h, self.c: self.do_header(f) self.do_body() + file_set_contents(self.implfile, ''.join(self.impls)) + file_set_contents(self.declfile, ''.join(self.decls)) + file_set_contents(self.docfile, ''.join(self.docs)) + # Header def do_header(self, f): f('/* Generated from: ') @@ -49,6 +58,7 @@ class Generator(object): f(""" */ +#include <glib.h> """) # Body diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py deleted file mode 100644 index 0d02c1341..000000000 --- a/tools/glib-signals-marshal-gen.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/python - -import sys -import xml.dom.minidom -from string import ascii_letters, digits - - -from libglibcodegen import signal_to_marshal_name, method_to_glue_marshal_name - - -class Generator(object): - - def __init__(self, dom): - self.dom = dom - self.marshallers = {} - - def do_method(self, method): - marshaller = method_to_glue_marshal_name(method, 'PREFIX') - - assert '__' in marshaller - rhs = marshaller.split('__', 1)[1].split('_') - - self.marshallers[marshaller] = rhs - - def do_signal(self, signal): - marshaller = signal_to_marshal_name(signal, 'PREFIX') - - assert '__' in marshaller - rhs = marshaller.split('__', 1)[1].split('_') - - self.marshallers[marshaller] = rhs - - def __call__(self): - methods = self.dom.getElementsByTagName('method') - - for method in methods: - self.do_method(method) - - signals = self.dom.getElementsByTagName('signal') - - for signal in signals: - self.do_signal(signal) - - all = self.marshallers.keys() - all.sort() - for marshaller in all: - rhs = self.marshallers[marshaller] - if not marshaller.startswith('g_cclosure'): - print 'VOID:' + ','.join(rhs) - -if __name__ == '__main__': - argv = sys.argv[1:] - dom = xml.dom.minidom.parse(argv[0]) - - Generator(dom)() diff --git a/tools/gobject-foo.py b/tools/gobject-foo.py new file mode 100644 index 000000000..002a290ba --- /dev/null +++ b/tools/gobject-foo.py @@ -0,0 +1,90 @@ +#!/usr/bin/python + +# gobject-foo.py: generate standard GObject type macros etc. +# +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (C) 2007-2010 Collabora Ltd. <http://www.collabora.co.uk/> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +def gobject_header(head, tail, as_interface=False): + out = [] + o = out.append + + name = head + '_' + tail + MixedCase = name.replace('_', '') + lower_case = name.lower() + UPPER_CASE = name.upper() + + gtype = head.upper() + '_TYPE_' + tail.upper() + + o("typedef struct _%s %s;" % (MixedCase, MixedCase)) + + if as_interface: + o("typedef struct _%sInterface %sInterface;" % (MixedCase, MixedCase)) + else: + o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase)) + o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase)) + + o("") + o("GType %s_get_type (void);" % lower_case) + o("") + + o("#define %s \\" % gtype) + o(" (%s_get_type ())" % lower_case) + + o("#define %s(obj) \\" % UPPER_CASE) + o(" (G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, \\" % gtype) + o(" %s))" % MixedCase) + + if not as_interface: + o("#define %s_CLASS(klass) \\" % UPPER_CASE) + o(" (G_TYPE_CHECK_CLASS_CAST ((klass), %s, \\" % gtype) + o(" %sClass))" % MixedCase) + + o("#define %s_IS_%s(obj) \\" % (head.upper(), tail.upper())) + o(" (G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))" % gtype) + + if as_interface: + o("#define %s_GET_IFACE(obj) \\" % UPPER_CASE) + o(" (G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, \\" % gtype) + o(" %sInterface))" % MixedCase) + else: + o("#define %s_IS_%s_CLASS(klass) \\" % (head.upper(), tail.upper())) + o(" (G_TYPE_CHECK_CLASS_TYPE ((klass), %s))" % gtype) + + o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE) + o(" (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype) + o(" %sClass))" % MixedCase) + + return out + +if __name__ == '__main__': + import sys + from getopt import gnu_getopt + + options, argv = gnu_getopt(sys.argv[1:], '', ['interface']) + + as_interface = False + + for opt, val in options: + if opt == '--interface': + as_interface = True + + head, tail = argv + + print '\n'.join(gobject_header(head, tail, as_interface=as_interface)) diff --git a/tools/lcov.am b/tools/lcov.am index 7384f1b99..80023cb78 100644 --- a/tools/lcov.am +++ b/tools/lcov.am @@ -8,6 +8,7 @@ lcov-report: --remove @top_builddir@/lcov.info.tmp telepathy-glib-scan.c rm @top_builddir@/lcov.info.tmp $(mkdir_p) @top_builddir@/lcov.html + echo "Coming soon!" > @top_builddir@/lcov.html/index.html git_commit=`GIT_DIR=@top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\ genhtml --title "@PACKAGE_STRING@ $$git_commit" \ --output-directory @top_builddir@/lcov.html lcov.info diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py index 837ff2f74..7e9eb9a50 100644 --- a/tools/libtpcodegen.py +++ b/tools/libtpcodegen.py @@ -20,7 +20,7 @@ please make any changes there. # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +import os from string import ascii_letters, digits @@ -28,6 +28,18 @@ NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" _ASCII_ALNUM = ascii_letters + digits +def file_set_contents(filename, contents): + try: + os.remove(filename) + except OSError: + pass + try: + os.remove(filename + '.tmp') + except OSError: + pass + + open(filename + '.tmp', 'w').write(contents) + os.rename(filename + '.tmp', filename) def cmp_by_name(node1, node2): return cmp(node1.getAttributeNode("name").nodeValue, diff --git a/tools/make-version-script.py b/tools/make-version-script.py new file mode 100644 index 000000000..0d30aa323 --- /dev/null +++ b/tools/make-version-script.py @@ -0,0 +1,208 @@ +#!/usr/bin/python + +"""Construct a GNU ld or Debian dpkg version-script from a set of +RFC822-style symbol lists. + +Usage: + make-version-script.py [--symbols SYMBOLS] [--unreleased-version VER] + [--dpkg "LIBRARY.so.0 LIBRARY0 #MINVER#"] + [--dpkg-build-depends-package LIBRARY-dev] + [FILES...] + +Each FILE starts with RFC822-style headers "Version:" (the name of the +symbol version, e.g. FOO_1.2.3) and "Extends:" (either the previous +version, or "-" if this is the first version). Next there is a blank +line, then a list of C symbols one per line. + +Comments (lines starting with whitespace + "#") are allowed and ignored. + +If --symbols is given, SYMBOLS lists the symbols actually exported by +the library (one per line). If --unreleased-version is given, any symbols +in SYMBOLS but not in FILES are assigned to that version; otherwise, any +such symbols cause an error. + +If --dpkg is given, produce a Debian dpkg-gensymbols file instead of a +GNU ld version-script. The argument to --dpkg is the first line of the +resulting symbols file, and --dpkg-build-depends-package can optionally +be used to set the Build-Depends-Package field. + +This script originates in telepathy-glib <http://telepathy.freedesktop.org/> - +please send us any changes that are needed. +""" + +# Copyright (C) 2008-2010 Collabora Ltd. <http://www.collabora.co.uk/> +# Copyright (C) 2008 Nokia Corporation +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +import sys +from getopt import gnu_getopt + + +def e(format, *args): + sys.stderr.write((format + '\n') % args) + + +def main(abifiles, symbols=None, unreleased_version=None, + dpkg=False, dpkg_first_line=None, dpkg_build_depends_package=None): + + gnuld = not dpkg + symbol_set = None + + if symbols is not None: + symbol_set = open(symbols, 'r').readlines() + symbol_set = map(str.strip, symbol_set) + symbol_set = set(symbol_set) + + versioned_symbols = set() + + dpkg_symbols = [] + dpkg_versions = [] + + if dpkg: + assert dpkg_first_line is not None + print dpkg_first_line + if dpkg_build_depends_package is not None: + print "* Build-Depends-Package: %s" % dpkg_build_depends_package + + for filename in abifiles: + lines = open(filename, 'r').readlines() + + version = None + extends = None + release = None + + for i, line in enumerate(lines): + line = line.strip() + + if line.startswith('#'): + continue + elif not line: + # the transition betwen headers and symbols + cut = i + 1 + break + elif line.lower().startswith('version:'): + line = line[8:].strip() + version = line + continue + elif line.lower().startswith('extends:'): + line = line[8:].strip() + extends = line + continue + elif line.lower().startswith('release:'): + release = line[8:].strip() + continue + else: + e('Could not understand line in %s header: %s', filename, line) + raise SystemExit(1) + + else: + e('No symbols in %s', filename) + raise SystemExit(1) + + if version is None: + e('No Versions: header in %s', filename) + raise SystemExit(1) + + if extends is None: + e('No Extends: header in %s', filename) + raise SystemExit(1) + + if release is None and dpkg: + e('No Release: header in %s', filename) + raise SystemExit(1) + + if dpkg: + dpkg_versions.append('%s@%s %s' % (version, version, release)) + + lines = lines[cut:] + + if gnuld: + print "%s {" % version + print " global:" + + for symbol in lines: + symbol = symbol.strip() + + if symbol.startswith('#'): + continue + + if gnuld: + print " %s;" % symbol + elif dpkg: + dpkg_symbols.append('%s@%s %s' % (symbol, version, release)) + + if symbol in versioned_symbols: + raise AssertionError('Symbol %s is in version %s and an ' + 'earlier version' % (symbol, version)) + + versioned_symbols.add(symbol) + + if gnuld: + if extends == '-': + print " local:" + print " *;" + print "};" + else: + print "} %s;" % extends + print + + if dpkg: + dpkg_symbols.sort() + dpkg_versions.sort() + + for x in dpkg_versions: + print " %s" % x + + for x in dpkg_symbols: + print " %s" % x + + if symbol_set is not None: + missing = versioned_symbols - symbol_set + + if missing: + e('These symbols have disappeared:') + + for symbol in missing: + e(' %s', symbol) + + raise SystemExit(1) + + unreleased = symbol_set - versioned_symbols + + if unreleased: + if unreleased_version is None: + e('Unversioned symbols are not allowed in releases:') + + for symbol in unreleased: + e(' %s', symbol) + + raise SystemExit(1) + + if gnuld: + print "%s {" % unreleased_version + print " global:" + + for symbol in unreleased: + print " %s;" % symbol + + print "} %s;" % version + + +if __name__ == '__main__': + options, argv = gnu_getopt (sys.argv[1:], '', + ['symbols=', 'unreleased-version=', + 'dpkg=', 'dpkg-build-depends-package=']) + + opts = {'dpkg': False} + + for option, value in options: + if option == '--dpkg': + opts['dpkg'] = True + opts['dpkg_first_line'] = value + else: + opts[option.lstrip('-').replace('-', '_')] = value + + main(argv, **opts) diff --git a/tools/manager-file.py b/tools/manager-file.py new file mode 100644 index 000000000..e1b51a616 --- /dev/null +++ b/tools/manager-file.py @@ -0,0 +1,187 @@ +#!/usr/bin/python + +# manager-file.py: generate .manager files and TpCMParamSpec arrays from the +# same data (should be suitable for all connection managers that don't have +# plugins) +# +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (c) Collabora Ltd. <http://www.collabora.co.uk/> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import re +import sys + +_NOT_C_STR = re.compile(r'[^A-Za-z0-9_-]') + +def c_string(x): + # whitelist-based brute force and ignorance - escape nearly all punctuation + return '"' + _NOT_C_STR.sub(lambda c: r'\x%02x' % ord(c), x) + '"' + +def desktop_string(x): + return x.replace(' ', r'\s').replace('\n', r'\n').replace('\r', r'\r').replace('\t', r'\t') + +supported = list('sbuiqn') + +fdefaultencoders = { + 's': desktop_string, + 'b': (lambda b: b and '1' or '0'), + 'u': (lambda n: '%u' % n), + 'i': (lambda n: '%d' % n), + 'q': (lambda n: '%u' % n), + 'n': (lambda n: '%d' % n), + } +for x in supported: assert x in fdefaultencoders + +gtypes = { + 's': 'G_TYPE_STRING', + 'b': 'G_TYPE_BOOLEAN', + 'u': 'G_TYPE_UINT', + 'i': 'G_TYPE_INT', + 'q': 'G_TYPE_UINT', + 'n': 'G_TYPE_INT', +} +for x in supported: assert x in gtypes + +gdefaultencoders = { + 's': c_string, + 'b': (lambda b: b and 'GINT_TO_POINTER (TRUE)' or 'GINT_TO_POINTER (FALSE)'), + 'u': (lambda n: 'GUINT_TO_POINTER (%u)' % n), + 'i': (lambda n: 'GINT_TO_POINTER (%d)' % n), + 'q': (lambda n: 'GUINT_TO_POINTER (%u)' % n), + 'n': (lambda n: 'GINT_TO_POINTER (%d)' % n), + } +for x in supported: assert x in gdefaultencoders + +gdefaultdefaults = { + 's': 'NULL', + 'b': 'GINT_TO_POINTER (FALSE)', + 'u': 'GUINT_TO_POINTER (0)', + 'i': 'GINT_TO_POINTER (0)', + 'q': 'GUINT_TO_POINTER (0)', + 'n': 'GINT_TO_POINTER (0)', + } +for x in supported: assert x in gdefaultdefaults + +gflags = { + 'has-default': 'TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT', + 'register': 'TP_CONN_MGR_PARAM_FLAG_REGISTER', + 'required': 'TP_CONN_MGR_PARAM_FLAG_REQUIRED', + 'secret': 'TP_CONN_MGR_PARAM_FLAG_SECRET', + 'dbus-property': 'TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY', +} + +def write_manager(f, manager, protos): + # pointless backwards compat section + print >> f, '[ConnectionManager]' + print >> f, 'BusName=org.freedesktop.Telepathy.ConnectionManager.' + manager + print >> f, 'ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/' + manager + + # protocols + for proto, params in protos.iteritems(): + print >> f + print >> f, '[Protocol %s]' % proto + + defaults = {} + + for param, info in params.iteritems(): + dtype = info['dtype'] + flags = info.get('flags', '').split() + struct_field = info.get('struct_field', param.replace('-', '_')) + filter = info.get('filter', 'NULL') + filter_data = info.get('filter_data', 'NULL') + setter_data = 'NULL' + + if 'default' in info: + default = fdefaultencoders[dtype](info['default']) + defaults[param] = default + + if flags: + flags = ' ' + ' '.join(flags) + else: + flags = '' + + print >> f, 'param-%s=%s%s' % (param, desktop_string(dtype), flags) + + for param, default in defaults.iteritems(): + print >> f, 'default-%s=%s' % (param, default) + +def write_c_params(f, manager, proto, struct, params): + print >> f, "static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto) + + for param, info in params.iteritems(): + dtype = info['dtype'] + flags = info.get('flags', '').split() + struct_field = info.get('struct_field', param.replace('-', '_')) + filter = info.get('filter', 'NULL') + filter_data = info.get('filter_data', 'NULL') + setter_data = 'NULL' + + if 'default' in info: + default = gdefaultencoders[dtype](info['default']) + else: + default = gdefaultdefaults[dtype] + + if flags: + flags = ' | '.join([gflags[flag] for flag in flags]) + else: + flags = '0' + + if struct is None or struct_field is None: + struct_offset = '0' + else: + struct_offset = 'G_STRUCT_OFFSET (%s, %s)' % (struct, struct_field) + + print >> f, (''' { %s, %s, %s, + %s, + %s, /* default */ + %s, /* struct offset */ + %s, /* filter */ + %s, /* filter data */ + %s /* setter data */ },''' % + (c_string(param), c_string(dtype), gtypes[dtype], flags, + default, struct_offset, filter, filter_data, setter_data)) + + print >> f, " { NULL }" + print >> f, "};" + +if __name__ == '__main__': + environment = {} + execfile(sys.argv[1], environment) + + filename = '%s/%s.manager' % (sys.argv[2], environment['MANAGER']) + try: + os.remove(filename) + except OSError: + pass + f = open(filename + '.tmp', 'w') + write_manager(f, environment['MANAGER'], environment['PARAMS']) + f.close() + os.rename(filename + '.tmp', filename) + + filename = '%s/param-spec-struct.h' % sys.argv[2] + try: + os.remove(filename) + except OSError: + pass + f = open(filename + '.tmp', 'w') + for protocol in environment['PARAMS']: + write_c_params(f, environment['MANAGER'], protocol, + environment['STRUCTS'][protocol], + environment['PARAMS'][protocol]) + f.close() + os.rename(filename + '.tmp', filename) diff --git a/tools/shave.mk b/tools/shave.mk new file mode 100644 index 000000000..53cb3bf5e --- /dev/null +++ b/tools/shave.mk @@ -0,0 +1 @@ +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) diff --git a/tools/telepathy-glib-env.in b/tools/telepathy-glib-env.in new file mode 100644 index 000000000..ddc47bfd8 --- /dev/null +++ b/tools/telepathy-glib-env.in @@ -0,0 +1,9 @@ +#!/bin/sh +abs_top_builddir="@abs_top_builddir@" +export abs_top_builddir +LD_LIBRARY_PATH="${abs_top_builddir}/telepathy-glib/.libs${LD_LIBRARY_PATH:+":${LD_LIBRARY_PATH}"}" +export LD_LIBRARY_PATH +G_DEBUG="fatal_criticals,fatal_warnings${G_DEBUG:+",${G_DEBUG}"}" +export G_DEBUG + +exec "$@" diff --git a/tools/telepathy-glib.supp b/tools/telepathy-glib.supp new file mode 100644 index 000000000..28bd5a06a --- /dev/null +++ b/tools/telepathy-glib.supp @@ -0,0 +1,390 @@ +# Valgrind error suppression file + +# ============================= libc ================================== + +{ + ld.so initialization + selinux + Memcheck:Leak + ... + fun:_dl_init + obj:/lib/ld-*.so +} + +{ + dlopen initialization, triggered by handle-leak-debug code + Memcheck:Leak + ... + fun:__libc_dlopen_mode + fun:init + fun:backtrace + fun:handle_leak_debug_bt + fun:dynamic_ensure_handle + fun:tp_handle_ensure +} + +# default.supp has these for 2.10, but they're too specific +{ + Debian libc6 (2.10.x, 2.11.x) stripped dynamic linker + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/lib/ld-*.so +} +{ + Debian libc6 (2.9.x - 2.11.x) stripped dynamic linker + Memcheck:Cond + fun:_dl_relocate_object + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/lib/ld-*.so +} + +{ + ld.so initialization on glibc 2.9 + Memcheck:Cond + fun:strlen + fun:_dl_init_paths + fun:dl_main + fun:_dl_sysdep_start + fun:_dl_start + obj:/lib/ld-2.9.so +} + +# ======================= libselinux on Debian amd64 ===================== + +{ + I have no idea what SELinux is doing but it's not my problem + Memcheck:Cond + ... + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 +} + +{ + I have no idea what SELinux is doing but it's not my problem + Memcheck:Value8 + ... + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 +} + +{ + I have no idea what SELinux is doing but it's not my problem + Memcheck:Leak + ... + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 + obj:/lib/libselinux.so.1 +} + +# ============================= GLib ================================== + +{ + g_set_prgname copies its argument + Memcheck:Leak + ... + fun:g_set_prgname +} + +{ + one g_get_charset per child^Wprocess + Memcheck:Leak + ... + fun:g_get_charset +} + +{ + one g_get_home_dir per process + Memcheck:Leak + ... + fun:g_get_home_dir +} + +{ + GQuarks can't be freed + Memcheck:Leak + ... + fun:g_quark_from_static_string +} + +{ + GQuarks can't be freed + Memcheck:Leak + ... + fun:g_quark_from_string +} + +{ + interned strings can't be freed + Memcheck:Leak + ... + fun:g_intern_string +} + +{ + interned strings can't be freed + Memcheck:Leak + ... + fun:g_intern_static_string +} + +{ + shared global default g_main_context + Memcheck:Leak + ... + fun:g_main_context_new + fun:g_main_context_default +} + +{ + GTest initialization + Memcheck:Leak + ... + fun:g_test_init + fun:main +} + +{ + GTest admin + Memcheck:Leak + ... + fun:g_test_add_vtable +} + +{ + GTest pseudorandomness + Memcheck:Leak + ... + fun:g_rand_new_with_seed_array + fun:test_run_seed + ... + fun:g_test_run +} + +{ + GSLice initialization + Memcheck:Leak + ... + fun:g_malloc0 + fun:g_slice_init_nomessage + fun:g_slice_alloc +} + +# ============================= GObject =============================== + +{ + g_type_init + Memcheck:Leak + ... + fun:g_type_init +} + +{ + g_type_init_with_debug_flags + Memcheck:Leak + ... + fun:g_type_init_with_debug_flags +} + +{ + g_type_register_static + Memcheck:Leak + ... + fun:g_type_register_static +} + +{ + g_type_add_interface_static + Memcheck:Leak + ... + fun:g_type_add_interface_static +} + +{ + initialization of interfaces + Memcheck:Leak + ... + fun:type_iface_vtable_base_init_Wm + fun:g_type_class_ref +} + +# ============================= GIO =================================== + +{ + GIO init + Memcheck:Leak + ... + fun:g_inet_address_class_intern_init +} + +{ + g_simple_async_result class + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_simple_async_result_new +} + +# ============================= dbus-glib ============================= + +{ + registering marshallers is permanent + Memcheck:Leak + ... + fun:dbus_g_object_register_marshaller_array + fun:dbus_g_object_register_marshaller +} + +{ + dbus-glib specialized GTypes are permanent + Memcheck:Leak + ... + fun:dbus_g_type_specialized_init +} + +{ + libdbus shared connection + Memcheck:Leak + ... + fun:dbus_g_bus_get +} + +{ + dbus-gobject registrations aren't freed unless we fall off the bus + Memcheck:Leak + ... + fun:g_slist_append + fun:dbus_g_connection_register_g_object +} + +{ + DBusGProxy slots aren't freed unless we fall off the bus + Memcheck:Leak + ... + fun:dbus_connection_allocate_data_slot + ... + fun:dbus_g_proxy_constructor +} + +{ + error registrations are for life, not just for Christmas + Memcheck:Leak + ... + fun:dbus_g_error_domain_register +} + +{ + DBusGProxy class init + Memcheck:Leak + ... + fun:dbus_g_proxy_class_init +} + +# ============================= telepathy-glib ======================== + +{ + tp_dbus_daemon_constructor @daemons once per DBusConnection + Memcheck:Leak + ... + fun:g_slice_alloc + fun:tp_dbus_daemon_constructor +} + +{ + tp_proxy_subclass_add_error_mapping refs the enum + Memcheck:Leak + ... + fun:g_type_class_ref + fun:tp_proxy_subclass_add_error_mapping +} + +{ + tp_proxy_or_subclass_hook_on_interface_add never frees its list + Memcheck:Leak + ... + fun:tp_proxy_or_subclass_hook_on_interface_add +} + +{ + tp_dbus_daemon_constructor filter not freed til we fall off the bus + Memcheck:Leak + ... + fun:dbus_connection_add_filter + fun:tp_dbus_daemon_constructor +} + +{ + tp_g_socket_address_from_variant reffing GNIO types + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:tp_g_socket_address_from_variant +} + +{ + creating classes for DBusGProxy + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_object_new + ... + fun:tp_proxy_borrow_interface_by_id +} + +{ + creating classes for tp_dbus_daemon_new + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_object_new + ... + fun:tp_dbus_daemon_new +} + +{ + creating classes for TpCHannel + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_object_new + ... + fun:tp_channel_new +} + +{ + creating a boxed type to use in TpCapabilities + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_param_spec_boxed + fun:tp_capabilities_class_intern_init +} + +# ============================= questionable ========================== + +{ + creating classes for instances (this is a pretty big hammer) + Memcheck:Leak + ... + fun:g_type_class_ref + ... + fun:g_type_create_instance + ... + fun:g_param_spec_string +} diff --git a/tools/test-wrapper.sh b/tools/test-wrapper.sh new file mode 100755 index 000000000..94900674a --- /dev/null +++ b/tools/test-wrapper.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# Make tests shut up. On success, if stdout is a tty, we only output messages +# about skipped tests; on failure, or if stdout is a file or pipe, we output +# the lot. +# +# Usage: test-wrapper.sh PROGRAM [ARGS...] + +set -e + +if test -t 1 && test "z$CHECK_VERBOSE" = z; then + : # continue with the output-suppressed code path, below +else + "$@" || e=$? + exit $e +fi + +e=0 +"$@" > capture-$$.log 2>&1 || e=$? +if test z$e = z0; then + grep -i skipped capture-$$.log || true + rm -f capture-$$.log +else + cat capture-$$.log + exit $e +fi + +# Copyright © 2010 Collabora Ltd. <http://www.collabora.co.uk/> +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. There is no warranty. diff --git a/tools/valgrind.mk b/tools/valgrind.mk new file mode 100644 index 000000000..25a3488cd --- /dev/null +++ b/tools/valgrind.mk @@ -0,0 +1,13 @@ +VALGRIND = valgrind --tool=memcheck \ + --verbose \ + --leak-check=full \ + --leak-resolution=high \ + --suppressions=$(top_srcdir)/tools/telepathy-glib.supp \ + --child-silent-after-fork=yes \ + --num-callers=20 \ + --gen-suppressions=all + +# other potentially interesting options: +# --show-reachable=yes reachable objects (many!) +# --read-var-info=yes better diagnostics from DWARF3 info +# --track-origins=yes better diagnostics for uninit values (slow) diff --git a/tools/with-session-bus.sh b/tools/with-session-bus.sh new file mode 100755 index 000000000..b3038cd9e --- /dev/null +++ b/tools/with-session-bus.sh @@ -0,0 +1,100 @@ +#!/bin/sh +# with-session-bus.sh - run a program with a temporary D-Bus session daemon +# +# The canonical location of this program is the telepathy-glib tools/ +# directory, please synchronize any changes with that copy. +# +# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/> +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +set -e + +me=with-session-bus + +dbus_daemon_args="--print-address=5 --print-pid=6 --fork" +sleep=0 + +usage () +{ + echo "usage: $me [options] -- program [program_options]" >&2 + echo "Requires write access to the current directory." >&2 + echo "" >&2 + echo "If \$WITH_SESSION_BUS_FORK_DBUS_MONITOR is set, fork dbus-monitor" >&2 + echo "with the arguments in \$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT." >&2 + echo "The output of dbus-monitor is saved in $me-<pid>.dbus-monitor-logs" >&2 + exit 2 +} + +while test "z$1" != "z--"; do + case "$1" in + --sleep=*) + sleep="$1" + sleep="${sleep#--sleep=}" + shift + ;; + --session) + dbus_daemon_args="$dbus_daemon_args --session" + shift + ;; + --config-file=*) + # FIXME: assumes config file doesn't contain any special characters + dbus_daemon_args="$dbus_daemon_args $1" + shift + ;; + *) + usage + ;; + esac +done +shift +if test "z$1" = "z"; then usage; fi + +exec 5> $me-$$.address +exec 6> $me-$$.pid + +cleanup () +{ + pid=`head -n1 $me-$$.pid` + if test -n "$pid" ; then + if [ -n "$VERBOSE_TESTS" ]; then + echo "Killing temporary bus daemon: $pid" >&2 + fi + kill -INT "$pid" + fi + rm -f $me-$$.address + rm -f $me-$$.pid +} + +trap cleanup INT HUP TERM +dbus-daemon $dbus_daemon_args + +if [ -n "$VERBOSE_TESTS" ]; then + { echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2 + { echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2 +fi + +e=0 +DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`" +export DBUS_SESSION_BUS_ADDRESS +DBUS_SESSION_BUS_PID="`cat $me-$$.pid`" +export DBUS_SESSION_BUS_PID + +if [ -n "$WITH_SESSION_BUS_FORK_DBUS_MONITOR" ] ; then + echo -n "Forking dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT" >&2 + dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT \ + > $me-$$.dbus-monitor-logs 2>&1 & +fi + +"$@" || e=$? + +if test $sleep != 0; then + sleep $sleep +fi + +trap - INT HUP TERM +cleanup + +exit $e |