diff options
271 files changed, 3514 insertions, 16745 deletions
diff --git a/.gitignore b/.gitignore index 9c42dc2c1..bb2a5bed8 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ Makefile.in _gen /aclocal.m4 /autom4te.cache +/build-aux /compile /config.cache /config.guess diff --git a/Makefile.am b/Makefile.am index 288478ba4..516610dc0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = docs tools extensions lib src data m4 plugins tests gabble -DISTCHECK_CONFIGURE_FLAGS = --disable-debug --enable-gtk-doc +DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc CLEANFILES = FIXME.out @@ -1,3 +1,57 @@ +telepathy-gabble 0.19.0 (UNRELEASED) +==================================== + +The “very confused owl” release. + +Compile-time configuration: + +• The --disable-debug option has gone away. The new configuration is + equivalent to --enable-debug. + +Dependencies: + +• telepathy-glib ≥ 0.23.0 is required + +• Autoconf 2.60 is required + +External changes: + +• Remove support for legacy StreamedMedia calls, and legacy Capabilities; + Gabble only implements Call1 calls and ContactCapabilities now + (fd.o #69194; Xavier, Simon, Guillaume) + +• Always announce channels one at a time (fd.o #69194, Simon) + +• Improve XMPP console (fd.o #66085, Will) + +Fixes: + +• Stop claiming to implement legacy Presence, which was deleted in 2011 + (fd.o #69194, Guillaume) + +• Use the correct capability token to control whether we advertise ICE-UDP + support (Guillaume) + +• Implement RequestClientTypes (fd.o #70134, Guillaume) + +• Correct the type of private tubes' IDs, fixing a crash on 64-bit platforms + (fd.o #70038, Guillaume) + +• Use telepathy-glib to implement Addressing, Sidecars1, + FileTransfer.FileCollection (fd.o #26609, #69817; Simon) + +• Implement Protocol.I.Avatars correctly (Guillaume) + +Internal changes: + +• Fix various deprecated things (fd.o #69194, #69618, #69767, #70045; + Simon, Guillaume) + +• Improved regression test coverage (fd.o #69474, Simon) + +• Remove regression tests for obsolete APIs to reduce delta between + 0.20 and 1.0 branches (Simon, Guillaume) + telepathy-gabble 0.18.1 (2013-09-06) ==================================== diff --git a/configure.ac b/configure.ac index bde9a51ac..2d4f11897 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_PREREQ([2.59]) +AC_PREREQ([2.60]) # Making releases: # set the new version number: @@ -9,7 +9,7 @@ AC_PREREQ([2.59]) m4_define([gabble_major_version], [0]) m4_define([gabble_minor_version], [18]) -m4_define([gabble_micro_version], [1]) +m4_define([gabble_micro_version], [999]) m4_define([gabble_nano_version], [1]) # Some magic @@ -23,8 +23,9 @@ AC_INIT([Telepathy Gabble], [gabble_version], [https://bugs.freedesktop.org/enter_bug.cgi?product=Telepathy&component=gabble]) AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) -AM_INIT_AUTOMAKE([1.9 -Wno-portability tar-ustar]) +AM_INIT_AUTOMAKE([1.9 -Wno-portability tar-ustar subdir-objects]) AM_CONFIG_HEADER(config.h) AC_USE_SYSTEM_EXTENSIONS @@ -93,7 +94,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]) @@ -149,10 +149,6 @@ if test -n "$with_ca_certificates"; then fi fi -AC_ARG_ENABLE(debug, - AC_HELP_STRING([--disable-debug],[compile without debug code]), - enable_debug=$enableval, enable_debug=yes ) - ifelse(gabble_nano_version, 0, [ # Gabble is version x.y.z - disable coding style checks by default AC_ARG_ENABLE(coding-style-checks, @@ -167,11 +163,6 @@ AC_ARG_ENABLE(coding-style-checks, [ENABLE_CODING_STYLE_CHECKS=$enableval], [ENABLE_CODING_STYLE_CHECKS=yes]) ]) -if test x$enable_debug = xyes; then - AC_DEFINE(ENABLE_DEBUG, [], [Enable debug code]) -fi -AM_CONDITIONAL([ENABLE_DEBUG], [test "x$enable_debug" = xyes]) - AC_SUBST([ENABLE_CODING_STYLE_CHECKS]) AC_ARG_ENABLE([installed-tests], @@ -228,7 +219,7 @@ PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.32, gobject-2.0, gthread-2.0, gio-2.0]) PKG_CHECK_MODULES(GMODULE, [gmodule-2.0 >= 2.32]) -AC_DEFINE(GLIB_VERSION_MIN_REQUIRED, GLIB_VERSION_2_30, [Ignore post 2.30 deprecations]) +AC_DEFINE(GLIB_VERSION_MIN_REQUIRED, GLIB_VERSION_2_32, [Ignore post 2.32 deprecations]) AC_DEFINE(GLIB_VERSION_MAX_ALLOWED, GLIB_VERSION_2_32, [Prevent post 2.32 APIs]) AC_SUBST(GLIB_CFLAGS) @@ -279,17 +270,6 @@ AC_SUBST(ENABLE_PLUGINS) AM_CONDITIONAL(ENABLE_PLUGIN_API, test x$enable_plugin_api = xyes) -AC_ARG_ENABLE(channel-type-call, - AC_HELP_STRING([--disable-channel-type-call], - [disable support for the draft Channel.Type.Call]), - [enable_channel_type_call=$enableval], [enable_channel_type_call=yes]) - -if test x$enable_channel_type_call = xyes; then - AC_DEFINE(ENABLE_CHANNEL_TYPE_CALL, [], [Enable Channel.Type.Call]) -fi - -AM_CONDITIONAL(ENABLE_CHANNEL_TYPE_CALL, test x$enable_channel_type_call = xyes) - dnl Check for D-Bus PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.1.0, dbus-glib-1 >= 0.82]) @@ -298,9 +278,9 @@ AC_SUBST(DBUS_LIBS) 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_DEFINE([TP_VERSION_MIN_REQUIRED], [TP_VERSION_0_24], [Ignore post 0.24 deprecations]) +AC_DEFINE([TP_VERSION_MAX_ALLOWED], [TP_VERSION_0_24], [Prevent post 0.24 APIs]) +PKG_CHECK_MODULES(TP_GLIB, [telepathy-glib >= 0.23.2]) AC_SUBST(TP_GLIB_CFLAGS) AC_SUBST(TP_GLIB_LIBS) @@ -462,7 +442,6 @@ Configure summary: Compiler Flags..............: ${CFLAGS} ${ERROR_CFLAGS} Prefix......................: ${prefix} Coding style checks.........: ${ENABLE_CODING_STYLE_CHECKS} - Enable debug................: ${enable_debug} Python tests................: ${tests_enabled} Install unit tests..........: ${installed_tests} @@ -471,7 +450,6 @@ Configure summary: Client type.................: \"${CLIENT_TYPE}\" Plugin support..............: ${enable_plugins} Plugin headers installed....: ${enable_plugin_api} - Channel.Type.Call support...: ${enable_channel_type_call} Google relay support........: ${enable_google_relay} File transfer support.......: ${enable_ft} Jingle file transfer support: ${enable_jingle_ft} diff --git a/extensions/Channel_Type_FileTransfer_Future.xml b/extensions/Channel_Type_FileTransfer_Future.xml deleted file mode 100644 index b155136e0..000000000 --- a/extensions/Channel_Type_FileTransfer_Future.xml +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Channel_Type_FileTransfer_Future" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright>Copyright (C) 2010 Collabora Ltd.</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>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.</p> - -<p>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.</p> - -<p>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 Street, Fifth Floor, Boston, MA 02110-1301, USA.</p> - </tp:license> - <interface name="org.freedesktop.Telepathy.Channel.Type.FileTransfer.FUTURE" - tp:causes-havoc="a staging area for future File Transfer Channel functionality"> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>This interface contains functionality which we intend to incorporate - into the File Transfer Channel interface in future. - It should be considered to be conceptually part of the core - File Transfer Channel interface, but without API or ABI guarantees.</p> - - <tp:rationale> - <p>If we add new functionality to the Channel interface, libraries - that use generated code (notably telepathy-glib) will have it as - part of their ABI forever, meaning we can't make incompatible - changes. By using this interface as a staging area for future - Channel functionality, we can try out new properties, signals - and methods as application-specific extensions, then merge them - into the core Channel interface when we have enough implementation - experience to declare them to be stable.</p> - - <p>The name is by analogy to Python's <code>__future__</code> - pseudo-module.</p> - </tp:rationale> - </tp:docstring> - - <property name="FileCollection" tp:name-for-bindings="FileCollection" - type="s" access="read"> - <tp:added version="0.19.2">(in Channel.Type.FileTransfer.FUTURE - pseudo-interface)</tp:added> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The FileCollection to which this channel belongs.</p> - - <p>A channel's FileCollection property can never change.</p> - - <p>At least on GTalk and apparently also on iChat the user can - send a set of files to a contact and that contact can then - pick and choose which files to actually receive. - - The CM should emit all new FT channels belonging to one collection - at the same time, UIs supporting this feature can then - bundle all these channels together in some way and show a - nice UI. UIs not supporting it will treat them as seperate - transfers, which is not great but a reasonable fallback</p> - </tp:docstring> - </property> - - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Connection_Future.xml b/extensions/Connection_Future.xml deleted file mode 100644 index 110479832..000000000 --- a/extensions/Connection_Future.xml +++ /dev/null @@ -1,110 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Connection_FUTURE" - xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" - > - <tp:copyright>Copyright © 2009 Collabora Limited</tp:copyright> - <tp:copyright>Copyright © 2009 Nokia Corporation</tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> -<p>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.</p> - -<p>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.</p> - -<p>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 Street, Fifth Floor, Boston, MA 02110-1301, -USA.</p> - </tp:license> - <interface name="org.freedesktop.Telepathy.Connection.FUTURE" - tp:causes-havoc='experimental'> - <tp:requires interface="org.freedesktop.Telepathy.Connection"/> - - <method name="EnsureSidecar" tp:name-for-bindings="Ensure_Sidecar"> - <tp:added version="0.19.UNRELEASED"/> - - <arg direction="in" name="Main_Interface" type="s" - tp:type="DBus_Interface"> - <tp:docstring> - The "primary" interface implemented by an object attached - to a connection. For example, a Gabble plugin implementing - fine-grained control of XEP-0016 privacy lists might expose an object - implementing <tt>com.example.PrivacyLists</tt>. - </tp:docstring> - </arg> - - <arg direction="out" name="Path" type="o"> - <tp:docstring>The object path of the sidecar, exported by the same bus - name as the Connection to which it is attached.</tp:docstring> - </arg> - <arg direction="out" name="Properties" type="a{sv}" - tp:type="Qualified_Property_Value_Map"> - <tp:docstring>Immutable properties of the sidecar.</tp:docstring> - </arg> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Request an object with a particular interface providing additional - connection-specific functionality, together with its immutable - properties. These will often be implemented by plug-ins to the - connection managers; for example, support for an XMPP XEP for which - no generic Telepathy interface exists might be implemented by a - Gabble plugin exposing a sidecar with a particular interface.</p> - - <p>This method may be called at any point during the lifetime of a - connection, even before its <tp:type>Connection_Status</tp:type> - changes to Connected. It MAY take a long time to - return—perhaps it needs to wait for a connection to be established - and for all the services supported by the server to be discovered - before determining whether necessary server-side support is - available—so callers SHOULD override the default method timeout (25 - seconds) with a much higher value (perhaps even MAX_INT32, meaning - “no timeout” in recent versions of libdbus).</p> - - <tp:rationale> - <p>There is an implicit assumption that any connection - manager plugin will only want to export one “primary” object per - feature it implements, since there is a one-to-one mapping between - interface and object. This is reasonable since Sidecars are - (intended to be) analogous to extra interfaces on the connection, - providing once-per-connection shared functionality; it also makes - client code straightforward (look up the interface you care about - in a dictionary, build a proxy object from the value). More - “plural” plugins are likely to want to implement new types of - <tp:dbus-ref - namespace="org.freedesktop.Telepathy">Channel</tp:dbus-ref> - instead.</p> - </tp:rationale> - </tp:docstring> - - <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented"> - <tp:docstring> - The requested sidecar is not implemented by this connection manager, - or a necessary server-side component does not exist. (FIXME: split - these two errors out? Then again, once we list the guaranteed and - possible sidecars on a Protocol object, clients can tell the - difference themselves, because they shouldn't be calling this in the - first case.) - </tp:docstring> - </tp:error> - - <tp:error name="org.freedesktop.Telepathy.Error.ServiceBusy"> - <tp:docstring> - A server-side component needed by the requested sidecar reported it - is currently too busy, or did not respond for some - implementation-defined time. The caller may wish to try again later. - </tp:docstring> - </tp:error> - - <tp:error name="org.freedesktop.Telepathy.Error.Cancelled"> - <tp:docstring> - The connection was disconnected while the sidecar was being set up. - </tp:docstring> - </tp:error> - </method> - - </interface> -</node> diff --git a/extensions/Connection_Interface_Addressing.xml b/extensions/Connection_Interface_Addressing.xml deleted file mode 100644 index 2d8145f3c..000000000 --- a/extensions/Connection_Interface_Addressing.xml +++ /dev/null @@ -1,245 +0,0 @@ -<?xml version="1.0" ?> -<node name="/Connection_Interface_Addressing" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> - <tp:copyright> Copyright (C) 2010 Collabora Limited </tp:copyright> - <tp:license xmlns="http://www.w3.org/1999/xhtml"> - <p>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.</p> - - <p>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.</p> - - <p>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 Street, Fifth Floor, Boston, MA 02110-1301, USA.</p> - </tp:license> - <interface name="org.freedesktop.Telepathy.Connection.Interface.Addressing1" - tp:causes-havoc="experimental"> - <tp:requires interface="org.freedesktop.Telepathy.Connection"/> - <tp:requires interface="org.freedesktop.Telepathy.Connection.Interface.Contacts"/> - <tp:added version="0.19.12">(as draft)</tp:added> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>This interface deals with the multiple address types that can - refer to the same contact, such as vCard fields and URIs.</p> - - <p>It can be used to retrieve contacts with a specific addresses - through <tp:member-ref>GetContactsByVCardField</tp:member-ref> and - <tp:member-ref>GetContactsByURI</tp:member-ref>, as well as - defining the various addressing methods for a given contact - through this interface's contact attributes.</p> - </tp:docstring> - - <method name="GetContactsByVCardField" - tp:name-for-bindings="Get_Contacts_By_VCard_Field"> - <arg direction="in" name="Field" type="s"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>The vCard field of the addresses we are requesting. The - field name SHOULD be in lower case. Supported - fields can be found in - <tp:dbus-ref namespace="org.freedesktop.Telepathy.Protocol.Interface.Addressing">AddressableVCardFields</tp:dbus-ref>.</p> - - <p>The <code>url</code> vCard field MUST NOT appear here; see - <tp:member-ref>GetContactsByURI</tp:member-ref> instead.</p> - - <tp:rationale> - <p>In practice, protocols have a limited set of URI - schemes that make sense to resolve as a contact.</p> - </tp:rationale> - - </tp:docstring> - </arg> - <arg direction="in" name="Addresses" type="as"> - <tp:docstring> - The addresses to get contact handles for. The address types - should match the given vCard field. - </tp:docstring> - </arg> - <arg direction="in" name="Interfaces" type="as" - tp:type="DBus_Interface[]"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A list of strings indicating which D-Bus interfaces the calling - process is interested in. All supported attributes from these - interfaces, whose values can be obtained without additional network - activity, will be in the reply.</p> - - <p>Attributes from this interface and from - <tp:dbus-ref>org.freedesktop.Telepathy.Connection</tp:dbus-ref> - are always returned, and need not be requested - explicitly.</p> - - <p>The behavior of this parameter is similar to the same - parameter in - <tp:dbus-ref namespace="org.freedesktop.Telepathy.Connection.Interface">Contacts.GetContactAttributes</tp:dbus-ref>.</p> - </tp:docstring> - </arg> - - <arg direction="out" type="a{su}" name="Requested" - tp:type="Addressing_Normalization_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A mapping from requested vCard addresses to the corresponding - contact handles.</p> - - <p>Requested addresses that are not valid or understood for this protocol - MUST be omitted from the mapping.</p> - </tp:docstring> - </arg> - - <arg direction="out" type="a{ua{sv}}" name="Attributes" - tp:type="Contact_Attributes_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A dictionary mapping the contact handles to contact attributes. - If any of the requested addresses are in fact invalid, they are - simply omitted from this mapping. If contact attributes are not - immediately known, the behaviour is defined by the interface; - the attribute should either be omitted from the result or - replaced with a default value.</p> - - <p>Requested addresses that are not valid or understood for this protocol - MUST be omitted from the mapping.</p> - - <p>Each contact's attributes will always include at least the - identifier that would be obtained by inspecting the handle - (<code>org.freedesktop.Telepathy.Connection/contact-id</code>). - </p> - </tp:docstring> - </arg> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Request contacts and retrieve their attributes using a given field - in their vCards.</p> - - <p>The connection manager should record that these handles are in - use by the client who invokes this method, and must not - deallocate the handles until the client disconnects from the - bus or calls the - <tp:dbus-ref namespace="org.freedesktop.Telepathy">Connection.ReleaseHandles</tp:dbus-ref> - method.</p> - </tp:docstring> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/> - </tp:possible-errors> - </method> - - <method name="GetContactsByURI" - tp:name-for-bindings="Get_Contacts_By_URI"> - <arg direction="in" name="URIs" type="as"> - <tp:docstring> - The URI addresses to get contact handles for. Supported - schemes can be found in - <tp:dbus-ref namespace="org.freedesktop.Telepathy.Protocol.Interface.Addressing">AddressableURISchemes</tp:dbus-ref>. - </tp:docstring> - </arg> - <arg direction="in" name="Interfaces" type="as" - tp:type="DBus_Interface[]"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A list of strings indicating which D-Bus interfaces the calling - process is interested in. All supported attributes from these - interfaces, whose values can be obtained without additional network - activity, will be in the reply.</p> - - <p>Attributes from this interface and from - <tp:dbus-ref>org.freedesktop.Telepathy.Connection</tp:dbus-ref> - are always returned, and need not be requested - explicitly.</p> - - <p>The behavior of this parameter is similar to the same - parameter in - <tp:dbus-ref namespace="org.freedesktop.Telepathy.Connection.Interface">Contacts.GetContactAttributes</tp:dbus-ref>.</p> - </tp:docstring> - </arg> - - <arg direction="out" type="a{su}" name="Requested" - tp:type="Addressing_Normalization_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A mapping of requested URIs to the corresponding contact handles.</p> - - <p>Requested URIs that are not valid or understood for this protocol - MUST be omitted from the mapping.</p> - </tp:docstring> - </arg> - - <arg direction="out" type="a{ua{sv}}" name="Attributes" - tp:type="Contact_Attributes_Map"> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A dictionary mapping the contact handles to contact attributes. - If any of the requested addresses are in fact invalid, they are - simply omitted from this mapping. If contact attributes are not - immediately known, the behaviour is defined by the interface; - the attribute should either be omitted from the result or - replaced with a default value.</p> - - <p>Requested URIs that are not valid or understood for this protocol - MUST be omitted from the mapping.</p> - - <p>Each contact's attributes will always include at least the - identifier that would be obtained by inspecting the handle - (<code>org.freedesktop.Telepathy.Connection/contact-id</code>). - </p> - </tp:docstring> - </arg> - - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>Request contacts and retrieve their attributes using URI addresses.</p> - - <p>The connection manager should record that these handles are in - use by the client who invokes this method, and must not - deallocate the handles until the client disconnects from the - bus or calls the - <tp:dbus-ref namespace="org.freedesktop.Telepathy">Connection.ReleaseHandles</tp:dbus-ref> - method.</p> - </tp:docstring> - - <tp:possible-errors> - <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/> - </tp:possible-errors> - </method> - - <tp:mapping name="VCard_Field_Address_Map" array-name=""> - <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A mapping of vCard fields and addresses that repreent - the given contact.</p> - </tp:docstring> - <tp:member type="s" name="VCard_Field"/> - <tp:member type="s" name="Address"/> - </tp:mapping> - - <tp:contact-attribute name="addresses" type="a{ss}" - tp:type="VCard_Field_Address_Map"> - <tp:docstring> - The various vCard addresses that identify this contact. - </tp:docstring> - </tp:contact-attribute> - - <tp:contact-attribute name="uris" type="as"> - <tp:docstring> - The various URI addresses that identify this contact. - </tp:docstring> - </tp:contact-attribute> - - <tp:mapping name="Addressing_Normalization_Map"> - <tp:docstring> - A map from URIs/vCard addresses to the corresponding handle. - </tp:docstring> - <tp:added version="0.25.UNRELEASED"/> - - <tp:member type="s" name="Requested_String"> - <tp:docstring> - The URI or vCard address that has been requested by - <tp:member-ref>GetContactsByVCardField</tp:member-ref> or - <tp:member-ref>GetContactsByURI</tp:member-ref>. - </tp:docstring> - </tp:member> - <tp:member type="u" name="Handle" tp:type="Contact_Handle"> - <tp:docstring> - A nonzero handle. - </tp:docstring> - </tp:member> - </tp:mapping> - - </interface> -</node> -<!-- vim:set sw=2 sts=2 et ft=xml: --> diff --git a/extensions/Gabble_Plugin_Console.xml b/extensions/Gabble_Plugin_Console.xml index 1e3b52385..a2d94ca0c 100644 --- a/extensions/Gabble_Plugin_Console.xml +++ b/extensions/Gabble_Plugin_Console.xml @@ -23,7 +23,7 @@ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/> <tp:docstring xmlns="http://www.w3.org/1999/xhtml"> - <p>A sidecar interface providing an XMPP console.</p> + <p>A channel type providing an XMPP console.</p> </tp:docstring> <method name="SendIQ" tp:name-for-bindings="Send_IQ"> diff --git a/extensions/Makefile.am b/extensions/Makefile.am index b435ae3f4..70210adf8 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -2,9 +2,6 @@ tools_dir = $(top_srcdir)/tools EXTRA_DIST = \ all.xml \ - Channel_Type_FileTransfer_Future.xml \ - Connection_Future.xml \ - Connection_Interface_Addressing.xml \ Connection_Interface_Gabble_Decloak.xml \ Gabble_Plugin_Console.xml \ Gabble_Plugin_Gateways.xml \ @@ -49,7 +46,7 @@ DROP_NAMESPACE = sed -e 's@xmlns:tp="http://telepathy\.freedesktop\.org/wiki/Dbu XSLTPROCFLAGS = --nonet --novalid _gen/all.xml: all.xml $(wildcard *.xml) Makefile.am - @$(mkdir_p) _gen + @$(MKDIR_P) _gen $(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py \ $< > $@.tmp && mv $@.tmp $@ diff --git a/extensions/all.xml b/extensions/all.xml index 99997d6db..b7c317422 100644 --- a/extensions/all.xml +++ b/extensions/all.xml @@ -33,14 +33,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p> from="Telepathy specification"/> </tp:generic-types> -<xi:include href="Connection_Interface_Addressing.xml"/> - <xi:include href="OLPC_Buddy_Info.xml"/> <xi:include href="OLPC_Activity_Properties.xml"/> -<xi:include href="Channel_Type_FileTransfer_Future.xml"/> <xi:include href="Connection_Interface_Gabble_Decloak.xml"/> -<xi:include href="Connection_Future.xml"/> <xi:include href="Gabble_Plugin_Console.xml"/> <xi:include href="Gabble_Plugin_Gateways.xml"/> @@ -108,17 +104,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p> <tp:external-type name="Connection_Status" type="u" from="Telepathy specification"/> - <!-- use types from Channel_Type_Streamed_Media.xml --> - <tp:enum name="Media_Stream_Type" type="u" - array-name="Media_Stream_Type_List"> - <tp:enumvalue suffix="Audio" value="0"> - <tp:docstring>An audio stream</tp:docstring> - </tp:enumvalue> - <tp:enumvalue suffix="Video" value="1"> - <tp:docstring>A video stream</tp:docstring> - </tp:enumvalue> - </tp:enum> - <!-- use types from generic-types.xml --> <tp:struct name="Socket_Address_IP" array-name="Socket_Address_IP_List"> <tp:docstring>An IP address and port.</tp:docstring> diff --git a/lib/ext/wocky b/lib/ext/wocky -Subproject 0db9f32fd023fc728abf1780c26b957102c3292 +Subproject c5932733128be4bfb1d5b0ce9be5b136746266d diff --git a/lib/gibber/gibber-debug.c b/lib/gibber/gibber-debug.c index 29b74f44e..69cf1a67c 100644 --- a/lib/gibber/gibber-debug.c +++ b/lib/gibber/gibber-debug.c @@ -6,8 +6,6 @@ #include "gibber-debug.h" -#ifdef ENABLE_DEBUG - static DebugFlags flags = 0; static gboolean initialized = FALSE; @@ -96,5 +94,3 @@ gibber_debug_stanza (DebugFlags flag, } } #endif - -#endif diff --git a/lib/gibber/gibber-debug.h b/lib/gibber/gibber-debug.h index 8c813bdad..7bc7f18aa 100644 --- a/lib/gibber/gibber-debug.h +++ b/lib/gibber/gibber-debug.h @@ -12,8 +12,6 @@ G_BEGIN_DECLS -#ifdef ENABLE_DEBUG - typedef enum { DEBUG_TRANSPORT = 1 << 0, @@ -59,20 +57,6 @@ void gibber_debug_stanza (DebugFlags flag, GibberXmppStanza *stanza, #endif /* DEBUG_FLAG */ -#else /* ENABLE_DEBUG */ - -#ifdef DEBUG_FLAG - -#define DEBUG(format, ...) G_STMT_START { } G_STMT_END - -#define DEBUG_STANZA(stanza, format, ...) G_STMT_START { } G_STMT_END - -#define DEBUGGING (0) - -#endif /* DEBUG_FLAG */ - -#endif /* ENABLE_DEBUG */ - G_END_DECLS #endif diff --git a/plugins/Makefile.am b/plugins/Makefile.am index a51160472..2b0007901 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -62,8 +62,15 @@ libgateways_la_SOURCES = \ gateways.h libconsole_la_SOURCES = \ - console.c \ - console.h + console/channel-manager.c \ + console/channel-manager.h \ + console/channel.c \ + console/channel.h \ + console/debug.c \ + console/debug.h \ + console/plugin.c \ + console/plugin.h \ + $(NULL) AM_CFLAGS = $(ERROR_CFLAGS) \ -I $(top_srcdir) -I $(top_builddir) \ diff --git a/plugins/console/channel-manager.c b/plugins/console/channel-manager.c new file mode 100644 index 000000000..2f4955225 --- /dev/null +++ b/plugins/console/channel-manager.c @@ -0,0 +1,279 @@ +/* XML console plugin + * + * Copyright © 2011–2013 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 + */ + +#include "config.h" +#include "console/channel-manager.h" + +#include <telepathy-glib/telepathy-glib-dbus.h> + +#include "extensions/extensions.h" +#include "console/channel.h" + +static void channel_manager_iface_init (gpointer, gpointer); + +G_DEFINE_TYPE_WITH_CODE (GabbleConsoleChannelManager, gabble_console_channel_manager, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_MANAGER, channel_manager_iface_init) + G_IMPLEMENT_INTERFACE (GABBLE_TYPE_CAPS_CHANNEL_MANAGER, NULL); + ) + +enum { + PROP_CONNECTION = 1, +}; + +static void connection_status_changed_cb ( + TpBaseConnection *conn, + guint status, + guint reason, + GabbleConsoleChannelManager *self); +static void gabble_console_channel_manager_close_all ( + GabbleConsoleChannelManager *self); + +static void +gabble_console_channel_manager_init (GabbleConsoleChannelManager *self) +{ + g_weak_ref_init (&self->plugin_connection_ref, NULL); +} + + +static void +gabble_console_channel_manager_constructed (GObject *object) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + GabblePluginConnection *plugin_connection; + + G_OBJECT_CLASS (gabble_console_channel_manager_parent_class)->constructed (object); + + plugin_connection = g_weak_ref_get (&self->plugin_connection_ref); + if (plugin_connection != NULL) + { + g_signal_connect_object (plugin_connection, "status-changed", + G_CALLBACK (connection_status_changed_cb), self, 0); + g_object_unref (plugin_connection); + } +} + + +static void +gabble_console_channel_manager_set_property ( + GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + + switch (property_id) + { + case PROP_CONNECTION: + g_weak_ref_set (&self->plugin_connection_ref, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +gabble_console_channel_manager_get_property ( + GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + + switch (property_id) + { + case PROP_CONNECTION: + g_value_take_object (value, g_weak_ref_get (&self->plugin_connection_ref)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + + +static void +gabble_console_channel_manager_dispose ( + GObject *object) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (object); + + gabble_console_channel_manager_close_all (self); + g_weak_ref_clear (&self->plugin_connection_ref); + + G_OBJECT_CLASS (gabble_console_channel_manager_parent_class)->dispose (object); +} + + +static void +connection_status_changed_cb ( + TpBaseConnection *conn, + guint status, + guint reason, + GabbleConsoleChannelManager *self) +{ + switch (status) + { + case TP_CONNECTION_STATUS_DISCONNECTED: + gabble_console_channel_manager_close_all (self); + break; + + default: + return; + } +} + +static void +gabble_console_channel_manager_close_all ( + GabbleConsoleChannelManager *self) +{ + TpBaseChannel *channel; + + while ((channel = g_queue_peek_head (&self->console_channels)) != NULL) + { + tp_base_channel_close (channel); + } +} + + +static void +gabble_console_channel_manager_class_init (GabbleConsoleChannelManagerClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->constructed = gabble_console_channel_manager_constructed; + oclass->set_property = gabble_console_channel_manager_set_property; + oclass->get_property = gabble_console_channel_manager_get_property; + oclass->dispose = gabble_console_channel_manager_dispose; + + g_object_class_install_property (oclass, PROP_CONNECTION, + g_param_spec_object ("plugin-connection", "Gabble Plugin Connection", + "Gabble Plugin Connection", + GABBLE_TYPE_PLUGIN_CONNECTION, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); +} + + +static const gchar * const allowed[] = { + TP_PROP_CHANNEL_CHANNEL_TYPE, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, + NULL +}; + +static void +gabble_console_channel_manager_type_foreach_channel_class (GType type, + TpChannelManagerTypeChannelClassFunc func, + gpointer user_data) +{ + GHashTable *table = tp_asv_new ( + TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, + TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_NONE, + NULL); + + func (type, table, NULL, user_data); + + g_hash_table_unref (table); +} + + +static void +console_channel_closed_cb ( + GabbleConsoleChannel *channel, + gpointer user_data) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (user_data); + + tp_channel_manager_emit_channel_closed_for_object (self, + TP_EXPORTABLE_CHANNEL (channel)); + + if (g_queue_remove (&self->console_channels, channel)) + { + g_object_unref (channel); + } +} + + +static gboolean +gabble_console_channel_manager_create_channel ( + TpChannelManager *manager, + gpointer request_token, + GHashTable *request_properties) +{ + GabbleConsoleChannelManager *self = GABBLE_CONSOLE_CHANNEL_MANAGER (manager); + GabblePluginConnection *connection; + TpBaseChannel *channel = NULL; + GError *error = NULL; + GSList *request_tokens; + + if (tp_strdiff (tp_asv_get_string (request_properties, + TP_IFACE_CHANNEL ".ChannelType"), + GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE)) + return FALSE; + + if (tp_asv_get_uint32 (request_properties, + TP_IFACE_CHANNEL ".TargetHandleType", NULL) != 0) + { + g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, + "Console channels can't have a target handle"); + goto error; + } + + if (tp_channel_manager_asv_has_unknown_properties (request_properties, + allowed, + allowed, + &error)) + goto error; + + connection = g_weak_ref_get (&self->plugin_connection_ref); + g_return_val_if_fail (connection != NULL, FALSE); + + channel = g_object_new (GABBLE_TYPE_CONSOLE_CHANNEL, + "connection", connection, + NULL); + tp_base_channel_register (channel); + g_signal_connect (channel, "closed", (GCallback) console_channel_closed_cb, + self); + g_queue_push_tail (&self->console_channels, channel); + + 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); + + g_object_unref (connection); + return TRUE; + +error: + tp_channel_manager_emit_request_failed (self, request_token, + error->domain, error->code, error->message); + g_error_free (error); + return TRUE; +} + + +static void +channel_manager_iface_init (gpointer g_iface, + gpointer iface_data) +{ + TpChannelManagerIface *iface = g_iface; + + iface->type_foreach_channel_class = gabble_console_channel_manager_type_foreach_channel_class; + iface->create_channel = gabble_console_channel_manager_create_channel; +} diff --git a/plugins/console/channel-manager.h b/plugins/console/channel-manager.h new file mode 100644 index 000000000..5e7a8b94d --- /dev/null +++ b/plugins/console/channel-manager.h @@ -0,0 +1,52 @@ +/* XML console plugin + * + * Copyright © 2011–2013 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 + */ + +#include <glib-object.h> +#include <gabble/gabble.h> + +typedef struct _GabbleConsoleChannelManager GabbleConsoleChannelManager; +typedef struct _GabbleConsoleChannelManagerClass GabbleConsoleChannelManagerClass; + +struct _GabbleConsoleChannelManagerClass { + GObjectClass parent_class; +}; + +struct _GabbleConsoleChannelManager { + GObject parent; + + GWeakRef plugin_connection_ref; + GQueue console_channels; +}; + +GType gabble_console_channel_manager_get_type (void); + +#define GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER \ + (gabble_console_channel_manager_get_type ()) +#define GABBLE_CONSOLE_CHANNEL_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER, GabbleConsoleChannelManager)) +#define GABBLE_CONSOLE_CHANNEL_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER,\ + GabbleConsoleChannelManagerClass)) +#define GABBLE_IS_CONSOLE_CHANNEL_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER)) +#define GABBLE_IS_CONSOLE_CHANNEL_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER)) +#define GABBLE_CONSOLE_CHANNEL_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER,\ + GabbleConsoleChannelManagerClass)) diff --git a/plugins/console.c b/plugins/console/channel.c index fd49d0bd8..3ddbef905 100644 --- a/plugins/console.c +++ b/plugins/console/channel.c @@ -18,156 +18,27 @@ */ #include "config.h" - -#include "console.h" +#include "console/channel.h" #include <string.h> #include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> - -#include "extensions/extensions.h" - #include <gabble/gabble.h> +#include "extensions/extensions.h" -/************************* - * Plugin implementation * - *************************/ - -static guint debug = 0; - -#define DEBUG(format, ...) \ -G_STMT_START { \ - if (debug != 0) \ - g_debug ("%s: " format, G_STRFUNC, ## __VA_ARGS__); \ -} G_STMT_END - -static const GDebugKey debug_keys[] = { - { "console", 1 }, - { NULL, 0 } -}; - -static void plugin_iface_init ( - gpointer g_iface, - gpointer data); - -static const gchar * const sidecar_interfaces[] = { - GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, - NULL -}; - -G_DEFINE_TYPE_WITH_CODE (GabbleConsolePlugin, gabble_console_plugin, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_PLUGIN, plugin_iface_init); - ) - -static void -gabble_console_plugin_init (GabbleConsolePlugin *self) -{ -} - -static void -gabble_console_plugin_class_init (GabbleConsolePluginClass *klass) -{ -} - -static void -gabble_console_plugin_create_sidecar_async ( - GabblePlugin *plugin, - const gchar *sidecar_interface, - GabblePluginConnection *connection, - WockySession *session, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (plugin), - callback, user_data, - gabble_console_plugin_create_sidecar_async); - GabbleSidecar *sidecar = NULL; - - if (!tp_strdiff (sidecar_interface, GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE)) - { - sidecar = g_object_new (GABBLE_TYPE_CONSOLE_SIDECAR, - "connection", connection, - "session", session, - NULL); - } - else - { - g_simple_async_result_set_error (result, TP_ERROR, - TP_ERROR_NOT_IMPLEMENTED, "'%s' not implemented", sidecar_interface); - } - - if (sidecar != NULL) - g_simple_async_result_set_op_res_gpointer (result, sidecar, - g_object_unref); - - g_simple_async_result_complete_in_idle (result); - g_object_unref (result); -} - -static GabbleSidecar * -gabble_console_plugin_create_sidecar_finish ( - GabblePlugin *plugin, - GAsyncResult *result, - GError **error) -{ - GabbleSidecar *sidecar; - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), - error)) - return NULL; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, - G_OBJECT (plugin), gabble_console_plugin_create_sidecar_async), NULL); - - sidecar = GABBLE_SIDECAR (g_simple_async_result_get_op_res_gpointer ( - G_SIMPLE_ASYNC_RESULT (result))); - - return g_object_ref (sidecar); -} - -static void -plugin_iface_init ( - gpointer g_iface, - gpointer data G_GNUC_UNUSED) -{ - GabblePluginInterface *iface = g_iface; - - iface->name = "XMPP console"; - iface->version = PACKAGE_VERSION; - iface->sidecar_interfaces = sidecar_interfaces; - iface->create_sidecar_async = gabble_console_plugin_create_sidecar_async; - iface->create_sidecar_finish = gabble_console_plugin_create_sidecar_finish; -} - -GabblePlugin * -gabble_plugin_create (void) -{ - debug = g_parse_debug_string (g_getenv ("GABBLE_DEBUG"), debug_keys, - G_N_ELEMENTS (debug_keys) - 1); - DEBUG ("loaded"); - - return g_object_new (GABBLE_TYPE_CONSOLE_PLUGIN, - NULL); -} - -/************************** - * Sidecar implementation * - **************************/ +#include "console/debug.h" enum { PROP_0, - PROP_CONNECTION, - PROP_SESSION, PROP_SPEW }; -struct _GabbleConsoleSidecarPrivate +struct _GabbleConsoleChannelPrivate { WockySession *session; - TpBaseConnection *connection; WockyXmppReader *reader; WockyXmppWriter *writer; @@ -182,43 +53,58 @@ struct _GabbleConsoleSidecarPrivate gulong sending_id; }; -static void sidecar_iface_init ( - gpointer g_iface, - gpointer data); static void console_iface_init ( gpointer g_iface, gpointer data); -static void gabble_console_sidecar_set_spew ( - GabbleConsoleSidecar *self, +static void gabble_console_channel_set_spew ( + GabbleConsoleChannel *self, gboolean spew); +gchar *gabble_console_channel_get_path (TpBaseChannel *chan); +static void gabble_console_channel_close (TpBaseChannel *chan); -G_DEFINE_TYPE_WITH_CODE (GabbleConsoleSidecar, gabble_console_sidecar, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SIDECAR, sidecar_iface_init); +G_DEFINE_TYPE_WITH_CODE (GabbleConsoleChannel, gabble_console_channel, + TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_GABBLE_PLUGIN_CONSOLE, console_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); ) static void -gabble_console_sidecar_init (GabbleConsoleSidecar *self) +gabble_console_channel_init (GabbleConsoleChannel *self) { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_CONSOLE_SIDECAR, - GabbleConsoleSidecarPrivate); + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_CONSOLE_CHANNEL, + GabbleConsoleChannelPrivate); self->priv->reader = wocky_xmpp_reader_new_no_stream_ns ( WOCKY_XMPP_NS_JABBER_CLIENT); self->priv->writer = wocky_xmpp_writer_new_no_stream (); } + +static void +gabble_console_channel_constructed (GObject *object) +{ + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); + void (*chain_up)(GObject *) = + G_OBJECT_CLASS (gabble_console_channel_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (object); + + self->priv->session = g_object_ref ( + gabble_plugin_connection_get_session ( + GABBLE_PLUGIN_CONNECTION ( + tp_base_channel_get_connection ( + TP_BASE_CHANNEL (self))))); + g_return_if_fail (self->priv->session != NULL); +} + static void -gabble_console_sidecar_get_property ( +gabble_console_channel_get_property ( GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (object); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); switch (property_id) { @@ -232,28 +118,18 @@ gabble_console_sidecar_get_property ( } static void -gabble_console_sidecar_set_property ( +gabble_console_channel_set_property ( GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (object); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); switch (property_id) { - case PROP_CONNECTION: - g_assert (self->priv->connection == NULL); /* construct-only */ - self->priv->connection = g_value_dup_object (value); - break; - - case PROP_SESSION: - g_assert (self->priv->session == NULL); /* construct-only */ - self->priv->session = g_value_dup_object (value); - break; - case PROP_SPEW: - gabble_console_sidecar_set_spew (self, g_value_get_boolean (value)); + gabble_console_channel_set_spew (self, g_value_get_boolean (value)); break; default: @@ -262,15 +138,14 @@ gabble_console_sidecar_set_property ( } static void -gabble_console_sidecar_dispose (GObject *object) +gabble_console_channel_dispose (GObject *object) { void (*chain_up) (GObject *) = - G_OBJECT_CLASS (gabble_console_sidecar_parent_class)->dispose; - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (object); + G_OBJECT_CLASS (gabble_console_channel_parent_class)->dispose; + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (object); - gabble_console_sidecar_set_spew (self, FALSE); + gabble_console_channel_set_spew (self, FALSE); - tp_clear_object (&self->priv->connection); tp_clear_object (&self->priv->reader); tp_clear_object (&self->priv->writer); tp_clear_object (&self->priv->session); @@ -280,46 +155,25 @@ gabble_console_sidecar_dispose (GObject *object) } static void -gabble_console_sidecar_class_init (GabbleConsoleSidecarClass *klass) +gabble_console_channel_class_init (GabbleConsoleChannelClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + TpBaseChannelClass *channel_class = TP_BASE_CHANNEL_CLASS (klass); static TpDBusPropertiesMixinPropImpl console_props[] = { { "SpewStanzas", "spew-stanzas", "spew-stanzas" }, { NULL }, }; - static TpDBusPropertiesMixinIfaceImpl interfaces[] = { - { GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, - tp_dbus_properties_mixin_getter_gobject_properties, - /* FIXME: if we were feeling clever, we'd override the setter so that - * we can monitor the bus name of any application which sets - * SpewStanzas to TRUE and flip it back to false when that application - * dies. - * - * Alternatively, we could just replace this sidecar with a channel. - */ - tp_dbus_properties_mixin_setter_gobject_properties, - console_props - }, - { NULL }, - }; - - object_class->get_property = gabble_console_sidecar_get_property; - object_class->set_property = gabble_console_sidecar_set_property; - object_class->dispose = gabble_console_sidecar_dispose; - g_type_class_add_private (klass, sizeof (GabbleConsoleSidecarPrivate)); + object_class->constructed = gabble_console_channel_constructed; + object_class->get_property = gabble_console_channel_get_property; + object_class->set_property = gabble_console_channel_set_property; + object_class->dispose = gabble_console_channel_dispose; - g_object_class_install_property (object_class, PROP_CONNECTION, - g_param_spec_object ("connection", "Connection", - "Gabble connection", - GABBLE_TYPE_PLUGIN_CONNECTION, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + channel_class->channel_type = GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE; + channel_class->get_object_path_suffix = gabble_console_channel_get_path; + channel_class->close = gabble_console_channel_close; - g_object_class_install_property (object_class, PROP_SESSION, - g_param_spec_object ("session", "Session", - "Wocky session", - WOCKY_TYPE_SESSION, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_type_class_add_private (klass, sizeof (GabbleConsoleChannelPrivate)); g_object_class_install_property (object_class, PROP_SPEW, g_param_spec_boolean ("spew-stanzas", "SpewStanzas", @@ -327,19 +181,26 @@ gabble_console_sidecar_class_init (GabbleConsoleSidecarClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - klass->props_class.interfaces = interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleConsoleSidecarClass, props_class)); + tp_dbus_properties_mixin_implement_interface (object_class, + GABBLE_IFACE_QUARK_GABBLE_PLUGIN_CONSOLE, + tp_dbus_properties_mixin_getter_gobject_properties, + tp_dbus_properties_mixin_setter_gobject_properties, + console_props); } -static void sidecar_iface_init ( - gpointer g_iface, - gpointer data) +gchar * +gabble_console_channel_get_path (TpBaseChannel *chan) +{ + return g_strdup_printf ("console%p", chan); +} + +static void +gabble_console_channel_close (TpBaseChannel *chan) { - GabbleSidecarInterface *iface = g_iface; + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (chan); - iface->interface = GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE; - iface->get_immutable_properties = NULL; + gabble_console_channel_set_spew (self, FALSE); + tp_base_channel_destroyed (chan); } static gboolean @@ -348,7 +209,7 @@ incoming_cb ( WockyStanza *stanza, gpointer user_data) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (user_data); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (user_data); const guint8 *body; gsize length; @@ -364,7 +225,7 @@ sending_cb ( WockyStanza *stanza, gpointer user_data) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (user_data); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (user_data); if (stanza != NULL) { @@ -379,11 +240,11 @@ sending_cb ( } static void -gabble_console_sidecar_set_spew ( - GabbleConsoleSidecar *self, +gabble_console_channel_set_spew ( + GabbleConsoleChannel *self, gboolean spew) { - GabbleConsoleSidecarPrivate *priv = self->priv; + GabbleConsoleChannelPrivate *priv = self->priv; if (!spew != !priv->spew) { @@ -424,7 +285,7 @@ return_from_send_iq ( GAsyncResult *result, gpointer user_data) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (source); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (source); DBusGMethodInvocation *context = user_data; GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); GError *error = NULL; @@ -523,12 +384,12 @@ validate_jid (const gchar **to, */ static gboolean parse_me_a_stanza ( - GabbleConsoleSidecar *self, + GabbleConsoleChannel *self, const gchar *xml, WockyStanza **stanza_out, GError **error) { - GabbleConsoleSidecarPrivate *priv = self->priv; + GabbleConsoleChannelPrivate *priv = self->priv; WockyStanza *stanza; wocky_xmpp_reader_reset (priv->reader); @@ -554,13 +415,13 @@ parse_me_a_stanza ( static void console_send_iq ( - GabbleSvcGabblePluginConsole *sidecar, + GabbleSvcGabblePluginConsole *channel, const gchar *type_str, const gchar *to, const gchar *body, DBusGMethodInvocation *context) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (sidecar); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (channel); WockyPorter *porter = wocky_session_get_porter (self->priv->session); WockyStanzaSubType sub_type; WockyStanza *fragment; @@ -640,11 +501,11 @@ stanza_looks_coherent ( static void console_send_stanza ( - GabbleSvcGabblePluginConsole *sidecar, + GabbleSvcGabblePluginConsole *channel, const gchar *xml, DBusGMethodInvocation *context) { - GabbleConsoleSidecar *self = GABBLE_CONSOLE_SIDECAR (sidecar); + GabbleConsoleChannel *self = GABBLE_CONSOLE_CHANNEL (channel); WockyPorter *porter = wocky_session_get_porter (self->priv->session); WockyStanza *stanza = NULL; GError *error = NULL; diff --git a/plugins/console/channel.h b/plugins/console/channel.h new file mode 100644 index 000000000..7e41c5ad2 --- /dev/null +++ b/plugins/console/channel.h @@ -0,0 +1,53 @@ +/* XML console plugin + * + * Copyright © 2011 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 + */ + +#include <glib-object.h> +#include <telepathy-glib/telepathy-glib.h> + +typedef struct _GabbleConsoleChannel GabbleConsoleChannel; +typedef struct _GabbleConsoleChannelClass GabbleConsoleChannelClass; +typedef struct _GabbleConsoleChannelPrivate GabbleConsoleChannelPrivate; + +struct _GabbleConsoleChannel { + TpBaseChannel parent; + + GabbleConsoleChannelPrivate *priv; +}; + +struct _GabbleConsoleChannelClass { + TpBaseChannelClass parent; +}; + +GType gabble_console_channel_get_type (void); + +#define GABBLE_TYPE_CONSOLE_CHANNEL \ + (gabble_console_channel_get_type ()) +#define GABBLE_CONSOLE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GABBLE_TYPE_CONSOLE_CHANNEL, \ + GabbleConsoleChannel)) +#define GABBLE_CONSOLE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GABBLE_TYPE_CONSOLE_CHANNEL, \ + GabbleConsoleChannelClass)) +#define GABBLE_IS_CONSOLE_CHANNEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GABBLE_TYPE_CONSOLE_CHANNEL)) +#define GABBLE_IS_CONSOLE_CHANNEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GABBLE_TYPE_CONSOLE_CHANNEL)) +#define GABBLE_CONSOLE_CHANNEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_CHANNEL, \ + GabbleConsoleChannelClass)) diff --git a/src/legacy-caps.c b/plugins/console/debug.c index 827fc15ea..251549a6d 100644 --- a/src/legacy-caps.c +++ b/plugins/console/debug.c @@ -1,7 +1,6 @@ -/* - * legacy-caps.c - Connection.Interface.Capabilities constants and utilities - * Copyright (C) 2005 Collabora Ltd. - * Copyright (C) 2005 Nokia Corporation +/* XML console plugin + * + * Copyright © 2011 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 @@ -18,23 +17,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" -#include "legacy-caps.h" +#include <glib.h> -#include <telepathy-glib/telepathy-glib-dbus.h> +#include "console/debug.h" -#define DEBUG_FLAG GABBLE_DEBUG_PRESENCE -#include "debug.h" -#ifdef ENABLE_VOIP -#include "media-factory.h" -#endif +int gabble_console_debug = 0; -const CapabilityConversionData capabilities_conversions[] = -{ -#ifdef ENABLE_VOIP - { TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - _gabble_media_factory_typeflags_to_caps, - _gabble_media_factory_caps_to_typeflags }, -#endif - { NULL, NULL, NULL} +static const GDebugKey debug_keys[] = { + { "console", 1 }, + { NULL, 0 } }; + +void +gabble_console_debug_init (void) +{ + gabble_console_debug = g_parse_debug_string (g_getenv ("GABBLE_DEBUG"), + debug_keys, G_N_ELEMENTS (debug_keys) - 1); +} diff --git a/src/legacy-caps.h b/plugins/console/debug.h index e2de46c37..afe94c922 100644 --- a/src/legacy-caps.h +++ b/plugins/console/debug.h @@ -1,7 +1,6 @@ -/* - * legacy-caps.h - Connection.Interface.Capabilities constants and utilities - * Copyright (C) 2005 Collabora Ltd. - * Copyright (C) 2005 Nokia Corporation +/* XML console plugin + * + * Copyright © 2011 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 @@ -18,25 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __GABBLE_LEGACY_CAPS__H__ -#define __GABBLE_LEGACY_CAPS__H__ - -#include <glib-object.h> - -#include "gabble/capabilities.h" - -typedef void (*TypeFlagsToCapsFunc) (guint typeflags, GabbleCapabilitySet *caps); -typedef guint (*CapsToTypeFlagsFunc) (const GabbleCapabilitySet *caps); - -typedef struct _CapabilityConversionData CapabilityConversionData; - -struct _CapabilityConversionData -{ - const gchar *iface; - TypeFlagsToCapsFunc tf2c_fn; - CapsToTypeFlagsFunc c2tf_fn; -}; +extern int gabble_console_debug; -extern const CapabilityConversionData capabilities_conversions[]; +#define DEBUG(format, ...) \ +G_STMT_START { \ + if (gabble_console_debug != 0) \ + g_debug ("%s: " format, G_STRFUNC, ## __VA_ARGS__); \ +} G_STMT_END -#endif +void gabble_console_debug_init (void); diff --git a/plugins/console/plugin.c b/plugins/console/plugin.c new file mode 100644 index 000000000..c17cf71b0 --- /dev/null +++ b/plugins/console/plugin.c @@ -0,0 +1,91 @@ +/* XML console plugin + * + * Copyright © 2011 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 + */ + +#include "config.h" +#include "console/plugin.h" + +#include <telepathy-glib/telepathy-glib.h> +#include <wocky/wocky.h> +#include <gabble/gabble.h> +#include "extensions/extensions.h" + +#include "console/channel-manager.h" +#include "console/channel.h" +#include "console/debug.h" + +static void plugin_iface_init ( + gpointer g_iface, + gpointer data); + +static const gchar * const sidecar_interfaces[] = { + GABBLE_IFACE_GABBLE_PLUGIN_CONSOLE, + NULL +}; + +G_DEFINE_TYPE_WITH_CODE (GabbleConsolePlugin, gabble_console_plugin, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GABBLE_TYPE_PLUGIN, plugin_iface_init); + ) + +static void +gabble_console_plugin_init (GabbleConsolePlugin *self) +{ +} + +static void +gabble_console_plugin_class_init (GabbleConsolePluginClass *klass) +{ +} + +static GPtrArray * +gabble_console_plugin_create_channel_managers (GabblePlugin *plugin, + GabblePluginConnection *plugin_connection) +{ + GPtrArray *ret = g_ptr_array_new (); + + g_ptr_array_add (ret, + g_object_new (GABBLE_TYPE_CONSOLE_CHANNEL_MANAGER, + "plugin-connection", plugin_connection, + NULL)); + + return ret; +} + +static void +plugin_iface_init ( + gpointer g_iface, + gpointer data G_GNUC_UNUSED) +{ + GabblePluginInterface *iface = g_iface; + + iface->name = "XMPP console"; + iface->version = PACKAGE_VERSION; + iface->create_channel_managers = gabble_console_plugin_create_channel_managers; +} + +GabblePlugin * +gabble_plugin_create (void) +{ + gabble_console_debug_init (); + + DEBUG ("loaded"); + + return g_object_new (GABBLE_TYPE_CONSOLE_PLUGIN, + NULL); +} diff --git a/plugins/console.h b/plugins/console/plugin.h index e646d067e..153484f91 100644 --- a/plugins/console.h +++ b/plugins/console/plugin.h @@ -19,10 +19,6 @@ #include <glib-object.h> -#include <gio/gio.h> -#include <wocky/wocky.h> -#include <telepathy-glib/telepathy-glib.h> - typedef struct _GabbleConsolePlugin GabbleConsolePlugin; typedef struct _GabbleConsolePluginClass GabbleConsolePluginClass; typedef struct _GabbleConsolePluginPrivate GabbleConsolePluginPrivate; @@ -53,36 +49,3 @@ GType gabble_console_plugin_get_type (void); #define GABBLE_CONSOLE_PLUGIN_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_PLUGIN, \ GabbleConsolePluginClass)) - -typedef struct _GabbleConsoleSidecar GabbleConsoleSidecar; -typedef struct _GabbleConsoleSidecarClass GabbleConsoleSidecarClass; -typedef struct _GabbleConsoleSidecarPrivate GabbleConsoleSidecarPrivate; - -struct _GabbleConsoleSidecar { - GObject parent; - GabbleConsoleSidecarPrivate *priv; -}; - -struct _GabbleConsoleSidecarClass { - GObjectClass parent; - - TpDBusPropertiesMixinClass props_class; -}; - -GType gabble_console_sidecar_get_type (void); - -#define GABBLE_TYPE_CONSOLE_SIDECAR \ - (gabble_console_sidecar_get_type ()) -#define GABBLE_CONSOLE_SIDECAR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GABBLE_TYPE_CONSOLE_SIDECAR, \ - GabbleConsoleSidecar)) -#define GABBLE_CONSOLE_SIDECAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GABBLE_TYPE_CONSOLE_SIDECAR, \ - GabbleConsoleSidecarClass)) -#define GABBLE_IS_CONSOLE_SIDECAR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GABBLE_TYPE_CONSOLE_SIDECAR)) -#define GABBLE_IS_CONSOLE_SIDECAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GABBLE_TYPE_CONSOLE_SIDECAR)) -#define GABBLE_CONSOLE_SIDECAR_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_CONSOLE_SIDECAR, \ - GabbleConsoleSidecarClass)) diff --git a/plugins/telepathy-gabble-xmpp-console b/plugins/telepathy-gabble-xmpp-console index 8b96469d8..a72c92b55 100755 --- a/plugins/telepathy-gabble-xmpp-console +++ b/plugins/telepathy-gabble-xmpp-console @@ -3,10 +3,10 @@ """ The world's worst XMPP console user interface. -Pass it the bus name of a Gabble connection; type some words; get minimalistic +Pass it a Gabble account name; type some words; get minimalistic error reporting. -Copyright © 2011 Collabora Ltd. <http://www.collabora.co.uk/> +Copyright © 2011–2013 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 @@ -24,23 +24,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ import sys -import re from xml.dom import minidom -from gi.repository import Gtk -from gi.repository import GLib -from gi.repository import Gio -from gi.repository import GtkSource +from gi.repository import Gtk, GLib, Gio, GtkSource +from gi.repository import TelepathyGLib as Tp PADDING = 6 -def pathify(name): - return '/' + name.replace('.', '/') - -def nameify(path): - return (path[1:]).replace('/', '.') - -CONN_FUTURE_IFACE = "org.freedesktop.Telepathy.Connection.FUTURE" CONSOLE_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Console" class StanzaViewer(Gtk.ScrolledWindow): @@ -302,32 +292,27 @@ class Window(Gtk.Window): STANZA_PAGE = 1 SNOOPY_PAGE = 2 - def __init__(self, bus, connection_bus_name): + def __init__(self, account): Gtk.Window.__init__(self) self.set_title('XMPP Console') self.set_default_size(600, 371) - conn_future_proxy = Gio.DBusProxy.new_sync(bus, 0, None, - connection_bus_name, pathify(connection_bus_name), - CONN_FUTURE_IFACE, None) - try: - sidecar_path, _ = conn_future_proxy.EnsureSidecar('(s)', CONSOLE_IFACE) - except Exception, e: - print """ -Couldn't connect to the XMPP console interface on '%(connection_bus_name)s': - %(e)s -Check that it's a running Jabber connection, and that you have the console -plugin installed.""" % locals() + request = Tp.AccountChannelRequest.new( + account, + { Tp.PROP_CHANNEL_CHANNEL_TYPE: CONSOLE_IFACE }, + 0) + request.create_and_handle_channel_async(None, self.__create_cb, None) - raise SystemExit(2) - - self.console_proxy = Gio.DBusProxy.new_sync(bus, 0, None, - connection_bus_name, sidecar_path, CONSOLE_IFACE, None) + self.connect('destroy', Window.__destroy_cb) + def __build_ui(self): # Build up the UI + self.grid = Gtk.Grid() + self.add(self.grid) + self.nb = Gtk.Notebook() - self.add(self.nb) + self.grid.attach(self.nb, 0, 0, 1, 1) self.iq = IQPage(self.console_proxy) self.nb.insert_page(self.iq, @@ -344,57 +329,103 @@ plugin installed.""" % locals() Gtk.Label.new_with_mnemonic("_Monitor network traffic"), self.SNOOPY_PAGE) - self.connect('destroy', Window.__destroy_cb) + self.infobar = Gtk.InfoBar() + self.infobar.set_message_type(Gtk.MessageType.WARNING) + self.infobar.set_no_show_all(True) + label = Gtk.Label("The connection went away! Time to leave.") + label.show() + self.infobar.get_content_area().add(label) + self.infobar_close_button = self.infobar.add_button("Close", Gtk.ResponseType.CLOSE) + self.infobar.connect('response', lambda infobar, response: Gtk.main_quit()) + self.infobar.connect('close', lambda infobar: Gtk.main_quit()) + + self.grid.attach_next_to(self.infobar, self.nb, + Gtk.PositionType.BOTTOM, 1, 1) + + def __create_cb(self, request, result, _): + try: + channel, context = request.create_and_handle_channel_finish(result) + channel.connect('invalidated', self.__channel_invalidated_cb) + + bus_name = channel.get_bus_name() + sidecar_path = channel.get_object_path() + + bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) + self.console_proxy = Gio.DBusProxy.new_sync(bus, 0, None, + bus_name, sidecar_path, CONSOLE_IFACE, None) + + except GLib.GError as e: + print """ +Couldn't connect to the XMPP console interface on '%(name)s': +%(e)s +Check that you have the console plugin installed.""" % { + 'name': request.get_account().get_path_suffix(), + 'e': e, + } + raise SystemExit(2) + + self.__build_ui() + self.show_all() + + def __channel_invalidated_cb(self, channel, domain, code, message): + self.infobar.show() + self.infobar_close_button.grab_focus() + self.nb.set_sensitive(False) + # TODO: try to reconnect? def __destroy_cb(self): - self.snoopy.teardown() + try: + self.snoopy.teardown() + except GLib.GError, e: + print "Couldn't turn off the monitor (maybe the connection went away?)" + print e Gtk.main_quit() -GABBLE_PREFIX = 'org.freedesktop.Telepathy.Connection.gabble.jabber.' - -AM_BUS_NAME = 'org.freedesktop.Telepathy.AccountManager' -ACCOUNT_PREFIX = '/org/freedesktop/Telepathy/Account' -ACCOUNT_IFACE = 'org.freedesktop.Telepathy.Account' +def usage(am): + xmpp_accounts = sorted( + account.get_path_suffix() + for account in am.dup_valid_accounts() + if account.get_cm_name() == 'gabble') -def usage(): print """ Usage: %(arg0)s gabble/jabber/blahblah - %(arg0)s %(prefix)sblahblah -List account identifiers using `mc-tool list | grep gabble`. -List connection bus names using `qdbus | grep gabble`. +Here are some account identifiers: + + %(accounts)s """ % { 'arg0': sys.argv[0], - 'prefix': GABBLE_PREFIX, + 'accounts': '\n '.join(xmpp_accounts), } raise SystemExit(1) -if __name__ == '__main__': - bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) - - if len(sys.argv) != 2: - usage() - - thing = sys.argv[1] - - if re.match('^gabble/jabber/[a-zA-Z0-9_]+$', thing): - # Looks like an account path to me. - account_proxy = Gio.DBusProxy.new_sync(bus, 0, None, - AM_BUS_NAME, '%s/%s' % (ACCOUNT_PREFIX, thing), - ACCOUNT_IFACE, None) - path = account_proxy.get_cached_property('Connection').get_string() - if path == '/': - print "%s is not online" % thing - raise SystemExit(1) - else: - thing = nameify(path) +def am_prepared_cb(am, result, account_suffix): + try: + am.prepare_finish(result) + except GLib.GError as e: + print e + raise SystemExit(2) + + if account_suffix is None: + usage(am) - if not re.match('^%s[a-zA-Z0-9_]+$' % GABBLE_PREFIX, thing): - usage() + for account in am.dup_valid_accounts(): + if account.get_path_suffix() == account_suffix: + if account.get_connection() is None: + print "%s is not online." % account_suffix + raise SystemExit(2) + else: + win = Window(account) + return + + usage(am) + +if __name__ == '__main__': + account_suffix = sys.argv[1] if len(sys.argv) == 2 else None - win = Window(bus, thing) - win.show_all() + am = Tp.AccountManager.dup() + am.prepare_async([], am_prepared_cb, account_suffix) Gtk.main() diff --git a/plugins/test.c b/plugins/test.c index bb6b71959..e084b00e2 100644 --- a/plugins/test.c +++ b/plugins/test.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> diff --git a/src/Makefile.am b/src/Makefile.am index 22a0278db..6f5b47c71 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -73,8 +73,6 @@ libgabble_convenience_la_SOURCES = \ im-channel.c \ im-factory.h \ im-factory.c \ - legacy-caps.h \ - legacy-caps.c \ message-util.h \ message-util.c \ muc-channel.h \ @@ -163,12 +161,6 @@ libgabble_convenience_la_SOURCES += \ jingle-mint.c \ jingle-tp-util.h \ jingle-tp-util.c \ - media-channel.h \ - media-channel-internal.h \ - media-channel.c \ - media-channel-hold.c \ - media-stream.h \ - media-stream.c \ media-factory.h \ media-factory.c endif diff --git a/src/call-stream.c b/src/call-stream.c index 89af93ce1..4653ff626 100644 --- a/src/call-stream.c +++ b/src/call-stream.c @@ -101,7 +101,7 @@ get_stun_servers (GabbleCallStream *self) WockyJingleFactory *jf; GList *stun_servers; - arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free); + arr = g_ptr_array_new_with_free_func ((GDestroyNotify) tp_value_array_free); 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)); @@ -250,7 +250,7 @@ _endpoint_state_changed_cb ( GParamSpec *spec, WockyJingleContent *content) { - TpMediaStreamState state; + TpStreamEndpointState state; /* We only care about connecting RTP, RTCP is optional */ state = tp_call_stream_endpoint_get_state (endpoint, 1); diff --git a/src/conn-addressing.c b/src/conn-addressing.c index 7fff35455..60431159d 100644 --- a/src/conn-addressing.c +++ b/src/conn-addressing.c @@ -34,7 +34,7 @@ static const char *assumed_interfaces[] = { TP_IFACE_CONNECTION, - GABBLE_IFACE_CONNECTION_INTERFACE_ADDRESSING, + TP_IFACE_CONNECTION_INTERFACE_ADDRESSING, NULL }; @@ -48,11 +48,11 @@ _fill_contact_attributes (TpHandleRepoIface *contact_repo, GHashTable *addresses = gabble_vcard_addresses_for_handle (contact_repo, contact); tp_contacts_mixin_set_contact_attribute (attributes_hash, - contact, GABBLE_IFACE_CONNECTION_INTERFACE_ADDRESSING"/uris", + contact, TP_TOKEN_CONNECTION_INTERFACE_ADDRESSING_URIS, tp_g_value_slice_new_take_boxed (G_TYPE_STRV, uris)); tp_contacts_mixin_set_contact_attribute (attributes_hash, - contact, GABBLE_IFACE_CONNECTION_INTERFACE_ADDRESSING"/addresses", + contact, TP_TOKEN_CONNECTION_INTERFACE_ADDRESSING_ADDRESSES, tp_g_value_slice_new_take_boxed (TP_HASH_TYPE_STRING_STRING_MAP, addresses)); } @@ -73,7 +73,7 @@ conn_addressing_fill_contact_attributes (GObject *obj, } static void -conn_addressing_get_contacts_by_uri (GabbleSvcConnectionInterfaceAddressing *iface, +conn_addressing_get_contacts_by_uri (TpSvcConnectionInterfaceAddressing *iface, const gchar **uris, const gchar **interfaces, DBusGMethodInvocation *context) @@ -101,7 +101,7 @@ conn_addressing_get_contacts_by_uri (GabbleSvcConnectionInterfaceAddressing *ifa attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (iface), handles, interfaces, assumed_interfaces, sender); - gabble_svc_connection_interface_addressing_return_from_get_contacts_by_uri ( + tp_svc_connection_interface_addressing_return_from_get_contacts_by_uri ( context, requested, attributes); g_array_unref (handles); @@ -111,7 +111,7 @@ conn_addressing_get_contacts_by_uri (GabbleSvcConnectionInterfaceAddressing *ifa } static void -conn_addressing_get_contacts_by_vcard_field (GabbleSvcConnectionInterfaceAddressing *iface, +conn_addressing_get_contacts_by_vcard_field (TpSvcConnectionInterfaceAddressing *iface, const gchar *field, const gchar **addresses, const gchar **interfaces, @@ -141,7 +141,7 @@ conn_addressing_get_contacts_by_vcard_field (GabbleSvcConnectionInterfaceAddress attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (iface), handles, interfaces, assumed_interfaces, sender); - gabble_svc_connection_interface_addressing_return_from_get_contacts_by_vcard_field ( + tp_svc_connection_interface_addressing_return_from_get_contacts_by_vcard_field ( context, requested, attributes); g_array_unref (handles); @@ -153,7 +153,7 @@ conn_addressing_get_contacts_by_vcard_field (GabbleSvcConnectionInterfaceAddress void conn_addressing_init (GabbleConnection *self) { tp_contacts_mixin_add_contact_attributes_iface (G_OBJECT (self), - GABBLE_IFACE_CONNECTION_INTERFACE_ADDRESSING, + TP_IFACE_CONNECTION_INTERFACE_ADDRESSING, conn_addressing_fill_contact_attributes); } @@ -162,7 +162,7 @@ conn_addressing_iface_init (gpointer g_iface, gpointer iface_data) { #define IMPLEMENT(x) \ - gabble_svc_connection_interface_addressing_implement_##x (\ + tp_svc_connection_interface_addressing_implement_##x (\ g_iface, conn_addressing_##x) IMPLEMENT (get_contacts_by_uri); diff --git a/src/conn-aliasing.c b/src/conn-aliasing.c index 26637039e..e5bef80f7 100644 --- a/src/conn-aliasing.c +++ b/src/conn-aliasing.c @@ -39,16 +39,12 @@ static void gabble_conn_aliasing_pep_nick_reply_handler ( GabbleConnection *conn, WockyStanza *msg, TpHandle handle); -static GQuark gabble_conn_aliasing_pep_alias_quark (void); static GabbleConnectionAliasSource _gabble_connection_get_cached_remote_alias ( GabbleConnection *, TpHandle, gchar **); static void maybe_request_vcard (GabbleConnection *self, TpHandle handle, GabbleConnectionAliasSource source); -/* distinct from any strdup()d pointer - used for negative caching */ -static const gchar *NO_ALIAS = ""; - /** * gabble_connection_get_alias_flags * @@ -202,12 +198,10 @@ static void _cache_negatively (GabbleConnection *self, TpHandle handle) { - TpBaseConnection *base = (TpBaseConnection *) self; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles (base, - TP_HANDLE_TYPE_CONTACT); - - tp_handle_set_qdata (contact_handles, handle, - gabble_conn_aliasing_pep_alias_quark (), (gchar *) NO_ALIAS, NULL); + /* We don't actually need to distinguish between "uncached" and + * "known to have no alias" because of how PEP works, so just + * remove it from the cache. */ + g_hash_table_remove (self->pep_alias_cache, GUINT_TO_POINTER (handle)); } /* Cache pep if successful */ @@ -476,7 +470,6 @@ nick_publish_msg_reply_cb (GabbleConnection *conn, GObject *object, gpointer user_data) { -#ifdef ENABLE_DEBUG GError *error = NULL; if (wocky_stanza_extract_errors (reply_msg, NULL, &error, NULL, NULL)) @@ -486,7 +479,6 @@ nick_publish_msg_reply_cb (GabbleConnection *conn, g_clear_error (&error); } -#endif } static gboolean @@ -632,20 +624,6 @@ gabble_connection_set_aliases (TpSvcConnectionInterfaceAliasing *iface, } } - -GQuark -gabble_conn_aliasing_pep_alias_quark (void) -{ - static GQuark quark = 0; - - if (G_UNLIKELY (quark == 0)) - quark = g_quark_from_static_string - ("gabble_conn_aliasing_pep_alias_quark"); - - return quark; -} - - static gboolean _grab_nickname (GabbleConnection *self, TpHandle handle, @@ -654,7 +632,6 @@ _grab_nickname (GabbleConnection *self, TpBaseConnection *base = (TpBaseConnection *) self; TpHandleRepoIface *contact_handles = tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT); - GQuark quark = gabble_conn_aliasing_pep_alias_quark (); const gchar *old, *nickname; node = wocky_node_get_child_ns (node, "nick", NS_NICK); @@ -668,23 +645,26 @@ _grab_nickname (GabbleConnection *self, } nickname = node->content; - old = tp_handle_get_qdata (contact_handles, handle, quark); + + old = g_hash_table_lookup (self->pep_alias_cache, GUINT_TO_POINTER (handle)); if (tp_strdiff (old, nickname)) { if (nickname == NULL) { - DEBUG ("got empty <nick/> node, caching as NO_ALIAS"); + DEBUG ("got empty <nick/> node, caching negatively"); _cache_negatively (self, handle); } else { - tp_handle_set_qdata (contact_handles, handle, quark, g_strdup (nickname), - g_free); + DEBUG ("caching positively"); + g_hash_table_insert (self->pep_alias_cache, GUINT_TO_POINTER (handle), + g_strdup (nickname)); } gabble_conn_aliasing_nickname_updated ((GObject *) self, handle, self); } + return TRUE; } @@ -909,9 +889,9 @@ get_cached_remote_alias ( const gchar *tmp; gchar *resource; - tmp = tp_handle_get_qdata (contact_handles, handle, - gabble_conn_aliasing_pep_alias_quark ()); - if (tmp != NULL && tmp != NO_ALIAS) + tmp = g_hash_table_lookup (conn->pep_alias_cache, GUINT_TO_POINTER (handle)); + + if (tmp != NULL) { maybe_set (alias, tmp); return GABBLE_CONNECTION_ALIAS_FROM_PRESENCE; @@ -1183,12 +1163,19 @@ conn_aliasing_init (GabbleConnection *conn) conn_aliasing_fill_contact_attributes); conn->pep_nick = wocky_pep_service_new (NS_NICK, TRUE); + conn->pep_alias_cache = g_hash_table_new_full (NULL, NULL, NULL, g_free); g_signal_connect (conn->pep_nick, "changed", G_CALLBACK (pep_nick_node_changed), conn); } void +conn_aliasing_finalize (GabbleConnection *conn) +{ + tp_clear_pointer (&conn->pep_alias_cache, g_hash_table_unref); +} + +void conn_aliasing_iface_init (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceAliasingClass *klass = g_iface; diff --git a/src/conn-aliasing.h b/src/conn-aliasing.h index 353e3238e..d165449b4 100644 --- a/src/conn-aliasing.h +++ b/src/conn-aliasing.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS void conn_aliasing_init (GabbleConnection *conn); +void conn_aliasing_finalize (GabbleConnection *conn); void conn_aliasing_iface_init (gpointer g_iface, gpointer iface_data); void gabble_conn_aliasing_nickname_updated (GObject *object, diff --git a/src/conn-avatars.c b/src/conn-avatars.c index a90555113..681a04df4 100644 --- a/src/conn-avatars.c +++ b/src/conn-avatars.c @@ -991,3 +991,37 @@ conn_avatars_properties_getter (GObject *object, g_value_set_uint (value, GPOINTER_TO_UINT (getter_data)); } } + +void +gabble_connection_dup_avatar_requirements (GStrv *supported_mime_types, + guint *min_height, + guint *min_width, + guint *rec_height, + guint *rec_width, + guint *max_height, + guint *max_width, + guint *max_bytes) +{ + if (supported_mime_types != NULL) + { + *supported_mime_types = g_strdupv ((gchar **) mimetypes); + } + + if (min_height != NULL) + *min_height = AVATAR_MIN_PX; + if (min_width != NULL) + *min_width = AVATAR_MIN_PX; + + if (rec_height != NULL) + *rec_height = AVATAR_REC_PX; + if (rec_width != NULL) + *rec_width = AVATAR_REC_PX; + + if (max_height != NULL) + *max_height = AVATAR_MAX_PX; + if (max_width != NULL) + *max_width = AVATAR_MAX_PX; + + if (max_bytes != NULL) + *max_bytes = AVATAR_MAX_BYTES; +} diff --git a/src/conn-avatars.h b/src/conn-avatars.h index 0e2899f24..a26506d0c 100644 --- a/src/conn-avatars.h +++ b/src/conn-avatars.h @@ -32,6 +32,15 @@ extern TpDBusPropertiesMixinPropImpl *conn_avatars_properties; void conn_avatars_properties_getter (GObject *object, GQuark interface, GQuark name, GValue *value, gpointer getter_data); +void gabble_connection_dup_avatar_requirements (GStrv *supported_mime_types, + guint *min_height, + guint *min_width, + guint *rec_height, + guint *rec_width, + guint *max_height, + guint *max_width, + guint *max_bytes); + G_END_DECLS #endif /* __CONN_AVATARS_H__ */ diff --git a/src/conn-client-types.c b/src/conn-client-types.c index 1a5ff1e8f..2947534c0 100644 --- a/src/conn-client-types.c +++ b/src/conn-client-types.c @@ -132,6 +132,44 @@ client_types_get_client_types (TpSvcConnectionInterfaceClientTypes *iface, g_hash_table_unref (client_types); } +static void +client_types_request_client_types (TpSvcConnectionInterfaceClientTypes *iface, + TpHandle contact, + DBusGMethodInvocation *context) +{ + GabbleConnection *conn = GABBLE_CONNECTION (iface); + TpBaseConnection *base = (TpBaseConnection *) conn; + TpHandleRepoIface *contact_handles; + GError *error = NULL; + gchar **types; + + /* Validate contact */ + contact_handles = tp_base_connection_get_handles (base, + TP_HANDLE_TYPE_CONTACT); + + if (!tp_handle_is_valid (contact_handles, contact, &error)) + { + dbus_g_method_return_error (context, error); + g_error_free (error); + return; + } + + DEBUG ("RequestClientTypes called on the following handle: %u", contact); + + if (!get_client_types_from_handle (conn, contact, &types)) + { + /* FIXME fdo#70140 : we should wait for the disco reply before + * returning. */ + static gchar *empty[] = { NULL }; + types = g_strdupv (empty); + } + + tp_svc_connection_interface_client_types_return_from_request_client_types ( + context, (const gchar **) types); + + g_strfreev (types); +} + void conn_client_types_iface_init (gpointer g_iface, gpointer iface_data) @@ -141,6 +179,7 @@ conn_client_types_iface_init (gpointer g_iface, #define IMPLEMENT(x) tp_svc_connection_interface_client_types_implement_##x \ (klass, client_types_##x) IMPLEMENT (get_client_types); + IMPLEMENT (request_client_types); #undef IMPLEMENT } diff --git a/src/conn-location.c b/src/conn-location.c index ae78d68be..b51196641 100644 --- a/src/conn-location.c +++ b/src/conn-location.c @@ -439,28 +439,21 @@ conn_location_properties_getter (GObject *object, } else if (!tp_strdiff (g_quark_to_string (name), "LocationAccessControl")) { - GValueArray *access_control = g_value_array_new (2); - GValue type = {0,}; - GValue variant = {0,}; - GValue *allocated_value; - - /* G_TYPE_UINT is the D-Bus type of TpRichPresenceAccessControlType */ - g_value_init (&type, G_TYPE_UINT); - g_value_set_uint (&type, - TP_RICH_PRESENCE_ACCESS_CONTROL_TYPE_PUBLISH_LIST); - g_value_array_append (access_control, &type); - g_value_unset (&type); - - g_value_init (&variant, G_TYPE_VALUE); + GValueArray *access_control; + GValue dummy = G_VALUE_INIT; + /* For Publish_List, the variant isn't used, so we set a dummy value, * (guint) 0 */ - allocated_value = tp_g_value_slice_new (G_TYPE_UINT); - g_value_set_uint (allocated_value, 0); - g_value_set_boxed (&variant, allocated_value); - g_value_array_append (access_control, &variant); - g_value_unset (&variant); - tp_g_value_slice_free (allocated_value); + g_value_init (&dummy, G_TYPE_UINT); + g_value_set_uint (&dummy, 0); + + access_control = tp_value_array_build (2, + G_TYPE_UINT, + (guint) TP_RICH_PRESENCE_ACCESS_CONTROL_TYPE_PUBLISH_LIST, + G_TYPE_VALUE, &dummy, + G_TYPE_INVALID); + g_value_unset (&dummy); g_value_take_boxed (value, access_control); } else if (name == g_quark_from_static_string ("SupportedLocationFeatures")) @@ -486,9 +479,9 @@ conn_location_properties_setter (GObject *object, gpointer setter_data, GError **error) { - GValueArray *access_control; - GValue *access_control_type_value; - TpRichPresenceAccessControlType access_control_type; + guint access_control_type; + GValue *access_control_argument; + g_return_val_if_fail (interface == TP_IFACE_QUARK_CONNECTION_INTERFACE_LOCATION, FALSE); @@ -496,17 +489,13 @@ conn_location_properties_setter (GObject *object, * already checked this. */ g_assert (name == g_quark_from_static_string ("LocationAccessControl")); - access_control = g_value_get_boxed (value); - - /* TpDBusPropertiesMixin already checked this */ - g_assert (access_control->n_values == 2); - - access_control_type_value = g_value_array_get_nth (access_control, 0); - - /* TpDBusPropertiesMixin already checked this */ - g_assert (G_VALUE_TYPE (access_control_type_value) == G_TYPE_UINT); + /* TpDBusPropertiesMixin already checked that it was a (uv). */ + g_assert (G_VALUE_HOLDS (value, + TP_STRUCT_TYPE_RICH_PRESENCE_ACCESS_CONTROL)); - access_control_type = g_value_get_uint (access_control_type_value); + tp_value_array_unpack (g_value_get_boxed (value), 2, + &access_control_type, + &access_control_argument); if (access_control_type != TP_RICH_PRESENCE_ACCESS_CONTROL_TYPE_PUBLISH_LIST) diff --git a/src/conn-mail-notif.c b/src/conn-mail-notif.c index 0bc7169f8..afefdf7de 100644 --- a/src/conn-mail-notif.c +++ b/src/conn-mail-notif.c @@ -123,7 +123,7 @@ return_from_request_inbox_url (GabbleConnection *conn) if (error == NULL) { - g_value_array_free (result); + tp_value_array_free (result); g_ptr_array_unref (empty_array); } else @@ -214,7 +214,7 @@ gabble_mail_notification_request_mail_url ( tp_svc_connection_interface_mail_notification_return_from_request_mail_url ( context, result); - g_value_array_free (result); + tp_value_array_free (result); g_ptr_array_unref (empty_array); g_free (url); } diff --git a/src/conn-sidecars.c b/src/conn-sidecars.c index d2dd57eca..87407a485 100644 --- a/src/conn-sidecars.c +++ b/src/conn-sidecars.c @@ -178,7 +178,7 @@ create_sidecar_cb ( GList *l; for (l = contexts; l != NULL; l = l->next) - gabble_svc_connection_future_return_from_ensure_sidecar (l->data, + tp_svc_connection_interface_sidecars1_return_from_ensure_sidecar (l->data, path, props); g_hash_table_unref (props); @@ -200,7 +200,7 @@ out: static void gabble_connection_ensure_sidecar ( - GabbleSvcConnectionFUTURE *iface, + TpSvcConnectionInterfaceSidecars1 *iface, const gchar *sidecar_iface, DBusGMethodInvocation *context) { @@ -238,7 +238,7 @@ gabble_connection_ensure_sidecar ( GHashTable *props = gabble_sidecar_get_immutable_properties (sidecar); DEBUG ("sidecar %s already exists at %s", sidecar_iface, path); - gabble_svc_connection_future_return_from_ensure_sidecar (context, path, + tp_svc_connection_interface_sidecars1_return_from_ensure_sidecar (context, path, props); g_free (path); @@ -340,14 +340,12 @@ sidecars_conn_status_changed_cb ( } void -conn_future_iface_init ( - gpointer g_iface, - gpointer iface_data) +conn_sidecars_iface_init (gpointer g_iface) { - GabbleSvcConnectionFUTUREClass *klass = g_iface; + TpSvcConnectionInterfaceSidecars1Class *klass = g_iface; #define IMPLEMENT(x) \ - gabble_svc_connection_future_implement_##x (\ + tp_svc_connection_interface_sidecars1_implement_##x (\ klass, gabble_connection_##x) IMPLEMENT (ensure_sidecar); #undef IMPLEMENT diff --git a/src/conn-sidecars.h b/src/conn-sidecars.h index 46e076c08..a2459a876 100644 --- a/src/conn-sidecars.h +++ b/src/conn-sidecars.h @@ -27,7 +27,7 @@ G_BEGIN_DECLS void conn_sidecars_init (GabbleConnection *conn); void conn_sidecars_dispose (GabbleConnection *conn); -void conn_future_iface_init (gpointer g_iface, gpointer iface_data); +void conn_sidecars_iface_init (gpointer g_iface); G_END_DECLS diff --git a/src/connection.c b/src/connection.c index 4bc10fc40..598e57171 100644 --- a/src/connection.c +++ b/src/connection.c @@ -57,7 +57,6 @@ #include "debug.h" #include "disco.h" #include "im-factory.h" -#include "legacy-caps.h" #include "muc-factory.h" #include "namespaces.h" #include "presence-cache.h" @@ -76,7 +75,6 @@ #include "conn-addressing.h" #ifdef ENABLE_VOIP -#include "media-channel.h" #include "media-factory.h" #endif @@ -84,10 +82,7 @@ static guint disco_reply_timeout = 5; #define DISCONNECT_TIMEOUT 5 -static void capabilities_service_iface_init (gpointer, gpointer); static void gabble_conn_contact_caps_iface_init (gpointer, gpointer); -static void conn_capabilities_fill_contact_attributes (GObject *obj, - const GArray *contacts, GHashTable *attributes_hash); static void conn_contact_capabilities_fill_contact_attributes (GObject *obj, const GArray *contacts, GHashTable *attributes_hash); static void gabble_plugin_connection_iface_init ( @@ -107,8 +102,6 @@ G_DEFINE_TYPE_WITH_CODE(GabbleConnection, conn_avatars_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO, conn_contact_info_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CAPABILITIES, - capabilities_service_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, tp_dbus_properties_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS, @@ -132,15 +125,15 @@ G_DEFINE_TYPE_WITH_CODE(GabbleConnection, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, gabble_conn_contact_caps_iface_init); - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CONNECTION_FUTURE, - conn_future_iface_init); + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIDECARS1, + conn_sidecars_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_MAIL_NOTIFICATION, conn_mail_notif_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CLIENT_TYPES, conn_client_types_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_POWER_SAVING, conn_power_saving_iface_init); - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CONNECTION_INTERFACE_ADDRESSING, + G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_ADDRESSING, conn_addressing_iface_init); G_IMPLEMENT_INTERFACE (GABBLE_TYPE_PLUGIN_CONNECTION, gabble_plugin_connection_iface_init); @@ -251,11 +244,8 @@ struct _GabbleConnectionPrivate /* subscriptions on behalf of the Connection, like PEP "+notify" * namespaces (this one is add-only) */ GabbleCapabilitySet *notify_caps; - /* caps provided by Capabilities.AdvertiseCapabilities (tp-spec 0.16) */ - GabbleCapabilitySet *legacy_caps; /* additional caps that we advertise until the first call to - * AdvertiseCapabilities or UpdateCapabilities, for vague historical - * reasons */ + * UpdateCapabilities, for vague historical reasons */ GabbleCapabilitySet *bonus_caps; /* sidecar caps set by gabble_connection_update_sidecar_capabilities */ GabbleCapabilitySet *sidecar_caps; @@ -457,10 +447,6 @@ gabble_connection_constructor (GType type, conn_addressing_init (self); tp_contacts_mixin_add_contact_attributes_iface (G_OBJECT (self), - TP_IFACE_CONNECTION_INTERFACE_CAPABILITIES, - conn_capabilities_fill_contact_attributes); - - tp_contacts_mixin_add_contact_attributes_iface (G_OBJECT (self), TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, conn_contact_capabilities_fill_contact_attributes); @@ -480,7 +466,6 @@ gabble_connection_constructor (GType type, priv->all_caps = gabble_capability_set_new (); priv->notify_caps = gabble_capability_set_new (); - priv->legacy_caps = gabble_capability_set_new (); priv->sidecar_caps = gabble_capability_set_new (); priv->client_caps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) gabble_capability_set_free); @@ -489,7 +474,7 @@ gabble_connection_constructor (GType type, g_free, (GDestroyNotify) g_ptr_array_unref); /* Historically, the optional Jingle transports were in our initial - * presence, but could be removed by AdvertiseCapabilities(). Emulate + * presence, but could be removed by UpdateCapabilities(). Emulate * that here for now. */ priv->bonus_caps = gabble_capability_set_new (); #ifdef ENABLE_VOIP @@ -867,7 +852,7 @@ gabble_connection_get_unique_name (TpBaseConnection *self) */ void _gabble_connection_create_handle_repos (TpBaseConnection *conn, - TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]) + TpHandleRepoIface *repos[TP_NUM_HANDLE_TYPES]) { repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new (TP_HANDLE_TYPE_CONTACT, @@ -888,9 +873,7 @@ static const gchar *implemented_interfaces[] = { /* always present interfaces */ TP_IFACE_CONNECTION_INTERFACE_POWER_SAVING, TP_IFACE_CONNECTION_INTERFACE_ALIASING, - TP_IFACE_CONNECTION_INTERFACE_CAPABILITIES, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE, - TP_IFACE_CONNECTION_INTERFACE_PRESENCE, TP_IFACE_CONNECTION_INTERFACE_AVATARS, TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO, TP_IFACE_CONNECTION_INTERFACE_CONTACTS, @@ -900,9 +883,9 @@ static const gchar *implemented_interfaces[] = { TP_IFACE_CONNECTION_INTERFACE_CONTACT_CAPABILITIES, TP_IFACE_CONNECTION_INTERFACE_LOCATION, GABBLE_IFACE_CONNECTION_INTERFACE_GABBLE_DECLOAK, - GABBLE_IFACE_CONNECTION_FUTURE, + TP_IFACE_CONNECTION_INTERFACE_SIDECARS1, TP_IFACE_CONNECTION_INTERFACE_CLIENT_TYPES, - GABBLE_IFACE_CONNECTION_INTERFACE_ADDRESSING, + TP_IFACE_CONNECTION_INTERFACE_ADDRESSING, NULL }; static const gchar **interfaces_always_present = implemented_interfaces + 3; @@ -1312,7 +1295,6 @@ gabble_connection_dispose (GObject *object) g_hash_table_unref (priv->client_caps); gabble_capability_set_free (priv->all_caps); gabble_capability_set_free (priv->notify_caps); - gabble_capability_set_free (priv->legacy_caps); gabble_capability_set_free (priv->sidecar_caps); gabble_capability_set_free (priv->bonus_caps); @@ -1367,6 +1349,7 @@ gabble_connection_finalize (GObject *object) tp_contacts_mixin_finalize (G_OBJECT(self)); + conn_aliasing_finalize (self); conn_presence_finalize (self); conn_contact_info_finalize (self); @@ -2501,7 +2484,6 @@ gabble_connection_refresh_capabilities (GabbleConnection *self, gabble_capability_set_update (self->priv->all_caps, gabble_capabilities_get_fixed_caps ()); gabble_capability_set_update (self->priv->all_caps, self->priv->notify_caps); - gabble_capability_set_update (self->priv->all_caps, self->priv->legacy_caps); gabble_capability_set_update (self->priv->all_caps, self->priv->sidecar_caps); gabble_capability_set_update (self->priv->all_caps, self->priv->bonus_caps); @@ -3132,67 +3114,12 @@ _emit_capabilities_changed (GabbleConnection *conn, const GabbleCapabilitySet *old_set, const GabbleCapabilitySet *new_set) { - GPtrArray *caps_arr; - const CapabilityConversionData *ccd; GHashTable *hash; - guint i; + GPtrArray *caps_arr; if (gabble_capability_set_equals (old_set, new_set)) return; - /* o.f.T.C.Capabilities */ - - caps_arr = g_ptr_array_new (); - - for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++) - { - guint old_specific = ccd->c2tf_fn (old_set); - guint new_specific = ccd->c2tf_fn (new_set); - - if (old_specific != 0 || new_specific != 0) - { - GValue caps_monster_struct = {0, }; - guint old_generic = old_specific ? - TP_CONNECTION_CAPABILITY_FLAG_CREATE | - TP_CONNECTION_CAPABILITY_FLAG_INVITE : 0; - guint new_generic = new_specific ? - TP_CONNECTION_CAPABILITY_FLAG_CREATE | - TP_CONNECTION_CAPABILITY_FLAG_INVITE : 0; - - if (0 == (old_specific ^ new_specific)) - continue; - - g_value_init (&caps_monster_struct, - TP_STRUCT_TYPE_CAPABILITY_CHANGE); - g_value_take_boxed (&caps_monster_struct, - dbus_g_type_specialized_construct - (TP_STRUCT_TYPE_CAPABILITY_CHANGE)); - - dbus_g_type_struct_set (&caps_monster_struct, - 0, handle, - 1, ccd->iface, - 2, old_generic, - 3, new_generic, - 4, old_specific, - 5, new_specific, - G_MAXUINT); - - g_ptr_array_add (caps_arr, g_value_get_boxed (&caps_monster_struct)); - } - } - - if (caps_arr->len) - tp_svc_connection_interface_capabilities_emit_capabilities_changed ( - conn, caps_arr); - - - for (i = 0; i < caps_arr->len; i++) - { - g_boxed_free (TP_STRUCT_TYPE_CAPABILITY_CHANGE, - g_ptr_array_index (caps_arr, i)); - } - g_ptr_array_unref (caps_arr); - /* o.f.T.C.ContactCapabilities */ caps_arr = gabble_connection_build_contact_caps (conn, handle, new_set); @@ -3256,125 +3183,6 @@ connection_capabilities_update_cb (GabblePresenceCache *cache, _emit_capabilities_changed (conn, handle, old_cap_set, new_cap_set); } -/** - * gabble_connection_advertise_capabilities - * - * Implements D-Bus method AdvertiseCapabilities - * on interface org.freedesktop.Telepathy.Connection.Interface.Capabilities - * - * @error: Used to return a pointer to a GError detailing any error - * that occurred, D-Bus will throw the error only if this - * function returns FALSE. - * - * Returns: TRUE if successful, FALSE if an error was thrown. - */ -static void -gabble_connection_advertise_capabilities (TpSvcConnectionInterfaceCapabilities *iface, - const GPtrArray *add, - const gchar **del, - DBusGMethodInvocation *context) -{ - GabbleConnection *self = GABBLE_CONNECTION (iface); - TpBaseConnection *base = (TpBaseConnection *) self; - guint i; - GabbleConnectionPrivate *priv = self->priv; - const CapabilityConversionData *ccd; - GPtrArray *ret; - GabbleCapabilitySet *save_set; - GabbleCapabilitySet *add_set, *remove_set; - - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); - - /* Now that someone has told us our *actual* capabilities, we can stop - * advertising spurious caps in initial presence */ - gabble_capability_set_clear (self->priv->bonus_caps); - - add_set = gabble_capability_set_new (); - remove_set = gabble_capability_set_new (); - - for (i = 0; i < add->len; i++) - { - GValue iface_flags_pair = {0, }; - gchar *channel_type; - guint flags; - - g_value_init (&iface_flags_pair, TP_STRUCT_TYPE_CAPABILITY_PAIR); - g_value_set_static_boxed (&iface_flags_pair, g_ptr_array_index (add, i)); - - dbus_g_type_struct_get (&iface_flags_pair, - 0, &channel_type, - 1, &flags, - G_MAXUINT); - - for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++) - if (g_str_equal (channel_type, ccd->iface)) - ccd->tf2c_fn (flags, add_set); - - g_free (channel_type); - } - - for (i = 0; NULL != del[i]; i++) - { - for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++) - if (g_str_equal (del[i], ccd->iface)) - ccd->tf2c_fn (~0, remove_set); - } - - gabble_capability_set_update (priv->legacy_caps, add_set); - gabble_capability_set_exclude (priv->legacy_caps, remove_set); - - if (DEBUGGING) - { - gchar *add_str = gabble_capability_set_dump (add_set, " "); - gchar *remove_str = gabble_capability_set_dump (remove_set, " "); - - DEBUG ("caps to add:\n%s", add_str); - DEBUG ("caps to remove:\n%s", remove_str); - g_free (add_str); - g_free (remove_str); - } - - gabble_capability_set_free (add_set); - gabble_capability_set_free (remove_set); - - if (gabble_connection_refresh_capabilities (self, &save_set)) - { - _emit_capabilities_changed (self, - tp_base_connection_get_self_handle (base), save_set, priv->all_caps); - gabble_capability_set_free (save_set); - } - - ret = g_ptr_array_new (); - - for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++) - { - guint tp_caps = ccd->c2tf_fn (self->priv->all_caps); - - if (tp_caps != 0) - { - GValue iface_flags_pair = {0, }; - - g_value_init (&iface_flags_pair, TP_STRUCT_TYPE_CAPABILITY_PAIR); - g_value_take_boxed (&iface_flags_pair, - dbus_g_type_specialized_construct ( - TP_STRUCT_TYPE_CAPABILITY_PAIR)); - - dbus_g_type_struct_set (&iface_flags_pair, - 0, ccd->iface, - 1, tp_caps, - G_MAXUINT); - - g_ptr_array_add (ret, g_value_get_boxed (&iface_flags_pair)); - } - } - - tp_svc_connection_interface_capabilities_return_from_advertise_capabilities ( - context, ret); - - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_unref (ret); -} - static const gchar * get_form_type (WockyDataForm *form) { @@ -3613,126 +3421,6 @@ gabble_connection_update_capabilities ( context); } -static const gchar *assumed_caps[] = -{ - TP_IFACE_CHANNEL_TYPE_TEXT, - NULL -}; - - -/** - * gabble_connection_get_handle_capabilities - * - * Add capabilities of handle to the given GPtrArray - */ -static void -gabble_connection_get_handle_capabilities (GabbleConnection *self, - TpHandle handle, GPtrArray *arr) -{ - TpBaseConnection *base = (TpBaseConnection *) self; - GabblePresence *pres; - const CapabilityConversionData *ccd; - guint typeflags; - const gchar **assumed; - - if (0 == handle) - { - /* obsolete request for the connection's capabilities, do nothing */ - return; - } - - if (handle == tp_base_connection_get_self_handle (base)) - pres = self->self_presence; - else - pres = gabble_presence_cache_get (self->presence_cache, handle); - - if (NULL != pres) - { - const GabbleCapabilitySet *cap_set = gabble_presence_peek_caps (pres); - - for (ccd = capabilities_conversions; NULL != ccd->iface; ccd++) - { - typeflags = ccd->c2tf_fn (cap_set); - - if (typeflags) - { - GValue monster = {0, }; - - g_value_init (&monster, TP_STRUCT_TYPE_CONTACT_CAPABILITY); - g_value_take_boxed (&monster, - dbus_g_type_specialized_construct ( - TP_STRUCT_TYPE_CONTACT_CAPABILITY)); - - dbus_g_type_struct_set (&monster, - 0, handle, - 1, ccd->iface, - 2, TP_CONNECTION_CAPABILITY_FLAG_CREATE | - TP_CONNECTION_CAPABILITY_FLAG_INVITE, - 3, typeflags, - G_MAXUINT); - - g_ptr_array_add (arr, g_value_get_boxed (&monster)); - } - } - } - - for (assumed = assumed_caps; NULL != *assumed; assumed++) - { - GValue monster = {0, }; - - g_value_init (&monster, TP_STRUCT_TYPE_CONTACT_CAPABILITY); - g_value_take_boxed (&monster, - dbus_g_type_specialized_construct ( - TP_STRUCT_TYPE_CONTACT_CAPABILITY)); - - dbus_g_type_struct_set (&monster, - 0, handle, - 1, *assumed, - 2, TP_CONNECTION_CAPABILITY_FLAG_CREATE | - TP_CONNECTION_CAPABILITY_FLAG_INVITE, - 3, 0, - G_MAXUINT); - - g_ptr_array_add (arr, g_value_get_boxed (&monster)); - } -} - - -static void -conn_capabilities_fill_contact_attributes (GObject *obj, - const GArray *contacts, GHashTable *attributes_hash) -{ - GabbleConnection *self = GABBLE_CONNECTION (obj); - guint i; - GPtrArray *array = NULL; - - for (i = 0; i < contacts->len; i++) - { - TpHandle handle = g_array_index (contacts, TpHandle, i); - - if (array == NULL) - array = g_ptr_array_new (); - - gabble_connection_get_handle_capabilities (self, handle, array); - - if (array->len > 0) - { - GValue *val = tp_g_value_slice_new ( - TP_ARRAY_TYPE_CONTACT_CAPABILITY_LIST); - - g_value_take_boxed (val, array); - tp_contacts_mixin_set_contact_attribute (attributes_hash, - handle, TP_IFACE_CONNECTION_INTERFACE_CAPABILITIES"/caps", - val); - - array = NULL; - } - } - - if (array != NULL) - g_ptr_array_unref (array); -} - static void conn_contact_capabilities_fill_contact_attributes (GObject *obj, const GArray *contacts, GHashTable *attributes_hash) @@ -3755,54 +3443,6 @@ conn_contact_capabilities_fill_contact_attributes (GObject *obj, } /** - * gabble_connection_get_capabilities - * - * Implements D-Bus method GetCapabilities - * on interface org.freedesktop.Telepathy.Connection.Interface.Capabilities - */ -static void -gabble_connection_get_capabilities (TpSvcConnectionInterfaceCapabilities *iface, - const GArray *handles, - DBusGMethodInvocation *context) -{ - GabbleConnection *self = GABBLE_CONNECTION (iface); - TpBaseConnection *base = (TpBaseConnection *) self; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles (base, - TP_HANDLE_TYPE_CONTACT); - guint i; - GPtrArray *ret; - GError *error = NULL; - - TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (base, context); - - if (!tp_handles_are_valid (contact_handles, handles, TRUE, &error)) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - ret = g_ptr_array_new (); - - for (i = 0; i < handles->len; i++) - { - TpHandle handle = g_array_index (handles, TpHandle, i); - - gabble_connection_get_handle_capabilities (self, handle, ret); - } - - tp_svc_connection_interface_capabilities_return_from_get_capabilities ( - context, ret); - - for (i = 0; i < ret->len; i++) - { - g_value_array_free (g_ptr_array_index (ret, i)); - } - - g_ptr_array_unref (ret); -} - -/** * gabble_connection_get_contact_capabilities * * Implements D-Bus method GetContactCapabilities @@ -3933,19 +3573,6 @@ gabble_connection_send_presence (GabbleConnection *conn, } static void -capabilities_service_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcConnectionInterfaceCapabilitiesClass *klass = - (TpSvcConnectionInterfaceCapabilitiesClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_connection_interface_capabilities_implement_##x (\ - klass, gabble_connection_##x) - IMPLEMENT(advertise_capabilities); - IMPLEMENT(get_capabilities); -#undef IMPLEMENT -} - -static void gabble_conn_contact_caps_iface_init (gpointer g_iface, gpointer iface_data) { TpSvcConnectionInterfaceContactCapabilitiesClass *klass = g_iface; diff --git a/src/connection.h b/src/connection.h index c3e9138b0..842f9e58f 100644 --- a/src/connection.h +++ b/src/connection.h @@ -26,6 +26,7 @@ #include <dbus/dbus-glib.h> #include <glib-object.h> #include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include <wocky/wocky.h> @@ -248,6 +249,12 @@ struct _GabbleConnection { /* ContactInfo.SupportedFields, or NULL to use the generic one */ GPtrArray *contact_info_fields; + /* Contacts' aliases from PEP. Private to conn-aliasing.c. + * TpHandle => (transfer full) gchar * + * We don't distinguish between "not cached" and "known to have + * no PEP alias" here. */ + GHashTable *pep_alias_cache; + GabbleConnectionPrivate *priv; }; @@ -304,7 +311,7 @@ const gchar **gabble_connection_get_guaranteed_interfaces (void); /* extern only for the benefit of the unit tests */ void _gabble_connection_create_handle_repos (TpBaseConnection *conn, - TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]); + TpHandleRepoIface *repos[TP_NUM_HANDLE_TYPES]); /* For unit tests only */ void gabble_connection_set_disco_reply_timeout (guint timeout); diff --git a/src/debug.h b/src/debug.h index 83bf43247..6566eda13 100644 --- a/src/debug.h +++ b/src/debug.h @@ -73,49 +73,21 @@ G_END_DECLS gabble_log (G_LOG_LEVEL_INFO, DEBUG_FLAG, "%s (%s): " format, \ G_STRFUNC, G_STRLOC, ##__VA_ARGS__) -#ifdef ENABLE_DEBUG -# define DEBUG(format, ...) \ +#define DEBUG(format, ...) \ gabble_log (G_LOG_LEVEL_DEBUG, DEBUG_FLAG, "%s (%s): " format, \ G_STRFUNC, G_STRLOC, ##__VA_ARGS__) -# define DEBUGGING gabble_debug_flag_is_set (DEBUG_FLAG) +#define DEBUGGING gabble_debug_flag_is_set (DEBUG_FLAG) -# define STANZA_DEBUG(st, s) \ +#define STANZA_DEBUG(st, s) \ NODE_DEBUG (wocky_stanza_get_top_node (st), s) -# define NODE_DEBUG(n, s) \ +#define NODE_DEBUG(n, s) \ G_STMT_START { \ gchar *debug_tmp = wocky_node_to_string (n); \ gabble_log (G_LOG_LEVEL_DEBUG, DEBUG_FLAG, "%s: %s:\n%s", G_STRFUNC, s, debug_tmp); \ g_free (debug_tmp); \ } G_STMT_END -#else /* !defined (ENABLE_DEBUG) */ -static inline void -DEBUG ( - const gchar *format, - ...) -{ -} - -# define DEBUGGING 0 - -static inline void -STANZA_DEBUG ( - WockyStanza *stanza, - const gchar *format, - ...) -{ -} - -static inline void -NODE_DEBUG ( - WockyNode *node, - const gchar *format, - ...) -{ -} -#endif /* !defined (ENABLE_DEBUG) */ - #endif /* DEBUG_FLAG */ #endif /* __DEBUG_H__ */ diff --git a/src/ft-channel.c b/src/ft-channel.c index fd82405c5..cf7359b7e 100644 --- a/src/ft-channel.c +++ b/src/ft-channel.c @@ -65,8 +65,6 @@ G_DEFINE_TYPE_WITH_CODE (GabbleFileTransferChannel, gabble_file_transfer_channel TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_FILE_TRANSFER, file_transfer_iface_init); - G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CHANNEL_TYPE_FILETRANSFER_FUTURE, - NULL); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA, NULL); ); @@ -96,7 +94,6 @@ enum PROP_BYTESTREAM, #ifdef ENABLE_JINGLE_FILE_TRANSFER - /* Chan.Type.FileTransfer.FUTURE */ PROP_GTALK_FILE_COLLECTION, #endif @@ -521,7 +518,7 @@ gabble_file_transfer_channel_fill_immutable_properties (TpBaseChannel *chan, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "AvailableSocketTypes", TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "TransferredBytes", TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "InitialOffset", - GABBLE_IFACE_CHANNEL_TYPE_FILETRANSFER_FUTURE, "FileCollection", + TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, "FileCollection", TP_IFACE_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA, "ServiceName", TP_IFACE_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA, "Metadata", NULL); @@ -548,7 +545,6 @@ gabble_file_transfer_channel_get_interfaces (TpBaseChannel *base) 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; @@ -577,10 +573,6 @@ gabble_file_transfer_channel_class_init ( { "InitialOffset", "initial-offset", NULL }, { "Date", "date", NULL }, { "URI", "uri", NULL }, - { NULL } - }; - - static TpDBusPropertiesMixinPropImpl file_future_props[] = { { "FileCollection", "file-collection", NULL }, { NULL } }; @@ -597,11 +589,6 @@ gabble_file_transfer_channel_class_init ( file_transfer_channel_properties_setter, file_props }, - { GABBLE_IFACE_CHANNEL_TYPE_FILETRANSFER_FUTURE, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - file_future_props - }, { TP_IFACE_CHANNEL_INTERFACE_FILE_TRANSFER_METADATA, tp_dbus_properties_mixin_getter_gobject_properties, NULL, @@ -633,7 +620,7 @@ gabble_file_transfer_channel_class_init ( "TpFileTransferState state", "State of the file transfer in this channel", 0, - NUM_TP_FILE_TRANSFER_STATES, + TP_NUM_FILE_TRANSFER_STATES, TP_FILE_TRANSFER_STATE_NONE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); @@ -674,7 +661,7 @@ gabble_file_transfer_channel_class_init ( "TpFileHashType content-hash-type", "Hash type", 0, - NUM_TP_FILE_HASH_TYPES, + TP_NUM_FILE_HASH_TYPES, TP_FILE_HASH_TYPE_NONE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); diff --git a/src/ft-manager.c b/src/ft-manager.c index a4266b5a0..cca26d4cb 100644 --- a/src/ft-manager.c +++ b/src/ft-manager.c @@ -289,8 +289,6 @@ static void gabble_ft_manager_channels_created (GabbleFtManager *self, GList *channels) { GList *i; - GHashTable *new_channels = g_hash_table_new_full (g_direct_hash, - g_direct_equal, NULL, NULL); for (i = channels; i ; i = i->next) { @@ -304,12 +302,9 @@ gabble_ft_manager_channels_created (GabbleFtManager *self, GList *channels) self->priv->channels = g_list_append (self->priv->channels, chan); /* The channels can't satisfy a request because this will always be called when we receive an incoming jingle-share session */ - g_hash_table_insert (new_channels, chan, NULL); + tp_channel_manager_emit_new_channel (self, + TP_EXPORTABLE_CHANNEL (chan), NULL); } - - tp_channel_manager_emit_new_channels (self, new_channels); - - g_hash_table_unref (new_channels); } #endif @@ -526,7 +521,7 @@ gabble_ft_manager_handle_request (TpChannelManager *manager, } else { - if (content_hash_type >= NUM_TP_FILE_HASH_TYPES) + if (content_hash_type >= TP_NUM_FILE_HASH_TYPES) { g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "%u is not a valid ContentHashType", content_hash_type); diff --git a/src/gabble.c b/src/gabble.c index e7e4da4d9..64c6bf4c3 100644 --- a/src/gabble.c +++ b/src/gabble.c @@ -44,7 +44,6 @@ construct_cm (void) GABBLE_TYPE_CONNECTION_MANAGER, NULL); } -#ifdef ENABLE_DEBUG static TpDebugSender *debug_sender = NULL; static void @@ -102,9 +101,6 @@ log_handler (const gchar *log_domain, log_to_debug_sender (log_domain, log_level, message); } -#endif - - void gabble_init (void) { @@ -148,7 +144,6 @@ gabble_main (int argc, g_log_set_always_fatal (fatal_mask); #endif -#ifdef ENABLE_DEBUG gabble_debug_set_flags_from_env (); stamp_logs = (g_getenv ("GABBLE_TIMING") != NULL); @@ -168,7 +163,6 @@ gabble_main (int argc, if (g_getenv ("GABBLE_PERSIST") != NULL) tp_debug_set_persistent (TRUE); -#endif loader = gabble_plugin_loader_dup (); @@ -179,10 +173,8 @@ gabble_main (int argc, g_object_unref (loader); -#ifdef ENABLE_DEBUG g_log_set_default_handler (g_log_default_handler, NULL); g_object_unref (debug_sender); -#endif wocky_deinit (); diff --git a/src/media-channel-hold.c b/src/media-channel-hold.c deleted file mode 100644 index b4dc26c5a..000000000 --- a/src/media-channel-hold.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * media-channel-hold.c - Hold and CallState interface implementations - * Copyright © 2006–2009 Collabora Ltd. - * Copyright © 2006–2009 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 - */ - -#include "config.h" - -#include "media-channel.h" -#include "media-channel-internal.h" - -#include <telepathy-glib/telepathy-glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "util.h" - -/* - * Implementation of Channel.Interface.Hold, which deals with placing the peer - * on and off hold. - */ - -static void -stream_hold_state_changed (GabbleMediaStream *stream G_GNUC_UNUSED, - GParamSpec *unused G_GNUC_UNUSED, - gpointer data) -{ - GabbleMediaChannel *self = data; - GabbleMediaChannelPrivate *priv = self->priv; - gboolean all_held = TRUE, any_held = FALSE; - guint i; - - for (i = 0; i < priv->streams->len; i++) - { - gboolean its_hold; - - g_object_get (g_ptr_array_index (priv->streams, i), - "local-hold", &its_hold, - NULL); - - DEBUG ("Stream at index %u has local-hold=%u", i, (guint) its_hold); - - all_held = all_held && its_hold; - any_held = any_held || its_hold; - } - - DEBUG ("all_held=%u, any_held=%u", (guint) all_held, (guint) any_held); - - if (all_held && !any_held) - { - /* There are no streams, move to the desired state immediately */ - switch (priv->hold_state) - { - case TP_LOCAL_HOLD_STATE_PENDING_HOLD: - DEBUG ("no streams, moving from pending hold to held"); - priv->hold_state = TP_LOCAL_HOLD_STATE_HELD; - - /* No need to touch the session: send_held (TRUE) is called as soon - * as Hold is requested. - */ - break; - - case TP_LOCAL_HOLD_STATE_PENDING_UNHOLD: - DEBUG ("no streams, moving from pending unhold to unheld"); - priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; - - if (priv->session != NULL) - wocky_jingle_session_set_local_hold (priv->session, FALSE); - - break; - - default: - /* nothing to change */ - return; - } - } - else if (all_held) - { - /* Move to state HELD */ - switch (priv->hold_state) - { - case TP_LOCAL_HOLD_STATE_HELD: - /* nothing changed */ - return; - - case TP_LOCAL_HOLD_STATE_PENDING_UNHOLD: - /* This can happen if the user asks us to hold, then changes their - * mind. We make no particular guarantees about stream states when - * in PENDING_UNHOLD state, so keep claiming to be in that state */ - return; - - case TP_LOCAL_HOLD_STATE_PENDING_HOLD: - /* We wanted to hold, and indeed we have. Yay! Keep whatever - * reason code we used for going to PENDING_HOLD */ - priv->hold_state = TP_LOCAL_HOLD_STATE_HELD; - break; - - case TP_LOCAL_HOLD_STATE_UNHELD: - /* We were previously UNHELD. So why have we gone on hold now? */ - DEBUG ("Unexpectedly entered HELD state!"); - priv->hold_state = TP_LOCAL_HOLD_STATE_HELD; - priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - break; - } - } - else if (any_held) - { - switch (priv->hold_state) - { - case TP_LOCAL_HOLD_STATE_UNHELD: - /* The streaming client has spontaneously changed its stream - * state. Why? We just don't know */ - DEBUG ("Unexpectedly entered PENDING_UNHOLD state!"); - priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_UNHOLD; - priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - break; - - case TP_LOCAL_HOLD_STATE_HELD: - /* Likewise */ - DEBUG ("Unexpectedly entered PENDING_HOLD state!"); - priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; - priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - break; - - default: - /* nothing particularly interesting - we're trying to change hold - * state already, so nothing to signal */ - return; - } - } - else - { - /* Move to state UNHELD */ - switch (priv->hold_state) - { - case TP_LOCAL_HOLD_STATE_UNHELD: - /* nothing changed */ - return; - - case TP_LOCAL_HOLD_STATE_PENDING_HOLD: - /* This can happen if the user asks us to unhold, then changes their - * mind. We make no particular guarantees about stream states when - * in PENDING_HOLD state, so keep claiming to be in that state */ - return; - - case TP_LOCAL_HOLD_STATE_PENDING_UNHOLD: - /* We wanted to hold, and indeed we have. Yay! Keep whatever - * reason code we used for going to PENDING_UNHOLD */ - priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; - break; - - case TP_LOCAL_HOLD_STATE_HELD: - /* We were previously HELD. So why have we gone off hold now? */ - DEBUG ("Unexpectedly entered UNHELD state!"); - priv->hold_state = TP_LOCAL_HOLD_STATE_UNHELD; - priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_NONE; - break; - } - - /* Tell the peer what's happened. */ - if (priv->session != NULL) - wocky_jingle_session_set_local_hold (priv->session, FALSE); - } - - tp_svc_channel_interface_hold_emit_hold_state_changed (self, - priv->hold_state, priv->hold_state_reason); -} - - -static void -stream_unhold_failed (GabbleMediaStream *stream, - gpointer data) -{ - GabbleMediaChannel *self = data; - GabbleMediaChannelPrivate *priv = self->priv; - guint i; - - DEBUG ("%p: %p", self, stream); - - /* Unholding failed - let's roll back to Hold state */ - priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; - priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_RESOURCE_NOT_AVAILABLE; - tp_svc_channel_interface_hold_emit_hold_state_changed (self, - priv->hold_state, priv->hold_state_reason); - - /* The stream's state may have changed from unheld to held, so re-poll. - * It's possible that all streams are now held, in which case we can stop. */ - stream_hold_state_changed (stream, NULL, self); - - if (priv->hold_state == TP_LOCAL_HOLD_STATE_HELD) - return; - - /* There should be no need to notify the peer, who already thinks they're - * on hold, so just tell the streaming client what to do. */ - - for (i = 0; i < priv->streams->len; i++) - { - gabble_media_stream_hold (g_ptr_array_index (priv->streams, i), - TRUE); - } -} - - -void -gabble_media_channel_hold_stream_closed (GabbleMediaChannel *chan, - GabbleMediaStream *stream) -{ - /* A stream closing might cause the "total" hold state to change: - * if there's one held and one unheld, and the unheld one closes, - * then our state changes from indeterminate to held. */ - stream_hold_state_changed (stream, NULL, chan); -} - - -/* Implements RequestHold on Telepathy.Channel.Interface.Hold */ -static void -gabble_media_channel_request_hold (TpSvcChannelInterfaceHold *iface, - gboolean hold, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv = self->priv; - WockyJingleSession *session = priv->session; - guint i; - TpLocalHoldState old_state = priv->hold_state; - - DEBUG ("%p: RequestHold(%u)", self, !!hold); - - if (hold) - { - if (priv->hold_state == TP_LOCAL_HOLD_STATE_HELD) - { - DEBUG ("No-op"); - tp_svc_channel_interface_hold_return_from_request_hold (context); - return; - } - - if (priv->hold_state == TP_LOCAL_HOLD_STATE_UNHELD && session != NULL) - wocky_jingle_session_set_local_hold (session, TRUE); - - priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_HOLD; - } - else - { - if (priv->hold_state == TP_LOCAL_HOLD_STATE_UNHELD) - { - DEBUG ("No-op"); - tp_svc_channel_interface_hold_return_from_request_hold (context); - return; - } - - priv->hold_state = TP_LOCAL_HOLD_STATE_PENDING_UNHOLD; - } - - if (old_state != priv->hold_state || - priv->hold_state_reason != TP_LOCAL_HOLD_STATE_REASON_REQUESTED) - { - tp_svc_channel_interface_hold_emit_hold_state_changed (self, - priv->hold_state, TP_LOCAL_HOLD_STATE_REASON_REQUESTED); - priv->hold_state_reason = TP_LOCAL_HOLD_STATE_REASON_REQUESTED; - } - - if (priv->streams->len == 0) - { - /* No streams yet! We can go straight to the desired state. */ - stream_hold_state_changed (NULL, NULL, self); - } - else - { - /* Tell streaming client to release or reacquire resources */ - - for (i = 0; i < priv->streams->len; i++) - { - gabble_media_stream_hold (g_ptr_array_index (priv->streams, i), hold); - } - } - - tp_svc_channel_interface_hold_return_from_request_hold (context); -} - - -/* Implements GetHoldState on Telepathy.Channel.Interface.Hold */ -static void -gabble_media_channel_get_hold_state (TpSvcChannelInterfaceHold *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = (GabbleMediaChannel *) iface; - GabbleMediaChannelPrivate *priv = self->priv; - - tp_svc_channel_interface_hold_return_from_get_hold_state (context, - priv->hold_state, priv->hold_state_reason); -} - - -void -gabble_media_channel_hold_iface_init (gpointer g_iface, - gpointer iface_data G_GNUC_UNUSED) -{ - TpSvcChannelInterfaceHoldClass *klass = g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_hold_implement_##x (\ - klass, gabble_media_channel_##x) - IMPLEMENT(get_hold_state); - IMPLEMENT(request_hold); -#undef IMPLEMENT -} - - -/* - * Implementation of Channel.Interface.CallState, which indicates call states - * from the peer (such as being put on or off hold, or that the peer's client - * is ringing. - */ - -static void -remote_state_changed_cb (WockyJingleSession *session, - GabbleMediaChannel *self) -{ - GabbleMediaChannelPrivate *priv = self->priv; - TpChannelCallStateFlags call_state = 0; - - if (wocky_jingle_session_get_remote_hold (session)) - call_state |= TP_CHANNEL_CALL_STATE_HELD; - - 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, - priv->call_state); - - if (call_state == priv->call_state) - return; - - priv->call_state = call_state; - - tp_svc_channel_interface_call_state_emit_call_state_changed (self, - priv->peer, call_state); -} - - -/* Implements GetCallStates on Channel.Interface.CallState */ -static void -gabble_media_channel_get_call_states (TpSvcChannelInterfaceCallState *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = (GabbleMediaChannel *) iface; - GabbleMediaChannelPrivate *priv = self->priv; - GHashTable *states = g_hash_table_new (g_direct_hash, g_direct_equal); - - if (priv->peer != 0) - { - g_hash_table_insert (states, GUINT_TO_POINTER (priv->peer), - GUINT_TO_POINTER (priv->call_state)); - } - - tp_svc_channel_interface_call_state_return_from_get_call_states (context, - states); - - g_hash_table_unref (states); -} - - -void -gabble_media_channel_call_state_iface_init (gpointer g_iface, - gpointer iface_data G_GNUC_UNUSED) -{ - TpSvcChannelInterfaceCallStateClass *klass = g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_call_state_implement_##x (\ - klass, gabble_media_channel_##x) - IMPLEMENT(get_call_states); -#undef IMPLEMENT -} - - -/* Called by construct_stream to allow the Hold code to hook itself up to a new - * stream. - */ -void -gabble_media_channel_hold_new_stream (GabbleMediaChannel *chan, - GabbleMediaStream *stream, - WockyJingleMediaRtp *content) -{ - GObject *chan_o = (GObject *) chan; - - gabble_signal_connect_weak (stream, "unhold-failed", - (GCallback) stream_unhold_failed, chan_o); - gabble_signal_connect_weak (stream, "notify::local-hold", - (GCallback) stream_hold_state_changed, chan_o); - - /* A stream being added might cause the "total" hold state to change */ - stream_hold_state_changed (stream, NULL, chan); -} - -/* Called by _latch_to_session to allow the CallState code to hook itself up to - * a new session. - */ -void -gabble_media_channel_hold_latch_to_session (GabbleMediaChannel *chan) -{ - g_assert (chan->priv->session != NULL); - - /* Watch the active/ringing/held state of the session so we can keep the call - * state up to date. - */ - gabble_signal_connect_weak (chan->priv->session, "remote-state-changed", - (GCallback) remote_state_changed_cb, (GObject *) chan); -} diff --git a/src/media-channel-internal.h b/src/media-channel-internal.h deleted file mode 100644 index 4459df726..000000000 --- a/src/media-channel-internal.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * media-channel-internal.h - implementation details shared between - * MediaChannel source files - * Copyright © 2006–2009 Collabora Ltd. - * Copyright © 2006–2009 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_MEDIA_CHANNEL_INTERNAL_H__ -#define __GABBLE_MEDIA_CHANNEL_INTERNAL_H__ - -#include "media-channel.h" - -#include <glib.h> - -#include <telepathy-glib/telepathy-glib.h> -#include <wocky/wocky.h> - -#include "media-stream.h" - -G_BEGIN_DECLS - -struct _GabbleMediaChannelPrivate -{ - GabbleConnection *conn; - gchar *object_path; - TpHandle creator; - TpHandle initial_peer; - TpHandle peer; - gboolean peer_in_rp; - - WockyJingleSession *session; - - /* array of referenced GabbleMediaStream*. Always non-NULL. */ - GPtrArray *streams; - /* list of PendingStreamRequest* in no particular order */ - GList *pending_stream_requests; - - /* list of StreamCreationData* in no particular order */ - GList *stream_creation_datas; - - guint next_stream_id; - - TpLocalHoldState hold_state; - TpLocalHoldStateReason hold_state_reason; - - TpChannelCallStateFlags call_state; - - GPtrArray *delayed_request_streams; - - TpDTMFPlayer *dtmf_player; - gchar *deferred_tones; - - gboolean initial_audio; - gboolean initial_video; - gboolean immutable_streams; - gboolean ready; - gboolean closed; - gboolean dispose_has_run; - gboolean tried_decloaking; - gboolean have_some_audio; -}; - -void gabble_media_channel_hold_latch_to_session (GabbleMediaChannel *chan); - -void gabble_media_channel_hold_new_stream (GabbleMediaChannel *chan, - GabbleMediaStream *stream, - WockyJingleMediaRtp *content); -void gabble_media_channel_hold_stream_closed (GabbleMediaChannel *chan, - GabbleMediaStream *stream); - -void gabble_media_channel_hold_iface_init (gpointer g_iface, - gpointer iface_data G_GNUC_UNUSED); - -void gabble_media_channel_call_state_iface_init (gpointer g_iface, - gpointer iface_data G_GNUC_UNUSED); - -G_END_DECLS - -#endif /* #ifndef __GABBLE_MEDIA_CHANNEL_INTERNAL_H__ */ diff --git a/src/media-channel.c b/src/media-channel.c deleted file mode 100644 index c4ab89e37..000000000 --- a/src/media-channel.c +++ /dev/null @@ -1,3184 +0,0 @@ -/* - * gabble-media-channel.c - Source for GabbleMediaChannel - * Copyright (C) 2006 Collabora Ltd. - * Copyright (C) 2006 Nokia Corporation - * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@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 - */ - -#include "config.h" -#include "media-channel.h" -#include "media-channel-internal.h" - -#include <dbus/dbus-glib.h> -#include <dbus/dbus-glib-lowlevel.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-tp-util.h" -#include "media-factory.h" -#include "media-stream.h" -#include "namespaces.h" -#include "presence-cache.h" -#include "presence.h" -#include "util.h" - -#define MAX_STREAMS 99 - -static void channel_iface_init (gpointer, gpointer); -static void dtmf_iface_init (gpointer, gpointer); -static void media_signalling_iface_init (gpointer, gpointer); -static void streamed_media_iface_init (gpointer, gpointer); -static void session_handler_iface_init (gpointer, gpointer); - -G_DEFINE_TYPE_WITH_CODE (GabbleMediaChannel, gabble_media_channel, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, - channel_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CALL_STATE, - gabble_media_channel_call_state_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DTMF, - dtmf_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP, - tp_group_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_HOLD, - gabble_media_channel_hold_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MEDIA_SIGNALLING, - media_signalling_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_STREAMED_MEDIA, - streamed_media_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_PROPERTIES_INTERFACE, - tp_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_EXPORTABLE_CHANNEL, NULL); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_SESSION_HANDLER, - session_handler_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL)); - -static const gchar *gabble_media_channel_interfaces[] = { - TP_IFACE_CHANNEL_INTERFACE_CALL_STATE, - TP_IFACE_CHANNEL_INTERFACE_DTMF, - TP_IFACE_CHANNEL_INTERFACE_GROUP, - TP_IFACE_CHANNEL_INTERFACE_HOLD, - TP_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING, - TP_IFACE_PROPERTIES_INTERFACE, - TP_IFACE_MEDIA_SESSION_HANDLER, - NULL -}; - -/* properties */ -enum -{ - PROP_OBJECT_PATH = 1, - PROP_CHANNEL_TYPE, - PROP_HANDLE_TYPE, - PROP_HANDLE, - PROP_TARGET_ID, - PROP_INITIAL_PEER, - PROP_PEER_IN_RP, - PROP_PEER, - PROP_REQUESTED, - PROP_CONNECTION, - PROP_CREATOR, - PROP_CREATOR_ID, - PROP_INTERFACES, - PROP_CHANNEL_DESTROYED, - PROP_CHANNEL_PROPERTIES, - PROP_INITIAL_AUDIO, - PROP_INITIAL_VIDEO, - PROP_IMMUTABLE_STREAMS, - PROP_CURRENTLY_SENDING_TONES, - PROP_INITIAL_TONES, - PROP_DEFERRED_TONES, - /* TP properties (see also below) */ - PROP_NAT_TRAVERSAL, - PROP_STUN_SERVER, - PROP_STUN_PORT, - PROP_GTALK_P2P_RELAY_TOKEN, - PROP_SESSION, - LAST_PROPERTY -}; - -/* TP properties */ -enum -{ - CHAN_PROP_NAT_TRAVERSAL = 0, - CHAN_PROP_STUN_SERVER, - CHAN_PROP_STUN_PORT, - CHAN_PROP_GTALK_P2P_RELAY_TOKEN, - NUM_CHAN_PROPS, - INVALID_CHAN_PROP -}; - -const TpPropertySignature channel_property_signatures[NUM_CHAN_PROPS] = { - { "nat-traversal", G_TYPE_STRING }, - { "stun-server", G_TYPE_STRING }, - { "stun-port", G_TYPE_UINT }, - { "gtalk-p2p-relay-token", G_TYPE_STRING } -}; - -typedef struct { - GabbleMediaChannel *self; - WockyJingleContent *content; - gulong removed_id; - gchar *name; - const gchar *nat_traversal; - gboolean initial; -} StreamCreationData; - -struct _delayed_request_streams_ctx { - GabbleMediaChannel *chan; - gulong caps_disco_id; - gulong unsure_period_ended_id; - guint contact_handle; - GArray *types; - GFunc succeeded_cb; - GFunc failed_cb; - gpointer context; -}; - -static void destroy_request (struct _delayed_request_streams_ctx *ctx, - gpointer user_data); - -static void -tones_deferred_cb (GabbleMediaChannel *self, - const gchar *tones, - TpDTMFPlayer *dtmf_player) -{ - DEBUG ("waiting for user to continue sending '%s'", tones); - - g_free (self->priv->deferred_tones); - self->priv->deferred_tones = g_strdup (tones); - tp_svc_channel_interface_dtmf_emit_tones_deferred (self, tones); -} - -static void -gabble_media_channel_init (GabbleMediaChannel *self) -{ - GabbleMediaChannelPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_MEDIA_CHANNEL, GabbleMediaChannelPrivate); - - self->priv = priv; - - priv->next_stream_id = 1; - priv->delayed_request_streams = g_ptr_array_sized_new (1); - priv->streams = g_ptr_array_sized_new (1); - - /* initialize properties mixin */ - tp_properties_mixin_init (G_OBJECT (self), G_STRUCT_OFFSET ( - GabbleMediaChannel, properties)); - - priv->dtmf_player = tp_dtmf_player_new (); - - tp_g_signal_connect_object (priv->dtmf_player, "finished", - G_CALLBACK (tp_svc_channel_interface_dtmf_emit_stopped_tones), self, - G_CONNECT_SWAPPED); - - tp_g_signal_connect_object (priv->dtmf_player, "tones-deferred", - G_CALLBACK (tones_deferred_cb), self, - G_CONNECT_SWAPPED); -} - -static void session_state_changed_cb (WockyJingleSession *session, - GParamSpec *arg1, GabbleMediaChannel *channel); -static void session_terminated_cb (WockyJingleSession *session, - gboolean local_terminator, WockyJingleReason reason, const gchar *text, - gpointer user_data); -static void session_new_content_cb (WockyJingleSession *session, - WockyJingleContent *c, gpointer user_data); -static void create_stream_from_content (GabbleMediaChannel *chan, - 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 (WockyJingleSession *session, - WockyJingleContent *c, WockyJingleReason reason, const gchar *message, - gpointer user_data); - -static void -create_initial_streams (GabbleMediaChannel *chan) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - GList *contents, *li; - - contents = wocky_jingle_session_get_contents (priv->session); - - for (li = contents; li; li = li->next) - { - WockyJingleContent *c = li->data; - - /* I'm so sorry. */ - if (G_OBJECT_TYPE (c) == WOCKY_TYPE_JINGLE_MEDIA_RTP) - { - guint media_type; - - g_object_get (c, "media-type", &media_type, NULL); - - switch (media_type) - { - case WOCKY_JINGLE_MEDIA_TYPE_AUDIO: - priv->initial_audio = TRUE; - break; - case WOCKY_JINGLE_MEDIA_TYPE_VIDEO: - priv->initial_video = TRUE; - break; - default: - /* smell? */ - DEBUG ("unknown rtp media type %u", media_type); - } - } - else - { - g_assert_not_reached (); - } - - create_stream_from_content (chan, c, TRUE); - } - - DEBUG ("initial_audio: %s, initial_video: %s", - priv->initial_audio ? "true" : "false", - priv->initial_video ? "true" : "false"); - - g_list_free (contents); -} - -static void -_latch_to_session (GabbleMediaChannel *chan) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - - g_assert (priv->session != NULL); - - DEBUG ("%p: Latching onto session %p", chan, priv->session); - - g_signal_connect (priv->session, "notify::state", - (GCallback) session_state_changed_cb, chan); - - g_signal_connect (priv->session, "new-content", - (GCallback) session_new_content_cb, chan); - - g_signal_connect (priv->session, "terminated", - (GCallback) session_terminated_cb, chan); - - g_signal_connect (priv->session, "content-rejected", - (GCallback) session_content_rejected_cb, chan); - - gabble_media_channel_hold_latch_to_session (chan); - - g_assert (priv->streams->len == 0); - - tp_svc_channel_interface_media_signalling_emit_new_session_handler ( - G_OBJECT (chan), priv->object_path, "rtp"); -} - -static void -create_session (GabbleMediaChannel *chan, - const gchar *jid, - WockyJingleDialect dialect) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - gboolean local_hold = (priv->hold_state != TP_LOCAL_HOLD_STATE_UNHELD); - WockyJingleFactory *jf; - - g_assert (priv->session == NULL); - - DEBUG ("%p: Creating new outgoing session", chan); - - jf = gabble_jingle_mint_get_factory (priv->conn->jingle_mint); - g_return_if_fail (jf != NULL); - priv->session = g_object_ref ( - wocky_jingle_factory_create_session (jf, jid, dialect, local_hold)); - - _latch_to_session (chan); -} - -static GObject * -gabble_media_channel_constructor (GType type, guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - GabbleMediaChannelPrivate *priv; - TpBaseConnection *conn; - TpDBusDaemon *bus; - TpIntset *set; - TpHandleRepoIface *contact_handles; - WockyJingleInfo *ji; - const gchar *relay_token; - GList *stun_servers; - - obj = G_OBJECT_CLASS (gabble_media_channel_parent_class)-> - constructor (type, n_props, props); - - priv = GABBLE_MEDIA_CHANNEL (obj)->priv; - conn = (TpBaseConnection *) priv->conn; - contact_handles = tp_base_connection_get_handles (conn, - TP_HANDLE_TYPE_CONTACT); - - /* register object on the bus */ - bus = tp_base_connection_get_dbus_daemon (conn); - tp_dbus_daemon_register_object (bus, priv->object_path, obj); - - tp_group_mixin_init (obj, G_STRUCT_OFFSET (GabbleMediaChannel, group), - contact_handles, tp_base_connection_get_self_handle (conn)); - - if (priv->session != NULL) - { - priv->peer = ensure_handle_from_contact (priv->conn, - wocky_jingle_session_get_peer_contact (priv->session)); - g_return_val_if_fail (priv->peer != 0, NULL); - priv->creator = priv->peer; - } - else - { - 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); - - set = tp_intset_new_containing (priv->creator); - tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, 0, - TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - tp_intset_destroy (set); - - /* We implement the 0.17.6 properties correctly, and can include a message - * when ending a call. - */ - tp_group_mixin_change_flags (obj, - TP_CHANNEL_GROUP_FLAG_PROPERTIES | - TP_CHANNEL_GROUP_FLAG_MESSAGE_REMOVE | - TP_CHANNEL_GROUP_FLAG_MESSAGE_REJECT | - TP_CHANNEL_GROUP_FLAG_MESSAGE_RESCIND, - 0); - - /* Set up Google relay related properties */ - ji = gabble_jingle_mint_get_info (priv->conn->jingle_mint); - 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->address, - "stun-port", (guint) stun_server->port, - NULL); - - g_list_free (stun_servers); - } - - relay_token = wocky_jingle_info_get_google_relay_token (ji); - - if (relay_token != NULL) - { - g_object_set (obj, - "gtalk-p2p-relay-token", relay_token, - NULL); - } - - if (priv->session != NULL) - { - /* This is an incoming call; make us local pending and don't set any - * group flags (all we can do is add or remove ourselves, which is always - * valid per the spec) - */ - 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); - - /* Set up signal callbacks, emit session handler, initialize streams, - * figure out InitialAudio and InitialVideo - */ - _latch_to_session (GABBLE_MEDIA_CHANNEL (obj)); - create_initial_streams (GABBLE_MEDIA_CHANNEL (obj)); - } - else - { - /* This is an outgoing call. */ - - if (priv->initial_peer != 0) - { - if (priv->peer_in_rp) - { - /* This channel was created with RequestChannel(SM, Contact, h) - * so the peer should start out in remote pending. - */ - set = tp_intset_new_containing (priv->initial_peer); - tp_group_mixin_change_members (obj, "", NULL, NULL, NULL, set, - tp_base_connection_get_self_handle (conn), - TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - tp_intset_destroy (set); - } - - /* else this channel was created with CreateChannel or EnsureChannel, - * so don't. - */ - } - else - { - /* This channel was created with RequestChannel(SM, None, 0). */ - - /* The peer can't be in remote pending */ - g_assert (!priv->peer_in_rp); - - /* The UI may call AddMembers([h], "") before calling - * RequestStreams(h, [...]). - */ - tp_group_mixin_change_flags (obj, TP_CHANNEL_GROUP_FLAG_CAN_ADD, 0); - } - } - - /* If this is a Google session, let's set ImmutableStreams */ - if (priv->session != NULL) - { - 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 - * for old-style capabilities. If we don't know who the peer will be, then - * the client is using an old calling convention and doesn't need to know - * this. - */ - else if (priv->initial_peer != 0) - { - GabblePresence *presence = gabble_presence_cache_get ( - priv->conn->presence_cache, priv->initial_peer); - TpChannelMediaCapabilities flags = 0; - - if (presence != NULL) - flags = _gabble_media_factory_caps_to_typeflags ( - gabble_presence_peek_caps (presence)); - - if (flags & TP_CHANNEL_MEDIA_CAPABILITY_IMMUTABLE_STREAMS) - priv->immutable_streams = TRUE; - } - - return obj; -} - -static void -gabble_media_channel_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (object); - GabbleMediaChannelPrivate *priv = chan->priv; - TpBaseConnection *base_conn = (TpBaseConnection *) priv->conn; - const gchar *param_name; - guint tp_property_id; - - 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_STREAMED_MEDIA); - break; - case PROP_HANDLE_TYPE: - /* This is used to implement TargetHandleType, which is immutable. If - * the peer was known at channel-creation time, this will be Contact; - * otherwise, it must be None even if we subsequently learn who the peer - * is. - */ - if (priv->initial_peer != 0) - g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT); - else - g_value_set_uint (value, TP_HANDLE_TYPE_NONE); - break; - case PROP_INITIAL_PEER: - case PROP_HANDLE: - /* As above: TargetHandle is immutable, so non-0 only if the peer handle - * was known at creation time. - */ - g_value_set_uint (value, priv->initial_peer); - break; - case PROP_TARGET_ID: - /* As above. */ - if (priv->initial_peer != 0) - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - const gchar *target_id = tp_handle_inspect (repo, priv->initial_peer); - - g_value_set_string (value, target_id); - } - else - { - g_value_set_static_string (value, ""); - } - - break; - case PROP_PEER: - { - TpHandle peer = 0; - - if (priv->initial_peer != 0) - peer = priv->initial_peer; - else - peer = priv->peer; - - g_value_set_uint (value, peer); - break; - } - case PROP_CONNECTION: - g_value_set_object (value, priv->conn); - break; - case PROP_CREATOR: - g_value_set_uint (value, priv->creator); - break; - case PROP_CREATOR_ID: - { - TpHandleRepoIface *repo = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - - g_value_set_string (value, tp_handle_inspect (repo, priv->creator)); - } - break; - case PROP_REQUESTED: - 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); - 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", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "InitialAudio", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "InitialVideo", - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, "ImmutableStreams", - NULL)); - break; - case PROP_SESSION: - g_value_set_object (value, priv->session); - break; - case PROP_INITIAL_AUDIO: - g_value_set_boolean (value, priv->initial_audio); - break; - case PROP_INITIAL_VIDEO: - g_value_set_boolean (value, priv->initial_video); - break; - case PROP_IMMUTABLE_STREAMS: - g_value_set_boolean (value, priv->immutable_streams); - break; - case PROP_CURRENTLY_SENDING_TONES: - g_value_set_boolean (value, - tp_dtmf_player_is_active (priv->dtmf_player)); - break; - case PROP_INITIAL_TONES: - /* FIXME: stub */ - g_value_set_static_string (value, ""); - break; - case PROP_DEFERRED_TONES: - if (priv->deferred_tones != NULL) - g_value_set_string (value, priv->deferred_tones); - else - g_value_set_static_string (value, ""); - break; - default: - param_name = g_param_spec_get_name (pspec); - - if (tp_properties_mixin_has_property (object, param_name, - &tp_property_id)) - { - GValue *tp_property_value = - chan->properties.properties[tp_property_id].value; - - if (tp_property_value) - { - g_value_copy (tp_property_value, value); - return; - } - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_media_channel_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (object); - GabbleMediaChannelPrivate *priv = chan->priv; - const gchar *param_name; - guint tp_property_id; - - switch (property_id) { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_HANDLE_TYPE: - case PROP_HANDLE: - case PROP_CHANNEL_TYPE: - /* these properties are writable in the interface, but not actually - * meaningfully changable on this channel, so we do nothing */ - break; - case PROP_CONNECTION: - priv->conn = g_value_get_object (value); - break; - case PROP_CREATOR: - priv->creator = g_value_get_uint (value); - break; - case PROP_INITIAL_PEER: - priv->initial_peer = g_value_get_uint (value); - break; - case PROP_PEER_IN_RP: - priv->peer_in_rp = g_value_get_boolean (value); - break; - case PROP_SESSION: - g_assert (priv->session == NULL); - priv->session = g_value_dup_object (value); - if (priv->session != NULL) - { - - } - break; - case PROP_INITIAL_AUDIO: - priv->initial_audio = g_value_get_boolean (value); - break; - case PROP_INITIAL_VIDEO: - priv->initial_video = g_value_get_boolean (value); - break; - default: - param_name = g_param_spec_get_name (pspec); - - if (tp_properties_mixin_has_property (object, param_name, - &tp_property_id)) - { - tp_properties_mixin_change_value (object, tp_property_id, value, - NULL); - tp_properties_mixin_change_flags (object, tp_property_id, - TP_PROPERTY_FLAG_READ, - 0, NULL); - - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void gabble_media_channel_dispose (GObject *object); -static void gabble_media_channel_finalize (GObject *object); -static gboolean gabble_media_channel_add_member (GObject *obj, - TpHandle handle, - const gchar *message, - GError **error); -static gboolean gabble_media_channel_remove_member (GObject *obj, - TpHandle handle, const gchar *message, guint reason, GError **error); - -static void -gabble_media_channel_class_init (GabbleMediaChannelClass *gabble_media_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", "creator", NULL }, - { "InitiatorID", "creator-id", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinPropImpl streamed_media_props[] = { - { "ImmutableStreams", "immutable-streams", NULL }, - { "InitialAudio", "initial-audio", NULL }, - { "InitialVideo", "initial-video", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinPropImpl dtmf_props[] = { - { "CurrentlySendingTones", "currently-sending-tones", NULL }, - { "InitialTones", "initial-tones", NULL }, - { "DeferredTones", "deferred-tones", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_CHANNEL, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - channel_props, - }, - { TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - streamed_media_props, - }, - { TP_IFACE_CHANNEL_INTERFACE_DTMF, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - dtmf_props, - }, - { NULL } - }; - GObjectClass *object_class = G_OBJECT_CLASS (gabble_media_channel_class); - GParamSpec *param_spec; - - g_type_class_add_private (gabble_media_channel_class, - sizeof (GabbleMediaChannelPrivate)); - - object_class->constructor = gabble_media_channel_constructor; - - object_class->get_property = gabble_media_channel_get_property; - object_class->set_property = gabble_media_channel_set_property; - - object_class->dispose = gabble_media_channel_dispose; - object_class->finalize = gabble_media_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_string ("target-id", "Target JID", - "Currently empty, because this channel always has handle 0.", - 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 ("initial-peer", "Other participant", - "The TpHandle representing the other participant in the channel if known " - "at construct-time; 0 if the other participant was unknown at the time " - "of channel creation", - 0, G_MAXUINT32, 0, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_PEER, param_spec); - - param_spec = g_param_spec_boolean ("peer-in-rp", - "Peer initially in Remote Pending?", - "True if the channel was created with the most-deprecated " - "RequestChannels form, and so the peer should be in Remote Pending " - "before any XML has been sent.", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PEER_IN_RP, param_spec); - - param_spec = g_param_spec_uint ("peer", "Other participant", - "The TpHandle representing the other participant in the channel if " - "currently known; 0 if this is an anonymous channel on which " - "RequestStreams has not yet been called.", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PEER, param_spec); - - param_spec = g_param_spec_object ("connection", "GabbleConnection object", - "Gabble connection object that owns this media 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_uint ("creator", "Channel creator", - "The TpHandle representing the contact who created 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_CREATOR, param_spec); - - param_spec = g_param_spec_string ("creator-id", "Creator bare JID", - "The bare JID obtained by inspecting the creator handle.", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATOR_ID, param_spec); - - param_spec = g_param_spec_boolean ("requested", "Requested?", - "True if this channel was requested by the local user", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REQUESTED, 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_string ("nat-traversal", "NAT traversal", - "NAT traversal mechanism.", - "gtalk-p2p", - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAT_TRAVERSAL, - param_spec); - - param_spec = g_param_spec_string ("stun-server", "STUN server", - "IP or address of STUN server.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_SERVER, param_spec); - - param_spec = g_param_spec_uint ("stun-port", "STUN port", - "UDP port of STUN server.", - 0, G_MAXUINT16, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_PORT, param_spec); - - param_spec = g_param_spec_string ("gtalk-p2p-relay-token", - "GTalk P2P Relay Token", - "Magic token to authenticate with the Google Talk relay server.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_GTALK_P2P_RELAY_TOKEN, - param_spec); - - param_spec = g_param_spec_object ("session", "WockyJingleSession object", - "Jingle session associated with this media channel object.", - 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); - - param_spec = g_param_spec_boolean ("initial-audio", "InitialAudio", - "Whether the channel initially contained an audio stream", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_AUDIO, - param_spec); - - param_spec = g_param_spec_boolean ("initial-video", "InitialVideo", - "Whether the channel initially contained an video stream", - FALSE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_VIDEO, - param_spec); - - param_spec = g_param_spec_boolean ("immutable-streams", "ImmutableStreams", - "Whether the set of streams on this channel are fixed once requested", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_IMMUTABLE_STREAMS, - param_spec); - - param_spec = g_param_spec_boolean ("currently-sending-tones", - "CurrentlySendingTones", - "True if a DTMF tone is being sent", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CURRENTLY_SENDING_TONES, - param_spec); - - param_spec = g_param_spec_string ("initial-tones", "InitialTones", - "Initial DTMF tones to be sent in the first audio stream", - "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_INITIAL_TONES, - param_spec); - - param_spec = g_param_spec_string ("deferred-tones", "DeferredTones", - "DTMF tones that followed a 'w' or 'W', to be resumed on user request", - "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DEFERRED_TONES, - param_spec); - - tp_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleMediaChannelClass, properties_class), - channel_property_signatures, NUM_CHAN_PROPS, NULL); - - gabble_media_channel_class->dbus_props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleMediaChannelClass, dbus_props_class)); - - tp_group_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleMediaChannelClass, group_class), - gabble_media_channel_add_member, NULL); - tp_group_mixin_class_set_remove_with_reason_func (object_class, - gabble_media_channel_remove_member); - tp_group_mixin_class_allow_self_removal (object_class); - - tp_group_mixin_init_dbus_properties (object_class); -} - -void -gabble_media_channel_dispose (GObject *object) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (object); - GabbleMediaChannelPrivate *priv = self->priv; - GList *l; - - if (priv->dispose_has_run) - return; - - DEBUG ("called"); - - priv->dispose_has_run = TRUE; - - if (!priv->closed) - gabble_media_channel_close (self); - - g_assert (priv->closed); - g_assert (priv->session == NULL); - - /* Since the session's dead, all the stream_creation_datas should have been - * cancelled (which is indicated by their 'content' being NULL). - */ - for (l = priv->stream_creation_datas; l != NULL; l = l->next) - { - StreamCreationData *d = l->data; - g_assert (d->content == NULL); - } - - g_list_free (priv->stream_creation_datas); - priv->stream_creation_datas = NULL; - - if (priv->delayed_request_streams != NULL) - { - g_ptr_array_foreach (priv->delayed_request_streams, - (GFunc) destroy_request, NULL); - g_ptr_array_unref (priv->delayed_request_streams); - priv->delayed_request_streams = NULL; - } - - /* All of the streams should have closed in response to the contents being - * removed when the call ended. - */ - g_assert (priv->streams->len == 0); - g_ptr_array_unref (priv->streams); - priv->streams = NULL; - - if (G_OBJECT_CLASS (gabble_media_channel_parent_class)->dispose) - G_OBJECT_CLASS (gabble_media_channel_parent_class)->dispose (object); -} - -void -gabble_media_channel_finalize (GObject *object) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (object); - GabbleMediaChannelPrivate *priv = self->priv; - - g_free (priv->object_path); - tp_clear_pointer (&self->priv->deferred_tones, g_free); - - tp_group_mixin_finalize (object); - tp_properties_mixin_finalize (object); - - G_OBJECT_CLASS (gabble_media_channel_parent_class)->finalize (object); -} - - -/** - * gabble_media_channel_close_async: - * - * Implements D-Bus method Close - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_media_channel_close_async (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - - if (DEBUGGING) - { - gchar *caller = dbus_g_method_get_sender (context); - - DEBUG ("called by %s", caller); - g_free (caller); - } - - gabble_media_channel_close (self); - tp_svc_channel_return_from_close (context); -} - -void -gabble_media_channel_close (GabbleMediaChannel *self) -{ - GabbleMediaChannelPrivate *priv = self->priv; - - DEBUG ("called on %p", self); - - if (!priv->closed) - { - priv->closed = TRUE; - - if (priv->session != NULL) - wocky_jingle_session_terminate (priv->session, - WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); - - tp_svc_channel_emit_closed (self); - } -} - - -/** - * gabble_media_channel_get_channel_type - * - * Implements D-Bus method GetChannelType - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_media_channel_get_channel_type (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_channel_type (context, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); -} - - -/** - * gabble_media_channel_get_handle - * - * Implements D-Bus method GetHandle - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_media_channel_get_handle (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - - if (self->priv->initial_peer == 0) - tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_NONE, 0); - else - tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT, - self->priv->initial_peer); -} - - -/** - * gabble_media_channel_get_interfaces - * - * Implements D-Bus method GetInterfaces - * on interface org.freedesktop.Telepathy.Channel - */ -static void -gabble_media_channel_get_interfaces (TpSvcChannel *iface, - DBusGMethodInvocation *context) -{ - tp_svc_channel_return_from_get_interfaces (context, - gabble_media_channel_interfaces); -} - - -/** - * gabble_media_channel_get_session_handlers - * - * Implements D-Bus method GetSessionHandlers - * on interface org.freedesktop.Telepathy.Channel.Interface.MediaSignalling - */ -static void -gabble_media_channel_get_session_handlers (TpSvcChannelInterfaceMediaSignalling *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv; - GPtrArray *ret; - GType info_type = TP_STRUCT_TYPE_MEDIA_SESSION_HANDLER_INFO; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (self)); - - priv = self->priv; - - if (priv->session) - { - GValue handler = { 0, }; - - g_value_init (&handler, info_type); - g_value_take_boxed (&handler, - dbus_g_type_specialized_construct (info_type)); - - dbus_g_type_struct_set (&handler, - 0, priv->object_path, - 1, "rtp", - G_MAXUINT); - - ret = g_ptr_array_sized_new (1); - g_ptr_array_add (ret, g_value_get_boxed (&handler)); - } - else - { - ret = g_ptr_array_sized_new (0); - } - - tp_svc_channel_interface_media_signalling_return_from_get_session_handlers ( - context, ret); - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_unref (ret); -} - -/** - * make_stream_list: - * - * Creates an array of MediaStreamInfo structs. - * - * Precondition: priv->session is non-NULL. - */ -static GPtrArray * -make_stream_list (GabbleMediaChannel *self, - guint len, - GabbleMediaStream **streams) -{ - GabbleMediaChannelPrivate *priv = self->priv; - GPtrArray *ret; - guint i; - GType info_type = TP_STRUCT_TYPE_MEDIA_STREAM_INFO; - - g_assert (priv->session != NULL); - - ret = g_ptr_array_sized_new (len); - - for (i = 0; i < len; i++) - { - GValue entry = { 0, }; - guint id; - TpMediaStreamType type; - TpMediaStreamState connection_state; - CombinedStreamDirection combined_direction; - - g_object_get (streams[i], - "id", &id, - "media-type", &type, - "connection-state", &connection_state, - "combined-direction", &combined_direction, - NULL); - - g_value_init (&entry, info_type); - g_value_take_boxed (&entry, - dbus_g_type_specialized_construct (info_type)); - - dbus_g_type_struct_set (&entry, - 0, id, - 1, priv->peer, - 2, type, - 3, connection_state, - 4, COMBINED_DIRECTION_GET_DIRECTION (combined_direction), - 5, COMBINED_DIRECTION_GET_PENDING_SEND (combined_direction), - G_MAXUINT); - - g_ptr_array_add (ret, g_value_get_boxed (&entry)); - } - - return ret; -} - -/** - * gabble_media_channel_list_streams - * - * Implements D-Bus method ListStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -gabble_media_channel_list_streams (TpSvcChannelTypeStreamedMedia *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv; - GPtrArray *ret; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (self)); - - priv = self->priv; - - /* If the session has not yet started, or has ended, return an empty array. - */ - if (priv->session == NULL) - { - ret = g_ptr_array_new (); - } - else - { - ret = make_stream_list (self, priv->streams->len, - (GabbleMediaStream **) priv->streams->pdata); - } - - tp_svc_channel_type_streamed_media_return_from_list_streams (context, ret); - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_unref (ret); -} - - -static GabbleMediaStream * -_find_stream_by_id (GabbleMediaChannel *chan, - guint stream_id, - GError **error) -{ - GabbleMediaChannelPrivate *priv; - guint i; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (chan)); - - priv = chan->priv; - - for (i = 0; i < priv->streams->len; i++) - { - GabbleMediaStream *stream = g_ptr_array_index (priv->streams, i); - guint id; - - g_object_get (stream, "id", &id, NULL); - if (id == stream_id) - return stream; - } - - 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, - WockyJingleContent *content) -{ - GabbleMediaChannelPrivate *priv; - guint i; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (chan)); - - priv = chan->priv; - - for (i = 0; i < priv->streams->len; i++) - { - GabbleMediaStream *stream = g_ptr_array_index (priv->streams, i); - WockyJingleContent *c = WOCKY_JINGLE_CONTENT ( - gabble_media_stream_get_content (stream)); - - if (content == c) - return stream; - } - - return NULL; -} - -/** - * gabble_media_channel_remove_streams - * - * Implements DBus method RemoveStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -gabble_media_channel_remove_streams (TpSvcChannelTypeStreamedMedia *iface, - const GArray * streams, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *obj = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv; - GPtrArray *stream_objs; - GError *error = NULL; - guint i; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (obj)); - - priv = obj->priv; - - if (!wocky_jingle_session_can_modify_contents (priv->session)) - { - 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; - } - - stream_objs = g_ptr_array_sized_new (streams->len); - - /* check that all stream ids are valid and at the same time build an array - * of stream objects so we don't have to look them up again after verifying - * all stream identifiers. */ - for (i = 0; i < streams->len; i++) - { - guint id = g_array_index (streams, guint, i); - GabbleMediaStream *stream; - guint j; - - stream = _find_stream_by_id (obj, id, &error); - - if (stream == NULL) - goto OUT; - - /* make sure we don't allow the client to repeatedly remove the same - stream */ - for (j = 0; j < stream_objs->len; j++) - { - GabbleMediaStream *tmp = g_ptr_array_index (stream_objs, j); - - if (tmp == stream) - { - stream = NULL; - break; - } - } - - if (stream != NULL) - g_ptr_array_add (stream_objs, stream); - } - - /* groovy, it's all good dude, let's remove them */ - if (stream_objs->len > 0) - { - GabbleMediaStream *stream; - WockyJingleMediaRtp *c; - - for (i = 0; i < stream_objs->len; i++) - { - stream = g_ptr_array_index (stream_objs, i); - c = gabble_media_stream_get_content (stream); - - /* FIXME: make sure session emits content-removed, on which we can - * delete it from the list */ - wocky_jingle_session_remove_content (priv->session, - (WockyJingleContent *) c); - } - } - -OUT: - g_ptr_array_unref (stream_objs); - - if (error) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - } - else - { - tp_svc_channel_type_streamed_media_return_from_remove_streams (context); - } -} - - -/** - * gabble_media_channel_request_stream_direction - * - * Implements D-Bus method RequestStreamDirection - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -gabble_media_channel_request_stream_direction (TpSvcChannelTypeStreamedMedia *iface, - guint stream_id, - guint stream_direction, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv; - GabbleMediaStream *stream; - GError *error = NULL; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (self)); - - priv = self->priv; - - if (stream_direction > TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL) - { - 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); - return; - } - - stream = _find_stream_by_id (self, stream_id, &error); - - if (stream == NULL) - { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - DEBUG ("called (stream %s, direction %u)", stream->name, stream_direction); - - /* streams with no session? I think not... */ - g_assert (priv->session != NULL); - - if (stream_direction == TP_MEDIA_STREAM_DIRECTION_NONE) - { - if (wocky_jingle_session_can_modify_contents (priv->session)) - { - WockyJingleMediaRtp *c; - - DEBUG ("request for NONE direction; removing stream"); - - c = gabble_media_stream_get_content (stream); - 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_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); - } - - return; - } - - if (gabble_media_stream_change_direction (stream, stream_direction, &error)) - { - tp_svc_channel_type_streamed_media_return_from_request_stream_direction ( - context); - } - else - { - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - -typedef struct { - /* number of streams requested == number of content objects */ - guint len; - /* array of @len borrowed pointers */ - 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]. - */ - GabbleMediaStream **streams; - /* number of non-NULL elements in streams (0 <= satisfied <= contents) */ - guint satisfied; - /* succeeded_cb(context, GPtrArray<TP_STRUCT_TYPE_MEDIA_STREAM_INFO>) - * will be called if the stream request succeeds. - */ - GFunc succeeded_cb; - /* failed_cb(context, GError *) will be called if the stream request fails. - */ - GFunc failed_cb; - gpointer context; -} PendingStreamRequest; - -static PendingStreamRequest * -pending_stream_request_new (GPtrArray *contents, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer context) -{ - PendingStreamRequest *p = g_slice_new0 (PendingStreamRequest); - - g_assert (succeeded_cb); - g_assert (failed_cb); - - p->len = contents->len; - p->contents = g_memdup (contents->pdata, contents->len * sizeof (gpointer)); - p->streams = g_new0 (GabbleMediaStream *, contents->len); - p->satisfied = 0; - p->succeeded_cb = succeeded_cb; - p->failed_cb = failed_cb; - p->context = context; - - return p; -} - -static gboolean -pending_stream_request_maybe_satisfy (PendingStreamRequest *p, - GabbleMediaChannel *channel, - WockyJingleContent *content, - GabbleMediaStream *stream) -{ - guint i; - - for (i = 0; i < p->len; i++) - { - if (p->contents[i] == content) - { - g_assert (p->streams[i] == NULL); - p->streams[i] = stream; - - if (++p->satisfied == p->len && p->context != NULL) - { - GPtrArray *ret = make_stream_list (channel, p->len, p->streams); - - p->succeeded_cb (p->context, ret); - g_ptr_array_foreach (ret, (GFunc) g_value_array_free, NULL); - g_ptr_array_unref (ret); - p->context = NULL; - return TRUE; - } - } - } - - return FALSE; -} - -static gboolean -pending_stream_request_maybe_fail (PendingStreamRequest *p, - GabbleMediaChannel *channel, - WockyJingleContent *content) -{ - guint i; - - for (i = 0; i < p->len; i++) - { - if (content == p->contents[i]) - { - GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "A stream was removed before it could be fully set up" }; - - /* return early */ - p->failed_cb (p->context, &e); - p->context = NULL; - return TRUE; - } - } - - return FALSE; -} - -static void -pending_stream_request_free (gpointer data) -{ - PendingStreamRequest *p = data; - - if (p->context != NULL) - { - GError e = { TP_ERROR, TP_ERROR_CANCELLED, - "The session terminated before the requested streams could be added" - }; - - p->failed_cb (p->context, &e); - } - - g_free (p->contents); - g_free (p->streams); - - g_slice_free (PendingStreamRequest, p); -} - -static gboolean -_gabble_media_channel_request_contents (GabbleMediaChannel *chan, - TpHandle peer, - const GArray *media_types, - GPtrArray **ret, - GError **error) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - gboolean want_audio, want_video; - WockyJingleDialect dialect; - guint idx; - const gchar *peer_resource; - const gchar *transport_ns = NULL; - - DEBUG ("called"); - - want_audio = want_video = FALSE; - - for (idx = 0; idx < media_types->len; idx++) - { - guint media_type = g_array_index (media_types, guint, idx); - - if (media_type == TP_MEDIA_STREAM_TYPE_AUDIO) - { - want_audio = TRUE; - } - else if (media_type == TP_MEDIA_STREAM_TYPE_VIDEO) - { - want_video = TRUE; - } - else - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "given media type %u is invalid", media_type); - return FALSE; - } - } - - /* existing call; the recipient and the mode has already been decided */ - if (priv->session != NULL) - { - peer_resource = wocky_jingle_session_get_peer_resource (priv->session); - - if (peer_resource[0] != '\0') - DEBUG ("existing call, using peer resource %s", peer_resource); - else - DEBUG ("existing call, using bare JID"); - - /* is a google call... we have no other option */ - if (!wocky_jingle_session_can_modify_contents (priv->session)) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Streams can't be added to ongoing Google Talk calls"); - return FALSE; - } - - /* check if the resource supports it; FIXME - we assume only - * one channel type (video or audio) will be added later */ - if (NULL == jingle_pick_best_content_type (priv->conn, peer, - peer_resource, - want_audio ? WOCKY_JINGLE_MEDIA_TYPE_AUDIO : WOCKY_JINGLE_MEDIA_TYPE_VIDEO)) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "member does not have the desired audio/video capabilities"); - - return FALSE; - } - - /* We assume we already picked the best possible transport ns for the - * previous streams, so we just reuse that one */ - { - 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); - - c = contents->data; - g_list_free (contents); - - transport_ns = wocky_jingle_content_get_transport_ns (c); - } - } - /* no existing call; we should choose a recipient and a mode */ - else - { - gchar *jid; - - DEBUG ("picking the best resource (want audio: %u, want video: %u", - want_audio, want_video); - - g_assert (priv->streams->len == 0); - - if (!jingle_pick_best_resource (priv->conn, peer, - want_audio, want_video, &transport_ns, &dialect, &peer_resource)) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_CAPABLE, - "member does not have the desired audio/video capabilities"); - return FALSE; - } - - DEBUG ("Picking resource '%s' (transport: %s, dialect: %u)", - peer_resource == NULL ? "(null)" : peer_resource, - transport_ns, dialect); - - jid = gabble_peer_to_jid (priv->conn, peer, peer_resource); - priv->peer = peer; - create_session (chan, jid, dialect); - g_free (jid); - - /* Change nat-traversal if we need to */ - if (!tp_strdiff (transport_ns, NS_JINGLE_TRANSPORT_ICEUDP)) - { - DEBUG ("changing nat-traversal property to ice-udp"); - g_object_set (chan, "nat-traversal", "ice-udp", NULL); - } - else if (!tp_strdiff (transport_ns, NS_JINGLE_TRANSPORT_RAWUDP)) - { - DEBUG ("changing nat-traversal property to raw-udp"); - g_object_set (chan, "nat-traversal", "none", NULL); - } - } - - /* check it's not a ridiculous number of streams */ - if ((priv->streams->len + media_types->len) > MAX_STREAMS) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "I think that's quite enough streams already"); - return FALSE; - } - - /* if we've got here, we're good to make the Jingle contents */ - - *ret = g_ptr_array_sized_new (media_types->len); - - for (idx = 0; idx < media_types->len; idx++) - { - guint media_type = g_array_index (media_types, guint, idx); - 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 ? - 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 */ - g_assert (content_ns != NULL); - g_assert (transport_ns != NULL); - - DEBUG ("Creating new jingle content with ns %s : %s", content_ns, transport_ns); - - c = wocky_jingle_session_add_content (priv->session, - media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? - 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 - * streams can take time due to the relay info lookup, and if it doesn't, - * we use an idle so it does). */ - g_assert (c != NULL); - g_ptr_array_add (*ret, c); - } - - return TRUE; -} - -/* user_data param is here so we match the GFunc prototype */ -static void -destroy_request (struct _delayed_request_streams_ctx *ctx, - gpointer user_data G_GNUC_UNUSED) -{ - GabbleMediaChannelPrivate *priv = ctx->chan->priv; - - if (ctx->unsure_period_ended_id) - g_signal_handler_disconnect (priv->conn->presence_cache, - ctx->unsure_period_ended_id); - - if (ctx->caps_disco_id) - g_signal_handler_disconnect (priv->conn->presence_cache, - ctx->caps_disco_id); - - if (ctx->context != NULL) - { - GError *error = NULL; - 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); - } - - g_array_unref (ctx->types); - g_slice_free (struct _delayed_request_streams_ctx, ctx); -} - -static void -destroy_and_remove_request (struct _delayed_request_streams_ctx *ctx) -{ - GabbleMediaChannelPrivate *priv = ctx->chan->priv; - - destroy_request (ctx, NULL); - g_ptr_array_remove_fast (priv->delayed_request_streams, ctx); -} - -static void media_channel_request_streams (GabbleMediaChannel *self, - TpHandle contact_handle, - const GArray *types, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer context); - -static gboolean -repeat_request (struct _delayed_request_streams_ctx *ctx) -{ - media_channel_request_streams (ctx->chan, ctx->contact_handle, ctx->types, - ctx->succeeded_cb, ctx->failed_cb, ctx->context); - - ctx->context = NULL; - destroy_and_remove_request (ctx); - return FALSE; -} - -static void -capabilities_discovered_cb (GabblePresenceCache *cache, - TpHandle handle, - struct _delayed_request_streams_ctx *ctx) -{ - /* If this isn't the contact we're waiting for, ignore the signal. */ - if (ctx->contact_handle != handle) - return; - - /* If we're still unsure about this contact (most likely because there are - * more cache caps pending), wait for them. */ - if (gabble_presence_cache_is_unsure (cache, handle)) - return; - - repeat_request (ctx); -} - -static void -delay_stream_request (GabbleMediaChannel *chan, - guint contact_handle, - const GArray *types, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer context) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - struct _delayed_request_streams_ctx *ctx = - g_slice_new0 (struct _delayed_request_streams_ctx); - - ctx->chan = chan; - ctx->contact_handle = contact_handle; - ctx->succeeded_cb = succeeded_cb; - ctx->failed_cb = failed_cb; - ctx->context = context; - ctx->types = g_array_sized_new (FALSE, FALSE, sizeof (guint), types->len); - g_array_append_vals (ctx->types, types->data, types->len); - - ctx->caps_disco_id = g_signal_connect (priv->conn->presence_cache, - "capabilities-discovered", G_CALLBACK (capabilities_discovered_cb), - ctx); - ctx->unsure_period_ended_id = g_signal_connect_swapped ( - priv->conn->presence_cache, "unsure-period-ended", - G_CALLBACK (repeat_request), ctx); - - g_ptr_array_add (priv->delayed_request_streams, ctx); -} - -static void -media_channel_request_streams (GabbleMediaChannel *self, - TpHandle contact_handle, - const GArray *types, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer context) -{ - GabbleMediaChannelPrivate *priv = self->priv; - GPtrArray *contents; - gboolean wait; - PendingStreamRequest *psr; - GError *error = NULL; - - if (types->len == 0) - { - GPtrArray *empty = g_ptr_array_sized_new (0); - - DEBUG ("no streams to request"); - succeeded_cb (context, empty); - g_ptr_array_unref (empty); - - return; - } - - /* If we know the caps haven't arrived yet, delay stream creation - * and check again later. Else, give up. */ - if (!contact_is_media_capable (self, contact_handle, &wait, &error)) - { - if (wait) - { - DEBUG ("Delaying RequestStreams until we get all caps from contact"); - delay_stream_request (self, contact_handle, types, - succeeded_cb, failed_cb, context); - g_error_free (error); - return; - } - - goto error; - } - - if (priv->peer != 0 && priv->peer != contact_handle) - { - 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; - } - - if (!_gabble_media_channel_request_contents (self, contact_handle, types, - &contents, &error)) - goto error; - - psr = pending_stream_request_new (contents, succeeded_cb, failed_cb, - context); - priv->pending_stream_requests = g_list_prepend (priv->pending_stream_requests, - psr); - g_ptr_array_unref (contents); - - /* signal acceptance */ - wocky_jingle_session_accept (priv->session); - - return; - -error: - DEBUG ("returning error %u: %s", error->code, error->message); - failed_cb (context, error); - g_error_free (error); -} - -/** - * gabble_media_channel_request_streams - * - * Implements D-Bus method RequestStreams - * on interface org.freedesktop.Telepathy.Channel.Type.StreamedMedia - */ -static void -gabble_media_channel_request_streams (TpSvcChannelTypeStreamedMedia *iface, - guint contact_handle, - const GArray *types, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - TpBaseConnection *base_conn = (TpBaseConnection *) self->priv->conn; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles ( - base_conn, TP_HANDLE_TYPE_CONTACT); - GError *error = NULL; - - if (!tp_handle_is_valid (contact_handles, contact_handle, &error)) - { - DEBUG ("that's not a handle, sonny! (%u)", contact_handle); - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - else - { - /* FIXME: disallow this if we've put the peer on hold? */ - - media_channel_request_streams (self, contact_handle, types, - (GFunc) tp_svc_channel_type_streamed_media_return_from_request_streams, - (GFunc) dbus_g_method_return_error, - context); - } -} - -/** - * gabble_media_channel_request_initial_streams: - * @chan: an outgoing call, which must have just been constructed. - * @succeeded_cb: called with arguments @user_data and a GPtrArray of - * TP_STRUCT_TYPE_MEDIA_STREAM_INFO if the request succeeds. - * @failed_cb: called with arguments @user_data and a GError * if the request - * fails. - * @user_data: context for the callbacks. - * - * Request streams corresponding to the values of InitialAudio and InitialVideo - * in the channel request. - */ -void -gabble_media_channel_request_initial_streams (GabbleMediaChannel *chan, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer user_data) -{ - 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 == tp_base_connection_get_self_handle (base_conn)); - /* ...which has just been constructed. */ - g_assert (priv->session == NULL); - - if (priv->initial_peer == 0) - { - /* This is a ye olde anonymous channel, so InitialAudio/Video should be - * impossible. - */ - g_assert (!priv->initial_audio); - g_assert (!priv->initial_video); - } - - if (priv->initial_audio) - { - media_type = TP_MEDIA_STREAM_TYPE_AUDIO; - g_array_append_val (types, media_type); - } - - if (priv->initial_video) - { - media_type = TP_MEDIA_STREAM_TYPE_VIDEO; - g_array_append_val (types, media_type); - } - - media_channel_request_streams (chan, priv->initial_peer, types, - succeeded_cb, failed_cb, user_data); - - g_array_unref (types); -} - -static gboolean -contact_is_media_capable (GabbleMediaChannel *chan, - TpHandle peer, - gboolean *wait_ret, - GError **error) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - GabblePresence *presence; - TpBaseConnection *conn = (TpBaseConnection *) priv->conn; - TpHandleRepoIface *contact_handles = tp_base_connection_get_handles ( - conn, TP_HANDLE_TYPE_CONTACT); - gboolean wait = FALSE; - - presence = gabble_presence_cache_get (priv->conn->presence_cache, peer); - - if (presence != NULL) - { - const GabbleCapabilitySet *caps = gabble_presence_peek_caps (presence); - - if (gabble_capability_set_has_one (caps, - gabble_capabilities_get_any_audio_video ())) - return TRUE; - } - - /* Okay, they're not capable (yet). Let's figure out whether we should wait, - * and return an appropriate error. - */ - if (gabble_presence_cache_is_unsure (priv->conn->presence_cache, peer)) - { - DEBUG ("presence cache is still unsure about handle %u", peer); - wait = TRUE; - } - else if (!priv->tried_decloaking && - gabble_presence_cache_request_decloaking (priv->conn->presence_cache, - peer, "media")) - { - /* only ask to decloak at most once per call */ - priv->tried_decloaking = TRUE; - DEBUG ("asked handle %u to decloak, let's see what they do", peer); - wait = TRUE; - } - - if (wait_ret != NULL) - *wait_ret = wait; - - if (presence == NULL) - 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_ERROR, TP_ERROR_NOT_CAPABLE, - "contact %d (%s) doesn't have sufficient media caps", peer, - tp_handle_inspect (contact_handles, peer)); - - return FALSE; -} - -static gboolean -gabble_media_channel_add_member (GObject *obj, - TpHandle handle, - const gchar *message, - GError **error) -{ - GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (obj); - GabbleMediaChannelPrivate *priv = chan->priv; - TpGroupMixin *mixin = TP_GROUP_MIXIN (obj); - TpIntset *set; - - /* did we create this channel? */ - if (priv->creator == mixin->self_handle) - { - GError *error_ = NULL; - gboolean wait; - - /* yes: check we don't have a peer already, and if not add this one to - * remote pending (but don't send an invitation yet). - */ - if (priv->peer != 0 && priv->peer != handle) - { - 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; - } - - /* We can't delay the request at this time, but if there's a chance - * the caps might be available later, we'll add the contact and - * hope for the best. */ - if (!contact_is_media_capable (chan, handle, &wait, &error_)) - { - if (wait) - { - DEBUG ("contact %u caps still pending, adding anyways", handle); - g_error_free (error_); - } - else - { - DEBUG ("%u: %s", error_->code, error_->message); - g_propagate_error (error, error_); - return FALSE; - } - } - - /* make the peer remote pending */ - set = tp_intset_new_containing (handle); - tp_group_mixin_change_members (obj, "", NULL, NULL, NULL, set, - mixin->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - tp_intset_destroy (set); - - /* and remove CanAdd, since it was only here to allow this deprecated - * API. */ - tp_group_mixin_change_flags (obj, 0, TP_CHANNEL_GROUP_FLAG_CAN_ADD); - - return TRUE; - } - else - { - /* no: has a session been created, is the handle being added ours, - * and are we in local pending? (call answer) */ - if (priv->session && - handle == mixin->self_handle && - tp_handle_set_is_member (mixin->local_pending, handle)) - { - /* is the call on hold? */ - if (priv->hold_state != TP_LOCAL_HOLD_STATE_UNHELD) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "Can't answer a call while it's on hold"); - return FALSE; - } - - /* make us a member */ - set = tp_intset_new_containing (handle); - tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, - handle, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - tp_intset_destroy (set); - - /* accept any local pending sends */ - g_ptr_array_foreach (priv->streams, - (GFunc) gabble_media_stream_accept_pending_local_send, NULL); - - /* signal acceptance */ - wocky_jingle_session_accept (priv->session); - - return TRUE; - } - } - - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "handle %u cannot be added in the current state", handle); - return FALSE; -} - -static gboolean -gabble_media_channel_remove_member (GObject *obj, - TpHandle handle, - const gchar *message, - TpChannelGroupChangeReason reason, - GError **error) -{ - GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (obj); - GabbleMediaChannelPrivate *priv = chan->priv; - TpGroupMixin *mixin = TP_GROUP_MIXIN (obj); - - /* We don't set CanRemove, and did allow self removal. So tp-glib should - * ensure this. - */ - g_assert (handle == mixin->self_handle); - - /* Closing up might make GabbleMediaFactory release its ref. */ - g_object_ref (chan); - - if (priv->session == NULL) - { - /* The call didn't even start yet; close up. */ - gabble_media_channel_close (chan); - } - else - { - WockyJingleReason wocky_jingle_reason = WOCKY_JINGLE_REASON_UNKNOWN; - - switch (reason) - { - case TP_CHANNEL_GROUP_CHANGE_REASON_NONE: - wocky_jingle_reason = WOCKY_JINGLE_REASON_UNKNOWN; - break; - case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE: - wocky_jingle_reason = WOCKY_JINGLE_REASON_GONE; - break; - case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY: - wocky_jingle_reason = WOCKY_JINGLE_REASON_BUSY; - break; - case TP_CHANNEL_GROUP_CHANGE_REASON_ERROR: - wocky_jingle_reason = WOCKY_JINGLE_REASON_GENERAL_ERROR; - break; - case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER: - wocky_jingle_reason = WOCKY_JINGLE_REASON_TIMEOUT; - break; - default: - 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; - } - - wocky_jingle_session_terminate (priv->session, wocky_jingle_reason, message, - error); - } - - /* Remove CanAdd if it was there for the deprecated anonymous channel - * semantics, since the channel will go away RSN. */ - tp_group_mixin_change_flags (obj, 0, TP_CHANNEL_GROUP_FLAG_CAN_ADD); - - g_object_unref (chan); - - return TRUE; -} - -/** - * copy_stream_list: - * - * Returns a copy of priv->streams. This is used when applying a function to - * all streams that could result in them being closed, to avoid stream_close_cb - * modifying the list being iterated. - */ -static GPtrArray * -copy_stream_list (GabbleMediaChannel *channel) -{ - return gabble_g_ptr_array_copy (channel->priv->streams); -} - - -/* return TRUE when the jingle reason is reason enough to raise a - * StreamError */ -static gboolean -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 (wocky_jingle_reason) - { - case WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR: - _stream_error = TP_MEDIA_STREAM_ERROR_NETWORK_ERROR; - break; - case WOCKY_JINGLE_REASON_MEDIA_ERROR: - _stream_error = TP_MEDIA_STREAM_ERROR_MEDIA_ERROR; - break; - case WOCKY_JINGLE_REASON_FAILED_APPLICATION: - _stream_error = TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED; - break; - case WOCKY_JINGLE_REASON_GENERAL_ERROR: - _stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; - break; - default: - { - if (stream_error != NULL) - *stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; - - return FALSE; - } - } - - if (stream_error != NULL) - *stream_error = _stream_error; - - return TRUE; -} - -static WockyJingleReason -media_stream_error_to_jingle_reason (TpMediaStreamError stream_error) -{ - switch (stream_error) - { - case TP_MEDIA_STREAM_ERROR_NETWORK_ERROR: - return WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR; - case TP_MEDIA_STREAM_ERROR_MEDIA_ERROR: - return WOCKY_JINGLE_REASON_MEDIA_ERROR; - case TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED: - return WOCKY_JINGLE_REASON_FAILED_APPLICATION; - default: - return WOCKY_JINGLE_REASON_GENERAL_ERROR; - } -} - -static TpChannelGroupChangeReason -wocky_jingle_reason_to_group_change_reason (WockyJingleReason wocky_jingle_reason) -{ - switch (wocky_jingle_reason) - { - case WOCKY_JINGLE_REASON_BUSY: - return TP_CHANNEL_GROUP_CHANGE_REASON_BUSY; - case WOCKY_JINGLE_REASON_GONE: - return TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE; - case WOCKY_JINGLE_REASON_TIMEOUT: - return TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER; - 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; - } -} - -static void -session_terminated_cb (WockyJingleSession *session, - gboolean local_terminator, - WockyJingleReason wocky_jingle_reason, - const gchar *text, - gpointer user_data) -{ - GabbleMediaChannel *channel = (GabbleMediaChannel *) user_data; - GabbleMediaChannelPrivate *priv = channel->priv; - TpGroupMixin *mixin = TP_GROUP_MIXIN (channel); - guint terminator; - WockyJingleState state; - TpIntset *set; - - DEBUG ("called"); - - g_object_get (session, - "state", &state, - NULL); - - if (local_terminator) - terminator = mixin->self_handle; - else - terminator = priv->peer; - - set = tp_intset_new (); - - /* remove us and the peer from the member list */ - tp_intset_add (set, mixin->self_handle); - tp_intset_add (set, priv->peer); - - tp_group_mixin_change_members ((GObject *) channel, - text, NULL, set, NULL, NULL, terminator, - wocky_jingle_reason_to_group_change_reason (wocky_jingle_reason)); - - tp_intset_destroy (set); - - /* Ignore any Google relay session responses we're waiting for. */ - g_list_foreach (priv->stream_creation_datas, stream_creation_data_cancel, - NULL); - - /* any contents that we were waiting for have now lost */ - g_list_foreach (priv->pending_stream_requests, - (GFunc) pending_stream_request_free, NULL); - g_list_free (priv->pending_stream_requests); - priv->pending_stream_requests = NULL; - - { - GPtrArray *tmp = copy_stream_list (channel); - guint i; - TpMediaStreamError stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; - gboolean is_error = extract_media_stream_error_from_jingle_reason ( - wocky_jingle_reason, &stream_error); - - for (i = 0; i < tmp->len; i++) - { - GabbleMediaStream *stream = tmp->pdata[i]; - - if (is_error) - { - guint id; - - DEBUG ("emitting stream error"); - - g_object_get (stream, "id", &id, NULL); - tp_svc_channel_type_streamed_media_emit_stream_error (channel, id, - stream_error, text); - } - - gabble_media_stream_close (stream); - } - - /* All the streams should have closed. */ - g_assert (priv->streams->len == 0); - - g_ptr_array_unref (tmp); - } - - /* remove the session */ - tp_clear_object (&priv->session); - - /* close us if we aren't already closed */ - if (!priv->closed) - { - DEBUG ("calling media channel close from session terminated cb"); - gabble_media_channel_close (channel); - } -} - - -static void -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); - WockyJingleState state; - TpIntset *set; - - DEBUG ("called"); - - g_object_get (session, - "state", &state, - NULL); - - set = tp_intset_new_containing (priv->peer); - - 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 - * in remote-pending if necessary */ - - tp_group_mixin_change_members (as_object, "", NULL, NULL, NULL, set, - mixin->self_handle, TP_CHANNEL_GROUP_CHANGE_REASON_INVITED); - - /* Remove CanAdd if it happened to be there to support deprecated - * RequestChannel(..., 0) followed by AddMembers([h], ...) semantics. - */ - tp_group_mixin_change_flags (as_object, 0, TP_CHANNEL_GROUP_FLAG_CAN_ADD); - } - - if (state == WOCKY_JINGLE_STATE_ACTIVE && - priv->creator == mixin->self_handle) - { - - DEBUG ("adding peer to the member list and updating flags"); - - /* add the peer to the member list */ - tp_group_mixin_change_members (as_object, "", set, NULL, NULL, NULL, - priv->peer, TP_CHANNEL_GROUP_CHANGE_REASON_NONE); - } - - tp_intset_destroy (set); -} - -static void -stream_close_cb (GabbleMediaStream *stream, - GabbleMediaChannel *chan) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - guint id, i; - gboolean still_have_audio = FALSE; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (chan)); - - g_object_get (stream, - "id", &id, - NULL); - - tp_svc_channel_type_streamed_media_emit_stream_removed (chan, id); - - if (g_ptr_array_remove (priv->streams, stream)) - g_object_unref (stream); - else - g_warning ("stream %p (%s) removed, but it wasn't in priv->streams!", - stream, stream->name); - - gabble_media_channel_hold_stream_closed (chan, stream); - - for (i = 0; i < priv->streams->len; i++) - { - GabbleMediaStream *other = g_ptr_array_index (priv->streams, i); - - if (gabble_media_stream_get_media_type (other) == - TP_MEDIA_STREAM_TYPE_AUDIO) - { - still_have_audio = TRUE; - } - } - - if (priv->have_some_audio && !still_have_audio) - { - /* the last audio stream just closed */ - tp_dtmf_player_cancel (priv->dtmf_player); - } - - priv->have_some_audio = still_have_audio; -} - -static void -stream_error_cb (GabbleMediaStream *stream, - TpMediaStreamError errno, - const gchar *message, - GabbleMediaChannel *chan) -{ - GabbleMediaChannelPrivate *priv = chan->priv; - WockyJingleMediaRtp *c; - GList *contents; - guint id; - - /* emit signal */ - g_object_get (stream, "id", &id, NULL); - tp_svc_channel_type_streamed_media_emit_stream_error (chan, id, errno, - message); - - contents = wocky_jingle_session_get_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 - * so we can dispose of the stream) - */ - c = gabble_media_stream_get_content (stream); - - if (errno == TP_MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED) - wocky_jingle_content_reject ((WockyJingleContent *) c, - WOCKY_JINGLE_REASON_FAILED_APPLICATION); - else - wocky_jingle_session_remove_content (priv->session, - (WockyJingleContent *) c); - } - else - { - /* We can't remove the content, or it's the only one left; let's - * terminate the call. (The alternative is to carry on the call with - * only audio/video, which will look or sound bad to the Google - * Talk-using peer.) - */ - DEBUG ("Terminating call in response to stream error"); - wocky_jingle_session_terminate (priv->session, - media_stream_error_to_jingle_reason (errno), message, NULL); - } - - g_list_free (contents); -} - -static void -stream_state_changed_cb (GabbleMediaStream *stream, - GParamSpec *pspec, - GabbleMediaChannel *chan) -{ - guint id; - TpMediaStreamState connection_state; - - g_object_get (stream, - "id", &id, - "connection-state", &connection_state, - NULL); - - tp_svc_channel_type_streamed_media_emit_stream_state_changed (chan, - id, connection_state); -} - -static void -stream_direction_changed_cb (GabbleMediaStream *stream, - GParamSpec *pspec, - GabbleMediaChannel *chan) -{ - guint id; - CombinedStreamDirection combined; - TpMediaStreamDirection direction; - TpMediaStreamPendingSend pending_send; - - g_object_get (stream, - "id", &id, - "combined-direction", &combined, - NULL); - - direction = COMBINED_DIRECTION_GET_DIRECTION (combined); - pending_send = COMBINED_DIRECTION_GET_PENDING_SEND (combined); - - DEBUG ("direction: %u, pending_send: %u", direction, pending_send); - - tp_svc_channel_type_streamed_media_emit_stream_direction_changed ( - chan, id, direction, pending_send); -} - -static void -construct_stream (GabbleMediaChannel *chan, - WockyJingleContent *c, - const gchar *name, - const gchar *nat_traversal, - const GPtrArray *relays, - gboolean initial) -{ - GObject *chan_o = (GObject *) chan; - GabbleMediaChannelPrivate *priv = chan->priv; - GabbleMediaStream *stream; - TpMediaStreamType mtype; - guint id; - gchar *object_path; - gboolean local_hold = (priv->hold_state == TP_LOCAL_HOLD_STATE_HELD || - priv->hold_state == TP_LOCAL_HOLD_STATE_PENDING_HOLD); - - id = priv->next_stream_id++; - - object_path = g_strdup_printf ("%s/MediaStream%u", - priv->object_path, id); - - stream = gabble_media_stream_new ( - tp_base_connection_get_dbus_daemon (TP_BASE_CONNECTION (priv->conn)), - object_path, c, name, id, nat_traversal, relays, local_hold); - mtype = gabble_media_stream_get_media_type (stream); - - if (mtype == TP_MEDIA_STREAM_TYPE_AUDIO) - { - gabble_media_stream_add_dtmf_player (stream, priv->dtmf_player); - priv->have_some_audio = TRUE; - } - - DEBUG ("%p: created new MediaStream %p for content '%s'", chan, stream, name); - - g_ptr_array_add (priv->streams, stream); - - /* if any RequestStreams call was waiting for a stream to be created for - * that content, return from it successfully */ - { - GList *l = priv->pending_stream_requests; - - while (l != NULL) - { - if (pending_stream_request_maybe_satisfy (l->data, - chan, c, stream)) - { - GList *dead = l; - - pending_stream_request_free (dead->data); - - l = dead->next; - priv->pending_stream_requests = g_list_delete_link ( - priv->pending_stream_requests, dead); - } - else - { - l = l->next; - } - } - } - - gabble_signal_connect_weak (stream, "close", (GCallback) stream_close_cb, - chan_o); - gabble_signal_connect_weak (stream, "error", (GCallback) stream_error_cb, - chan_o); - gabble_signal_connect_weak (stream, "notify::connection-state", - (GCallback) stream_state_changed_cb, chan_o); - gabble_signal_connect_weak (stream, "notify::combined-direction", - (GCallback) stream_direction_changed_cb, chan_o); - - if (initial) - { - /* If we accepted the call, then automagically accept the initial streams - * when they pop up */ - if (tp_handle_set_is_member (chan->group.members, - chan->group.self_handle)) - { - gabble_media_stream_accept_pending_local_send (stream); - } - } - - DEBUG ("emitting StreamAdded with type '%s'", - mtype == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video"); - - tp_svc_channel_type_streamed_media_emit_stream_added ( - chan, id, priv->peer, mtype); - - /* StreamAdded does not include the stream's direction and pending send - * information, so we call the notify::combined-direction handler in order to - * emit StreamDirectionChanged for the initial state. - */ - stream_direction_changed_cb (stream, NULL, chan); - - gabble_media_channel_hold_new_stream (chan, stream, - WOCKY_JINGLE_MEDIA_RTP (c)); - - if (priv->ready) - { - /* all of the streams are bidirectional from farsight's point of view, it's - * just in the signalling they change */ - DEBUG ("emitting MediaSessionHandler:NewStreamHandler signal for stream %d", id); - tp_svc_media_session_handler_emit_new_stream_handler (chan, - object_path, id, mtype, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); - } - - g_free (object_path); -} - -static void -stream_creation_data_cancel (gpointer p, - gpointer unused) -{ - StreamCreationData *d = p; - - tp_clear_object (&d->content); -} - -static void -stream_creation_data_free (gpointer p) -{ - StreamCreationData *d = p; - - g_free (d->name); - - if (d->content != NULL) - { - g_signal_handler_disconnect (d->content, d->removed_id); - g_object_unref (d->content); - } - - if (d->self != NULL) - { - GabbleMediaChannelPrivate *priv = d->self->priv; - - g_object_remove_weak_pointer (G_OBJECT (d->self), (gpointer *) &d->self); - priv->stream_creation_datas = g_list_remove ( - priv->stream_creation_datas, d); - } - - g_slice_free (StreamCreationData, d); -} - -static gboolean -construct_stream_later_cb (gpointer user_data) -{ - StreamCreationData *d = user_data; - - if (d->content != NULL && d->self != NULL) - construct_stream (d->self, d->content, d->name, d->nat_traversal, NULL, - d->initial); - - return FALSE; -} - -static void -google_relay_session_cb (GPtrArray *relays, - gpointer user_data) -{ - StreamCreationData *d = user_data; - GPtrArray *tp_relays = gabble_build_tp_relay_info (relays); - - if (d->content != NULL && d->self != NULL) - construct_stream (d->self, d->content, d->name, d->nat_traversal, tp_relays, - d->initial); - - g_ptr_array_unref (tp_relays); - stream_creation_data_free (d); -} - -static void -content_removed_cb (WockyJingleContent *content, - StreamCreationData *d) -{ - - if (d->content == NULL) - return; - - if (d->self != NULL) - { - GList *l = d->self->priv->pending_stream_requests; - - /* if any RequestStreams call was waiting for a stream to be created for - * that content, return from it unsuccessfully */ - while (l != NULL) - { - if (pending_stream_request_maybe_fail (l->data, - d->self, d->content)) - { - GList *dead = l; - - pending_stream_request_free (dead->data); - - l = dead->next; - d->self->priv->pending_stream_requests = g_list_delete_link ( - d->self->priv->pending_stream_requests, dead); - } - else - { - l = l->next; - } - } - } - - g_signal_handler_disconnect (d->content, d->removed_id); - g_object_unref (d->content); - d->content = NULL; -} - -static void -create_stream_from_content (GabbleMediaChannel *self, - WockyJingleContent *c, - gboolean initial) -{ - gchar *name; - StreamCreationData *d; - - g_object_get (c, - "name", &name, - NULL); - - if (G_OBJECT_TYPE (c) != WOCKY_TYPE_JINGLE_MEDIA_RTP) - { - DEBUG ("ignoring non MediaRtp content '%s'", name); - g_free (name); - return; - } - - d = g_slice_new0 (StreamCreationData); - - d->self = self; - d->name = name; - d->content = g_object_ref (c); - d->initial = initial; - - g_object_add_weak_pointer (G_OBJECT (d->self), (gpointer *) &d->self); - - /* If the content gets removed before we've finished looking up its - * relay, we need to cancel the creation of the stream, - * and make any PendingStreamRequests fail */ - d->removed_id = g_signal_connect (c, "removed", - G_CALLBACK (content_removed_cb), d); - - self->priv->stream_creation_datas = g_list_prepend ( - self->priv->stream_creation_datas, d); - - 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. - * We ask for enough relays for 2 components (RTP and RTCP) since we - * don't yet know whether there will be RTCP. */ - d->nat_traversal = "gtalk-p2p"; - DEBUG ("Attempting to 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; - - case JINGLE_TRANSPORT_ICE_UDP: - d->nat_traversal = "ice-udp"; - break; - - default: - d->nat_traversal = "none"; - } - - /* If we got here, just create the stream (do it asynchronously so that the - * behaviour is the same in each case) */ - g_idle_add_full (G_PRIORITY_DEFAULT, construct_stream_later_cb, - d, stream_creation_data_free); -} - -static void -session_content_rejected_cb (WockyJingleSession *session, - WockyJingleContent *c, WockyJingleReason reason, const gchar *message, - gpointer user_data) -{ - GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (user_data); - GabbleMediaStream *stream = _find_stream_by_content (chan, c); - TpMediaStreamError stream_error = TP_MEDIA_STREAM_ERROR_UNKNOWN; - guint id = 0; - - DEBUG (" "); - - g_return_if_fail (stream != NULL); - - g_object_get (stream, - "id", &id, - NULL); - - extract_media_stream_error_from_jingle_reason (reason, &stream_error); - - tp_svc_channel_type_streamed_media_emit_stream_error (chan, id, stream_error, - message); -} - -static void -session_new_content_cb (WockyJingleSession *session, - WockyJingleContent *c, gpointer user_data) -{ - GabbleMediaChannel *chan = GABBLE_MEDIA_CHANNEL (user_data); - - DEBUG ("called"); - - create_stream_from_content (chan, c, FALSE); -} - -static void -_emit_new_stream (GabbleMediaChannel *chan, - GabbleMediaStream *stream) -{ - gchar *object_path; - guint id, media_type; - - g_object_get (stream, - "object-path", &object_path, - "id", &id, - "media-type", &media_type, - NULL); - - /* all of the streams are bidirectional from farsight's point of view, it's - * just in the signalling they change */ - DEBUG ("emitting MediaSessionHandler:NewStreamHandler signal for %s stream %d ", - media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video", id); - tp_svc_media_session_handler_emit_new_stream_handler (chan, - object_path, id, media_type, TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL); - - g_free (object_path); -} - - -static void -gabble_media_channel_ready (TpSvcMediaSessionHandler *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv = self->priv; - - if (priv->session == NULL) - { - /* This could also be because someone called Ready() before the - * SessionHandler was announced. But the fact that the SessionHandler is - * actually also the Channel, and thus this method is available before - * NewSessionHandler is emitted, is an implementation detail. So the - * error message describes the only legitimate situation in which this - * could arise. - */ - 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); - return; - } - - if (!priv->ready) - { - guint i; - - DEBUG ("emitting NewStreamHandler for each stream"); - - priv->ready = TRUE; - - for (i = 0; i < priv->streams->len; i++) - _emit_new_stream (self, g_ptr_array_index (priv->streams, i)); - } - - tp_svc_media_session_handler_return_from_ready (context); -} - -static void -gabble_media_channel_error (TpSvcMediaSessionHandler *iface, - guint errno, - const gchar *message, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GabbleMediaChannelPrivate *priv; - GPtrArray *tmp; - guint i; - WockyJingleState state; - - g_assert (GABBLE_IS_MEDIA_CHANNEL (self)); - - priv = self->priv; - - if (priv->session == NULL) - { - /* This could also be because someone called Error() before the - * SessionHandler was announced. But the fact that the SessionHandler is - * actually also the Channel, and thus this method is available before - * NewSessionHandler is emitted, is an implementation detail. So the - * error message describes the only legitimate situation in which this - * could arise. - */ - 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); - return; - } - - DEBUG ("Media.SessionHandler::Error called, error %u (%s) -- " - "emitting error on each stream", errno, message); - - g_object_get (priv->session, "state", &state, NULL); - - if (state == WOCKY_JINGLE_STATE_ENDED) - { - tp_svc_media_session_handler_return_from_error (context); - return; - } - 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", WOCKY_JINGLE_STATE_ENDED, NULL); - tp_svc_media_session_handler_return_from_error (context); - return; - } - - /* Calling gabble_media_stream_error () on all the streams will ultimately - * cause them all to emit 'closed'. In response to 'closed', stream_close_cb - * unrefs them, and removes them from priv->streams. So, we copy the stream - * list to avoid it being modified from underneath us. - */ - tmp = copy_stream_list (self); - - for (i = 0; i < tmp->len; i++) - { - GabbleMediaStream *stream = g_ptr_array_index (tmp, i); - - gabble_media_stream_error (stream, errno, message, NULL); - } - - g_ptr_array_unref (tmp); - - tp_svc_media_session_handler_return_from_error (context); -} - -#define TONE_MS 200 -#define GAP_MS 100 -#define PAUSE_MS 3000 -/* arbitrary limit on the length of a tone started with StartTone */ -#define MAX_TONE_SECONDS 10 - -static void -gabble_media_channel_start_tone (TpSvcChannelInterfaceDTMF *iface, - guint stream_id G_GNUC_UNUSED, - guchar event, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - gchar tones[2] = { '\0', '\0' }; - GError *error = NULL; - - if (!self->priv->have_some_audio) - { - GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "There are no audio streams" }; - - dbus_g_method_return_error (context, &e); - return; - } - - tones[0] = tp_dtmf_event_to_char (event); - - if (tp_dtmf_player_play (self->priv->dtmf_player, - tones, MAX_TONE_SECONDS * 1000, GAP_MS, PAUSE_MS, &error)) - { - tp_clear_pointer (&self->priv->deferred_tones, g_free); - tp_svc_channel_interface_dtmf_emit_sending_tones (self, tones); - tp_svc_channel_interface_dtmf_return_from_start_tone (context); - } - else - { - dbus_g_method_return_error (context, error); - g_clear_error (&error); - } -} - -static void -gabble_media_channel_stop_tone (TpSvcChannelInterfaceDTMF *iface, - guint stream_id, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - - tp_dtmf_player_cancel (self->priv->dtmf_player); - tp_svc_channel_interface_dtmf_return_from_stop_tone (context); -} - -static void -gabble_media_channel_multiple_tones ( - TpSvcChannelInterfaceDTMF *iface, - const gchar *dialstring, - DBusGMethodInvocation *context) -{ - GabbleMediaChannel *self = GABBLE_MEDIA_CHANNEL (iface); - GError *error = NULL; - - if (!self->priv->have_some_audio) - { - GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "There are no audio streams" }; - - dbus_g_method_return_error (context, &e); - return; - } - - if (tp_dtmf_player_play (self->priv->dtmf_player, - dialstring, TONE_MS, GAP_MS, PAUSE_MS, &error)) - { - tp_clear_pointer (&self->priv->deferred_tones, g_free); - tp_svc_channel_interface_dtmf_emit_sending_tones (self, dialstring); - tp_svc_channel_interface_dtmf_return_from_start_tone (context); - } - else - { - dbus_g_method_return_error (context, error); - g_clear_error (&error); - } -} - -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_media_channel_##x##suffix) - IMPLEMENT(close,_async); - IMPLEMENT(get_channel_type,); - IMPLEMENT(get_handle,); - IMPLEMENT(get_interfaces,); -#undef IMPLEMENT -} - -static void -dtmf_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceDTMFClass *klass = g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_dtmf_implement_##x (\ - klass, gabble_media_channel_##x) - IMPLEMENT(start_tone); - IMPLEMENT(stop_tone); - IMPLEMENT(multiple_tones); -#undef IMPLEMENT -} - -static void -streamed_media_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelTypeStreamedMediaClass *klass = - (TpSvcChannelTypeStreamedMediaClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_type_streamed_media_implement_##x (\ - klass, gabble_media_channel_##x) - IMPLEMENT(list_streams); - IMPLEMENT(remove_streams); - IMPLEMENT(request_stream_direction); - IMPLEMENT(request_streams); -#undef IMPLEMENT -} - -static void -media_signalling_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcChannelInterfaceMediaSignallingClass *klass = - (TpSvcChannelInterfaceMediaSignallingClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_channel_interface_media_signalling_implement_##x (\ - klass, gabble_media_channel_##x) - IMPLEMENT(get_session_handlers); -#undef IMPLEMENT -} - -static void -session_handler_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcMediaSessionHandlerClass *klass = - (TpSvcMediaSessionHandlerClass *) g_iface; - -#define IMPLEMENT(x) tp_svc_media_session_handler_implement_##x (\ - klass, gabble_media_channel_##x) - IMPLEMENT(error); - IMPLEMENT(ready); -#undef IMPLEMENT -} diff --git a/src/media-channel.h b/src/media-channel.h deleted file mode 100644 index cbe488af2..000000000 --- a/src/media-channel.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * gabble-media-channel.h - Header for GabbleMediaChannel - * Copyright (C) 2006 Collabora Ltd. - * Copyright (C) 2006 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_MEDIA_CHANNEL_H__ -#define __GABBLE_MEDIA_CHANNEL_H__ - -#include <glib-object.h> - -#include <telepathy-glib/telepathy-glib.h> -#include <telepathy-glib/properties-mixin.h> - -#include "presence.h" - -G_BEGIN_DECLS - -typedef struct _GabbleMediaChannel GabbleMediaChannel; -typedef struct _GabbleMediaChannelPrivate GabbleMediaChannelPrivate; -typedef struct _GabbleMediaChannelClass GabbleMediaChannelClass; - -struct _GabbleMediaChannelClass { - GObjectClass parent_class; - - TpGroupMixinClass group_class; - TpPropertiesMixinClass properties_class; - TpDBusPropertiesMixinClass dbus_props_class; -}; - -struct _GabbleMediaChannel { - GObject parent; - - TpGroupMixin group; - TpPropertiesMixin properties; - - GabbleMediaChannelPrivate *priv; -}; - -GType gabble_media_channel_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_MEDIA_CHANNEL \ - (gabble_media_channel_get_type ()) -#define GABBLE_MEDIA_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_MEDIA_CHANNEL,\ - GabbleMediaChannel)) -#define GABBLE_MEDIA_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_MEDIA_CHANNEL,\ - GabbleMediaChannelClass)) -#define GABBLE_IS_MEDIA_CHANNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_MEDIA_CHANNEL)) -#define GABBLE_IS_MEDIA_CHANNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_MEDIA_CHANNEL)) -#define GABBLE_MEDIA_CHANNEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_MEDIA_CHANNEL, \ - GabbleMediaChannelClass)) - -void gabble_media_channel_request_initial_streams (GabbleMediaChannel *chan, - GFunc succeeded_cb, - GFunc failed_cb, - gpointer user_data); - -void gabble_media_channel_close (GabbleMediaChannel *self); - -G_END_DECLS - -#endif /* #ifndef __GABBLE_MEDIA_CHANNEL_H__*/ diff --git a/src/media-factory.c b/src/media-factory.c index 2d46258b6..039f54911 100644 --- a/src/media-factory.c +++ b/src/media-factory.c @@ -38,7 +38,6 @@ #include "debug.h" #include "call-channel.h" -#include "media-channel.h" #include "namespaces.h" #include "util.h" @@ -72,29 +71,6 @@ media_channel_request_free (MediaChannelRequest *mcr) g_slice_free (MediaChannelRequest, mcr); } -static void -media_channel_request_succeeded_cb (MediaChannelRequest *mcr, - GPtrArray *streams) -{ - tp_channel_manager_emit_new_channel (mcr->self, - mcr->channel, mcr->request_tokens); - - media_channel_request_free (mcr); -} - -static void -media_channel_request_failed_cb (MediaChannelRequest *mcr, - GError *error) -{ - GSList *l; - - for (l = mcr->request_tokens; l != NULL; l = g_slist_next (l)) - tp_channel_manager_emit_request_failed (mcr->self, l->data, - error->domain, error->code, error->message); - - media_channel_request_free (mcr); -} - static void channel_manager_iface_init (gpointer, gpointer); static void caps_channel_manager_iface_init (gpointer, gpointer); @@ -117,14 +93,10 @@ struct _GabbleMediaFactoryPrivate GabbleConnection *conn; gulong status_changed_id; - GList *media_channels; GList *call_channels; GList *pending_call_channels; guint channel_index; - /* Whether or not we should use call channels for incoming calls */ - gboolean use_call_channels; - gboolean dispose_has_run; }; @@ -159,7 +131,6 @@ gabble_media_factory_dispose (GObject *object) priv->dispose_has_run = TRUE; gabble_media_factory_close_all (fac); - g_assert (priv->media_channels == NULL); g_assert (priv->call_channels == NULL); if (G_OBJECT_CLASS (gabble_media_factory_parent_class)->dispose) @@ -231,76 +202,6 @@ gabble_media_factory_class_init (GabbleMediaFactoryClass *gabble_media_factory_c } -/** - * media_channel_closed_cb: - * - * Signal callback for when a media channel is closed. Removes the references - * that #GabbleMediaFactory holds to them. - */ -static void -media_channel_closed_cb (GabbleMediaChannel *chan, gpointer user_data) -{ - GabbleMediaFactory *fac = GABBLE_MEDIA_FACTORY (user_data); - GabbleMediaFactoryPrivate *priv = fac->priv; - - tp_channel_manager_emit_channel_closed_for_object (fac, - TP_EXPORTABLE_CHANNEL (chan)); - - DEBUG ("removing media channel %p with ref count %d", - chan, G_OBJECT (chan)->ref_count); - - priv->media_channels = g_list_remove (priv->media_channels, chan); - g_object_unref (chan); -} - -/** - * new_media_channel - * - * Creates a new empty GabbleMediaChannel. - */ -static GabbleMediaChannel * -new_media_channel (GabbleMediaFactory *fac, - WockyJingleSession *sess, - TpHandle maybe_peer, - gboolean peer_in_rp, - gboolean initial_audio, - gboolean initial_video) -{ - GabbleMediaFactoryPrivate *priv; - TpBaseConnection *conn; - GabbleMediaChannel *chan; - gchar *object_path; - - g_assert (GABBLE_IS_MEDIA_FACTORY (fac)); - - priv = fac->priv; - conn = (TpBaseConnection *) priv->conn; - - object_path = g_strdup_printf ("%s/MediaChannel%u", - tp_base_connection_get_object_path (conn), priv->channel_index); - priv->channel_index += 1; - - chan = g_object_new (GABBLE_TYPE_MEDIA_CHANNEL, - "connection", priv->conn, - "object-path", object_path, - "session", sess, - "initial-peer", maybe_peer, - "peer-in-rp", peer_in_rp, - "initial-audio", initial_audio, - "initial-video", initial_video, - NULL); - - DEBUG ("object path %s", object_path); - - g_signal_connect (chan, "closed", (GCallback) media_channel_closed_cb, fac); - - priv->media_channels = g_list_prepend (priv->media_channels, chan); - - g_free (object_path); - - return chan; -} - static void call_channel_closed_cb (GabbleCallChannel *chan, gpointer user_data) { @@ -423,11 +324,6 @@ gabble_media_factory_close_all (GabbleMediaFactory *fac) DEBUG ("closing channels"); /* Close will cause the channel to be removed from the list indirectly..*/ - while (priv->media_channels != NULL) - gabble_media_channel_close ( - GABBLE_MEDIA_CHANNEL (priv->media_channels->data)); - - /* Close will cause the channel to be removed from the list indirectly..*/ while (priv->call_channels != NULL) tp_base_channel_close (TP_BASE_CHANNEL (priv->call_channels->data)); @@ -464,43 +360,10 @@ new_jingle_session_cb (GabbleJingleMint *jm, peer = tp_handle_ensure (contacts, wocky_jingle_session_get_peer_jid (sess), NULL, NULL); - if (self->priv->use_call_channels) - { - new_call_channel (self, sess, peer, - FALSE, NULL, - FALSE, NULL, - NULL); - } - else - { - GabbleMediaChannel *chan = new_media_channel (self, sess, - peer, - FALSE, FALSE, FALSE); - GList *cs; - - /* FIXME: we need this detection to properly adjust nat-traversal on - * the channel. We hope all contents will have the same transport... */ - cs = wocky_jingle_session_get_contents (sess); - - if (cs != NULL) - { - WockyJingleContent *c = cs->data; - gchar *ns; - - g_object_get (c, "transport-ns", &ns, NULL); - - if (!tp_strdiff (ns, NS_JINGLE_TRANSPORT_ICEUDP)) - g_object_set (chan, "nat-traversal", "ice-udp", NULL); - else if (!tp_strdiff (ns, NS_JINGLE_TRANSPORT_RAWUDP)) - g_object_set (chan, "nat-traversal", "none", NULL); - - g_free (ns); - g_list_free (cs); - } - - tp_channel_manager_emit_new_channel (self, - TP_EXPORTABLE_CHANNEL (chan), NULL); - } + new_call_channel (self, sess, peer, + FALSE, NULL, + FALSE, NULL, + NULL); } static void @@ -550,9 +413,6 @@ gabble_media_factory_foreach_channel (TpChannelManager *manager, GabbleMediaFactoryPrivate *priv = fac->priv; GList *l; - for (l = priv->media_channels; l != NULL; l = g_list_next (l)) - foreach (TP_EXPORTABLE_CHANNEL (l->data), user_data); - for (l = priv->call_channels; l != NULL; l = g_list_next (l)) foreach (TP_EXPORTABLE_CHANNEL (l->data), user_data); } @@ -563,38 +423,6 @@ static const gchar * const media_channel_fixed_properties[] = { NULL }; -/* If you change this at all, you'll probably also need to change both_allowed - * and video_allowed */ -static const gchar * const named_channel_allowed_properties[] = { - TP_PROP_CHANNEL_TARGET_HANDLE, - TP_PROP_CHANNEL_TARGET_ID, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, - NULL -}; - -static const gchar * const * both_allowed = - named_channel_allowed_properties + 2; - -static const gchar * const audio_allowed[] = { - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_IMMUTABLE_STREAMS, - NULL -}; - -static const gchar * const video_allowed[] = { - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_IMMUTABLE_STREAMS, - NULL -}; - -static const gchar * const both_allowed_immutable[] = { - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_IMMUTABLE_STREAMS, - NULL -}; - static const gchar * const call_channel_allowed_properties[] = { TP_PROP_CHANNEL_TARGET_HANDLE, TP_PROP_CHANNEL_TARGET_ID, @@ -648,21 +476,6 @@ gabble_media_factory_call_channel_allowed_properties (void) } static GHashTable * -gabble_media_factory_streamed_media_channel_class (void) -{ - GHashTable *table = tp_asv_new ( - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, - TP_HANDLE_TYPE_CONTACT, - NULL); - - tp_asv_set_static_string (table, - TP_PROP_CHANNEL_CHANNEL_TYPE, - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA); - - return table; -} - -static GHashTable * gabble_media_factory_call_channel_class (void) { GHashTable *table = tp_asv_new ( @@ -681,13 +494,7 @@ gabble_media_factory_type_foreach_channel_class (GType type, TpChannelManagerTypeChannelClassFunc func, gpointer user_data) { - GHashTable *table = gabble_media_factory_streamed_media_channel_class (); - - func (type, table, named_channel_allowed_properties, user_data); - - g_hash_table_unref (table); - - table = gabble_media_factory_call_channel_class (); + GHashTable *table = gabble_media_factory_call_channel_class (); func (type, table, call_channel_allowed_properties, user_data); @@ -697,154 +504,11 @@ gabble_media_factory_type_foreach_channel_class (GType type, typedef enum { - METHOD_REQUEST, METHOD_CREATE, METHOD_ENSURE, } RequestMethod; static gboolean -gabble_media_factory_requestotron (TpChannelManager *manager, - gpointer request_token, - GHashTable *request_properties, - RequestMethod method) -{ - GabbleMediaFactory *self = GABBLE_MEDIA_FACTORY (manager); - GabbleMediaFactoryPrivate *priv = self->priv; - TpHandleType handle_type; - TpHandle handle; - GabbleMediaChannel *channel = NULL; - GError *error = NULL; - gboolean require_target_handle, add_peer_to_remote_pending; - gboolean initial_audio, initial_video; - - /* Supported modes of operation: - * - RequestChannel(None, 0): - * channel is anonymous; - * caller may optionally use AddMembers to add the peer to RemotePending - * without sending them any XML; - * caller uses RequestStreams to set the peer and start the call. - * - RequestChannel(Contact, n) where n != 0: - * channel has TargetHandle=n; - * n is in remote pending; - * call is started when caller calls RequestStreams. - * - CreateChannel({THT: Contact, TH: n}): - * channel has TargetHandle=n - * n is not in the group interface at all - * call is started when caller calls RequestStreams. - * - EnsureChannel({THT: Contact, TH: n}): - * look for a channel whose peer is n, and return that if found with - * whatever properties and group membership it has; - * otherwise the same as into CreateChannel - */ - switch (method) - { - case METHOD_REQUEST: - require_target_handle = FALSE; - add_peer_to_remote_pending = TRUE; - break; - case METHOD_CREATE: - case METHOD_ENSURE: - require_target_handle = TRUE; - add_peer_to_remote_pending = FALSE; - break; - default: - g_assert_not_reached (); - } - - if (tp_strdiff (tp_asv_get_string (request_properties, - TP_PROP_CHANNEL_CHANNEL_TYPE), - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA)) - return FALSE; - - handle_type = tp_asv_get_uint32 (request_properties, - TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL); - - handle = tp_asv_get_uint32 (request_properties, - TP_PROP_CHANNEL_TARGET_HANDLE, NULL); - - initial_audio = tp_asv_get_boolean (request_properties, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, NULL); - initial_video = tp_asv_get_boolean (request_properties, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, NULL); - - switch (handle_type) - { - case TP_HANDLE_TYPE_NONE: - /* already checked by TpBaseConnection */ - g_assert (handle == 0); - - if (require_target_handle) - { - g_set_error (&error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED, - "A valid Contact handle must be provided when requesting a media " - "channel"); - goto error; - } - - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - media_channel_fixed_properties, anon_channel_allowed_properties, - &error)) - goto error; - - channel = new_media_channel (self, NULL, 0, FALSE, FALSE, FALSE); - break; - - case TP_HANDLE_TYPE_CONTACT: - /* validity already checked by TpBaseConnection */ - g_assert (handle != 0); - - if (tp_channel_manager_asv_has_unknown_properties (request_properties, - media_channel_fixed_properties, named_channel_allowed_properties, - &error)) - goto error; - - if (method == METHOD_ENSURE) - { - GList *l; - TpHandle peer = 0; - - for (l = priv->media_channels; l != NULL; l = g_list_next (l)) - { - channel = GABBLE_MEDIA_CHANNEL (l->data); - g_object_get (channel, "peer", &peer, NULL); - - if (peer == handle) - { - /* Per the spec, we ignore InitialAudio and InitialVideo when - * looking for an existing channel. - */ - tp_channel_manager_emit_request_already_satisfied (self, - request_token, TP_EXPORTABLE_CHANNEL (channel)); - return TRUE; - } - } - } - - channel = new_media_channel (self, NULL, handle, - add_peer_to_remote_pending, initial_audio, initial_video); - break; - default: - return FALSE; - } - - g_assert (channel != NULL); - - gabble_media_channel_request_initial_streams (channel, - (GFunc) media_channel_request_succeeded_cb, - (GFunc) media_channel_request_failed_cb, - media_channel_request_new (self, - TP_EXPORTABLE_CHANNEL (channel), request_token)); - - return TRUE; - -error: - tp_channel_manager_emit_request_failed (self, request_token, - error->domain, error->code, error->message); - g_error_free (error); - return TRUE; -} - -static gboolean gabble_media_factory_create_call (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties, @@ -856,6 +520,10 @@ gabble_media_factory_create_call (TpChannelManager *manager, gboolean initial_audio, initial_video; const gchar *initial_audio_name, *initial_video_name; + if (tp_strdiff (tp_asv_get_string (request_properties, + TP_PROP_CHANNEL_CHANNEL_TYPE), + TP_IFACE_CHANNEL_TYPE_CALL)) + return FALSE; DEBUG ("Creating a new call channel"); @@ -947,27 +615,11 @@ error: } static gboolean -gabble_media_factory_request_channel (TpChannelManager *manager, - gpointer request_token, - GHashTable *request_properties) -{ - return gabble_media_factory_requestotron (manager, request_token, - request_properties, METHOD_REQUEST); -} - - -static gboolean gabble_media_factory_create_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { - if (!tp_strdiff (tp_asv_get_string (request_properties, - TP_PROP_CHANNEL_CHANNEL_TYPE), - TP_IFACE_CHANNEL_TYPE_CALL)) - return gabble_media_factory_create_call (manager, request_token, - request_properties, METHOD_CREATE); - else - return gabble_media_factory_requestotron (manager, request_token, + return gabble_media_factory_create_call (manager, request_token, request_properties, METHOD_CREATE); } @@ -977,14 +629,8 @@ gabble_media_factory_ensure_channel (TpChannelManager *manager, gpointer request_token, GHashTable *request_properties) { - if (!tp_strdiff (tp_asv_get_string (request_properties, - TP_PROP_CHANNEL_CHANNEL_TYPE), - TP_IFACE_CHANNEL_TYPE_CALL)) - return gabble_media_factory_create_call (manager, request_token, - request_properties, METHOD_ENSURE); - else - return gabble_media_factory_requestotron (manager, request_token, - request_properties, METHOD_ENSURE); + return gabble_media_factory_create_call (manager, request_token, + request_properties, METHOD_ENSURE); } @@ -997,7 +643,6 @@ channel_manager_iface_init (gpointer g_iface, iface->foreach_channel = gabble_media_factory_foreach_channel; iface->type_foreach_channel_class = gabble_media_factory_type_foreach_channel_class; - iface->request_channel = gabble_media_factory_request_channel; iface->create_channel = gabble_media_factory_create_channel; iface->ensure_channel = gabble_media_factory_ensure_channel; } @@ -1059,12 +704,21 @@ gabble_media_factory_add_caps (GabbleCapabilitySet *caps, } } +typedef enum { + MEDIA_CAPABILITY_AUDIO = 1, + MEDIA_CAPABILITY_VIDEO = 2, + MEDIA_CAPABILITY_NAT_TRAVERSAL_STUN = 4, + MEDIA_CAPABILITY_NAT_TRAVERSAL_GTALK_P2P = 8, + MEDIA_CAPABILITY_NAT_TRAVERSAL_ICE_UDP = 16, + MEDIA_CAPABILITY_IMMUTABLE_STREAMS = 32, +} MediaCapabilities; + /* The switch in gabble_media_factory_get_contact_caps needs to be kept in * sync with the possible returns from this function. */ -TpChannelMediaCapabilities +static MediaCapabilities _gabble_media_factory_caps_to_typeflags (const GabbleCapabilitySet *caps) { - TpChannelMediaCapabilities typeflags = 0; + MediaCapabilities typeflags = 0; gboolean has_a_transport, just_google, one_media_type; has_a_transport = gabble_capability_set_has_one (caps, @@ -1073,12 +727,12 @@ _gabble_media_factory_caps_to_typeflags (const GabbleCapabilitySet *caps) if (has_a_transport && gabble_capability_set_has_one (caps, gabble_capabilities_get_any_audio ())) - typeflags |= TP_CHANNEL_MEDIA_CAPABILITY_AUDIO; + typeflags |= MEDIA_CAPABILITY_AUDIO; if (has_a_transport && gabble_capability_set_has_one (caps, gabble_capabilities_get_any_video ())) - typeflags |= TP_CHANNEL_MEDIA_CAPABILITY_VIDEO; + typeflags |= MEDIA_CAPABILITY_VIDEO; /* The checks below are an intentional asymmetry with the function going the * other way - we don't require the other end to advertise the GTalk-P2P @@ -1086,10 +740,10 @@ _gabble_media_factory_caps_to_typeflags (const GabbleCapabilitySet *caps) * Having Google voice implied Google session and GTalk-P2P. */ if (gabble_capability_set_has (caps, NS_GOOGLE_FEAT_VOICE)) - typeflags |= TP_CHANNEL_MEDIA_CAPABILITY_AUDIO; + typeflags |= MEDIA_CAPABILITY_AUDIO; if (gabble_capability_set_has (caps, NS_GOOGLE_FEAT_VIDEO)) - typeflags |= TP_CHANNEL_MEDIA_CAPABILITY_VIDEO; + typeflags |= MEDIA_CAPABILITY_VIDEO; just_google = gabble_capability_set_has_one (caps, @@ -1097,46 +751,28 @@ _gabble_media_factory_caps_to_typeflags (const GabbleCapabilitySet *caps) !gabble_capability_set_has_one (caps, gabble_capabilities_get_any_jingle_av ()); - one_media_type = (typeflags == TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) - || (typeflags == TP_CHANNEL_MEDIA_CAPABILITY_VIDEO); + one_media_type = (typeflags == MEDIA_CAPABILITY_AUDIO) + || (typeflags == MEDIA_CAPABILITY_VIDEO); if (just_google || one_media_type) - typeflags |= TP_CHANNEL_MEDIA_CAPABILITY_IMMUTABLE_STREAMS; + typeflags |= MEDIA_CAPABILITY_IMMUTABLE_STREAMS; return typeflags; } -void -_gabble_media_factory_typeflags_to_caps (TpChannelMediaCapabilities flags, - GabbleCapabilitySet *caps) -{ - DEBUG ("adding Jingle caps %u", flags); - - /* The client name just appears in a debug message, so use something that - * won't, in practice, clash with any client that uses ContactCapabilities */ - gabble_media_factory_add_caps (caps, "<legacy Capabilities>", - (flags & TP_CHANNEL_MEDIA_CAPABILITY_AUDIO) != 0, - (flags & TP_CHANNEL_MEDIA_CAPABILITY_VIDEO) != 0, - (flags & TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_GTALK_P2P) != 0, - (flags & TP_CHANNEL_MEDIA_CAPABILITY_NAT_TRAVERSAL_ICE_UDP) != 0, - TRUE /* assume we have H.264 for now */); -} - static void gabble_media_factory_get_contact_caps (GabbleCapsChannelManager *manager, TpHandle handle, const GabbleCapabilitySet *caps, GPtrArray *arr) { - TpChannelMediaCapabilities typeflags = + MediaCapabilities typeflags = _gabble_media_factory_caps_to_typeflags (caps); - GValueArray *va; - const gchar * const *streamed_media_allowed; const gchar * const *call_allowed; - typeflags &= (TP_CHANNEL_MEDIA_CAPABILITY_AUDIO | - TP_CHANNEL_MEDIA_CAPABILITY_VIDEO | - TP_CHANNEL_MEDIA_CAPABILITY_IMMUTABLE_STREAMS); + typeflags &= (MEDIA_CAPABILITY_AUDIO | + MEDIA_CAPABILITY_VIDEO | + MEDIA_CAPABILITY_IMMUTABLE_STREAMS); /* This switch is over the values of several bits from a * bitfield-represented-as-an-enum, simultaneously, which upsets gcc-4.5; @@ -1148,28 +784,24 @@ gabble_media_factory_get_contact_caps (GabbleCapsChannelManager *manager, case 0: return; - case TP_CHANNEL_MEDIA_CAPABILITY_AUDIO - | TP_CHANNEL_MEDIA_CAPABILITY_IMMUTABLE_STREAMS: - streamed_media_allowed = audio_allowed; + case MEDIA_CAPABILITY_AUDIO + | MEDIA_CAPABILITY_IMMUTABLE_STREAMS: call_allowed = call_audio_allowed; break; - case TP_CHANNEL_MEDIA_CAPABILITY_VIDEO - | TP_CHANNEL_MEDIA_CAPABILITY_IMMUTABLE_STREAMS: - streamed_media_allowed = video_allowed; + case MEDIA_CAPABILITY_VIDEO + | MEDIA_CAPABILITY_IMMUTABLE_STREAMS: call_allowed = call_video_allowed; break; - case TP_CHANNEL_MEDIA_CAPABILITY_AUDIO - | TP_CHANNEL_MEDIA_CAPABILITY_VIDEO: /* both */ - streamed_media_allowed = both_allowed; + case MEDIA_CAPABILITY_AUDIO + | MEDIA_CAPABILITY_VIDEO: /* both */ call_allowed = call_both_allowed; break; - case TP_CHANNEL_MEDIA_CAPABILITY_AUDIO /* both but immutable */ - | TP_CHANNEL_MEDIA_CAPABILITY_VIDEO - | TP_CHANNEL_MEDIA_CAPABILITY_IMMUTABLE_STREAMS: - streamed_media_allowed = both_allowed_immutable; + case MEDIA_CAPABILITY_AUDIO /* both but immutable */ + | MEDIA_CAPABILITY_VIDEO + | MEDIA_CAPABILITY_IMMUTABLE_STREAMS: call_allowed = call_both_allowed_immutable; break; @@ -1177,29 +809,12 @@ gabble_media_factory_get_contact_caps (GabbleCapsChannelManager *manager, g_assert_not_reached (); } - /* Streamed Media channel */ - va = g_value_array_new (2); - g_value_array_append (va, NULL); - g_value_array_append (va, NULL); - g_value_init (va->values + 0, TP_HASH_TYPE_CHANNEL_CLASS); - g_value_init (va->values + 1, G_TYPE_STRV); - g_value_take_boxed (va->values + 0, - gabble_media_factory_streamed_media_channel_class ()); - g_value_set_static_boxed (va->values + 1, streamed_media_allowed); - - g_ptr_array_add (arr, va); - /* Call channel */ - va = g_value_array_new (2); - g_value_array_append (va, NULL); - g_value_array_append (va, NULL); - g_value_init (va->values + 0, TP_HASH_TYPE_CHANNEL_CLASS); - g_value_init (va->values + 1, G_TYPE_STRV); - g_value_take_boxed (va->values + 0, - gabble_media_factory_call_channel_class ()); - g_value_set_static_boxed (va->values + 1, call_allowed); - - g_ptr_array_add (arr, va); + g_ptr_array_add (arr, + tp_value_array_build (2, + TP_HASH_TYPE_CHANNEL_CLASS, gabble_media_factory_call_channel_class (), + G_TYPE_STRV, call_allowed, + G_TYPE_INVALID)); } static void @@ -1210,29 +825,22 @@ gabble_media_factory_represent_client (GabbleCapsChannelManager *manager, GabbleCapabilitySet *cap_set, GPtrArray *data_forms) { - static GQuark q_gtalk_p2p = 0, q_ice_udp = 0, q_h264 = 0; static GQuark qc_gtalk_p2p = 0, qc_ice_udp = 0, qc_h264 = 0, qc_ice = 0; gboolean gtalk_p2p = FALSE, h264 = FALSE, audio = FALSE, video = FALSE, ice_udp = FALSE; guint i; /* One-time initialization - turn the tokens we care about into quarks */ - if (G_UNLIKELY (q_gtalk_p2p == 0)) + if (G_UNLIKELY (qc_gtalk_p2p == 0)) { - q_gtalk_p2p = g_quark_from_static_string ( - TP_TOKEN_CHANNEL_INTERFACE_MEDIA_SIGNALLING_GTALK_P2P); qc_gtalk_p2p = g_quark_from_static_string ( TP_TOKEN_CHANNEL_TYPE_CALL_GTALK_P2P); - q_ice_udp = g_quark_from_static_string ( - TP_TOKEN_CHANNEL_INTERFACE_MEDIA_SIGNALLING_ICE_UDP); qc_ice = g_quark_from_static_string ( TP_TOKEN_CHANNEL_TYPE_CALL_ICE); /* 'ice-udp' isn't the proper cap name, 'ice' is. We keep supporting * 'ice-udp' for now to not break existing clients. */ qc_ice_udp = g_quark_from_static_string ( TP_IFACE_CHANNEL_TYPE_CALL "/ice-udp"); - q_h264 = g_quark_from_static_string ( - TP_IFACE_CHANNEL_INTERFACE_MEDIA_SIGNALLING "/video/h264"); qc_h264 = g_quark_from_static_string ( TP_IFACE_CHANNEL_TYPE_CALL "/video/h264"); } @@ -1248,10 +856,10 @@ gabble_media_factory_represent_client (GabbleCapsChannelManager *manager, GQuark quark; gboolean *cap; } q2cap[] = { - { q_gtalk_p2p, >alk_p2p }, { qc_gtalk_p2p, >alk_p2p }, - { q_ice_udp, &ice_udp }, { qc_ice_udp, &ice_udp }, + { qc_gtalk_p2p, >alk_p2p }, + { qc_ice_udp, &ice_udp }, { qc_ice, &ice_udp }, - { q_h264, &h264 }, { qc_h264, &h264 }, + { qc_h264, &h264 }, { 0, NULL }, }; @@ -1278,27 +886,12 @@ gabble_media_factory_represent_client (GabbleCapsChannelManager *manager, if (tp_strdiff (tp_asv_get_string (filter, TP_PROP_CHANNEL_CHANNEL_TYPE), - TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA) - && tp_strdiff (tp_asv_get_string (filter, - TP_PROP_CHANNEL_CHANNEL_TYPE), TP_IFACE_CHANNEL_TYPE_CALL)) { /* not interesting to this channel manager */ continue; } -#ifdef ENABLE_CHANNEL_TYPE_CALL - /* If there is a handler that can support Call channels, use those for - * incoming channels */ - if (!tp_strdiff (tp_asv_get_string (filter, - TP_PROP_CHANNEL_CHANNEL_TYPE), - TP_IFACE_CHANNEL_TYPE_CALL)) - { - GabbleMediaFactory *self = GABBLE_MEDIA_FACTORY (manager); - self->priv->use_call_channels = TRUE; - } -#endif - if (tp_asv_lookup (filter, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE) != NULL && tp_asv_get_uint32 (filter, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, @@ -1311,14 +904,10 @@ gabble_media_factory_represent_client (GabbleCapsChannelManager *manager, } if (tp_asv_get_boolean (filter, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO, NULL) - || tp_asv_get_boolean (filter, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, NULL)) audio = TRUE; if (tp_asv_get_boolean (filter, - TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO, NULL) - || tp_asv_get_boolean (filter, TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, NULL)) video = TRUE; diff --git a/src/media-factory.h b/src/media-factory.h index 98007f60c..b02b4b575 100644 --- a/src/media-factory.h +++ b/src/media-factory.h @@ -22,7 +22,10 @@ #include <glib-object.h> -#include "media-channel.h" +#include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> + +#include "gabble/capabilities-set.h" G_BEGIN_DECLS @@ -59,19 +62,6 @@ GType gabble_media_factory_get_type (void); (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_MEDIA_FACTORY,\ GabbleMediaFactoryClass)) -const gchar * _gabble_media_factory_allocate_sid (GabbleMediaFactory *fac, - GabbleMediaChannel *chan); -const gchar * _gabble_media_factory_register_sid (GabbleMediaFactory *fac, - const gchar *sid, GabbleMediaChannel *chan); -void _gabble_media_factory_free_sid (GabbleMediaFactory *fac, - const gchar *sid); - -void _gabble_media_factory_typeflags_to_caps (TpChannelMediaCapabilities flags, - GabbleCapabilitySet *caps); - -TpChannelMediaCapabilities -_gabble_media_factory_caps_to_typeflags (const GabbleCapabilitySet *caps); - const gchar * const * gabble_media_factory_call_channel_allowed_properties ( void); diff --git a/src/media-stream.c b/src/media-stream.c deleted file mode 100644 index 426aa8a20..000000000 --- a/src/media-stream.c +++ /dev/null @@ -1,2085 +0,0 @@ -/* - * gabble-media-stream.c - Source for GabbleMediaStream - * Copyright © 2006-2009 Collabora Ltd. - * Copyright © 2006-2009 Nokia Corporation - * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@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 - */ - -#include "config.h" -#include "media-stream.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <dbus/dbus-glib.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 "media-channel.h" -#include "namespaces.h" -#include "util.h" - -static void stream_handler_iface_init (gpointer, gpointer); - -G_DEFINE_TYPE_WITH_CODE(GabbleMediaStream, - gabble_media_stream, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_MEDIA_STREAM_HANDLER, - stream_handler_iface_init); - G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES, - tp_dbus_properties_mixin_iface_init); - ) - -/* signal enum */ -enum -{ - ERROR, - UNHOLD_FAILED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_DBUS_DAEMON = 1, - PROP_OBJECT_PATH, - PROP_NAME, - PROP_ID, - PROP_MEDIA_TYPE, - PROP_CONNECTION_STATE, - PROP_READY, - PROP_PLAYING, - PROP_COMBINED_DIRECTION, - PROP_LOCAL_HOLD, - PROP_CONTENT, - PROP_STUN_SERVERS, - PROP_RELAY_INFO, - PROP_NAT_TRAVERSAL, - PROP_CREATED_LOCALLY, - LAST_PROPERTY -}; - -/* private structure */ - -struct _GabbleMediaStreamPrivate -{ - WockyJingleContent *content; - - TpDBusDaemon *dbus_daemon; - gchar *object_path; - guint id; - guint media_type; - - gboolean local_codecs_set; - - /* Whether we're waiting for a codec intersection from the streaming - * implementation. If FALSE, SupportedCodecs is a no-op. - */ - gboolean awaiting_intersection; - - GValue local_rtp_hdrexts; - GValue local_feedback_messages; - - GValue remote_codecs; - GValue remote_rtp_hdrexts; - GValue remote_feedback_messages; - GValue remote_candidates; - - guint remote_candidate_count; - - /* source ID for initial codecs/candidates getter */ - gulong initial_getter_id; - - gchar *nat_traversal; - /* GPtrArray(GValueArray(STRING, UINT)) */ - GPtrArray *stun_servers; - /* GPtrArray(GHashTable(string => GValue)) */ - GPtrArray *relay_info; - - gboolean on_hold; - - /* These are really booleans, but gboolean is signed. Thanks, GLib */ - unsigned closed:1; - unsigned dispose_has_run:1; - unsigned local_hold:1; - unsigned ready:1; - unsigned sending:1; - unsigned created_locally:1; -}; - -static void push_remote_media_description (GabbleMediaStream *stream); -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 (WockyJingleContent *content, - GList *clist, GabbleMediaStream *stream); -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 (WockyJingleContent *c, - GParamSpec *pspec, GabbleMediaStream *stream); -static void remote_state_changed_cb (WockyJingleSession *session, - GabbleMediaStream *stream); -static void content_removed_cb (WockyJingleContent *content, - GabbleMediaStream *stream); -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, - WockyJingleContent *content, - const gchar *name, - guint id, - const gchar *nat_traversal, - const GPtrArray *relay_info, - gboolean local_hold) -{ - GPtrArray *empty = NULL; - GabbleMediaStream *result; - - g_return_val_if_fail (WOCKY_IS_JINGLE_MEDIA_RTP (content), NULL); - - if (relay_info == NULL) - { - empty = g_ptr_array_sized_new (0); - relay_info = empty; - } - - result = g_object_new (GABBLE_TYPE_MEDIA_STREAM, - "dbus-daemon", dbus_daemon, - "object-path", object_path, - "content", content, - "name", name, - "id", id, - "nat-traversal", nat_traversal, - "relay-info", relay_info, - "local-hold", local_hold, - NULL); - - if (empty != NULL) - g_ptr_array_unref (empty); - - return result; -} - -TpMediaStreamType -gabble_media_stream_get_media_type (GabbleMediaStream *self) -{ - return self->priv->media_type; -} - -static void -gabble_media_stream_init (GabbleMediaStream *self) -{ - GabbleMediaStreamPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - GABBLE_TYPE_MEDIA_STREAM, GabbleMediaStreamPrivate); - GType candidate_list_type = - TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE_LIST; - GType codec_list_type = - TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CODEC_LIST; - GType rtp_hdrext_list_type = TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST; - GType fb_msg_map_type = TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP; - - self->priv = priv; - - g_value_init (&priv->local_rtp_hdrexts, rtp_hdrext_list_type); - g_value_init (&priv->local_feedback_messages, fb_msg_map_type); - - g_value_init (&priv->remote_codecs, codec_list_type); - g_value_take_boxed (&priv->remote_codecs, - dbus_g_type_specialized_construct (codec_list_type)); - - g_value_init (&priv->remote_rtp_hdrexts, rtp_hdrext_list_type); - g_value_take_boxed (&priv->remote_rtp_hdrexts, - dbus_g_type_specialized_construct (rtp_hdrext_list_type)); - - g_value_init (&priv->remote_feedback_messages, fb_msg_map_type); - g_value_take_boxed (&priv->remote_feedback_messages, - dbus_g_type_specialized_construct (fb_msg_map_type)); - - g_value_init (&priv->remote_candidates, candidate_list_type); - g_value_take_boxed (&priv->remote_candidates, - dbus_g_type_specialized_construct (candidate_list_type)); - - priv->stun_servers = g_ptr_array_sized_new (1); -} - -static gboolean -_get_initial_codecs_and_candidates (gpointer user_data) -{ - GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (user_data); - GabbleMediaStreamPrivate *priv = stream->priv; - WockyJingleMediaDescription *md; - - priv->initial_getter_id = 0; - - /* we can immediately get the codecs if we're responder */ - 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); - - /* if any candidates arrived before idle loop had the chance to excute - * us (e.g. specified in session-initiate/content-add), we don't want to - * miss them */ - new_remote_candidates_cb (priv->content, - wocky_jingle_content_get_remote_candidates (priv->content), stream); - - return FALSE; -} - -static GObject * -gabble_media_stream_constructor (GType type, guint n_props, - GObjectConstructParam *props) -{ - GObject *obj; - GabbleMediaStream *stream; - GabbleMediaStreamPrivate *priv; - WockyJingleFactory *jf; - GList *stun_servers; - - /* call base class constructor */ - obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)-> - constructor (type, n_props, props); - stream = GABBLE_MEDIA_STREAM (obj); - priv = stream->priv; - - g_assert (priv->content != NULL); - - /* 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 = 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) - { - 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 */ - g_assert (priv->dbus_daemon != NULL); - tp_dbus_daemon_register_object (priv->dbus_daemon, priv->object_path, obj); - - update_direction (stream, priv->content); - - /* 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. - * FIXME: add API for ordering IQs rather than using g_idle_add. - */ - priv->initial_getter_id = - g_idle_add (_get_initial_codecs_and_candidates, stream); - - if (priv->created_locally) - { - g_object_set (stream, "combined-direction", - MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - 0), NULL); - } - else - { - priv->awaiting_intersection = TRUE; - } - - return obj; -} - -static void -gabble_media_stream_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object); - GabbleMediaStreamPrivate *priv = stream->priv; - - switch (property_id) { - case PROP_DBUS_DAEMON: - g_value_set_object (value, priv->dbus_daemon); - break; - case PROP_OBJECT_PATH: - g_value_set_string (value, priv->object_path); - break; - case PROP_NAME: - g_value_set_string (value, stream->name); - break; - case PROP_ID: - g_value_set_uint (value, priv->id); - break; - case PROP_MEDIA_TYPE: - g_value_set_uint (value, priv->media_type); - break; - case PROP_CONNECTION_STATE: - g_value_set_uint (value, stream->connection_state); - break; - case PROP_READY: - g_value_set_boolean (value, priv->ready); - break; - case PROP_PLAYING: - g_value_set_boolean (value, stream->playing); - break; - case PROP_COMBINED_DIRECTION: - g_value_set_uint (value, stream->combined_direction); - break; - case PROP_LOCAL_HOLD: - g_value_set_boolean (value, priv->local_hold); - break; - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_STUN_SERVERS: - g_value_set_boxed (value, priv->stun_servers); - break; - case PROP_NAT_TRAVERSAL: - g_value_set_string (value, priv->nat_traversal); - break; - case PROP_CREATED_LOCALLY: - g_value_set_boolean (value, priv->created_locally); - break; - case PROP_RELAY_INFO: - g_value_set_boxed (value, priv->relay_info); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gabble_media_stream_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GabbleMediaStream *stream = GABBLE_MEDIA_STREAM (object); - GabbleMediaStreamPrivate *priv = stream->priv; - - switch (property_id) { - case PROP_OBJECT_PATH: - g_free (priv->object_path); - priv->object_path = g_value_dup_string (value); - break; - case PROP_DBUS_DAEMON: - g_assert (priv->dbus_daemon == NULL); - priv->dbus_daemon = g_value_dup_object (value); - break; - case PROP_NAME: - g_free (stream->name); - stream->name = g_value_dup_string (value); - break; - case PROP_ID: - priv->id = g_value_get_uint (value); - break; - case PROP_CONNECTION_STATE: - DEBUG ("stream %s connection state %d", - stream->name, stream->connection_state); - stream->connection_state = g_value_get_uint (value); - break; - case PROP_READY: - priv->ready = g_value_get_boolean (value); - break; - case PROP_PLAYING: - { - gboolean old = stream->playing; - stream->playing = g_value_get_boolean (value); - if (stream->playing != old) - push_playing (stream); - } - break; - case PROP_COMBINED_DIRECTION: - DEBUG ("changing combined direction from %u to %u", - stream->combined_direction, g_value_get_uint (value)); - stream->combined_direction = g_value_get_uint (value); - break; - case PROP_CONTENT: - g_assert (priv->content == NULL); - - priv->content = g_value_dup_object (value); - - { - guint jtype; - gboolean locally_created; - - g_object_get (priv->content, - "media-type", &jtype, - "locally-created", &locally_created, - NULL); - - if (jtype == WOCKY_JINGLE_MEDIA_TYPE_VIDEO) - priv->media_type = TP_MEDIA_STREAM_TYPE_VIDEO; - else - priv->media_type = TP_MEDIA_STREAM_TYPE_AUDIO; - - priv->created_locally = locally_created; - } - - DEBUG ("%p: connecting to content %p signals", stream, priv->content); - - gabble_signal_connect_weak (priv->content, "new-candidates", - (GCallback) new_remote_candidates_cb, object); - - /* we need this also, if we're the initiator of the stream - * (so remote codecs arrive later) */ - gabble_signal_connect_weak (priv->content, "remote-media-description", - (GCallback) new_remote_media_description_cb, object); - - gabble_signal_connect_weak (priv->content, "notify::state", - (GCallback) content_state_changed_cb, object); - - gabble_signal_connect_weak (priv->content, "notify::senders", - (GCallback) content_senders_changed_cb, object); - - gabble_signal_connect_weak (priv->content->session, - "remote-state-changed", (GCallback) remote_state_changed_cb, object); - - gabble_signal_connect_weak (priv->content, "removed", - (GCallback) content_removed_cb, object); - break; - case PROP_NAT_TRAVERSAL: - g_assert (priv->nat_traversal == NULL); - priv->nat_traversal = g_value_dup_string (value); - break; - case PROP_RELAY_INFO: - g_assert (priv->relay_info == NULL); - priv->relay_info = g_value_dup_boxed (value); - break; - case PROP_LOCAL_HOLD: - priv->local_hold = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void gabble_media_stream_dispose (GObject *object); -static void gabble_media_stream_finalize (GObject *object); - -static void -gabble_media_stream_class_init (GabbleMediaStreamClass *gabble_media_stream_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (gabble_media_stream_class); - GParamSpec *param_spec; - static TpDBusPropertiesMixinPropImpl stream_handler_props[] = { - { "RelayInfo", "relay-info", NULL }, - { "STUNServers", "stun-servers", NULL }, - { "NATTraversal", "nat-traversal", NULL }, - { "CreatedLocally", "created-locally", NULL }, - { NULL } - }; - static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = { - { TP_IFACE_MEDIA_STREAM_HANDLER, - tp_dbus_properties_mixin_getter_gobject_properties, - NULL, - stream_handler_props, - }, - { NULL } - }; - - g_type_class_add_private (gabble_media_stream_class, - sizeof (GabbleMediaStreamPrivate)); - - object_class->constructor = gabble_media_stream_constructor; - - object_class->get_property = gabble_media_stream_get_property; - object_class->set_property = gabble_media_stream_set_property; - - object_class->dispose = gabble_media_stream_dispose; - object_class->finalize = gabble_media_stream_finalize; - - param_spec = g_param_spec_object ("dbus-daemon", "TpDBusDaemon", - "Bus on which to export this object", - TP_TYPE_DBUS_DAEMON, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DBUS_DAEMON, param_spec); - - param_spec = g_param_spec_string ("object-path", "D-Bus object path", - "The D-Bus object path used for this " - "object on the bus.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); - - param_spec = g_param_spec_string ("name", "Stream name", - "An opaque name for the stream used in the signalling.", NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_NAME, param_spec); - - param_spec = g_param_spec_uint ("id", "Stream ID", - "A stream number for the stream used in the " - "D-Bus API.", - 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_ID, param_spec); - - param_spec = g_param_spec_uint ("media-type", "Stream media type", - "A constant indicating which media type the stream carries.", - TP_MEDIA_STREAM_TYPE_AUDIO, TP_MEDIA_STREAM_TYPE_VIDEO, - TP_MEDIA_STREAM_TYPE_AUDIO, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); - - param_spec = g_param_spec_uint ("connection-state", "Stream connection state", - "An integer indicating the state of the" - "stream's connection.", - TP_MEDIA_STREAM_STATE_DISCONNECTED, - TP_MEDIA_STREAM_STATE_CONNECTED, - TP_MEDIA_STREAM_STATE_DISCONNECTED, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONNECTION_STATE, - param_spec); - - param_spec = g_param_spec_boolean ("ready", "Ready?", - "A boolean signifying whether the user " - "is ready to handle signals from this " - "object.", - FALSE, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_READY, param_spec); - - param_spec = g_param_spec_boolean ("playing", "Set playing", - "A boolean signifying whether the stream " - "has been set playing yet.", - FALSE, - G_PARAM_CONSTRUCT | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_PLAYING, param_spec); - - param_spec = g_param_spec_uint ("combined-direction", - "Combined direction", - "An integer indicating the directions the stream currently sends in, " - "and the peers who have been asked to send.", - TP_MEDIA_STREAM_DIRECTION_NONE, - MAKE_COMBINED_DIRECTION (TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - TP_MEDIA_STREAM_PENDING_LOCAL_SEND | - TP_MEDIA_STREAM_PENDING_REMOTE_SEND), - TP_MEDIA_STREAM_DIRECTION_NONE, - G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_COMBINED_DIRECTION, - param_spec); - - param_spec = g_param_spec_boolean ("local-hold", "Local hold?", - "True if resources used for this stream have been freed.", FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - 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", "WockyJingleContent object", - "Jingle content signalling this media stream.", - WOCKY_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_boxed ("stun-servers", "STUN servers", - "Array of (STRING: address literal, UINT: port) pairs", - /* FIXME: use correct macro when available */ - tp_type_dbus_array_su (), - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STUN_SERVERS, param_spec); - - param_spec = g_param_spec_boxed ("relay-info", "Relay info", - "Array of mappings containing relay server information", - TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_RELAY_INFO, param_spec); - - param_spec = g_param_spec_string ("nat-traversal", "NAT traversal", - "NAT traversal mechanism for this stream", NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAT_TRAVERSAL, - param_spec); - - param_spec = g_param_spec_boolean ("created-locally", "Created locally?", - "True if this stream was created by the local user", FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CREATED_LOCALLY, - param_spec); - - /* signals not exported by D-Bus interface */ - - signals[ERROR] = - g_signal_new ("error", - G_OBJECT_CLASS_TYPE (gabble_media_stream_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - gabble_marshal_VOID__UINT_STRING, - G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING); - - signals[UNHOLD_FAILED] = g_signal_new ("unhold-failed", - G_OBJECT_CLASS_TYPE (gabble_media_stream_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - - gabble_media_stream_class->props_class.interfaces = prop_interfaces; - tp_dbus_properties_mixin_class_init (object_class, - G_STRUCT_OFFSET (GabbleMediaStreamClass, props_class)); -} - -void -gabble_media_stream_dispose (GObject *object) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object); - GabbleMediaStreamPrivate *priv = self->priv; - - DEBUG ("called"); - - if (priv->dispose_has_run) - return; - - if (priv->initial_getter_id != 0) - { - g_source_remove (priv->initial_getter_id); - priv->initial_getter_id = 0; - } - - gabble_media_stream_close (self); - - priv->dispose_has_run = TRUE; - - tp_clear_object (&priv->content); - tp_clear_pointer (&self->name, g_free); - g_clear_object (&priv->dbus_daemon); - - if (G_OBJECT_CLASS (gabble_media_stream_parent_class)->dispose) - G_OBJECT_CLASS (gabble_media_stream_parent_class)->dispose (object); -} - -void -gabble_media_stream_finalize (GObject *object) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (object); - GabbleMediaStreamPrivate *priv = self->priv; - - g_free (priv->object_path); - g_free (priv->nat_traversal); - - /* FIXME: use correct macro when available */ - if (priv->stun_servers != NULL) - g_boxed_free (tp_type_dbus_array_su (), priv->stun_servers); - - if (priv->relay_info != NULL) - g_boxed_free (TP_ARRAY_TYPE_STRING_VARIANT_MAP_LIST, priv->relay_info); - - g_value_unset (&priv->local_rtp_hdrexts); - g_value_unset (&priv->local_feedback_messages); - - g_value_unset (&priv->remote_codecs); - g_value_unset (&priv->remote_rtp_hdrexts); - g_value_unset (&priv->remote_feedback_messages); - g_value_unset (&priv->remote_candidates); - - G_OBJECT_CLASS (gabble_media_stream_parent_class)->finalize (object); -} - -/** - * gabble_media_stream_codec_choice - * - * Implements D-Bus method CodecChoice - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_codec_choice (TpSvcMediaStreamHandler *iface, - guint codec_id, - DBusGMethodInvocation *context) -{ - tp_svc_media_stream_handler_return_from_codec_choice (context); -} - - -gboolean -gabble_media_stream_error (GabbleMediaStream *self, - guint errnum, - const gchar *message, - GError **error) -{ - g_assert (GABBLE_IS_MEDIA_STREAM (self)); - - DEBUG ( "Media.StreamHandler::Error called, error %u (%s) -- emitting signal", - errnum, message); - g_signal_emit (self, signals[ERROR], 0, errnum, message); - - return TRUE; -} - - -/** - * gabble_media_stream_error - * - * Implements D-Bus method Error - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_error_async (TpSvcMediaStreamHandler *iface, - guint errnum, - const gchar *message, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GError *error = NULL; - - if (gabble_media_stream_error (self, errnum, message, &error)) - { - tp_svc_media_stream_handler_return_from_error (context); - } - else - { - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - - -/** - * gabble_media_stream_hold: - * - * Tell streaming clients that the stream is going on hold, so they should - * stop streaming and free up any resources they are currently holding - * (e.g. close hardware devices); or that the stream is coming off hold, - * so they should reacquire those resources. - */ -void -gabble_media_stream_hold (GabbleMediaStream *self, - gboolean hold) -{ - tp_svc_media_stream_handler_emit_set_stream_held (self, hold); -} - - -/** - * gabble_media_stream_hold_state: - * - * Called by streaming clients when the stream's hold state has been changed - * successfully in response to SetStreamHeld. - */ -static void -gabble_media_stream_hold_state (TpSvcMediaStreamHandler *iface, - gboolean hold_state, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv = self->priv; - - DEBUG ("%p: %s", self, hold_state ? "held" : "unheld"); - priv->local_hold = hold_state; - - g_object_notify ((GObject *) self, "local-hold"); - - tp_svc_media_stream_handler_return_from_hold_state (context); -} - - -/** - * gabble_media_stream_unhold_failure: - * - * Called by streaming clients when an attempt to reacquire the necessary - * hardware or software resources to unhold the stream, in response to - * SetStreamHeld, has failed. - */ -static void -gabble_media_stream_unhold_failure (TpSvcMediaStreamHandler *iface, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv = self->priv; - - DEBUG ("%p", self); - - priv->local_hold = TRUE; - - g_signal_emit (self, signals[UNHOLD_FAILED], 0); - g_object_notify ((GObject *) self, "local-hold"); - - tp_svc_media_stream_handler_return_from_unhold_failure (context); -} - - -/** - * gabble_media_stream_native_candidates_prepared - * - * Implements D-Bus method NativeCandidatesPrepared - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_native_candidates_prepared (TpSvcMediaStreamHandler *iface, - DBusGMethodInvocation *context) -{ - tp_svc_media_stream_handler_return_from_native_candidates_prepared (context); -} - - -/** - * gabble_media_stream_new_active_candidate_pair - * - * Implements D-Bus method NewActiveCandidatePair - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_new_active_candidate_pair (TpSvcMediaStreamHandler *iface, - const gchar *native_candidate_id, - const gchar *remote_candidate_id, - DBusGMethodInvocation *context) -{ - DEBUG ("called (%s, %s); this is a no-op on Jingle", native_candidate_id, - remote_candidate_id); - - tp_svc_media_stream_handler_return_from_new_active_candidate_pair (context); -} - - -/** - * gabble_media_stream_new_native_candidate - * - * Implements D-Bus method NewNativeCandidate - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_new_native_candidate (TpSvcMediaStreamHandler *iface, - const gchar *candidate_id, - const GPtrArray *transports, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv; - WockyJingleState state; - GList *li = NULL; - guint i; - - g_assert (GABBLE_IS_MEDIA_STREAM (self)); - - priv = self->priv; - - g_object_get (priv->content->session, "state", &state, NULL); - - /* FIXME: maybe this should be an assertion in case the channel - * isn't closed early enough right now? */ - if (state > WOCKY_JINGLE_STATE_ACTIVE) - { - DEBUG ("state > WOCKY_JINGLE_STATE_ACTIVE, doing nothing"); - tp_svc_media_stream_handler_return_from_new_native_candidate (context); - return; - } - - for (i = 0; i < transports->len; i++) - { - GValueArray *transport; - guint component; - const gchar *addr; - WockyJingleCandidate *c; - - transport = g_ptr_array_index (transports, i); - component = g_value_get_uint (g_value_array_get_nth (transport, 0)); - - /* Farsight 1 compatibility */ - if (component == 0) - component = 1; - - /* We understand RTP and RTCP, and silently ignore the rest */ - if ((component != 1) && (component != 2)) - continue; - - addr = g_value_get_string (g_value_array_get_nth (transport, 1)); - if (!strcmp (addr, "127.0.0.1")) - { - DEBUG ("ignoring native localhost candidate"); - continue; - } - - 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 */ - g_value_get_uint (g_value_array_get_nth (transport, 7)), - /* id */ - candidate_id, - /* component */ - component, - /* address */ - g_value_get_string (g_value_array_get_nth (transport, 1)), - /* port */ - g_value_get_uint (g_value_array_get_nth (transport, 2)), - /* generation */ - 0, - /* preference */ - (int) (g_value_get_double (g_value_array_get_nth (transport, 6)) * 65536), - /* username */ - g_value_get_string (g_value_array_get_nth (transport, 8)), - /* password */ - g_value_get_string (g_value_array_get_nth (transport, 9)), - /* network */ - 0); - - li = g_list_prepend (li, c); - } - - if (li != NULL) - wocky_jingle_content_add_candidates (priv->content, li); - - tp_svc_media_stream_handler_return_from_new_native_candidate (context); -} - -static void gabble_media_stream_set_local_codecs (TpSvcMediaStreamHandler *, - const GPtrArray *codecs, DBusGMethodInvocation *); - -/** - * gabble_media_stream_ready - * - * Implements D-Bus method Ready - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_ready (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv; - - g_assert (GABBLE_IS_MEDIA_STREAM (self)); - - priv = self->priv; - - DEBUG ("ready called"); - - if (priv->ready == FALSE) - { - g_object_set (self, "ready", TRUE, NULL); - - push_remote_media_description (self); - push_remote_candidates (self); - push_playing (self); - push_sending (self); - - /* If a new stream is added while the call's on hold, it will have - * local_hold set at construct time. So once tp-fs has called Ready(), we - * should let it know this stream's on hold. - */ - if (priv->local_hold) - gabble_media_stream_hold (self, priv->local_hold); - } - else - { - DEBUG ("Ready called twice, running plain SetLocalCodecs instead"); - } - - /* set_local_codecs and ready return the same thing, so we can do... */ - gabble_media_stream_set_local_codecs (iface, codecs, context); -} - -static gboolean -pass_local_codecs (GabbleMediaStream *stream, - const GPtrArray *codecs, - gboolean ready, - GError **error) -{ - GabbleMediaStreamPrivate *priv = stream->priv; - guint i; - WockyJingleMediaDescription *md; - const GPtrArray *hdrexts; - GHashTable *fbs; - GError *wocky_error = NULL; - - DEBUG ("putting list of %d supported codecs from stream-engine into cache", - codecs->len); - - md = wocky_jingle_media_description_new (); - - fbs = g_value_get_boxed (&priv->local_feedback_messages); - - for (i = 0; i < codecs->len; i++) - { - GType codec_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC; - - GValue codec = { 0, }; - guint id, clock_rate, channels; - gchar *name; - GHashTable *params; - WockyJingleCodec *c; - GValueArray *fb_codec; - - g_value_init (&codec, codec_struct_type); - g_value_set_static_boxed (&codec, g_ptr_array_index (codecs, i)); - - dbus_g_type_struct_get (&codec, - 0, &id, - 1, &name, - 3, &clock_rate, - 4, &channels, - 5, ¶ms, - G_MAXUINT); - - c = jingle_media_rtp_codec_new (id, name, - clock_rate, channels, params); - - if (fbs != NULL) - { - fb_codec = g_hash_table_lookup (fbs, GUINT_TO_POINTER (id)); - if (fb_codec != NULL) - { - if (G_VALUE_HOLDS_UINT ( - g_value_array_get_nth (fb_codec, 0)) && - G_VALUE_TYPE (g_value_array_get_nth (fb_codec, 1)) == - TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST) - { - GValue *val; - const GPtrArray *fb_array; - guint j; - - val = g_value_array_get_nth (fb_codec, 0); - c->trr_int = g_value_get_uint (val); - - val = g_value_array_get_nth (fb_codec, 1); - fb_array = g_value_get_boxed (val); - - for (j = 0; j < fb_array->len; j++) - { - GValueArray *message = g_ptr_array_index (fb_array, j); - const gchar *type; - const gchar *subtype; - - val = g_value_array_get_nth (message, 0); - type = g_value_get_string (val); - - val = g_value_array_get_nth (message, 1); - subtype = g_value_get_string (val); - - c->feedback_msgs = g_list_append (c->feedback_msgs, - wocky_jingle_feedback_message_new (type, subtype)); - } - } - } - } - DEBUG ("adding codec %s (%u %u %u)", c->name, c->id, c->clockrate, c->channels); - md->codecs = g_list_append (md->codecs, c); - g_free (name); - g_hash_table_unref (params); - } - - if (fbs != NULL) - g_value_reset (&priv->local_feedback_messages); - - hdrexts = g_value_get_boxed (&priv->local_rtp_hdrexts); - - if (hdrexts != NULL) - { - gboolean have_initiator = FALSE; - gboolean initiated_by_us; - - for (i = 0; i < hdrexts->len; i++) - { - GValueArray *hdrext; - guint id; - guint direction; - WockyJingleContentSenders senders; - gchar *uri; - gchar *params; - - hdrext = g_ptr_array_index (hdrexts, i); - - g_assert (hdrext); - g_assert (hdrext->n_values == 4); - g_assert (G_VALUE_HOLDS_UINT (g_value_array_get_nth (hdrext, 0))); - g_assert (G_VALUE_HOLDS_UINT (g_value_array_get_nth (hdrext, 1))); - g_assert (G_VALUE_HOLDS_STRING (g_value_array_get_nth (hdrext, 2))); - g_assert (G_VALUE_HOLDS_STRING (g_value_array_get_nth (hdrext, 3))); - - tp_value_array_unpack (hdrext, 4, - &id, - &direction, - &uri, - ¶ms); - - if (!have_initiator) - { - g_object_get (priv->content->session, "local-initiator", - &initiated_by_us, NULL); - have_initiator = TRUE; - } - - switch (direction) - { - case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: - senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; - break; - case TP_MEDIA_STREAM_DIRECTION_NONE: - senders = WOCKY_JINGLE_CONTENT_SENDERS_NONE; - break; - case TP_MEDIA_STREAM_DIRECTION_SEND: - 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 ? WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : - WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; - break; - default: - g_assert_not_reached (); - } - - md->hdrexts = g_list_append (md->hdrexts, - wocky_jingle_rtp_header_extension_new (id, senders, uri)); - } - /* Can only be used once */ - g_value_reset (&priv->local_rtp_hdrexts); - } - - wocky_jingle_media_description_simplify (md); - - if (jingle_media_rtp_set_local_media_description ( - WOCKY_JINGLE_MEDIA_RTP (priv->content), md, ready, &wocky_error)) - return TRUE; - - g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - wocky_error->message); - g_clear_error (&wocky_error); - return FALSE; -} - -/** - * gabble_media_stream_set_local_codecs - * - * Implements D-Bus method SetLocalCodecs - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_set_local_codecs (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv = self->priv; - GError *error = NULL; - - DEBUG ("called"); - - if (codecs->len == 0) - goto done; - - priv->local_codecs_set = TRUE; - - if (wocky_jingle_content_is_created_by_us (self->priv->content)) - { - if (!pass_local_codecs (self, codecs, self->priv->created_locally, - &error)) - { - DEBUG ("failed: %s", error->message); - - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - } - else - { - DEBUG ("ignoring local codecs, waiting for codec intersection"); - } - done: - - tp_svc_media_stream_handler_return_from_set_local_codecs (context); -} - -/** - * gabble_media_stream_stream_state - * - * Implements D-Bus method StreamState - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_stream_state (TpSvcMediaStreamHandler *iface, - guint connection_state, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv = self->priv; - WockyJingleTransportState ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED; - - switch (connection_state) { - case TP_MEDIA_STREAM_STATE_DISCONNECTED: - ts = WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED; - break; - case TP_MEDIA_STREAM_STATE_CONNECTING: - ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTING; - break; - case TP_MEDIA_STREAM_STATE_CONNECTED: - ts = WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED; - break; - default: - DEBUG ("ignoring unknown connection state %u", connection_state); - goto OUT; - } - - g_object_set (self, "connection-state", connection_state, NULL); - wocky_jingle_content_set_transport_state (priv->content, ts); - -OUT: - tp_svc_media_stream_handler_return_from_stream_state (context); -} - - -/** - * gabble_media_stream_supported_codecs - * - * Implements D-Bus method SupportedCodecs - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_supported_codecs (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GabbleMediaStreamPrivate *priv = self->priv; - GError *error = NULL; - - DEBUG ("called"); - - if (codecs->len == 0) - { - GError e = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "SupportedCodecs must have a non-empty list of codecs" }; - - dbus_g_method_return_error (context, &e); - return; - } - - priv->local_codecs_set = TRUE; - - if (priv->awaiting_intersection) - { - if (!pass_local_codecs (self, codecs, TRUE, &error)) - { - DEBUG ("failed: %s", error->message); - - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } - - priv->awaiting_intersection = FALSE; - } - else - { - /* If we created the stream, we don't need to send the intersection. If - * we didn't create it, but have already sent the intersection once, we - * don't need to send it again. In either case, extra calls to - * SupportedCodecs are in response to an incoming description-info, which - * can only change parameters and which XEP-0167 §10 says is purely - * advisory. - */ - DEBUG ("we already sent, or don't need to send, our codecs"); - } - - tp_svc_media_stream_handler_return_from_supported_codecs (context); -} - -/** - * gabble_media_stream_codecs_updated - * - * Implements D-Bus method CodecsUpdated - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_codecs_updated (TpSvcMediaStreamHandler *iface, - const GPtrArray *codecs, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - GError *error = NULL; - - if (!self->priv->local_codecs_set) - { - GError e = { TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "CodecsUpdated may only be called once an initial set of codecs " - "has been set" }; - - dbus_g_method_return_error (context, &e); - return; - } - - if (self->priv->awaiting_intersection) - { - /* When awaiting an intersection the initial set of codecs should be set - * by calling SupportedCodecs as that is the canonical set of codecs, - * updates are only meaningful afterwards */ - tp_svc_media_stream_handler_return_from_codecs_updated (context); - return; - } - - if (pass_local_codecs (self, codecs, self->priv->created_locally, &error)) - { - tp_svc_media_stream_handler_return_from_codecs_updated (context); - } - else - { - DEBUG ("failed: %s", error->message); - - dbus_g_method_return_error (context, error); - g_error_free (error); - } -} - -/** - * gabble_media_stream_supported_header_extensions - * - * Implements D-Bus method SupportedHeaderExtensions - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_supported_header_extensions (TpSvcMediaStreamHandler *iface, - const GPtrArray *hdrexts, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - - g_value_set_boxed (&self->priv->local_rtp_hdrexts, hdrexts); - - tp_svc_media_stream_handler_return_from_supported_header_extensions (context); -} - -/** - * gabble_media_stream_supported_feedback_messages - * - * Implements D-Bus method SupportedFeedbackMessages - * on interface org.freedesktop.Telepathy.Media.StreamHandler - */ -static void -gabble_media_stream_supported_feedback_messages (TpSvcMediaStreamHandler *iface, - GHashTable *messages, - DBusGMethodInvocation *context) -{ - GabbleMediaStream *self = GABBLE_MEDIA_STREAM (iface); - - g_value_set_boxed (&self->priv->local_feedback_messages, messages); - - tp_svc_media_stream_handler_return_from_supported_feedback_messages (context); -} - -void -gabble_media_stream_close (GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv; - - g_assert (GABBLE_IS_MEDIA_STREAM (stream)); - - priv = stream->priv; - - if (!priv->closed) - { - priv->closed = TRUE; - tp_svc_media_stream_handler_emit_close (stream); - } -} - -static void -insert_feedback_message (WockyJingleFeedbackMessage *fb, GPtrArray *fb_msgs) -{ - GValueArray *msg; - - msg = tp_value_array_build (3, - G_TYPE_STRING, fb->type, - G_TYPE_STRING, fb->subtype, - G_TYPE_STRING, "", - G_TYPE_INVALID); - - g_ptr_array_add (fb_msgs, msg); -} - -static void -new_remote_media_description_cb (WockyJingleContent *content, - WockyJingleMediaDescription *md, GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv; - GList *li; - GPtrArray *codecs; - GPtrArray *hdrexts; - GHashTable *fbs; - GType codec_struct_type = TP_STRUCT_TYPE_MEDIA_STREAM_HANDLER_CODEC; - gboolean have_initiator = FALSE; - gboolean initiated_by_us; - - DEBUG ("called"); - - g_assert (GABBLE_IS_MEDIA_STREAM (stream)); - - priv = stream->priv; - - codecs = g_value_get_boxed (&priv->remote_codecs); - - if (codecs->len != 0) - { - /* We already had some codecs; let's free the old list and make a new, - * empty one to fill in. - */ - g_value_reset (&priv->remote_codecs); - codecs = dbus_g_type_specialized_construct ( - TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CODEC_LIST); - g_value_take_boxed (&priv->remote_codecs, codecs); - } - - hdrexts = g_value_get_boxed (&priv->remote_rtp_hdrexts); - - if (hdrexts->len != 0) - { - /* We already had some rtp hdrext; let's free the old list and make a new, - * empty one to fill in. - */ - g_value_reset (&priv->remote_rtp_hdrexts); - hdrexts = dbus_g_type_specialized_construct ( - TP_ARRAY_TYPE_RTP_HEADER_EXTENSIONS_LIST); - g_value_take_boxed (&priv->remote_rtp_hdrexts, hdrexts); - } - - fbs = g_value_get_boxed (&priv->remote_feedback_messages); - - if (g_hash_table_size (fbs) != 0) - { - /* We already had some rtp hdrext; let's free the old list and make a new, - * empty one to fill in. - */ - g_value_reset (&priv->remote_feedback_messages); - fbs = dbus_g_type_specialized_construct ( - TP_HASH_TYPE_RTCP_FEEDBACK_MESSAGE_MAP); - g_value_take_boxed (&priv->remote_feedback_messages, fbs); - } - - for (li = md->codecs; li; li = li->next) - { - GValue codec = { 0, }; - WockyJingleCodec *c = li->data; - - g_value_init (&codec, codec_struct_type); - g_value_take_boxed (&codec, - dbus_g_type_specialized_construct (codec_struct_type)); - - DEBUG ("new remote %s codec: %u '%s' %u %u %u", - priv->media_type == TP_MEDIA_STREAM_TYPE_AUDIO ? "audio" : "video", - c->id, c->name, priv->media_type, c->clockrate, c->channels); - - dbus_g_type_struct_set (&codec, - 0, c->id, - 1, c->name, - 2, priv->media_type, - 3, c->clockrate, - 4, c->channels, - 5, c->params, - G_MAXUINT); - - if (md->trr_int != G_MAXUINT || c->trr_int != G_MAXUINT || - md->feedback_msgs != NULL || c->feedback_msgs != NULL) - { - GValueArray *fb_msg_props; - guint trr_int; - GPtrArray *fb_msgs = g_ptr_array_new (); - - if (c->trr_int != G_MAXUINT) - trr_int = c->trr_int; - else - trr_int = md->trr_int; - - g_list_foreach (md->feedback_msgs, (GFunc) insert_feedback_message, - fb_msgs); - g_list_foreach (c->feedback_msgs, (GFunc) insert_feedback_message, - fb_msgs); - - fb_msg_props = tp_value_array_build (2, - G_TYPE_UINT, trr_int, - TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST, fb_msgs, - G_TYPE_INVALID); - - g_boxed_free (TP_ARRAY_TYPE_RTCP_FEEDBACK_MESSAGE_LIST, fb_msgs); - - g_hash_table_insert (fbs, GUINT_TO_POINTER (c->id), fb_msg_props); - } - - g_ptr_array_add (codecs, g_value_get_boxed (&codec)); - } - - for (li = md->hdrexts; li; li = li->next) - { - WockyJingleRtpHeaderExtension *h = li->data; - TpMediaStreamDirection direction; - - if (!have_initiator) - { - g_object_get (priv->content->session, "local-initiator", - &initiated_by_us, NULL); - have_initiator = TRUE; - } - - switch (h->senders) - { - case WOCKY_JINGLE_CONTENT_SENDERS_BOTH: - direction = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; - break; - case WOCKY_JINGLE_CONTENT_SENDERS_NONE: - direction = TP_MEDIA_STREAM_DIRECTION_NONE; - break; - case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR: - direction = initiated_by_us ? TP_MEDIA_STREAM_DIRECTION_SEND : - TP_MEDIA_STREAM_DIRECTION_RECEIVE; - break; - case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER: - direction = initiated_by_us ? TP_MEDIA_STREAM_DIRECTION_RECEIVE : - TP_MEDIA_STREAM_DIRECTION_SEND; - break; - default: - g_assert_not_reached (); - } - - DEBUG ("new RTP header ext : %u %s", h->id, h->uri); - - g_ptr_array_add (hdrexts, - tp_value_array_build (4, - G_TYPE_UINT, h->id, - G_TYPE_UINT, direction, - G_TYPE_STRING, h->uri, - G_TYPE_STRING, "", /* No protocol defines parameters */ - G_TYPE_INVALID)); - } - - DEBUG ("pushing remote codecs"); - - push_remote_media_description (stream); -} - - -static void -push_remote_media_description (GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv; - GPtrArray *codecs; - GPtrArray *hdrexts; - GHashTable *fbs; - - g_assert (GABBLE_IS_MEDIA_STREAM (stream)); - - priv = stream->priv; - - if (!priv->ready) - return; - - codecs = g_value_get_boxed (&priv->remote_codecs); - if (codecs->len == 0) - return; - - hdrexts = g_value_get_boxed (&priv->remote_rtp_hdrexts); - - fbs = g_value_get_boxed (&priv->remote_feedback_messages); - - DEBUG ("passing %d remote codecs to stream-engine", - codecs->len); - - tp_svc_media_stream_handler_emit_set_remote_header_extensions (stream, - hdrexts); - tp_svc_media_stream_handler_emit_set_remote_feedback_messages (stream, fbs); - tp_svc_media_stream_handler_emit_set_remote_codecs (stream, codecs); -} - -static void -new_remote_candidates_cb (WockyJingleContent *content, - GList *clist, GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv = stream->priv; - GPtrArray *candidates; - GList *li; - - candidates = g_value_get_boxed (&priv->remote_candidates); - - DEBUG ("got new remote candidates"); - - for (li = clist; li; li = li->next) - { - gchar *candidate_id; - GValue candidate = { 0, }; - GPtrArray *transports; - GValue transport = { 0, }; - 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; - - g_value_init (&transport, transport_struct_type); - g_value_take_boxed (&transport, - dbus_g_type_specialized_construct (transport_struct_type)); - - dbus_g_type_struct_set (&transport, - 0, c->component, - 1, c->address, - 2, c->port, - 3, c->protocol == WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP ? 0 : 1, - 4, "RTP", - 5, "AVP", - 6, (gdouble) (c->preference / 65536.0), - 7, c->type, /* FIXME: we're relying on 1:1 tp/jingle candidate type enums */ - 8, c->username, - 9, c->password, - G_MAXUINT); - - transports = g_ptr_array_sized_new (1); - g_ptr_array_add (transports, g_value_get_boxed (&transport)); - - g_value_init (&candidate, candidate_struct_type); - g_value_take_boxed (&candidate, - dbus_g_type_specialized_construct (candidate_struct_type)); - - if (c->id == NULL) - /* FIXME: is this naming scheme sensible? */ - candidate_id = g_strdup_printf ("R%d", ++priv->remote_candidate_count); - else - candidate_id = c->id; - - dbus_g_type_struct_set (&candidate, - 0, candidate_id, - 1, transports, - G_MAXUINT); - - g_free (candidate_id); - g_value_unset (&transport); - g_ptr_array_unref (transports); - - g_ptr_array_add (candidates, g_value_get_boxed (&candidate)); - } - - push_remote_candidates (stream); -} - -static void -content_state_changed_cb (WockyJingleContent *c, - GParamSpec *pspec, - GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv = stream->priv; - WockyJingleContentState state; - - g_object_get (c, "state", &state, NULL); - - DEBUG ("called"); - - switch (state) { - 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; - update_sending (stream, TRUE); - push_playing (stream); - push_sending (stream); - break; - case WOCKY_JINGLE_CONTENT_STATE_REMOVING: - stream->playing = FALSE; - priv->sending = FALSE; - push_playing (stream); - break; - default: - /* so gcc doesn't cry */ - break; - } -} - -static void -push_remote_candidates (GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv; - GPtrArray *candidates; - guint i; - GType candidate_list_type = - TP_ARRAY_TYPE_MEDIA_STREAM_HANDLER_CANDIDATE_LIST; - - g_assert (GABBLE_IS_MEDIA_STREAM (stream)); - - priv = stream->priv; - - candidates = g_value_get_boxed (&priv->remote_candidates); - - if (candidates->len == 0) - return; - - if (!priv->ready) - return; - - for (i = 0; i < candidates->len; i++) - { - GValueArray *candidate = g_ptr_array_index (candidates, i); - const gchar *candidate_id; - const GPtrArray *transports; - - candidate_id = g_value_get_string (g_value_array_get_nth (candidate, 0)); - transports = g_value_get_boxed (g_value_array_get_nth (candidate, 1)); - - DEBUG ("passing 1 remote candidate to stream engine: %s", candidate_id); - tp_svc_media_stream_handler_emit_add_remote_candidate ( - stream, candidate_id, transports); - } - - g_value_take_boxed (&priv->remote_candidates, - dbus_g_type_specialized_construct (candidate_list_type)); -} - -static void -push_playing (GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv; - - g_assert (GABBLE_IS_MEDIA_STREAM (stream)); - - priv = stream->priv; - - if (!priv->ready) - return; - - DEBUG ("stream %s emitting SetStreamPlaying(%s)", - stream->name, stream->playing ? "true" : "false"); - - tp_svc_media_stream_handler_emit_set_stream_playing ( - stream, stream->playing); -} - -static void -push_sending (GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv; - gboolean emit; - - g_assert (GABBLE_IS_MEDIA_STREAM (stream)); - - priv = stream->priv; - - if (!priv->ready) - return; - - emit = (priv->sending && !(priv->on_hold)); - DEBUG ("stream %s emitting SetStreamSending(%s); sending=%s, on_hold=%s", - stream->name, emit ? "true" : "false", priv->sending ? "true" : "false", - priv->on_hold ? "true" : "false"); - - tp_svc_media_stream_handler_emit_set_stream_sending ( - stream, emit); -} - -static void -update_direction (GabbleMediaStream *stream, WockyJingleContent *c) -{ - CombinedStreamDirection new_combined_dir; - TpMediaStreamDirection requested_dir, current_dir; - TpMediaStreamPendingSend pending_send; - WockyJingleContentSenders senders; - gboolean local_initiator; - - DEBUG ("called"); - - g_object_get (c, "senders", &senders, NULL); - g_object_get (c->session, "local-initiator", &local_initiator, NULL); - - switch (senders) { - case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR: - requested_dir = local_initiator ? - TP_MEDIA_STREAM_DIRECTION_SEND : TP_MEDIA_STREAM_DIRECTION_RECEIVE; - break; - case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER: - requested_dir = local_initiator ? - TP_MEDIA_STREAM_DIRECTION_RECEIVE : TP_MEDIA_STREAM_DIRECTION_SEND; - break; - case WOCKY_JINGLE_CONTENT_SENDERS_BOTH: - requested_dir = TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL; - break; - default: - requested_dir = TP_MEDIA_STREAM_DIRECTION_NONE; - } - - current_dir = COMBINED_DIRECTION_GET_DIRECTION (stream->combined_direction); - pending_send = COMBINED_DIRECTION_GET_PENDING_SEND - (stream->combined_direction); - - /* if local sending has been added, remove it, - * and set the pending local send flag */ - if (((current_dir & TP_MEDIA_STREAM_DIRECTION_SEND) == 0) && - ((requested_dir & TP_MEDIA_STREAM_DIRECTION_SEND) != 0)) - { - DEBUG ("setting pending local send flag"); - requested_dir &= ~TP_MEDIA_STREAM_DIRECTION_SEND; - pending_send |= TP_MEDIA_STREAM_PENDING_LOCAL_SEND; - } - - /* make any necessary changes */ - new_combined_dir = MAKE_COMBINED_DIRECTION (requested_dir, pending_send); - if (new_combined_dir != stream->combined_direction) - { - g_object_set (stream, "combined-direction", new_combined_dir, NULL); - update_sending (stream, FALSE); - } - -} - -static void -content_senders_changed_cb (WockyJingleContent *c, - GParamSpec *pspec, - GabbleMediaStream *stream) -{ - update_direction (stream, c); -} - -static void -remote_state_changed_cb (WockyJingleSession *session, - GabbleMediaStream *stream) -{ - GabbleMediaStreamPrivate *priv = stream->priv; - gboolean old_hold = priv->on_hold; - - priv->on_hold = wocky_jingle_session_get_remote_hold (session); - - if (old_hold != priv->on_hold) - push_sending (stream); -} - -static void -content_removed_cb (WockyJingleContent *content, GabbleMediaStream *stream) -{ - gabble_media_stream_close (stream); -} - - -gboolean -gabble_media_stream_change_direction (GabbleMediaStream *stream, - guint requested_dir, GError **error) -{ - GabbleMediaStreamPrivate *priv = stream->priv; - CombinedStreamDirection new_combined_dir; - TpMediaStreamDirection current_dir; - TpMediaStreamPendingSend pending_send; - WockyJingleContentSenders senders; - gboolean local_initiator; - - current_dir = COMBINED_DIRECTION_GET_DIRECTION (stream->combined_direction); - pending_send = COMBINED_DIRECTION_GET_PENDING_SEND - (stream->combined_direction); - - /* if we're awaiting a local decision on sending... */ - if ((pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0) - { - /* clear the flag */ - pending_send &= ~TP_MEDIA_STREAM_PENDING_LOCAL_SEND; - - /* make our current_dir match what other end thinks (he thinks we're - * bidirectional) so that we send the correct transitions */ - current_dir ^= TP_MEDIA_STREAM_DIRECTION_SEND; - } - - /* make any necessary changes */ - new_combined_dir = MAKE_COMBINED_DIRECTION (requested_dir, pending_send); - if (new_combined_dir != stream->combined_direction) - { - WockyJingleContentState state; - gboolean start_sending; - - g_object_set (stream, "combined-direction", new_combined_dir, NULL); - - /* We would like to emit SetStreamSending(True) (if appropriate) only if: - * - the content was locally created, or - * - the user explicitly okayed the content. - * This appears to be the meaning of Acknowledged. :-) - */ - g_object_get (stream->priv->content, "state", &state, NULL); - start_sending = (state == WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED); - - update_sending (stream, start_sending); - } - - DEBUG ("current_dir: %u, requested_dir: %u", current_dir, requested_dir); - - /* short-circuit sending a request if we're not asking for anything new */ - if (current_dir == requested_dir) - return TRUE; - - g_object_get (priv->content->session, "local-initiator", &local_initiator, NULL); - - switch (requested_dir) - { - case TP_MEDIA_STREAM_DIRECTION_SEND: - senders = local_initiator ? - WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER; - break; - - case TP_MEDIA_STREAM_DIRECTION_RECEIVE: - senders = local_initiator ? - WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; - break; - - case TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL: - senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; - break; - - default: - g_assert_not_reached (); - } - - if (!wocky_jingle_content_change_direction (priv->content, senders)) - { - g_set_error (error, TP_ERROR, TP_ERROR_NOT_AVAILABLE, - "stream direction invalid for the Jingle dialect in use"); - return FALSE; - } - - return TRUE; -} - -void -gabble_media_stream_accept_pending_local_send (GabbleMediaStream *stream) -{ - CombinedStreamDirection combined_dir = stream->combined_direction; - TpMediaStreamDirection current_dir; - TpMediaStreamPendingSend pending_send; - - current_dir = COMBINED_DIRECTION_GET_DIRECTION (combined_dir); - pending_send = COMBINED_DIRECTION_GET_PENDING_SEND (combined_dir); - - if ((pending_send & TP_MEDIA_STREAM_PENDING_LOCAL_SEND) != 0) - { - DEBUG ("accepting pending local send on stream %s", stream->name); - - gabble_media_stream_change_direction (stream, - current_dir | TP_MEDIA_STREAM_DIRECTION_SEND, NULL); - } - else - { - DEBUG ("stream %s not pending local send", stream->name); - } -} - -static void -update_sending (GabbleMediaStream *stream, gboolean start_sending) -{ - GabbleMediaStreamPrivate *priv = stream->priv; - gboolean new_sending; - - new_sending = - ((stream->combined_direction & TP_MEDIA_STREAM_DIRECTION_SEND) != 0); - - if (priv->sending == new_sending) - return; - - if (new_sending && !start_sending) - return; - - priv->sending = new_sending; - push_sending (stream); -} - -static void -stream_handler_iface_init (gpointer g_iface, gpointer iface_data) -{ - TpSvcMediaStreamHandlerClass *klass = - (TpSvcMediaStreamHandlerClass *) g_iface; - -#define IMPLEMENT(x,suffix) tp_svc_media_stream_handler_implement_##x (\ - klass, gabble_media_stream_##x##suffix) - IMPLEMENT(codec_choice,); - IMPLEMENT(error,_async); - IMPLEMENT(hold_state,); - IMPLEMENT(native_candidates_prepared,); - IMPLEMENT(new_active_candidate_pair,); - IMPLEMENT(new_native_candidate,); - IMPLEMENT(ready,); - IMPLEMENT(set_local_codecs,); - IMPLEMENT(stream_state,); - IMPLEMENT(supported_codecs,); - IMPLEMENT(unhold_failure,); - IMPLEMENT(codecs_updated,); - IMPLEMENT(supported_header_extensions,); - IMPLEMENT(supported_feedback_messages,); -#undef IMPLEMENT -} - -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 WockyJingleMediaRtp. - */ - return WOCKY_JINGLE_MEDIA_RTP (self->priv->content); -} - -void -gabble_media_stream_start_telephony_event (GabbleMediaStream *self, - guchar event) -{ - DEBUG ("stream %s: %c", self->name, tp_dtmf_event_to_char (event)); - - tp_svc_media_stream_handler_emit_start_telephony_event ( - (TpSvcMediaStreamHandler *) self, event); -} - -void -gabble_media_stream_stop_telephony_event (GabbleMediaStream *self) -{ - DEBUG ("stream %s", self->name); - - tp_svc_media_stream_handler_emit_stop_telephony_event ( - (TpSvcMediaStreamHandler *) self); -} - -void -gabble_media_stream_add_dtmf_player (GabbleMediaStream *self, - TpDTMFPlayer *dtmf_player) -{ - tp_g_signal_connect_object (dtmf_player, "started-tone", - G_CALLBACK (gabble_media_stream_start_telephony_event), self, - G_CONNECT_SWAPPED); - tp_g_signal_connect_object (dtmf_player, "stopped-tone", - G_CALLBACK (gabble_media_stream_stop_telephony_event), self, - G_CONNECT_SWAPPED); -} diff --git a/src/media-stream.h b/src/media-stream.h deleted file mode 100644 index 0fb3504cb..000000000 --- a/src/media-stream.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * gabble-media-stream.h - Header for GabbleMediaStream - * Copyright (C) 2006 Collabora Ltd. - * Copyright (C) 2006 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_MEDIA_STREAM_H__ -#define __GABBLE_MEDIA_STREAM_H__ - -#include <glib-object.h> -#include <telepathy-glib/telepathy-glib.h> -#include <wocky/wocky.h> - -G_BEGIN_DECLS - -typedef enum -{ - STREAM_SIG_STATE_NEW, - STREAM_SIG_STATE_SENT, - STREAM_SIG_STATE_ACKNOWLEDGED, - STREAM_SIG_STATE_REMOVING -} StreamSignallingState; - -typedef guint32 CombinedStreamDirection; - -typedef struct _GabbleMediaStream GabbleMediaStream; -typedef struct _GabbleMediaStreamClass GabbleMediaStreamClass; -typedef struct _GabbleMediaStreamPrivate GabbleMediaStreamPrivate; - -struct _GabbleMediaStreamClass { - GObjectClass parent_class; - - TpDBusPropertiesMixinClass props_class; -}; - -struct _GabbleMediaStream { - GObject parent; - - gchar *name; - - TpMediaStreamState connection_state; - - CombinedStreamDirection combined_direction; - gboolean playing; - - GabbleMediaStreamPrivate *priv; -}; - -GType gabble_media_stream_get_type (void); - -/* TYPE MACROS */ -#define GABBLE_TYPE_MEDIA_STREAM \ - (gabble_media_stream_get_type ()) -#define GABBLE_MEDIA_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_MEDIA_STREAM, \ - GabbleMediaStream)) -#define GABBLE_MEDIA_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_MEDIA_STREAM, \ - GabbleMediaStreamClass)) -#define GABBLE_IS_MEDIA_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_MEDIA_STREAM)) -#define GABBLE_IS_MEDIA_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_MEDIA_STREAM)) -#define GABBLE_MEDIA_STREAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_MEDIA_STREAM, \ - GabbleMediaStreamClass)) - -#define COMBINED_DIRECTION_GET_DIRECTION(d) \ - ((TpMediaStreamDirection) ((d) & TP_MEDIA_STREAM_DIRECTION_BIDIRECTIONAL)) -#define COMBINED_DIRECTION_GET_PENDING_SEND(d) \ - ((TpMediaStreamPendingSend) ((d) >> 2)) -#define MAKE_COMBINED_DIRECTION(d, p) \ - ((CombinedStreamDirection) ((d) | ((p) << 2))) - -gboolean gabble_media_stream_error (GabbleMediaStream *self, guint errnum, - const gchar *message, GError **error); - -void gabble_media_stream_close (GabbleMediaStream *close); -void gabble_media_stream_hold (GabbleMediaStream *stream, gboolean hold); -gboolean gabble_media_stream_change_direction (GabbleMediaStream *stream, - guint requested_dir, GError **error); -void gabble_media_stream_accept_pending_local_send (GabbleMediaStream *stream); - -GabbleMediaStream *gabble_media_stream_new ( - TpDBusDaemon *dbus_daemon, - const gchar *object_path, - WockyJingleContent *content, - const gchar *name, - guint id, - const gchar *nat_traversal, - const GPtrArray *relay_info, - gboolean local_hold); -TpMediaStreamType gabble_media_stream_get_media_type (GabbleMediaStream *self); - -void gabble_media_stream_add_dtmf_player (GabbleMediaStream *self, - TpDTMFPlayer *dtmf_player); - -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); - -G_END_DECLS - -#endif /* #ifndef __GABBLE_MEDIA_STREAM_H__*/ diff --git a/src/message-util.c b/src/message-util.c index 01bb71735..6b80708f7 100644 --- a/src/message-util.c +++ b/src/message-util.c @@ -118,7 +118,7 @@ gabble_message_util_build_stanza (TpMessage *message, if (!result) RETURN_INVALID_ARGUMENT ("message-type must be a 32-bit unsigned integer"); - if (type >= NUM_TP_CHANNEL_TEXT_MESSAGE_TYPES) + if (type >= TP_NUM_CHANNEL_TEXT_MESSAGE_TYPES) RETURN_INVALID_ARGUMENT ("invalid message type: %u", type); n_parts = tp_message_count_parts (message); diff --git a/src/muc-channel.c b/src/muc-channel.c index 15c337b07..78f79c74d 100644 --- a/src/muc-channel.c +++ b/src/muc-channel.c @@ -815,7 +815,7 @@ tube_pre_presence (GabbleMucChannel *gmuc, GabbleTubeIface *tube = value; TpTubeChannelState state; WockyNode *tube_node; - TpTubeType type; + TubeType type; TpHandle initiator; g_object_get (tube, @@ -827,7 +827,7 @@ tube_pre_presence (GabbleMucChannel *gmuc, if (state != TP_TUBE_CHANNEL_STATE_OPEN) continue; - if (type == TP_TUBE_TYPE_STREAM + if (type == TUBE_TYPE_STREAM && initiator != TP_GROUP_MIXIN (gmuc)->self_handle) /* We only announce stream tubes we initiated */ continue; @@ -1971,7 +1971,7 @@ tube_closed_cb (GabbleTubeIface *tube, static GabbleTubeIface * create_new_tube (GabbleMucChannel *gmuc, - TpTubeType type, + TubeType type, TpHandle initiator, const gchar *service, GHashTable *parameters, @@ -1990,13 +1990,13 @@ create_new_tube (GabbleMucChannel *gmuc, switch (type) { - case TP_TUBE_TYPE_DBUS: + case 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: + case 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)); @@ -2044,7 +2044,7 @@ gabble_muc_channel_tube_request (GabbleMucChannel *self, GHashTable *parameters = NULL; guint64 tube_id; gchar *stream_id; - TpTubeType type; + TubeType type; tube_id = generate_tube_id (self); @@ -2053,14 +2053,14 @@ gabble_muc_channel_tube_request (GabbleMucChannel *self, if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE)) { - type = TP_TUBE_TYPE_STREAM; + type = 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; + type = TUBE_TYPE_DBUS; service = tp_asv_get_string (request_properties, TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME); } @@ -2231,7 +2231,7 @@ tubes_presence_update (GabbleMucChannel *gmuc, const gchar *stream_id; GabbleTubeIface *tube; guint64 tube_id; - TpTubeType type; + TubeType type; stream_id = wocky_node_get_attribute (tube_node, "stream-id"); @@ -2255,13 +2255,13 @@ tubes_presence_update (GabbleMucChannel *gmuc, contact_repo, tube_node, &type, &initiator_handle, &service, ¶meters, NULL)) { - if (type == TP_TUBE_TYPE_DBUS && initiator_handle == 0) + if (type == 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) + else if (type == TUBE_TYPE_STREAM) { initiator_handle = contact; } @@ -2287,7 +2287,7 @@ tubes_presence_update (GabbleMucChannel *gmuc, g_object_get (tube, "type", &type, NULL); - if (type == TP_TUBE_TYPE_DBUS) + if (type == TUBE_TYPE_DBUS) { /* Update mapping of handle -> D-Bus name. */ if (!gabble_tube_dbus_handle_in_names (GABBLE_TUBE_DBUS (tube), diff --git a/src/muc-factory.c b/src/muc-factory.c index 0f1dbcb07..39f468509 100644 --- a/src/muc-factory.c +++ b/src/muc-factory.c @@ -266,56 +266,51 @@ muc_ready_cb (GabbleMucChannel *text_chan, { GabbleMucFactory *fac = GABBLE_MUC_FACTORY (data); GabbleMucFactoryPrivate *priv = fac->priv; - GHashTable *channels; TpBaseChannel *base = TP_BASE_CHANNEL (text_chan); - GSList *requests_satisfied_text = NULL; GQueue *tube_channels; DEBUG ("text chan=%p", text_chan); - 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); + /* 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)) + { + tp_channel_manager_emit_new_channel (fac, + TP_EXPORTABLE_CHANNEL (text_chan), requests_satisfied_text); + } + /* Announce tube channels now */ tube_channels = g_hash_table_lookup (priv->text_needed_for_tube, text_chan); + if (tube_channels != NULL) { GList *l; for (l = tube_channels->head; l != NULL; l = l->next) { - GabbleTubeIface *tube_chan = GABBLE_TUBE_IFACE (l->data); + TpExportableChannel *tube_chan = TP_EXPORTABLE_CHANNEL (l->data); GSList *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_hash_table_insert (channels, tube_chan, requests_satisfied_tube); + tp_channel_manager_emit_new_channel (fac, tube_chan, + requests_satisfied_tube); + g_slist_free (requests_satisfied_tube); } g_hash_table_remove (priv->text_needed_for_tube, text_chan); } - - /* 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)) - { - tp_channel_manager_emit_new_channel (fac, - TP_EXPORTABLE_CHANNEL (text_chan), requests_satisfied_text); - } - - tp_channel_manager_emit_new_channels (fac, channels); - - g_hash_table_unref (channels); } static void diff --git a/src/plugin-loader.c b/src/plugin-loader.c index 2e14c0781..392715966 100644 --- a/src/plugin-loader.c +++ b/src/plugin-loader.c @@ -89,13 +89,18 @@ plugin_loader_try_to_load ( } else { - gchar *sidecars = g_strjoinv (", ", - (gchar **) gabble_plugin_get_sidecar_interfaces (plugin)); + const gchar * const *interfaces = gabble_plugin_get_sidecar_interfaces (plugin); const gchar *version = gabble_plugin_get_version (plugin); + gchar *sidecars; if (version == NULL) version = "(unspecified)"; + if (interfaces != NULL) + sidecars = g_strjoinv (", ", (gchar **) interfaces); + else + sidecars = g_strdup ("none (maybe it implements some channels instead?)"); + DEBUG ("loaded '%s' version %s (%s), implementing these sidecars: %s", gabble_plugin_get_name (plugin), version, path, sidecars); diff --git a/src/private-tubes-factory.c b/src/private-tubes-factory.c index 192450907..b70f1b069 100644 --- a/src/private-tubes-factory.c +++ b/src/private-tubes-factory.c @@ -89,8 +89,6 @@ struct _GabblePrivateTubesFactoryPrivate gboolean dispose_has_run; }; -#define GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE(obj) ((obj)->priv) - static const gchar * const tubes_channel_fixed_properties[] = { TP_PROP_CHANNEL_CHANNEL_TYPE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, @@ -107,7 +105,7 @@ gboolean gabble_private_tubes_factory_extract_tube_information ( TpHandleRepoIface *contact_repo, WockyNode *tube_node, - TpTubeType *type, + TubeType *type, TpHandle *initiator_handle, const gchar **service, GHashTable **parameters, @@ -121,11 +119,11 @@ gabble_private_tubes_factory_extract_tube_information ( if (!tp_strdiff (_type, "stream")) { - *type = TP_TUBE_TYPE_STREAM; + *type = TUBE_TYPE_STREAM; } else if (!tp_strdiff (_type, "dbus")) { - *type = TP_TUBE_TYPE_DBUS; + *type = TUBE_TYPE_DBUS; } else { @@ -197,16 +195,14 @@ gabble_private_tubes_factory_extract_tube_information ( static void gabble_private_tubes_factory_init (GabblePrivateTubesFactory *self) { - GabblePrivateTubesFactoryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_PRIVATE_TUBES_FACTORY, GabblePrivateTubesFactoryPrivate); - self->priv = priv; - - priv->tubes = g_hash_table_new_full (g_direct_hash, g_direct_equal, + self->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; + self->priv->conn = NULL; + self->priv->dispose_has_run = FALSE; } @@ -220,15 +216,15 @@ porter_available_cb ( gpointer user_data) { GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (user_data); - GabblePrivateTubesFactoryPrivate *priv = self->priv; - priv->msg_tube_cb = wocky_porter_register_handler_from_anyone (porter, + self->priv->msg_tube_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, '(', "tube", ':', NS_TUBES, ')', NULL); - priv->msg_close_cb = wocky_porter_register_handler_from_anyone (porter, + + self->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_tube_close_cb, self, @@ -258,17 +254,15 @@ gabble_private_tubes_factory_constructor (GType type, { GObject *obj; GabblePrivateTubesFactory *self; - GabblePrivateTubesFactoryPrivate *priv; obj = G_OBJECT_CLASS (gabble_private_tubes_factory_parent_class)-> constructor (type, n_props, props); self = GABBLE_PRIVATE_TUBES_FACTORY (obj); - priv = GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); self->priv->status_changed_id = g_signal_connect (self->priv->conn, "status-changed", (GCallback) connection_status_changed_cb, obj); - tp_g_signal_connect_object (priv->conn, "porter-available", + tp_g_signal_connect_object (self->priv->conn, "porter-available", (GCallback) porter_available_cb, obj, 0); return obj; @@ -278,18 +272,16 @@ gabble_private_tubes_factory_constructor (GType type, static void gabble_private_tubes_factory_dispose (GObject *object) { - GabblePrivateTubesFactory *fac = GABBLE_PRIVATE_TUBES_FACTORY (object); - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (fac); + GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (object); - if (priv->dispose_has_run) + if (self->priv->dispose_has_run) return; DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; + self->priv->dispose_has_run = TRUE; - gabble_private_tubes_factory_close_all (fac); - g_assert (priv->tubes == NULL); + gabble_private_tubes_factory_close_all (self); + g_assert (self->priv->tubes == NULL); if (G_OBJECT_CLASS (gabble_private_tubes_factory_parent_class)->dispose) G_OBJECT_CLASS (gabble_private_tubes_factory_parent_class)->dispose ( @@ -302,14 +294,12 @@ gabble_private_tubes_factory_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - GabblePrivateTubesFactory *fac = GABBLE_PRIVATE_TUBES_FACTORY (object); - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (fac); + GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (object); switch (property_id) { case PROP_CONNECTION: - g_value_set_object (value, priv->conn); + g_value_set_object (value, self->priv->conn); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -323,14 +313,12 @@ gabble_private_tubes_factory_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - GabblePrivateTubesFactory *fac = GABBLE_PRIVATE_TUBES_FACTORY (object); - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (fac); + GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (object); switch (property_id) { case PROP_CONNECTION: - priv->conn = g_value_get_object (value); + self->priv->conn = g_value_get_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -366,37 +354,35 @@ gabble_private_tubes_factory_class_init ( } static void -gabble_private_tubes_factory_close_all (GabblePrivateTubesFactory *fac) +gabble_private_tubes_factory_close_all (GabblePrivateTubesFactory *self) { - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (fac); - DEBUG ("closing 1-1 tubes channels"); - if (priv->status_changed_id != 0) + if (self->priv->status_changed_id != 0) { - g_signal_handler_disconnect (priv->conn, - priv->status_changed_id); - priv->status_changed_id = 0; + g_signal_handler_disconnect (self->priv->conn, + self->priv->status_changed_id); + self->priv->status_changed_id = 0; } - if (priv->msg_tube_cb != 0) + if (self->priv->msg_tube_cb != 0) { - WockyPorter *porter = wocky_session_get_porter (priv->conn->session); + WockyPorter *porter = wocky_session_get_porter ( + self->priv->conn->session); - wocky_porter_unregister_handler (porter, priv->msg_tube_cb); - priv->msg_tube_cb = 0; - wocky_porter_unregister_handler (porter, priv->msg_close_cb); - priv->msg_close_cb = 0; + wocky_porter_unregister_handler (porter, self->priv->msg_tube_cb); + self->priv->msg_tube_cb = 0; + wocky_porter_unregister_handler (porter, self->priv->msg_close_cb); + self->priv->msg_close_cb = 0; } - tp_clear_pointer (&priv->tubes, g_hash_table_unref); + tp_clear_pointer (&self->priv->tubes, g_hash_table_unref); } static void add_service_to_array (const gchar *service, GPtrArray *arr, - TpTubeType type, + TubeType type, TpHandle handle) { GValue monster = {0, }; @@ -410,7 +396,7 @@ add_service_to_array (const gchar *service, NULL }; - g_assert (type == TP_TUBE_TYPE_STREAM || type == TP_TUBE_TYPE_DBUS); + g_assert (type == TUBE_TYPE_STREAM || type == TUBE_TYPE_DBUS); g_value_init (&monster, TP_STRUCT_TYPE_REQUESTABLE_CHANNEL_CLASS); g_value_take_boxed (&monster, @@ -421,7 +407,7 @@ add_service_to_array (const gchar *service, (GDestroyNotify) tp_g_value_slice_free); channel_type_value = tp_g_value_slice_new (G_TYPE_STRING); - if (type == TP_TUBE_TYPE_STREAM) + if (type == TUBE_TYPE_STREAM) g_value_set_static_string (channel_type_value, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE); else @@ -437,7 +423,7 @@ add_service_to_array (const gchar *service, target_handle_type_value = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (target_handle_type_value, service); - if (type == TP_TUBE_TYPE_STREAM) + if (type == TUBE_TYPE_STREAM) g_hash_table_insert (fixed_properties, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE, target_handle_type_value); @@ -546,10 +532,10 @@ get_contact_caps_foreach (gpointer data, if (g_str_has_prefix (ns, STREAM_CAP_PREFIX)) add_service_to_array (ns + strlen (STREAM_CAP_PREFIX), closure->arr, - TP_TUBE_TYPE_STREAM, closure->handle); + TUBE_TYPE_STREAM, closure->handle); else if (g_str_has_prefix (ns, DBUS_CAP_PREFIX)) add_service_to_array (ns + strlen (DBUS_CAP_PREFIX), closure->arr, - TP_TUBE_TYPE_DBUS, closure->handle); + TUBE_TYPE_DBUS, closure->handle); } static void @@ -591,8 +577,7 @@ gabble_private_tubes_factory_add_cap (GabbleCapsChannelManager *manager, TP_PROP_CHANNEL_CHANNEL_TYPE); /* this channel is not for this factory */ - 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; @@ -665,15 +650,13 @@ gabble_private_tubes_factory_foreach_channel (TpChannelManager *manager, TpExportableChannelFunc foreach, gpointer user_data) { - GabblePrivateTubesFactory *fac = GABBLE_PRIVATE_TUBES_FACTORY (manager); - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (fac); + GabblePrivateTubesFactory *self = GABBLE_PRIVATE_TUBES_FACTORY (manager); struct _ForeachData data; data.user_data = user_data; data.foreach = foreach; - g_hash_table_foreach (priv->tubes, _foreach_slave, &data); + g_hash_table_foreach (self->priv->tubes, _foreach_slave, &data); } void @@ -684,9 +667,8 @@ gabble_private_tubes_factory_handle_si_tube_request ( const gchar *stream_id, WockyStanza *msg) { - GabblePrivateTubesFactoryPrivate *priv = self->priv; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); WockyNode *si_node, *tube_node; WockyStanzaType stanza_type; WockyStanzaSubType sub_type; @@ -718,7 +700,7 @@ gabble_private_tubes_factory_handle_si_tube_request ( return; } - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + tube = g_hash_table_lookup (self->priv->tubes, GUINT_TO_POINTER (tube_id)); if (tube != NULL) { GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, @@ -742,10 +724,8 @@ gabble_private_tubes_factory_handle_si_stream_request ( const gchar *stream_id, WockyStanza *msg) { - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); const gchar *tmp; guint64 tube_id; WockyNode *si_node, *stream_node; @@ -789,7 +769,7 @@ gabble_private_tubes_factory_handle_si_stream_request ( return; } - tube = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + tube = g_hash_table_lookup (self->priv->tubes, GUINT_TO_POINTER (tube_id)); if (tube == NULL) { GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, @@ -814,10 +794,8 @@ tube_msg_checks (GabblePrivateTubesFactory *self, TpHandle *out_handle, guint64 *out_tube_id) { - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); const gchar *from, *tmp; TpHandle handle; guint64 tube_id; @@ -867,8 +845,6 @@ private_tubes_factory_msg_tube_cb ( 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; @@ -881,7 +857,7 @@ private_tubes_factory_msg_tube_cb ( if (!tube_msg_checks (self, msg, node, &handle, &tube_id)) return FALSE; - channel = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + channel = g_hash_table_lookup (self->priv->tubes, GUINT_TO_POINTER (tube_id)); if (channel != NULL) { @@ -914,12 +890,10 @@ private_tubes_factory_tube_close_cb ( 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; + TubeType type; node = wocky_node_get_child_ns ( wocky_stanza_get_top_node (msg), "close", NS_TUBES); @@ -928,7 +902,7 @@ private_tubes_factory_tube_close_cb ( if (!tube_msg_checks (self, msg, node, NULL, &tube_id)) return FALSE; - channel = g_hash_table_lookup (priv->tubes, GUINT_TO_POINTER (tube_id)); + channel = g_hash_table_lookup (self->priv->tubes, GUINT_TO_POINTER (tube_id)); if (channel == NULL) { @@ -937,7 +911,7 @@ private_tubes_factory_tube_close_cb ( } g_object_get (channel, "type", &type, NULL); - if (type != TP_TUBE_TYPE_STREAM) + if (type != TUBE_TYPE_STREAM) { DEBUG ("Only stream tubes can be closed using a close message"); return TRUE; @@ -955,12 +929,10 @@ gabble_private_tubes_factory_lookup (GabblePrivateTubesFactory *self, 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); + g_hash_table_iter_init (&iter, self->priv->tubes); while (g_hash_table_iter_next (&iter, NULL, &value)) { GabbleTubeIface *tube = value; @@ -994,8 +966,6 @@ static void channel_closed_cb (GabbleTubeIface *tube, GabblePrivateTubesFactory *self) { - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); guint64 id; g_object_get (tube, @@ -1005,15 +975,13 @@ channel_closed_cb (GabbleTubeIface *tube, 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)); + if (self->priv->tubes != NULL) + g_hash_table_remove (self->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 */ @@ -1021,7 +989,7 @@ generate_tube_id (GabblePrivateTubesFactory *self) { out = g_random_int_range (1, G_MAXINT32); } - while (g_hash_table_lookup (priv->tubes, + while (g_hash_table_lookup (self->priv->tubes, GUINT_TO_POINTER (out)) != NULL); return out; @@ -1033,10 +1001,8 @@ 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); + TpBaseConnection *base_conn = TP_BASE_CONNECTION (self->priv->conn); gchar *stream_id; @@ -1063,7 +1029,7 @@ new_channel_from_request (GabblePrivateTubesFactory *self, service = tp_asv_get_string (request, TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE); - tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (priv->conn, + tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (self->priv->conn, handle, handle_type, tp_base_connection_get_self_handle (base_conn), tp_base_connection_get_self_handle (base_conn), @@ -1076,7 +1042,7 @@ new_channel_from_request (GabblePrivateTubesFactory *self, stream_id = gabble_bytestream_factory_generate_stream_id (); - tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (priv->conn, + tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (self->priv->conn, handle, handle_type, tp_base_connection_get_self_handle (base_conn), tp_base_connection_get_self_handle (base_conn), @@ -1094,7 +1060,7 @@ new_channel_from_request (GabblePrivateTubesFactory *self, g_signal_connect (tube, "closed", G_CALLBACK (channel_closed_cb), self); - g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), + g_hash_table_insert (self->priv->tubes, GUINT_TO_POINTER (tube_id), tube); g_hash_table_unref (parameters); @@ -1107,15 +1073,13 @@ 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); + porter = gabble_connection_dup_porter (self->priv->conn); /* Send the close message */ msg = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE, @@ -1143,14 +1107,12 @@ new_channel_from_stanza (GabblePrivateTubesFactory *self, guint64 tube_id, GabbleBytestreamIface *bytestream) { - GabblePrivateTubesFactoryPrivate *priv = - GABBLE_PRIVATE_TUBES_FACTORY_GET_PRIVATE (self); GabbleTubeIface *tube; - TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn); + TpBaseConnection *base_conn = TP_BASE_CONNECTION (self->priv->conn); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); + (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); - TpTubeType type; + TubeType type; TpHandle handle; const gchar *service; GHashTable *parameters; @@ -1169,13 +1131,13 @@ new_channel_from_stanza (GabblePrivateTubesFactory *self, return NULL; } - if (bytestream == NULL && type != TP_TUBE_TYPE_STREAM) + if (bytestream == NULL && type != 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) + else if (bytestream != NULL && type != TUBE_TYPE_DBUS) { GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_FORBIDDEN, "Only D-Bus tubes are allowed to be created using SI" }; @@ -1185,9 +1147,9 @@ new_channel_from_stanza (GabblePrivateTubesFactory *self, return NULL; } - if (type == TP_TUBE_TYPE_STREAM) + if (type == TUBE_TYPE_STREAM) { - tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (priv->conn, + tube = GABBLE_TUBE_IFACE (gabble_tube_stream_new (self->priv->conn, handle, TP_HANDLE_TYPE_CONTACT, tp_base_connection_get_self_handle (base_conn), handle, service, parameters, tube_id, NULL, FALSE)); @@ -1204,7 +1166,7 @@ new_channel_from_stanza (GabblePrivateTubesFactory *self, 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, + tube = GABBLE_TUBE_IFACE (gabble_tube_dbus_new (self->priv->conn, handle, TP_HANDLE_TYPE_CONTACT, tp_base_connection_get_self_handle (base_conn), handle, service, parameters, @@ -1216,7 +1178,7 @@ new_channel_from_stanza (GabblePrivateTubesFactory *self, g_signal_connect (tube, "closed", G_CALLBACK (channel_closed_cb), self); - g_hash_table_insert (priv->tubes, GUINT_TO_POINTER (tube_id), + g_hash_table_insert (self->priv->tubes, GUINT_TO_POINTER (tube_id), tube); g_hash_table_unref (parameters); diff --git a/src/private-tubes-factory.h b/src/private-tubes-factory.h index d9e01f17a..5725b7f94 100644 --- a/src/private-tubes-factory.h +++ b/src/private-tubes-factory.h @@ -23,9 +23,11 @@ #include <glib-object.h> #include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "connection.h" #include "bytestream-iface.h" +#include "tube-iface.h" G_BEGIN_DECLS @@ -77,7 +79,7 @@ void gabble_private_tubes_factory_handle_si_stream_request ( gboolean gabble_private_tubes_factory_extract_tube_information ( TpHandleRepoIface *contact_repo, WockyNode *tube_node, - TpTubeType *type, TpHandle *initiator_handle, + TubeType *type, TpHandle *initiator_handle, const gchar **service, GHashTable **parameters, guint64 *tube_id); diff --git a/src/protocol.c b/src/protocol.c index deeaa8d9e..ce2f59b4a 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -30,6 +30,7 @@ #include "extensions/extensions.h" +#include "conn-avatars.h" #include "conn-presence.h" #include "connection.h" @@ -180,6 +181,9 @@ static TpCMParamSpec jabber_params[] = { { "extra-certificate-identities", "as", 0, 0, NULL, 0 /* unused */, NULL, NULL }, + { "account-path-suffix", "s", G_TYPE_STRING, + 0, NULL, 0 /* unused */, NULL, NULL }, + { NULL, NULL, 0, 0, NULL, 0 } }; @@ -276,6 +280,8 @@ new_connection (TpBaseProtocol *protocol, conn = g_object_new (GABBLE_TYPE_CONNECTION, "protocol", PROTOCOL_NAME, "password", tp_asv_get_string (params, "password"), + "account-path-suffix", tp_asv_get_string (params, + "account-path-suffix"), NULL); /* split up account into username, stream-server and resource */ @@ -330,6 +336,7 @@ get_interfaces_array (TpBaseProtocol *self) g_ptr_array_add (interfaces, TP_IFACE_PROTOCOL_INTERFACE_PRESENCE); g_ptr_array_add (interfaces, TP_IFACE_PROTOCOL_INTERFACE_ADDRESSING); + g_ptr_array_add (interfaces, TP_IFACE_PROTOCOL_INTERFACE_AVATARS); return interfaces; } @@ -454,6 +461,21 @@ addressing_normalize_contact_uri (TpBaseProtocol *self, } static void +get_avatar_details (TpBaseProtocol *base, + GStrv *supported_mime_types, + guint *min_height, + guint *min_width, + guint *rec_height, + guint *rec_width, + guint *max_height, + guint *max_width, + guint *max_bytes) +{ + gabble_connection_dup_avatar_requirements (supported_mime_types, min_height, + min_width, rec_height, rec_width, max_height, max_width, max_bytes); +} + +static void gabble_jabber_protocol_class_init (GabbleJabberProtocolClass *klass) { TpBaseProtocolClass *base_class = @@ -467,6 +489,7 @@ gabble_jabber_protocol_class_init (GabbleJabberProtocolClass *klass) base_class->get_connection_details = get_connection_details; base_class->get_statuses = get_presence_statuses; base_class->dup_authentication_types = dup_authentication_types; + base_class->get_avatar_details = get_avatar_details; } TpBaseProtocol * diff --git a/src/roster.c b/src/roster.c index d2cc4dae8..aa07a6034 100644 --- a/src/roster.c +++ b/src/roster.c @@ -63,7 +63,8 @@ struct _GabbleRosterPrivate guint presence_cb; GHashTable *items; - TpHandleSet *groups; + /* Used as a set of own (gchar *) */ + GHashTable *groups; /* set of contacts whose subscription requests will automatically be * accepted during this session */ @@ -114,8 +115,8 @@ struct _GabbleRosterItemEdit /* if TRUE, disregard new_name and remove name='' from the roster item */ gboolean remove_name; - TpHandleSet *add_to_groups; - TpHandleSet *remove_from_groups; + GHashTable *add_to_groups; + GHashTable *remove_from_groups; gboolean remove_from_all_other_groups; }; @@ -127,7 +128,7 @@ struct _GabbleRosterItem GoogleItemType google_type; gchar *name; gchar *alias_for; - TpHandleSet *groups; + GHashTable *groups; /* if TRUE, an edit attempt is already "in-flight" so we can't send off * edits immediately - instead, store them in unsent_edits */ gboolean edits_in_flight; @@ -230,7 +231,7 @@ _gabble_roster_item_free (GabbleRosterItem *item) { g_assert (item != NULL); - tp_handle_set_destroy (item->groups); + g_hash_table_unref (item->groups); item_edit_free (item->unsent_edits); g_free (item->name); g_free (item->alias_for); @@ -288,13 +289,11 @@ _parse_item_subscription (WockyNode *item_node) } } -static TpHandleSet * +static GHashTable * _parse_item_groups (WockyNode *item_node, TpBaseConnection *conn) { - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - conn, TP_HANDLE_TYPE_GROUP); - TpHandleSet *groups = tp_handle_set_new (group_repo); - TpHandle handle; + GHashTable *groups = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); WockyNodeIter i; WockyNode *group_node; @@ -306,10 +305,7 @@ _parse_item_groups (WockyNode *item_node, TpBaseConnection *conn) if (NULL == value) continue; - handle = tp_handle_ensure (group_repo, value, NULL, NULL); - if (!handle) - continue; - tp_handle_set_add (groups, handle); + g_hash_table_add (groups, g_strdup (value)); } return groups; @@ -409,8 +405,6 @@ _gabble_roster_item_ensure (GabbleRoster *roster, TpHandle handle) { GabbleRosterPrivate *priv = roster->priv; - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_GROUP); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); GabbleRosterItem *item; @@ -444,7 +438,8 @@ _gabble_roster_item_ensure (GabbleRoster *roster, item->subscribe = TP_SUBSCRIPTION_STATE_NO; item->publish = TP_SUBSCRIPTION_STATE_NO; item->name = alias; - item->groups = tp_handle_set_new (group_repo); + item->groups = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); g_hash_table_insert (priv->items, GUINT_TO_POINTER (handle), item); } @@ -500,6 +495,87 @@ _gabble_roster_item_maybe_remove (GabbleRoster *roster, return TRUE; } +/* Add all the groups from @set to @add using @copy to duplicate them into + * @set. + * Returns (transfer full) the groups which have been actually added. + */ +static GHashTable * +group_set_update (GHashTable *set, + GHashTable *add) +{ + GHashTable *added = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + GHashTableIter iter; + gpointer k; + + g_hash_table_iter_init (&iter, add); + while (g_hash_table_iter_next (&iter, &k, NULL)) + { + if (!g_hash_table_contains (set, k)) + { + g_hash_table_add (set, g_strdup (k)); + g_hash_table_add (added, g_strdup (k)); + } + } + + return added; +} + +static void +group_set_difference_update (GHashTable *set, + GHashTable *other) +{ + GHashTableIter iter; + gpointer k; + + g_hash_table_iter_init (&iter, other); + while (g_hash_table_iter_next (&iter, &k, NULL)) + { + g_hash_table_remove (set, k); + } +} + +/* Returns (transfer full) the set of groups which are in @left and not + * in @right */ +static GHashTable * +group_set_difference (GHashTable *left, + GHashTable *right) +{ + GHashTable *diff = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + GHashTableIter iter; + gpointer k; + + g_hash_table_iter_init (&iter, left); + while (g_hash_table_iter_next (&iter, &k, NULL)) + { + if (!g_hash_table_contains (right, k)) + g_hash_table_add (diff, g_strdup (k)); + } + + return diff; +} + +static gboolean +group_set_is_equal (GHashTable *left, + GHashTable *right) +{ + GHashTableIter iter; + gpointer k; + + if (g_hash_table_size (left) != g_hash_table_size (right)) + return FALSE; + + g_hash_table_iter_init (&iter, left); + while (g_hash_table_iter_next (&iter, &k, NULL)) + { + if (!g_hash_table_contains (right, k)) + return FALSE; + } + + return TRUE; +} + static GabbleRosterItem * _gabble_roster_item_update (GabbleRoster *roster, TpHandle contact_handle, @@ -510,13 +586,10 @@ _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; - TpHandleSet *new_groups_handle_set, *old_groups; + GHashTable *new_groups, *removed_from, *added_to; TpBaseContactList *base = (TpBaseContactList *) roster; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_GROUP); g_assert (roster != NULL); g_assert (GABBLE_IS_ROSTER (roster)); @@ -560,40 +633,36 @@ _gabble_roster_item_update (GabbleRoster *roster, *nickname_updated = FALSE; } - new_groups_handle_set = _parse_item_groups (node, + new_groups = _parse_item_groups (node, (TpBaseConnection *) priv->conn); - new_groups = tp_handle_set_peek (new_groups_handle_set); - old_groups = tp_handle_set_copy (item->groups); - removed_from = tp_intset_difference (tp_handle_set_peek (item->groups), - new_groups); - added_to = tp_handle_set_update (item->groups, new_groups); - removed_from2 = tp_handle_set_difference_update (item->groups, removed_from); + removed_from = group_set_difference (item->groups, new_groups); + added_to = group_set_update (item->groups, new_groups); + group_set_difference_update (item->groups, removed_from); if (roster->priv->groups != NULL) { - TpIntset *created_groups = tp_handle_set_update (roster->priv->groups, - new_groups); + GHashTable *created_groups; + + created_groups = group_set_update (roster->priv->groups, new_groups); /* we don't need to do this work if TpBaseContactList will just be * ignoring it, as it will before we've received the roster */ if (tp_base_contact_list_get_state ((TpBaseContactList *) roster, NULL) == TP_CONTACT_LIST_STATE_SUCCESS && - !tp_intset_is_empty (created_groups)) + g_hash_table_size (created_groups) > 0) { - GPtrArray *strv = g_ptr_array_sized_new (tp_intset_size ( + GPtrArray *strv = g_ptr_array_sized_new (g_hash_table_size ( created_groups)); - TpIntsetFastIter iter; - TpHandle group; + GHashTableIter iter; + gpointer k; - tp_intset_fast_iter_init (&iter, created_groups); - - while (tp_intset_fast_iter_next (&iter, &group)) + g_hash_table_iter_init (&iter, created_groups); + while (g_hash_table_iter_next (&iter, &k, NULL)) { - const gchar *group_name = tp_handle_inspect (group_repo, - group); + const gchar *group_name = k; - DEBUG ("Group was just created: #%u '%s'", group, group_name); + DEBUG ("Group was just created: '%s'", group_name); g_ptr_array_add (strv, (gchar *) group_name); } @@ -603,7 +672,7 @@ _gabble_roster_item_update (GabbleRoster *roster, g_ptr_array_unref (strv); } - tp_clear_pointer (&created_groups, tp_intset_destroy); + tp_clear_pointer (&created_groups, g_hash_table_unref); } /* We emit one GroupsChanged signal per contact, because that's most natural @@ -614,38 +683,35 @@ _gabble_roster_item_update (GabbleRoster *roster, * recover state. */ if (tp_base_contact_list_get_state (base, NULL) == TP_CONTACT_LIST_STATE_SUCCESS && - (!tp_intset_is_empty (added_to) || !tp_intset_is_empty (removed_from))) + (g_hash_table_size (added_to) > 0 || + g_hash_table_size (removed_from) > 0)) { - GPtrArray *added_names = g_ptr_array_sized_new (tp_intset_size (added_to)); + GPtrArray *added_names = g_ptr_array_sized_new ( + g_hash_table_size (added_to)); GPtrArray *removed_names = g_ptr_array_sized_new ( - tp_intset_size (removed_from)); + g_hash_table_size (removed_from)); TpHandleSet *the_contact = tp_handle_set_new (contact_repo); - TpIntsetFastIter iter; - TpHandle group; + GHashTableIter iter; + gpointer k; tp_handle_set_add (the_contact, contact_handle); - tp_intset_fast_iter_init (&iter, added_to); - - while (tp_intset_fast_iter_next (&iter, &group)) + g_hash_table_iter_init (&iter, added_to); + while (g_hash_table_iter_next (&iter, &k, NULL)) { - const gchar *group_name = tp_handle_inspect (group_repo, - group); + const gchar *group_name = k; - DEBUG ("Contact #%u added to group #%u '%s'", contact_handle, group, - group_name); + DEBUG ("Contact #%u added to group '%s'", contact_handle, group_name); g_ptr_array_add (added_names, (gchar *) group_name); } - tp_intset_fast_iter_init (&iter, removed_from); - - while (tp_intset_fast_iter_next (&iter, &group)) + g_hash_table_iter_init (&iter, removed_from); + while (g_hash_table_iter_next (&iter, &k, NULL)) { - const gchar *group_name = tp_handle_inspect (group_repo, - group); + const gchar *group_name = k; - DEBUG ("Contact #%u removed from group #%u '%s'", contact_handle, - group, group_name); + DEBUG ("Contact #%u removed from group '%s'", contact_handle, + group_name); g_ptr_array_add (removed_names, (gchar *) group_name); } @@ -655,22 +721,21 @@ _gabble_roster_item_update (GabbleRoster *roster, (const gchar * const *) removed_names->pdata, removed_names->len); } - tp_intset_destroy (added_to); - tp_intset_destroy (removed_from); - tp_intset_destroy (removed_from2); - new_groups = NULL; - tp_handle_set_destroy (new_groups_handle_set); - tp_handle_set_destroy (old_groups); + g_hash_table_unref (added_to); + g_hash_table_unref (removed_from); + g_hash_table_unref (new_groups); return item; } - -#ifdef ENABLE_DEBUG static void -_gabble_roster_item_dump_group (guint handle, gpointer user_data) +_gabble_roster_item_dump_group (gpointer k, + gpointer v, + gpointer user_data) { - g_string_append_printf ((GString *) user_data, "group#%u ", handle); + const gchar *group = k; + + g_string_append_printf ((GString *) user_data, "group '%s'", group); } static gchar * @@ -696,14 +761,11 @@ _gabble_roster_item_dump (GabbleRosterItem *item) if (item->groups) { - tp_intset_foreach (tp_handle_set_peek (item->groups), - _gabble_roster_item_dump_group, str); + g_hash_table_foreach (item->groups, _gabble_roster_item_dump_group, str); } return g_string_free (str, FALSE); } -#endif /* ENABLE_DEBUG */ - static WockyStanza * _gabble_roster_message_new (GabbleRoster *roster, @@ -743,21 +805,15 @@ _gabble_roster_message_new (GabbleRoster *roster, } -struct _ItemToMessageContext { - TpBaseConnection *conn; - WockyNode *item_node; -}; - static void -_gabble_roster_item_put_group_in_message (guint handle, gpointer user_data) +_gabble_roster_item_put_group_in_message (gpointer k, + gpointer v, + gpointer user_data) { - struct _ItemToMessageContext *ctx = - (struct _ItemToMessageContext *)user_data; - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - ctx->conn, TP_HANDLE_TYPE_GROUP); - const char *name = tp_handle_inspect (group_repo, handle); + const char *name = k; + WockyNode *item_node = user_data; - wocky_node_add_child_with_content (ctx->item_node, "group", name); + wocky_node_add_child_with_content (item_node, "group", name); } /* @@ -780,9 +836,6 @@ _gabble_roster_item_to_message (GabbleRoster *roster, WockyStanza *message; WockyNode *query_node, *item_node; const gchar *jid; - struct _ItemToMessageContext ctx = { - (TpBaseConnection *) priv->conn, - }; g_assert (roster != NULL); g_assert (GABBLE_IS_ROSTER (roster)); @@ -793,7 +846,6 @@ _gabble_roster_item_to_message (GabbleRoster *roster, &query_node); item_node = wocky_node_add_child (query_node, "item"); - ctx.item_node = item_node; jid = tp_handle_inspect (contact_repo, handle); wocky_node_set_attribute (item_node, "jid", jid); @@ -825,9 +877,8 @@ _gabble_roster_item_to_message (GabbleRoster *roster, if (item->groups) { - tp_intset_foreach (tp_handle_set_peek (item->groups), - _gabble_roster_item_put_group_in_message, - (void *)&ctx); + g_hash_table_foreach (item->groups, + _gabble_roster_item_put_group_in_message, item_node); } DONE: @@ -1100,14 +1151,13 @@ process_roster ( item = _gabble_roster_item_update (roster, handle, item_node, google_roster, &nickname_updated); -#ifdef ENABLE_DEBUG + if (DEBUGGING) { gchar *dump = _gabble_roster_item_dump (item); DEBUG ("jid: %s, %s", jid, dump); g_free (dump); } -#endif if (nickname_updated) g_array_append_val (updated_nicknames, handle); @@ -1685,7 +1735,7 @@ gabble_roster_close_all (GabbleRoster *self) self->priv->porter_available_id = 0; } - tp_clear_pointer (&priv->groups, tp_handle_set_destroy); + tp_clear_pointer (&priv->groups, g_hash_table_unref); tp_clear_pointer (&priv->pre_authorized, tp_handle_set_destroy); if (self->priv->cancel_on_disconnect != NULL) @@ -1814,7 +1864,6 @@ gabble_roster_constructed (GObject *obj) TpBaseContactList *base = TP_BASE_CONTACT_LIST (obj); void (*chain_up)(GObject *) = ((GObjectClass *) gabble_roster_parent_class)->constructed; - TpHandleRepoIface *group_repo; TpHandleRepoIface *contact_repo; if (chain_up != NULL) @@ -1830,8 +1879,6 @@ gabble_roster_constructed (GObject *obj) base, NULL)); g_assert (GABBLE_IS_CONNECTION (self->priv->conn)); - group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); @@ -1840,7 +1887,8 @@ gabble_roster_constructed (GObject *obj) self->priv->porter_available_id = g_signal_connect (self->priv->conn, "porter-available", G_CALLBACK (gabble_roster_porter_available_cb), obj); - self->priv->groups = tp_handle_set_new (group_repo); + self->priv->groups = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); self->priv->pre_authorized = tp_handle_set_new (contact_repo); } @@ -1886,8 +1934,8 @@ item_edit_free (GabbleRosterItemEdit *edits) g_slist_free (edits->results); 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); + tp_clear_pointer (&edits->add_to_groups, g_hash_table_unref); + tp_clear_pointer (&edits->remove_from_groups, g_hash_table_unref); g_free (edits->new_name); g_slice_free (GabbleRosterItemEdit, edits); } @@ -1947,10 +1995,7 @@ roster_item_apply_edits (GabbleRoster *roster, { gboolean altered = FALSE; GabbleRosterItem edited_item; - TpIntset *intset; GabbleRosterPrivate *priv = roster->priv; - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_GROUP); GabbleRosterItemEdit *edits = item->unsent_edits; WockyStanza *message; @@ -1977,14 +2022,12 @@ roster_item_apply_edits (GabbleRoster *roster, memcpy (&edited_item, item, sizeof (GabbleRosterItem)); -#ifdef ENABLE_DEBUG if (DEBUGGING) { gchar *dump = _gabble_roster_item_dump (&edited_item); DEBUG ("Before, contact#%u: %s", contact, dump); g_free (dump); } -#endif if (edits->create) { @@ -2060,14 +2103,13 @@ roster_item_apply_edits (GabbleRoster *roster, if (edits->add_to_groups != NULL || edits->remove_from_groups != NULL || edits->remove_from_all_other_groups) { -#ifdef ENABLE_DEBUG if (DEBUGGING) { if (edits->add_to_groups != NULL) { GString *str = g_string_new ("Adding to groups: "); - tp_intset_foreach (tp_handle_set_peek (edits->add_to_groups), - _gabble_roster_item_dump_group, str); + g_hash_table_foreach (edits->add_to_groups, + _gabble_roster_item_dump_group, str); DEBUG("%s", g_string_free (str, FALSE)); } else @@ -2083,8 +2125,8 @@ roster_item_apply_edits (GabbleRoster *roster, if (edits->remove_from_groups != NULL) { GString *str = g_string_new ("Removing from groups: "); - tp_intset_foreach (tp_handle_set_peek (edits->remove_from_groups), - _gabble_roster_item_dump_group, str); + g_hash_table_foreach (edits->remove_from_groups, + _gabble_roster_item_dump_group, str); DEBUG("%s", g_string_free (str, FALSE)); } else @@ -2092,32 +2134,34 @@ roster_item_apply_edits (GabbleRoster *roster, DEBUG ("Not removing from any groups"); } } -#endif - edited_item.groups = tp_handle_set_new (group_repo); + + edited_item.groups = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); if (!edits->remove_from_all_other_groups) { - intset = tp_handle_set_update (edited_item.groups, - tp_handle_set_peek (item->groups)); - tp_intset_destroy (intset); + GHashTable *added; + + added = group_set_update (edited_item.groups, item->groups); + g_hash_table_unref (added); } if (edits->add_to_groups) { - intset = tp_handle_set_update (edited_item.groups, - tp_handle_set_peek (edits->add_to_groups)); - tp_intset_destroy (intset); + GHashTable *added; + + added = group_set_update (edited_item.groups, + edits->add_to_groups); + g_hash_table_unref (added); } if (edits->remove_from_groups) { - intset = tp_handle_set_difference_update (edited_item.groups, - tp_handle_set_peek (edits->remove_from_groups)); - tp_intset_destroy (intset); + group_set_difference_update (edited_item.groups, + edits->remove_from_groups); } - if (!tp_intset_is_equal (tp_handle_set_peek (edited_item.groups), - tp_handle_set_peek (item->groups))) + if (!group_set_is_equal (edited_item.groups, item->groups)) altered = TRUE; } @@ -2132,14 +2176,12 @@ roster_item_apply_edits (GabbleRoster *roster, edited_item.subscription = GABBLE_ROSTER_SUBSCRIPTION_NONE; } -#ifdef ENABLE_DEBUG if (DEBUGGING) { gchar *dump = _gabble_roster_item_dump (&edited_item); DEBUG ("After, contact#%u: %s", contact, dump); g_free (dump); } -#endif if (!altered) { @@ -2168,7 +2210,7 @@ roster_item_apply_edits (GabbleRoster *roster, if (edited_item.groups != item->groups) { - tp_handle_set_destroy (edited_item.groups); + g_hash_table_unref (edited_item.groups); } } @@ -2453,42 +2495,40 @@ gabble_roster_handle_add (GabbleRoster *roster, static void gabble_roster_handle_add_to_group (GabbleRoster *roster, - TpHandle handle, - TpHandle group, - GSimpleAsyncResult *result) + TpHandle handle, + const gchar *group, + GSimpleAsyncResult *result) { GabbleRosterPrivate *priv = roster->priv; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_GROUP); GabbleRosterItem *item; g_return_if_fail (roster != NULL); g_return_if_fail (GABBLE_IS_ROSTER (roster)); g_return_if_fail (tp_handle_is_valid (contact_repo, handle, NULL)); - g_return_if_fail (tp_handle_is_valid (group_repo, group, NULL)); item = _gabble_roster_item_ensure (roster, handle); if (item->unsent_edits == NULL) item->unsent_edits = item_edit_new (contact_repo, handle); - DEBUG ("queue edit to contact#%u - add to group#%u", handle, group); + DEBUG ("queue edit to contact#%u - add to group '%s'", handle, group); gabble_simple_async_countdown_inc (result); item->unsent_edits->results = g_slist_prepend ( item->unsent_edits->results, g_object_ref (result)); if (!item->unsent_edits->add_to_groups) { - item->unsent_edits->add_to_groups = tp_handle_set_new (group_repo); + item->unsent_edits->add_to_groups = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, NULL); } - tp_handle_set_add (item->unsent_edits->add_to_groups, group); + g_hash_table_add (item->unsent_edits->add_to_groups, g_strdup (group)); if (item->unsent_edits->remove_from_groups) { - tp_handle_set_remove (item->unsent_edits->remove_from_groups, group); + g_hash_table_remove (item->unsent_edits->remove_from_groups, group); } /* maybe we can apply the edit immediately? */ @@ -2497,28 +2537,25 @@ gabble_roster_handle_add_to_group (GabbleRoster *roster, static void gabble_roster_handle_remove_from_group (GabbleRoster *roster, - TpHandle handle, - TpHandle group, - GSimpleAsyncResult *result) + TpHandle handle, + const gchar *group, + GSimpleAsyncResult *result) { GabbleRosterPrivate *priv = roster->priv; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_GROUP); GabbleRosterItem *item; g_return_if_fail (roster != NULL); g_return_if_fail (GABBLE_IS_ROSTER (roster)); g_return_if_fail (tp_handle_is_valid (contact_repo, handle, NULL)); - g_return_if_fail (tp_handle_is_valid (group_repo, group, NULL)); item = _gabble_roster_item_ensure (roster, handle); if (item->unsent_edits == NULL) item->unsent_edits = item_edit_new (contact_repo, handle); - DEBUG ("queue edit to contact#%u - remove from group#%u", handle, group); + DEBUG ("queue edit to contact#%u - remove from group '%s'", handle, group); gabble_simple_async_countdown_inc (result); item->unsent_edits->results = g_slist_prepend ( @@ -2526,15 +2563,15 @@ gabble_roster_handle_remove_from_group (GabbleRoster *roster, if (!item->unsent_edits->remove_from_groups) { - item->unsent_edits->remove_from_groups = tp_handle_set_new ( - group_repo); + item->unsent_edits->remove_from_groups = g_hash_table_new_full ( + g_str_hash, g_str_equal, g_free, NULL); } - tp_handle_set_add (item->unsent_edits->remove_from_groups, group); + g_hash_table_add (item->unsent_edits->remove_from_groups, g_strdup (group)); if (item->unsent_edits->add_to_groups) { - tp_handle_set_remove (item->unsent_edits->add_to_groups, group); + g_hash_table_remove (item->unsent_edits->add_to_groups, group); } /* maybe we can apply the edit immediately? */ @@ -3058,25 +3095,23 @@ static GStrv gabble_roster_dup_groups (TpBaseContactList *base) { GabbleRoster *self = GABBLE_ROSTER (base); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); GPtrArray *ret; if (self->priv->groups != NULL) { - TpIntsetFastIter iter; - TpHandle group; + GHashTableIter iter; + gpointer k; ret = g_ptr_array_sized_new ( - tp_handle_set_size (self->priv->groups) + 1); + g_hash_table_size (self->priv->groups) + 1); - tp_intset_fast_iter_init (&iter, - tp_handle_set_peek (self->priv->groups)); + g_hash_table_iter_init (&iter, self->priv->groups); - while (tp_intset_fast_iter_next (&iter, &group)) + while (g_hash_table_iter_next (&iter, &k, NULL)) { - g_ptr_array_add (ret, g_strdup (tp_handle_inspect (group_repo, - group))); + const gchar *group = k; + + g_ptr_array_add (ret, g_strdup (group)); } } else @@ -3098,19 +3133,15 @@ gabble_roster_dup_contact_groups (TpBaseContactList *base, if (item != NULL && item->groups != NULL) { - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpIntsetFastIter iter; - TpHandle group; - - ret = g_ptr_array_sized_new (tp_handle_set_size (item->groups) + 1); + GHashTableIter iter; + gpointer k; - tp_intset_fast_iter_init (&iter, tp_handle_set_peek (item->groups)); + ret = g_ptr_array_sized_new (g_hash_table_size (item->groups) + 1); - while (tp_intset_fast_iter_next (&iter, &group)) + g_hash_table_iter_init (&iter, item->groups); + while (g_hash_table_iter_next (&iter, &k, NULL)) { - g_ptr_array_add (ret, - g_strdup (tp_handle_inspect (group_repo, group))); + g_ptr_array_add (ret, g_strdup (k)); } } else @@ -3130,9 +3161,6 @@ gabble_roster_dup_group_members (TpBaseContactList *base, TpHandleSet *set; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpHandle group_handle; GHashTableIter iter; gpointer k, v; @@ -3140,20 +3168,12 @@ gabble_roster_dup_group_members (TpBaseContactList *base, g_hash_table_iter_init (&iter, self->priv->items); - group_handle = tp_handle_lookup (group_repo, group, NULL, NULL); - - if (G_UNLIKELY (group_handle == 0)) - { - /* clearly it doesn't have members */ - return set; - } - while (g_hash_table_iter_next (&iter, &k, &v)) { GabbleRosterItem *item = v; if (item->groups != NULL && - tp_handle_set_is_member (item->groups, group_handle)) + g_hash_table_lookup (item->groups, group) != NULL) tp_handle_set_add (set, GPOINTER_TO_UINT (k)); } @@ -3172,9 +3192,8 @@ gabble_roster_set_contact_groups_async (TpBaseContactList *base, GabbleRosterItem *item = _gabble_roster_item_ensure (self, contact); TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpHandleSet *groups_set = tp_handle_set_new (group_repo); + GHashTable *groups_set = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); GPtrArray *groups_created = g_ptr_array_new (); guint i; GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, @@ -3182,17 +3201,11 @@ gabble_roster_set_contact_groups_async (TpBaseContactList *base, for (i = 0; i < n; i++) { - TpHandle group_handle = tp_handle_ensure (group_repo, groups[i], NULL, - NULL); + g_hash_table_add (groups_set, g_strdup (groups[i])); - if (G_UNLIKELY (group_handle == 0)) - continue; - - tp_handle_set_add (groups_set, group_handle); - - if (!tp_handle_set_is_member (self->priv->groups, group_handle)) + if (g_hash_table_lookup (self->priv->groups, groups[i]) == NULL) { - tp_handle_set_add (self->priv->groups, group_handle); + g_hash_table_add (self->priv->groups, g_strdup (groups[i])); g_ptr_array_add (groups_created, (gchar *) groups[i]); } @@ -3212,13 +3225,13 @@ gabble_roster_set_contact_groups_async (TpBaseContactList *base, DEBUG ("queue edit to contact#%u - set %" G_GSIZE_FORMAT "contact groups", contact, n); - tp_clear_pointer (&item->unsent_edits->add_to_groups, tp_handle_set_destroy); + tp_clear_pointer (&item->unsent_edits->add_to_groups, g_hash_table_unref); item->unsent_edits->add_to_groups = groups_set; item->unsent_edits->remove_from_all_other_groups = TRUE; tp_clear_pointer (&item->unsent_edits->remove_from_groups, - tp_handle_set_destroy); + g_hash_table_unref); gabble_simple_async_countdown_inc (result); item->unsent_edits->results = g_slist_prepend ( @@ -3238,28 +3251,16 @@ gabble_roster_set_group_members_async (TpBaseContactList *base, gpointer user_data) { GabbleRoster *self = GABBLE_ROSTER (base); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpHandle group_handle = tp_handle_ensure (group_repo, group, NULL, - NULL); GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_set_group_members_async, 1); GHashTableIter iter; gpointer k; - /* You can't add people to an invalid group. */ - if (G_UNLIKELY (group_handle == 0)) - { - g_simple_async_result_set_error (result, TP_ERROR, - TP_ERROR_INVALID_ARGUMENT, "Invalid group name: %s", group); - goto finally; - } - /* we create the group even if @contacts is empty, as the base class * requires */ - if (!tp_handle_set_is_member (self->priv->groups, group_handle)) + if (g_hash_table_lookup (self->priv->groups, group) == NULL) { - tp_handle_set_add (self->priv->groups, group_handle); + g_hash_table_add (self->priv->groups, g_strdup (group)); tp_base_contact_list_groups_created (base, &group, 1); } @@ -3270,14 +3271,11 @@ gabble_roster_set_group_members_async (TpBaseContactList *base, TpHandle contact = GPOINTER_TO_UINT (k); if (tp_handle_set_is_member (contacts, contact)) - gabble_roster_handle_add_to_group (self, contact, group_handle, - result); + gabble_roster_handle_add_to_group (self, contact, group, result); else - gabble_roster_handle_remove_from_group (self, contact, group_handle, - result); + gabble_roster_handle_remove_from_group (self, contact, group, result); } -finally: gabble_simple_async_countdown_dec (result); g_object_unref (result); } @@ -3292,26 +3290,14 @@ gabble_roster_add_to_group_async (TpBaseContactList *base, GabbleRoster *self = GABBLE_ROSTER (base); TpIntsetFastIter iter; TpHandle contact; - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpHandle group_handle = tp_handle_ensure (group_repo, group, NULL, - NULL); GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_add_to_group_async, 1); - /* You can't add people to an invalid group. */ - if (G_UNLIKELY (group_handle == 0)) - { - g_simple_async_result_set_error (result, TP_ERROR, - TP_ERROR_INVALID_ARGUMENT, "Invalid group name: %s", group); - goto finally; - } - /* we create the group even if @contacts is empty, as the base class * requires */ - if (!tp_handle_set_is_member (self->priv->groups, group_handle)) + if (g_hash_table_lookup (self->priv->groups, group) == NULL) { - tp_handle_set_add (self->priv->groups, group_handle); + g_hash_table_add (self->priv->groups, g_strdup (group)); tp_base_contact_list_groups_created (base, &group, 1); } @@ -3320,10 +3306,9 @@ gabble_roster_add_to_group_async (TpBaseContactList *base, while (tp_intset_fast_iter_next (&iter, &contact)) { /* we ignore any NetworkError */ - gabble_roster_handle_add_to_group (self, contact, group_handle, result); + gabble_roster_handle_add_to_group (self, contact, group, result); } -finally: gabble_simple_async_countdown_dec (result); g_object_unref (result); } @@ -3338,31 +3323,22 @@ gabble_roster_remove_from_group_async (TpBaseContactList *base, GabbleRoster *self = GABBLE_ROSTER (base); TpIntsetFastIter iter; TpHandle contact; - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - TpHandle group_handle = tp_handle_lookup (group_repo, group, NULL, NULL); GSimpleAsyncResult *result = gabble_simple_async_countdown_new (self, callback, user_data, gabble_roster_remove_from_group_async, 1); - /* if the group didn't exist then we have nothing to do */ - if (group_handle == 0) - goto finally; - tp_intset_fast_iter_init (&iter, tp_handle_set_peek (contacts)); while (tp_intset_fast_iter_next (&iter, &contact)) { - gabble_roster_handle_remove_from_group (self, contact, group_handle, - result); + gabble_roster_handle_remove_from_group (self, contact, group, result); } -finally: gabble_simple_async_countdown_dec (result); g_object_unref (result); } typedef struct { - TpHandle group_handle; + gchar *group; GAsyncReadyCallback callback; gpointer user_data; TpHandleSet *contacts; @@ -3376,12 +3352,8 @@ gabble_roster_remove_group_removed_cb (GObject *source, GabbleRoster *self = GABBLE_ROSTER (source); RemoveGroupContext *context = user_data; - if (context->group_handle != 0) + if (context->group != NULL) { - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); - const gchar *group = tp_handle_inspect (group_repo, - context->group_handle); GHashTableIter iter; gpointer k, v; TpHandle remaining_member = 0; @@ -3406,8 +3378,8 @@ gabble_roster_remove_group_removed_cb (GObject *source, TpHandle contact = GPOINTER_TO_UINT (k); GabbleRosterItem *item = v; - if (item->groups != NULL && tp_handle_set_is_member (item->groups, - context->group_handle)) + if (item->groups != NULL && g_hash_table_lookup (item->groups, + context->group) != NULL) { if (!tp_handle_set_is_member (context->contacts, contact)) remaining_member = contact; @@ -3416,9 +3388,10 @@ gabble_roster_remove_group_removed_cb (GObject *source, if (remaining_member == 0) { - tp_handle_set_remove (self->priv->groups, context->group_handle); + g_hash_table_remove (self->priv->groups, context->group); + tp_base_contact_list_groups_removed ((TpBaseContactList *) self, - &group, 1); + (const gchar * const *) &context->group, 1); g_hash_table_iter_init (&iter, self->priv->items); @@ -3427,20 +3400,21 @@ gabble_roster_remove_group_removed_cb (GObject *source, GabbleRosterItem *item = v; if (item->groups != NULL && - tp_handle_set_is_member (item->groups, - context->group_handle)) - tp_handle_set_remove (item->groups, context->group_handle); + g_hash_table_lookup (item->groups, + context->group) != NULL) + g_hash_table_remove (item->groups, context->group); } } else { DEBUG ("contact #%u is still a member of group '%s', not removing", - remaining_member, group); + remaining_member, context->group); } } context->callback (source, result, context->user_data); tp_clear_pointer (&context->contacts, tp_handle_set_destroy); + g_free (context->group); g_slice_free (RemoveGroupContext, context); } @@ -3455,13 +3429,11 @@ gabble_roster_remove_group_async (TpBaseContactList *base, gpointer k, v; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_CONTACT); - TpHandleRepoIface *group_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) self->priv->conn, TP_HANDLE_TYPE_GROUP); GSimpleAsyncResult *result; RemoveGroupContext *context; context = g_slice_new0 (RemoveGroupContext); - context->group_handle = tp_handle_lookup (group_repo, group, NULL, NULL); + context->group = g_strdup (group); context->callback = callback; context->user_data = user_data; context->contacts = tp_handle_set_new (contact_repo); @@ -3471,8 +3443,8 @@ gabble_roster_remove_group_async (TpBaseContactList *base, context, gabble_roster_remove_group_async, 1); /* if the group didn't exist then we have nothing to do */ - if (context->group_handle == 0 || - !tp_handle_set_is_member (self->priv->groups, context->group_handle)) + if (context->group == NULL || + g_hash_table_lookup (self->priv->groups, context->group) == NULL) goto finally; g_hash_table_iter_init (&iter, self->priv->items); @@ -3482,12 +3454,12 @@ gabble_roster_remove_group_async (TpBaseContactList *base, TpHandle contact = GPOINTER_TO_UINT (k); GabbleRosterItem *item = v; - if (item->groups != NULL && tp_handle_set_is_member (item->groups, - context->group_handle)) + if (item->groups != NULL && g_hash_table_lookup (item->groups, + context->group) != NULL) { tp_handle_set_add (context->contacts, contact); - gabble_roster_handle_remove_from_group (self, contact, - context->group_handle, result); + gabble_roster_handle_remove_from_group (self, contact, context->group, + result); } } diff --git a/src/search-channel.c b/src/search-channel.c index 0c253ba92..ab8a7d12d 100644 --- a/src/search-channel.c +++ b/src/search-channel.c @@ -519,26 +519,13 @@ static GValueArray * make_field (const gchar *field_name, gchar **values) { - GValueArray *field = g_value_array_new (3); - GValue *value; static const gchar **empty = { NULL }; - g_value_array_append (field, NULL); - value = g_value_array_get_nth (field, 0); - g_value_init (value, G_TYPE_STRING); - g_value_set_static_string (value, field_name); - - g_value_array_append (field, NULL); - value = g_value_array_get_nth (field, 1); - g_value_init (value, G_TYPE_STRV); - g_value_set_static_boxed (value, empty); - - g_value_array_append (field, NULL); - value = g_value_array_get_nth (field, 2); - g_value_init (value, G_TYPE_STRV); - g_value_set_boxed (value, values); - - return field; + return tp_value_array_build (3, + G_TYPE_STRING, field_name, + G_TYPE_STRV, empty, + G_TYPE_STRV, values, + G_TYPE_INVALID); } static gchar * diff --git a/src/server-sasl-channel.c b/src/server-sasl-channel.c index 3eb4f66f2..9ff85054a 100644 --- a/src/server-sasl-channel.c +++ b/src/server-sasl-channel.c @@ -382,7 +382,7 @@ gabble_server_sasl_channel_class_init (GabbleServerSaslChannelClass *klass) param_spec = g_param_spec_uint ("sasl-status", "SASLStatus", "Status of this channel", - 0, NUM_TP_SASL_STATUSES, 0, + 0, TP_NUM_SASL_STATUSES, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SASL_STATUS, param_spec); diff --git a/src/server-tls-manager.c b/src/server-tls-manager.c index 4e961cdde..6a23c998a 100644 --- a/src/server-tls-manager.c +++ b/src/server-tls-manager.c @@ -556,7 +556,9 @@ gabble_server_tls_manager_get_rejection_details (GabbleServerTLSManager *self, GabbleTLSCertificate *certificate; GPtrArray *rejections; GValueArray *rejection; - TpTLSCertificateRejectReason tls_reason; + guint tls_reason; + const gchar *dbus_error_tmp; + GHashTable *details_tmp; /* We probably want the rejection details of last completed operation */ g_return_if_fail (self->priv->completed_channels != NULL); @@ -574,9 +576,13 @@ gabble_server_tls_manager_get_rejection_details (GabbleServerTLSManager *self, rejection = g_ptr_array_index (rejections, 0); - tls_reason = g_value_get_uint (g_value_array_get_nth (rejection, 0)); - *dbus_error = g_value_dup_string (g_value_array_get_nth (rejection, 1)); - *details = g_value_dup_boxed (g_value_array_get_nth (rejection, 2)); + tp_value_array_unpack (rejection, 3, + &tls_reason, + &dbus_error_tmp, + &details_tmp); + + *dbus_error = g_strdup (dbus_error_tmp); + *details = g_boxed_copy (TP_HASH_TYPE_STRING_VARIANT_MAP, details_tmp); *reason = cert_reject_reason_to_conn_reason (tls_reason); diff --git a/src/tls-certificate.c b/src/tls-certificate.c index 303b70644..c00bac7a8 100644 --- a/src/tls-certificate.c +++ b/src/tls-certificate.c @@ -216,7 +216,7 @@ gabble_tls_certificate_class_init (GabbleTLSCertificateClass *klass) pspec = g_param_spec_uint ("state", "State of this certificate", "The state of this TLS certificate.", - 0, NUM_TP_TLS_CERTIFICATE_STATES - 1, + 0, TP_NUM_TLS_CERTIFICATE_STATES - 1, TP_TLS_CERTIFICATE_STATE_PENDING, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (oclass, PROP_STATE, pspec); diff --git a/src/tube-dbus.c b/src/tube-dbus.c index d982e7902..3b6197ebc 100644 --- a/src/tube-dbus.c +++ b/src/tube-dbus.c @@ -611,7 +611,7 @@ gabble_tube_dbus_get_property (GObject *object, g_value_set_string (value, priv->stream_id); break; case PROP_TYPE: - g_value_set_uint (value, TP_TUBE_TYPE_DBUS); + g_value_set_uint (value, TUBE_TYPE_DBUS); break; case PROP_SERVICE: g_value_set_string (value, priv->service); diff --git a/src/tube-iface.c b/src/tube-iface.c index 7faf514ea..aef131e09 100644 --- a/src/tube-iface.c +++ b/src/tube-iface.c @@ -84,7 +84,7 @@ gabble_tube_iface_base_init (gpointer klass) param_spec = g_param_spec_uint ( "type", "Tube type", - "The TpTubeType this tube object.", + "The TubeType this tube object.", 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_interface_install_property (klass, param_spec); @@ -150,7 +150,7 @@ gabble_tube_iface_publish_in_node (GabbleTubeIface *tube, { WockyNode *parameters_node; GHashTable *parameters; - TpTubeType type; + TubeType type; gchar *service, *id_str; guint64 tube_id; TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( @@ -176,7 +176,7 @@ gabble_tube_iface_publish_in_node (GabbleTubeIface *tube, switch (type) { - case TP_TUBE_TYPE_DBUS: + case TUBE_TYPE_DBUS: { gchar *name, *stream_id; @@ -198,7 +198,7 @@ gabble_tube_iface_publish_in_node (GabbleTubeIface *tube, g_free (stream_id); } break; - case TP_TUBE_TYPE_STREAM: + case TUBE_TYPE_STREAM: { wocky_node_set_attribute (node, "type", "stream"); } diff --git a/src/tube-iface.h b/src/tube-iface.h index b727f391d..6cfa8ca55 100644 --- a/src/tube-iface.h +++ b/src/tube-iface.h @@ -27,6 +27,12 @@ G_BEGIN_DECLS +typedef enum +{ + TUBE_TYPE_DBUS = 0, + TUBE_TYPE_STREAM +} TubeType; + typedef struct _GabbleTubeIface GabbleTubeIface; typedef struct _GabbleTubeIfaceClass GabbleTubeIfaceClass; diff --git a/src/tube-stream.c b/src/tube-stream.c index e1d2289de..c62381366 100644 --- a/src/tube-stream.c +++ b/src/tube-stream.c @@ -1234,7 +1234,7 @@ gabble_tube_stream_get_property (GObject *object, g_value_set_uint64 (value, priv->id); break; case PROP_TYPE: - g_value_set_uint (value, TP_TUBE_TYPE_STREAM); + g_value_set_uint (value, TUBE_TYPE_STREAM); break; case PROP_SERVICE: g_value_set_string (value, priv->service); @@ -1483,7 +1483,7 @@ gabble_tube_stream_class_init (GabbleTubeStreamClass *gabble_tube_stream_class) "address type", "a TpSocketAddressType representing the type of the listening" "address of the local service", - 0, NUM_TP_SOCKET_ADDRESS_TYPES - 1, + 0, TP_NUM_SOCKET_ADDRESS_TYPES - 1, TP_SOCKET_ADDRESS_TYPE_UNIX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ADDRESS_TYPE, @@ -1502,7 +1502,7 @@ gabble_tube_stream_class_init (GabbleTubeStreamClass *gabble_tube_stream_class) "access control", "a TpSocketAccessControl representing the access control " "the local service applies to the local socket", - 0, NUM_TP_SOCKET_ACCESS_CONTROLS - 1, + 0, TP_NUM_SOCKET_ACCESS_CONTROLS - 1, TP_SOCKET_ACCESS_CONTROL_LOCALHOST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_ACCESS_CONTROL, diff --git a/src/vcard-manager.c b/src/vcard-manager.c index 74e933e9c..9f40b7523 100644 --- a/src/vcard-manager.c +++ b/src/vcard-manager.c @@ -46,8 +46,6 @@ static guint default_request_timeout = 180; * the same recipient */ static guint request_wait_delay = 5 * 60; -static const gchar *NO_ALIAS = "none"; - struct _GabbleVCardManagerEditInfo { /* name of element to edit */ gchar *element_name; @@ -100,7 +98,13 @@ struct _GabbleVCardManagerPrivate gboolean dispose_has_run; GabbleConnection *connection; - /* TpHandle borrowed from the entry => owned (GabbleVCardCacheEntry *) */ + /* TpHandle => owned string, or NULL for negative cache + * Note that NULL as an item is considered to be distinct from + * a missing item. We keep aliases indefinitely, whereas + * the rest of the vCard is cached for a finite time. */ + GHashTable *alias_cache; + + /* TpHandle => owned (GabbleVCardCacheEntry *) */ GHashTable *cache; /* Those (GabbleVCardCacheEntry *) s that have not expired, ordered by @@ -199,15 +203,6 @@ gabble_vcard_manager_error_quark (void) return quark; } -GQuark -gabble_vcard_manager_cache_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("gabble-vcard-manager-cache"); - return quark; -} - static void cache_entry_free (void *data); static gint cache_entry_compare (gconstpointer a, gconstpointer b); static void manager_patch_vcard ( @@ -223,6 +218,7 @@ gabble_vcard_manager_init (GabbleVCardManager *obj) GabbleVCardManagerPrivate); obj->priv = priv; + priv->alias_cache = g_hash_table_new_full (NULL, NULL, NULL, g_free); priv->cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, cache_entry_free); /* no destructor here - the hash table is responsible for freeing it */ @@ -576,7 +572,12 @@ gabble_vcard_manager_dispose (GObject *object) static void gabble_vcard_manager_finalize (GObject *object) { + GabbleVCardManager *self = GABBLE_VCARD_MANAGER (object); + DEBUG ("%p", object); + + tp_clear_pointer (&self->priv->alias_cache, g_hash_table_unref); + G_OBJECT_CLASS (gabble_vcard_manager_parent_class)->finalize (object); } @@ -804,8 +805,6 @@ observe_vcard (GabbleConnection *conn, TpHandle handle, WockyNode *vcard_node) { - TpHandleRepoIface *contact_repo = tp_base_connection_get_handles ( - (TpBaseConnection *) conn, TP_HANDLE_TYPE_CONTACT); const gchar *field = "<NICKNAME>"; gchar *alias; const gchar *old_alias; @@ -846,15 +845,16 @@ observe_vcard (GabbleConnection *conn, handle, field); /* takes ownership of alias */ - tp_handle_set_qdata (contact_repo, handle, - gabble_vcard_manager_cache_quark (), alias, g_free); + g_hash_table_insert (manager->priv->alias_cache, + GUINT_TO_POINTER (handle), alias); } else { DEBUG ("got no vCard alias for handle %u", handle); - tp_handle_set_qdata (contact_repo, handle, - gabble_vcard_manager_cache_quark (), (gchar *) NO_ALIAS, NULL); + /* cache negatively */ + g_hash_table_insert (manager->priv->alias_cache, + GUINT_TO_POINTER (handle), NULL); } if ((old_alias != NULL) || (alias != NULL)) @@ -1649,7 +1649,6 @@ gabble_vcard_manager_get_cached_alias (GabbleVCardManager *self, { GabbleVCardManagerPrivate *priv; TpHandleRepoIface *contact_repo; - const gchar *s; g_return_val_if_fail (GABBLE_IS_VCARD_MANAGER (self), NULL); @@ -1659,13 +1658,8 @@ gabble_vcard_manager_get_cached_alias (GabbleVCardManager *self, g_return_val_if_fail (tp_handle_is_valid (contact_repo, handle, NULL), NULL); - s = tp_handle_get_qdata (contact_repo, handle, - gabble_vcard_manager_cache_quark ()); - - if (s == NO_ALIAS) - s = NULL; - - return s; + /* Return NULL for uncached or negatively cached contacts. */ + return g_hash_table_lookup (priv->alias_cache, GUINT_TO_POINTER (handle)); } /** @@ -1677,7 +1671,6 @@ gabble_vcard_manager_has_cached_alias (GabbleVCardManager *self, { GabbleVCardManagerPrivate *priv; TpHandleRepoIface *contact_repo; - gpointer p; g_return_val_if_fail (GABBLE_IS_VCARD_MANAGER (self), FALSE); @@ -1688,10 +1681,8 @@ gabble_vcard_manager_has_cached_alias (GabbleVCardManager *self, g_return_val_if_fail (tp_handle_is_valid (contact_repo, handle, NULL), FALSE); - p = tp_handle_get_qdata (contact_repo, handle, - gabble_vcard_manager_cache_quark ()); - - return p != NULL; + /* Return TRUE for positively or negatively cached contacts. */ + return g_hash_table_contains (priv->alias_cache, GUINT_TO_POINTER (handle)); } /* For unit tests only */ diff --git a/src/write-mgr-file.c b/src/write-mgr-file.c index b097316ba..90da9fd2a 100644 --- a/src/write-mgr-file.c +++ b/src/write-mgr-file.c @@ -26,6 +26,7 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-protocol.h> #include <telepathy-glib/telepathy-glib.h> +#include <telepathy-glib/telepathy-glib-dbus.h> #include "extensions/extensions.h" #include "protocol.h" @@ -214,14 +215,6 @@ generate_group_name (GHashTable *props) handle_type_name = "-multi"; break; - case TP_HANDLE_TYPE_GROUP: - handle_type_name = "-group"; - break; - - case TP_HANDLE_TYPE_LIST: - handle_type_name = "-list"; - break; - default: handle_type_name = ""; } @@ -277,6 +270,45 @@ write_rccs (GKeyFile *f, const gchar *section_name, GHashTable *props) g_strfreev (group_names); } +static void +write_presence (GKeyFile *f, + const gchar *section_name, + GHashTable *props) +{ + GHashTable *statuses; + GHashTableIter iter; + gpointer k, v; + + statuses = tp_asv_get_boxed (props, + TP_PROP_PROTOCOL_INTERFACE_PRESENCE_STATUSES, + TP_HASH_TYPE_SIMPLE_STATUS_SPEC_MAP); + g_return_if_fail (statuses != NULL); + + g_hash_table_iter_init (&iter, statuses); + while (g_hash_table_iter_next (&iter, &k, &v)) + { + const gchar *id = k; + GValueArray *status = v; + TpConnectionPresenceType type; + gboolean may_set_on_self, can_have_msg; + gchar *key, *value; + + key = g_strdup_printf ("status-%s", id); + + tp_value_array_unpack (status, 3, &type, &may_set_on_self, &can_have_msg); + + value = g_strdup_printf ("%u%s%s", + type, + may_set_on_self ? " settable" : "", + can_have_msg ? " message" : ""); + + g_key_file_set_string (f, section_name, key, value); + + g_free (key); + g_free (value); + } +} + static gchar * mgr_file_contents (const char *busname, const char *objpath, @@ -302,6 +334,7 @@ mgr_file_contents (const char *busname, const gchar * const *addr_vcard_fields; const gchar * const *addr_uri_schemes; const gchar * const *auth_types; + const gchar * const *mime_types; g_object_get (G_OBJECT (protocol), "immutable-properties", &props, @@ -319,6 +352,8 @@ mgr_file_contents (const char *busname, TP_PROP_PROTOCOL_INTERFACE_ADDRESSING_ADDRESSABLE_VCARD_FIELDS); addr_uri_schemes = tp_asv_get_strv (props, TP_PROP_PROTOCOL_INTERFACE_ADDRESSING_ADDRESSABLE_URI_SCHEMES); + mime_types = tp_asv_get_strv (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_SUPPORTED_AVATAR_MIME_TYPES); write_parameters (f, section_name, TP_BASE_PROTOCOL (protocol)); write_rccs (f, section_name, props); @@ -334,6 +369,40 @@ mgr_file_contents (const char *busname, g_key_file_set_string_list (f, section_name, "AddressableURISchemes", addr_uri_schemes, g_strv_length ((gchar **) addr_uri_schemes)); + /* Avatars */ + g_key_file_set_string_list (f, section_name, "SupportedAvatarMIMETypes", + mime_types, g_strv_length ((gchar **) mime_types)); + g_key_file_set_integer (f, section_name, "MinimumAvatarHeight", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_MINIMUM_AVATAR_HEIGHT, + NULL)); + g_key_file_set_integer (f, section_name, "RecommendedAvatarHeight", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_RECOMMENDED_AVATAR_HEIGHT, + NULL)); + g_key_file_set_integer (f, section_name, "MaximumAvatarHeight", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_MAXIMUM_AVATAR_HEIGHT, + NULL)); + g_key_file_set_integer (f, section_name, "MinimumAvatarWidth", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_MINIMUM_AVATAR_WIDTH, + NULL)); + g_key_file_set_integer (f, section_name, "RecommendedAvatarWidth", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_RECOMMENDED_AVATAR_WIDTH, + NULL)); + g_key_file_set_integer (f, section_name, "MaximumAvatarWidth", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_MAXIMUM_AVATAR_WIDTH, + NULL)); + g_key_file_set_integer (f, section_name, "MaximumAvatarBytes", + tp_asv_get_uint32 (props, + TP_PROP_PROTOCOL_INTERFACE_AVATARS_MAXIMUM_AVATAR_BYTES, + NULL)); + + write_presence (f, section_name, props); + WRITE_STR (TP_PROP_PROTOCOL_VCARD_FIELD, "VCardField"); WRITE_STR (TP_PROP_PROTOCOL_ENGLISH_NAME, "EnglishName"); WRITE_STR (TP_PROP_PROTOCOL_ICON, "Icon"); diff --git a/tests/test-handles.c b/tests/test-handles.c index a0d60be49..ebc4c3914 100644 --- a/tests/test-handles.c +++ b/tests/test-handles.c @@ -12,7 +12,7 @@ static void test_handles (guint handle_type) { - TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES]; + TpHandleRepoIface *repos[TP_NUM_HANDLE_TYPES]; TpHandleRepoIface *tp_repo = NULL; GError *error = NULL; guint i; @@ -21,7 +21,7 @@ test_handles (guint handle_type) const gchar *jid = "handle.test@foobar"; const gchar *return_jid; - for (i = 0; i < NUM_TP_HANDLE_TYPES; i++) + for (i = 0; i < TP_NUM_HANDLE_TYPES; i++) { repos[i] = NULL; } @@ -64,7 +64,7 @@ test_handles (guint handle_type) return_jid = tp_handle_inspect (tp_repo, handle); g_assert (!strcmp (return_jid, jid)); - for (i = 0; i < NUM_TP_HANDLE_TYPES; i++) + for (i = 0; i < TP_NUM_HANDLE_TYPES; i++) { if (repos[i]) g_object_unref ((GObject *) repos[i]); diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index d93d5b34e..22cf954ab 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -2,7 +2,6 @@ TWISTED_TESTS = \ addressing.py \ avatar-requirements.py \ caps/advertise-contact-caps.py \ - caps/advertise-legacy.py \ caps/broken-reply.py \ caps/caps-cache.py \ caps/caps-persistent-cache.py \ @@ -78,15 +77,12 @@ TWISTED_TESTS = \ pubsub.py \ roster/authorize.py \ roster/edit-before-roster.py \ - roster/ensure.py \ roster/groups-12791.py \ roster/groups.py \ roster/initial-aliases.py \ roster/push-from-contact.py \ roster/push-without-id.py \ roster/removed-from-rp-subscribe.py \ - roster/request-group-after-roster.py \ - roster/request-group-before-roster.py \ roster/test-google-roster.py \ roster/test-roster-item-deletion.py \ roster/test-roster.py \ @@ -176,7 +172,6 @@ TWISTED_VCARD_TESTS = \ $(NULL) TWISTED_JINGLE_TESTS = \ - jingle/accept-extra-stream.py \ jingle/call-basics.py \ jingle/call-codecoffer.py \ jingle/call-content-adding-removal.py \ @@ -187,38 +182,10 @@ TWISTED_JINGLE_TESTS = \ jingle/call-muc-cancel.py \ jingle/call-muc.py \ jingle/call-muc-re-re-request.py \ - jingle/call-state.py \ jingle/decloak-peer.py \ - jingle/dtmf-no-audio.py \ - jingle/dtmf.py \ - jingle/google-relay.py \ - jingle/hold-audio.py \ - jingle/hold-av.py \ - jingle/incoming-basics.py \ - jingle/incoming-call-stream-error.py \ - jingle/incoming-gmail-modern-jingle.py \ - jingle/initial-audio-video.py \ - jingle/misuse.py \ - jingle/outgoing-basics.py \ - jingle/outgoing-ensure.py \ - jingle/outgoing-many-streams.py \ - jingle/payload-types.py \ jingle/preload-caps-crash.py \ jingle/session-id-collision.py \ - jingle/stream-errors-on-content-reject.py \ - jingle/stream-errors-on-terminate.py \ - jingle/stream-handler-error.py \ jingle/stun-server.py \ - jingle/test-content-adding-removal.py \ - jingle/test-content-complex.py \ - jingle/test-description-info.py \ - jingle/test-incoming-call-reject.py \ - jingle/test-incoming-iceudp.py \ - jingle/test-outgoing-call-rejected.py \ - jingle/test-outgoing-iceudp.py \ - jingle/test-wait-for-caps-incomplete.py \ - jingle/test-wait-for-caps.py \ - jingle/transport-info-parsing.py \ jingle/unknown-session.py \ $(NULL) @@ -271,6 +238,7 @@ TWISTED_OTHER_FILES = \ mucutil.py \ ns.py \ olpc/util.py \ + presence_helper.py \ presence/__init__.py \ presence/invisible_helper.py \ rostertest.py \ @@ -344,24 +312,12 @@ else @echo "and then re-run configure." endif -if ENABLE_DEBUG -DEBUGGING_PYBOOL = True -else -DEBUGGING_PYBOOL = False -endif - if ENABLE_PLUGINS PLUGINS_ENABLED_PYBOOL = True else PLUGINS_ENABLED_PYBOOL = False endif -if ENABLE_CHANNEL_TYPE_CALL -CHANNEL_TYPE_CALL_ENABLED_PYBOOL = True -else -CHANNEL_TYPE_CALL_ENABLED_PYBOOL = False -endif - if ENABLE_GOOGLE_RELAY GOOGLE_RELAY_ENABLED_PYBOOL = True else @@ -390,9 +346,7 @@ config.py: Makefile $(AM_V_GEN) { \ echo "PACKAGE_STRING = \"$(PACKAGE_STRING)\""; \ echo "CLIENT_TYPE = '$(CLIENT_TYPE)'"; \ - echo "DEBUGGING = $(DEBUGGING_PYBOOL)"; \ echo "PLUGINS_ENABLED = $(PLUGINS_ENABLED_PYBOOL)"; \ - echo "CHANNEL_TYPE_CALL_ENABLED = $(CHANNEL_TYPE_CALL_ENABLED_PYBOOL)"; \ echo "GOOGLE_RELAY_ENABLED = $(GOOGLE_RELAY_ENABLED_PYBOOL)"; \ echo "FILE_TRANSFER_ENABLED = $(FILE_TRANSFER_ENABLED_PYBOOL)"; \ echo "VOIP_ENABLED = $(VOIP_ENABLED_PYBOOL)"; \ diff --git a/tests/twisted/addressing.py b/tests/twisted/addressing.py index 9528e12cb..057617bf3 100644 --- a/tests/twisted/addressing.py +++ b/tests/twisted/addressing.py @@ -2,13 +2,11 @@ Test Gabble's different addressing interfaces. """ -import dbus -from servicetest import unwrap, tp_path_prefix, assertEquals, ProxyWrapper, \ - assertContains, assertSameSets, assertDoesNotContain, pretty +from servicetest import tp_path_prefix, assertEquals, ProxyWrapper, \ + assertContains, assertSameSets from gabbletest import exec_test, call_async import constants as cs import ns -import time def test_protocol(q, bus, conn, stream): proto = ProxyWrapper( diff --git a/tests/twisted/avatar-requirements.py b/tests/twisted/avatar-requirements.py index 0272e95f0..25301b910 100644 --- a/tests/twisted/avatar-requirements.py +++ b/tests/twisted/avatar-requirements.py @@ -1,5 +1,5 @@ -from servicetest import call_async, EventPattern -from gabbletest import exec_test, acknowledge_iq, make_result_iq +from gabbletest import exec_test +from servicetest import assertEquals import constants as cs def test_get_all(conn): @@ -35,15 +35,13 @@ def test(q, bus, conn, stream): test_get_all(conn) # deprecated version - types, minw, minh, maxw, maxh, maxb = conn.Avatars.GetAvatarRequirements() - assert types[0] == 'image/png', types - assert 'image/jpeg' in types, types - assert 'image/gif' in types, types - assert minw == 32, minw - assert minh == 32, minh - assert maxw == 96, maxw - assert maxh == 96, maxh - assert maxb == 8192, maxb + props = conn.Properties.GetAll(cs.CONN_IFACE_AVATARS) + assertEquals(['image/png', 'image/jpeg', 'image/gif'], props['SupportedAvatarMIMETypes']) + assertEquals(32, props['MinimumAvatarWidth']) + assertEquals(32, props['MinimumAvatarHeight']) + assertEquals(96, props['MaximumAvatarWidth']) + assertEquals(96, props['MaximumAvatarHeight']) + assertEquals(8192, props['MaximumAvatarBytes']) if __name__ == '__main__': exec_test(test, do_connect=False) diff --git a/tests/twisted/caps/advertise-contact-caps.py b/tests/twisted/caps/advertise-contact-caps.py index 138cb2627..ec7ec7b59 100644 --- a/tests/twisted/caps/advertise-contact-caps.py +++ b/tests/twisted/caps/advertise-contact-caps.py @@ -221,16 +221,6 @@ def run_mixed_test (q, bus, conn, stream): conn.Connect() conn.ContactCapabilities.UpdateCapabilities([ - (cs.CLIENT + '.SquareWheel', [ - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.INITIAL_AUDIO: True}, - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.INITIAL_VIDEO: True}, - ], [ - cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/gtalk-p2p', - cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/ice-udp', - cs.CHANNEL_IFACE_MEDIA_SIGNALLING + '/video/h264', - ]), (cs.CLIENT + '.FlyingCar', [ { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_AUDIO: True}, @@ -250,14 +240,6 @@ def run_mixed_test (q, bus, conn, stream): if __name__ == '__main__': 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( - partial(run_test, media_channel_type=cs.CHANNEL_TYPE_CALL, media_interface=cs.CHANNEL_TYPE_CALL, initial_audio=cs.CALL_INITIAL_AUDIO, diff --git a/tests/twisted/caps/advertise-legacy.py b/tests/twisted/caps/advertise-legacy.py deleted file mode 100644 index 95b16245a..000000000 --- a/tests/twisted/caps/advertise-legacy.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -Test AdvertiseCapabilities. -""" - -import dbus - -from twisted.words.xish import xpath, domish - -from servicetest import EventPattern -from gabbletest import exec_test -from caps_helper import caps_contain, receive_presence_and_ask_caps,\ - check_caps, JINGLE_CAPS -import constants as cs -import ns - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def run_test(q, bus, conn, stream): - initial_presence = q.expect('stream-presence') - - # This method call looks wrong, but it's "the other side" of - # test/twisted/capabilities/legacy-caps.py in MC 5.1 - MC doesn't know - # how to map Client capabilities into the old Capabilities interface. - # - # Also, MC sometimes puts the same channel type in the list twice, so - # make sure Gabble copes. - add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, 2L**32-1), - (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1), - (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1)] - remove = [] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, JINGLE_CAPS) - - # Remove all our caps again - add = [] - remove = [cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.CHANNEL_TYPE_STREAM_TUBE] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, []) - - # Add caps selectively (i.e. what a client that actually understood the - # old Capabilities interface would do). With AUDIO and GTALK_P2P, we're - # callable, but not via ICE-UDP, and not with video. - # - # (Jingle and raw UDP need no special client support, so are automatically - # enabled whenever we can do audio or video.) - add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_GTALKP2P)] - remove = [] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, - [ns.GOOGLE_P2P, ns.JINGLE_TRANSPORT_RAWUDP, ns.JINGLE, - ns.JINGLE_015, ns.GOOGLE_FEAT_VOICE, ns.JINGLE_RTP_AUDIO, - ns.JINGLE_RTP, ns.JINGLE_015_AUDIO]) - - # Remove all our caps again - add = [] - remove = [cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.CHANNEL_TYPE_STREAM_TUBE] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, []) - - # With AUDIO but no transport, we are only callable via raw UDP, which - # Google clients cannot do. - add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.MEDIA_CAP_AUDIO)] - remove = [] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, - [ns.JINGLE_TRANSPORT_RAWUDP, ns.JINGLE, - ns.JINGLE_015, ns.JINGLE_RTP_AUDIO, - ns.JINGLE_RTP, ns.JINGLE_015_AUDIO]) - - # Remove all our caps again - add = [] - remove = [cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.CHANNEL_TYPE_STREAM_TUBE] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, []) - - # With VIDEO and ICE-UDP only, we are very futuristic indeed. - # Google clients cannot interop with us. - add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.MEDIA_CAP_VIDEO | cs.MEDIA_CAP_ICEUDP)] - remove = [] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) - (disco_response, namespaces, _, _) = receive_presence_and_ask_caps(q, stream, - False) - check_caps(namespaces, - [ns.JINGLE_TRANSPORT_ICEUDP, ns.JINGLE_TRANSPORT_RAWUDP, ns.JINGLE, - ns.JINGLE_015, ns.JINGLE_RTP_VIDEO, - ns.JINGLE_RTP, ns.JINGLE_015_VIDEO]) - -if __name__ == '__main__': - exec_test(run_test) diff --git a/tests/twisted/caps/caps-cache.py b/tests/twisted/caps/caps-cache.py index 9c63e03b6..0102d5ceb 100644 --- a/tests/twisted/caps/caps-cache.py +++ b/tests/twisted/caps/caps-cache.py @@ -12,7 +12,8 @@ import constants as cs import ns from caps_helper import ( compute_caps_hash, fake_client_dataforms, presence_and_disco, - send_presence, expect_disco, send_disco_reply) + send_presence, expect_disco, send_disco_reply, + assert_rccs_callable, get_contacts_capabilities_sync) from config import VOIP_ENABLED @@ -31,13 +32,16 @@ features = [ def expect_caps(q, conn, h): # we can now do audio and video calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged') + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: h in e.args[0]), + ) + assert_rccs_callable(cc.args[0][h], require_video=True) check_caps(conn, h) def check_caps(conn, h): - assertContains((h, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO), - conn.Capabilities.GetCapabilities([h])) + caps = get_contacts_capabilities_sync(conn, [h]) + assert_rccs_callable(caps[h], require_video=True) def update_contact_caps(q, conn, stream, contact, caps, disco = True, dataforms = {}, initial = True): diff --git a/tests/twisted/caps/caps-persistent-cache.py b/tests/twisted/caps/caps-persistent-cache.py index 2b1318396..b4725a8fa 100644 --- a/tests/twisted/caps/caps-persistent-cache.py +++ b/tests/twisted/caps/caps-persistent-cache.py @@ -5,7 +5,8 @@ from servicetest import ( assertEquals, assertContains, assertDoesNotContain, EventPattern, ) from gabbletest import make_presence, exec_test -from caps_helper import compute_caps_hash, send_disco_reply +from caps_helper import (compute_caps_hash, send_disco_reply, + assert_rccs_callable) import constants as cs import ns @@ -46,16 +47,13 @@ def handle_disco(q, stream, contact_jid, identity): send_disco_reply(stream, event.stanza, [identity], features) def capabilities_changed(q, contact_handle): - streamed_media_caps = (contact_handle, cs.CHANNEL_TYPE_STREAMED_MEDIA, - 0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) - e = q.expect('dbus-signal', signal='CapabilitiesChanged') - assertContains(streamed_media_caps, e.args[0]) e = q.expect('dbus-signal', signal='ContactCapabilitiesChanged') assertContains(contact_handle, e.args[0]) + assert_rccs_callable(e.args[0][contact_handle], require_video=True) assertContains(xiangqi_tube_cap, e.args[0][contact_handle]) def test1(q, bus, conn, stream): - contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact_bare_jid])[0] + contact_handle = conn.get_contact_handle_sync(contact_bare_jid) send_presence(q, stream, contact_jid, 'client/pc//thane') handle_disco(q, stream, contact_jid, 'client/pc//thane') capabilities_changed(q, contact_handle) @@ -63,7 +61,7 @@ def test1(q, bus, conn, stream): def test2(q, bus, conn, stream): # The second time around, the capabilities are retrieved from the cache, # so no disco request is sent. - contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact_bare_jid])[0] + contact_handle = conn.get_contact_handle_sync(contact_bare_jid) send_presence(q, stream, contact_jid, 'client/pc//thane') capabilities_changed(q, contact_handle) diff --git a/tests/twisted/caps/from-bare-jid.py b/tests/twisted/caps/from-bare-jid.py index 0460fd61b..122aaf696 100644 --- a/tests/twisted/caps/from-bare-jid.py +++ b/tests/twisted/caps/from-bare-jid.py @@ -8,7 +8,8 @@ from servicetest import ( assertEquals, assertContains, assertDoesNotContain, EventPattern, ) from gabbletest import make_presence, exec_test -from caps_helper import compute_caps_hash, send_disco_reply +from caps_helper import (compute_caps_hash, send_disco_reply, + assert_rccs_callable, assert_rccs_not_callable) import constants as cs import ns @@ -22,7 +23,7 @@ def test(q, bus, conn, stream): client = 'http://example.com/perverse-client' contact_bare_jid = 'edgecase@example.com' contact_with_resource = 'edgecase@example.com/hi' - contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact_bare_jid])[0] + contact_handle = conn.get_contact_handle_sync(contact_bare_jid) # Gabble gets a presence stanza from a bare JID, which is a tad surprising. features = [ @@ -49,10 +50,10 @@ def test(q, bus, conn, stream): # Gabble lets us know their caps have changed. (Gabble used to ignore the # reply.) - streamed_media_caps = (contact_handle, cs.CHANNEL_TYPE_STREAMED_MEDIA, - 0, 3, 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) - e = q.expect('dbus-signal', signal='CapabilitiesChanged') - assertContains(streamed_media_caps, e.args[0]) + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + assert_rccs_callable(cc.args[0][contact_handle]) # Gabble gets another presence stanza from the bare JID, with different # caps. @@ -84,12 +85,12 @@ def test(q, bus, conn, stream): # a resource (and vice versa), so it should now say the contact is # incapable. Gabble also looks up the resourceful JID's hash. cc, disco3 = q.expect_many( - EventPattern('dbus-signal', signal='CapabilitiesChanged'), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), EventPattern('stream-iq', to=contact_with_resource, query_ns='http://jabber.org/protocol/disco#info'), ) - assertDoesNotContain(streamed_media_caps, cc.args[0]) + assert_rccs_not_callable(cc.args[0][contact_handle]) query_node = xpath.queryForNodes('/iq/query', disco3.stanza)[0] assertEquals(client + '#' + caps['ver'], query_node.attributes['node']) @@ -103,8 +104,10 @@ def test(q, bus, conn, stream): send_disco_reply(stream, disco3.stanza, [], features_) # Gabble should announce that the contact has acquired some caps. - e = q.expect('dbus-signal', signal='CapabilitiesChanged') - assertContains(streamed_media_caps, e.args[0]) + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + assert_rccs_callable(cc.args[0][contact_handle]) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/caps/hashed-caps.py b/tests/twisted/caps/hashed-caps.py index 5c4562c7e..ce0ca5f57 100644 --- a/tests/twisted/caps/hashed-caps.py +++ b/tests/twisted/caps/hashed-caps.py @@ -5,13 +5,13 @@ Test the verification string introduced in version 1.5 of XEP-0115 This test changes the caps several times: - Initial presence to be online - Change presence to handle audio calls, using XEP-0115-v1.3. Check that - 'CapabilitiesChanged' *is* fired + 'ContactCapabilitiesChanged' *is* fired - Change presence *not* to handle audio calls, using XEP-0115-v1.5, but with a - *bogus* hash. Check that 'CapabilitiesChanged' is *not* fired + *bogus* hash. Check that 'ContactCapabilitiesChanged' is *not* fired - Change presence *not* to handle audio calls, using XEP-0115-v1.5, with a - *good* hash. Check that 'CapabilitiesChanged' *is* fired + *good* hash. Check that 'ContactCapabilitiesChanged' *is* fired - Change presence to handle audio calls, using XEP-0115-v1.5, with a XEP-0128 - dataform. Check that 'CapabilitiesChanged' is fired + dataform. Check that 'ContactCapabilitiesChanged' is fired This is done for 2 contacts Then, this test announce 2 contacts with the same hash. @@ -27,12 +27,13 @@ from twisted.words.xish import xpath from gabbletest import ( exec_test, make_result_iq, make_presence, sync_stream, elem, ) -from servicetest import sync_dbus, EventPattern, assertLength +from servicetest import sync_dbus, EventPattern, assertLength, assertEquals import constants as cs import ns from caps_helper import ( compute_caps_hash, make_caps_disco_reply, send_disco_reply, - fake_client_dataforms) + fake_client_dataforms, assert_rccs_callable, assert_rccs_not_callable, + get_contacts_capabilities_sync) from config import VOIP_ENABLED @@ -40,8 +41,6 @@ if not VOIP_ENABLED: print "NOTE: built with --disable-voip" raise SystemExit(77) -caps_changed_flag = False - some_identities = [ 'client/pc/fr/le gabble', 'client/pc/en/gabble', @@ -53,15 +52,7 @@ jingle_av_features = [ ns.GOOGLE_P2P, ] -def caps_changed_cb(dummy): - # Workaround to bug 9980: do not raise an error but use a flag - # https://bugs.freedesktop.org/show_bug.cgi?id=9980 - global caps_changed_flag - caps_changed_flag = True - def test_hash(q, bus, conn, stream, contact, contact_handle, client): - global caps_changed_flag - presence = make_presence(contact, status='hello') stream.send(presence) @@ -70,8 +61,8 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): (2, u'available', 'hello')}]) # no special capabilities - basic_caps = [(contact_handle, cs.CHANNEL_TYPE_TEXT, 3, 0)] - assert conn.Capabilities.GetCapabilities([contact_handle]) == basic_caps + for rcc in get_contacts_capabilities_sync(conn, [contact_handle])[contact_handle]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # send updated presence with Jingle caps info presence = make_presence(contact, status='hello', @@ -91,12 +82,13 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): send_disco_reply(stream, event.stanza, [], jingle_av_features) # we can now do audio calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged') - caps_diff = event.args[0] - media_diff = [c for c in caps_diff - if c[1] == cs.CHANNEL_TYPE_STREAMED_MEDIA][0] - assert media_diff[5] & cs.MEDIA_CAP_AUDIO, media_diff[5] - caps_changed_flag = False + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + + assert_rccs_callable(cc.args[0][contact_handle]) + assertEquals(cc.args[0], + get_contacts_capabilities_sync(conn, [contact_handle])) # Send presence without any capabilities. XEP-0115 §8.4 Caps Optimization # says “receivers of presence notifications MUST NOT expect an annotation @@ -105,10 +97,9 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): stream.send(make_presence(contact, status='very capable')) q.expect('dbus-signal', signal='PresencesChanged', args=[{contact_handle: (2, u'available', 'very capable')}]) - ye_olde_caps = conn.Capabilities.GetCapabilities([contact_handle]) - assertLength(1, [c for c in ye_olde_caps - if c[1] == cs.CHANNEL_TYPE_STREAMED_MEDIA and - c[3] & cs.MEDIA_CAP_AUDIO]) + # still exactly the same capabilities + assertEquals(cc.args[0], + get_contacts_capabilities_sync(conn, [contact_handle])) # send bogus presence caps = { @@ -131,10 +122,12 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): ['http://jabber.org/protocol/bogus-feature']) # don't receive any D-Bus signal + forbidden = [ + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ] + q.forbid_events(forbidden) sync_dbus(bus, q, conn) sync_stream(q, stream) - assert caps_changed_flag == False - # send presence with empty caps presence = make_presence(contact, status='hello', @@ -152,18 +145,22 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): # still don't receive any D-Bus signal sync_dbus(bus, q, conn) - assert caps_changed_flag == False # send good reply + q.unforbid_events(forbidden) result = make_result_iq(stream, event.stanza) query = result.firstChildElement() stream.send(result) # we can now do nothing - event = q.expect('dbus-signal', signal='CapabilitiesChanged') - assert caps_changed_flag == True - caps_changed_flag = False - + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + for rcc in cc.args[0][contact_handle]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) + assert_rccs_not_callable(cc.args[0][contact_handle]) + assertEquals(cc.args[0], + get_contacts_capabilities_sync(conn, [contact_handle])) # send correct presence ver = compute_caps_hash(some_identities, jingle_av_features, fake_client_dataforms) @@ -183,22 +180,24 @@ def test_hash(q, bus, conn, stream, contact, contact_handle, client): client + '#' + caps['ver'] # don't receive any D-Bus signal + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) # send good reply send_disco_reply( stream, event.stanza, some_identities, jingle_av_features, fake_client_dataforms) # we can now do audio calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - ) - assert caps_changed_flag == True - caps_changed_flag = False + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + assert_rccs_callable(cc.args[0][contact_handle]) + assertEquals(cc.args[0], + get_contacts_capabilities_sync(conn, [contact_handle])) def test_two_clients(q, bus, conn, stream, contact1, contact2, contact_handle1, contact_handle2, client, broken_hash): - global caps_changed_flag presence = make_presence(contact1, status='hello') stream.send(presence) @@ -215,10 +214,9 @@ def test_two_clients(q, bus, conn, stream, contact1, contact2, (2, u'available', 'hello')}]) # no special capabilities - basic_caps = [(contact_handle1, cs.CHANNEL_TYPE_TEXT, 3, 0)] - assert conn.Capabilities.GetCapabilities([contact_handle1]) == basic_caps - basic_caps = [(contact_handle2, cs.CHANNEL_TYPE_TEXT, 3, 0)] - assert conn.Capabilities.GetCapabilities([contact_handle2]) == basic_caps + for h in (contact_handle1, contact_handle2): + for rcc in get_contacts_capabilities_sync(conn, [h])[h]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # send updated presence with Jingle caps info ver = compute_caps_hash(some_identities, jingle_av_features, {}) @@ -240,8 +238,12 @@ def test_two_clients(q, bus, conn, stream, contact1, contact2, client + '#' + ver # don't receive any D-Bus signal + forbidden = [ + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ] + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) result = make_caps_disco_reply( stream, event.stanza, some_identities, jingle_av_features) @@ -263,28 +265,33 @@ def test_two_clients(q, bus, conn, stream, contact1, contact2, client + '#' + ver # don't receive any D-Bus signal + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) # send good reply send_disco_reply(stream, event.stanza, some_identities, jingle_av_features) - # we can now do audio calls with both contacts - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - args=[[(contact_handle2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]) + # we can now do audio calls + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: contact_handle2 in e.args[0]), + ) + assert_rccs_callable(cc.args[0][contact_handle2]) + if not broken_hash: # if the first contact failed to provide a good hash, it does not # deserve its capabilities to be understood by Gabble! - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - args=[[(contact_handle1, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, 0, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]) - - caps_changed_flag = False - - # don't receive any D-Bus signal + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: contact_handle1 in e.args[0]), + ) + assert_rccs_callable(cc.args[0][contact_handle1]) + + # don't receive any further signals + q.forbid_events(forbidden) sync_dbus(bus, q, conn) - assert caps_changed_flag == False + q.unforbid_events(forbidden) def test_39464(q, bus, conn, stream): """ @@ -318,10 +325,6 @@ def test_39464(q, bus, conn, stream): sync_stream(q, stream) def test(q, bus, conn, stream): - # be notified when the signal CapabilitiesChanged is fired - conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CAPS) - conn_caps_iface.connect_to_signal('CapabilitiesChanged', caps_changed_cb) - test_hash(q, bus, conn, stream, 'bob@foo.com/Foo', 2L, 'http://telepathy.freedesktop.org/fake-client') test_hash(q, bus, conn, stream, 'bob2@foo.com/Foo', 3L, 'http://telepathy.freedesktop.org/fake-client2') diff --git a/tests/twisted/caps/jingle-caps.py b/tests/twisted/caps/jingle-caps.py index 42f69cf1d..4b142059b 100644 --- a/tests/twisted/caps/jingle-caps.py +++ b/tests/twisted/caps/jingle-caps.py @@ -13,8 +13,10 @@ from servicetest import ( ) import constants as cs import ns -from caps_helper import presence_and_disco, compute_caps_hash, send_presence +from caps_helper import (presence_and_disco, compute_caps_hash, send_presence, + get_contacts_capabilities_sync) from jingle.jingletest2 import JingleTest2, JingleProtocol031 +from call_helper import CallTest from config import VOIP_ENABLED @@ -46,17 +48,14 @@ def test_caps(q, conn, stream, contact, features, audio, video, google=False): client, caps, features) cflags = 0 - stream_expected_media_caps = [] call_expected_media_caps = [] if audio: cflags |= cs.MEDIA_CAP_AUDIO - stream_expected_media_caps.append (cs.INITIAL_AUDIO) call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO) call_expected_media_caps.append (cs.CALL_INITIAL_AUDIO_NAME) if video: cflags |= cs.MEDIA_CAP_VIDEO - stream_expected_media_caps.append (cs.INITIAL_VIDEO) call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO) call_expected_media_caps.append (cs.CALL_INITIAL_VIDEO_NAME) @@ -64,32 +63,17 @@ def test_caps(q, conn, stream, contact, features, audio, video, google=False): # client, they'll have the ImmutableStreams cap. if cflags < (cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO) or google: cflags |= cs.MEDIA_CAP_IMMUTABLE_STREAMS - stream_expected_media_caps.append(cs.IMMUTABLE_STREAMS) else: call_expected_media_caps.append(cs.CALL_MUTABLE_CONTENTS) - _, event = q.expect_many( - EventPattern('dbus-signal', signal='CapabilitiesChanged', - args = [[ ( h, - cs.CHANNEL_TYPE_STREAMED_MEDIA, - 0, # old generic - 3, # new generic (can create and receive these) - 0, # old specific - cflags ) ]] # new specific - ), + event, = q.expect_many( EventPattern('dbus-signal', signal='ContactCapabilitiesChanged') ) - assertContains((h, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, cflags), - conn.Capabilities.GetCapabilities([h])) - - # Check Contact capabilities for streamed media + # Check Contact capabilities assertEquals(len(event.args), 1) assertEquals (event.args[0], - conn.ContactCapabilities.GetContactCapabilities([h])) - - check_contact_caps (event.args[0][h], - cs.CHANNEL_TYPE_STREAMED_MEDIA, stream_expected_media_caps) + get_contacts_capabilities_sync(conn, [h])) check_contact_caps (event.args[0][h], cs.CHANNEL_TYPE_CALL, call_expected_media_caps) @@ -142,6 +126,11 @@ def test(q, bus, conn, stream): def test_prefer_phones(q, bus, conn, stream, expect_disco): cat = 'cat@windowsill' + # This needs to be done once per connection + jp = JingleProtocol031() + JingleTest2(jp, conn, q, stream, 'test@localhost', + cat).prepare() + def sign_in_a_cat(jid, identities, show=None): caps['ver'] = compute_caps_hash(identities, features, {}) @@ -151,32 +140,19 @@ def test_prefer_phones(q, bus, conn, stream, expect_disco): sync_stream(q, stream) def make_call(expected_recipient): - jp = JingleProtocol031() - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'dummy') - - conn.Requests.CreateChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: cat, - cs.INITIAL_AUDIO: True, - }) - e = q.expect('dbus-signal', signal='NewSessionHandler') - session = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session.Ready() + class MyTest(CallTest): + PEER_JID = expected_recipient - e = q.expect('dbus-signal', signal='NewStreamHandler') + def check_session_initiate_iq(self, e): + assertEquals(expected_recipient, e.to) - stream_handler = make_channel_proxy(conn, e.args[0], - 'Media.StreamHandler') - stream_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) + def prepare(self): + # Don't do the preparation step: we did that already + pass - e = q.expect('stream-iq', - predicate=jp.action_predicate('session-initiate')) - assertEquals(expected_recipient, e.to) + test = MyTest(jp, q, bus, conn, stream, incoming=False, params={}) + test.run() features = [ ns.JINGLE_RTP, ns.JINGLE_RTP_AUDIO, ns.JINGLE_RTP_VIDEO ] + all_transports @@ -214,7 +190,7 @@ def test_google_caps(q, bus, conn, stream): 'ver': '1.1', 'ext': ' '.join(ext_set) } - handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + handle = conn.get_contact_handle_sync(jid) send_presence(q, conn, stream, jid, gcaps, initial=True) diff --git a/tests/twisted/caps/offline.py b/tests/twisted/caps/offline.py index 1313c6d09..dea958b72 100644 --- a/tests/twisted/caps/offline.py +++ b/tests/twisted/caps/offline.py @@ -4,6 +4,7 @@ Test for fd.o#32874 -- Offline contacts do not have capabilities. from gabbletest import exec_test from servicetest import assertEquals, assertSameSets, assertLength +from caps_helper import get_contacts_capabilities_sync import constants as cs import ns @@ -26,10 +27,10 @@ def test(q, bus, conn, stream): q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]), - bob_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + bob_handle = conn.get_contact_handle_sync(jid) # new ContactCapabilities - ccaps_map = conn.ContactCapabilities.GetContactCapabilities([bob_handle]) + ccaps_map = get_contacts_capabilities_sync(conn, [bob_handle]) assertLength(1, ccaps_map) assertLength(1, ccaps_map[bob_handle]) @@ -40,13 +41,5 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT}, fixed) assertSameSets([cs.TARGET_HANDLE], allowed) - # old Capabilities - all_caps = conn.Capabilities.GetCapabilities([bob_handle]) - assertLength(1, all_caps) - - caps = all_caps[0] - - assertEquals((bob_handle, cs.CHANNEL_TYPE_TEXT, 3, 0), caps) - if __name__ == '__main__': exec_test(test, do_connect=False) diff --git a/tests/twisted/caps/receive-jingle.py b/tests/twisted/caps/receive-jingle.py index 7ea84f535..c35d0dbb8 100644 --- a/tests/twisted/caps/receive-jingle.py +++ b/tests/twisted/caps/receive-jingle.py @@ -6,6 +6,8 @@ import dbus from servicetest import EventPattern, assertEquals, sync_dbus from gabbletest import exec_test, make_result_iq, make_presence, sync_stream +from caps_helper import (assert_rccs_callable, assert_rccs_not_callable, + check_rccs_callable, get_contacts_capabilities_sync) import constants as cs from config import VOIP_ENABLED @@ -14,26 +16,30 @@ if not VOIP_ENABLED: print "NOTE: built with --disable-voip" raise SystemExit(77) -icaps_attr = cs.CONN_IFACE_CAPS + "/caps" -basic_caps = [(2, cs.CHANNEL_TYPE_TEXT, 3, 0)] - def test(q, bus, conn, stream): + bob = conn.get_contact_handle_sync('bob@foo.com') + presence = make_presence('bob@foo.com/Foo', status='hello') stream.send(presence) q.expect('dbus-signal', signal='PresencesChanged', - args=[{2L: (2, u'available', 'hello')}]) + args=[{bob: (cs.PRESENCE_AVAILABLE, u'available', 'hello')}]) - # FIXME: throughout this test, Bob's handle is assumed to be 2. + basic_caps = [(bob, cs.CHANNEL_TYPE_TEXT, 3, 0)] - # no special capabilities - assert conn.Capabilities.GetCapabilities([2]) == basic_caps + # only Text + for rcc in get_contacts_capabilities_sync(conn, [bob])[bob]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # holding the handle here: see below - assert conn.Contacts.GetContactAttributes( - [2], [cs.CONN_IFACE_CAPS], True) == \ - { 2L: { icaps_attr: basic_caps, - cs.CONN + '/contact-id': 'bob@foo.com'}} + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: + get_contacts_capabilities_sync(conn, [bob])[bob], + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], [cs.CONN_IFACE_CONTACT_CAPS], True)) # send updated presence with Jingle audio/video caps info. we turn on both # audio and video at the same time to test that all of the capabilities are @@ -76,16 +82,22 @@ def test(q, bus, conn, stream): stream.send(result) # we can now do audio and video calls - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - args=[[(2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 3, - 0, cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO)]]) - - caps = conn.Contacts.GetContactAttributes([2], [cs.CONN_IFACE_CAPS], False) - assert caps.keys() == [2L] - assert icaps_attr in caps[2L] - assert len(caps[2L][icaps_attr]) == 2 - assert basic_caps[0] in caps[2L][icaps_attr] - assert (2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 3) in caps[2L][icaps_attr] + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', + predicate=lambda e: check_rccs_callable(e.args[0][bob])), + ) + assert_rccs_callable(cc.args[0][bob], require_video=True, + mutable_contents=True) + + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: + cc.args[0][bob], + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], + [cs.CONN_IFACE_CONTACT_CAPS], True)) # send updated presence without video support presence = make_presence('bob@foo.com/Foo', status='hello', @@ -97,19 +109,22 @@ def test(q, bus, conn, stream): # we can now do only audio calls (and as a result have the ImmutableStreams # cap) - event = q.expect('dbus-signal', signal='CapabilitiesChanged', - args=[[(2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 3, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_VIDEO, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS)]]) - - caps = conn.Contacts.GetContactAttributes([2], [cs.CONN_IFACE_CAPS], False) - assert caps.keys() == [2L] - assert icaps_attr in caps[2L] - assert len(caps[2L][icaps_attr]) == 2 - assert basic_caps[0] in caps[2L][icaps_attr] - assert (2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS) \ - in caps[2L][icaps_attr] + cc, = q.expect_many( + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), + ) + assert_rccs_callable(cc.args[0][bob]) + assert_rccs_not_callable(cc.args[0][bob], require_audio=False, + require_video=True, mutable_contents=False) + + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: + cc.args[0][bob], + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], + [cs.CONN_IFACE_CONTACT_CAPS], True)) # go offline presence = make_presence('bob@foo.com/Foo', type='unavailable') @@ -117,35 +132,31 @@ def test(q, bus, conn, stream): # can't do audio calls any more q.expect_many( - EventPattern('dbus-signal', signal='CapabilitiesChanged', - args=[[(2, cs.CHANNEL_TYPE_STREAMED_MEDIA, 3, 0, - cs.MEDIA_CAP_AUDIO | cs.MEDIA_CAP_IMMUTABLE_STREAMS, - 0)]], - ), EventPattern('dbus-signal', signal='PresencesChanged', - args=[{2: (cs.PRESENCE_OFFLINE, 'offline', '')}]), + args=[{bob: (cs.PRESENCE_OFFLINE, 'offline', '')}]), + EventPattern('dbus-signal', signal='ContactCapabilitiesChanged'), ) # Contact went offline. Previously, this test asserted that the handle # became invalid, but that's not guaranteed to happen immediately; so we # now hold the handle (above), to guarantee that it does *not* become # invalid. - assert conn.Contacts.GetContactAttributes( - [2], [cs.CONN_IFACE_CAPS], False) == \ - { 2L: { icaps_attr: basic_caps, - cs.CONN + '/contact-id': 'bob@foo.com'}} + rccs = get_contacts_capabilities_sync(conn, [bob])[bob] + for rcc in rccs: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) + + assertEquals( + { bob: { + cs.ATTR_CONTACT_CAPABILITIES: rccs, + cs.CONN + '/contact-id': 'bob@foo.com', + }, + }, + conn.Contacts.GetContactAttributes([bob], + [cs.CONN_IFACE_CONTACT_CAPS], True)) # What about a handle that's not valid? assertEquals({}, conn.Contacts.GetContactAttributes( - [31337], [cs.CONN_IFACE_CAPS], False)) - - # regression test for fd.o #15198: getting caps of invalid handle crashed - try: - conn.Capabilities.GetCapabilities([31337]) - except dbus.DBusException, e: - pass - else: - assert False, "Should have had an error!" + [31337], [cs.CONN_IFACE_CONTACT_CAPS], False)) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/caps/trust-thyself.py b/tests/twisted/caps/trust-thyself.py index 34a145b62..fda08ec3e 100644 --- a/tests/twisted/caps/trust-thyself.py +++ b/tests/twisted/caps/trust-thyself.py @@ -49,12 +49,25 @@ def test(q, bus, conn, stream): stream.send(p) sync_stream(q, stream) - # Advertise some different capabilities, to change our own caps hash. - add = [(cs.CHANNEL_TYPE_STREAMED_MEDIA, 2L**32-1), - (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1), - (cs.CHANNEL_TYPE_STREAM_TUBE, 2L**32-1)] - remove = [] - caps = conn.Capabilities.AdvertiseCapabilities(add, remove) + conn.ContactCapabilities.UpdateCapabilities([ + (cs.CLIENT + '.AbiWord', [ + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.STREAM_TUBE_SERVICE: 'x-abiword' }, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAM_TUBE, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.STREAM_TUBE_SERVICE: 'x-abiword' }, + ], []), + (cs.CLIENT + '.KCall', [ + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL }, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_AUDIO: True}, + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.CALL_INITIAL_VIDEO: True}, + ], [ + cs.CHANNEL_TYPE_CALL + '/gtalk-p2p', + cs.CHANNEL_TYPE_CALL + '/ice-udp', + cs.CHANNEL_TYPE_CALL + '/video/h264', + ]), + ]) self_presence = q.expect('stream-presence') c_ = xpath.queryForNodes('/presence/c', self_presence.stanza)[0] diff --git a/tests/twisted/caps/tube-caps.py b/tests/twisted/caps/tube-caps.py index 3d3f698dd..1ceb6f8b5 100644 --- a/tests/twisted/caps/tube-caps.py +++ b/tests/twisted/caps/tube-caps.py @@ -47,7 +47,7 @@ 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, receive_presence_and_ask_caps,\ - caps_contain, ft_fixed_properties, ft_allowed_properties + caps_contain, ft_fixed_properties, ft_allowed_properties, get_contacts_capabilities_sync import ns specialized_tube_allowed_properties = dbus.Array([cs.TARGET_HANDLE, @@ -130,11 +130,11 @@ def receive_caps(q, conn, stream, contact, contact_handle, features, # Make sure Gabble's got the caps sync_stream(q, stream) - caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps) # test again, to check GetContactCapabilities does not have side effect - caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps) # check the Contacts interface give the same caps @@ -144,11 +144,11 @@ def receive_caps(q, conn, stream, contact, contact_handle, features, assertSameElements(caps[contact_handle], caps_via_contacts_iface) def test_tube_caps_from_contact(q, bus, conn, stream, contact): - contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + contact_handle = conn.get_contact_handle_sync(contact) # Check that we don't crash if we haven't seen any caps/presence for this # contact yet. - caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) basic_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties)]}) @@ -227,7 +227,7 @@ def test_tube_caps_from_contact(q, bus, conn, stream, contact): def advertise_caps(q, conn, stream, filters, expected_features, unexpected_features, expected_caps): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") ret_caps = conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', filters, [])]) @@ -245,7 +245,7 @@ def advertise_caps(q, conn, stream, filters, expected_features, unexpected_featu assertDoesNotContain(var, namespaces) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertSameElements(expected_caps, caps) # check the Contacts interface give the same caps @@ -255,7 +255,7 @@ def advertise_caps(q, conn, stream, filters, expected_features, unexpected_featu assertSameElements(caps[self_handle], caps_via_contacts_iface) def test_tube_caps_to_contact(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") basic_caps = dbus.Dictionary({self_handle: [(text_fixed_properties, text_allowed_properties), @@ -292,7 +292,7 @@ def test_tube_caps_to_contact(q, bus, conn, stream): (ft_fixed_properties, ft_allowed_properties)]}) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertEquals(basic_caps, caps) # check the Contacts interface give the same caps @@ -306,7 +306,7 @@ def test_tube_caps_to_contact(q, bus, conn, stream): [(cs.CLIENT + '.Foo', {}, [])]) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps) @@ -323,7 +323,7 @@ def test_tube_caps_to_contact(q, bus, conn, stream): [(cs.CLIENT + '.Foo', [outgoing_daap_fixed_properties], [])]) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps) diff --git a/tests/twisted/caps_helper.py b/tests/twisted/caps_helper.py index 11b05d9d8..b5579a2e0 100644 --- a/tests/twisted/caps_helper.py +++ b/tests/twisted/caps_helper.py @@ -315,8 +315,15 @@ def presence_and_disco(q, conn, stream, contact, disco, return h +def get_contacts_capabilities_sync(conn, contacts): + h2asv = conn.Contacts.GetContactAttributes(contacts, [cs.CONN_IFACE_CONTACT_CAPS], False) + ret = {} + for h in contacts: + ret[h] = h2asv[h][cs.ATTR_CONTACT_CAPABILITIES] + return ret + def send_presence(q, conn, stream, contact, caps, initial=True, show=None): - h = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + h = conn.get_contact_handle_sync(contact) if initial: stream.send(make_presence(contact, status='hello')) @@ -326,8 +333,8 @@ def send_presence(q, conn, stream, contact, caps, initial=True, show=None): (2, u'available', 'hello')}]) # no special capabilities - assertEquals([(h, cs.CHANNEL_TYPE_TEXT, 3, 0)], - conn.Capabilities.GetCapabilities([h])) + for rcc in get_contacts_capabilities_sync(conn, [h])[h]: + assertEquals(cs.CHANNEL_TYPE_TEXT, rcc[0].get(cs.CHANNEL_TYPE)) # send updated presence with caps info stream.send(make_presence(contact, show=show, status='hello', caps=caps)) @@ -345,6 +352,73 @@ def send_disco_reply(stream, stanza, identities, features, dataforms={}): stream.send( make_caps_disco_reply(stream, stanza, identities, features, dataforms)) +def assert_rccs_callable(rccs, **kwargs): + assert check_rccs_callable(rccs, **kwargs), rccs + +def assert_rccs_not_callable(rccs, **kwargs): + assert not check_rccs_callable(rccs, **kwargs), rccs + +def check_rccs_callable(rccs, + require_audio=True, + require_video=False, + mutable_contents=None): + """rccs: a list of RequestableChannelClass tuples""" + + audio_callable = False + video_callable = False + av_callable = False + + for rcc in rccs: + fixed, allowed = rcc + + if fixed.get(cs.CHANNEL_TYPE) != cs.CHANNEL_TYPE_CALL: + continue + + if fixed.get(cs.TARGET_HANDLE_TYPE) != cs.HT_CONTACT: + continue + + if len(fixed) > (int(cs.CHANNEL_TYPE in fixed) + + int(cs.TARGET_HANDLE_TYPE in fixed) + + int(cs.CALL_INITIAL_AUDIO in fixed) + + int(cs.CALL_INITIAL_VIDEO in fixed)): + continue + + assert fixed.get(cs.CALL_INITIAL_AUDIO) in (True, None) + assert fixed.get(cs.CALL_INITIAL_VIDEO) in (True, None) + + if mutable_contents is not None: + if mutable_contents: + assertContains(cs.CALL_MUTABLE_CONTENTS, allowed) + else: + assertDoesNotContain(cs.CALL_MUTABLE_CONTENTS, allowed) + + if (fixed.get(cs.CALL_INITIAL_AUDIO) == True or + cs.CALL_INITIAL_AUDIO in allowed): + audio_callable = True + assertContains(cs.CALL_INITIAL_AUDIO_NAME, allowed) + + if (fixed.get(cs.CALL_INITIAL_VIDEO) == True or + cs.CALL_INITIAL_VIDEO in allowed): + video_callable = True + assertContains(cs.CALL_INITIAL_VIDEO_NAME, allowed) + + if ((fixed.get(cs.CALL_INITIAL_AUDIO) == True or + cs.CALL_INITIAL_AUDIO in allowed) and + (fixed.get(cs.CALL_INITIAL_VIDEO) == True or + cs.CALL_INITIAL_VIDEO in allowed)): + av_callable = True + + if require_audio and not audio_callable: + return False + + if require_video and not video_callable: + return False + + if require_audio and require_video and not av_callable: + return False + + return True + if __name__ == '__main__': # example from XEP-0115 assertEquals('QgayPKawpkPSDYmwT/WM94uAlu0=', diff --git a/tests/twisted/client-types.py b/tests/twisted/client-types.py index 2eaeebedb..7becd11a4 100644 --- a/tests/twisted/client-types.py +++ b/tests/twisted/client-types.py @@ -1,10 +1,10 @@ """ Test Conn.I.ClientTypes """ -import random from functools import partial -from servicetest import EventPattern, assertEquals, assertLength, assertContains, assertSameSets +from servicetest import (EventPattern, assertEquals, assertLength, + assertContains, assertSameSets, call_async) from gabbletest import exec_test, make_presence, sync_stream import constants as cs import ns @@ -50,7 +50,7 @@ def build_stuff(identities): def contact_online(q, conn, stream, contact, identities, disco=True, dataforms={}, initial=True, show=None): (caps, client, types) = build_stuff(identities) - handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + handle = conn.get_contact_handle_sync(contact) # make contact come online presence_and_disco (q, conn, stream, contact, @@ -62,6 +62,10 @@ def contact_online(q, conn, stream, contact, identities, event = q.expect('dbus-signal', signal='ClientTypesUpdated') assertEquals([handle, types], event.args) +def get_client_types(conn, handle): + h2asv = conn.Contacts.GetContactAttributes([handle], [cs.CONN_IFACE_CLIENT_TYPES], False) + return h2asv[handle][cs.ATTR_CLIENT_TYPES] + def test(q, bus, conn, stream): # check all these types appear as they should contact_online(q, conn, stream, 'bot@bot.com/lol', BOT) @@ -76,7 +80,7 @@ def test(q, bus, conn, stream): meredith_one = 'meredith@foo.com/One' meredith_two = 'meredith@foo.com/Two' meredith_three = 'meredith@foo.com/Three' - meredith_handle = conn.RequestHandles(cs.HT_CONTACT, [meredith_one])[0] + meredith_handle = conn.get_contact_handle_sync(meredith_one) # Meredith signs in from one resource contact_online(q, conn, stream, meredith_one, PC, show='chat') @@ -92,12 +96,16 @@ def test(q, bus, conn, stream): # ClientTypes should be: ['pc'] # check we're still a PC - types = conn.GetClientTypes([meredith_handle], - dbus_interface=cs.CONN_IFACE_CLIENT_TYPES) + types = get_client_types(conn, meredith_handle) + + assertLength(1, types) + assertEquals('pc', types[0]) + + types = conn.RequestClientTypes(meredith_handle, + dbus_interface=cs.CONN_IFACE_CLIENT_TYPES) assertLength(1, types) - assertLength(1, types[meredith_handle]) - assertEquals('pc', types[meredith_handle][0]) + assertEquals('pc', types[0]) # Two now becomes more available stream.send(make_presence(meredith_two, show='chat')) @@ -106,9 +114,8 @@ def test(q, bus, conn, stream): # * Two: chat: phone # ClientTypes should be: ['pc'] - types = conn.GetClientTypes([meredith_handle], - dbus_interface=cs.CONN_IFACE_CLIENT_TYPES) - assertEquals('pc', types[meredith_handle][0]) + types = get_client_types(conn, meredith_handle) + assertEquals('pc', types[0]) # One now becomes less available stream.send(make_presence(meredith_one, show='away')) @@ -158,9 +165,8 @@ def test(q, bus, conn, stream): args=[{meredith_handle: (cs.PRESENCE_AWAY, 'away', '')}]) # check it still thinks we're a PC - types = conn.GetClientTypes([meredith_handle], - dbus_interface=cs.CONN_IFACE_CLIENT_TYPES) - assertEquals('pc', types[meredith_handle][0]) + types = get_client_types(conn, meredith_handle) + assertEquals('pc', types[0]) # Three, with multiple identities, signs in identities = [PHONE[0], CONSOLE[0], HANDHELD[0], BOT[0]] @@ -201,21 +207,19 @@ def test(q, bus, conn, stream): def test2(q, bus, conn, stream): marco_pidgin = 'marco@fancy.italian.restaurant/Pidgin' marco_phone = 'marco@fancy.italian.restaurant/N900' - handle = conn.RequestHandles(cs.HT_CONTACT, [marco_pidgin])[0] + handle = conn.get_contact_handle_sync(marco_pidgin) # pidgin comes online contact_online(q, conn, stream, marco_pidgin, PC) - types = conn.GetClientTypes([handle], - dbus_interface=cs.CONN_IFACE_CLIENT_TYPES) - assertSameSets(['pc'], types[handle]) + types = get_client_types(conn, handle) + assertSameSets(['pc'], types) # phone comes online contact_online(q, conn, stream, marco_phone, PHONE, initial=False) - types = conn.GetClientTypes([handle], - dbus_interface=cs.CONN_IFACE_CLIENT_TYPES) - assertSameSets(['pc'], types[handle]) + types = get_client_types(conn, handle) + assertSameSets(['pc'], types) sync_stream(q, stream) @@ -249,7 +253,7 @@ def two_contacts_with_the_same_hash(q, bus, conn, stream, bare_jids): contact1 += '/lol' contact2 += '/whut' - h1, h2 = conn.RequestHandles(cs.HT_CONTACT, [contact1, contact2]) + h1, h2 = conn.get_contact_handles_sync([contact1, contact2]) ver = compute_caps_hash(BANANAPHONE, features, {}) caps = { # Uniquify slightly with a stringified boolean ;-) diff --git a/tests/twisted/cm/protocol.py b/tests/twisted/cm/protocol.py index e9c0b1c3b..2c34036c8 100644 --- a/tests/twisted/cm/protocol.py +++ b/tests/twisted/cm/protocol.py @@ -3,27 +3,19 @@ Test Gabble's o.T.Protocol implementation """ import dbus -from servicetest import unwrap, tp_path_prefix, assertEquals +from servicetest import unwrap, tp_path_prefix, assertEquals, assertContains from gabbletest import exec_test, call_async import constants as cs -import time def test(q, bus, conn, stream): cm = bus.get_object(cs.CM + '.gabble', tp_path_prefix + '/ConnectionManager/gabble') - cm_iface = dbus.Interface(cm, cs.CM) cm_prop_iface = dbus.Interface(cm, cs.PROPERTIES_IFACE) protocols = unwrap(cm_prop_iface.Get(cs.CM, 'Protocols')) assertEquals(set(['jabber']), set(protocols.keys())) - protocol_names = unwrap(cm_iface.ListProtocols()) - assertEquals(set(['jabber']), set(protocol_names)) - - cm_params = cm_iface.GetParameters('jabber') jabber_props = protocols['jabber'] - jabber_params = jabber_props[cs.PROTOCOL + '.Parameters'] - assertEquals(cm_params, jabber_params) proto = bus.get_object(cm.bus_name, cm.object_path + '/jabber') proto_iface = dbus.Interface(proto, cs.PROTOCOL) @@ -39,7 +31,7 @@ def test(q, bus, conn, stream): assertEquals('foo@mit.edu', unwrap(proto_iface.NormalizeContact('foo@MIT.Edu/Telepathy'))) - # org.freedesktop.Telepathy.Protocol.Interface.Presence + # Protocol.Interface.Presence expected_status = {'available': (cs.PRESENCE_AVAILABLE, True, True), 'dnd' : (cs.PRESENCE_BUSY, True, True), 'unknown' : (cs.PRESENCE_UNKNOWN, False, False), @@ -66,6 +58,17 @@ def test(q, bus, conn, stream): acc_name = unwrap(proto_iface.IdentifyAccount(test_params)) assertEquals(test_params['account'], acc_name) + assertContains(cs.PROTOCOL_IFACE_AVATARS, proto_props['Interfaces']) + avatar_props = unwrap(proto_prop_iface.GetAll(cs.PROTOCOL_IFACE_AVATARS)) + assertEquals(8192, avatar_props['MaximumAvatarBytes']) + assertEquals(96, avatar_props['MaximumAvatarHeight']) + assertEquals(96, avatar_props['MaximumAvatarWidth']) + assertEquals(32, avatar_props['MinimumAvatarHeight']) + assertEquals(32, avatar_props['MinimumAvatarWidth']) + assertEquals(64, avatar_props['RecommendedAvatarHeight']) + assertEquals(64, avatar_props['RecommendedAvatarWidth']) + assertEquals(['image/png', 'image/jpeg', 'image/gif'], avatar_props['SupportedAvatarMIMETypes']) + conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) q.expect('stream-authenticated') diff --git a/tests/twisted/connect/test-twice.py b/tests/twisted/connect/test-twice.py index 437ecec61..9ab1b09f7 100644 --- a/tests/twisted/connect/test-twice.py +++ b/tests/twisted/connect/test-twice.py @@ -9,8 +9,6 @@ import dbus import constants as cs from gabbletest import exec_test -from rostertest import expect_contact_list_signals, check_contact_list_signals -from servicetest import assertLength def test(q, bus, conns, streams): @@ -30,16 +28,8 @@ def test(q, bus, conns, streams): args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED], path=conn1.object.object_path) - pairs = expect_contact_list_signals(q, bus, conn1, - ['publish', 'subscribe', 'stored']) - - check_contact_list_signals(q, bus, conn1, pairs.pop(0), cs.HT_LIST, - 'publish', []) - check_contact_list_signals(q, bus, conn1, pairs.pop(0), cs.HT_LIST, - 'subscribe', []) - check_contact_list_signals(q, bus, conn1, pairs.pop(0), cs.HT_LIST, - 'stored', []) - assertLength(0, pairs) # i.e. we popped and checked all of them + q.expect('dbus-signal', signal='ContactListStateChanged', + args=[cs.CONTACT_LIST_STATE_SUCCESS], path=conn1.object.object_path) # Connection 2 conn2.Connect() @@ -54,16 +44,8 @@ def test(q, bus, conns, streams): args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED], path=conn2.object.object_path) - pairs = expect_contact_list_signals(q, bus, conn2, - ['publish', 'subscribe', 'stored']) - - check_contact_list_signals(q, bus, conn2, pairs.pop(0), cs.HT_LIST, - 'publish', []) - check_contact_list_signals(q, bus, conn2, pairs.pop(0), cs.HT_LIST, - 'subscribe', []) - check_contact_list_signals(q, bus, conn2, pairs.pop(0), cs.HT_LIST, - 'stored', []) - assertLength(0, pairs) # i.e. we popped and checked all of them + q.expect('dbus-signal', signal='ContactListStateChanged', + args=[cs.CONTACT_LIST_STATE_SUCCESS], path=conn2.object.object_path) if __name__ == '__main__': exec_test(test, num_instances=2, do_connect=False) diff --git a/tests/twisted/console.py b/tests/twisted/console.py index 95c76a30e..f92e57aa8 100644 --- a/tests/twisted/console.py +++ b/tests/twisted/console.py @@ -4,14 +4,14 @@ A smoketest for the XMPP console API. from servicetest import ( ProxyWrapper, EventPattern, - call_async, assertEquals, assertContains, assertNotEquals, sync_dbus, + call_async, assertEquals, assertNotEquals, assertContains, sync_dbus, ) from gabbletest import exec_test, acknowledge_iq, elem, elem_iq from config import PLUGINS_ENABLED -from twisted.words.xish import domish import ns +import constants as cs -CONSOLE_PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Console" +CONSOLE_PLUGIN_IFACE = cs.PREFIX + ".Gabble.Plugin.Console" STACY = 'stacy@pilgrim.lit' if not PLUGINS_ENABLED: @@ -27,9 +27,25 @@ def send_unrecognised_get(q, stream): return q.expect('stream-iq', iq_type='error') def test(q, bus, conn, stream): - path, _ = conn.Future.EnsureSidecar(CONSOLE_PLUGIN_IFACE) + rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS, + 'RequestableChannelClasses') + + fixed = { + cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE, + cs.TARGET_HANDLE_TYPE: cs.HT_NONE, + } + allowed = [] + assertContains((fixed, allowed), rccs) + + path, _ = conn.Requests.CreateChannel({ cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE }) + other_path, _ = conn.Requests.CreateChannel({ cs.CHANNEL_TYPE: CONSOLE_PLUGIN_IFACE }) + + assertNotEquals(path, other_path) + # leave the other one open, to test we don't crash on disconnect + console = ProxyWrapper(bus.get_object(conn.bus_name, path), - CONSOLE_PLUGIN_IFACE) + CONSOLE_PLUGIN_IFACE, + {'Channel': cs.CHANNEL}) assert not console.Properties.Get(CONSOLE_PLUGIN_IFACE, 'SpewStanzas') es = [ @@ -88,5 +104,7 @@ def test(q, bus, conn, stream): assertEquals('body', body.name) assertEquals(ns.CLIENT, body.uri) + console.Channel.Close() + if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py index d541c75fe..e21bc134a 100644 --- a/tests/twisted/constants.py +++ b/tests/twisted/constants.py @@ -1,10 +1,34 @@ +# Copyright (C) 2009 Nokia Corporation +# Copyright (C) 2009-2013 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 + """ Some handy constants for other tests to share and enjoy. """ -from dbus import PROPERTIES_IFACE +from dbus import PROPERTIES_IFACE, INTROSPECTABLE_IFACE + +PREFIX = "org.freedesktop.Telepathy" +PATH_PREFIX = '/' + PREFIX.replace('.', '/') + +tp_name_prefix = PREFIX +tp_path_prefix = PATH_PREFIX -CM = "org.freedesktop.Telepathy.ConnectionManager" +CM = PREFIX + ".ConnectionManager" HT_NONE = 0 HT_CONTACT = 1 @@ -12,7 +36,7 @@ HT_ROOM = 2 HT_LIST = 3 HT_GROUP = 4 -CHANNEL = "org.freedesktop.Telepathy.Channel" +CHANNEL = PREFIX + ".Channel" CHANNEL_IFACE_CALL_STATE = CHANNEL + ".Interface.CallState" CHANNEL_IFACE_CHAT_STATE = CHANNEL + '.Interface.ChatState' @@ -30,6 +54,7 @@ CHANNEL_IFACE_ROOM = CHANNEL + '.Interface.Room2' CHANNEL_IFACE_ROOM_CONFIG = CHANNEL + '.Interface.RoomConfig1' CHANNEL_IFACE_SUBJECT = CHANNEL + '.Interface.Subject2' CHANNEL_IFACE_FILE_TRANSFER_METADATA = CHANNEL + '.Interface.FileTransfer.Metadata' +CHANNEL_IFACE_SMS = CHANNEL + '.Interface.SMS' CHANNEL_TYPE_CALL = CHANNEL + ".Type.Call1" CHANNEL_TYPE_CONTACT_LIST = CHANNEL + ".Type.ContactList" @@ -38,15 +63,15 @@ CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text" CHANNEL_TYPE_TUBES = CHANNEL + ".Type.Tubes" CHANNEL_TYPE_STREAM_TUBE = CHANNEL + ".Type.StreamTube" CHANNEL_TYPE_DBUS_TUBE = CHANNEL + ".Type.DBusTube" -CHANNEL_TYPE_STREAMED_MEDIA = CHANNEL + ".Type.StreamedMedia" CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text" CHANNEL_TYPE_FILE_TRANSFER = CHANNEL + ".Type.FileTransfer" +CHANNEL_TYPE_ROOM_LIST = CHANNEL + ".Type.RoomList" CHANNEL_TYPE_SERVER_AUTHENTICATION = \ CHANNEL + ".Type.ServerAuthentication" CHANNEL_TYPE_SERVER_TLS_CONNECTION = \ CHANNEL + ".Type.ServerTLSConnection" -TP_AWKWARD_PROPERTIES = "org.freedesktop.Telepathy.Properties" +TP_AWKWARD_PROPERTIES = PREFIX + ".Properties" PROPERTY_FLAG_READ = 1 PROPERTY_FLAG_WRITE = 2 PROPERTY_FLAGS_RW = PROPERTY_FLAG_READ | PROPERTY_FLAG_WRITE @@ -60,30 +85,31 @@ INITIATOR_HANDLE = CHANNEL + '.InitiatorHandle' INITIATOR_ID = CHANNEL + '.InitiatorID' INTERFACES = CHANNEL + '.Interfaces' -INITIAL_AUDIO = CHANNEL_TYPE_STREAMED_MEDIA + '.InitialAudio' -INITIAL_VIDEO = CHANNEL_TYPE_STREAMED_MEDIA + '.InitialVideo' -IMMUTABLE_STREAMS = CHANNEL_TYPE_STREAMED_MEDIA + '.ImmutableStreams' - +CALL_CONTENTS = CHANNEL_TYPE_CALL + '.Contents' +CALL_CALL_STATE_DETAILS = CHANNEL_TYPE_CALL + '.CallStateDetails' +CALL_CALL_STATE = CHANNEL_TYPE_CALL + '.CallState' +CALL_CALL_FLAGS = CHANNEL_TYPE_CALL + '.CallFlags' +CALL_CALL_STATE_REASON = CHANNEL_TYPE_CALL + '.CallStateReason' +CALL_HARDWARE_STREAMING = CHANNEL_TYPE_CALL + '.HardwareStreaming' +CALL_CALL_MEMBERS = CHANNEL_TYPE_CALL + '.CallMembers' +CALL_MEMBER_IDENTIFIERS = CHANNEL_TYPE_CALL + '.MemberIdentifiers' +CALL_INITIAL_TRANSPORT = CHANNEL_TYPE_CALL + '.InitialTransport' CALL_INITIAL_AUDIO = CHANNEL_TYPE_CALL + '.InitialAudio' CALL_INITIAL_AUDIO_NAME = CHANNEL_TYPE_CALL + '.InitialAudioName' CALL_INITIAL_VIDEO = CHANNEL_TYPE_CALL + '.InitialVideo' CALL_INITIAL_VIDEO_NAME = CHANNEL_TYPE_CALL + '.InitialVideoName' CALL_MUTABLE_CONTENTS = CHANNEL_TYPE_CALL + '.MutableContents' -CALL_CONTENT = 'org.freedesktop.Telepathy.Call1.Content' -CALL_CONTENT_IFACE_MEDIA = \ - 'org.freedesktop.Telepathy.Call1.Content.Interface.Media' -CALL_CONTENT_IFACE_DTMF = \ - 'org.freedesktop.Telepathy.Call1.Content.Interface.DTMF' +CALL_CONTENT = PREFIX + '.Call1.Content' +CALL_CONTENT_IFACE_MEDIA = CALL_CONTENT + '.Interface.Media' +CALL_CONTENT_IFACE_DTMF = CALL_CONTENT + '.Interface.DTMF' -CALL_CONTENT_MEDIADESCRIPTION = \ - 'org.freedesktop.Telepathy.Call1.Content.MediaDescription' +CALL_CONTENT_MEDIA_DESCRIPTION = CALL_CONTENT + '.MediaDescription' -CALL_STREAM = 'org.freedesktop.Telepathy.Call1.Stream' -CALL_STREAM_IFACE_MEDIA = \ - 'org.freedesktop.Telepathy.Call1.Stream.Interface.Media' +CALL_STREAM = PREFIX + '.Call1.Stream' +CALL_STREAM_IFACE_MEDIA = CALL_STREAM + '.Interface.Media' -CALL_STREAM_ENDPOINT = 'org.freedesktop.Telepathy.Call1.Stream.Endpoint' +CALL_STREAM_ENDPOINT = CALL_STREAM + '.Endpoint' CALL_MEDIA_TYPE_AUDIO = 0 CALL_MEDIA_TYPE_VIDEO = 1 @@ -100,11 +126,7 @@ CALL_STREAM_TRANSPORT_WLM_2009 = 4 CALL_STREAM_TRANSPORT_SHM = 5 CALL_STREAM_TRANSPORT_MULTICAST = 6 -#for streamed media -CALL_STATE_RINGING = 1 -CALL_STATE_HELD = 4 - -CALL_STATE_UNKNOWN = 0, +CALL_STATE_UNKNOWN = 0 CALL_STATE_PENDING_INITIATOR = 1 CALL_STATE_INITIALISING = 2 CALL_STATE_INITIALISED = 3 @@ -174,7 +196,7 @@ CONTACT_LIST_STATE_WAITING = 1 CONTACT_LIST_STATE_FAILURE = 2 CONTACT_LIST_STATE_SUCCESS = 3 -CONN = "org.freedesktop.Telepathy.Connection" +CONN = PREFIX + ".Connection" CONN_IFACE_AVATARS = CONN + '.Interface.Avatars' CONN_IFACE_ALIASING = CONN + '.Interface.Aliasing' CONN_IFACE_CAPS = CONN + '.Interface.Capabilities' @@ -182,6 +204,8 @@ CONN_IFACE_CONTACTS = CONN + '.Interface.Contacts' CONN_IFACE_CONTACT_CAPS = CONN + '.Interface.ContactCapabilities' CONN_IFACE_CONTACT_INFO = CONN + ".Interface.ContactInfo" CONN_IFACE_PRESENCE = CONN + '.Interface.Presence' +CONN_IFACE_RENAMING = CONN + '.Interface.Renaming' +CONN_IFACE_SIDECARS1 = CONN + '.Interface.Sidecars1' CONN_IFACE_SIMPLE_PRESENCE = CONN + '.Interface.SimplePresence' CONN_IFACE_REQUESTS = CONN + '.Interface.Requests' CONN_IFACE_LOCATION = CONN + '.Interface.Location' @@ -193,12 +217,23 @@ CONN_IFACE_CLIENT_TYPES = CONN + '.Interface.ClientTypes' CONN_IFACE_POWER_SAVING = CONN + '.Interface.PowerSaving' CONN_IFACE_CONTACT_BLOCKING = CONN + '.Interface.ContactBlocking' CONN_IFACE_ADDRESSING = CONN + '.Interface.Addressing1' +CONN_IFACE_SERVICE_POINT = CONN + '.Interface.ServicePoint' +ATTR_ALIAS = CONN_IFACE_ALIASING + '/alias' +ATTR_AVATAR_TOKEN = CONN_IFACE_AVATARS + '/token' +ATTR_CLIENT_TYPES = CONN_IFACE_CLIENT_TYPES + '/client-types' ATTR_CONTACT_CAPABILITIES = CONN_IFACE_CONTACT_CAPS + '/capabilities' +ATTR_CONTACT_ID = CONN + '/contact-id' +ATTR_CONTACT_INFO = CONN_IFACE_CONTACT_INFO + '/info' +ATTR_GROUPS = CONN_IFACE_CONTACT_GROUPS + '/groups' +ATTR_LOCATION = CONN_IFACE_LOCATION + '/location' +ATTR_PRESENCE = CONN_IFACE_SIMPLE_PRESENCE + '/presence' +ATTR_PUBLISH = CONN_IFACE_CONTACT_LIST + '/publish' +ATTR_SUBSCRIBE = CONN_IFACE_CONTACT_LIST + '/subscribe' -STREAM_HANDLER = 'org.freedesktop.Telepathy.Media.StreamHandler' +STREAM_HANDLER = PREFIX + '.Media.StreamHandler' -ERROR = 'org.freedesktop.Telepathy.Error' +ERROR = PREFIX + '.Error' INVALID_ARGUMENT = ERROR + '.InvalidArgument' NOT_IMPLEMENTED = ERROR + '.NotImplemented' NOT_AVAILABLE = ERROR + '.NotAvailable' @@ -209,6 +244,7 @@ CONNECTION_REFUSED = ERROR + '.ConnectionRefused' CONNECTION_FAILED = ERROR + '.ConnectionFailed' CONNECTION_LOST = ERROR + '.ConnectionLost' CANCELLED = ERROR + '.Cancelled' +NOT_YOURS = ERROR + '.NotYours' DISCONNECTED = ERROR + '.Disconnected' REGISTRATION_EXISTS = ERROR + '.RegistrationExists' AUTHENTICATION_FAILED = ERROR + '.AuthenticationFailed' @@ -220,10 +256,12 @@ INVALID_HANDLE = ERROR + '.InvalidHandle' CERT_UNTRUSTED = ERROR + '.Cert.Untrusted' SERVICE_BUSY = ERROR + '.ServiceBusy' SERVICE_CONFUSED = ERROR + '.ServiceConfused' +SOFTWARE_UPGRADE_REQUIRED = ERROR + '.SoftwareUpgradeRequired' BANNED = ERROR + '.Channel.Banned' -UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod' +DBUS_ERROR_UNKNOWN_METHOD = 'org.freedesktop.DBus.Error.UnknownMethod' +DBUS_ERROR_NO_REPLY = 'org.freedesktop.DBus.Error.NoReply' TUBE_PARAMETERS = CHANNEL_IFACE_TUBE + '.Parameters' TUBE_STATE = CHANNEL_IFACE_TUBE + '.State' @@ -330,7 +368,7 @@ FT_DATE = CHANNEL_TYPE_FILE_TRANSFER + '.Date' FT_AVAILABLE_SOCKET_TYPES = CHANNEL_TYPE_FILE_TRANSFER + '.AvailableSocketTypes' FT_TRANSFERRED_BYTES = CHANNEL_TYPE_FILE_TRANSFER + '.TransferredBytes' FT_INITIAL_OFFSET = CHANNEL_TYPE_FILE_TRANSFER + '.InitialOffset' -FT_FILE_COLLECTION = CHANNEL_TYPE_FILE_TRANSFER + '.FUTURE.FileCollection' +FT_FILE_COLLECTION = CHANNEL_TYPE_FILE_TRANSFER + '.FileCollection' FT_URI = CHANNEL_TYPE_FILE_TRANSFER + '.URI' FT_SERVICE_NAME = CHANNEL_IFACE_FILE_TRANSFER_METADATA + '.ServiceName' FT_METADATA = CHANNEL_IFACE_FILE_TRANSFER_METADATA + '.Metadata' @@ -407,8 +445,9 @@ MEDIA_CAP_GTALKP2P = 8 MEDIA_CAP_ICEUDP = 16 MEDIA_CAP_IMMUTABLE_STREAMS = 32 -CLIENT = 'org.freedesktop.Telepathy.Client' +CLIENT = PREFIX + '.Client' +PRESENCE_UNSET = 0 PRESENCE_OFFLINE = 1 PRESENCE_AVAILABLE = 2 PRESENCE_AWAY = 3 @@ -477,9 +516,10 @@ class SendError(object): TOO_LONG = 4 NOT_IMPLEMENTED = 5 -PROTOCOL = 'org.freedesktop.Telepathy.Protocol' +PROTOCOL = PREFIX + '.Protocol' PROTOCOL_IFACE_PRESENCES = PROTOCOL + '.Interface.Presence' PROTOCOL_IFACE_ADDRESSING = PROTOCOL + '.Interface.Addressing' +PROTOCOL_IFACE_AVATARS = PROTOCOL + '.Interface.Avatars' PARAM_REQUIRED = 1 PARAM_REGISTER = 2 @@ -487,7 +527,7 @@ PARAM_HAS_DEFAULT = 4 PARAM_SECRET = 8 PARAM_DBUS_PROPERTY = 16 -AUTHENTICATION = 'org.freedesktop.Telepathy.Authentication' +AUTHENTICATION = PREFIX + '.Authentication' AUTH_TLS_CERT = AUTHENTICATION + ".TLSCertificate" TLS_CERT_STATE_PENDING = 0 @@ -539,3 +579,58 @@ ROOM_SERVER = CHANNEL_IFACE_ROOM + '.Server' SUBJECT = CHANNEL_IFACE_ROOM + '.Subject' SUBJECT_PRESENT = 1 SUBJECT_CAN_SET = 2 + +DEBUG_IFACE = PREFIX + '.Debug' +DEBUG_PATH = PATH_PREFIX + '/debug' + +SERVICE_POINT_TYPE_NONE = 0 +SERVICE_POINT_TYPE_EMERGENCY = 1 +SERVICE_POINT_TYPE_COUNSELING = 2 + +CLIENT = PREFIX + '.Client' +CLIENT_PATH = PATH_PREFIX + '/Client' +OBSERVER = PREFIX + '.Client.Observer' +APPROVER = PREFIX + '.Client.Approver' +HANDLER = PREFIX + '.Client.Handler' +CLIENT_IFACE_REQUESTS = CLIENT + '.Interface.Requests' + +ACCOUNT = PREFIX + '.Account' +ACCOUNT_IFACE_AVATAR = ACCOUNT + '.Interface.Avatar' +ACCOUNT_IFACE_ADDRESSING = ACCOUNT + '.Interface.Addressing' +ACCOUNT_IFACE_HIDDEN = ACCOUNT + '.Interface.Hidden.DRAFT1' +ACCOUNT_IFACE_NOKIA_CONDITIONS = 'com.nokia.Account.Interface.Conditions' +ACCOUNT_PATH_PREFIX = PATH_PREFIX + '/Account/' + +AM = PREFIX + '.AccountManager' +AM_IFACE_HIDDEN = AM + '.Interface.Hidden.DRAFT1' +AM_PATH = PATH_PREFIX + '/AccountManager' + +CR = PREFIX + '.ChannelRequest' +CDO = PREFIX + '.ChannelDispatchOperation' + +CD = PREFIX + '.ChannelDispatcher' +CD_IFACE_MESSAGES1 = PREFIX + '.ChannelDispatcher.Interface.Messages1' +CD_IFACE_OP_LIST = PREFIX + '.ChannelDispatcher.Interface.OperationList' +CD_PATH = PATH_PREFIX + '/ChannelDispatcher' +CD_REDISPATCH = CD + '.Interface.Redispatch.DRAFT' + +MC = PREFIX + '.MissionControl5' +MC_PATH = PATH_PREFIX + '/MissionControl5' + +DTMF_CURRENTLY_SENDING_TONES = CHANNEL_IFACE_DTMF + '.CurrentlySendingTones' +DTMF_INITIAL_TONES = CHANNEL_IFACE_DTMF + '.InitialTones' +DTMF_DEFERRED_TONES = CHANNEL_IFACE_DTMF + '.DeferredTones' + +TESTDOT = PREFIX + ".Test." +TESTSLASH = PATH_PREFIX + "/Test/" + +TEST_DBUS_ACCOUNT_SERVICE = TESTDOT + "DBusAccountService" +TEST_DBUS_ACCOUNT_SERVICE_PATH = TESTSLASH + "DBusAccountService" +TEST_DBUS_ACCOUNT_SERVICE_IFACE = TEST_DBUS_ACCOUNT_SERVICE + +TEST_DBUS_ACCOUNT_PLUGIN_PATH = TESTSLASH + "DBusAccountPlugin" +TEST_DBUS_ACCOUNT_PLUGIN_IFACE = TESTDOT + "DBusAccountPlugin" + +# Channel.Interface.SMS +SMS_FLASH = CHANNEL_IFACE_SMS + '.Flash' +SMS_CHANNEL = CHANNEL_IFACE_SMS + '.SMSChannel' diff --git a/tests/twisted/dataforms.py b/tests/twisted/dataforms.py index 6004c1516..87cb625b8 100644 --- a/tests/twisted/dataforms.py +++ b/tests/twisted/dataforms.py @@ -2,10 +2,8 @@ Test dataforms """ -from servicetest import sync_dbus, assertEquals -from gabbletest import exec_test, sync_stream -import ns -import constants as cs +from servicetest import assertEquals +from gabbletest import exec_test from caps_helper import receive_presence_and_ask_caps from config import VOIP_ENABLED diff --git a/tests/twisted/file-transfer/file_transfer_helper.py b/tests/twisted/file-transfer/file_transfer_helper.py index 79b3acf92..4fa915b5d 100644 --- a/tests/twisted/file-transfer/file_transfer_helper.py +++ b/tests/twisted/file-transfer/file_transfer_helper.py @@ -88,13 +88,13 @@ class FileTransferTest(object): announce_socks5_proxy(self.q, self.stream, disco_event.stanza) - self.self_handle = self.conn.GetSelfHandle() - self.self_handle_name = self.conn.InspectHandles(cs.HT_CONTACT, [self.self_handle])[0] + self.self_handle = self.conn.Properties.Get(cs.CONN, "SelfHandle") + self.self_handle_name = self.conn.inspect_contact_sync(self.self_handle) def announce_contact(self, name=CONTACT_NAME, metadata=True): self.contact_name = name self.contact_full_jid = '%s/Telepathy' % name - self.handle = self.conn.RequestHandles(cs.HT_CONTACT, [name])[0] + self.handle = self.conn.get_contact_handle_sync(name) presence = domish.Element(('jabber:client', 'presence')) presence['from'] = self.contact_full_jid @@ -216,11 +216,10 @@ class ReceiveFileTest(FileTransferTest): path, props = channels[0] # check channel properties - # org.freedesktop.Telepathy.Channel D-Bus properties + # Channel D-Bus properties assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER 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 @@ -229,7 +228,7 @@ class ReceiveFileTest(FileTransferTest): assert props[cs.INITIATOR_HANDLE] == self.handle assert props[cs.INITIATOR_ID] == self.contact_name - # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties + # Channel.Type.FileTransfer D-Bus properties assert props[cs.FT_STATE] == cs.FT_STATE_PENDING assert props[cs.FT_CONTENT_TYPE] == self.file.content_type assert props[cs.FT_FILENAME] == self.file.name @@ -334,7 +333,6 @@ class ReceiveFileTest(FileTransferTest): def _read_file_from_socket(self, s): # Read the file from Gabble's socket data = '' - read = 0 to_receive = self.file.size - self.file.offset e = self.q.expect('dbus-signal', signal='TransferredBytesChanged') @@ -409,11 +407,10 @@ class SendFileTest(FileTransferTest): self.ft_path, props = self.conn.Requests.CreateChannel(request) - # org.freedesktop.Telepathy.Channel D-Bus properties + # Channel D-Bus properties assertEquals(cs.CHANNEL_TYPE_FILE_TRANSFER, props[cs.CHANNEL_TYPE]) 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]) @@ -422,7 +419,7 @@ class SendFileTest(FileTransferTest): assertEquals(self.self_handle, props[cs.INITIATOR_HANDLE]) assertEquals(self.self_handle_name, props[cs.INITIATOR_ID]) - # org.freedesktop.Telepathy.Channel.Type.FileTransfer D-Bus properties + # Channel.Type.FileTransfer D-Bus properties assertEquals(cs.FT_STATE_PENDING, props[cs.FT_STATE]) assertEquals(self.file.content_type, props[cs.FT_CONTENT_TYPE]) assertEquals(self.file.name, props[cs.FT_FILENAME]) diff --git a/tests/twisted/file-transfer/ft-client-caps.py b/tests/twisted/file-transfer/ft-client-caps.py index 336d7a070..f8c65c940 100644 --- a/tests/twisted/file-transfer/ft-client-caps.py +++ b/tests/twisted/file-transfer/ft-client-caps.py @@ -36,18 +36,16 @@ make a FT service advertised as a cap. import dbus -from twisted.words.xish import xpath - from servicetest import assertEquals, assertLength, assertContains,\ assertDoesNotContain, sync_dbus -from gabbletest import exec_test, make_result_iq, sync_stream, make_presence +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, receive_presence_and_ask_caps,\ - caps_contain, ft_fixed_properties, ft_allowed_properties, ft_allowed_properties_with_metadata, \ - presence_and_disco + ft_fixed_properties, ft_allowed_properties, ft_allowed_properties_with_metadata, \ + presence_and_disco, get_contacts_capabilities_sync import ns from config import FILE_TRANSFER_ENABLED @@ -105,11 +103,11 @@ def receive_caps(q, conn, stream, contact, contact_handle, features, # Make sure Gabble's got the caps sync_stream(q, stream) - caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps[contact_handle]) # test again, to check GetContactCapabilities does not have side effect - caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assertSameElements(expected_caps, caps[contact_handle]) # check the Contacts interface give the same caps @@ -119,11 +117,11 @@ def receive_caps(q, conn, stream, contact, contact_handle, features, assertSameElements(caps[contact_handle], caps_via_contacts_iface) def test_ft_caps_from_contact(q, bus, conn, stream, contact): - contact_handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + contact_handle = conn.get_contact_handle_sync(contact) # Check that we don't crash if we haven't seen any caps/presence for this # contact yet. - caps = conn.ContactCapabilities.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) basic_caps = [(text_fixed_properties, text_allowed_properties)] @@ -179,7 +177,7 @@ def advertise_caps(q, bus, conn, stream, filters, expected_features, unexpected_ # make sure nothing from a previous update is still running sync_dbus(bus, q, conn) - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") ret_caps = conn.ContactCapabilities.UpdateCapabilities( [(cs.CLIENT + '.Foo', filters, [])]) @@ -197,7 +195,7 @@ def advertise_caps(q, bus, conn, stream, filters, expected_features, unexpected_ assertDoesNotContain(var, namespaces) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertSameElements(expected_caps, caps[self_handle]) # check the Contacts interface give the same caps @@ -207,7 +205,7 @@ def advertise_caps(q, bus, conn, stream, filters, expected_features, unexpected_ assertSameElements(caps[self_handle], caps_via_contacts_iface) def test_ft_caps_to_contact(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") basic_caps = [ (text_fixed_properties, text_allowed_properties), @@ -233,7 +231,7 @@ def test_ft_caps_to_contact(q, bus, conn, stream): # # Check our own caps; we should have no FT caps # - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertEquals(basic_caps, caps[self_handle]) # check the Contacts interface give the same caps @@ -249,7 +247,7 @@ def test_ft_caps_to_contact(q, bus, conn, stream): [(cs.CLIENT + '.Foo', {}, [])]) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(basic_caps, caps[self_handle]) @@ -268,7 +266,7 @@ def test_ft_caps_to_contact(q, bus, conn, stream): [(cs.CLIENT + '.Foo', [no_service_fixed_properties], [])]) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(simple_ft_caps, caps[self_handle]) @@ -287,7 +285,7 @@ def test_ft_caps_to_contact(q, bus, conn, stream): [(cs.CLIENT + '.Foo', [outgoing_daap_fixed_properties], [])]) # Check our own caps - caps = conn.ContactCapabilities.GetContactCapabilities([self_handle]) + caps = get_contacts_capabilities_sync(conn, [self_handle]) assertLength(1, caps) assertEquals(simple_ft_caps, caps[self_handle]) diff --git a/tests/twisted/file-transfer/metadata.py b/tests/twisted/file-transfer/metadata.py index 8667a9caa..337e90c1a 100644 --- a/tests/twisted/file-transfer/metadata.py +++ b/tests/twisted/file-transfer/metadata.py @@ -3,7 +3,7 @@ import dbus from file_transfer_helper import exec_file_transfer_test, ReceiveFileTest, SendFileTest -from servicetest import assertEquals, call_async +from servicetest import call_async import constants as cs diff --git a/tests/twisted/file-transfer/test-caps-file-transfer.py b/tests/twisted/file-transfer/test-caps-file-transfer.py index 743906af0..c7d6c9b30 100644 --- a/tests/twisted/file-transfer/test-caps-file-transfer.py +++ b/tests/twisted/file-transfer/test-caps-file-transfer.py @@ -2,14 +2,12 @@ import dbus from twisted.words.xish import xpath -from servicetest import assertEquals from gabbletest import exec_test, make_result_iq, sync_stream, make_presence 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 caps_helper import (compute_caps_hash, text_fixed_properties, + text_allowed_properties, ft_fixed_properties, ft_allowed_properties, + get_contacts_capabilities_sync) import ns @@ -50,10 +48,10 @@ def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, cli # no special capabilities basic_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties)]}) - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # test again, to check GetContactCapabilities does not have side effect - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( @@ -92,10 +90,10 @@ def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, cli assert len(event.args) == 1 assert event.args[0] == generic_tubes_caps - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_tubes_caps, caps # test again, to check GetContactCapabilities does not have side effect - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_tubes_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( diff --git a/tests/twisted/file-transfer/test-ibb-too-early.py b/tests/twisted/file-transfer/test-ibb-too-early.py index a5a8d97b8..51b0e46d9 100644 --- a/tests/twisted/file-transfer/test-ibb-too-early.py +++ b/tests/twisted/file-transfer/test-ibb-too-early.py @@ -25,7 +25,7 @@ class IbbTooEarlyTest (ReceiveFileTest): # Instead of us accepting the other side starts sending the iq open # skip the open step explicitely self.bytestream.checked = True - event = self.bytestream.open_bytestream( + self.bytestream.open_bytestream( expected_after = [ EventPattern ('stream-iq', iq_type = 'error') ] ) return True diff --git a/tests/twisted/file-transfer/test-send-file-declined.py b/tests/twisted/file-transfer/test-send-file-declined.py index f2e79ab9c..89b865df1 100644 --- a/tests/twisted/file-transfer/test-send-file-declined.py +++ b/tests/twisted/file-transfer/test-send-file-declined.py @@ -24,8 +24,8 @@ class SendFileDeclinedTest(SendFileTest): error = reply.addElement((None, 'error')) error['code'] = '403' error['type'] = 'cancel' - forbidden = error.addElement((ns.STANZA, 'forbidden')) - text = error.addElement((ns.STANZA, 'text'), content='Offer Declined') + error.addElement((ns.STANZA, 'forbidden')) + error.addElement((ns.STANZA, 'text'), content='Offer Declined') self.stream.send(reply) e = self.q.expect('dbus-signal', signal='FileTransferStateChanged') diff --git a/tests/twisted/file-transfer/test-send-file-send-before-accept.py b/tests/twisted/file-transfer/test-send-file-send-before-accept.py index bb1389477..491e86fdc 100644 --- a/tests/twisted/file-transfer/test-send-file-send-before-accept.py +++ b/tests/twisted/file-transfer/test-send-file-send-before-accept.py @@ -1,11 +1,7 @@ -import dbus import constants as cs from servicetest import EventPattern from file_transfer_helper import SendFileTest, exec_file_transfer_test -from twisted.words.xish import domish -import ns - from config import FILE_TRANSFER_ENABLED if not FILE_TRANSFER_ENABLED: diff --git a/tests/twisted/file-transfer/test-send-file-to-unknown-contact.py b/tests/twisted/file-transfer/test-send-file-to-unknown-contact.py index 17d0799ed..dc1d691c2 100644 --- a/tests/twisted/file-transfer/test-send-file-to-unknown-contact.py +++ b/tests/twisted/file-transfer/test-send-file-to-unknown-contact.py @@ -17,7 +17,7 @@ class SendFileTransferToUnknownContactTest(SendFileTest): def my_request_ft_channel(self): self.contact_name = 'jean@localhost' - self.handle = self.conn.RequestHandles(cs.HT_CONTACT, [self.contact_name])[0] + self.handle = self.conn.get_contact_handle_sync(self.contact_name) try: self.request_ft_channel() diff --git a/tests/twisted/gabbletest.py b/tests/twisted/gabbletest.py index e6b8baa0e..fe2ce6637 100644 --- a/tests/twisted/gabbletest.py +++ b/tests/twisted/gabbletest.py @@ -57,11 +57,6 @@ def send_error_reply(stream, iq, error_stanza=None): stream.send(result) -def request_muc_handle(q, conn, stream, muc_jid): - servicetest.call_async(q, conn, 'RequestHandles', 2, [muc_jid]) - event = q.expect('dbus-return', method='RequestHandles') - return event.value[0][0] - def make_muc_presence(affiliation, role, muc_jid, alias, jid=None, photo=None): presence = domish.Element((None, 'presence')) presence['from'] = '%s/%s' % (muc_jid, alias) @@ -682,7 +677,7 @@ def exec_test_deferred(fun, params, protocol=None, timeout=None, # Connection has already been disconnected and destroyed continue try: - if conn.GetStatus() == cs.CONN_STATUS_CONNECTED: + if conn.Properties.Get(cs.CONN, 'Status') == cs.CONN_STATUS_CONNECTED: # Connection is connected, properly disconnect it disconnect_conn(queue, conn, streams[i]) else: diff --git a/tests/twisted/gateways.py b/tests/twisted/gateways.py index d4073dd25..ebe1b2ef7 100644 --- a/tests/twisted/gateways.py +++ b/tests/twisted/gateways.py @@ -5,18 +5,13 @@ Test the gateways plugin import dbus from twisted.words.xish import domish, xpath -from servicetest import ( - sync_dbus, call_async, EventPattern, assertEquals, assertContains, - ) -from gabbletest import ( - exec_test, send_error_reply, acknowledge_iq, sync_stream, - make_presence, - ) +from servicetest import call_async, EventPattern, assertEquals +from gabbletest import exec_test, send_error_reply, acknowledge_iq, make_presence import constants as cs import ns from config import PLUGINS_ENABLED -PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Gateways" +PLUGIN_IFACE = cs.PREFIX + ".Gabble.Plugin.Gateways" if not PLUGINS_ENABLED: print "NOTE: built without --enable-plugins, not testing plugins" @@ -68,7 +63,7 @@ def test_not_acceptable(q, gateways_iface, stream): def test(q, bus, conn, stream): # Request a sidecar thate we support before we're connected; it should just # wait around until we're connected. - call_async(q, conn.Future, 'EnsureSidecar', PLUGIN_IFACE) + call_async(q, conn.Sidecars1, 'EnsureSidecar', PLUGIN_IFACE) conn.Connect() q.expect('dbus-signal', signal='StatusChanged', diff --git a/tests/twisted/jingle-share/file_transfer_helper.py b/tests/twisted/jingle-share/file_transfer_helper.py index 19a45ca57..07119d443 100644 --- a/tests/twisted/jingle-share/file_transfer_helper.py +++ b/tests/twisted/jingle-share/file_transfer_helper.py @@ -2,23 +2,20 @@ import dbus import socket import hashlib import time -import datetime from servicetest import EventPattern, assertEquals, assertLength, assertSameSets -from gabbletest import exec_test, sync_stream, make_result_iq, elem_iq, elem +from gabbletest import exec_test, elem_iq, elem import ns from caps_helper import 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, compute_caps_hash, \ - extract_disco_parts + extract_disco_parts, get_contacts_capabilities_sync from twisted.words.xish import domish, xpath import constants as cs -import sys - class File(object): DEFAULT_DATA = "What a nice file" @@ -77,12 +74,12 @@ class FileTransferTest(object): args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED], path=self.conn.object.object_path) - self.self_handle = self.conn.GetSelfHandle() - self.self_handle_name = self.conn.InspectHandles(cs.HT_CONTACT, [self.self_handle])[0] + self.self_handle = self.conn.Properties.Get(cs.CONN, "SelfHandle") + self.self_handle_name = self.conn.inspect_contact_sync(self.self_handle) def set_target(self, jid): self.target = jid - self.handle = self.conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + self.handle = self.conn.get_contact_handle_sync(jid) def set_ft_caps(self): caps_iface = dbus.Interface(self.conn, cs.CONN_IFACE_CONTACT_CAPS) @@ -95,15 +92,13 @@ class FileTransferTest(object): args=[{self.self_handle:generic_ft_caps}]) def wait_for_ft_caps(self): - conn_caps_iface = dbus.Interface(self.conn, cs.CONN_IFACE_CONTACT_CAPS) - - caps = conn_caps_iface.GetContactCapabilities([self.handle]) + caps = get_contacts_capabilities_sync(self.conn, [self.handle]) if caps != dbus.Dictionary({self.handle:generic_ft_caps}): self.q.expect('dbus-signal', signal='ContactCapabilitiesChanged', path=self.conn.object.object_path, args=[{self.handle:generic_ft_caps}]) - caps = conn_caps_iface.GetContactCapabilities([self.handle]) + caps = get_contacts_capabilities_sync(self.conn, [self.handle]) assert caps == dbus.Dictionary({self.handle:generic_ft_caps}), caps def create_ft_channel(self): @@ -275,7 +270,6 @@ class ReceiveFileTest(FileTransferTest): assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, 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 @@ -430,7 +424,6 @@ class SendFileTest(FileTransferTest): assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER 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 diff --git a/tests/twisted/jingle-share/jingleshareutils.py b/tests/twisted/jingle-share/jingleshareutils.py index 6ade4f50d..21030dc4d 100644 --- a/tests/twisted/jingle-share/jingleshareutils.py +++ b/tests/twisted/jingle-share/jingleshareutils.py @@ -2,13 +2,13 @@ import dbus from twisted.words.xish import xpath -from servicetest import (assertEquals, EventPattern) -from gabbletest import exec_test, make_result_iq, sync_stream, make_presence +from servicetest import (assertEquals) +from gabbletest import make_result_iq, sync_stream, make_presence import constants as cs from caps_helper import compute_caps_hash, \ text_fixed_properties, text_allowed_properties, \ - ft_fixed_properties, ft_allowed_properties + ft_fixed_properties, ft_allowed_properties, get_contacts_capabilities_sync import ns @@ -47,10 +47,10 @@ def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, cli # no special capabilities basic_caps = dbus.Dictionary({contact_handle: [(text_fixed_properties, text_allowed_properties)]}) - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # test again, to check GetContactCapabilities does not have side effect - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == basic_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( @@ -89,10 +89,10 @@ def test_ft_caps_from_contact(q, bus, conn, stream, contact, contact_handle, cli assert len(event.args) == 1 assert event.args[0] == generic_ft_caps - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_ft_caps, caps # test again, to check GetContactCapabilities does not have side effect - caps = conn_caps_iface.GetContactCapabilities([contact_handle]) + caps = get_contacts_capabilities_sync(conn, [contact_handle]) assert caps == generic_ft_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( diff --git a/tests/twisted/jingle-share/test-caps-file-transfer.py b/tests/twisted/jingle-share/test-caps-file-transfer.py index 0bf869a1a..f3be084ed 100644 --- a/tests/twisted/jingle-share/test-caps-file-transfer.py +++ b/tests/twisted/jingle-share/test-caps-file-transfer.py @@ -2,15 +2,16 @@ import dbus from twisted.words.xish import xpath -from servicetest import (assertEquals, EventPattern) -from gabbletest import exec_test, make_result_iq, sync_stream, make_presence +from servicetest import EventPattern +from gabbletest import exec_test import constants as cs -from caps_helper import compute_caps_hash, \ +from caps_helper import \ 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_with_metadata + ft_fixed_properties, ft_allowed_properties_with_metadata,\ + get_contacts_capabilities_sync import ns from jingleshareutils import test_ft_caps_from_contact @@ -43,7 +44,6 @@ generic_caps = [(text_fixed_properties, text_allowed_properties), (dbus_tube_fixed_properties, dbus_tube_allowed_properties)] def check_contact_caps(conn, handle, with_ft): - conn_caps_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACT_CAPS) conn_contacts_iface = dbus.Interface(conn, cs.CONN_IFACE_CONTACTS) if with_ft: @@ -51,7 +51,7 @@ def check_contact_caps(conn, handle, with_ft): else: expected_caps = dbus.Dictionary({handle: generic_caps}) - caps = conn_caps_iface.GetContactCapabilities([handle]) + caps = get_contacts_capabilities_sync(conn, [handle]) assert caps == expected_caps, caps # check the Contacts interface give the same caps caps_via_contacts_iface = conn_contacts_iface.GetContactAttributes( @@ -65,11 +65,11 @@ def test2(q, bus, connections, streams): conn1, conn2 = connections stream1, stream2 = streams conn1_handle = conn1.Properties.Get(cs.CONN, 'SelfHandle') - conn1_jid = conn1.InspectHandles(cs.HT_CONTACT, [conn1_handle])[0] + conn1_jid = conn1.inspect_contact_sync(conn1_handle) conn2_handle = conn2.Properties.Get(cs.CONN, 'SelfHandle') - conn2_jid = conn2.InspectHandles(cs.HT_CONTACT, [conn2_handle])[0] - handle1 = conn2.RequestHandles(cs.HT_CONTACT, [conn1_jid])[0] - handle2 = conn1.RequestHandles(cs.HT_CONTACT, [conn2_jid])[0] + conn2_jid = conn2.inspect_contact_sync(conn2_handle) + handle1 = conn2.get_contact_handle_sync(conn1_jid) + handle2 = conn1.get_contact_handle_sync(conn2_jid) q.expect_many(EventPattern('dbus-signal', signal='ContactCapabilitiesChanged', diff --git a/tests/twisted/jingle-share/test-multift.py b/tests/twisted/jingle-share/test-multift.py index d318e427d..889e6aeca 100644 --- a/tests/twisted/jingle-share/test-multift.py +++ b/tests/twisted/jingle-share/test-multift.py @@ -25,8 +25,8 @@ def test(q, bus, conn, stream): test_ft_caps_from_contact(q, bus, conn, stream, contact, 2L, client) - self_handle = conn.GetSelfHandle() - jid = conn.InspectHandles(cs.HT_CONTACT, [self_handle])[0] + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") + jid = conn.inspect_contact_sync(self_handle) iq = IQ(stream, "set") iq['to'] = jid @@ -59,17 +59,46 @@ def test(q, bus, conn, stream): url['name'] = 'preview-path' stream.send(iq) - event = q.expect('dbus-signal', signal="NewChannels") - channels = event.args[0] - # Make sure we get the right amout of channels - assert len(channels) == len(files) + patterns = [] + found = {} + + def get_predicate(name, found, i): + # This needs to be a function so that name, found, i + # are part of a closure. + + # /!\ This predicate has side-effects: it writes to 'found' + def predicate(e): + path, props = e.args[0][0] + if props[cs.CHANNEL_TYPE] != cs.CHANNEL_TYPE_FILE_TRANSFER: + return False + + if props[cs.FT_FILENAME] == name: + found[i] = (path, props) + return True + return predicate + + for i, f in enumerate(files): + type, name, size, image = f + if type == "folder": + name = "%s.tar" % name + + return False + + patterns.append(EventPattern('dbus-signal', + signal='NewChannels', + predicate=get_predicate(name, found, i))) # Make sure every file transfer has a channel associated with it - found = [False for i in files] file_collection = None - for channel in channels: - path, props = channel + q.expect_many(*patterns) + assertLength(len(files), found) + + channels = [] + for i in found: + assert found[i] is not None + path, props = found[i] + channels.append((path, props)) # Get the FileCollection and make sure it exists if file_collection is None: @@ -80,22 +109,15 @@ def test(q, bus, conn, stream): # FileCollection must be the same for every channel assert props[cs.FT_FILE_COLLECTION] == file_collection, props - for i, f in enumerate(files): - type, name, size, image = f - if type == "folder": - name = "%s.tar" % name - if size is None: - size = 0 + type, name, size, image = files[i] + if size is None: + size = 0 - if props[cs.FT_FILENAME].encode('utf=8') == name: - assert found[i] == False - found[i] = True - assert props[cs.FT_SIZE] == size, props + assertEquals(size, props[cs.FT_SIZE]) assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_FILE_TRANSFER, 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 @@ -118,8 +140,6 @@ def test(q, bus, conn, stream): assert props[cs.FT_TRANSFERRED_BYTES] == 0, props assert props[cs.FT_INITIAL_OFFSET] == 0, props - assert False not in found - event = q.expect('stream-iq', to=contact, iq_type='set', query_name='session') session_node = event.query diff --git a/tests/twisted/jingle/accept-extra-stream.py b/tests/twisted/jingle/accept-extra-stream.py deleted file mode 100644 index 95e46377c..000000000 --- a/tests/twisted/jingle/accept-extra-stream.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -Test that we can accept streams added after the call has been accepted. -""" - -from servicetest import ( - make_channel_proxy, EventPattern, sync_dbus, call_async, - assertEquals, - ) -from gabbletest import exec_test, make_result_iq, sync_stream -import constants as cs - -from jingletest2 import JingleProtocol031, JingleTest2 - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream): - worker(q, bus, conn, stream, remote_jid='foo@bar.com/Foo') - -def test_bare_jid(q, bus, conn, stream): - worker(q, bus, conn, stream, remote_jid='foo@sip.bar.com') - -def worker(q, bus, conn, stream, remote_jid): - jp = JingleProtocol031() - jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - jt2.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [jt2.peer])[0] - - # Remote end calls us - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'session-initiate', [ - jp.Content('audiostream', 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.audio_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - nc = q.expect('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args) - path, ct, ht, h, sh = nc.args - assert ct == cs.CHANNEL_TYPE_STREAMED_MEDIA, ct - assert ht == cs.HT_CONTACT, ht - assert h == remote_handle, h - - group = make_channel_proxy(conn, path, 'Channel.Interface.Group') - sm = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - ms = make_channel_proxy(conn, path, 'Channel.Interface.MediaSignalling') - - streams = sm.ListStreams() - assert len(streams) == 1, streams - audio_stream_id, h, media_type, state, direction, pending = streams[0] - assert h == remote_handle, (h, remote_handle) - assert media_type == cs.MEDIA_STREAM_TYPE_AUDIO, media_type - assert state == cs.MEDIA_STREAM_STATE_DISCONNECTED, state - # FIXME: This turns out to be Bidirectional; wjt thinks this sounds wrong - # since the stream is (we hope) pending local send. - #assert direction == cs.MEDIA_STREAM_DIRECTION_RECEIVE, direction - assert pending == cs.MEDIA_STREAM_PENDING_LOCAL_SEND, pending - - session_handlers = ms.GetSessionHandlers() - assert len(session_handlers) == 1, session_handlers - session_handler = make_channel_proxy(conn, session_handlers[0][0], - 'Media.SessionHandler') - session_handler.Ready() - - nsh = q.expect('dbus-signal', signal='NewStreamHandler') - stream_handler_path, stream_id, media_type, direction = nsh.args - assert stream_id == audio_stream_id, (stream_id, audio_stream_id) - assert media_type == cs.MEDIA_STREAM_TYPE_AUDIO, media_type - # FIXME: As above - #assert direction == cs.MEDIA_STREAM_DIRECTION_RECEIVE, direction - - stream_handler = make_channel_proxy(conn, stream_handler_path, - 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(jt2.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - stream_handler.SupportedCodecs(jt2.get_audio_codecs_dbus()) - - # peer gets the transport - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - assertEquals(jt2.peer, e.query['initiator']) - - stream.send(make_result_iq(stream, e.stanza)) - - # Make sure all the above's happened. - sync_stream(q, stream) - sync_dbus(bus, q, conn) - - # At last, accept the call - group.AddMembers([self_handle], 'accepted') - - # Call is accepted, we become a member, and the stream that was pending - # local send is now sending. - memb, acc, _, _, _, = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [self_handle], [], [], [], - self_handle, - cs.GC_REASON_NONE]), - EventPattern('stream-iq', - predicate=lambda e: (e.query.name == 'jingle' and - e.query['action'] == 'session-accept')), - EventPattern('dbus-signal', signal='SetStreamSending', args=[True]), - EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]), - EventPattern('dbus-signal', signal='StreamDirectionChanged', - args=[audio_stream_id, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]), - ) - - # Respond to session-accept - # FIXME: wjt thinks Gabble should accept the content-add without this. - stream.send(jp.xml(jp.ResultIq('test@localhost', acc.stanza, []))) - - # Foo would like to gaze upon our beautiful complexion - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-add', [ - jp.Content('videostream', 'initiator', 'both', - jp.Description('video', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.video_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - added, nsh = q.expect_many( - EventPattern('dbus-signal', signal='StreamAdded'), - EventPattern('dbus-signal', signal='NewStreamHandler'), - ) - - video_stream_id, h, type = added.args - assert h == remote_handle, (h, remote_handle) - assert type == cs.MEDIA_STREAM_TYPE_VIDEO, type - - stream_handler_path, stream_id, media_type, direction = nsh.args - assert stream_id == video_stream_id, (stream_id, video_stream_id) - assert media_type == cs.MEDIA_STREAM_TYPE_VIDEO, type - # FIXME: As above - #assert direction == cs.MEDIA_STREAM_DIRECTION_RECEIVE, direction - - video_handler = make_channel_proxy(conn, stream_handler_path, - 'Media.StreamHandler') - - video_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - video_handler.Ready(jt2.get_video_codecs_dbus()) - video_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - video_handler.SupportedCodecs(jt2.get_video_codecs_dbus()) - - ti, _, _, _ = q.expect_many( - # Peer gets the transport - EventPattern('stream-iq', - predicate=jp.action_predicate('transport-info')), - # Gabble tells the peer we accepted - EventPattern('stream-iq', - predicate=jp.action_predicate('content-accept')), - EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]), - # It's not entirely clear that this *needs* to fire here... - EventPattern('dbus-signal', signal='SetStreamSending', args=[False]), - ) - assertEquals(jt2.peer, ti.query['initiator']) - - stream.send(make_result_iq(stream, e.stanza)) - - # Okay, so now the stream's playing but not sending, and we should be still - # pending local send: - streams = sm.ListStreams() - assert len(streams) == 2, streams - video_streams = [s for s in streams if s[2] == cs.MEDIA_STREAM_TYPE_VIDEO] - assert len(video_streams) == 1, streams - stream_id, h, _, state, direction, pending = video_streams[0] - assert stream_id == video_stream_id, (stream_id, video_stream_id) - assert h == remote_handle, (h, remote_handle) - assert state == cs.MEDIA_STREAM_STATE_CONNECTED, state - assert direction == cs.MEDIA_STREAM_DIRECTION_RECEIVE, direction - assert pending == cs.MEDIA_STREAM_PENDING_LOCAL_SEND, pending - - # Let's accept the stream; the direction should change, and we should be - # told to start sending. - call_async(q, sm, 'RequestStreamDirection', video_stream_id, - cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL) - - # The stream's direction should change, and we should be told to start - # playing. - q.expect_many( - EventPattern('dbus-signal', signal='StreamDirectionChanged', - args=[video_stream_id, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]), - EventPattern('dbus-signal', signal='SetStreamSending', args=[True]), - ) - - # That'll do, pig. That'll do. - -if __name__ == '__main__': - exec_test(test) - exec_test(test_bare_jid) diff --git a/tests/twisted/jingle/call-basics.py b/tests/twisted/jingle/call-basics.py index a044f83bc..68d8182bb 100644 --- a/tests/twisted/jingle/call-basics.py +++ b/tests/twisted/jingle/call-basics.py @@ -4,10 +4,6 @@ Test basic outgoing and incoming call handling import config -if not config.CHANNEL_TYPE_CALL_ENABLED: - print "NOTE: built with --disable-channel-type-call" - raise SystemExit(77) - import dbus from dbus.exceptions import DBusException diff --git a/tests/twisted/jingle/call-codecoffer.py b/tests/twisted/jingle/call-codecoffer.py index 91821721e..987ebf3b4 100644 --- a/tests/twisted/jingle/call-codecoffer.py +++ b/tests/twisted/jingle/call-codecoffer.py @@ -13,11 +13,7 @@ import constants as cs from jingletest2 import JingleTest2, test_dialects, JingleProtocol031 -from config import CHANNEL_TYPE_CALL_ENABLED, VOIP_ENABLED - -if not CHANNEL_TYPE_CALL_ENABLED: - print "NOTE: built with --disable-channel-type-call" - raise SystemExit(77) +from config import VOIP_ENABLED if not VOIP_ENABLED: print "NOTE: built with --disable-voip" @@ -30,10 +26,10 @@ def check_offer (bus, conn, content): assertNotEquals ("/", path) offer = bus.get_object (conn.bus_name, path) - md_property = offer.Get (cs.CALL_CONTENT_MEDIADESCRIPTION, + md_property = offer.Get (cs.CALL_CONTENT_MEDIA_DESCRIPTION, "Codecs", dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals (md[cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"], md_property) + assertEquals (md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"], md_property) def accept_offer (q, bus, conn, self_handle, remote_handle, content, md_props, offer_path = None, @@ -43,19 +39,19 @@ def accept_offer (q, bus, conn, self_handle, remote_handle, offer = bus.get_object (conn.bus_name, path) - offer.Accept (md_props, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept (md_props, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) current_mds = content.Get (cs.CALL_CONTENT_IFACE_MEDIA, "RemoteMediaDescriptions", dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals (md_props[cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs'], - current_mds[remote_handle][cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs']) + assertEquals (md_props[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs'], + current_mds[remote_handle][cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs']) if codecs_changed: o = q.expect ('dbus-signal', signal='RemoteMediaDescriptionsChanged') - assertEquals (md_props[cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs'], - o.args[0][remote_handle][cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs']) + assertEquals (md_props[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs'], + o.args[0][remote_handle][cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs']) def reject_offer (q, bus, conn, content, codecs, offer_path = None): @@ -64,7 +60,7 @@ def reject_offer (q, bus, conn, offer = bus.get_object (conn.bus_name, path) - offer.Reject ((0, 0, "", ""), dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Reject ((0, 0, "", ""), dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) def update_codecs(jt2): contents = jt2.generate_contents() @@ -80,8 +76,8 @@ def prepare_test(jp, q, bus, conn, stream): jt2.prepare() - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(1, ["foo@bar.com/Foo"])[0] + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") + remote_handle = conn.get_contact_handle_sync("foo@bar.com/Foo") # Advertise that we can do new style calls conn.ContactCapabilities.UpdateCapabilities([ @@ -102,7 +98,7 @@ def prepare_test(jp, q, bus, conn, stream): def try_to_access_old_offer(conn, path): try: offer = bus.get_object (conn.bus_name, path) - ret = offer.GetAll (cs.CALL_CONTENT_MEDIADESCRIPTION, + ret = offer.GetAll (cs.CALL_CONTENT_MEDIA_DESCRIPTION, dbus_interface=dbus.PROPERTIES_IFACE) except Exception, e: pass @@ -186,7 +182,7 @@ def test_outgoing(jp, q, bus, conn, stream): chan = bus.get_object(conn.bus_name, ret[0].args[0][0][0]) # there is no remote codec information, so this should be empty - assertEquals(ret[1].args[1][cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"], []) + assertEquals(ret[1].args[1][cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"], []) # get a list of audio codecs we can support md = jt2.get_call_audio_md_dbus(remote_handle) @@ -212,13 +208,13 @@ def test_outgoing(jp, q, bus, conn, stream): # make an offer they can't refuse offer = bus.get_object(conn.bus_name, ret[1].args[0]) - props = offer.GetAll(cs.CALL_CONTENT_MEDIADESCRIPTION, + props = offer.GetAll(cs.CALL_CONTENT_MEDIA_DESCRIPTION, dbus_interface=dbus.PROPERTIES_IFACE) # this also needs to be empty assertEquals(props["Codecs"], []) - offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) o = q.expect('dbus-signal', signal='RemoteMediaDescriptionsChanged') @@ -264,17 +260,17 @@ def test_outgoing(jp, q, bus, conn, stream): ret = q.expect('dbus-signal', signal='NewMediaDescriptionOffer') # make sure the codec offer has the updated codecs - assertEquals(ret.args[1][cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"], - md[cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"][:-1]) + assertEquals(ret.args[1][cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"], + md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"][:-1]) # accept new offer offer = bus.get_object(conn.bus_name, ret.args[0]) - md[cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"].pop() - offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"].pop() + offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) # now we should both have the smaller set of codecs, easy o = q.expect ('dbus-signal', signal='RemoteMediaDescriptionsChanged') - assertEquals (md[cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"], o.args[0][remote_handle][cs.CALL_CONTENT_MEDIADESCRIPTION + ".Codecs"]) + assertEquals (md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"], o.args[0][remote_handle][cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs"]) chan.Close(dbus_interface=cs.CHANNEL) signal = q.expect('dbus-signal', signal='ChannelClosed') diff --git a/tests/twisted/jingle/call-google-relay.py b/tests/twisted/jingle/call-google-relay.py index 85168f5d9..c9acbb0ef 100644 --- a/tests/twisted/jingle/call-google-relay.py +++ b/tests/twisted/jingle/call-google-relay.py @@ -259,7 +259,7 @@ class CallGoogleRelayTest(CallTest): except dbus.DBusException, e: # This should fail because the object's gone away, not because # Gabble's crashed. - assert cs.UNKNOWN_METHOD == e.get_dbus_name(), \ + assert cs.DBUS_ERROR_UNKNOWN_METHOD == e.get_dbus_name(), \ "maybe Gabble crashed? %s" % e else: # Gabble will probably also crash in a moment, because the http diff --git a/tests/twisted/jingle/call-hold-av.py b/tests/twisted/jingle/call-hold-av.py index 441a453cf..82f0b0987 100644 --- a/tests/twisted/jingle/call-hold-av.py +++ b/tests/twisted/jingle/call-hold-av.py @@ -62,7 +62,7 @@ class CallHoldAVTest(CallTest): [path, _] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, "MediaDescriptionOffer", dbus_interface=dbus.PROPERTIES_IFACE) offer = bus.get_object (conn.bus_name, path) - offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, cstream.Get(cs.CALL_STREAM_IFACE_MEDIA, 'SendingState', @@ -104,7 +104,7 @@ class CallHoldAVTest(CallTest): [path, _] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, "MediaDescriptionOffer", dbus_interface=dbus.PROPERTIES_IFACE) offer = bus.get_object (conn.bus_name, path) - offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, cstream.Get(cs.CALL_STREAM_IFACE_MEDIA, 'SendingState', diff --git a/tests/twisted/jingle/call-muc.py b/tests/twisted/jingle/call-muc.py index 715a3e248..f82c07eee 100644 --- a/tests/twisted/jingle/call-muc.py +++ b/tests/twisted/jingle/call-muc.py @@ -35,7 +35,7 @@ def run_incoming_test(q, bus, conn, stream, bob_leaves_room = False): jt.prepare() forbidden = [ no_muji_presences (muc) ] - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") _, _, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) @@ -173,7 +173,7 @@ def run_outgoing_test(q, bus, conn, stream, close_channel=False): jt = JingleTest2(jp, conn, q, stream, 'test@localhost', muc + '/bob') jt.prepare() - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # Not allowed to have muji related presences before we accept the channel forbidden = [ no_muji_presences (muc) ] @@ -231,7 +231,7 @@ def run_outgoing_test(q, bus, conn, stream, close_channel=False): e = q.expect('dbus-signal', signal = 'NewMediaDescriptionOffer') offer = bus.get_object (conn.bus_name, e.args[0]) - offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) jt.incoming_call(audio = "Audio") diff --git a/tests/twisted/jingle/call-state.py b/tests/twisted/jingle/call-state.py deleted file mode 100644 index b4d749b83..000000000 --- a/tests/twisted/jingle/call-state.py +++ /dev/null @@ -1,288 +0,0 @@ -""" -Test exposing incoming <hold/>, <ringing/> and <active/> notifications via the -CallState interface. -""" - -from twisted.words.xish import xpath - -from gabbletest import make_result_iq -from servicetest import ( - wrap_channel, make_channel_proxy, EventPattern, sync_dbus) -import ns -import constants as cs - -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(jp, q, bus, conn, stream): - remote_jid = 'foo@bar.com/Foo' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - - jt.prepare() - - self_handle = conn.GetSelfHandle() - handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, - handle, True) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', - ['MediaSignalling', 'Group', 'CallState']) - chan_props = chan.Properties.GetAll(cs.CHANNEL) - assert cs.CHANNEL_IFACE_CALL_STATE in chan_props['Interfaces'], \ - chan_props['Interfaces'] - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: 0 } or \ - call_states == {}, call_states - - chan.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') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - audio_path = e.args[0] - stream_handler = make_channel_proxy(conn, audio_path, 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - stream.send(make_result_iq(stream, e.stanza)) - - jt.parse_session_initiate(e.query) - - if jp.is_modern_jingle(): - # The other person's client starts ringing, and tells us so! - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('ringing', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - # If this is an old Jingle dialect, Gabble should treat the - # session-initiate ack as ringing notification; if it's modern Jingle, we - # just sent a ringing notification. - q.expect('dbus-signal', signal='CallStateChanged', - args=[handle, cs.CALL_STATE_RINGING]) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_RINGING }, call_states - - if jp.is_modern_jingle(): - # We're waiting in a queue, so the other person's client tells us we're on - # hold. Gabble should ack the IQ, and set the call state to Ringing | Held. - # Also, Gabble certainly shouldn't tell s-e to start sending. (Although it - # might tell it not to; we don't mind.) - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('hold', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - forbidden = [ - EventPattern('dbus-signal', signal='SetStreamSending', args=[True], - path=audio_path), - ] - q.forbid_events(forbidden) - - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[handle, cs.CALL_STATE_RINGING | cs.CALL_STATE_HELD]), - ) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_RINGING | cs.CALL_STATE_HELD }, call_states - - # We're at the head of a queue, so the other person's client tells us we're - # no longer on hold. The call centre phone's still ringing, though. s-e - # still shouldn't start sending. - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('unhold', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[handle, cs.CALL_STATE_RINGING]), - ) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_RINGING }, call_states - - sync_dbus(bus, q, conn) - q.unforbid_events(forbidden) - - jt.accept() - - if jp.is_modern_jingle(): - # The other person's client decides it's not ringing any more - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('active', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - # Gabble tells s-e to start sending, and removes the Ringing flag, either - # because we got <active/> or because of the session-accept in ye olde - # Jingle. - q.expect_many( - EventPattern('dbus-signal', signal='SetStreamSending', args=[True], - path=audio_path), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[ handle, 0 ]), - ) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: 0 } or call_states == {}, call_states - - # The rest of the test concerns things we only support in the glorious - # modern Jingle future. - if not jp.is_modern_jingle(): - return - - # The other person puts us on hold. Gabble should ack the session-info IQ, - # tell s-e to stop sending on the held stream, and set the call state. - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('hold', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='SetStreamSending', args=[False], - path=audio_path), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[handle, cs.CALL_STATE_HELD]), - ) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_HELD }, call_states - - # The peer pings us with an empty session-info; Gabble should just ack it. - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [])]) - stream.send(jp.xml(node)) - - q.expect('stream-iq', iq_type='result', iq_id=node[2]['id']) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_HELD }, call_states - - # The peer sends us some unknown-namespaced misc in a session-info; Gabble - # should nak it with <unsupported-info/> - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('boiling', 'com.example.Kettle', {}, []) ]) ]) - stream.send(jp.xml(node)) - - e = q.expect('stream-iq', iq_type='error', iq_id=node[2]['id']) - xpath.queryForNodes("/jingle/error/unsupported-info", e.query) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_HELD }, call_states - - # The other person unholds us; Gabble should ack the session-info IQ, tell - # s-e to start sending on the now-active stream, and set the call state. - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('active', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='SetStreamSending', args=[True], - path=audio_path), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[handle, 0]), - ) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: 0 } or call_states == {}, call_states - - # Okay, let's get a second stream involved! - - chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO]) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - video_path = e.args[0] - stream_handler2 = make_channel_proxy(conn, video_path, 'Media.StreamHandler') - - stream_handler2.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler2.Ready(jt.get_video_codecs_dbus()) - stream_handler2.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('content-add')) - stream.send(make_result_iq(stream, e.stanza)) - - jt.content_accept(e.query, 'video') - - q.expect('dbus-signal', signal='SetStreamSending', args=[True], - path=video_path) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: 0 } or call_states == {}, call_states - - # The other person puts us on hold. Gabble should ack the session-info IQ, - # tell s-e to stop sending on both streams, and set the call state. - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('hold', ns.JINGLE_RTP_INFO_1, {}, []) ]) ]) - stream.send(jp.xml(node)) - - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='SetStreamSending', args=[False], - path=audio_path), - EventPattern('dbus-signal', signal='SetStreamSending', args=[False], - path=video_path), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[handle, cs.CALL_STATE_HELD]), - ) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_HELD }, call_states - - # Now the other person sets the audio stream to mute. We can't represent - # mute yet, but Gabble shouldn't take this to mean the call is active, as - # one stream being muted doesn't change the fact that the call's on hold. - # FIXME: hardcoded stream id - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.jid, 'session-info', [ - ('mute', ns.JINGLE_RTP_INFO_1, - {'name': 'Audio', 'creator': 'initiator'}, []) ]) ]) - stream.send(jp.xml(node)) - - forbidden = [ - EventPattern('dbus-signal', signal='SetStreamSending', args=[True], - path=audio_path), - EventPattern('dbus-signal', signal='CallStateChanged', - args=[ handle, 0 ]), - ] - q.forbid_events(forbidden) - - q.expect('stream-iq', iq_type='result', iq_id=node[2]['id']) - - call_states = chan.CallState.GetCallStates() - assert call_states == { handle: cs.CALL_STATE_HELD }, call_states - - sync_dbus(bus, q, conn) - q.unforbid_events(forbidden) - - # That'll do, pig. - - chan.Group.RemoveMembers([self_handle], 'closed') - e = q.expect('dbus-signal', signal='Close') #XXX - match against the path - -if __name__ == '__main__': - test_all_dialects(test) diff --git a/tests/twisted/jingle/call_helper.py b/tests/twisted/jingle/call_helper.py index 024ddaad1..76f595322 100644 --- a/tests/twisted/jingle/call_helper.py +++ b/tests/twisted/jingle/call_helper.py @@ -4,10 +4,6 @@ Base classes for Call tests import config -if not config.CHANNEL_TYPE_CALL_ENABLED: - print "NOTE: built with --disable-channel-type-call" - raise SystemExit(77) - import dbus from dbus.exceptions import DBusException @@ -60,9 +56,8 @@ class CallTest(object): self.PEER_JID) self.can_change_direction = (jp.dialect not in ['gtalk-v0.3', 'gtalk-v0.4']) - self.self_handle = conn.GetSelfHandle() - self.peer_handle = conn.RequestHandles(1, ["foo@bar.com/Foo"])[0] - + self.self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") + self.peer_handle = conn.get_contact_handle_sync(self.PEER_JID) def check_channel_state(self, state, wait = False): """Optionnally wait for channel state to be reached and check that the @@ -112,13 +107,13 @@ class CallTest(object): assertNotEquals("/", path) offer = self.bus.get_object(self.conn.bus_name, path) - codecmap_property = offer.Get(cs.CALL_CONTENT_MEDIADESCRIPTION, + codecmap_property = offer.Get(cs.CALL_CONTENT_MEDIA_DESCRIPTION, "Codecs", dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals(remote_md[cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs'], + assertEquals(remote_md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs'], codecmap_property) - offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept(md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) current_md = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, "LocalMediaDescriptions", dbus_interface=dbus.PROPERTIES_IFACE) @@ -135,7 +130,7 @@ class CallTest(object): incoming = self.incoming content = wrap_content(self.bus.get_object(self.conn.bus_name, - content_path), ['DTMF', 'Media']) + content_path)) content_props = content.GetAll(cs.CALL_CONTENT, dbus_interface=dbus.PROPERTIES_IFACE) @@ -321,8 +316,7 @@ class CallTest(object): chan_path = signal.args[0][0][0] self.chan = wrap_channel( - self.bus.get_object(self.conn.bus_name, chan_path), - 'Call', ['Hold']) + self.bus.get_object(self.conn.bus_name, chan_path), 'Call') properties = self.chan.GetAll(cs.CHANNEL_TYPE_CALL, dbus_interface=dbus.PROPERTIES_IFACE) @@ -460,8 +454,9 @@ class CallTest(object): ret = self.q.expect_many(*expected) # Check the first LocalCandidatesAdded signal (third in the array) assertEquals(candidates, ret[2].args[0]) - if not self.incoming: + self.check_session_initiate_iq(ret[-1]) + if expect_after_si is not None: sync_stream(self.q, self.stream) self.q.unforbid_events(expect_after_si) @@ -607,6 +602,10 @@ class CallTest(object): self.check_channel_state(cs.CALL_STATE_INITIALISED) + def check_session_initiate_iq(self, e): + """e is the session-initiate stream-iq event.""" + pass + def connect(self, expect_after_si=None): """Negotiate all the codecs, bringing the channel to INITIALISED state""" diff --git a/tests/twisted/jingle/callutils.py b/tests/twisted/jingle/callutils.py index 8688c9b71..b4db0b0f7 100644 --- a/tests/twisted/jingle/callutils.py +++ b/tests/twisted/jingle/callutils.py @@ -37,7 +37,7 @@ def check_and_accept_offer (q, bus, conn, content, md, in_remote_handle = 0, [path, remote_md] = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, "MediaDescriptionOffer", dbus_interface=dbus.PROPERTIES_IFACE) - remote_handle = remote_md[cs.CALL_CONTENT_MEDIADESCRIPTION + '.RemoteContact'] + remote_handle = remote_md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.RemoteContact'] if in_remote_handle != 0: assertEquals(remote_handle, in_remote_handle) @@ -48,12 +48,12 @@ def check_and_accept_offer (q, bus, conn, content, md, in_remote_handle = 0, assertNotEquals ("/", path) offer = bus.get_object (conn.bus_name, path) - codecmap_property = offer.Get (cs.CALL_CONTENT_MEDIADESCRIPTION, + codecmap_property = offer.Get (cs.CALL_CONTENT_MEDIA_DESCRIPTION, "Codecs", dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals (remote_md[cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs'], codecmap_property) + assertEquals (remote_md[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs'], codecmap_property) - offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIADESCRIPTION) + offer.Accept (md, dbus_interface=cs.CALL_CONTENT_MEDIA_DESCRIPTION) current_md = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, "LocalMediaDescriptions", dbus_interface=dbus.PROPERTIES_IFACE) diff --git a/tests/twisted/jingle/decloak-peer.py b/tests/twisted/jingle/decloak-peer.py index fa8f1ee50..237472b66 100644 --- a/tests/twisted/jingle/decloak-peer.py +++ b/tests/twisted/jingle/decloak-peer.py @@ -36,16 +36,13 @@ def run_test(q, bus, conn, stream, jt, decloak_allowed): presence at all. """ - request = dbus.Dictionary({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - 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') - handle = props[cs.TARGET_HANDLE] - - call_async(q, media_iface, 'RequestStreams', handle, - [cs.MEDIA_STREAM_TYPE_AUDIO]) + call_async(q, conn.Requests, 'CreateChannel', + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_ID: jt.peer, + cs.CALL_INITIAL_AUDIO: True, + cs.CALL_INITIAL_VIDEO: False, + }) e = q.expect('stream-presence', to=jt.peer_bare_jid, presence_type=None) @@ -57,10 +54,13 @@ def run_test(q, bus, conn, stream, jt, decloak_allowed): jt.send_presence_and_caps() # RequestStreams should now happily complete - q.expect('dbus-return', method='RequestStreams') + q.expect('dbus-return', method='CreateChannel') else: - q.expect('dbus-error', method='RequestStreams', + q.expect('dbus-error', method='CreateChannel', name=cs.OFFLINE) if __name__ == '__main__': + print "FIXME: needs to be ported to Call1" + raise SystemExit(77) + exec_test(test, timeout=10) diff --git a/tests/twisted/jingle/dtmf-no-audio.py b/tests/twisted/jingle/dtmf-no-audio.py deleted file mode 100644 index fd5f568cf..000000000 --- a/tests/twisted/jingle/dtmf-no-audio.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -Test inability to send DTMF events on a video-only call. -""" - -from twisted.words.xish import xpath - -from gabbletest import make_result_iq -from servicetest import (call_async, - wrap_channel, make_channel_proxy, EventPattern, sync_dbus) -import constants as cs - -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(jp, q, bus, conn, stream): - if not jp.can_do_video_only(): - return - - remote_jid = 'foo@bar.com/Foo' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - jt.prepare() - - self_handle = conn.GetSelfHandle() - handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - chan_path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, handle, True) - chan = wrap_channel(bus.get_object(conn.bus_name, chan_path), - 'StreamedMedia', ['MediaSignalling', 'Group', 'CallState', 'DTMF']) - chan_props = chan.Properties.GetAll(cs.CHANNEL) - assert cs.CHANNEL_IFACE_DTMF in chan_props['Interfaces'], \ - chan_props['Interfaces'] - - chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO]) - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - video_path = e.args[0] - stream_handler = make_channel_proxy(conn, video_path, 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_video_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - stream.send(make_result_iq(stream, e.stanza)) - - jt.parse_session_initiate(e.query) - - jt.accept() - - # Gabble tells s-e to start sending - q.expect('dbus-signal', signal='SetStreamSending', args=[True], - path=video_path) - - # We don't actually have an audio stream, so this is a non-starter. - call_async(q, chan.DTMF, 'StartTone', 666, 3) - q.expect('dbus-error', method='StartTone', name=cs.NOT_AVAILABLE) - call_async(q, chan.DTMF, 'MultipleTones', '**666##') - q.expect('dbus-error', method='MultipleTones', name=cs.NOT_AVAILABLE) - - # We can still stop all the tones that are playing (a no-op). - call_async(q, chan.DTMF, 'StopTone', 666) - q.expect('dbus-return', method='StopTone') - - chan.Group.RemoveMembers([self_handle], 'closed') - e = q.expect('dbus-signal', signal='Closed', path=chan_path) - -if __name__ == '__main__': - test_all_dialects(test) diff --git a/tests/twisted/jingle/dtmf.py b/tests/twisted/jingle/dtmf.py deleted file mode 100644 index 4116e9d10..000000000 --- a/tests/twisted/jingle/dtmf.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -Test DTMF events. -""" - -from twisted.words.xish import xpath - -from gabbletest import make_result_iq -from servicetest import (call_async, - wrap_channel, make_channel_proxy, EventPattern, sync_dbus, assertEquals) -import constants as cs - -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(jp, q, bus, conn, stream): - # this test uses multiple streams - if not jp.is_modern_jingle(): - return - - remote_jid = 'foo@bar.com/Foo' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - jt.prepare() - - self_handle = conn.GetSelfHandle() - handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - chan_path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, handle, True) - chan = wrap_channel(bus.get_object(conn.bus_name, chan_path), - 'StreamedMedia', ['MediaSignalling', 'Group', 'CallState', 'DTMF']) - chan_props = chan.Properties.GetAll(cs.CHANNEL) - assert cs.CHANNEL_IFACE_DTMF in chan_props['Interfaces'], \ - chan_props['Interfaces'] - - assertEquals('', - chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'InitialTones')) - assertEquals('', - chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'DeferredTones')) - - chan.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') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - audio_path = e.args[0] - stream_handler = make_channel_proxy(conn, audio_path, 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - stream.send(make_result_iq(stream, e.stanza)) - - jt.parse_session_initiate(e.query) - - jt.accept() - - # Gabble tells s-e to start sending - q.expect('dbus-signal', signal='SetStreamSending', args=[True], - path=audio_path) - - chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - audio2_path = e.args[0] - - # The Stream_ID is specified to be ignored; we use 666 here. - call_async(q, chan.DTMF, 'StartTone', 666, 3) - q.expect_many( - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio2_path), - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio_path), - EventPattern('dbus-signal', signal='SendingTones', args=['3'], - path=chan_path), - EventPattern('dbus-return', method='StartTone'), - ) - - call_async(q, chan.DTMF, 'StopTone', 666) - q.expect_many( - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio_path), - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio2_path), - EventPattern('dbus-signal', signal='StoppedTones', args=[True], - path=chan_path), - EventPattern('dbus-return', method='StopTone'), - ) - - call_async(q, chan.DTMF, 'MultipleTones', '123w*#') - q.expect_many( - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio_path, args=[1]), - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio2_path, args=[1]), - EventPattern('dbus-signal', signal='SendingTones', args=['123w*#'], - path=chan_path), - EventPattern('dbus-return', method='MultipleTones'), - ) - q.expect_many( - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio_path), - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio2_path), - ) - q.expect_many( - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio_path, args=[2]), - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio2_path, args=[2]), - ) - q.expect_many( - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio_path), - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio2_path), - ) - q.expect_many( - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio_path, args=[3]), - EventPattern('dbus-signal', signal='StartTelephonyEvent', - path=audio2_path, args=[3]), - ) - q.expect_many( - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio_path), - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio2_path), - EventPattern('dbus-signal', signal='StoppedTones', args=[False], - path=chan_path), - EventPattern('dbus-signal', signal='TonesDeferred', - args=['*#']), - ) - - assertEquals('*#', - chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'DeferredTones')) - - forbidden = [EventPattern('dbus-signal', signal='StartTelephonyEvent', - args=[9])] - q.forbid_events(forbidden) - - # This is technically a race condition, but this dialstring is almost - # certainly long enough that the Python script will win the race, i.e. - # cancel before Gabble processes the whole dialstring. - call_async(q, chan.DTMF, 'MultipleTones', - '1,1' * 100) - q.expect('dbus-return', method='MultipleTones') - - call_async(q, chan.DTMF, 'MultipleTones', '9') - q.expect('dbus-error', method='MultipleTones', - name=cs.SERVICE_BUSY) - call_async(q, chan.DTMF, 'StartTone', 666, 9) - q.expect('dbus-error', method='StartTone', name=cs.SERVICE_BUSY) - call_async(q, chan.DTMF, 'StopTone', 666) - q.expect_many( - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio_path), - EventPattern('dbus-signal', signal='StopTelephonyEvent', - path=audio2_path), - EventPattern('dbus-signal', signal='StoppedTones', args=[True], - path=chan_path), - EventPattern('dbus-return', method='StopTone'), - ) - - # emitting any sound resets TonesDeferred - assertEquals('', - chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'DeferredTones')) - - q.unforbid_events(forbidden) - - chan.Group.RemoveMembers([self_handle], 'closed') - e = q.expect('dbus-signal', signal='Closed', path=chan_path) - -if __name__ == '__main__': - test_all_dialects(test) diff --git a/tests/twisted/jingle/google-relay.py b/tests/twisted/jingle/google-relay.py deleted file mode 100644 index 24b2cf493..000000000 --- a/tests/twisted/jingle/google-relay.py +++ /dev/null @@ -1,424 +0,0 @@ -""" -Test getting relay from Google jingleinfo -""" - -import config - -if not config.GOOGLE_RELAY_ENABLED: - print "NOTE: built with --disable-google-relay" - raise SystemExit(77) - -from functools import partial - -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 jingletest2 -import gabbletest -import constants as cs -import dbus -import ns -import config -from twisted.words.protocols.jabber.client import IQ - -from twisted.web import http - -from httptest import listen_http - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -# A real request/response looks like this: -# -# GET /create_session HTTP/1.1 -# Connection: Keep-Alive -# Content-Length: 0 -# Host: relay.l.google.com -# User-Agent: farsight-libjingle -# X-Google-Relay-Auth: censored -# X-Talk-Google-Relay-Auth: censored -# -# HTTP/1.1 200 OK -# Content-Type: text/plain -# Date: Tue, 03 Mar 2009 18:33:28 GMT -# Server: MediaProxy -# Cache-Control: private, x-gzip-ok="" -# Transfer-Encoding: chunked -# -# c3 -# relay.ip=74.125.47.126 -# relay.udp_port=19295 -# relay.tcp_port=19294 -# relay.ssltcp_port=443 -# stun.ip=74.125.47.126 -# stun.port=19302 -# username=censored -# password=censored -# magic_cookie=censored -# -# 0 -response_template = """c3 -relay.ip=127.0.0.1 -relay.udp_port=11111 -relay.tcp_port=22222 -relay.ssltcp_port=443 -stun.ip=1.2.3.4 -stun.port=12345 -username=UUUUUUUU%d -password=PPPPPPPP%d -magic_cookie=MMMMMMMM -""" - -def handle_request(req, n): - req.setResponseCode(http.OK) - req.setHeader("Content-Type", "text/plain") - req.write(response_template % (n, n)) - req.finish() - -TOO_SLOW_CLOSE = 1 -TOO_SLOW_REMOVE_SELF = 2 -TOO_SLOW_DISCONNECT = 3 -TOO_SLOW_DISCONNECT_IMMEDIATELY = 4 - -def test(q, bus, conn, stream, incoming=True, too_slow=None, use_call=False): - 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 - # one specific crash, not to verify that it all works... - assert incoming - assert too_slow in [TOO_SLOW_CLOSE, TOO_SLOW_DISCONNECT] - - # Tell Gabble we want to use Call. - conn.ContactCapabilities.UpdateCapabilities([ - (cs.CLIENT + ".CallHandler", [ - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, - cs.CALL_INITIAL_AUDIO: True}, - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, - cs.CALL_INITIAL_VIDEO: True}, - ], [ - cs.CHANNEL_TYPE_CALL + '/gtalk-p2p', - cs.CHANNEL_TYPE_CALL + '/ice', - cs.CHANNEL_TYPE_CALL + '/video/h264', - ]), - ]) - - # See: http://code.google.com/apis/talk/jep_extensions/jingleinfo.html - 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 - # before receiving a reply to the google:jingleinfo query. - if too_slow == TOO_SLOW_DISCONNECT_IMMEDIATELY: - disconnect_conn(q, conn, stream, []) - return - - listen_port = listen_http(q, 0) - - jingleinfo = make_result_iq(stream, ji_event.stanza) - stun = jingleinfo.firstChildElement().addElement('stun') - server = stun.addElement('server') - server['host'] = 'resolves-to-1.2.3.4' - server['udp'] = '12345' - - expected_stun_server = '1.2.3.4' - expected_stun_port = 12345 - - # This bit is undocumented... but it has the same format as what we get - # from Google Talk servers: - # <iq to="censored" from="censored" id="73930208084" type="result"> - # <query xmlns="google:jingleinfo"> - # <stun> - # <server host="stun.l.google.com" udp="19302"/> - # <server host="stun4.l.google.com" udp="19302"/> - # <server host="stun3.l.google.com" udp="19302"/> - # <server host="stun1.l.google.com" udp="19302"/> - # <server host="stun2.l.google.com" udp="19302"/> - # </stun> - # <relay> - # <token>censored</token> - # <server host="relay.google.com" udp="19295" tcp="19294" - # tcpssl="443"/> - # </relay> - # </query> - # </iq> - relay = jingleinfo.firstChildElement().addElement('relay') - relay.addElement('token', content='jingle all the way') - server = relay.addElement('server') - server['host'] = '127.0.0.1' - server['udp'] = '11111' - server['tcp'] = '22222' - server['tcpssl'] = '443' - # The special regression-test build of Gabble parses this attribute, - # because we can't listen on port 80 - server['gabble-test-http-port'] = str(listen_port.getHost().port) - stream.send(jingleinfo) - jingleinfo = None - - # Spoof some jingle info. This is a regression test for - # <https://bugs.freedesktop.org/show_bug.cgi?id=34048>. We assert that - # Gabble has ignored this stuff later. - iq = IQ(stream, 'set') - iq['from'] = "evil@evil.net" - query = iq.addElement((ns.GOOGLE_JINGLE_INFO, "query")) - - stun = query.addElement('stun') - server = stun.addElement('server') - server['host'] = '6.6.6.6' - server['udp'] = '6666' - - relay = query.addElement('relay') - relay.addElement('token', content='mwohahahahaha') - server = relay.addElement('server') - server['host'] = '127.0.0.1' - server['udp'] = '666' - server['tcp'] = '999' - server['tcpssl'] = '666' - - stream.send(iq) - - jt.send_presence_and_caps() - - remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] - self_handle = conn.GetSelfHandle() - req_pattern = EventPattern('http-request', method='GET', path='/create_session') - - if incoming: - # Remote end calls us - jt.incoming_call() - - if use_call: - def looks_like_a_call_to_me(event): - channels, = event.args - path, props = channels[0] - return props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL - new_channels = q.expect('dbus-signal', signal='NewChannels', - predicate=looks_like_a_call_to_me) - - path = new_channels.args[0][0][0] - media_chan = bus.get_object(conn.bus_name, path) - else: - # FIXME: these signals are not observable by real clients, since they - # happen before NewChannels. - # The caller is in members - # We're pending because of remote_handle - mc, _, e = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [remote_handle], [], [], [], 0, 0]), - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [self_handle], [], remote_handle, - cs.GC_REASON_INVITED]), - EventPattern('dbus-signal', signal='NewSessionHandler')) - - media_chan = make_channel_proxy(conn, mc.path, - 'Channel.Interface.Group') - media_iface = make_channel_proxy(conn, mc.path, - 'Channel.Type.StreamedMedia') - else: - call_async(q, conn.Requests, 'CreateChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle, - }) - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in - e.args[0][0][1].values()), - ) - path = ret.value[0] - media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') - media_iface = make_channel_proxy(conn, path, - 'Channel.Type.StreamedMedia') - call_async(q, media_iface, 'RequestStreams', - remote_handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) - e = q.expect('dbus-signal', signal='NewSessionHandler') - - req1 = q.expect('http-request', method='GET', path='/create_session') - req2 = q.expect('http-request', method='GET', path='/create_session') - - if too_slow is not None: - test_too_slow(q, bus, conn, stream, req1, req2, media_chan, too_slow) - return - - if incoming: - assertLength(0, media_iface.ListStreams()) - # Accept the call. - media_chan.AddMembers([self_handle], '') - - # In response to the streams call, we now have two HTTP requests - # (for RTP and RTCP) - handle_request(req1.request, 0) - handle_request(req2.request, 1) - - if incoming: - # We accepted the call, and it should get a new, bidirectional stream - # now that the relay info request has finished. This tests against a - # regression of bug #24023. - q.expect('dbus-signal', signal='StreamAdded', - args=[1, remote_handle, cs.MEDIA_STREAM_TYPE_AUDIO]) - q.expect('dbus-signal', signal='StreamDirectionChanged', - args=[1, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]) - else: - # Now that we have the relay info, RequestStreams can return - q.expect('dbus-return', method='RequestStreams') - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - # Exercise channel properties - channel_props = media_chan.GetAll( - cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) - assert channel_props['TargetHandle'] == remote_handle - assert channel_props['TargetHandleType'] == cs.HT_CONTACT - assert channel_props['TargetID'] == 'foo@bar.com' - assert channel_props['Requested'] == (not incoming) - - # The new API for STUN servers etc. - sh_props = stream_handler.GetAll( - cs.STREAM_HANDLER, dbus_interface=dbus.PROPERTIES_IFACE) - - assert sh_props['NATTraversal'] == 'gtalk-p2p' - assert sh_props['CreatedLocally'] == (not incoming) - - # If Gabble has erroneously paid attention to the contact evil@evil.net who - # sent us a google:jingleinfo stanza, this assertion will fail. - assertEquals([(expected_stun_server, expected_stun_port)], - sh_props['STUNServers']) - - credentials_used = {} - credentials = {} - - for relay in sh_props['RelayInfo']: - assert relay['ip'] == '127.0.0.1', sh_props['RelayInfo'] - assert relay['type'] in ('udp', 'tcp', 'tls') - assert relay['component'] in (1, 2) - - if relay['type'] == 'udp': - assert relay['port'] == 11111, sh_props['RelayInfo'] - elif relay['type'] == 'tcp': - assert relay['port'] == 22222, sh_props['RelayInfo'] - elif relay['type'] == 'tls': - assert relay['port'] == 443, sh_props['RelayInfo'] - - assert relay['username'][:8] == 'UUUUUUUU', sh_props['RelayInfo'] - assert relay['password'][:8] == 'PPPPPPPP', sh_props['RelayInfo'] - assert relay['password'][8:] == relay['username'][8:], \ - sh_props['RelayInfo'] - assert (relay['password'][8:], relay['type']) not in credentials_used - credentials_used[(relay['password'][8:], relay['type'])] = 1 - credentials[(relay['component'], relay['type'])] = relay['password'][8:] - - assert (1, 'udp') in credentials - assert (1, 'tcp') in credentials - assert (1, 'tls') in credentials - assert (2, 'udp') in credentials - assert (2, 'tcp') in credentials - assert (2, 'tls') in credentials - - assert ('0', 'udp') in credentials_used - assert ('0', 'tcp') in credentials_used - assert ('0', 'tls') in credentials_used - assert ('1', 'udp') in credentials_used - assert ('1', 'tcp') in credentials_used - assert ('1', 'tls') in credentials_used - - # consistency check, since we currently reimplement Get separately - for k in sh_props: - assert sh_props[k] == stream_handler.Get( - 'org.freedesktop.Telepathy.Media.StreamHandler', k, - dbus_interface=dbus.PROPERTIES_IFACE), k - - media_chan.RemoveMembers([self_handle], '') - - if incoming: - 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'), - EventPattern('dbus-signal', signal='Closed'), - ) - else: - # We haven't sent a session-initiate, so we shouldn't expect to send a - # session-terminate. - q.expect('dbus-signal', signal='Closed') - - # Tests completed, close the connection - -def test_too_slow(q, bus, conn, stream, req1, req2, media_chan, too_slow): - """ - Regression test for a bug where if the channel was closed before the HTTP - responses arrived, the responses finally arriving crashed Gabble. - """ - - # User gets bored, and ends the call. - e = EventPattern('dbus-signal', signal='Closed', - path=media_chan.object_path) - - if too_slow == TOO_SLOW_CLOSE: - call_async(q, media_chan, 'Close', dbus_interface=cs.CHANNEL) - elif too_slow == TOO_SLOW_REMOVE_SELF: - media_chan.RemoveMembers([conn.GetSelfHandle()], "", - dbus_interface=cs.CHANNEL_IFACE_GROUP) - elif too_slow == TOO_SLOW_DISCONNECT: - disconnect_conn(q, conn, stream, [e]) - - try: - media_chan.GetMembers() - except dbus.DBusException, e: - # This should fail because the object's gone away, not because - # Gabble's crashed. - assert cs.UNKNOWN_METHOD == e.get_dbus_name(), \ - "maybe Gabble crashed? %s" % e - else: - # Gabble will probably also crash in a moment, because the http - # request callbacks will be called after the channel's meant to - # have died, which will cause the channel to try to call methods on - # the (finalized) connection. - assert False, "the channel should be dead by now" - - return - - q.expect_many(e) - - # Now Google answers! - handle_request(req1.request, 2) - handle_request(req2.request, 3) - - # Make a misc method call to check that Gabble's still alive. - sync_dbus(bus, q, conn) - -def exec_relay_test(incoming, too_slow=None, use_call=False): - exec_test( - partial(test, incoming=incoming, too_slow=too_slow, use_call=use_call), - protocol=GoogleXmlStream) - -if __name__ == '__main__': - exec_relay_test(True) - exec_relay_test(False) - exec_relay_test(True, TOO_SLOW_CLOSE) - exec_relay_test(False, TOO_SLOW_CLOSE) - exec_relay_test(True, TOO_SLOW_REMOVE_SELF) - exec_relay_test(False, TOO_SLOW_REMOVE_SELF) - exec_relay_test(True, TOO_SLOW_DISCONNECT) - exec_relay_test(False, TOO_SLOW_DISCONNECT) - exec_relay_test(True, TOO_SLOW_DISCONNECT_IMMEDIATELY) - - if config.CHANNEL_TYPE_CALL_ENABLED: - exec_relay_test(True, TOO_SLOW_CLOSE, use_call=True) - exec_relay_test(True, TOO_SLOW_DISCONNECT, use_call=True) - diff --git a/tests/twisted/jingle/hold-audio.py b/tests/twisted/jingle/hold-audio.py deleted file mode 100644 index d7656889a..000000000 --- a/tests/twisted/jingle/hold-audio.py +++ /dev/null @@ -1,425 +0,0 @@ -""" -Test the Hold API. -""" - -from gabbletest import make_result_iq, sync_stream -from servicetest import ( - assertEquals, sync_dbus, - make_channel_proxy, call_async, EventPattern, wrap_channel, - ) -import constants as cs - -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(jp, q, bus, conn, stream): - remote_jid = 'foo@bar.com/Foo' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - - jt.prepare() - - self_handle = conn.GetSelfHandle() - handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, - handle, True) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', - ['Hold']) - - # These are 0- (for old dialects) or 1- (for new dialects) element lists - # that can be splatted into expect_many with * - hold_event = jp.rtp_info_event_list("hold") - unhold_event = jp.rtp_info_event_list("unhold") - - # Before we have any streams, GetHoldState returns Unheld and unhold is a - # no-op. - assertEquals((cs.HS_UNHELD, cs.HSR_NONE), chan.Hold.GetHoldState()) - chan.Hold.RequestHold(False) - - # Before we have any streams, RequestHold(True) should work; because there - # are no streams, it should take effect at once. It certainly shouldn't - # send anything to the peer. - q.forbid_events(hold_event) - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', True) - q.expect('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]) - q.expect('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]) - assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState()) - - # If we unhold, it should succeed immediately again, because there are no - # resources to reclaim. - call_async(q, chan.Hold, 'RequestHold', False) - q.expect('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]) - q.expect('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]) - assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState()) - - # Put the call back on hold ... - call_async(q, chan.Hold, 'RequestHold', True) - q.expect('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]) - q.expect('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]) - assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState()) - - # ... and request a stream. - chan.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') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - # Syncing here to make sure SetStreamHeld happens after Ready... - sync_dbus(bus, q, conn) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - # Now Gabble tells the streaming implementation to go on hold (because it - # said it was Ready), and the session is initiated. - e = q.expect_many( - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('stream-iq', - predicate=jp.action_predicate('session-initiate')), - )[1] - - # Ensure that if Gabble sent the <hold/> stanza too early it's already - # arrived. - sync_stream(q, stream) - q.unforbid_events(hold_event) - - stream.send(make_result_iq(stream, e.stanza)) - - # We've acked the s-i, so we do speak Jingle; Gabble should send the - # <hold/> notification. - q.expect_many(*hold_event) - - # The call's still on hold, both before and after the streaming - # implementation says it's okay with that (re-entering PENDING_HOLD seems - # silly). - assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState()) - stream_handler.HoldState(True) - assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState()) - - # The peer answers the call; they're still on hold. - jt.parse_session_initiate(e.query) - jt.accept() - - q.expect('stream-iq', iq_type='result') - - assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState()) - - # Now we decide we do actually want to speak to them, and unhold. - # Ensure that if Gabble sent the <unhold/> stanza too early it's already - # arrived. - sync_stream(q, stream) - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - # Ensure that if Gabble sent the <unhold/> stanza too early it's already - # arrived. - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - # Hooray! Now let's check that Hold works properly once the call's fully - # established. - - # ---- Test 1: GetHoldState returns unheld and unhold is a no-op ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - chan.Hold.RequestHold(False) - - # ---- Test 2: successful hold ---- - - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='RequestHold', value=()), - *hold_event - ) - - call_async(q, stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - # ---- Test 3: GetHoldState returns held and hold is a no-op ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_HELD, hold_state - chan.Hold.RequestHold(True) - - # ---- Test 4: successful unhold ---- - - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - # Ensure that if Gabble sent the <unhold/> stanza too early it's already - # arrived. - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - # ---- Test 5: GetHoldState returns False and unhold is a no-op ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - chan.Hold.RequestHold(False) - - # ---- Test 6: 3 parallel calls to hold ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - - call_async(q, chan.Hold, 'RequestHold', True) - call_async(q, chan.Hold, 'RequestHold', True) - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='RequestHold', value=()), - *hold_event - ) - - call_async(q, stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - # ---- Test 7: 3 parallel calls to unhold ---- - - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - call_async(q, chan.Hold, 'RequestHold', False) - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - # Ensure that if Gabble sent the <unhold/> stanza too early it's already - # arrived. - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - # ---- Test 8: hold, then change our minds before s-e has responded ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - *hold_event - ) - - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - # Gabble shouldn't send <unhold/> here because s-e might have already - # relinquished the audio hardware. - ) - - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, stream_handler, 'HoldState', True) - q.expect('dbus-return', method='HoldState', value=()) - - call_async(q, stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - - # ---- Test 9: unhold, then change our minds before s-e has responded ---- - - # Go to state "held" first - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='RequestHold', value=()), - *hold_event - ) - call_async(q, stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - # Actually do test 9 - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_HELD, hold_state - - # Check that Gabble doesn't send another <hold/>, or send <unhold/> before - # we change our minds. - q.forbid_events(unhold_event + hold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - ) - - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - ) - - - call_async(q, stream_handler, 'HoldState', False) - call_async(q, stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_HELD, hold_state - - sync_stream(q, stream) - q.unforbid_events(unhold_event + hold_event) - - # ---- Test 10: attempting to unhold fails ---- - - # Check that Gabble doesn't send another <hold/>, or send <unhold/> even - # though unholding fails. - q.forbid_events(unhold_event + hold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - call_async(q, stream_handler, 'UnholdFailure') - - q.expect_many( - EventPattern('dbus-return', method='UnholdFailure', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]), - ) - - sync_stream(q, stream) - q.unforbid_events(unhold_event + hold_event) - - # ---- Test 11: when we successfully unhold, the peer gets <unhold/> --- - - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - # Ensure that if Gabble sent the <unhold/> stanza too early it's already - # arrived. - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - # ---- The end ---- - - chan.Group.RemoveMembers([self_handle], 'closed') - - # Test completed, close the connection - - e = q.expect('dbus-signal', signal='Close') #XXX - match against the path - -if __name__ == '__main__': - test_all_dialects(test) diff --git a/tests/twisted/jingle/hold-av.py b/tests/twisted/jingle/hold-av.py deleted file mode 100644 index 1e150c01a..000000000 --- a/tests/twisted/jingle/hold-av.py +++ /dev/null @@ -1,481 +0,0 @@ -""" -Test the Hold API. -""" - -from gabbletest import make_result_iq, sync_stream -from servicetest import ( - assertEquals, wrap_channel, - make_channel_proxy, call_async, EventPattern, sync_dbus) - -import constants as cs - -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def mutable_stream_tests(jp, jt, q, bus, conn, stream, chan, handle): - # ---- Test 13: while the call's on hold, we add a new stream --- - # We shouldn't go off hold locally as a result, and the new StreamHandler - # should tell s-e to hold the stream. - - pending_hold = [ - EventPattern('dbus-signal', signal='HoldStateChanged', - predicate=lambda e: e.args[0] == cs.HS_PENDING_HOLD), - ] - q.forbid_events(pending_hold) - - call_async(q, chan.StreamedMedia, 'RequestStreams', handle, - [cs.MEDIA_STREAM_TYPE_AUDIO]) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - audio_stream_path = e.args[0] - audio_stream_handler = make_channel_proxy(conn, e.args[0], - 'Media.StreamHandler') - - # Syncing here to make sure SetStreamHeld happens after Ready... - sync_dbus(bus, q, conn) - - audio_stream_handler.Ready(jt.get_audio_codecs_dbus()) - audio_stream_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - audio_stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - q.expect_many( - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True], - path=audio_stream_path), - EventPattern('dbus-signal', signal='SetStreamSending', args=[False], - path=audio_stream_path), - ) - - assertEquals(cs.HS_HELD, chan.Hold.GetHoldState()[0]) - - sync_dbus(bus, q, conn) - - # ---- Test 14: while the call's on hold, the peer adds a new stream ---- - # Again, we shouldn't go off hold locally as a result, and the new - # StreamHandler should tell s-e to hold the stream. - - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.peer, 'content-add', [ - jp.Content('videostream', 'initiator', 'both', - jp.Description('video', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt.video_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - video_stream_path = e.args[0] - video_stream_handler = make_channel_proxy(conn, e.args[0], - 'Media.StreamHandler') - - # Syncing here to make sure SetStreamHeld happens after Ready... - sync_dbus(bus, q, conn) - - video_stream_handler.Ready(jt.get_video_codecs_dbus()) - video_stream_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - video_stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - q.expect_many( - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True], - path=video_stream_path), - EventPattern('dbus-signal', signal='SetStreamSending', args=[False], - path=video_stream_path), - ) - - assertEquals(cs.HS_HELD, chan.Hold.GetHoldState()[0]) - - sync_dbus(bus, q, conn) - q.unforbid_events(pending_hold) - - - -def test(jp, q, bus, conn, stream): - # These are 0- (for old dialects) or 1- (for new dialects) element lists - # that can be splatted into expect_many with * - hold_event = jp.rtp_info_event_list("hold") - unhold_event = jp.rtp_info_event_list("unhold") - - # Let's forbid them until we're ready to start holding, to check that - # Gabble doesn't send spurious notifications. - q.forbid_events(hold_event) - q.forbid_events(unhold_event) - - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - - jt.prepare() - - self_handle = conn.GetSelfHandle() - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, handle, True) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', - ['Hold']) - - call_async(q, chan.StreamedMedia, 'RequestStreams', handle, - [cs.MEDIA_STREAM_TYPE_AUDIO, cs.MEDIA_STREAM_TYPE_VIDEO]) - - if not jp.can_do_video(): - # Video on GTalk? Not so much. - e = q.expect('dbus-error', method='RequestStreams') - # The spec and implemention say this should be NotAvailable, but wjt - # thinks it should be NotCapable. The spec bug is #20920. - name = e.error.get_dbus_name() - #assert name == cs.NOT_CAPABLE, name - return - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - # FIXME: we assume this one's the audio stream, just because we requested - # that first - audio_stream_path = e.args[0] - audio_stream_handler = make_channel_proxy(conn, e.args[0], - 'Media.StreamHandler') - - audio_stream_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - audio_stream_handler.Ready(jt.get_audio_codecs_dbus()) - audio_stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - video_stream_path = e.args[0] - video_stream_handler = make_channel_proxy(conn, e.args[0], - 'Media.StreamHandler') - - video_stream_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - video_stream_handler.Ready(jt.get_video_codecs_dbus()) - video_stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - stream.send(make_result_iq(stream, e.stanza)) - - jt.parse_session_initiate(e.query) - jt.accept() - - q.expect('stream-iq', iq_type='result') - - # ---- Test 1: GetHoldState returns unheld and unhold is a no-op ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - chan.Hold.RequestHold(False) - - # We're about to start holding, so remove the ban on <hold/>. - sync_stream(q, stream) - q.unforbid_events(hold_event) - - # ---- Test 2: successful hold ---- - - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='RequestHold', value=()), - *hold_event - ) - - call_async(q, audio_stream_handler, 'HoldState', True) - call_async(q, video_stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - # ---- Test 3: GetHoldState returns held and hold is a no-op ---- - - q.forbid_events(hold_event) - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_HELD, hold_state - chan.Hold.RequestHold(True) - - sync_stream(q, stream) - q.unforbid_events(hold_event) - - # ---- Test 4: successful unhold ---- - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, audio_stream_handler, 'HoldState', False) - call_async(q, video_stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - # ---- Test 5: GetHoldState returns False and unhold is a no-op ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - chan.Hold.RequestHold(False) - - # ---- Test 6: 3 parallel calls to hold ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - - call_async(q, chan.Hold, 'RequestHold', True) - call_async(q, chan.Hold, 'RequestHold', True) - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='RequestHold', value=()), - *hold_event - ) - - call_async(q, audio_stream_handler, 'HoldState', True) - call_async(q, video_stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - # ---- Test 7: 3 parallel calls to unhold ---- - - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - call_async(q, chan.Hold, 'RequestHold', False) - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, audio_stream_handler, 'HoldState', False) - call_async(q, video_stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - # ---- Test 8: hold, then change our minds before s-e has responded ---- - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - *hold_event - ) - - # Gabble can't send <unhold/> until s-e confirms it has the resources - q.forbid_events(unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - ) - - call_async(q, audio_stream_handler, 'HoldState', True) - call_async(q, video_stream_handler, 'HoldState', True) - call_async(q, audio_stream_handler, 'HoldState', False) - - sync_stream(q, stream) - q.unforbid_events(unhold_event) - - call_async(q, video_stream_handler, 'HoldState', False) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_UNHELD, cs.HSR_REQUESTED]), - *unhold_event - ) - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_UNHELD, hold_state - - # ---- Test 9: unhold, then change our minds before s-e has responded ---- - - # Go to state "held" first - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='RequestHold', value=()), - *hold_event - ) - call_async(q, audio_stream_handler, 'HoldState', True) - call_async(q, video_stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - # Actually do test 9 - - q.forbid_events(hold_event + unhold_event) - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_HELD, hold_state - - call_async(q, chan.Hold, 'RequestHold', False) - call_async(q, chan.Hold, 'RequestHold', True) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - ) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - ) - - call_async(q, audio_stream_handler, 'HoldState', False) - call_async(q, video_stream_handler, 'HoldState', False) - call_async(q, audio_stream_handler, 'HoldState', True) - call_async(q, video_stream_handler, 'HoldState', True) - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_REQUESTED]), - ) - - sync_stream(q, stream) - q.unforbid_events(hold_event + unhold_event) - - hold_state = chan.Hold.GetHoldState() - assert hold_state[0] == cs.HS_HELD, hold_state - - # ---- Test 10: attempting to unhold fails (both streams) ---- - - q.forbid_events(hold_event + unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - call_async(q, audio_stream_handler, 'UnholdFailure') - call_async(q, video_stream_handler, 'UnholdFailure') - - q.expect_many( - EventPattern('dbus-return', method='UnholdFailure', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]), - ) - - sync_stream(q, stream) - q.unforbid_events(hold_event + unhold_event) - - # ---- Test 11: attempting to unhold fails (first stream) ---- - - q.forbid_events(hold_event + unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - call_async(q, audio_stream_handler, 'UnholdFailure') - - q.expect_many( - EventPattern('dbus-return', method='UnholdFailure', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]), - ) - - sync_stream(q, stream) - q.unforbid_events(hold_event + unhold_event) - - # ---- Test 12: attempting to unhold partially fails, so roll back ---- - - q.forbid_events(hold_event + unhold_event) - - call_async(q, chan.Hold, 'RequestHold', False) - q.expect_many( - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]), - EventPattern('dbus-signal', signal='SetStreamHeld', args=[False]), - EventPattern('dbus-return', method='RequestHold', value=()), - ) - - call_async(q, audio_stream_handler, 'HoldState', False) - q.expect('dbus-return', method='HoldState', value=()) - - call_async(q, video_stream_handler, 'UnholdFailure') - - q.expect_many( - EventPattern('dbus-signal', signal='SetStreamHeld', args=[True]), - EventPattern('dbus-return', method='UnholdFailure', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_PENDING_HOLD, cs.HSR_RESOURCE_NOT_AVAILABLE]), - ) - - call_async(q, audio_stream_handler, 'HoldState', True) - - q.expect_many( - EventPattern('dbus-return', method='HoldState', value=()), - EventPattern('dbus-signal', signal='HoldStateChanged', - args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]), - ) - - sync_stream(q, stream) - q.unforbid_events(hold_event + unhold_event) - - if jp.has_mutable_streams(): - mutable_stream_tests(jp, jt, q, bus, conn, stream, chan, handle) - - # ---- The end ---- - - chan.Group.RemoveMembers([self_handle], 'closed') - - # Test completed, close the connection - - e = q.expect('dbus-signal', signal='Close') #XXX - match against the path - -if __name__ == '__main__': - test_all_dialects(test) diff --git a/tests/twisted/jingle/incoming-basics.py b/tests/twisted/jingle/incoming-basics.py deleted file mode 100644 index 28c0598fb..000000000 --- a/tests/twisted/jingle/incoming-basics.py +++ /dev/null @@ -1,191 +0,0 @@ -""" -Test incoming call handling. -""" - -import dbus - -from gabbletest import make_result_iq -from servicetest import ( - make_channel_proxy, unwrap, EventPattern, assertEquals, assertLength) -from jingletest2 import JingleTest2, test_all_dialects -import constants as cs - -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(jp, q, bus, conn, stream, peer='foo@bar.com/Foo'): - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', peer) - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - - # Remote end calls us - jt.incoming_call() - - # If this is a Jingle dialect that supports it, Gabble should send a - # <ringing/> notification when it gets the session-initiate until Telepathy - # has a way for the UI to do this. - # https://bugs.freedesktop.org/show_bug.cgi?id=21964 - ringing_event = jp.rtp_info_event_list("ringing") - - if jp.dialect == 'gtalk-v0.4': - # With gtalk4, apparently we have to send transport-accept immediately, - # not even just before we send our transport-info. wjt tested this, and - # indeed if we don't send this for incoming calls, the call never - # connects. - ta_event = [ - EventPattern('stream-iq', predicate=lambda x: - xpath.queryForNodes("/iq/session[@type='transport-accept']", - x.stanza)), - ] - else: - ta_event = [] - - nc, e = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewSessionHandler'), - *(ringing_event + ta_event) - )[0:2] - path, ct, ht, h, _ = nc.args - - assert ct == cs.CHANNEL_TYPE_STREAMED_MEDIA, ct - assert ht == cs.HT_CONTACT, ht - assert h == remote_handle, h - - media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') - media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - - # S-E was notified about new session handler, and calls Ready on it - assert e.args[1] == 'rtp' - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - nsh_event = q.expect('dbus-signal', signal='NewStreamHandler') - - # S-E gets notified about a newly-created stream - stream_handler = make_channel_proxy(conn, nsh_event.args[0], - 'Media.StreamHandler') - - streams = media_iface.ListStreams() - assertLength(1, streams) - - stream_id, stream_handle, stream_type, _, stream_direction, pending_flags =\ - streams[0] - assertEquals(remote_handle, stream_handle) - assertEquals(cs.MEDIA_STREAM_TYPE_AUDIO, stream_type) - assertEquals(cs.MEDIA_STREAM_DIRECTION_RECEIVE, stream_direction) - assertEquals(cs.MEDIA_STREAM_PENDING_LOCAL_SEND, pending_flags) - - # Exercise channel properties - channel_props = media_chan.GetAll( - cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals(remote_handle, channel_props['TargetHandle']) - assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) - assertEquals((cs.HT_CONTACT, remote_handle), - media_chan.GetHandle(dbus_interface=cs.CHANNEL)) - assertEquals(jt.peer_bare_jid, channel_props['TargetID']) - assertEquals(jt.peer_bare_jid, channel_props['InitiatorID']) - assertEquals(remote_handle, channel_props['InitiatorHandle']) - assertEquals(False, channel_props['Requested']) - - group_props = media_chan.GetAll( - cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) - - assert group_props['SelfHandle'] == self_handle, \ - (group_props['SelfHandle'], self_handle) - - flags = group_props['GroupFlags'] - assert flags & cs.GF_PROPERTIES, flags - # Changing members in any way other than adding or removing yourself is - # meaningless for incoming calls, and the flags need not be sent to change - # your own membership. - assert not flags & cs.GF_CAN_ADD, flags - assert not flags & cs.GF_CAN_REMOVE, flags - assert not flags & cs.GF_CAN_RESCIND, flags - - assert group_props['Members'] == [remote_handle], group_props['Members'] - assert group_props['RemotePendingMembers'] == [], \ - group_props['RemotePendingMembers'] - # We're local pending because remote_handle invited us. - assert group_props['LocalPendingMembers'] == \ - [(self_handle, remote_handle, cs.GC_REASON_INVITED, '')], \ - unwrap(group_props['LocalPendingMembers']) - - streams = media_chan.ListStreams( - dbus_interface=cs.CHANNEL_TYPE_STREAMED_MEDIA) - assert len(streams) == 1, streams - assert len(streams[0]) == 6, streams[0] - # streams[0][0] is the stream identifier, which in principle we can't - # make any assertion about (although in practice it's probably 1) - assert streams[0][1] == remote_handle, (streams[0], remote_handle) - assert streams[0][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] - # We haven't connected yet - assert streams[0][3] == cs.MEDIA_STREAM_STATE_DISCONNECTED, streams[0] - # In Gabble, incoming streams start off with remote send enabled, and - # local send requested - assert streams[0][4] == cs.MEDIA_STREAM_DIRECTION_RECEIVE, streams[0] - assert streams[0][5] == cs.MEDIA_STREAM_PENDING_LOCAL_SEND, streams[0] - - # Connectivity checks happen before we have accepted the call - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - stream_handler.SupportedCodecs(jt.get_audio_codecs_dbus()) - - # peer gets the transport - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - assertEquals(jt.peer, e.query['initiator']) - - if jp.dialect in ['jingle-v0.15', 'jingle-v0.31']: - content = xpath.queryForNodes('/iq/jingle/content', e.stanza)[0] - assertEquals('initiator', content['creator']) - - stream.send(make_result_iq(stream, e.stanza)) - - # At last, accept the call - media_chan.AddMembers([self_handle], 'accepted') - - # Call is accepted, we become a member, and the stream that was pending - # local send is now sending. - memb, acc, _, _, _ = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [self_handle], [], [], [], self_handle, - cs.GC_REASON_NONE]), - EventPattern('stream-iq', - predicate=jp.action_predicate('session-accept')), - EventPattern('dbus-signal', signal='SetStreamSending', args=[True]), - EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]), - EventPattern('dbus-signal', signal='StreamDirectionChanged', - args=[stream_id, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]), - ) - - stream.send(make_result_iq(stream, acc.stanza)) - - # Also, if this is a Jingle dialect that supports it, Gabble should send an - # <active/> notification when the session-accept is acked (until the - # Telepathy spec lets the UI say it's not ringing any more). - active_event = jp.rtp_info_event("active") - if active_event is not None: - q.expect_many(active_event) - - # we are now both in members - members = media_chan.GetMembers() - assert set(members) == set([self_handle, remote_handle]), members - - # Connected! Blah, blah, ... - - # 'Nuff said - jt.terminate() - q.expect('dbus-signal', signal='Closed', path=path) - -if __name__ == '__main__': - test_all_dialects(test) - test_all_dialects(lambda jp, q, bus, conn, stream: - test(jp, q, bus, conn, stream, 'foo@sip.bar.com')) diff --git a/tests/twisted/jingle/incoming-call-stream-error.py b/tests/twisted/jingle/incoming-call-stream-error.py deleted file mode 100644 index b6a9e25b7..000000000 --- a/tests/twisted/jingle/incoming-call-stream-error.py +++ /dev/null @@ -1,107 +0,0 @@ - -""" -Test handling of Error() call on stream handler. - -This tests a regression in which MembersChanged was emitted with reason other -than GC_REASON_ERROR. -""" - -from servicetest import EventPattern, assertEquals, make_channel_proxy -from jingletest2 import JingleTest2, test_all_dialects -import constants as cs - -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def _session_terminate_predicate(event, reason, msg, jp): - matches = jp.match_jingle_action(event.query, 'session-terminate') - - if matches and jp.is_modern_jingle(): - reason = xpath.queryForNodes("/iq" - "/jingle[@action='session-terminate']" - "/reason/%s" % reason, - event.stanza) - reason_text = xpath.queryForString("/iq/jingle/reason/text", - event.stanza) - - return bool(reason) and reason_text == msg - - return matches - -def _test(jp, q, bus, conn, stream, - jingle_reason, group_change_reason, stream_error): - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt.prepare() - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] - - # Ring ring! - jt.incoming_call() - new_channel, new_session_handler = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewSessionHandler')) - assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, new_channel.args[1]) - assertEquals(cs.HT_CONTACT, new_channel.args[2]) - assertEquals(remote_handle, new_channel.args[3]) - assertEquals('rtp', new_session_handler.args[1]) - - channel_path = new_channel.args[0] - - # Client calls Ready on new session handler. - session_handler = make_channel_proxy( - conn, new_session_handler.args[0], 'Media.SessionHandler') - session_handler.Ready() - - # Client gets notified about a newly created stream... - new_stream_handler = q.expect('dbus-signal', signal='NewStreamHandler') - stream_id = new_stream_handler.args[1] - stream_handler = make_channel_proxy( - conn, new_stream_handler.args[0], 'Media.StreamHandler') - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.dbusify_codecs([("FOO", 5, 8000, {})])) - - q.expect('dbus-signal', signal='SetRemoteCodecs') - - msg = u"o noes" - - # ...but something goes wrong. - stream_handler.Error(stream_error, msg) - - q.expect("stream-iq", iq_type="set", - predicate=lambda x: _session_terminate_predicate(x, jingle_reason, - msg, jp)) - # Bye bye members. - mc = q.expect('dbus-signal', signal='MembersChanged', - interface=cs.CHANNEL_IFACE_GROUP, path=channel_path, - args=[msg, [], [self_handle, remote_handle], [], - [], self_handle, group_change_reason]) - - q.expect('dbus-signal', signal='StreamError', - interface=cs.CHANNEL_TYPE_STREAMED_MEDIA, - args=[stream_id, stream_error, msg]) - - # Bye bye stream - q.expect('dbus-signal', signal='Close') - q.expect('dbus-signal', signal='StreamRemoved') - - # Bye bye channel. - q.expect('dbus-signal', signal='Closed') - q.expect('dbus-signal', signal='ChannelClosed') - -def test_connection_error(jp, q, bus, conn, stream): - _test(jp, q, bus, conn, stream, "connectivity-error", cs.GC_REASON_ERROR, - cs.MEDIA_STREAM_ERROR_NETWORK_ERROR) - -def test_codec_negotiation_fail(jp, q, bus, conn, stream): - _test(jp, q, bus, conn, stream, "failed-application", cs.GC_REASON_ERROR, - cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED) - -if __name__ == '__main__': - test_all_dialects(test_connection_error) - test_all_dialects(test_codec_negotiation_fail) diff --git a/tests/twisted/jingle/incoming-gmail-modern-jingle.py b/tests/twisted/jingle/incoming-gmail-modern-jingle.py deleted file mode 100644 index 033a9975d..000000000 --- a/tests/twisted/jingle/incoming-gmail-modern-jingle.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -Tests workarounds for calls with the GMail client, which supports a (currently -quirky) variation on the theme of modern Jingle. -""" - -from servicetest import EventPattern, wrap_channel, make_channel_proxy, assertEquals -from gabbletest import elem, elem_iq, exec_test -from jingletest2 import JingleTest2, JingleProtocol031 -import ns -import constants as cs -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -class GMail(JingleTest2): - remote_caps = { - 'ext': 'pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1', - 'ver': '1.1', - 'node': 'http://mail.google.com/xmpp/client/caps', - } - -def test(q, bus, conn, stream): - peer = 'foo@gmail.com/gmail.7E1F07D0' - self = 'test@localhost/test' - jp = JingleProtocol031() - jt = GMail(jp, conn, q, stream, 'test@localhost', peer) - jt.prepare(send_roster=False) - - sid = 'c1025763497' - 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')( - elem('payload-type', id='99', name='H264-SVC')( - elem('parameter', name='width', value='320'), - elem('parameter', name='height', value='200'), - elem('parameter', name='framerate', value='30'), - ), - # ... other codecs elided ... - elem('encryption'), - ), - elem(ns.GOOGLE_P2P, 'transport'), - ), - elem('content', name='audio')( - elem(ns.JINGLE_RTP, 'description', media='audio')( - elem('payload-type', id='103', name='ISAC', clockrate='16000')( - elem('parameter', name='bitrate', value='32000'), - ), - # ... other codecs elided ... - elem('encryption'), - ), - elem(ns.GOOGLE_P2P, 'transport'), - ) - ), - elem(ns.GOOGLE_SESSION, 'session', action='initiate', sid='c1025763497', initiator=peer)( - elem(ns.GOOGLE_SESSION_VIDEO, 'description')( - elem('payload-type', id='99', name='H264-SVC', width='320', height='200', framerate='30'), - # ... other codecs elided ... - elem(ns.JINGLE_RTP, 'encryption')( - elem(ns.GOOGLE_SESSION_VIDEO, 'usage'), - ), - elem(ns.GOOGLE_SESSION_PHONE, 'payload-type', id='103', name='ISAC', bitrate='32000', clockrate='16000'), - # ... other codecs elided ... - elem(ns.JINGLE_RTP, 'encryption')( - elem(ns.GOOGLE_SESSION_PHONE, 'usage'), - ), - ), - ), - ) - stream.send(si) - - 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'), - ) - - path, properties = nc.args[0][0] - - # It's an audio+video call - assert properties[cs.INITIAL_AUDIO] - assert properties[cs.INITIAL_VIDEO] - # Google can't add and remove streams on the fly. We special-case GMail. - assert properties[cs.IMMUTABLE_STREAMS] - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - session_handler = make_channel_proxy(conn, nsh.args[0], 'Media.SessionHandler') - session_handler.Ready() - - path, _, _, _ = q.expect('dbus-signal', signal='NewStreamHandler').args - stream1 = make_channel_proxy(conn, path, 'Media.StreamHandler') - path, _, _, _ = q.expect('dbus-signal', signal='NewStreamHandler').args - stream2 = make_channel_proxy(conn, path, 'Media.StreamHandler') - - stream1.Ready([]) - stream2.Ready([]) - - # Audio rtcp - stream.send( - elem_iq(stream, from_=peer, to=self, type='set')( - elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( - elem('content', name='audio')( - elem(ns.GOOGLE_P2P, 'transport')( - elem('candidate', address='172.22.64.192', port='54335', - name='rtcp', username='+wJqkmRVYotCz+Rd', - password='POWPzg5Pks4+ywAz', preference='1', protocol='udp', - generation='0', network='1', type='local') - ) - ) - ) - ) - ) - q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream1.object_path) - - # audio rtp - stream.send( - elem_iq(stream, from_=peer, to=self, type='set')( - elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( - elem('content', name='audio')( - elem(ns.GOOGLE_P2P, 'transport')( - elem('candidate', address='172.22.64.192', port='54337', - name='rtp', username='F7rgdWcCgH3Q/HgE', - password='ioh2IDwd3iZEZHzM', preference='1', protocol='udp', - generation='0', network='1', type='local') - ) - ) - ) - ) - ) - q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream1.object_path) - - # video rtcp: note the weird name='' field which Gabble has to work around - stream.send( - elem_iq(stream, from_=peer, to=self, type='set')( - elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( - elem('content', name='video')( - elem(ns.GOOGLE_P2P, 'transport')( - elem('candidate', address='172.22.64.192', port='54339', - name='video_rtcp', username='fnLduEIu6VHsSOqh', - password='IYeNu/HWzMpx2zrS', preference='1', protocol='udp', - generation='0', network='1', type='local') - ) - ) - ) - ) - ) - q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream2.object_path) - - # video rtp: ditto - stream.send( - elem_iq(stream, from_=peer, to=self, type='set')( - elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( - elem('content', name='video')( - elem(ns.GOOGLE_P2P, 'transport')( - elem('candidate', address='172.22.64.192', port='54341', - name='video_rtp', username='mZVBFdQ2LyAP6oyE', - password='3uoyCHP8zwE+/Ylw', preference='1', protocol='udp', - generation='0', network='1', type='local') - ) - ) - ) - ) - ) - q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream2.object_path) - - # Test that we're sending with name='video_rtp' as well, but only for the video stream. - stream1.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - candidate = xpath.queryForNodes( - '/iq/jingle/content[@name="audio"]/transport/candidate', - e.stanza)[0] - assertEquals('rtp', candidate['name']) - - stream2.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - candidate = xpath.queryForNodes( - '/iq/jingle/content[@name="video"]/transport/candidate', - e.stanza)[0] - assertEquals('video_rtp', candidate['name']) - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/jingle/initial-audio-video.py b/tests/twisted/jingle/initial-audio-video.py deleted file mode 100644 index 49bb285aa..000000000 --- a/tests/twisted/jingle/initial-audio-video.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Tests outgoing calls created with InitialAudio and/or InitialVideo, and -exposing the initial contents of incoming calls as values of InitialAudio and -InitialVideo -""" - -import operator - -from servicetest import ( - assertContains, assertEquals, assertLength, - wrap_channel, EventPattern, call_async, make_channel_proxy) - -from jingletest2 import JingleTest2, test_all_dialects - -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def outgoing(jp, q, bus, conn, stream): - remote_jid = 'flames@cold.mountain/beyond' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS, 'RequestableChannelClasses') - media_classes = [ rcc for rcc in rccs - if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAMED_MEDIA ] - - assertLength(1, media_classes) - fixed, allowed = media_classes[0] - assertContains(cs.INITIAL_AUDIO, allowed) - assertContains(cs.INITIAL_VIDEO, allowed) - - check_neither(q, conn, bus, stream, remote_handle) - check_iav(jt, q, conn, bus, stream, remote_handle, True, False) - check_iav(jt, q, conn, bus, stream, remote_handle, False, True) - check_iav(jt, q, conn, bus, stream, remote_handle, True, True) - -def check_neither(q, conn, bus, stream, remote_handle): - """ - Make a channel without specifying InitialAudio or InitialVideo; check - that it's announced with both False, and that they're both present and - false in GetAll(). - """ - - path, props = conn.Requests.CreateChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle}) - - assertContains((cs.INITIAL_AUDIO, False), props.items()) - assertContains((cs.INITIAL_VIDEO, False), props.items()) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), - cs.CHANNEL_TYPE_STREAMED_MEDIA, ['MediaSignalling']) - props = chan.Properties.GetAll(cs.CHANNEL_TYPE_STREAMED_MEDIA) - assertContains(('InitialAudio', False), props.items()) - assertContains(('InitialVideo', False), props.items()) - - # We shouldn't have started a session yet, so there shouldn't be any - # session handlers. Strictly speaking, there could be a session handler - # with no stream handlers, but... - session_handlers = chan.MediaSignalling.GetSessionHandlers() - assertLength(0, session_handlers) - -def check_iav(jt, q, conn, bus, stream, remote_handle, initial_audio, - initial_video): - """ - Make a channel and check that its InitialAudio and InitialVideo properties - come out correctly. - """ - - call_async(q, conn.Requests, 'CreateChannel', { - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle, - cs.INITIAL_AUDIO: initial_audio, - cs.INITIAL_VIDEO: initial_video, - }) - if initial_video and (not jt.jp.can_do_video() - or (not initial_audio and not jt.jp.can_do_video_only ())): - # Some protocols can't do video - event = q.expect('dbus-error', method='CreateChannel') - assertEquals(cs.NOT_CAPABLE, event.error.get_dbus_name()) - else: - path, props = q.expect('dbus-return', method='CreateChannel').value - - assertContains((cs.INITIAL_AUDIO, initial_audio), props.items()) - assertContains((cs.INITIAL_VIDEO, initial_video), props.items()) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), - cs.CHANNEL_TYPE_STREAMED_MEDIA, ['MediaSignalling']) - props = chan.Properties.GetAll(cs.CHANNEL_TYPE_STREAMED_MEDIA) - assertContains(('InitialAudio', initial_audio), props.items()) - assertContains(('InitialVideo', initial_video), props.items()) - - session_handlers = chan.MediaSignalling.GetSessionHandlers() - - assertLength(1, session_handlers) - path, type = session_handlers[0] - assertEquals('rtp', type) - session_handler = make_channel_proxy(conn, path, 'Media.SessionHandler') - session_handler.Ready() - - stream_handler_paths = [] - stream_handler_types = [] - - for x in [initial_audio, initial_video]: - if x: - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_handler_paths.append(e.args[0]) - stream_handler_types.append(e.args[2]) - - if initial_audio: - assertContains(cs.MEDIA_STREAM_TYPE_AUDIO, stream_handler_types) - - if initial_video: - assertContains(cs.MEDIA_STREAM_TYPE_VIDEO, stream_handler_types) - - for x in xrange (0, len(stream_handler_paths)): - p = stream_handler_paths[x] - t = stream_handler_types[x] - sh = make_channel_proxy(conn, p, 'Media.StreamHandler') - sh.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - if t == cs.MEDIA_STREAM_TYPE_AUDIO: - sh.Ready(jt.get_audio_codecs_dbus()) - else: - sh.Ready(jt.get_video_codecs_dbus()) - sh.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', - predicate=jt.jp.action_predicate('session-initiate')) - jt.parse_session_initiate (e.query) - - jt.accept() - - events = reduce(operator.concat, - [ [ EventPattern('dbus-signal', signal='SetRemoteCodecs', path=p), - EventPattern('dbus-signal', signal='SetStreamPlaying', path=p), - ] for p in stream_handler_paths - ], []) - q.expect_many(*events) - - chan.Close() - -def incoming(jp, q, bus, conn, stream): - remote_jid = 'skinny.fists@heaven/antennas' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - for a, v in [("audio1", None), (None, "video1"), ("audio1", "video1")]: - if v!= None and not jp.can_do_video(): - continue - if a == None and v != None and not jp.can_do_video_only(): - continue - - jt.incoming_call(audio=a, video=v) - e = q.expect('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()) - chans = e.args[0] - assertLength(1, chans) - - path, props = chans[0] - - assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, props[cs.CHANNEL_TYPE]) - assertEquals(a != None, props[cs.INITIAL_AUDIO]) - assertEquals(v != None, props[cs.INITIAL_VIDEO]) - - # FIXME: This doesn't check non-Google contacts that can only do one - # media type, as such contacts as simulated by JingleTest2 can always - # do both. - assertEquals(not jp.can_do_video() or not jp.can_do_video_only(), - props[cs.IMMUTABLE_STREAMS]) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), - cs.CHANNEL_TYPE_STREAMED_MEDIA) - chan.Close() - - -if __name__ == '__main__': - test_all_dialects(outgoing) - test_all_dialects(incoming) diff --git a/tests/twisted/jingle/jingletest2.py b/tests/twisted/jingle/jingletest2.py index 64eaa40e8..1883960c1 100644 --- a/tests/twisted/jingle/jingletest2.py +++ b/tests/twisted/jingle/jingletest2.py @@ -823,18 +823,18 @@ class JingleTest2(object): def get_call_audio_md_dbus(self, handle = 0): d = dbus.Dictionary( - { cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs': self.__get_call_audio_codecs_dbus(), + { cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs': self.__get_call_audio_codecs_dbus(), }, signature='sv') if handle != 0: - d[cs.CALL_CONTENT_MEDIADESCRIPTION + '.RemoteContact'] = dbus.UInt32 (handle) + d[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.RemoteContact'] = dbus.UInt32 (handle) return d def get_call_video_md_dbus(self, handle = 0): d = dbus.Dictionary( - { cs.CALL_CONTENT_MEDIADESCRIPTION + '.Codecs': self.__get_call_video_codecs_dbus(), + { cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.Codecs': self.__get_call_video_codecs_dbus(), }, signature='sv') if handle != 0: - d[cs.CALL_CONTENT_MEDIADESCRIPTION + '.RemoteContact'] = dbus.UInt32 (handle) + d[cs.CALL_CONTENT_MEDIA_DESCRIPTION + '.RemoteContact'] = dbus.UInt32 (handle) return d def get_remote_transports_dbus(self): diff --git a/tests/twisted/jingle/misuse.py b/tests/twisted/jingle/misuse.py deleted file mode 100644 index 51283b4c0..000000000 --- a/tests/twisted/jingle/misuse.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -Test misuse of the streamed media API, which should return error messages -rather than asserting Gabble. -""" - -from dbus import DBusException - -from servicetest import make_channel_proxy, wrap_channel, assertEquals -from gabbletest import exec_test -from jingletest2 import JingleTest2, JingleProtocol031 - -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream): - jp = JingleProtocol031() - remote_jid = 'foo@example.com/misc' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - path, _ = conn.Requests.CreateChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle}) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - - # In Gabble, the StreamedMedia channel is secretly also the SessionHandler. - # Let's make up a proxy and call some methods on it. They should fail - # gracefully, rather than crashing Gabble. - session_handler = make_channel_proxy(conn, path, 'Media.SessionHandler') - - try: - session_handler.Ready() - except DBusException, e: - assertEquals(cs.NOT_AVAILABLE, e.get_dbus_name()) - - try: - session_handler.Error(0, "slowing down but with a sense of speeding up") - except DBusException, e: - assertEquals(cs.NOT_AVAILABLE, e.get_dbus_name()) - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/jingle/outgoing-basics.py b/tests/twisted/jingle/outgoing-basics.py deleted file mode 100644 index 0e9a5f269..000000000 --- a/tests/twisted/jingle/outgoing-basics.py +++ /dev/null @@ -1,349 +0,0 @@ -""" -Test basic outgoing call handling, using CreateChannel and all three variations -of RequestChannel. -""" -from functools import partial -import dbus -from twisted.words.xish import xpath - -from gabbletest import exec_test -from servicetest import ( - make_channel_proxy, wrap_channel, - EventPattern, call_async, - assertEquals, assertContains, assertLength, - ) -import constants as cs -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -# There are various deprecated APIs for requesting calls, documented at -# <http://telepathy.freedesktop.org/wiki/Requesting StreamedMedia channels>. -# These are ordered from most recent to most deprecated. -CREATE = 0 # CreateChannel({TargetHandleType: Contact, TargetHandle: h}); - # RequestStreams() -REQUEST_ANONYMOUS = 1 # RequestChannel(HandleTypeNone, 0); RequestStreams() -REQUEST_ANONYMOUS_AND_ADD = 2 # RequestChannel(HandleTypeNone, 0); - # AddMembers([h], ...); RequestStreams(h,...) -REQUEST_NONYMOUS = 3 # RequestChannel(HandleTypeContact, h); - # RequestStreams(h, ...) - -def create(jp, q, bus, conn, stream, peer='foo@bar.com/Res'): - worker(jp, q, bus, conn, stream, CREATE, peer) - -def request_anonymous(jp, q, bus, conn, stream, peer='publish@foo.com/Res'): - worker(jp, q, bus, conn, stream, REQUEST_ANONYMOUS, peer) - -def request_anonymous_and_add(jp, q, bus, conn, stream, - peer='publish-subscribe@foo.com/Res'): - worker(jp, q, bus, conn, stream, REQUEST_ANONYMOUS_AND_ADD, peer) - -def request_nonymous(jp, q, bus, conn, stream, peer='subscribe@foo.com/Res'): - worker(jp, q, bus, conn, stream, REQUEST_NONYMOUS, peer) - -def worker(jp, q, bus, conn, stream, variant, peer): - jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', peer) - jt2.prepare(send_presence=True, send_roster=True) - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(1, [jt2.peer])[0] - - if variant == REQUEST_NONYMOUS: - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, remote_handle, True) - elif variant == CREATE: - path = conn.Requests.CreateChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle, - })[0] - else: - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_NONE, 0, True) - - old_sig, new_sig = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), - ) - - if variant == REQUEST_NONYMOUS or variant == CREATE: - assertEquals( [path, cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, - remote_handle, True], old_sig.args) - else: - assertEquals( [path, cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_NONE, 0, - True], old_sig.args) - - assertLength(1, new_sig.args) - assertLength(1, new_sig.args[0]) # one channel - assertLength(2, new_sig.args[0][0]) # two struct members - emitted_props = new_sig.args[0][0][1] - - assertEquals( - cs.CHANNEL_TYPE_STREAMED_MEDIA, emitted_props[cs.CHANNEL_TYPE]) - - if variant == REQUEST_NONYMOUS or variant == CREATE: - assertEquals(remote_handle, emitted_props[cs.TARGET_HANDLE]) - assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals(jt2.peer_bare_jid, emitted_props[cs.TARGET_ID]) - else: - assertEquals(0, emitted_props[cs.TARGET_HANDLE]) - assertEquals(cs.HT_NONE, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals('', emitted_props[cs.TARGET_ID]) - - assertEquals(True, emitted_props[cs.REQUESTED]) - assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE]) - assertEquals('test@localhost', emitted_props[cs.INITIATOR_ID]) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', - ['MediaSignalling']) - - # Exercise basic Channel Properties - channel_props = chan.Properties.GetAll(cs.CHANNEL) - - assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, - channel_props.get('ChannelType')) - - if variant == REQUEST_NONYMOUS or variant == CREATE: - assertEquals(remote_handle, channel_props['TargetHandle']) - assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) - assertEquals(jt2.peer_bare_jid, channel_props['TargetID']) - assertEquals((cs.HT_CONTACT, remote_handle), chan.GetHandle()) - else: - assertEquals(0, channel_props['TargetHandle']) - assertEquals(cs.HT_NONE, channel_props['TargetHandleType']) - assertEquals('', channel_props['TargetID']) - assertEquals((cs.HT_NONE, 0), chan.GetHandle()) - - for interface in [ - cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_MEDIA_SIGNALLING, - cs.TP_AWKWARD_PROPERTIES, cs.CHANNEL_IFACE_HOLD]: - assertContains(interface, channel_props['Interfaces']) - - assertEquals(True, channel_props['Requested']) - assertEquals('test@localhost', channel_props['InitiatorID']) - assertEquals(conn.GetSelfHandle(), channel_props['InitiatorHandle']) - - # Exercise Group Properties - group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) - - assertEquals([self_handle], group_props['Members']) - assertEquals([], group_props['LocalPendingMembers']) - - if variant == REQUEST_NONYMOUS: - # In this variant, they're meant to be in RP even though we've sent - # nothing - assertEquals([remote_handle], group_props['RemotePendingMembers']) - else: - # For an anonymous channel, the peer isn't yet known; for a Create-d - # channel, the peer only appears in RP when we actually send them the - # session-initiate - assertEquals([], group_props['RemotePendingMembers']) - - if variant == REQUEST_ANONYMOUS_AND_ADD: - # but we should be allowed to add the peer. - chan.Group.AddMembers([remote_handle], 'I love backwards compat') - - base_flags = cs.GF_MEMBERS_CHANGED_DETAILED | cs.GF_PROPERTIES | cs.GF_MESSAGE_REMOVE \ - | cs.GF_MESSAGE_REJECT | cs.GF_MESSAGE_RESCIND - - if variant == REQUEST_ANONYMOUS_AND_ADD or variant == REQUEST_ANONYMOUS: - expected_flags = base_flags | cs.GF_CAN_ADD - else: - expected_flags = base_flags - assertEquals(expected_flags, group_props['GroupFlags']) - assertEquals({}, group_props['HandleOwners']) - - assertEquals([], chan.StreamedMedia.ListStreams()) - streams = chan.StreamedMedia.RequestStreams(remote_handle, - [cs.MEDIA_STREAM_TYPE_AUDIO]) - assertEquals(streams, chan.StreamedMedia.ListStreams()) - assertLength(1, streams) - - # streams[0][0] is the stream identifier, which in principle we can't - # make any assertion about (although in practice it's probably 1) - - assertEquals(( - remote_handle, - cs.MEDIA_STREAM_TYPE_AUDIO, - # We haven't connected yet - cs.MEDIA_STREAM_STATE_DISCONNECTED, - # In Gabble, requested streams start off bidirectional - cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - 0), - streams[0][1:]) - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(jt2.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - sh_props = stream_handler.GetAll( - cs.STREAM_HANDLER, dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals('gtalk-p2p', sh_props['NATTraversal']) - assertEquals(True, sh_props['CreatedLocally']) - - if variant == CREATE: - # When we actually send XML to the peer, they should pop up in remote - # pending. - session_initiate, _ = q.expect_many( - EventPattern('stream-iq', iq_type='set', predicate=lambda e: - jp.match_jingle_action(e.query, 'session-initiate')), - EventPattern('dbus-signal', signal='MembersChanged', - args=["", [], [], [], [remote_handle], self_handle, - cs.GC_REASON_INVITED]), - ) - else: - forbidden = [] - - if peer.split('/', 1)[0] in ( - 'publish@foo.com', 'publish-subscribe@foo.com'): - forbidden = [EventPattern('stream-presence')] - q.forbid_events(forbidden) - else: - # we're calling someone not on our roster, so we'll send directed - # presence first - presence = q.expect('stream-presence') - assert (xpath.queryForNodes('/presence/c', presence.stanza) - is not None) - assert (xpath.queryForNodes( - '/presence/x[@xmlns="vcard-temp:x:update"]', presence.stanza) - is not None) - - session_initiate = q.expect('stream-iq', - predicate=jp.action_predicate('session-initiate')) - - if forbidden: - q.unforbid_events(forbidden) - - jt2.parse_session_initiate(session_initiate.query) - stream.send(jp.xml(jp.ResultIq('test@localhost', session_initiate.stanza, - []))) - - # Check the Group interface's properties again. Regardless of the call - # requesting API in use, the state should be the same here: - group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) - assertContains('HandleOwners', group_props) - assertEquals([self_handle], group_props['Members']) - assertEquals([], group_props['LocalPendingMembers']) - assertEquals([remote_handle], group_props['RemotePendingMembers']) - - if jp.dialect == 'gtalk-v0.4': - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'transport-accept', [ - jp.TransportGoogleP2P() ]) ]) - stream.send(jp.xml(node)) - - # FIXME: expect transport-info, then if we're gtalk3, send - # candidates, and check that gabble resends transport-info as - # candidates - jt2.accept() - - q.expect_many( - EventPattern('stream-iq', iq_type='result'), - # Call accepted - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [remote_handle], [], [], [], remote_handle, - cs.GC_REASON_NONE]), - ) - - # Time passes ... afterwards we close the chan - - chan.Group.RemoveMembers([self_handle], 'closed') - - # Make sure gabble sends proper terminate action - if jp.dialect.startswith('gtalk'): - terminate = EventPattern('stream-iq', predicate=lambda x: - xpath.queryForNodes("/iq/session[@type='terminate']", - x.stanza)) - else: - terminate = EventPattern('stream-iq', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='session-terminate']", - x.stanza)) - - mc_event, _, _ = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged'), - EventPattern('dbus-signal', signal='Close'), - terminate, - ) - # Check that we're the actor - assertEquals(self_handle, mc_event.args[5]) - -def rccs(q, bus, conn, stream): - """ - Tests that the connection's RequestableChannelClasses for StreamedMedia are - sane. - """ - rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS, - 'RequestableChannelClasses') - - # Test Channel.Type.StreamedMedia - media_classes = [ rcc for rcc in rccs - if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAMED_MEDIA ] - - assertLength(1, media_classes) - - fixed, allowed = media_classes[0] - - assertEquals(cs.HT_CONTACT, fixed[cs.TARGET_HANDLE_TYPE]) - - expected_allowed = [ - cs.TARGET_ID, cs.TARGET_HANDLE, - cs.INITIAL_VIDEO, cs.INITIAL_AUDIO - ] - - allowed.sort() - expected_allowed.sort() - assertEquals(expected_allowed, allowed) - - # Test Channel.Type.Call - media_classes = [ rcc for rcc in rccs - if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL ] - assertLength(2, media_classes) - - hts = [] - - for mc in media_classes: - fixed, allowed = mc - - hts.append (fixed[cs.TARGET_HANDLE_TYPE]) - - expected_allowed = [ - cs.TARGET_ID, cs.TARGET_HANDLE, - cs.CALL_INITIAL_VIDEO, cs.CALL_INITIAL_AUDIO, - cs.CALL_INITIAL_VIDEO_NAME, cs.CALL_INITIAL_AUDIO_NAME, - cs.CALL_MUTABLE_CONTENTS - ] - - allowed.sort() - expected_allowed.sort() - assertEquals(expected_allowed, allowed) - - assertEquals(sorted([cs.HT_CONTACT, cs.HT_ROOM]), sorted(hts)) - -if __name__ == '__main__': - exec_test(rccs) - test_all_dialects(create) - test_all_dialects(request_anonymous) - test_all_dialects(request_anonymous_and_add) - test_all_dialects(request_nonymous) - test_all_dialects(partial(create, peer='foo@gw.bar.com')) - test_all_dialects(partial(request_anonymous, peer='foo@gw.bar.com')) - test_all_dialects(partial(request_anonymous_and_add, peer='foo@gw.bar.com')) - test_all_dialects(partial(request_nonymous, peer='foo@gw.bar.com')) diff --git a/tests/twisted/jingle/outgoing-ensure.py b/tests/twisted/jingle/outgoing-ensure.py deleted file mode 100644 index a5bab23c7..000000000 --- a/tests/twisted/jingle/outgoing-ensure.py +++ /dev/null @@ -1,217 +0,0 @@ -""" -Test making outgoing calls using EnsureChannel, and retrieving existing calls -using EnsureChannel. - -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, - call_async, EventPattern, - assertEquals, assertLength, - ) -import constants as cs -from jingletest2 import JingleProtocol031, JingleTest2 - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream, channel_type): - jt = JingleTest2(JingleProtocol031(), conn, q, stream, 'test@localhost', - 'foo@sip.bar.com') - jt.prepare() - - self_handle = conn.GetSelfHandle() - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - - request = { cs.CHANNEL_TYPE: channel_type, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: handle} - - if channel_type == cs.CHANNEL_TYPE_CALL: - request[cs.CALL_INITIAL_AUDIO] = True - - # Ensure a channel that doesn't exist yet. - call_async(q, conn.Requests, 'EnsureChannel', request) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='EnsureChannel'), - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), - ) - - yours, path, props = ret.value - - # this channel was created in response to our EnsureChannel call, so it - # should be ours. - assert yours, ret.value - - sig_path, sig_ct, sig_ht, sig_h, sig_sh = old_sig.args - - assertEquals(sig_path, path) - assertEquals(channel_type, sig_ct) - assertEquals(cs.HT_CONTACT, sig_ht) - assertEquals(handle, sig_h) - assert sig_sh # suppress handler - - assertLength(1, new_sig.args) - assertLength(1, new_sig.args[0]) # one channel - assertLength(2, new_sig.args[0][0]) # two struct members - assertEquals(path, new_sig.args[0][0][0]) - emitted_props = new_sig.args[0][0][1] - - assertEquals(channel_type, emitted_props[cs.CHANNEL_TYPE]) - assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals(handle, emitted_props[cs.TARGET_HANDLE]) - assertEquals(jt.peer_bare_jid, emitted_props[cs.TARGET_ID]) - assert emitted_props[cs.REQUESTED] - assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE]) - assertEquals('test@localhost', emitted_props[cs.INITIATOR_ID]) - - # Now ensure a media channel with the same contact, and check it's the - # same. - call_async(q, conn.Requests, 'EnsureChannel', request) - - event = q.expect('dbus-return', method='EnsureChannel') - yours2, path2, props2 = event.value - - # We should have got back the same channel we created a page or so ago. - assertEquals(path2, path) - # It's not been created for this call, so Yours should be False. - assert not yours2 - - # Time passes ... afterwards we close the chan - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - chan.Close() - - - # Ensure a channel that doesn't exist yet. - call_async(q, conn.Requests, 'EnsureChannel', request) - - # Re-ensure a channel that is hopefully still pending creation. - call_async(q, conn.Requests, 'EnsureChannel', request) - - ret, ret2, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='EnsureChannel'), - EventPattern('dbus-return', method='EnsureChannel'), - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), - ) - - yours, path, props = ret.value - - # this channel was created in response to our EnsureChannel call, so it - # should be ours. - assert yours, ret.value - - sig_path, sig_ct, sig_ht, sig_h, sig_sh = old_sig.args - - assertEquals(sig_path, path) - assertEquals(channel_type, sig_ct) - assertEquals(cs.HT_CONTACT, sig_ht) - assertEquals(handle, sig_h) - assert sig_sh # suppress handler - - assertLength(1, new_sig.args) - assertLength(1, new_sig.args[0]) # one channel - assertLength(2, new_sig.args[0][0]) # two struct members - assertEquals(path, new_sig.args[0][0][0]) - emitted_props = new_sig.args[0][0][1] - - assertEquals(channel_type, emitted_props[cs.CHANNEL_TYPE]) - assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals(handle, emitted_props[cs.TARGET_HANDLE]) - assertEquals(jt.peer_bare_jid, emitted_props[cs.TARGET_ID]) - assert emitted_props[cs.REQUESTED] - assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE]) - assertEquals('test@localhost', emitted_props[cs.INITIATOR_ID]) - - yours2, path2, props2 = ret2.value - - # We should have got back the same channel we created a page or so ago. - assertEquals(path2, path) - # It's not been created for this call, so Yours should be False. - assert not yours2 - - # Time passes ... afterwards we close the chan - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - chan.Close() - - - # The remaining checks don't apply to calls - if channel_type == cs.CHANNEL_TYPE_CALL: - return - - # Now, create an anonymous channel with RequestChannel, add the other - # person to it with RequestStreams, then Ensure a media channel with that - # person. We should get the anonymous channel back. - call_async( - q, conn, 'RequestChannel', channel_type, 0, 0, True) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), - ) - - path = ret.value[0] - assertEquals( - [path, channel_type, cs.HT_NONE, 0, True], - old_sig.args) - - assertLength(1, new_sig.args) - assertLength(1, new_sig.args[0]) # one channel - assertLength(2, new_sig.args[0][0]) # two struct members - assertEquals(path, new_sig.args[0][0][0]) - emitted_props = new_sig.args[0][0][1] - - assertEquals(channel_type, emitted_props[cs.CHANNEL_TYPE]) - assertEquals(cs.HT_NONE, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals(0, emitted_props[cs.TARGET_HANDLE]) - assertEquals('', emitted_props[cs.TARGET_ID]) - assert emitted_props[cs.REQUESTED] - assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE]) - assertEquals('test@localhost', emitted_props[cs.INITIATOR_ID]) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - - # Request streams with the other person. This should make them the - # channel's "peer" property. - chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_AUDIO]) - - # Now, Ensuring a media channel with handle should yield the channel just - # created. - - call_async(q, conn.Requests, 'EnsureChannel', request) - - event = q.expect('dbus-return', method='EnsureChannel') - yours, path2, _ = event.value - - # we should have got back the anonymous channel we got with requestchannel - # and called RequestStreams(handle) on. - assertEquals(path2, path) - # It's not been created for this call, so Yours should be False. - assert not yours - - chan.Close() - -if __name__ == '__main__': - 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 deleted file mode 100644 index b93ce616c..000000000 --- a/tests/twisted/jingle/outgoing-many-streams.py +++ /dev/null @@ -1,221 +0,0 @@ - -""" -Test making outgoing call using CreateChannel. This tests the happy scenario -when the remote party accepts the call. -""" - -import dbus - -from gabbletest import exec_test, sync_stream -from servicetest import ( - make_channel_proxy, call_async, EventPattern) -import jingletest2 -import gabbletest - -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream): - worker(q, bus, conn, stream, 'foo@bar.com/Foo') - worker(q, bus, conn, stream, 'foo@sip.bar.com') - -def worker(q, bus, conn, stream, peer): - jp = jingletest2.JingleProtocol031() - jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', peer) - - self_handle = conn.GetSelfHandle() - jt.send_presence_and_caps() - - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - - call_async(q, conn.Requests, 'CreateChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: handle, - }) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), - ) - - path = ret.value[0] - - sig_path, sig_ct, sig_ht, sig_h, sig_sh = old_sig.args - - assert sig_path == path, (sig_path, path) - assert sig_ct == cs.CHANNEL_TYPE_STREAMED_MEDIA, sig_ct - assert sig_ht == cs.HT_CONTACT, sig_ht - assert sig_h == handle, sig_h - assert sig_sh == True # suppress handler - - assert len(new_sig.args) == 1 - assert len(new_sig.args[0]) == 1 # one channel - assert len(new_sig.args[0][0]) == 2 # two struct members - assert new_sig.args[0][0][0] == path - emitted_props = new_sig.args[0][0][1] - - 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.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' - - 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') - - # Exercise basic Channel Properties from spec 0.17.7 - channel_props = group_iface.GetAll(cs.CHANNEL, - dbus_interface=dbus.PROPERTIES_IFACE) - assert channel_props.get('TargetHandle') == handle, \ - channel_props.get('TargetHandle') - assert channel_props.get('TargetHandleType') == cs.HT_CONTACT,\ - channel_props.get('TargetHandleType') - assert media_iface.GetHandle(dbus_interface=cs.CHANNEL) == (cs.HT_CONTACT, - handle) - assert channel_props.get('ChannelType') == cs.CHANNEL_TYPE_STREAMED_MEDIA,\ - channel_props.get('ChannelType') - - interfaces = channel_props['Interfaces'] - for i in [cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_MEDIA_SIGNALLING, - cs.TP_AWKWARD_PROPERTIES, cs.CHANNEL_IFACE_HOLD]: - assert i in interfaces, (i, interfaces) - - 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 - - # Exercise Group Properties from spec 0.17.6 (in a basic way) - group_props = group_iface.GetAll(cs.CHANNEL_IFACE_GROUP, - dbus_interface=dbus.PROPERTIES_IFACE) - 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 - - # The remote contact shouldn't be in remote pending yet (nor should it be - # in members!) - assert handle not in group_props['RemotePendingMembers'], group_props - assert handle not in group_props['Members'], group_props - - list_streams_result = media_iface.ListStreams() - assert len(list_streams_result) == 0, list_streams_result - - # Asking for 4 audio and 3 video streams is pathological, but we claim to - # support up to 99 streams, so we should test a decent number of them. - # - # More practically, the success of this test implies that the simpler case - # of one audio stream and one video stream should easily work. - streams = media_iface.RequestStreams(handle, - [cs.MEDIA_STREAM_TYPE_AUDIO, - cs.MEDIA_STREAM_TYPE_VIDEO, - cs.MEDIA_STREAM_TYPE_VIDEO, - cs.MEDIA_STREAM_TYPE_AUDIO, - cs.MEDIA_STREAM_TYPE_AUDIO, - cs.MEDIA_STREAM_TYPE_VIDEO, - cs.MEDIA_STREAM_TYPE_AUDIO]) - assert len(streams) == 7, streams - - streams_by_id = {} - - for s in streams: - streams_by_id[s[0]] = s - - assert len(s) == 6, s - assert s[1] == handle, (s, handle) - assert s[2] in (cs.MEDIA_STREAM_TYPE_AUDIO, - cs.MEDIA_STREAM_TYPE_VIDEO), s - # We haven't connected yet - assert s[3] == cs.MEDIA_STREAM_STATE_DISCONNECTED, s - # In Gabble, requested streams start off bidirectional - assert s[4] == cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, s - assert s[5] == 0, s # no pending send - - # the streams should all have unique IDs - stream_ids = streams_by_id.keys() - assert len(stream_ids) == 7 - - # the streams should come out in the same order as the requests - assert streams[0][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] - assert streams[1][2] == cs.MEDIA_STREAM_TYPE_VIDEO, streams[0] - assert streams[2][2] == cs.MEDIA_STREAM_TYPE_VIDEO, streams[0] - assert streams[3][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] - assert streams[4][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] - assert streams[5][2] == cs.MEDIA_STREAM_TYPE_VIDEO, streams[0] - assert streams[6][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] - - # The ListStreams() result must be the streams we got from RequestStreams, - # but this time the order is unimportant - list_streams_result = media_iface.ListStreams() - listed_streams_by_id = {} - - for s in list_streams_result: - listed_streams_by_id[s[0]] = s - - assert listed_streams_by_id == streams_by_id, (listed_streams_by_id, - streams_by_id) - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler_path = e.args[0] - session_handler = make_channel_proxy(conn, session_handler_path, - 'Media.SessionHandler') - session_handler.Ready() - - stream_handler_paths = [] - - # give all 7 streams some candidates - for i in xrange(7): - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_handler_paths.append(e.args[0]) - stream_handler = make_channel_proxy(conn, e.args[0], - 'Media.StreamHandler') - stream_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq') - 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.accept() - - q.expect('stream-iq', iq_type='result') - - # Time passes ... afterwards we close the chan - - group_iface.RemoveMembers([self_handle], 'closed') - - # Everything closes - closes = [ EventPattern('dbus-signal', signal='Close', - path=stream_handler_paths[i]) - for i in range(0,7) ] - removeds = [ EventPattern('dbus-signal', signal='StreamRemoved', - args=[stream_ids[i]], path=path) - for i in range(0,7) ] - q.expect_many( - EventPattern('dbus-signal', signal='ChannelClosed', args=[path]), - *(closes + removeds) - ) - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/jingle/payload-types.py b/tests/twisted/jingle/payload-types.py deleted file mode 100644 index 64a300ff1..000000000 --- a/tests/twisted/jingle/payload-types.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Regression test for https://bugs.freedesktop.org/show_bug.cgi?id=18918 -""" - -import dbus - -from gabbletest import exec_test -from servicetest import wrap_channel, make_channel_proxy -import jingletest2 -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream): - jp = jingletest2.JingleProtocol031() - jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', - 'foo@bar.com/Foo') - - self_handle = conn.GetSelfHandle() - - jt.send_presence_and_caps() - - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - path = conn.RequestChannel( - cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, handle, True) - - 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. - - 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') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_id = e.args[1] - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - - codecs = dbus.Array( [ (96, 'speex', 0, 16000, 0, {'vbr': 'on'}) ], - signature='(usuuua{ss})') - stream_handler.Ready(codecs) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq') - content = list(e.query.elements())[0] - assert content.name == 'content' - for child in content.elements(): - if child.name == 'description': - description = child - break - assert description is not None - - # there should be one <payload-type> tag for speex: - assert len(list(description.elements())) == 1 - payload_type = list(description.elements())[0] - assert payload_type.name == 'payload-type' - assert payload_type['name'] == 'speex' - - # the vbr parameter should not be an attribute on the <payload-type>, but - # a child <parameter/> tag - assert 'vbr' not in payload_type.attributes - assert len(list(payload_type.elements())) == 1 - parameter = list(payload_type.elements())[0] - assert parameter.name == 'parameter' - assert parameter['name'] == 'vbr' - assert parameter['value'] == 'on' - - channel.Close() - - - # Test that codec parameters are correctly extracted from <parameter> - # children of <payload-type> rather than from attributes of the latter. - - jt.audio_codecs = [ ('GSM', 3, 8000, {'misc': 'other'}) ] - jt.incoming_call() - - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_id = e.args[1] - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - stream_handler.Ready( dbus.Array( [], signature='(usuuua{ss})')) - - e = q.expect('dbus-signal', signal='SetRemoteCodecs') - for codec in e.args[0]: - id, name, type, rate, channels, parameters = codec - assert len(parameters) == 1, parameters - assert parameters['misc'] == 'other', parameters - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/jingle/session-id-collision.py b/tests/twisted/jingle/session-id-collision.py index 724537fe0..b9815407b 100644 --- a/tests/twisted/jingle/session-id-collision.py +++ b/tests/twisted/jingle/session-id-collision.py @@ -27,14 +27,14 @@ def test(jp, q, bus, conn, stream): jt2.sid = '1' jt1.incoming_call() - q.expect('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args) + q.expect('dbus-signal', signal='NewChannels', + predicate=lambda e: cs.CHANNEL_TYPE_CALL in e.args[0][0][1][cs.CHANNEL_TYPE]) # If Gabble confuses the two sessions, it'll NAK the IQ rather than # realising this is a new call. jt2.incoming_call() - q.expect('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args) + q.expect('dbus-signal', signal='NewChannels', + predicate=lambda e: cs.CHANNEL_TYPE_CALL in e.args[0][0][1][cs.CHANNEL_TYPE]) # On the other hand, if the same person calls twice with the same sid, # Gabble _should_ NAK the second s-i. diff --git a/tests/twisted/jingle/stream-errors-on-content-reject.py b/tests/twisted/jingle/stream-errors-on-content-reject.py deleted file mode 100644 index 404373c72..000000000 --- a/tests/twisted/jingle/stream-errors-on-content-reject.py +++ /dev/null @@ -1,246 +0,0 @@ -""" -Test StreamError events when new content is rejected in-call. -""" - -import dbus - -from gabbletest import make_result_iq, sync_stream, exec_test -from servicetest import ( - make_channel_proxy, unwrap, EventPattern, assertEquals, assertLength) -from jingletest2 import JingleTest2, JingleProtocol031 -import constants as cs - -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def _content_reject_predicate(event): - reason = xpath.queryForNodes("/iq" - "/jingle[@action='content-reject']" - "/reason/failed-application", - event.stanza) - - return bool(reason) - -def _start_audio_session(jp, q, bus, conn, stream, incoming): - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - - if incoming: - jt.incoming_call() - else: - ret = conn.Requests.CreateChannel( - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle, - cs.INITIAL_AUDIO: True - }) - - nc, e = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewSessionHandler')) - - path = nc.args[0] - - media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') - media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - - # S-E was notified about new session handler, and calls Ready on it - session_handler = make_channel_proxy(conn, e.args[0], - 'Media.SessionHandler') - session_handler.Ready() - - nsh_event = q.expect('dbus-signal', signal='NewStreamHandler') - - # S-E gets notified about a newly-created stream - stream_handler = make_channel_proxy(conn, nsh_event.args[0], - 'Media.StreamHandler') - - group_props = media_chan.GetAll( - cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) - - if incoming: - assertEquals([remote_handle], group_props['Members']) - assertEquals(unwrap(group_props['LocalPendingMembers']), - [(self_handle, remote_handle, cs.GC_REASON_INVITED, '')]) - else: - assertEquals([self_handle], group_props['Members']) - - streams = media_chan.ListStreams( - dbus_interface=cs.CHANNEL_TYPE_STREAMED_MEDIA) - - stream_id = streams[0][0] - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.dbusify_codecs([("FOO", 5, 8000, {})])) - - msg = u"None of the codecs are good for us, damn!" - - expected_events = [] - - if incoming: - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - stream_handler.SupportedCodecs(jt.get_audio_codecs_dbus()) - - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - assertEquals(jt.peer, e.query['initiator']) - content = xpath.queryForNodes('/iq/jingle/content', e.stanza)[0] - assertEquals('initiator', content['creator']) - - stream.send(make_result_iq(stream, e.stanza)) - - media_chan.AddMembers([self_handle], 'accepted') - - memb, acc, _, _, _ = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [self_handle], [], [], [], self_handle, - cs.GC_REASON_NONE]), - EventPattern('stream-iq', - predicate=jp.action_predicate('session-accept')), - EventPattern('dbus-signal', signal='SetStreamSending', - args=[True]), - EventPattern('dbus-signal', signal='SetStreamPlaying', - args=[True]), - EventPattern('dbus-signal', signal='StreamDirectionChanged', - args=[stream_id, - cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0])) - - stream.send(make_result_iq(stream, acc.stanza)) - - active_event = jp.rtp_info_event("active") - if active_event is not None: - q.expect_many(active_event) - - members = media_chan.GetMembers() - assert set(members) == set([self_handle, remote_handle]), members - else: - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - session_initiate = q.expect( - 'stream-iq', - predicate=jp.action_predicate('session-initiate')) - - q.expect('dbus-signal', signal='MembersChanged', path=path, - args=['', [], [], [], [remote_handle], self_handle, - cs.GC_REASON_INVITED]) - - jt.parse_session_initiate(session_initiate.query) - stream.send(jp.xml(jp.ResultIq('test@localhost', - session_initiate.stanza, []))) - - jt.accept() - - q.expect_many( - EventPattern('stream-iq', iq_type='result'), - # Call accepted - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [remote_handle], [], [], [], remote_handle, - cs.GC_REASON_NONE]), - ) - return jt, media_iface - -def _start_audio_session_outgoing(jp, q, bus, conn, stream): - return _start_audio_session(jp, q, bus, conn, stream, False) - -def _start_audio_session_incoming(jp, q, bus, conn, stream): - return _start_audio_session(jp, q, bus, conn, stream, True) - -def _remote_content_add(jp, q, bus, conn, stream, initiate_call_func): - jt, chan = initiate_call_func(jp, q, bus, conn, stream) - - video_codecs = [ - jp.PayloadType(name, str(rate), str(id), parameters) \ - for (name, id, rate, parameters) in jt.video_codecs] - - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.peer, 'content-add', [ - jp.Content( - 'videostream', 'initiator', 'both', - jp.Description('video', video_codecs), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - _, nsh = q.expect_many( - EventPattern('dbus-signal', signal='StreamAdded'), - EventPattern('dbus-signal', signal='NewStreamHandler')) - - stream_handler_path, stream_id, media_type, direction = nsh.args - - video_handler = make_channel_proxy(conn, stream_handler_path, - 'Media.StreamHandler') - - video_handler.NewNativeCandidate("fake", - jt.get_remote_transports_dbus()) - video_handler.Ready(jt.dbusify_codecs([("FOO", 5, 8000, {})])) - - msg = u"None of the codecs are good for us, damn!" - - video_handler.Error(cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED, msg) - - q.expect_many( - EventPattern('dbus-signal', signal='StreamError', - args=[stream_id, - cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED, - msg]), - EventPattern('stream-iq', predicate=_content_reject_predicate)) - -def _local_content_add(jp, q, bus, conn, stream, initiate_call_func): - jt, chan = initiate_call_func(jp, q, bus, conn, stream) - - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - - chan.RequestStreams(remote_handle, [cs.MEDIA_STREAM_TYPE_VIDEO]) - - nsh = q.expect('dbus-signal', signal='NewStreamHandler') - stream_handler_path, stream_id, media_type, direction = nsh.args - video_handler = make_channel_proxy(conn, stream_handler_path, - 'Media.StreamHandler') - - video_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - video_handler.Ready(jt.get_audio_codecs_dbus()) - video_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('content-add')) - c = e.query.firstChildElement() - stream.send(make_result_iq(stream, e.stanza)) - - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.peer, 'content-reject', [ - ('reason', None, {}, [ - ('failed-application', None, {}, [])]), - jp.Content(c['name'], c['creator'], c['senders']) ]) ]) - stream.send(jp.xml(node)) - - q.expect('dbus-signal', signal='StreamError', - args=[stream_id, - cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED, - ""]), - -def test_remote_content_add_incoming(jp, q, bus, conn, stream): - _remote_content_add(jp, q, bus, conn, stream, - _start_audio_session_incoming) - -def test_remote_content_add_outgoing(jp, q, bus, conn, stream): - _remote_content_add(jp, q, bus, conn, stream, - _start_audio_session_outgoing) - -def test_local_content_add_incoming(jp, q, bus, conn, stream): - _local_content_add(jp, q, bus, conn, stream, _start_audio_session_incoming) - -def test_local_content_add_outgoing(jp, q, bus, conn, stream): - _local_content_add(jp, q, bus, conn, stream, _start_audio_session_outgoing) - -if __name__ == '__main__': - for f in (test_local_content_add_incoming, - test_local_content_add_outgoing, - test_remote_content_add_incoming, - test_remote_content_add_outgoing): - exec_test( - lambda q, b, c, s: f(JingleProtocol031(), q, b, c, s)) diff --git a/tests/twisted/jingle/stream-errors-on-terminate.py b/tests/twisted/jingle/stream-errors-on-terminate.py deleted file mode 100644 index 2fc403cd5..000000000 --- a/tests/twisted/jingle/stream-errors-on-terminate.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -Test StreamError events and on session terminate, both directions. -""" - -import dbus - -from gabbletest import make_result_iq, sync_stream, exec_test -from servicetest import ( - make_channel_proxy, unwrap, EventPattern, assertEquals, assertLength) -from jingletest2 import JingleTest2, JingleProtocol031 -import constants as cs - -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def _session_terminate_predicate(event, msg): - reason = xpath.queryForNodes("/iq" - "/jingle[@action='session-terminate']" - "/reason/failed-application", - event.stanza) - reason_text = xpath.queryForString("/iq/jingle/reason/text", - event.stanza) - - return reason is not None and reason_text == msg - -def _test_terminate_reason(jp, q, bus, conn, stream, incoming): - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - - if incoming: - jt.incoming_call() - else: - ret = conn.Requests.CreateChannel( - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_HANDLE: remote_handle, - cs.INITIAL_AUDIO: True - }) - - nc, e = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewSessionHandler')) - - path = nc.args[0] - - media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') - media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - - # S-E was notified about new session handler, and calls Ready on it - session_handler = make_channel_proxy(conn, e.args[0], - 'Media.SessionHandler') - session_handler.Ready() - - nsh_event = q.expect('dbus-signal', signal='NewStreamHandler') - - # S-E gets notified about a newly-created stream - stream_handler = make_channel_proxy(conn, nsh_event.args[0], - 'Media.StreamHandler') - - group_props = media_chan.GetAll( - cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) - - if incoming: - assertEquals([remote_handle], group_props['Members']) - assertEquals(unwrap(group_props['LocalPendingMembers']), - [(self_handle, remote_handle, cs.GC_REASON_INVITED, '')]) - else: - assertEquals([self_handle], group_props['Members']) - - streams = media_chan.ListStreams( - dbus_interface=cs.CHANNEL_TYPE_STREAMED_MEDIA) - - stream_id = streams[0][0] - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.dbusify_codecs([("FOO", 5, 8000, {})])) - - msg = u"None of the codecs are good for us, damn!" - - expected_events = [] - - if incoming: - q.expect('dbus-signal', signal='SetRemoteCodecs') - stream_handler.Error(cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED, - msg) - expected_events = [EventPattern( - "stream-iq", iq_type="set", - predicate=lambda x: _session_terminate_predicate(x, msg))] - rejector = self_handle - else: - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - session_initiate = q.expect( - 'stream-iq', - predicate=jp.action_predicate('session-initiate')) - - q.expect('dbus-signal', signal='MembersChanged', path=path, - args=['', [], [], [], [remote_handle], self_handle, - cs.GC_REASON_INVITED]) - - jt.parse_session_initiate(session_initiate.query) - stream.send(jp.xml(jp.ResultIq('test@localhost', - session_initiate.stanza, []))) - jt.terminate('failed-application', msg) - rejector = remote_handle - - expected_events += [ - EventPattern('dbus-signal', signal='StreamError', - interface=cs.CHANNEL_TYPE_STREAMED_MEDIA, path=path, - args=[stream_id, - cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED, - msg]), - EventPattern('dbus-signal', signal='MembersChanged', - interface=cs.CHANNEL_IFACE_GROUP, path=path, - args=[msg, [], [self_handle, remote_handle], [], [], - rejector, cs.GC_REASON_ERROR])] - - - q.expect_many(*expected_events) - - q.expect('dbus-signal', signal='Closed', path=path) - -def test_terminate_outgoing(jp, q, bus, conn, stream): - _test_terminate_reason(jp, q, bus, conn, stream, False) - -def test_terminate_incoming(jp, q, bus, conn, stream): - _test_terminate_reason(jp, q, bus, conn, stream, True) - -if __name__ == '__main__': - for f in (test_terminate_incoming, test_terminate_outgoing): - exec_test( - lambda q, b, c, s: f(JingleProtocol031(), q, b, c, s)) diff --git a/tests/twisted/jingle/stream-handler-error.py b/tests/twisted/jingle/stream-handler-error.py deleted file mode 100644 index 5b05f6d15..000000000 --- a/tests/twisted/jingle/stream-handler-error.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Test handling of errors from StreamHandler during calls. This is a regression -test for a bug introduced by 54021cee0ad38 which removed an idle callback -masking refcounting assumptions. -""" - -from functools import partial - -from gabbletest import exec_test -from servicetest import make_channel_proxy -import jingletest2 - -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream, call_error_on): - jp = jingletest2.JingleProtocol031() - jt = jingletest2.JingleTest2(jp, conn, q, stream, 'test@localhost', - 'foo@bar.com/Foo') - - remote_handle = conn.RequestHandles(1, [jt.peer])[0] - - # Remote end calls us - jt.incoming_call() - - # FIXME: these signals are not observable by real clients, since they - # happen before NewChannels. - # The caller is in members - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [remote_handle], [], [], [], 0, 0]) - - # We're pending because of remote_handle - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [1L], [], remote_handle, cs.GC_REASON_INVITED]) - - media_chan_suffix = e.path - - e = q.expect('dbus-signal', signal='NewSessionHandler') - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - - if call_error_on == 'session': - session_handler.Error(0, "this has been deprecated for years") - else: - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - # S-E gets notified about a newly-created stream - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - # Something goes wrong immediately! - stream_handler.Error(0, "i'll have the eggs tostada please") - - # Gabble doesn't fall over, and the channel closes nicely. - e = q.expect('dbus-signal', signal='Closed', path=media_chan_suffix) - -if __name__ == '__main__': - exec_test(partial(test, call_error_on='stream')) - exec_test(partial(test, call_error_on='session')) diff --git a/tests/twisted/jingle/stun-server.py b/tests/twisted/jingle/stun-server.py index 1ecb1c738..ab7c538ce 100644 --- a/tests/twisted/jingle/stun-server.py +++ b/tests/twisted/jingle/stun-server.py @@ -15,7 +15,7 @@ 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 +from config import GOOGLE_RELAY_ENABLED, VOIP_ENABLED if not VOIP_ENABLED: print "NOTE: built with --disable-voip" @@ -77,121 +77,10 @@ def init_test(jp, q, conn, stream, google=False, google_push_replacements=None): jt.send_presence_and_caps() - remote_handle = conn.RequestHandles(1, ["foo@bar.com/Foo"])[0] + remote_handle = conn.get_contact_handle_sync("foo@bar.com/Foo") return jt, remote_handle -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(jp, q, conn, stream, google, google_push_replacements) - - # Remote end calls us - jt.incoming_call() - - # FIXME: these signals are not observable by real clients, since they - # happen before NewChannels. - # The caller is in members - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [remote_handle], [], [], [], 0, 0]) - - # We're pending because of remote_handle - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [1L], [], remote_handle, cs.GC_REASON_INVITED]) - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - media_chan = make_channel_proxy(conn, e.path, 'Channel.Interface.Group') - - # Exercise channel properties - channel_props = media_chan.GetAll( - cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) - assert channel_props['TargetHandle'] == remote_handle - assert channel_props['TargetHandleType'] == 1 - assert channel_props['TargetID'] == 'foo@bar.com' - assert channel_props['Requested'] == False - assert channel_props['InitiatorID'] == 'foo@bar.com' - assert channel_props['InitiatorHandle'] == remote_handle - - # The new API for STUN servers etc. - sh_props = stream_handler.GetAll( - 'org.freedesktop.Telepathy.Media.StreamHandler', - dbus_interface=dbus.PROPERTIES_IFACE) - - assert sh_props['NATTraversal'] == 'gtalk-p2p' - assert sh_props['CreatedLocally'] == False - - test_stun_server(sh_props['STUNServers'], expected_stun_servers) - assert sh_props['RelayInfo'] == expected_relays - - # consistency check, since we currently reimplement Get separately - for k in sh_props: - assert sh_props[k] == stream_handler.Get( - 'org.freedesktop.Telepathy.Media.StreamHandler', k, - dbus_interface=dbus.PROPERTIES_IFACE), k - - # The old API for STUN servers etc. still needs supporting, for farsight 1 - tp_prop_list = media_chan.ListProperties(dbus_interface=cs.TP_AWKWARD_PROPERTIES) - tp_props = {} - tp_prop_ids = {} - - for spec in tp_prop_list: - tp_prop_ids[spec[0]] = spec[1] - tp_props[spec[1]] = { 'id': spec[0], 'sig': spec[2], 'flags': spec[3] } - - assert 'nat-traversal' in tp_props - assert tp_props['nat-traversal']['sig'] == 's' - assert tp_props['nat-traversal']['flags'] == cs.PROPERTY_FLAG_READ - assert 'stun-server' in tp_props - assert tp_props['stun-server']['sig'] == 's' - assert 'stun-port' in tp_props - assert tp_props['stun-port']['sig'] in ('u', 'q') - assert 'gtalk-p2p-relay-token' in tp_props - assert tp_props['gtalk-p2p-relay-token']['sig'] == 's' - - assert tp_props['stun-server']['flags'] == cs.PROPERTY_FLAG_READ - assert tp_props['stun-port']['flags'] == cs.PROPERTY_FLAG_READ - - if google: - assert tp_props['gtalk-p2p-relay-token']['flags'] == cs.PROPERTY_FLAG_READ - else: - assert tp_props['gtalk-p2p-relay-token']['flags'] == 0 - - tp_prop_values = media_chan.GetProperties( - [tp_props[k]['id'] for k in tp_props if tp_props[k]['flags']], - dbus_interface=cs.TP_AWKWARD_PROPERTIES) - - for value in tp_prop_values: - assert value[0] in tp_prop_ids - tp_props[tp_prop_ids[value[0]]]['value'] = value[1] - - assert tp_props['nat-traversal']['value'] == 'gtalk-p2p' - - 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 - assert tp_props['stun-port']['value'] == expected_stun_port - - if google: - assert tp_props['gtalk-p2p-relay-token']['value'] == 'jingle all the way' - - media_chan.RemoveMembers([dbus.UInt32(1)], 'rejected') - - q.expect_many( - EventPattern('stream-iq', - predicate=jp.action_predicate('session-terminate')), - EventPattern('dbus-signal', signal='Closed'), - ) - def test_call(jp, q, bus, conn, stream, expected_stun_servers=None, google=False, google_push_replacements=None, expected_relays=[]): @@ -264,53 +153,18 @@ def test_call(jp, q, bus, conn, stream, assertEquals(True, stream_props['HasServerInfo']) if __name__ == '__main__': - # StreamedMedia tests - test_all_dialects(partial(test_streamed_media, + # Call tests + test_all_dialects(partial(test_call, google=False)) - test_all_dialects(partial(test_streamed_media, + 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)}) - test_all_dialects(partial(test_streamed_media, google=False, - expected_stun_servers=[('5.4.3.2', 1)]), + test_all_dialects(partial(test_call, + google=False, expected_stun_servers=[('5.4.3.2', 1)]), params={'account': 'test@stunning.localhost'}) if GOOGLE_RELAY_ENABLED: - 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)}) - 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)}) - 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: - 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)}) - 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: test_all_dialects(partial(test_call, google=True, expected_stun_servers=[('1.2.3.4', 12345)]), protocol=GoogleXmlStream) @@ -329,5 +183,5 @@ if __name__ == '__main__': 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" + print "NOTE: built with --disable-google-relay; omitting Call tests with Google relay" diff --git a/tests/twisted/jingle/test-content-adding-removal.py b/tests/twisted/jingle/test-content-adding-removal.py deleted file mode 100644 index db33274f7..000000000 --- a/tests/twisted/jingle/test-content-adding-removal.py +++ /dev/null @@ -1,168 +0,0 @@ -""" -Test content adding and removal during the session. We start -session with only one stream, then add one more, then remove -the first one and lastly remove the second stream, which -closes the session. -""" - -from gabbletest import make_result_iq, sync_stream -from servicetest import ( - wrap_channel, make_channel_proxy, assertEquals, EventPattern) -from jingletest2 import ( - JingleTest2, test_dialects, JingleProtocol031, JingleProtocol015, - ) -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def gabble_terminates(jp, q, bus, conn, stream): - test(jp, q, bus, conn, stream, False) - -def peer_terminates(jp, q, bus, conn, stream): - test(jp, q, bus, conn, stream, True) - -def test(jp, q, bus, conn, stream, peer_removes_final_content): - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt.prepare() - - handle = conn.RequestHandles(cs.HT_CONTACT, [jt.peer])[0] - path = conn.RequestChannel( - cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, handle, True) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - - chan.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') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_id = e.args[1] - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - - # Before sending the initiate, request another stream - - chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO]) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_id2 = e.args[1] - - stream_handler2 = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - stream_handler2.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - - # Before the CM can initiate session, we modify a stream direction. This - # should result in a no-op since there's no need to inform the peer of - # change. - chan.StreamedMedia.RequestStreamDirection(stream_id2, - cs.MEDIA_STREAM_DIRECTION_RECEIVE) - - # We set both streams as ready, which will trigger the session initiate - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - stream_handler2.Ready(jt.get_audio_codecs_dbus()) - stream_handler2.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - # We changed our mind locally, don't want video - chan.StreamedMedia.RemoveStreams([stream_id2]) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - stream.send(make_result_iq(stream, e.stanza)) - - jt.parse_session_initiate(e.query) - - # Gabble sends content-remove for the video stream... - e2 = q.expect('stream-iq', predicate=jp.action_predicate('content-remove')) - - # ...but before the peer notices, they accept the call. - jt.accept() - - # Only now the remote end removes the video stream; if gabble mistakenly - # marked it as accepted on session acceptance, it'll crash right about - # now. If it's good, stream will be really removed, and - # we can proceed. - stream.send(make_result_iq(stream, e2.stanza)) - - q.expect('dbus-signal', signal='StreamRemoved') - - # Actually, we *do* want video! - chan.StreamedMedia.RequestStreams(handle, [cs.MEDIA_STREAM_TYPE_VIDEO]) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream2_id = e.args[1] - - stream_handler2 = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler2.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler2.Ready(jt.get_audio_codecs_dbus()) - stream_handler2.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('content-add')) - c = e.query.firstChildElement() - assertEquals('initiator', c['creator']) - stream.send(make_result_iq(stream, e.stanza)) - - # Peer accepts - jt.content_accept(e.query, 'video') - - # Let's start sending and receiving video! - q.expect_many( - EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]), - EventPattern('dbus-signal', signal='SetStreamSending', args=[True]), - ) - - # Now, the call draws to a close. - # We first remove the original stream - chan.StreamedMedia.RemoveStreams([stream_id]) - - e = q.expect('stream-iq', predicate=jp.action_predicate('content-remove')) - content_remove_ack = make_result_iq(stream, e.stanza) - - if peer_removes_final_content: - # The peer removes the final countdo^W content. From a footnote (!) in - # XEP 0166: - # If the content-remove results in zero content definitions for the - # session, the entity that receives the content-remove SHOULD send - # a session-terminate action to the other party (since a session - # with no content definitions is void). - # So, Gabble should respond to the content-remove with a - # session-terminate. - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.peer, 'content-remove', [ - jp.Content(c['name'], c['creator'], c['senders']) ]) ]) - stream.send(jp.xml(node)) - else: - # The Telepathy client removes the second stream; Gabble should - # terminate the session rather than sending a content-remove. - chan.StreamedMedia.RemoveStreams([stream2_id]) - - st, closed = q.expect_many( - EventPattern('stream-iq', - predicate=jp.action_predicate('session-terminate')), - # Gabble shouldn't wait for the peer to ack the terminate before - # considering the call finished. - EventPattern('dbus-signal', signal='Closed', path=path)) - - # Only now does the peer ack the content-remove. This serves as a - # regression test for contents outliving the session; if the content didn't - # die properly, this crashed Gabble. - stream.send(content_remove_ack) - sync_stream(q, stream) - - # The peer can ack the terminate too, just for completeness. - stream.send(make_result_iq(stream, st.stanza)) - -if __name__ == '__main__': - test_dialects(gabble_terminates, [JingleProtocol015, JingleProtocol031]) - test_dialects(peer_terminates, [JingleProtocol015, JingleProtocol031]) - diff --git a/tests/twisted/jingle/test-content-complex.py b/tests/twisted/jingle/test-content-complex.py deleted file mode 100644 index c23f2c9a0..000000000 --- a/tests/twisted/jingle/test-content-complex.py +++ /dev/null @@ -1,257 +0,0 @@ -""" -Test everything related to contents -""" - -from gabbletest import sync_stream -from servicetest import ( - make_channel_proxy, assertEquals, EventPattern) -import constants as cs -from jingletest2 import ( - JingleTest2, JingleProtocol015, JingleProtocol031, test_dialects) - -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def worker(jp, q, bus, conn, stream): - - def make_stream_request(stream_type): - media_iface.RequestStreams(remote_handle, [stream_type]) - - e = q.expect('dbus-signal', signal='NewStreamHandler') - stream_id = e.args[1] - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(jt2.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - return (stream_handler, stream_id) - - - jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt2.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] - - # Remote end calls us - jt2.incoming_call() - - # FIXME: these signals are not observable by real clients, since they - # happen before NewChannels. - # The caller is in members - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [remote_handle], [], [], [], 0, 0]) - - # We're pending because of remote_handle - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [self_handle], [], remote_handle, - cs.GC_REASON_INVITED]) - - media_chan = make_channel_proxy(conn, e.path, 'Channel.Interface.Group') - signalling_iface = make_channel_proxy(conn, e.path, 'Channel.Interface.MediaSignalling') - media_iface = make_channel_proxy(conn, e.path, 'Channel.Type.StreamedMedia') - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - media_chan.AddMembers([self_handle], 'accepted') - - # S-E gets notified about a newly-created stream - e = q.expect('dbus-signal', signal='NewStreamHandler') - id1 = e.args[1] - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - # We are now in members too - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [self_handle], [], [], [], self_handle, - cs.GC_REASON_NONE]) - - # we are now both in members - members = media_chan.GetMembers() - assert set(members) == set([self_handle, remote_handle]), members - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(jt2.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - # First one is transport-info - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - assertEquals('foo@bar.com/Foo', e.query['initiator']) - - # stream.send(gabbletest.make_result_iq(stream, e.stanza)) - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # S-E reports codec intersection, after which gabble can send acceptance - stream_handler.SupportedCodecs(jt2.get_audio_codecs_dbus()) - - # Second one is session-accept - e = q.expect('stream-iq', predicate=jp.action_predicate('session-accept')) - - # stream.send(gabbletest.make_result_iq(stream, e.stanza)) - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # Here starts the interesting part of this test - # Remote end tries to create a content we can't handle - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-add', [ - jp.Content('bogus', 'initiator', 'both', - jp.Description('hologram', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.audio_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - # In older Jingle, this is a separate namespace, which isn't - # recognized, but it's a valid request, so it gets ackd and rejected - if jp.dialect == 'jingle-v0.15': - # Gabble should acknowledge content-add - q.expect('stream-iq', iq_type='result') - - # .. and then send content-reject for the bogus content - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='content-reject']/content[@name='bogus']", - x.stanza)) - - # In new Jingle, this is a bogus subtype of recognized namespace, - # so Gabble returns a bad request error - else: - q.expect('stream-iq', iq_type='error') - - # Remote end then tries to create a content with a name it's already used - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-add', [ - jp.Content(jt2.audio_names[0], 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.audio_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - # Gabble should return error (content already exists) - q.expect('stream-iq', iq_type='error') - - # We try to add a stream - (stream_handler2, id2) = make_stream_request(cs.MEDIA_STREAM_TYPE_VIDEO) - - # Gabble should now send content-add - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='content-add']", - x.stanza)) - - c = e.query.firstChildElement() - assert c['creator'] == 'responder', c['creator'] - - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # We try to add yet another stream - (stream_handler3, id3) = make_stream_request(cs.MEDIA_STREAM_TYPE_VIDEO) - - # Gabble should send another content-add - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='content-add']", - x.stanza)) - - d = e.query.firstChildElement() - assertEquals('responder', d['creator']) - - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # Remote end rejects the first stream we tried to add. - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-reject', [ - jp.Content(c['name'], c['creator'], c['senders']) ]) ]) - stream.send(jp.xml(node)) - - # Gabble removes the stream - q.expect('dbus-signal', signal='StreamRemoved', - interface=cs.CHANNEL_TYPE_STREAMED_MEDIA) - - # Remote end tries to add a content with the same name as the second one we - # just added - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-add', [ - jp.Content(d['name'], 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.audio_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - # Because stream names are namespaced by creator, Gabble should be okay - # with that. - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='StreamAdded'), - ) - - # Remote end thinks better of that, and removes the similarly-named stream - # it tried to add. - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-remove', [ - jp.Content(d['name'], 'initiator', d['senders']) ]) ]) - stream.send(jp.xml(node)) - - q.expect_many( - EventPattern('stream-iq', iq_type='result', iq_id=node[2]['id']), - EventPattern('dbus-signal', signal='StreamRemoved'), - ) - - # Remote end finally accepts. When Gabble did not namespace contents by - # their creator, it would NAK this IQ: - # - Gabble (responder) created a stream called 'foo'; - # - test suite (initiator) created a stream called 'foo', which Gabble - # decided would replace its own stream called 'foo'; - # - test suite removed its 'foo'; - # - test suite accepted Gabble's 'foo', but Gabble didn't believe a stream - # called 'foo' existed any more. - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-accept', [ - jp.Content(d['name'], d['creator'], d['senders'], - jp.Description('video', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters ) in jt2.audio_codecs ]), - jp.TransportGoogleP2P()) ]) ]) - stream.send(jp.xml(node)) - - # We get remote codecs - e = q.expect('dbus-signal', signal='SetRemoteCodecs') - - # Now, both we and remote peer try to remove the content simultaneously: - # Telepathy client calls RemoveStreams... - media_iface.RemoveStreams([id3]) - - # ...so Gabble sends a content-remove... - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='content-remove']", - x.stanza)) - - # ...but before it's acked the peer sends its own content-remove... - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'content-remove', [ - jp.Content(c['name'], c['creator'], c['senders']) ]) ]) - stream.send(jp.xml(node)) - - # ...and we don't want Gabble to break when that happens. - sync_stream(q, stream) - - # Now we want to remove the first stream - media_iface.RemoveStreams([id1]) - - # Since this is the last stream, Gabble will just terminate the session. - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='session-terminate']", - x.stanza)) - -if __name__ == '__main__': - test_dialects(worker, [JingleProtocol015, JingleProtocol031]) diff --git a/tests/twisted/jingle/test-description-info.py b/tests/twisted/jingle/test-description-info.py deleted file mode 100644 index 1adda17ba..000000000 --- a/tests/twisted/jingle/test-description-info.py +++ /dev/null @@ -1,213 +0,0 @@ -""" -Test emition and handling of codec update using description-info -""" - -from gabbletest import exec_test, sync_stream -from servicetest import ( - wrap_channel, assertEquals, make_channel_proxy, unwrap, EventPattern, - call_async) -from jingletest2 import JingleTest2, JingleProtocol031 -import constants as cs - -from twisted.words.xish import xpath - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def extract_params(payload_type): - ret = {} - for node in payload_type.elements(): - assert node.name == 'parameter' - ret[node['name']] = node['value'] - return ret - -def early_description_info(q, bus, conn, stream): - test(q, bus, conn, stream, send_early_description_info=True) - -def test(q, bus, conn, stream, send_early_description_info=False): - jp = JingleProtocol031() - jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt2.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] - - # Remote end calls us - jt2.incoming_call() - - # FIXME: these signals are not observable by real clients, since they - # happen before NewChannels. - # The caller is in members - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [remote_handle], [], [], [], 0, 0]) - - # We're pending because of remote_handle - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [self_handle], [], remote_handle, - cs.GC_REASON_INVITED]) - - chan = wrap_channel(bus.get_object(conn.bus_name, e.path), - 'StreamedMedia') - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - if send_early_description_info: - """ - Regression test for a bug where Gabble would crash if you sent it - description-info before calling Ready() on the relevant StreamHandler, - and then for a bug where Gabble would never accept the call if a - description-info was received before all StreamHandlers were Ready(). - """ - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'description-info', [ - jp.Content('stream1', 'initiator', 'both', - jp.Description('audio', [ ])) ]) ]) - stream.send(jp.xml(node)) - - sync_stream(q, stream) - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - chan.Group.AddMembers([self_handle], 'accepted') - - # S-E gets notified about a newly-created stream - e = q.expect('dbus-signal', signal='NewStreamHandler') - id1 = e.args[1] - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - # We are now in members too - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [self_handle], [], [], [], self_handle, - cs.GC_REASON_NONE]) - - # we are now both in members - members = chan.Group.GetMembers() - assert set(members) == set([self_handle, remote_handle]), members - - local_codecs = [('GSM', 3, 8000, {}), - ('PCMA', 8, 8000, {'helix':'woo yay'}), - ('PCMU', 0, 8000, {}) ] - local_codecs_dbus = jt2.dbusify_codecs_with_params(local_codecs) - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(local_codecs_dbus) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - stream_handler.CodecsUpdated(local_codecs_dbus) - - local_codecs = [('GSM', 3, 8000, {}), - ('PCMA', 8, 8000, {'gstreamer':'rock on'}), - ('PCMU', 0, 8000, {}) ] - local_codecs_dbus = jt2.dbusify_codecs_with_params(local_codecs) - stream_handler.CodecsUpdated(local_codecs_dbus) - - - # First IQ is transport-info; also, we expect to be told what codecs the - # other end wants. - e, src = q.expect_many( - EventPattern('stream-iq', - predicate=jp.action_predicate('transport-info')), - EventPattern('dbus-signal', signal='SetRemoteCodecs') - ) - assertEquals('foo@bar.com/Foo', e.query['initiator']) - - assert jt2.audio_codecs == [ (name, id, rate, parameters) - for id, name, type, rate, channels, parameters in unwrap(src.args[0]) ], \ - (jt2.audio_codecs, unwrap(src.args[0])) - - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # S-E reports codec intersection, after which gabble can send acceptance - stream_handler.SupportedCodecs(local_codecs_dbus) - - # Second one is session-accept - e = q.expect('stream-iq', predicate=jp.action_predicate('session-accept')) - - # farstream is buggy, and tells tp-fs to tell Gabble to change the third - # codec's clockrate. This isn't legal, so Gabble says no. - new_codecs = [ ('GSM', 3, 8000, {}), - ('PCMA', 8, 8000, {}), - ('PCMU', 0, 4000, {}) ] - call_async(q, stream_handler, 'CodecsUpdated', - jt2.dbusify_codecs(new_codecs)) - event = q.expect('dbus-error', method='CodecsUpdated') - assert event.error.get_dbus_name() == cs.INVALID_ARGUMENT, \ - event.error.get_dbus_name() - - # With its tail between its legs, tp-fs decides it wants to add some - # parameters to the first two codecs, not changing the third. - new_codecs = [ ('GSM', 3, 8000, {'type': 'banana'}), - ('PCMA', 8, 8000, {'helix': 'BUFFERING'}), - ('PCMU', 0, 8000, {}) ] - stream_handler.CodecsUpdated(jt2.dbusify_codecs_with_params(new_codecs)) - - audio_content = jt2.audio_names[0] - - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='description-info']", - x.stanza)) - payload_types = xpath.queryForNodes( - "/iq/jingle/content[@name='%s']/description/payload-type" - % audio_content, - e.stanza) - # Gabble SHOULD only include the changed codecs in description-info - assert len(payload_types) == 2, payload_types - - payload_types_tupled = [ (pt['name'], int(pt['id']), int(pt['clockrate']), - extract_params(pt)) - for pt in payload_types ] - assert sorted(payload_types_tupled) == sorted(new_codecs[0:2]), \ - (payload_types_tupled, new_codecs[0:2]) - - # The remote end decides it wants to change the number of channels in the - # third codec. This is not meant to happen, so Gabble should send it an IQ - # error back. - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'description-info', [ - jp.Content(audio_content, 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType('PCMU', '1600', '0') ])) ]) ]) - stream.send(jp.xml(node)) - q.expect('stream-iq', iq_type='error', - predicate=lambda x: x.stanza['id'] == node[2]['id']) - - # Instead, the remote end decides to add a parameter to the third codec. - new_codecs = [ ('GSM', 3, 8000, {}), - ('PCMA', 8, 8000, {}), - ('PCMU', 0, 8000, {'choppy': 'false'}), - ] - # As per the XEP, it only sends the ones which have changed. - c = new_codecs[2] - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'description-info', [ - jp.Content(audio_content, 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType(c[0], str(c[2]), str(c[1]), c[3]) - ])) ]) ]) - stream.send(jp.xml(node)) - - # Gabble should patch its idea of the remote codecs with the update it just - # got, and emit SetRemoteCodecs for them all. - e = q.expect('dbus-signal', signal='SetRemoteCodecs') - new_codecs_dbus = unwrap(jt2.dbusify_codecs_with_params(new_codecs)) - announced = unwrap(e.args[0]) - assert new_codecs_dbus == announced, (new_codecs_dbus, announced) - - # We close the session by removing the stream - chan.StreamedMedia.RemoveStreams([id1]) - - e = q.expect('stream-iq', iq_type='set', predicate=lambda x: - xpath.queryForNodes("/iq/jingle[@action='session-terminate']", - x.stanza)) - -if __name__ == '__main__': - exec_test(test) - exec_test(early_description_info) - diff --git a/tests/twisted/jingle/test-incoming-call-reject.py b/tests/twisted/jingle/test-incoming-call-reject.py deleted file mode 100644 index 581ea7f60..000000000 --- a/tests/twisted/jingle/test-incoming-call-reject.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -Test incoming call handling - reject a call because we're busy, and for no -reason. -""" - -from twisted.words.xish import xpath - -from servicetest import make_channel_proxy, EventPattern, call_async -from jingletest2 import JingleTest2, test_all_dialects - -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test_busy(jp, q, bus, conn, stream): - test(jp, q, bus, conn, stream, True) - -def test_no_reason(jp, q, bus, conn, stream): - test(jp, q, bus, conn, stream, False) - -def test(jp, q, bus, conn, stream, busy): - remote_jid = 'foo@bar.com/Foo' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - # Remote end calls us - jt.incoming_call() - - # FIXME: these signals are not observable by real clients, since they - # happen before NewChannels. - # The caller is in members - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [remote_handle], [], [], [], 0, 0]) - - # We're pending because of remote_handle - e = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [self_handle], [], remote_handle, - cs.GC_REASON_INVITED]) - - # S-E gets notified about new session handler, and calls Ready on it - e = q.expect('dbus-signal', signal='NewSessionHandler') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - media_chan = make_channel_proxy(conn, e.path, 'Channel.Interface.Group') - - # Exercise channel properties - channel_props = media_chan.GetAll(cs.CHANNEL, - dbus_interface=cs.PROPERTIES_IFACE) - assert channel_props['TargetHandle'] == remote_handle - assert channel_props['TargetHandleType'] == 1 - assert channel_props['TargetID'] == 'foo@bar.com' - assert channel_props['Requested'] == False - assert channel_props['InitiatorID'] == 'foo@bar.com' - assert channel_props['InitiatorHandle'] == remote_handle - - if busy: - # First, try using a reason that doesn't make any sense - call_async(q, media_chan, 'RemoveMembersWithReason', - [self_handle], "what kind of a reason is Separated?!", - cs.GC_REASON_SEPARATED) - e = q.expect('dbus-error', method='RemoveMembersWithReason') - assert e.error.get_dbus_name() == cs.INVALID_ARGUMENT - - # Now try a more sensible reason. - media_chan.RemoveMembersWithReason([self_handle], - "which part of 'Do Not Disturb' don't you understand?", - cs.GC_REASON_BUSY) - else: - media_chan.RemoveMembers([self_handle], 'rejected') - - iq, mc, _ = q.expect_many( - EventPattern('stream-iq', - predicate=jp.action_predicate('session-terminate')), - EventPattern('dbus-signal', signal='MembersChanged'), - EventPattern('dbus-signal', signal='Closed'), - ) - - _, added, removed, lp, rp, actor, reason = mc.args - assert added == [], added - assert set(removed) == set([self_handle, remote_handle]), \ - (removed, self_handle, remote_handle) - assert lp == [], lp - assert rp == [], rp - assert actor == self_handle, (actor, self_handle) - if busy: - assert reason == cs.GC_REASON_BUSY, reason - else: - assert reason == cs.GC_REASON_NONE, reason - - if jp.is_modern_jingle(): - jingle = iq.query - if busy: - r = "/jingle/reason/busy" - else: - r = "/jingle/reason/cancel" - assert xpath.queryForNodes(r, jingle) is not None, (jingle.toXml(), r) - -if __name__ == '__main__': - test_all_dialects(test_busy) - test_all_dialects(test_no_reason) - diff --git a/tests/twisted/jingle/test-incoming-iceudp.py b/tests/twisted/jingle/test-incoming-iceudp.py deleted file mode 100644 index f59e44355..000000000 --- a/tests/twisted/jingle/test-incoming-iceudp.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -Test usage of ICE-UDP in incoming calls. -""" - -from twisted.words.xish import xpath - -from gabbletest import exec_test -from servicetest import ( - make_channel_proxy, wrap_channel, assertEquals, EventPattern, assertLength, - ) -import ns -import constants as cs - -from jingletest2 import * - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def worker(jp, q, bus, conn, stream): - jp.features.append(ns.JINGLE_TRANSPORT_ICEUDP) - jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt2.prepare() - - remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] - - # Remote end calls us - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'session-initiate', [ - jp.Content('stream1', 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.audio_codecs ]), - jp.TransportIceUdp()) ]) ]) - stream.send(jp.xml(node)) - - nc, e = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewSessionHandler'), - ) - path = nc.args[0] - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - - hrggh = chan.ListProperties(dbus_interface=cs.TP_AWKWARD_PROPERTIES) - id = [x for x, name, _, _ in hrggh if name == 'nat-traversal'][0] - nrgrg = chan.GetProperties([id], dbus_interface=cs.TP_AWKWARD_PROPERTIES) - _, nat_traversal = nrgrg[0] - assertEquals('ice-udp', nat_traversal) - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - chan.Group.AddMembers([conn.GetSelfHandle()], 'accepted') - - # S-E gets notified about a newly-created stream - e = q.expect('dbus-signal', signal='NewStreamHandler') - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(jt2.get_audio_codecs_dbus()) - stream_handler.StreamState(2) - - # First one is transport-info - e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) - transport_stanza = xpath.queryForNodes( - "/iq/jingle/content/transport[@xmlns='%s']" - % ns.JINGLE_TRANSPORT_ICEUDP, e.stanza)[0] - - # username - assertEquals(transport_stanza['ufrag'], jt2.remote_transports[0][7]) - # password - assertEquals(transport_stanza['pwd'], jt2.remote_transports[0][8]) - - children = list(transport_stanza.elements()) - assertLength(1, children) - - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # Set codec intersection so gabble can accept the session - stream_handler.SupportedCodecs(jt2.get_audio_codecs_dbus()) - - # Second one is session-accept - e = q.expect('stream-iq', predicate=jp.action_predicate('session-accept')) - assert xpath.queryForNodes("/iq/jingle/content/transport[@xmlns='%s']" % - ns.JINGLE_TRANSPORT_ICEUDP, e.stanza) - - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # Connected! Blah, blah, ... - - jt2.terminate() - - e = q.expect('dbus-signal', signal='Close') - -def test031(q, bus, conn, stream): - return worker(JingleProtocol031(),q, bus, conn, stream) - -if __name__ == '__main__': - exec_test(test031) diff --git a/tests/twisted/jingle/test-outgoing-call-rejected.py b/tests/twisted/jingle/test-outgoing-call-rejected.py deleted file mode 100644 index 819249ee7..000000000 --- a/tests/twisted/jingle/test-outgoing-call-rejected.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -Test outgoing call handling. This tests the case when the -remote party rejects our call because they're busy. -""" - -from gabbletest import make_result_iq -from servicetest import make_channel_proxy, assertEquals -import constants as cs -from jingletest2 import JingleTest2, test_all_dialects - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def _test(jp, q, bus, conn, stream, - jingle_reason, group_change_reason, stream_error): - remote_jid = 'foo@bar.com/Foo' - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', remote_jid) - - jt.prepare() - - self_handle = conn.GetSelfHandle() - remote_handle = conn.RequestHandles(cs.HT_CONTACT, [remote_jid])[0] - - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, remote_handle, True) - - signalling_iface = make_channel_proxy(conn, path, 'Channel.Interface.MediaSignalling') - media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - - media_iface.RequestStreams(remote_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') - assert e.args[1] == 'rtp' - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) - stream_handler.Ready(jt.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - stream.send(make_result_iq(stream, e.stanza)) - - text = u"begone!" - - jt.parse_session_initiate(e.query) - jt.terminate(reason=jingle_reason, text=text) - - mc = q.expect('dbus-signal', signal='MembersChanged') - message, added, removed, lp, rp, actor, reason = mc.args - assert added == [], added - assert set(removed) == set([self_handle, remote_handle]), \ - (removed, self_handle, remote_handle) - assert lp == [], lp - assert rp == [], rp - assert actor == remote_handle, (actor, remote_handle) - if jp.is_modern_jingle(): - assertEquals(text, message) - assertEquals(group_change_reason, reason) - - if jp.is_modern_jingle() and stream_error: - se = q.expect('dbus-signal', signal='StreamError') - assertEquals(stream_error, se.args[1]) - - q.expect('dbus-signal', signal='Close') #XXX - match against the path - -def test_busy(jp, q, bus, conn, stream): - _test(jp, q, bus, conn, stream, "busy", cs.GC_REASON_BUSY, None) - -def test_codec_fail(jp, q, bus, conn, stream): - _test(jp, q, bus, conn, stream, "failed-application", cs.GC_REASON_ERROR, - cs.MEDIA_STREAM_ERROR_CODEC_NEGOTIATION_FAILED) - -if __name__ == '__main__': - test_all_dialects(test_busy) - test_all_dialects(test_codec_fail) diff --git a/tests/twisted/jingle/test-outgoing-iceudp.py b/tests/twisted/jingle/test-outgoing-iceudp.py deleted file mode 100644 index fbdad9472..000000000 --- a/tests/twisted/jingle/test-outgoing-iceudp.py +++ /dev/null @@ -1,162 +0,0 @@ -""" -Test outgoing call using ICE-UDP transport mechanism. -""" - -from gabbletest import exec_test, sync_stream -from servicetest import ( - wrap_channel, make_channel_proxy, EventPattern, call_async, - assertEquals) -import gabbletest -import dbus -import time -from twisted.words.xish import xpath -import ns -import constants as cs - -from jingletest2 import * - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def worker(jp, q, bus, conn, stream): - jp.features.remove(ns.GOOGLE_P2P) - jp.features.append(ns.JINGLE_TRANSPORT_ICEUDP) - jt2 = JingleTest2(jp, conn, q, stream, 'test@localhost', 'foo@bar.com/Foo') - jt2.prepare() - - remote_handle = conn.RequestHandles(cs.HT_CONTACT, ["foo@bar.com/Foo"])[0] - - call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_STREAMED_MEDIA, 0, 0, - True) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: cs.CHANNEL_TYPE_CONTACT_LIST not in e.args), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), - ) - path = ret.value[0] - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') - - chan.StreamedMedia.RequestStreams(remote_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') - assert e.args[1] == 'rtp' - - # The 'nat-traversal' tp property should be "ice-udp" - hrggh = chan.ListProperties(dbus_interface=cs.TP_AWKWARD_PROPERTIES) - id = [x for x, name, _, _ in hrggh if name == 'nat-traversal'][0] - nrgrg = chan.GetProperties([id], dbus_interface=cs.TP_AWKWARD_PROPERTIES) - _, nat_traversal = nrgrg[0] - assertEquals('ice-udp', nat_traversal) - - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - e = q.expect('dbus-signal', signal='NewStreamHandler') - - stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", jt2.get_remote_transports_dbus()) - stream_handler.Ready(jt2.get_audio_codecs_dbus()) - stream_handler.StreamState(2) - - e = q.expect('stream-iq', predicate=jp.action_predicate('session-initiate')) - # The session-initiate "MUST include a <transport/> child element qualified - # by the [ice-udp] namespace" - node = xpath.queryForNodes("/iq/jingle/content/transport[@xmlns='%s']" % - ns.JINGLE_TRANSPORT_ICEUDP, e.stanza)[0] - jt2.parse_session_initiate(e.query) - - # ...which SHOULD contain the higher-priority ICE candidates. We supplied - # one candidate, so... - assertEquals('username', node['ufrag']) - assertEquals('password', node['pwd']) - node = [ x for x in node.children if type(x) != unicode ][0] - assertEquals('candidate', node.name) - assert node['foundation'] is not None - - stream.send(jp.xml(jp.ResultIq('test@localhost', e.stanza, []))) - - # Make sure that it doesn't send a duplicate of our one ICE candidate here. - ti_event = [ - EventPattern('stream-iq', - predicate=jp.action_predicate('transport-info')) - ] - q.forbid_events(ti_event) - sync_stream(q, stream) - q.unforbid_events(ti_event) - - # XEP-0166 6.4 Negotiation: "The allowable negotiations include: - # Exchanging particular transport candidates via the transport-info action." - candidate = ( - "192.168.0.69", # host - 668, # 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" ) - transport = jp.TransportIceUdp([candidate]) - - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'transport-info', [ - jp.Content('Audio', 'initiator', 'both', - transport = transport) ]) ]) - stream.send(jp.xml(node)) - - candidate_e, result_e = q.expect_many( - EventPattern('dbus-signal', signal='AddRemoteCandidate'), - EventPattern('stream-iq', iq_type='result')) - - fake_, (returned_candidate,) = candidate_e.args - assertEquals(candidate, returned_candidate[1:]) - - candidate = ( - "192.168.0.69", # host - 670, # 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" ) - transport = jp.TransportIceUdp([candidate]) - - # It is also valid to send transports in the accept. - # This is what pidgin does. - node = jp.SetIq(jt2.peer, jt2.jid, [ - jp.Jingle(jt2.sid, jt2.peer, 'session-accept', [ - jp.Content('Audio', 'initiator', 'both', - jp.Description('audio', [ - jp.PayloadType(name, str(rate), str(id), parameters) for - (name, id, rate, parameters) in jt2.audio_codecs ]), - transport) ]) ]) - stream.send(jp.xml(node)) - - candidate_e, result_e = q.expect_many( - EventPattern('dbus-signal', signal='AddRemoteCandidate'), - EventPattern('stream-iq', iq_type='result')) - - fake_, (returned_candidate,) = candidate_e.args - assertEquals(candidate, returned_candidate[1:]) - - chan.Close() - e = q.expect('stream-iq', - predicate=jp.action_predicate('session-terminate')) - -def test031(q, bus, conn, stream): - return worker(JingleProtocol031(),q, bus, conn, stream) - -if __name__ == '__main__': - exec_test(test031) diff --git a/tests/twisted/jingle/test-wait-for-caps-incomplete.py b/tests/twisted/jingle/test-wait-for-caps-incomplete.py deleted file mode 100644 index e6e97c226..000000000 --- a/tests/twisted/jingle/test-wait-for-caps-incomplete.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Test that Gabble properly cleans up delayed RequestStream contexts -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 constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream, channel_type): - 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, [peer])[0] - - if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, handle, True) - media_iface = make_channel_proxy(conn, path, - 'Channel.Type.StreamedMedia') - - # So it turns out that the calls to RequestStreams and Disconnect could be - # reordered while the first waits on the result of introspecting the - # channel's object which is kicked off by making a proxy object for it, - # whereas the connection proxy is long ago introspected. Isn't dbus-python - # great? Syncing here forces that introspection to finish so we can rely on - # the ordering of RequestStreams and Disconnect. Yay. - sync_dbus(bus, q, conn) - - # Now we request streams before either <presence> or caps have arrived - if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: - call_async(q, media_iface, 'RequestStreams', handle, - [cs.MEDIA_STREAM_TYPE_AUDIO]) - - before_events, after_events = disconnect_conn(q, conn, stream, - [EventPattern('dbus-error', method='RequestStreams')]) - - # RequestStreams should now return NotAvailable - assert before_events[0].error.get_dbus_name() == cs.NOT_AVAILABLE, \ - before_events[0].error - else: - call_async(q, conn.Requests, 'CreateChannel', - { cs.CHANNEL_TYPE: channel_type, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: peer, - cs.CALL_INITIAL_AUDIO: True - }) - - before_events, after_events = disconnect_conn(q, conn, stream, - [EventPattern('dbus-error', method='CreateChannel')]) - - # CreateChannel should now return Disconnected - assert before_events[0].error.get_dbus_name() == cs.DISCONNECTED, \ - before_events[0].error - -if __name__ == '__main__': - 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 deleted file mode 100644 index 98221ef8e..000000000 --- a/tests/twisted/jingle/test-wait-for-caps.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Test use-case when client requests going online and immediately -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 jingletest2 - -import dbus - -import constants as cs - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream, channel_type): - 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' - - run_test(q, bus, conn, stream, jt, True, channel_type) - run_test(q, bus, conn, stream, jt2, False, channel_type) - -def run_test(q, bus, conn, stream, jt, request_before_presence, channel_type): - """ - 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). - """ - - # 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 - request = dbus.Dictionary({ cs.CHANNEL_TYPE: channel_type, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: jt.peer, - }, signature='sv') - - if channel_type == cs.CHANNEL_TYPE_CALL: - request[cs.CALL_INITIAL_AUDIO] = True - - if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: - path, props = conn.CreateChannel(request, - dbus_interface=cs.CONN_IFACE_REQUESTS) - media_iface = make_channel_proxy(conn, path, - 'Channel.Type.StreamedMedia') - - handle = props[cs.TARGET_HANDLE] - - sync_dbus(bus, q, conn) - - def call_request_streams(): - if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: - call_async(q, media_iface, 'RequestStreams', handle, - [cs.MEDIA_STREAM_TYPE_AUDIO]) - else: - call_async(q, conn.Requests, 'CreateChannel', request) - - if request_before_presence: - # Request streams before either <presence> or caps have arrived. Gabble - # should wait for both to arrive before returning from RequestStreams. - call_request_streams() - - # Ensure Gabble's received the method call. - sync_dbus(bus, q, conn) - - # Now send the presence. - info_event = jt.send_presence() - else: - info_event = jt.send_presence() - - # Now call RequestStreams; it should wait for the disco reply. - call_request_streams() - - jt.send_remote_disco_reply(info_event.stanza) - - # RequestStreams should now happily complete - if channel_type == cs.CHANNEL_TYPE_STREAMED_MEDIA: - q.expect('dbus-return', method='RequestStreams') - else: - q.expect('dbus-return', method='CreateChannel') - -if __name__ == '__main__': - 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/transport-info-parsing.py b/tests/twisted/jingle/transport-info-parsing.py deleted file mode 100644 index b84d84770..000000000 --- a/tests/twisted/jingle/transport-info-parsing.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -Test whether we parse the transport info with multiple contents correctly -""" - -from gabbletest import exec_test -from servicetest import ( make_channel_proxy, EventPattern, - assertEquals, assertNotEquals ) -from jingletest2 import * - -from config import VOIP_ENABLED - -if not VOIP_ENABLED: - print "NOTE: built with --disable-voip" - raise SystemExit(77) - -def test(q, bus, conn, stream, peer='foo@bar.com/Foo'): - jp = JingleProtocol031() - - jt = JingleTest2(jp, conn, q, stream, 'test@localhost', peer) - jt.prepare() - - # Remote end calls us - jt.incoming_call(audio = "Audio", video = "Video") - - e = q.expect ('dbus-signal', signal='NewSessionHandler') - handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - handler.Ready() - - events = q.expect_many ( - EventPattern('dbus-signal', signal='NewStreamHandler'), - EventPattern('dbus-signal', signal='NewStreamHandler') - ) - for e in events: - handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler') - handler.Ready([]) - - candidate0 = ( - "1.2.3.4", # 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" ) - - candidate1 = ( - "5.6.7.8", # host - 999, # 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" ) - - node = jp.SetIq(jt.peer, jt.jid, [ - jp.Jingle(jt.sid, jt.peer, 'transport-info', [ - jp.Content('Audio', 'initiator', 'both', - transport = jp.TransportGoogleP2P([candidate0])), - jp.Content('Video', 'initiator', 'both', - transport = jp.TransportGoogleP2P([candidate1])), - ] ) ]) - - stream.send(jp.xml(node)) - - q.expect ('stream-iq', iq_type='result') - (c0, c1) = q.expect_many( - EventPattern('dbus-signal', signal='AddRemoteCandidate'), - EventPattern('dbus-signal', signal='AddRemoteCandidate')) - - assertNotEquals(c0.path, c1.path) - - mapping = { 666: candidate0, 999: candidate1} - - # Candidate without component number to compare - candidate = c0.args[1][0][1:] - assertEquals(mapping[candidate[1]], candidate) - - candidate = c1.args[1][0][1:] - assertEquals(mapping[candidate[1]], candidate) - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/last-activity.py b/tests/twisted/last-activity.py index fd3da5a36..7f82e6f23 100644 --- a/tests/twisted/last-activity.py +++ b/tests/twisted/last-activity.py @@ -1,7 +1,7 @@ """ Trivial smoke-test for XEP-0012 support. """ -from servicetest import assertEquals, assertContains +from servicetest import assertEquals from gabbletest import exec_test, elem, elem_iq import ns diff --git a/tests/twisted/mail-notification.py b/tests/twisted/mail-notification.py index ef19c7d79..a56eee24f 100644 --- a/tests/twisted/mail-notification.py +++ b/tests/twisted/mail-notification.py @@ -56,7 +56,6 @@ def test_google_featured(q, bus, conn, stream): # Email thread 3 data thread3_id = "3" thread3_date = 1235L - thread3_url = 'http://mail.google.com/mail/#inbox/%x' % long(thread3_id) thread3_senders = [('Le Chat', 'le@chat.fr'),] thread3_subject = "subject3" thread3_snippet = "body3" @@ -333,7 +332,7 @@ def test_no_google_featured(q, bus, conn, stream): def test(q, bus, conn, stream): - interfaces = conn.GetInterfaces() + interfaces = conn.Properties.Get(cs.CONN, 'Interfaces') if stream.__class__ is GoogleXmlStream: assert cs.CONN_IFACE_MAIL_NOTIFICATION in interfaces diff --git a/tests/twisted/muc/avatars.py b/tests/twisted/muc/avatars.py index 91cc17f31..323b63b24 100644 --- a/tests/twisted/muc/avatars.py +++ b/tests/twisted/muc/avatars.py @@ -7,12 +7,11 @@ import hashlib from servicetest import ( - call_async, EventPattern, assertEquals, assertLength, sync_dbus, - wrap_channel, + call_async, EventPattern, assertEquals, assertLength, wrap_channel, ) from gabbletest import ( exec_test, expect_and_handle_get_vcard, expect_and_handle_set_vcard, - make_muc_presence, elem, + make_muc_presence, ) from twisted.words.xish import xpath import ns @@ -35,7 +34,7 @@ def extract_hash_from_presence(stanza): stanza) def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # When Gabble initially requests its avatar from the server, it discovers # it has none. @@ -101,13 +100,12 @@ def test(q, bus, conn, stream): photo=AVATAR_1_SHA1)) path, _ = q.expect('dbus-return', method='CreateChannel').value - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['Messages']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') members = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members') assertLength(3, members) - fredrik, wendy, muc_self_handle = conn.RequestHandles(cs.HT_CONTACT, + fredrik, wendy, muc_self_handle = conn.get_contact_handles_sync( ['%s/%s' % (MUC, x) for x in ["fredrik", "wendy", "test"]]) known = conn.Avatars.GetKnownAvatarTokens(members) diff --git a/tests/twisted/muc/chat-states.py b/tests/twisted/muc/chat-states.py index 4be5f50b2..5aaee085c 100644 --- a/tests/twisted/muc/chat-states.py +++ b/tests/twisted/muc/chat-states.py @@ -31,7 +31,7 @@ def check_state_notification(elem, name, allow_body=False): 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, + (chan, user, bob) = join_muc_and_check(q, bus, conn, stream, MUC) states = chan.Properties.Get(cs.CHANNEL_IFACE_CHAT_STATE, 'ChatStates') @@ -108,7 +108,7 @@ def test(q, bus, conn, stream): # XEP 0085: # every content message SHOULD contain an <active/> notification. - chan.Text.Send(0, 'hi.') + chan.send_msg_sync('hi.') stream_message = q.expect('stream-message') stanza = stream_message.stanza diff --git a/tests/twisted/muc/conference.py b/tests/twisted/muc/conference.py index d8e87fa3c..5d5e8e7c1 100644 --- a/tests/twisted/muc/conference.py +++ b/tests/twisted/muc/conference.py @@ -3,8 +3,7 @@ Test the different ways to request a channel using the Conference interface """ from gabbletest import exec_test, make_muc_presence -from servicetest import (call_async, EventPattern, assertEquals, - assertContains) +from servicetest import (call_async, assertEquals, assertContains) import constants as cs import dbus diff --git a/tests/twisted/muc/kicked.py b/tests/twisted/muc/kicked.py index e32648853..307b96f25 100644 --- a/tests/twisted/muc/kicked.py +++ b/tests/twisted/muc/kicked.py @@ -14,13 +14,14 @@ MUC = 'deerhoof@evil.lit' def test(q, bus, conn, stream): # The user happily joins a MUC - _, chan, _, _ = join_muc(q, bus, conn, stream, MUC) - muc_self_handle = chan.Group.GetSelfHandle() - muc_self_jid, = conn.InspectHandles(cs.HT_CONTACT, [muc_self_handle]) + chan, _, _ = join_muc(q, bus, conn, stream, MUC) + muc_self_handle = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, + "SelfHandle") + muc_self_jid = conn.inspect_contact_sync(muc_self_handle) # But then Bob kicks us. bob_jid = '%s/bob' % MUC - bob_handle, = conn.RequestHandles(cs.HT_CONTACT, [bob_jid]) + bob_handle = conn.get_contact_handle_sync(bob_jid) stream.send( elem('presence', from_=muc_self_jid, type='unavailable')( elem(ns.MUC_USER, 'x')( diff --git a/tests/twisted/muc/name-conflict.py b/tests/twisted/muc/name-conflict.py index 512c16e0b..2aee8d2f3 100644 --- a/tests/twisted/muc/name-conflict.py +++ b/tests/twisted/muc/name-conflict.py @@ -78,7 +78,7 @@ def test_join(q, bus, conn, stream, room_jid, transient_conflict): text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') group_props = unwrap(text_chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP)) - t, t_ = conn.RequestHandles(cs.HT_CONTACT, [member, member_]) + t, t_ = conn.get_contact_handles_sync([member, member_]) # Check that Gabble think our nickname in the room is test_, not test muc_self_handle = group_props['SelfHandle'] @@ -101,7 +101,7 @@ def test_join(q, bus, conn, stream, room_jid, transient_conflict): # Check that test_'s handle owner is us, and that test (if it's there) has # no owner. handle_owners = group_props['HandleOwners'] - assertEquals (conn.GetSelfHandle(), handle_owners[t_]) + assertEquals (conn.Properties.Get(cs.CONN, "SelfHandle"), handle_owners[t_]) if not transient_conflict: assertEquals (0, handle_owners[t]) @@ -184,8 +184,8 @@ def test_gtalk_weirdness(q, bus, conn, stream, room_jid): # resources of the same contact. There is no race between this method # returning and MembersChangedDetailed firing, because libdbus reorders # messages when you make blocking calls. - handle, handle_, handle__, foobar_handle = conn.RequestHandles( - cs.HT_CONTACT, jids + ['%s/foobar_gmail.com' % room_jid]) + handle, handle_, handle__, foobar_handle = conn.get_contact_handles_sync( + jids + ['%s/foobar_gmail.com' % room_jid]) q.expect('dbus-signal', signal='MembersChangedDetailed', predicate=lambda e: e.args[0:4] == [[foobar_handle], [], [], []]) diff --git a/tests/twisted/muc/only-text-when-needed.py b/tests/twisted/muc/only-text-when-needed.py index 260d26c8a..744e47ef0 100644 --- a/tests/twisted/muc/only-text-when-needed.py +++ b/tests/twisted/muc/only-text-when-needed.py @@ -3,14 +3,11 @@ 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, \ +from gabbletest import exec_test, make_muc_presence, \ sync_stream, elem import constants as cs -import ns from mucutil import echo_muc_presence @@ -295,7 +292,7 @@ def test_message(q, bus, conn, stream): 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] + bob_handle = conn.get_contact_handle_sync(bob_jid) # now let's send a message stream.send( @@ -337,7 +334,7 @@ def test_requested_message(q, bus, conn, stream): presence=False) bob_jid = '%s/bob' % jid - bob_handle = conn.RequestHandles(cs.HT_CONTACT, [bob_jid])[0] + bob_handle = conn.get_contact_handle_sync(bob_jid) # make sure it says we requested it props = text_chan.Properties.GetAll(cs.CHANNEL) diff --git a/tests/twisted/muc/password.py b/tests/twisted/muc/password.py index 7a67d17af..ee1ec3300 100644 --- a/tests/twisted/muc/password.py +++ b/tests/twisted/muc/password.py @@ -1,4 +1,4 @@ -from gabbletest import exec_test, elem, request_muc_handle, make_muc_presence +from gabbletest import exec_test, elem, make_muc_presence from servicetest import call_async, EventPattern, wrap_channel, assertEquals import constants as cs import ns @@ -12,12 +12,11 @@ def expect_attempt(q, expected_muc_jid, expected_password): def test(q, bus, conn, stream): room = 'chat@conf.localhost' - handle = request_muc_handle(q, conn, stream, room) call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_HANDLE: handle}) + cs.TARGET_ID: room }) expected_muc_jid = '%s/%s' % (room, 'test') q.expect('stream-presence', to=expected_muc_jid) @@ -39,8 +38,7 @@ def test(q, bus, conn, stream): EventPattern('dbus-signal', signal='PasswordFlagsChanged', args=[cs.PASSWORD_FLAG_PROVIDE, 0])) - chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text', - ['Password']) + chan = wrap_channel(bus.get_object(conn.bus_name, cc.value[0]), 'Text') flags = chan.Password.GetPasswordFlags() assertEquals(cs.PASSWORD_FLAG_PROVIDE, flags) diff --git a/tests/twisted/muc/presence-before-closing.py b/tests/twisted/muc/presence-before-closing.py index b89abef4f..f2f96e54a 100644 --- a/tests/twisted/muc/presence-before-closing.py +++ b/tests/twisted/muc/presence-before-closing.py @@ -2,15 +2,11 @@ Test for fd.o#19930. """ -import dbus - -from twisted.words.xish import domish - from gabbletest import ( - exec_test, make_result_iq, request_muc_handle, wrap_channel, elem, + exec_test, wrap_channel, elem, ) -from servicetest import (EventPattern, assertEquals, assertLength, - assertContains, sync_dbus, call_async) +from servicetest import (EventPattern, assertEquals, + sync_dbus, call_async) import constants as cs import ns @@ -19,7 +15,7 @@ from mucutil import join_muc, echo_muc_presence def test(q, bus, conn, stream): room = 'test@conf.localhost' - room_handle, chan, path, props, disco = join_muc(q, bus, conn, stream, + chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)]) @@ -56,7 +52,7 @@ def test(q, bus, conn, stream): # now that the channel has finally closed, let's try and request # it again which should succeed! - _, chan, _, _ = join_muc(q, bus, conn, stream, room) + chan, _, _ = join_muc(q, bus, conn, stream, room) # let's clear up though. chan.Close() @@ -68,7 +64,7 @@ def test(q, bus, conn, stream): def test_then_disconnect(q, bus, conn, stream): room = 'test@conf.localhost' - room_handle, chan, path, props, disco = join_muc(q, bus, conn, stream, + chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)]) @@ -106,12 +102,11 @@ def test_then_disconnect(q, bus, conn, stream): def test_with_password(q, bus, conn, stream): room = 'chat@conf.localhost' - handle = request_muc_handle(q, conn, stream, room) call_async(q, conn.Requests, 'CreateChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_HANDLE: handle}) + cs.TARGET_ID: room }) expected_muc_jid = '%s/%s' % (room, 'test') q.expect('stream-presence', to=expected_muc_jid) diff --git a/tests/twisted/muc/renamed.py b/tests/twisted/muc/renamed.py index ed86ed3ff..a5578b588 100644 --- a/tests/twisted/muc/renamed.py +++ b/tests/twisted/muc/renamed.py @@ -5,28 +5,27 @@ Test dealing with the server giving you a nick you didn't ask for. import dbus from gabbletest import ( - exec_test, make_muc_presence, request_muc_handle + exec_test, make_muc_presence ) from servicetest import call_async, unwrap from constants import ( - HT_CONTACT, HT_ROOM, + HT_ROOM, CONN_IFACE_REQUESTS, CHANNEL_TYPE_TEXT, CHANNEL_IFACE_GROUP, - CHANNEL_TYPE, TARGET_HANDLE_TYPE, TARGET_HANDLE, + CHANNEL_TYPE, TARGET_HANDLE_TYPE, TARGET_ID, ) import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") requests = dbus.Interface(conn, CONN_IFACE_REQUESTS) room_jid = 'chat@conf.localhost' - room_handle = request_muc_handle(q, conn, stream, room_jid) call_async(q, requests, 'CreateChannel', dbus.Dictionary({ CHANNEL_TYPE: CHANNEL_TYPE_TEXT, TARGET_HANDLE_TYPE: HT_ROOM, - TARGET_HANDLE: room_handle, + TARGET_ID: room_jid, }, signature='sv')) expected_jid = '%s/%s' % (room_jid, 'test') @@ -54,7 +53,7 @@ def test(q, bus, conn, stream): group_props = unwrap(text_chan.GetAll(CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE)) - liz, toofer, expected_handle = conn.RequestHandles(HT_CONTACT, + liz, toofer, expected_handle = conn.get_contact_handles_sync( ["%s/%s" % (room_jid, m) for m in ['liz', 'toofer', 'test']]) # Check that Gabble think our nickname in the room is toofer not test diff --git a/tests/twisted/muc/room-config.py b/tests/twisted/muc/room-config.py index ef5c78a74..c7cfd9282 100644 --- a/tests/twisted/muc/room-config.py +++ b/tests/twisted/muc/room-config.py @@ -8,9 +8,9 @@ from twisted.words.xish import xpath from gabbletest import ( exec_test, make_result_iq, acknowledge_iq, make_muc_presence, - request_muc_handle, sync_stream, disconnect_conn) + disconnect_conn) from servicetest import ( - call_async, wrap_channel, EventPattern, assertEquals, assertSameSets, + call_async, EventPattern, assertEquals, assertSameSets, assertContains, ) from mucutil import join_muc @@ -118,7 +118,7 @@ def handle_disco_info_iq(stream, stanza): stream.send(iq) def test_some_stuff(q, bus, conn, stream): - _, text_chan, _, _, disco_iq, owner_iq, _ = join_muc(q, bus, conn, stream, + text_chan, _, _, disco_iq, owner_iq, _ = join_muc(q, bus, conn, stream, 'chat@conf.localhost', role='moderator', affiliation='owner', also_capture=[ EventPattern('stream-iq', to='chat@conf.localhost', iq_type='get', @@ -255,7 +255,7 @@ def test_role_changes(q, bus, conn, stream): # The test user joins a room. Bob is an owner (and moderator); the test # user starts out with no affiliation and the rôle of participant. MUC = 'aoeu@snth' - _, chan, _, immutable_props, disco = join_muc(q, bus, conn, stream, + chan, _, immutable_props, disco = join_muc(q, bus, conn, stream, MUC, role='participant', also_capture=[ EventPattern('stream-iq', to=MUC, iq_type='get', @@ -331,7 +331,7 @@ def test_role_changes(q, bus, conn, stream): def test_broken_server(q, bus, conn, stream): MUC = 'bro@ken' - _, chan, _ , _ = join_muc(q, bus, conn, stream, MUC, affiliation='owner') + chan, _ , _ = join_muc(q, bus, conn, stream, MUC, affiliation='owner') owner_iq = q.expect('stream-iq', to=MUC, iq_type='get', query_ns=ns.MUC_OWNER) handle_muc_owner_get_iq(stream, owner_iq.stanza) @@ -350,7 +350,7 @@ def test_disconnect_during_update_configuration(q, bus, conn, stream): changes to be acked. """ def join_me_up_buttercup(muc): - _, chan, _, _ = join_muc(q, bus, conn, stream, muc, affiliation='owner') + chan, _, _ = join_muc(q, bus, conn, stream, muc, affiliation='owner') # Gabble grabs the owner configuration form to see whether it's # possible to change the room description. owner_iq = q.expect('stream-iq', to=muc, iq_type='get', diff --git a/tests/twisted/muc/room.py b/tests/twisted/muc/room.py index e047fdc6e..a67a89fd4 100644 --- a/tests/twisted/muc/room.py +++ b/tests/twisted/muc/room.py @@ -3,12 +3,9 @@ Test the different ways to request a channel using the Room interface """ from gabbletest import exec_test, make_muc_presence -from servicetest import (call_async, EventPattern, assertEquals, - assertContains) +from servicetest import (call_async, assertEquals) import constants as cs -import dbus - import re def create_muc(q, conn, stream, props): diff --git a/tests/twisted/muc/roomlist.py b/tests/twisted/muc/roomlist.py index cd29dc254..d16fc8987 100644 --- a/tests/twisted/muc/roomlist.py +++ b/tests/twisted/muc/roomlist.py @@ -6,7 +6,7 @@ Test MUC support. import dbus from gabbletest import make_result_iq, exec_test, sync_stream, disconnect_conn -from servicetest import call_async, EventPattern, tp_name_prefix +from servicetest import call_async, EventPattern, assertEquals import constants as cs def test(q, bus, conn, stream): @@ -32,129 +32,55 @@ def test(q, bus, conn, stream): # Make sure the stream has been processed sync_stream(q, stream) - properties = conn.GetAll( - tp_name_prefix + '.Connection.Interface.Requests', - dbus_interface=dbus.PROPERTIES_IFACE) + properties = conn.Properties.GetAll(cs.CONN_IFACE_REQUESTS) assert properties.get('Channels') == [], properties['Channels'] - assert ({tp_name_prefix + '.Channel.ChannelType': - tp_name_prefix + '.Channel.Type.RoomList', - tp_name_prefix + '.Channel.TargetHandleType': 0, + assert ({ cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, + cs.TARGET_HANDLE_TYPE: cs.HT_NONE, }, - [tp_name_prefix + '.Channel.Type.RoomList.Server'], + [cs.CHANNEL_TYPE_ROOM_LIST + '.Server'], ) in properties.get('RequestableChannelClasses'),\ properties['RequestableChannelClasses'] - call_async(q, conn, 'RequestChannel', - tp_name_prefix + '.Channel.Type.RoomList', 0, 0, True) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels'), - ) - - bus = dbus.SessionBus() - path1 = ret.value[0] - chan = bus.get_object(conn.bus_name, path1) - - assert new_sig.args[0][0][0] == path1 - - props = new_sig.args[0][0][1] - assert props[tp_name_prefix + '.Channel.ChannelType'] ==\ - tp_name_prefix + '.Channel.Type.RoomList' - assert props[tp_name_prefix + '.Channel.TargetHandleType'] == 0 - assert props[tp_name_prefix + '.Channel.TargetHandle'] == 0 - assert props[tp_name_prefix + '.Channel.TargetID'] == '' - assert props[tp_name_prefix + '.Channel.Requested'] == True - assert props[tp_name_prefix + '.Channel.InitiatorHandle'] \ - == conn.GetSelfHandle() - assert props[tp_name_prefix + '.Channel.InitiatorID'] \ - == 'test@localhost' - assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == \ - 'conf.localhost' - - assert old_sig.args[0] == path1 - assert old_sig.args[1] == tp_name_prefix + '.Channel.Type.RoomList' - assert old_sig.args[2] == 0 # handle type - assert old_sig.args[3] == 0 # handle - assert old_sig.args[4] == 1 # suppress handler - - # Exercise basic Channel Properties from spec 0.17.7 - channel_props = chan.GetAll( - tp_name_prefix + '.Channel', - dbus_interface=dbus.PROPERTIES_IFACE) - assert channel_props.get('TargetHandle') == 0,\ - channel_props.get('TargetHandle') - assert channel_props['TargetID'] == '', channel_props - assert channel_props.get('TargetHandleType') == 0,\ - channel_props.get('TargetHandleType') - assert channel_props.get('ChannelType') == \ - tp_name_prefix + '.Channel.Type.RoomList',\ - channel_props.get('ChannelType') - assert channel_props['Requested'] == True - assert channel_props['InitiatorID'] == 'test@localhost' - assert channel_props['InitiatorHandle'] == conn.GetSelfHandle() - - assert chan.Get( - tp_name_prefix + '.Channel.Type.RoomList', 'Server', - dbus_interface=dbus.PROPERTIES_IFACE) == \ - 'conf.localhost' - # FIXME: actually list the rooms! call_async(q, conn.Requests, 'CreateChannel', - { tp_name_prefix + '.Channel.ChannelType': - tp_name_prefix + '.Channel.Type.RoomList', - tp_name_prefix + '.Channel.TargetHandleType': 0, - tp_name_prefix + '.Channel.Type.RoomList.Server': + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, + cs.TARGET_HANDLE_TYPE: cs.HT_NONE, + cs.CHANNEL_TYPE_ROOM_LIST + '.Server': 'conference.example.net', }) - ret, old_sig, new_sig = q.expect_many( + ret, sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) path2 = ret.value[0] chan = bus.get_object(conn.bus_name, path2) props = ret.value[1] - assert props[tp_name_prefix + '.Channel.ChannelType'] ==\ - tp_name_prefix + '.Channel.Type.RoomList' - assert props[tp_name_prefix + '.Channel.TargetHandleType'] == 0 - assert props[tp_name_prefix + '.Channel.TargetHandle'] == 0 - assert props[tp_name_prefix + '.Channel.TargetID'] == '' - assert props[tp_name_prefix + '.Channel.Requested'] == True - assert props[tp_name_prefix + '.Channel.InitiatorHandle'] \ - == conn.GetSelfHandle() - assert props[tp_name_prefix + '.Channel.InitiatorID'] \ - == 'test@localhost' - assert props[tp_name_prefix + '.Channel.Type.RoomList.Server'] == \ - 'conference.example.net' - - assert new_sig.args[0][0][0] == path2 - assert new_sig.args[0][0][1] == props - - assert old_sig.args[0] == path2 - assert old_sig.args[1] == tp_name_prefix + '.Channel.Type.RoomList' - assert old_sig.args[2] == 0 # handle type - assert old_sig.args[3] == 0 # handle - assert old_sig.args[4] == 1 # suppress handler - - assert chan.Get( - tp_name_prefix + '.Channel.Type.RoomList', 'Server', + assertEquals(cs.CHANNEL_TYPE_ROOM_LIST, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_NONE, props[cs.TARGET_HANDLE_TYPE]) + assertEquals(0, props[cs.TARGET_HANDLE]) + assertEquals('', props[cs.TARGET_ID]) + assertEquals(True, props[cs.REQUESTED]) + assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), props[cs.INITIATOR_HANDLE]) + assertEquals('test@localhost', props[cs.INITIATOR_ID]) + assertEquals('conference.example.net', props[cs.CHANNEL_TYPE_ROOM_LIST+ '.Server']) + + assert sig.args[0][0][0] == path2 + assert sig.args[0][0][1] == props + + assert chan.Get(cs.CHANNEL_TYPE_ROOM_LIST, 'Server', dbus_interface=dbus.PROPERTIES_IFACE) == \ 'conference.example.net' # FIXME: actually list the rooms! call_async(q, conn.Requests, 'EnsureChannel', - { tp_name_prefix + '.Channel.ChannelType': - tp_name_prefix + '.Channel.Type.RoomList', - tp_name_prefix + '.Channel.TargetHandleType': 0, - tp_name_prefix + '.Channel.Type.RoomList.Server': - 'conference.example.net', - }) + { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_ROOM_LIST, + cs.TARGET_HANDLE_TYPE: cs.HT_NONE, + cs.CHANNEL_TYPE_ROOM_LIST + '.Server': 'conference.example.net', + }) ret = q.expect('dbus-return', method='EnsureChannel') yours, ensured_path, ensured_props = ret.value @@ -163,9 +89,7 @@ def test(q, bus, conn, stream): assert ensured_path == path2, (ensured_path, path2) disconnect_conn(q, conn, stream, [ - EventPattern('dbus-signal', signal='Closed', path=path1), EventPattern('dbus-signal', signal='Closed', path=path2), - EventPattern('dbus-signal', signal='ChannelClosed', args=[path1]), EventPattern('dbus-signal', signal='ChannelClosed', args=[path2])]) if __name__ == '__main__': diff --git a/tests/twisted/muc/scrollback.py b/tests/twisted/muc/scrollback.py index 607d3c6f8..a1f75c62f 100644 --- a/tests/twisted/muc/scrollback.py +++ b/tests/twisted/muc/scrollback.py @@ -7,12 +7,9 @@ MUC's bare JID. Also acts as a scrollback messages in general! """ -import dbus - from servicetest import assertEquals, assertContains from gabbletest import exec_test, elem -import constants as cs import ns from mucutil import join_muc_and_check @@ -23,7 +20,7 @@ def test(q, bus, conn, stream): bob_jid = room + '/bob' marco_jid = room + '/marco' - room_handle, chan, test_handle, bob_handle = \ + chan, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, room) # Here are a few scrollback messages. One from us; one from bob; and one @@ -74,8 +71,7 @@ def test(q, bus, conn, stream): marco = badger(m3) assertEquals([our_jid, bob_jid, marco_jid], - conn.InspectHandles(cs.HT_CONTACT, - [ me, bob, marco ])) + conn.inspect_contacts_sync([ me, bob, marco ])) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/muc/send-error.py b/tests/twisted/muc/send-error.py index 33f376bf5..4f59fbd18 100644 --- a/tests/twisted/muc/send-error.py +++ b/tests/twisted/muc/send-error.py @@ -2,7 +2,6 @@ Test incoming error messages in MUC channels. """ -import warnings import dbus from gabbletest import exec_test @@ -14,7 +13,7 @@ from mucutil import join_muc_and_check def test(q, bus, conn, stream): muc = 'chat@conf.localhost' - _, text_chan, test_handle, bob_handle = \ + text_chan, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) # Suppose we don't have permission to speak in this MUC. Send a message to @@ -69,9 +68,8 @@ def send_message_and_expect_error(q, stream, sent_token = text_chan.Messages.SendMessage(greeting, dbus.UInt32(0)) - stream_message, _, _ = q.expect_many( + stream_message, _ = q.expect_many( EventPattern('stream-message'), - EventPattern('dbus-signal', signal='Sent'), EventPattern('dbus-signal', signal='MessageSent'), ) @@ -92,36 +90,7 @@ def send_message_and_expect_error(q, stream, stream.send(elem) - # check that we got a failed delivery report and a SendError - send_error, received, message_received = q.expect_many( - EventPattern('dbus-signal', signal='SendError'), - EventPattern('dbus-signal', signal='Received'), - EventPattern('dbus-signal', signal='MessageReceived'), - ) - - err, timestamp, type, text = send_error.args - assertEquals(send_error_value, err) - # there's no way to tell when the original message was sent from the error stanza - assertEquals(0, timestamp) - # Gabble can't determine the type of the original message; see muc/test-muc.py - # assert type == 0, 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 - - 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) + message_received = q.expect('dbus-signal', signal='MessageReceived') # Check that the Messages.MessageReceived signal was a failed delivery report assertLength(1, message_received.args) diff --git a/tests/twisted/muc/subject.py b/tests/twisted/muc/subject.py index e83c0fc16..c323331ec 100644 --- a/tests/twisted/muc/subject.py +++ b/tests/twisted/muc/subject.py @@ -7,8 +7,7 @@ import dbus from twisted.words.xish import domish from gabbletest import exec_test, make_result_iq, make_muc_presence -from servicetest import (EventPattern, assertEquals, assertLength, - assertContains, call_async) +from servicetest import (EventPattern, assertEquals, call_async) import constants as cs import ns @@ -46,7 +45,7 @@ def test_subject(q, bus, conn, stream, change_subject, send_first, moderator): room = 'test@conf.localhost' - room_handle, chan, path, props, disco = join_muc(q, bus, conn, stream, + chan, path, props, disco = join_muc(q, bus, conn, stream, room, also_capture=[EventPattern('stream-iq', iq_type='get', query_name='query', query_ns=ns.DISCO_INFO, to=room)], diff --git a/tests/twisted/muc/test-ensure.py b/tests/twisted/muc/test-ensure.py index e03ae3567..858385256 100644 --- a/tests/twisted/muc/test-ensure.py +++ b/tests/twisted/muc/test-ensure.py @@ -3,7 +3,7 @@ Test that EnsureChannel works for MUCs, particularly in the case when there are several pending requests for the same MUC. """ -from gabbletest import make_result_iq, exec_test, make_muc_presence +from gabbletest import exec_test, make_muc_presence from servicetest import (call_async, EventPattern, assertContains, assertEquals) import constants as cs @@ -12,31 +12,27 @@ def test(q, bus, conn, stream): # Need to call this asynchronously as it involves Gabble sending us a # query. jids = ['chat@conf.localhost', 'chien@conf.localhost'] - call_async(q, conn, 'RequestHandles', 2, jids) - event = q.expect('dbus-return', method='RequestHandles') - room_handles = event.value[0] + test_create_ensure(q, conn, bus, stream, jids[0]) + test_ensure_ensure(q, conn, bus, stream, jids[1]) - test_create_ensure(q, conn, bus, stream, jids[0], room_handles[0]) - test_ensure_ensure(q, conn, bus, stream, jids[1], room_handles[1]) - -def test_create_ensure(q, conn, bus, stream, room_jid, room_handle): +def test_create_ensure(q, conn, bus, stream, room_jid): # Call both Create and Ensure for the same channel. 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, + cs.TARGET_ID: room_jid, }) call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_HANDLE: room_handle, + cs.TARGET_ID: room_jid, }) mc, _ = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged'), + EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('stream-presence', to=('%s/test' % room_jid))) - msg, added, removed, local_pending, remote_pending, actor, reason = mc.args + added, removed, local_pending, remote_pending, details = mc.args assert added == [], mc.args assert removed == [], mc.args @@ -49,15 +45,15 @@ def test_create_ensure(q, conn, bus, stream, room_jid, room_handle): # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) - mc = q.expect('dbus-signal', signal='MembersChanged') - msg, added, removed, local_pending, remote_pending, actor, reason = mc.args + mc = q.expect('dbus-signal', signal='MembersChangedDetailed') + added, removed, local_pending, remote_pending, details = mc.args assert len(added) == 2, mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert remote_pending == [], mc.args - members = conn.InspectHandles(1, added) + members = conn.inspect_contacts_sync(added) members.sort() assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members @@ -84,23 +80,23 @@ def test_create_ensure(q, conn, bus, stream, room_jid, room_handle): c_props[cs.DELIVERY_REPORTING_SUPPORT]) -def test_ensure_ensure(q, conn, bus, stream, room_jid, room_handle): +def test_ensure_ensure(q, conn, bus, stream, room_jid): # Call Ensure twice for the same channel. call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_HANDLE: room_handle, + cs.TARGET_ID: room_jid, }) call_async(q, conn.Requests, 'EnsureChannel', { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, - cs.TARGET_HANDLE: room_handle, + cs.TARGET_ID: room_jid, }) mc, _ = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged'), + EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('stream-presence', to=('%s/test' % room_jid))) - msg, added, removed, local_pending, remote_pending, actor, reason = mc.args + added, removed, local_pending, remote_pending, details = mc.args assert added == [], mc.args assert removed == [], mc.args @@ -113,15 +109,15 @@ def test_ensure_ensure(q, conn, bus, stream, room_jid, room_handle): # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'test')) - mc = q.expect('dbus-signal', signal='MembersChanged') - msg, added, removed, local_pending, remote_pending, actor, reason = mc.args + mc = q.expect('dbus-signal', signal='MembersChangedDetailed') + added, removed, local_pending, remote_pending, details = mc.args assert len(added) == 2, mc.args assert removed == [], mc.args assert local_pending == [], mc.args assert remote_pending == [], mc.args - members = conn.InspectHandles(1, added) + members = conn.inspect_contacts_sync(added) members.sort() assert members == ['%s/bob' % room_jid, '%s/test' % room_jid], members diff --git a/tests/twisted/muc/test-muc-alias.py b/tests/twisted/muc/test-muc-alias.py index edfd78b96..a07af1c06 100644 --- a/tests/twisted/muc/test-muc-alias.py +++ b/tests/twisted/muc/test-muc-alias.py @@ -2,7 +2,7 @@ Test that our alias is used to create MUC JIDs. """ -from gabbletest import exec_test, make_muc_presence, request_muc_handle, \ +from gabbletest import exec_test, make_muc_presence, \ expect_and_handle_get_vcard, expect_and_handle_set_vcard from servicetest import call_async, EventPattern @@ -11,7 +11,7 @@ import constants as cs def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_set_vcard(q, stream) @@ -20,15 +20,24 @@ def test(q, bus, conn, stream): args=[[(self_handle, u'lala')]]) room_jid = 'chat@conf.localhost' - room_handle = request_muc_handle(q, conn, stream, room_jid) - call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, - room_handle, True) + # muc stream tube + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: room_jid}) gfc, _, _ = q.expect_many( EventPattern('dbus-signal', signal='GroupFlagsChanged'), - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [], [2], 0, 0]), + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + e.args[0] == [] and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + len(e.args[3]) == 1 and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + e.args[4]['contact-ids'][e.args[3][0]] == 'chat@conf.localhost/lala'), EventPattern('stream-presence', to='%s/lala' % room_jid)) assert gfc.args[1] == 0 @@ -38,12 +47,18 @@ def test(q, bus, conn, stream): # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', room_jid, 'lala')) - event = q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [2, 3], [], [], [], 0, 0]) - assert conn.InspectHandles(1, [2]) == ['chat@conf.localhost/lala'] - assert conn.InspectHandles(1, [3]) == ['chat@conf.localhost/bob'] + event = q.expect('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + len(e.args[0]) == 2 and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + e.args[3] == [] and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == + set(['chat@conf.localhost/lala', 'chat@conf.localhost/bob'])) - event = q.expect('dbus-return', method='RequestChannel') + event = q.expect('dbus-return', method='CreateChannel') if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/muc/test-muc-invitation.py b/tests/twisted/muc/test-muc-invitation.py index e30c68dc2..6cc8efc44 100644 --- a/tests/twisted/muc/test-muc-invitation.py +++ b/tests/twisted/muc/test-muc-invitation.py @@ -2,12 +2,10 @@ Test MUC invitations. """ -import dbus - from twisted.words.xish import domish, xpath from gabbletest import exec_test, make_muc_presence -from servicetest import call_async, EventPattern +from servicetest import call_async, EventPattern, wrap_channel, assertEquals import constants as cs def test(q, bus, conn, stream): @@ -23,34 +21,32 @@ def test(q, bus, conn, stream): stream.send(message) - event = q.expect('dbus-signal', signal='NewChannel') - assert event.args[1] == cs.CHANNEL_TYPE_TEXT - - assert event.args[2] == 2 # handle type - assert event.args[3] == 1 # handle - room_handle = 1 + event = q.expect('dbus-signal', signal='NewChannels') + path, props = event.args[0][0] + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_ROOM, props[cs.TARGET_HANDLE_TYPE]) + assertEquals(1, props[cs.TARGET_HANDLE]) - text_chan = bus.get_object(conn.bus_name, event.args[0]) - group_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_GROUP) + text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') - members = group_iface.GetMembers() - local_pending = group_iface.GetLocalPendingMembers() - remote_pending = group_iface.GetRemotePendingMembers() + members = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'Members') + local_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'LocalPendingMembers') + remote_pending = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'RemotePendingMembers') assert len(members) == 1 - assert conn.InspectHandles(1, members)[0] == 'bob@localhost' + assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' bob_handle = members[0] assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption - assert conn.InspectHandles(1, local_pending)[0] == \ + assert conn.inspect_contact_sync(local_pending[0][0]) == \ 'chat@conf.localhost/test' assert len(remote_pending) == 0 - room_self_handle = group_iface.GetSelfHandle() - assert room_self_handle == local_pending[0] + room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, + "SelfHandle") + assert room_self_handle == local_pending[0][0] - channel_props = text_chan.GetAll( - cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) + channel_props = text_chan.Properties.GetAll(cs.CHANNEL) assert channel_props['TargetID'] == 'chat@conf.localhost', channel_props assert channel_props['Requested'] == False assert channel_props['InitiatorID'] == 'bob@localhost' @@ -62,11 +58,11 @@ def test(q, bus, conn, stream): conn.SimplePresence.SetPresence('available', 'success') # accept the invitation - call_async(q, group_iface, 'AddMembers', [room_self_handle], 'Oh, OK then') + call_async(q, text_chan.Group, 'AddMembers', [room_self_handle], 'Oh, OK then') event, event2, _ = q.expect_many( EventPattern('stream-presence', to='chat@conf.localhost/test'), - EventPattern('dbus-signal', signal='MembersChanged'), + EventPattern('dbus-signal', signal='MembersChangedDetailed'), EventPattern('dbus-return', method='AddMembers') ) @@ -81,8 +77,12 @@ def test(q, bus, conn, stream): # We are added as remote pending while joining the room. The inviter (Bob) # is removed for now. It will be re-added with his channel specific handle # once we have joined. - assert event2.args == ['', [], [bob_handle], [], - [room_self_handle], 0, cs.GC_REASON_INVITED] + added, removed, local_pending, remote_pending, details = event2.args + assertEquals([], added) + assertEquals([bob_handle], removed) + assertEquals([], local_pending) + assertEquals([room_self_handle], remote_pending) + assertEquals(cs.GC_REASON_INVITED, details['change-reason']) # Send presence for Bob's membership of room. stream.send(make_muc_presence('owner', 'moderator', 'chat@conf.localhost', 'bob')) @@ -90,14 +90,19 @@ def test(q, bus, conn, stream): # Send presence for own membership of room. stream.send(make_muc_presence('owner', 'moderator', 'chat@conf.localhost', 'test')) - event = q.expect('dbus-signal', signal='MembersChanged') + event = q.expect('dbus-signal', signal='MembersChangedDetailed') + + room_bob_handle = conn.get_contact_handle_sync('chat@conf.localhost/bob') - room_bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat@conf.localhost/bob'])[0] - assert event.args == ['', [room_self_handle, room_bob_handle], [], [], [], 0, 0] + added, removed, local_pending, remote_pending, details = event.args + assertEquals([room_self_handle, room_bob_handle], added) + assertEquals([], removed) + assertEquals([], local_pending) + assertEquals([], remote_pending) # Test sending an invitation - alice_handle = conn.RequestHandles(1, ['alice@localhost'])[0] - call_async(q, group_iface, 'AddMembers', [alice_handle], + alice_handle = conn.get_contact_handle_sync('alice@localhost') + call_async(q, text_chan.Group, 'AddMembers', [alice_handle], 'I want to test invitations') event = q.expect('stream-message', to='chat@conf.localhost') diff --git a/tests/twisted/muc/test-muc-ownership.py b/tests/twisted/muc/test-muc-ownership.py index f0f2d504f..9ac2c84cd 100644 --- a/tests/twisted/muc/test-muc-ownership.py +++ b/tests/twisted/muc/test-muc-ownership.py @@ -1,15 +1,13 @@ """ Test support for the HANDLE_OWNERS_NOT_AVAILABLE group flag, and calling -GetHandleOwners on MUC members. +HandleOwners on MUC members. By default, MUC channels should have the flag set. The flag should be unset when presence is received that includes the MUC JID's owner JID. """ -import dbus - -from gabbletest import make_result_iq, exec_test, make_muc_presence +from gabbletest import exec_test, make_muc_presence from servicetest import ( call_async, EventPattern, assertEquals, assertFlagsSet, assertFlagsUnset, wrap_channel, @@ -17,18 +15,20 @@ from servicetest import ( import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() - room_handle = conn.RequestHandles(cs.HT_ROOM, ['chat@conf.localhost'])[0] + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") - 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_ID: 'chat@conf.localhost' + }) gfc, _, _, _ = q.expect_many( # Initial group flags EventPattern('dbus-signal', signal='GroupFlagsChanged', predicate=lambda e: e.args[0] != 0), - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [], [2], 0, 0]), + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: e.args[3] == [2]), # Removing CAN_ADD EventPattern('dbus-signal', signal='GroupFlagsChanged', args = [0, cs.GF_CAN_ADD], predicate=lambda e: e.args[0] == 0), @@ -60,11 +60,11 @@ def test(q, bus, conn, stream): event = q.expect('dbus-signal', signal='HandleOwnersChanged') owners = event.args[0] - event = q.expect('dbus-signal', signal='MembersChanged') - added = event.args[1] + event = q.expect('dbus-signal', signal='MembersChangedDetailed') + added = event.args[0] [test, bob, brian, che, che_owner, chris, chris_owner] = \ - conn.RequestHandles(cs.HT_CONTACT, + conn.get_contact_handles_sync( [ 'chat@conf.localhost/test', 'chat@conf.localhost/bob', 'chat@conf.localhost/brian', 'chat@conf.localhost/che', 'che@foo.com', 'chat@conf.localhost/chris', 'chris@foo.com', @@ -79,13 +79,14 @@ def test(q, bus, conn, stream): assertEquals(expected_members, sorted(added)) assertEquals(expected_owners, owners) - event = q.expect('dbus-return', method='RequestChannel') + event = q.expect('dbus-return', method='CreateChannel') chan = wrap_channel(bus.get_object(conn.bus_name, event.value[0]), 'Text') - # Exercise GetHandleOwners - assertEquals([che_owner, chris_owner], - chan.Group.GetHandleOwners([che, chris])) + # Exercise HandleOwners + owners = chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'HandleOwners') + assertEquals(che_owner, owners[che]) + assertEquals(chris_owner, owners[chris]) # Exercise D-Bus properties all = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) @@ -97,7 +98,7 @@ def test(q, bus, conn, stream): assert all[u'HandleOwners'] == expected_owners, all flags = all[u'GroupFlags'] - assertFlagsSet(cs.GF_PROPERTIES | cs.GF_CHANNEL_SPECIFIC_HANDLES, flags) + assertFlagsSet(cs.GF_CHANNEL_SPECIFIC_HANDLES, flags) assertFlagsUnset(cs.GF_HANDLE_OWNERS_NOT_AVAILABLE, flags) if __name__ == '__main__': diff --git a/tests/twisted/muc/test-muc.py b/tests/twisted/muc/test-muc.py index a254d8ee8..8daedb251 100644 --- a/tests/twisted/muc/test-muc.py +++ b/tests/twisted/muc/test-muc.py @@ -19,26 +19,24 @@ from mucutil import join_muc_and_check def test(q, bus, conn, stream): room = 'chat@conf.localhost' - room_handle, chan, test_handle, bob_handle = \ + chan, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, room) # Exercise basic Channel Properties from spec 0.17.7 channel_props = chan.Properties.GetAll(cs.CHANNEL) - assertEquals(room_handle, channel_props.get('TargetHandle')) assertEquals(cs.HT_ROOM, channel_props.get('TargetHandleType')) assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType')) interfaces = channel_props.get('Interfaces') assertContains(cs.CHANNEL_IFACE_GROUP, interfaces) assertContains(cs.CHANNEL_IFACE_PASSWORD, interfaces) - assertDoesNotContain(cs.TP_AWKWARD_PROPERTIES, interfaces) assertContains(cs.CHANNEL_IFACE_CHAT_STATE, interfaces) assertContains(cs.CHANNEL_IFACE_MESSAGES, 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() + assert channel_props['InitiatorHandle'] == conn.Properties.Get(cs.CONN, "SelfHandle") # Exercise Group Properties from spec 0.17.6 (in a basic way) group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) @@ -56,20 +54,7 @@ def test(q, bus, conn, stream): body = message.addElement('body', content='hello') stream.send(message) - received, message_received = q.expect_many( - EventPattern('dbus-signal', signal='Received'), - EventPattern('dbus-signal', signal='MessageReceived'), - ) - - # Check Channel.Type.Text.Received: - # sender: bob - assert received.args[2] == bob_handle - # message type: normal - assert received.args[3] == 0 - # flags: none - assert received.args[4] == 0 - # body - assert received.args[5] == 'hello' + message_received = q.expect('dbus-signal', signal='MessageReceived') # Check Channel.Interface.Messages.MessageReceived: message = message_received.args[0] @@ -117,9 +102,8 @@ def test(q, bus, conn, stream): assert sent_token - stream_message, sent, message_sent = q.expect_many( + stream_message, message_sent = q.expect_many( EventPattern('stream-message'), - EventPattern('dbus-signal', signal='Sent'), EventPattern('dbus-signal', signal='MessageSent'), ) @@ -138,9 +122,6 @@ def test(q, bus, conn, stream): assertEquals(cs.MSG_SENDING_FLAGS_REPORT_DELIVERY, flags) assertEquals(sent_token, token) - assert sent.args[1] == 1, sent.args # Action - assert sent.args[2] == u'peers through a gap in the curtains', sent.args - assert message_sent.args[2] == sent_token elem = stream_message.stanza @@ -161,10 +142,7 @@ def test(q, bus, conn, stream): stream.send(elem) # Check that we got the corresponding delivery report - report, old_received = q.expect_many( - EventPattern('dbus-signal', signal='MessageReceived'), - EventPattern('dbus-signal', signal='Received'), - ) + report = q.expect('dbus-signal', signal='MessageReceived') assert len(report.args) == 1, report.args parts = report.args[0] @@ -191,27 +169,17 @@ def test(q, bus, conn, stream): assert key in echo[i], (i, key, echo) assert echo[i][key] == greeting[i][key], (i, key, echo, greeting) - # The Text.Received signal should be a "you're not tall enough" stub - id, timestamp, sender, type, flags, text = old_received.args - assert sender == 0, old_received.args - assert type == 4, old_received.args # Message_Type_Delivery_Report - assert flags == 2, old_received.args # Non_Text_Content - assert text == '', old_received.args - - # Send a normal message using the Channel.Type.Text API - chan.Text.Send(0, 'goodbye') + chan.send_msg_sync('goodbye') - event, sent, message_sent = q.expect_many( + event, message_sent = q.expect_many( EventPattern('stream-message'), - EventPattern('dbus-signal', signal='Sent'), EventPattern('dbus-signal', signal='MessageSent'), ) sent_message, flags, _ = message_sent.args assert len(sent_message) == 2, sent_message header = sent_message[0] - assert 'message-type' not in header, header # Normal body = sent_message[1] assert body['content-type'] == 'text/plain', body assert body['content'] == u'goodbye', body @@ -221,9 +189,6 @@ def test(q, bus, conn, stream): # Gabble's within its rights to pretend that the caller asked. assert flags in [0, cs.MSG_SENDING_FLAGS_REPORT_DELIVERY], flags - assert sent.args[1] == 0, sent.args # Normal - assert sent.args[2] == u'goodbye', sent.args - sent_token = message_sent.args[2] elem = event.stanza @@ -265,7 +230,8 @@ def test(q, bus, conn, stream): assert x_muc_nodes is None, elem.toXml() # test that leaving the channel results in an unavailable message - chan.Group.RemoveMembers([chan.Group.GetSelfHandle()], 'booo') + chan.Group.RemoveMembers([chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, + "SelfHandle")], 'booo') event = q.expect('stream-presence', to='chat@conf.localhost/test') elem = event.stanza diff --git a/tests/twisted/mucutil.py b/tests/twisted/mucutil.py index 103b68b79..8bb830b9e 100644 --- a/tests/twisted/mucutil.py +++ b/tests/twisted/mucutil.py @@ -5,10 +5,10 @@ Utility functions for tests that need to interact with MUCs. import dbus -from twisted.words.xish import domish, xpath +from twisted.words.xish import xpath from servicetest import call_async, wrap_channel, EventPattern, assertLength -from gabbletest import make_muc_presence, request_muc_handle +from gabbletest import make_muc_presence import constants as cs import ns @@ -56,11 +56,10 @@ def try_to_join_muc(q, bus, conn, stream, muc, request=None): def join_muc(q, bus, conn, stream, muc, request=None, also_capture=[], role='participant', affiliation='none'): """ - Joins 'muc', returning the muc's handle, a proxy object for the channel, + Joins 'muc', returning a proxy object for the channel, its path and its immutable properties just after the CreateChannel event has fired. The room contains one other member. """ - muc_handle = request_muc_handle(q, conn, stream, muc) try_to_join_muc(q, bus, conn, stream, muc, request=request) # Send presence for other member of room. @@ -74,23 +73,22 @@ 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', 'ChatState']) + ['Subject.DRAFT']) - return (muc_handle, chan, path, props) + tuple(captured[1:]) + + return (chan, path, props) + tuple(captured[1:]) def join_muc_and_check(q, bus, conn, stream, muc, request=None): """ Like join_muc(), but also checks the NewChannels and NewChannel signals and the Members property, and returns both members' handles. """ - muc_handle, chan, path, props = \ + chan, path, props = \ join_muc(q, bus, conn, stream, muc, request=request) q.expect('dbus-signal', signal='NewChannels', args=[[(path, props)]]) - q.expect('dbus-signal', signal='NewChannel', - args=[path, cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, muc_handle, True]) - test_handle, bob_handle = conn.RequestHandles(cs.HT_CONTACT, + test_handle, bob_handle = conn.get_contact_handles_sync( ['%s/test' % muc, '%s/bob' % muc]) members = chan.Get(cs.CHANNEL_IFACE_GROUP, 'Members', @@ -98,4 +96,4 @@ def join_muc_and_check(q, bus, conn, stream, muc, request=None): assert set(members) == set([test_handle, bob_handle]), \ (members, (test_handle, bob_handle)) - return (muc_handle, chan, test_handle, bob_handle) + return (chan, test_handle, bob_handle) diff --git a/tests/twisted/olpc/change-notifications.py b/tests/twisted/olpc/change-notifications.py index 648ef5df7..3b637dffa 100644 --- a/tests/twisted/olpc/change-notifications.py +++ b/tests/twisted/olpc/change-notifications.py @@ -19,7 +19,7 @@ def test(q, bus, conn, stream): handles = {} - handles['alice'] = conn.RequestHandles(1, ['alice@localhost'])[0] + handles['alice'] = conn.get_contact_handle_sync('alice@localhost') # Alice, one our friends changed her properties send_buddy_changed_properties_msg(stream, 'alice@localhost', diff --git a/tests/twisted/olpc/current-activity.py b/tests/twisted/olpc/current-activity.py index 0906f4a1e..382110217 100644 --- a/tests/twisted/olpc/current-activity.py +++ b/tests/twisted/olpc/current-activity.py @@ -24,7 +24,7 @@ def test(q, bus, conn, stream): handles = {} # Alice is one of our friend so we receive her PEP notifications - handles['alice'] = conn.RequestHandles(1, ['alice@localhost'])[0] + handles['alice'] = conn.get_contact_handle_sync('alice@localhost') # Try to get Alice's currrent-activity call_async(q, buddy_info_iface, "GetCurrentActivity", handles['alice']) diff --git a/tests/twisted/olpc/olpc-muc-invitation.py b/tests/twisted/olpc/olpc-muc-invitation.py index 2c9ee92c3..8307e2972 100644 --- a/tests/twisted/olpc/olpc-muc-invitation.py +++ b/tests/twisted/olpc/olpc-muc-invitation.py @@ -7,13 +7,13 @@ import dbus from twisted.words.xish import domish, xpath from gabbletest import exec_test, make_muc_presence -from servicetest import call_async, EventPattern +from servicetest import call_async, EventPattern, wrap_channel import constants as cs import ns def test(q, bus, conn, stream): handles = {} - handles['bob'] = conn.RequestHandles(1, ['bob@localhost'])[0] + handles['bob'] = conn.get_contact_handle_sync('bob@localhost') buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') @@ -79,22 +79,24 @@ def test(q, bus, conn, stream): assert event.args[2] == 2 # handle type assert event.args[3] == handles['chat'] # handle - text_chan = bus.get_object(conn.bus_name, event.args[0]) - group_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_GROUP) + text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]), + 'Text') + group_iface = text_chan.Group members = group_iface.GetAllMembers()[0] local_pending = group_iface.GetAllMembers()[1] remote_pending = group_iface.GetAllMembers()[2] assert len(members) == 1 - assert conn.InspectHandles(1, members)[0] == 'bob@localhost' + assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption - assert conn.InspectHandles(1, local_pending)[0] == \ + assert conn.inspect_contact_sync(local_pending[0]) == \ 'chat@conf.localhost/test' assert len(remote_pending) == 0 - handles['chat_self'] = group_iface.GetSelfHandle() + handles['chat_self'] = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, + "SelfHandle") assert handles['chat_self'] == local_pending[0] # by now, we should have picked up the extra activity properties @@ -148,8 +150,7 @@ def test(q, bus, conn, stream): q.expect('dbus-return', method='SetProperties') # Test sending an invitation - handles['alice'] = conn.RequestHandles(1, - ['alice@localhost'])[0] + handles['alice'] = conn.get_contact_handle_sync('alice@localhost') call_async(q, group_iface, 'AddMembers', [handles['alice']], 'I want to test invitations') diff --git a/tests/twisted/olpc/olpc-muc-prop-change.py b/tests/twisted/olpc/olpc-muc-prop-change.py index 8a20303a2..d18788ccd 100644 --- a/tests/twisted/olpc/olpc-muc-prop-change.py +++ b/tests/twisted/olpc/olpc-muc-prop-change.py @@ -7,7 +7,7 @@ import dbus from twisted.words.xish import domish, xpath from gabbletest import exec_test, acknowledge_iq, make_muc_presence -from servicetest import call_async, EventPattern +from servicetest import call_async, EventPattern, wrap_channel import constants as cs import ns @@ -21,7 +21,7 @@ def test(q, bus, conn, stream): buddy_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo') act_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.ActivityProperties') - bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] + bob_handle = conn.get_contact_handle_sync('bob@localhost') # Bob invites us to a chatroom, pre-seeding properties message = domish.Element(('jabber:client', 'message')) @@ -61,24 +61,25 @@ def test(q, bus, conn, stream): assert event.args[3] == 1 # handle room_handle = 1 - text_chan = bus.get_object(conn.bus_name, event.args[0]) - chan_iface = dbus.Interface(text_chan, cs.CHANNEL) - group_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_GROUP) + text_chan = wrap_channel(bus.get_object(conn.bus_name, event.args[0]), + 'Text') + group_iface = text_chan.Group members = group_iface.GetAllMembers()[0] local_pending = group_iface.GetAllMembers()[1] remote_pending = group_iface.GetAllMembers()[2] assert len(members) == 1 - assert conn.InspectHandles(1, members)[0] == 'bob@localhost' + assert conn.inspect_contact_sync(members[0]) == 'bob@localhost' bob_handle = members[0] assert len(local_pending) == 1 # FIXME: the username-part-is-nickname assumption - assert conn.InspectHandles(1, local_pending)[0] == \ + assert conn.inspect_contact_sync(local_pending[0]) == \ 'chat@conf.localhost/test' assert len(remote_pending) == 0 - room_self_handle = group_iface.GetSelfHandle() + room_self_handle = text_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, + "SelfHandle") assert room_self_handle == local_pending[0] # by now, we should have picked up the extra activity properties @@ -359,7 +360,7 @@ def test(q, bus, conn, stream): q.expect('dbus-return', method='SetProperties') - chan_iface.Close() + text_chan.Close() # we must echo the MUC presence so the room will actually close event = q.expect('stream-presence', to='chat@conf.localhost/test', diff --git a/tests/twisted/pep-support.py b/tests/twisted/pep-support.py index 10e5c94e8..257ea55fb 100644 --- a/tests/twisted/pep-support.py +++ b/tests/twisted/pep-support.py @@ -1,7 +1,4 @@ -import dbus - -from gabbletest import exec_test, GoogleXmlStream, acknowledge_iq, BaseXmlStream,\ - sync_stream +from gabbletest import exec_test, GoogleXmlStream, acknowledge_iq, BaseXmlStream from servicetest import call_async, EventPattern from twisted.words.protocols.jabber.client import IQ diff --git a/tests/twisted/plugin-channel-managers.py b/tests/twisted/plugin-channel-managers.py index 320dd7ac7..03668d733 100644 --- a/tests/twisted/plugin-channel-managers.py +++ b/tests/twisted/plugin-channel-managers.py @@ -2,14 +2,12 @@ Test Gabble's implementation of channel managers from plugins. """ -from servicetest import ( - sync_dbus, call_async, EventPattern, assertEquals, assertContains, - ) -from gabbletest import exec_test, send_error_reply, acknowledge_iq, sync_stream +from servicetest import assertContains +from gabbletest import exec_test import constants as cs from config import PLUGINS_ENABLED -TEST_PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Test" +TEST_PLUGIN_IFACE = cs.PREFIX + ".Gabble.Plugin.Test" if not PLUGINS_ENABLED: print "NOTE: built without --enable-plugins, not testing plugins" diff --git a/tests/twisted/power-save.py b/tests/twisted/power-save.py index 862c709c9..28861d5d5 100644 --- a/tests/twisted/power-save.py +++ b/tests/twisted/power-save.py @@ -2,21 +2,15 @@ Test entering and leaving power saving mode. """ -import config - import constants as cs from gabbletest import exec_test, GoogleXmlStream, make_result_iq, \ send_error_reply, disconnect_conn, make_presence, sync_stream, elem, \ acknowledge_iq -from servicetest import call_async, Event, assertEquals, EventPattern, \ - assertContains, assertDoesNotContain, sync_dbus +from servicetest import call_async, assertEquals, EventPattern, \ + assertContains, sync_dbus import ns -import dbus -import dbus.service - -from twisted.internet import reactor from twisted.words.xish import domish def expect_command(q, name): @@ -123,7 +117,7 @@ def test_local_queueing(q, bus, conn, stream): event = q.expect('dbus-signal', signal='AliasesChanged') # .. and finally the message that flushed the stanza queue - q.expect('dbus-signal', signal='NewChannel') + q.expect('dbus-signal', signal='NewChannels') sync_stream(q, stream) diff --git a/tests/twisted/presence/decloak.py b/tests/twisted/presence/decloak.py index 235116c25..541762d20 100644 --- a/tests/twisted/presence/decloak.py +++ b/tests/twisted/presence/decloak.py @@ -21,7 +21,7 @@ def test(q, bus, conn, stream, should_decloak=False): worker(q, bus, conn, stream, should_decloak) # Trivial test for SendDirectedPresence() - bob_handle = conn.RequestHandles(1, ['bob@foo.com'])[0] + bob_handle = conn.get_contact_handle_sync('bob@foo.com') conn.SendDirectedPresence(bob_handle, False, dbus_interface=cs.CONN_IFACE_GABBLE_DECLOAK) q.expect('stream-presence', to='bob@foo.com') @@ -31,7 +31,7 @@ def worker(q, bus, conn, stream, should_decloak): 'DecloakAutomatically', dbus_interface=cs.PROPERTIES_IFACE) assertEquals(should_decloak, decloak_automatically) - amy_handle = conn.RequestHandles(1, ['amy@foo.com'])[0] + amy_handle = conn.get_contact_handle_sync('amy@foo.com') # Amy directs presence to us diff --git a/tests/twisted/presence/error.py b/tests/twisted/presence/error.py index 53f3703bc..33339e65a 100644 --- a/tests/twisted/presence/error.py +++ b/tests/twisted/presence/error.py @@ -13,7 +13,7 @@ def test(q, bus, conn, stream): 'thehawk@unreachable.example.net', ] gregory, hawk = jids - gregory_handle, hawk_handle = conn.RequestHandles(cs.HT_CONTACT, jids) + gregory_handle, hawk_handle = conn.get_contact_handles_sync(jids) event = q.expect('stream-iq', query_ns=ns.ROSTER) event.stanza['type'] = 'result' diff --git a/tests/twisted/presence/initial-contact-presence.py b/tests/twisted/presence/initial-contact-presence.py index 881316c73..c76309f17 100644 --- a/tests/twisted/presence/initial-contact-presence.py +++ b/tests/twisted/presence/initial-contact-presence.py @@ -10,6 +10,7 @@ This serves as a regression test for from gabbletest import exec_test, make_presence, sync_stream, elem from servicetest import assertEquals, EventPattern, sync_dbus +from presence_helper import get_contacts_presences_sync import constants as cs import ns @@ -29,16 +30,17 @@ def make_roster_item(jid, subscription): def test(q, bus, conn, stream): event = q.expect('stream-iq', query_ns=ns.ROSTER) - amy, bob, che, dre, eve = conn.RequestHandles(cs.HT_CONTACT, + amy, bob, che, dre, eve = conn.get_contact_handles_sync( ['amy@foo.com', 'bob@foo.com', 'che@foo.com', 'dre@foo.com', 'eve@foo.com']) + assertEquals({amy: UNKNOWN, bob: UNKNOWN, che: UNKNOWN, dre: UNKNOWN, eve: UNKNOWN, }, - conn.SimplePresence.GetPresences([amy, bob, che, dre, eve])) + get_contacts_presences_sync(conn, [amy, bob, che, dre, eve])) # Before the server sends Gabble the roster, it relays an 'unavailable' # presence for one of the contacts we're subscribed to. This seems to @@ -94,7 +96,7 @@ def test(q, bus, conn, stream): dre: OFFLINE, eve: AVAILABLE, }, - conn.SimplePresence.GetPresences([amy, bob, che, dre, eve])) + get_contacts_presences_sync(conn, [amy, bob, che, dre, eve])) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/presence/presence.py b/tests/twisted/presence/presence.py index 49974691b..8d35e284a 100644 --- a/tests/twisted/presence/presence.py +++ b/tests/twisted/presence/presence.py @@ -1,20 +1,18 @@ """ A simple smoke-test for C.I.SimplePresence - -FIXME: test C.I.Presence too """ from twisted.words.xish import domish from gabbletest import exec_test, make_presence -from servicetest import EventPattern +from servicetest import EventPattern, assertEquals import ns import constants as cs def test(q, bus, conn, stream): event = q.expect('stream-iq', query_ns=ns.ROSTER) - amy_handle = conn.RequestHandles(1, ['amy@foo.com'])[0] + amy_handle = conn.get_contact_handle_sync('amy@foo.com') event.stanza['type'] = 'result' @@ -31,9 +29,18 @@ def test(q, bus, conn, stream): stream.send(make_presence( 'amy@foo.com', show='chat', status='I may have been drinking')) - q.expect('dbus-signal', signal='PresencesChanged', + e = q.expect('dbus-signal', signal='PresencesChanged', args=[{amy_handle: (cs.PRESENCE_AVAILABLE, 'chat', 'I may have been drinking')}]) + amy_handle, asv = conn.Contacts.GetContactByID('amy@foo.com', + [cs.CONN_IFACE_SIMPLE_PRESENCE]) + assertEquals(e.args[0][amy_handle], asv.get(cs.ATTR_PRESENCE)) + + bob_handle, asv = conn.Contacts.GetContactByID('bob@foo.com', + [cs.CONN_IFACE_SIMPLE_PRESENCE]) + assertEquals((cs.PRESENCE_UNKNOWN, 'unknown', ''), + asv.get(cs.ATTR_PRESENCE)) + if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/presence/set-idempotence.py b/tests/twisted/presence/set-idempotence.py index dc11ceb79..02f519ef3 100644 --- a/tests/twisted/presence/set-idempotence.py +++ b/tests/twisted/presence/set-idempotence.py @@ -24,7 +24,7 @@ def run_test(q, bus, conn, stream): assert simple_signal.args == [{1L: (3L, u'away', u'gone')}] assert conn.Contacts.GetContactAttributes([1], [cs.CONN_IFACE_SIMPLE_PRESENCE], False) == { 1L: { cs.CONN_IFACE_SIMPLE_PRESENCE + "/presence": (3L, u'away', u'gone'), - 'org.freedesktop.Telepathy.Connection/contact-id': + cs.ATTR_CONTACT_ID: 'test@localhost'}} children = list(presence.stanza.elements()) @@ -38,7 +38,7 @@ def run_test(q, bus, conn, stream): conn.SimplePresence.SetPresence('away', 'gone') assert conn.Contacts.GetContactAttributes([1], [cs.CONN_IFACE_SIMPLE_PRESENCE], False) == { 1L: { cs.CONN_IFACE_SIMPLE_PRESENCE + "/presence": (3L, u'away', u'gone'), - 'org.freedesktop.Telepathy.Connection/contact-id': + cs.ATTR_CONTACT_ID: 'test@localhost'}} # Set presence a third time. This call is not redundant, and should @@ -55,7 +55,7 @@ def run_test(q, bus, conn, stream): assert str(children[0]) == 'yo' assert conn.Contacts.GetContactAttributes([1], [cs.CONN_IFACE_SIMPLE_PRESENCE], False) == { 1L: { cs.CONN_IFACE_SIMPLE_PRESENCE + "/presence": (2L, u'available', u'yo'), - 'org.freedesktop.Telepathy.Connection/contact-id': + cs.ATTR_CONTACT_ID: 'test@localhost'}} # call SetPresence with an empty message, as this used to cause a @@ -68,7 +68,7 @@ def run_test(q, bus, conn, stream): assert simple_signal.args == [{1L: (2L, u'available', u'')}] assert conn.Contacts.GetContactAttributes([1], [cs.CONN_IFACE_SIMPLE_PRESENCE], False) == { 1L: { cs.CONN_IFACE_SIMPLE_PRESENCE + "/presence": (2L, u'available', u''), - 'org.freedesktop.Telepathy.Connection/contact-id': + cs.ATTR_CONTACT_ID: 'test@localhost'}} if __name__ == '__main__': diff --git a/tests/twisted/presence/shared-status.py b/tests/twisted/presence/shared-status.py index 17945e3e9..b2e02b8cc 100644 --- a/tests/twisted/presence/shared-status.py +++ b/tests/twisted/presence/shared-status.py @@ -17,6 +17,7 @@ import constants as cs import dbus from twisted.words.xish import xpath, domish from invisible_helper import SharedStatusStream +from presence_helper import get_contacts_presences_sync presence_types = {'available' : cs.PRESENCE_AVAILABLE, 'away' : cs.PRESENCE_AWAY, @@ -37,8 +38,8 @@ def _show_to_shared_status_show(show): return shared_show, shared_invisible def _test_remote_status(q, bus, conn, stream, msg, show, list_attrs): - self = conn.GetSelfHandle() - presence = conn.SimplePresence.GetPresences([self])[self] + self = conn.Properties.Get(cs.CONN, "SelfHandle") + presence = get_contacts_presences_sync(conn, [self])[self] is_away = presence[0] in (cs.PRESENCE_AWAY, cs.PRESENCE_EXTENDED_AWAY) if is_away: @@ -78,8 +79,8 @@ def _test_local_status(q, conn, stream, msg, show, expected_show=None): expected_show = expected_show or show away = expected_show in ('away', 'xa') - self = conn.GetSelfHandle() - prev_presence = conn.SimplePresence.GetPresences([self])[self] + self = conn.Properties.Get(cs.CONN, "SelfHandle") + prev_presence = get_contacts_presences_sync(conn, [self])[self] was_away = prev_presence[0] in (cs.PRESENCE_AWAY, cs.PRESENCE_EXTENDED_AWAY) was_invisible = (prev_presence[0] == cs.PRESENCE_HIDDEN) diff --git a/tests/twisted/presence_helper.py b/tests/twisted/presence_helper.py new file mode 100644 index 000000000..768963376 --- /dev/null +++ b/tests/twisted/presence_helper.py @@ -0,0 +1,8 @@ +import constants as cs + +def get_contacts_presences_sync(conn, contacts): + h2asv = conn.Contacts.GetContactAttributes(contacts, [cs.CONN_IFACE_SIMPLE_PRESENCE], False) + presences = {} + for h in contacts: + presences[h] = h2asv[h][cs.ATTR_PRESENCE] + return presences diff --git a/tests/twisted/pubsub.py b/tests/twisted/pubsub.py index 298106d95..16850ab93 100644 --- a/tests/twisted/pubsub.py +++ b/tests/twisted/pubsub.py @@ -1,7 +1,6 @@ """Send malformed pubsub notifications to be sure that Gabble isn't confused about those""" from gabbletest import exec_test, elem, sync_stream -import constants as cs import ns def make_pubsub_event(from_, node, *contents): diff --git a/tests/twisted/roster/authorize.py b/tests/twisted/roster/authorize.py index 8d52435fc..906950ebd 100644 --- a/tests/twisted/roster/authorize.py +++ b/tests/twisted/roster/authorize.py @@ -4,16 +4,15 @@ Test receiving and authorizing publish requests, including "pre-authorization" """ from gabbletest import (exec_test, sync_stream, acknowledge_iq) -from rostertest import (expect_contact_list_signals, - check_contact_list_signals, send_roster_push) -from servicetest import (assertEquals, assertLength, call_async, EventPattern, +from rostertest import send_roster_push +from servicetest import (assertEquals, call_async, EventPattern, sync_dbus) import constants as cs import ns from twisted.words.xish import domish -def test(q, bus, conn, stream, modern=True, remove=False): +def test(q, bus, conn, stream, remove=False): call_async(q, conn.ContactList, 'GetContactListAttributes', [], False) q.expect('dbus-error', method='GetContactListAttributes', @@ -27,20 +26,17 @@ def test(q, bus, conn, stream, modern=True, remove=False): event.stanza['type'] = 'result' stream.send(event.stanza) - holly, dave, arnold, kristine, cat = conn.RequestHandles(cs.HT_CONTACT, + holly, dave, arnold, kristine, cat = conn.get_contact_handles_sync( ['holly@example.com', 'dave@example.com', 'arnold@example.com', 'kristine@example.com', 'cat@example.com']) - # slight implementation detail: TpBaseContactList emits ContactsChanged + # slight implementation detail: TpBaseContactList emits ContactsChangedWithID # before it announces its channels - s = q.expect('dbus-signal', signal='ContactsChanged', + s = q.expect('dbus-signal', signal='ContactsChangedWithID', interface=cs.CONN_IFACE_CONTACT_LIST, path=conn.object_path) assertEquals([{ holly: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), - }, []], s.args) - - pairs = expect_contact_list_signals(q, bus, conn, - ['publish', 'subscribe', 'stored']) + }, { holly: 'holly@example.com' }, {}], s.args) # this is emitted last, so clients can tell when the initial state dump # has finished @@ -59,23 +55,10 @@ def test(q, bus, conn, stream, modern=True, remove=False): } },), r.value) - # check that the channels were as we expected too - publish = check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'publish', ['holly@example.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'subscribe', ['holly@example.com']) - stored = check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'stored', ['holly@example.com']) - assertLength(0, pairs) # i.e. we've checked all of them - # publication authorized for Dave, Holly (the former is pre-authorization, # the latter is a no-op) - if modern: - call_async(q, conn.ContactList, 'AuthorizePublication', [dave, holly]) - event = q.expect('dbus-return', method='AuthorizePublication') - else: - call_async(q, publish.Group, 'AddMembers', [dave, holly], '') - event = q.expect('dbus-return', method='AddMembers') + call_async(q, conn.ContactList, 'AuthorizePublication', [dave, holly]) + event = q.expect('dbus-return', method='AuthorizePublication') # Receive authorization requests from the contacts @@ -86,10 +69,10 @@ def test(q, bus, conn, stream, modern=True, remove=False): stream.send(presence) q.expect_many( - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{dave: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_ASK, - '')}, []]), + '')}, { dave: 'dave@example.com' }, {}]), EventPattern('stream-presence', presence_type='subscribed', to='dave@example.com'), ) @@ -98,34 +81,30 @@ def test(q, bus, conn, stream, modern=True, remove=False): send_roster_push(stream, 'dave@example.com', 'from') q.expect_many( EventPattern('stream-iq', iq_type='result', iq_id='push'), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{dave: (cs.SUBSCRIPTION_STATE_NO, - cs.SUBSCRIPTION_STATE_YES, '')}, []]), + cs.SUBSCRIPTION_STATE_YES, '')}, { dave: 'dave@example.com' }, {}]), ) # The request from Kristine needs authorization (below) presence['from'] = 'kristine@example.com' stream.send(presence) - q.expect('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{kristine: (cs.SUBSCRIPTION_STATE_NO, - cs.SUBSCRIPTION_STATE_ASK, '')}, []]) + cs.SUBSCRIPTION_STATE_ASK, '')}, { kristine: 'kristine@example.com' }, {}]) # This request from Arnold is dealt with below presence['from'] = 'arnold@example.com' stream.send(presence) - q.expect('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{arnold: (cs.SUBSCRIPTION_STATE_NO, - cs.SUBSCRIPTION_STATE_ASK, '')}, []]) + cs.SUBSCRIPTION_STATE_ASK, '')}, { arnold: 'arnold@example.com' }, {}]) - if modern: - returning_method = 'AuthorizePublication' - call_async(q, conn.ContactList, 'AuthorizePublication', - [kristine, holly]) - else: - returning_method = 'AddMembers' - call_async(q, publish.Group, 'AddMembers', [kristine, holly], '') + returning_method = 'AuthorizePublication' + call_async(q, conn.ContactList, 'AuthorizePublication', + [kristine, holly]) q.expect_many( EventPattern('dbus-return', method=returning_method), @@ -137,10 +116,10 @@ def test(q, bus, conn, stream, modern=True, remove=False): # does not change. send_roster_push(stream, 'kristine@example.com', 'from') q.expect_many( - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{kristine: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_YES, - '')}, []]), + '')}, { kristine: 'kristine@example.com' }, {}]), EventPattern('stream-iq', iq_type='result', iq_id='push'), ) @@ -150,9 +129,9 @@ def test(q, bus, conn, stream, modern=True, remove=False): stream.send(presence) q.expect_many( - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{arnold: (cs.SUBSCRIPTION_STATE_NO, - cs.SUBSCRIPTION_STATE_REMOVED_REMOTELY, '')}, []]), + cs.SUBSCRIPTION_STATE_REMOVED_REMOTELY, '')}, { arnold: 'arnold@example.com' }, {}]), EventPattern('stream-presence', presence_type='unsubscribed', to='arnold@example.com'), ) @@ -174,8 +153,8 @@ def test(q, bus, conn, stream, modern=True, remove=False): # in his removal. q.expect_many( EventPattern('dbus-return', method=returning_method), - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [arnold]]), + EventPattern('dbus-signal', signal='ContactsChangedWithID', + args=[{}, {}, {arnold: 'arnold@example.com' }]), ) # Rejecting an authorization request also works @@ -184,32 +163,24 @@ def test(q, bus, conn, stream, modern=True, remove=False): presence['from'] = 'cat@example.com' stream.send(presence) - q.expect('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{cat: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_ASK, - '')}, []]) - - if modern: - if remove: - returning_method = 'RemoveContacts' - call_async(q, conn.ContactList, 'RemoveContacts', [cat]) - else: - returning_method = 'Unpublish' - call_async(q, conn.ContactList, 'Unpublish', [cat]) - else: - returning_method = 'RemoveMembers' + '')}, { cat: 'cat@example.com' }, {}]) - if remove: - call_async(q, stored.Group, 'RemoveMembers', [cat], '') - else: - call_async(q, publish.Group, 'RemoveMembers', [cat], '') + if remove: + returning_method = 'RemoveContacts' + call_async(q, conn.ContactList, 'RemoveContacts', [cat]) + else: + returning_method = 'Unpublish' + call_async(q, conn.ContactList, 'Unpublish', [cat]) # As above, the only reason the Cat is on our contact list is the pending # publish request, so Unpublish really results in removal. q.expect_many( EventPattern('dbus-return', method=returning_method), - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [cat]]), + EventPattern('dbus-signal', signal='ContactsChangedWithID', + args=[{}, {}, { cat: 'cat@example.com' }]), ) # Redundant API calls (removing an absent contact, etc.) cause no network @@ -237,20 +208,12 @@ def test(q, bus, conn, stream, modern=True, remove=False): # There's one more case: revoking the publish permission of someone who is # genuinely on the roster. - if modern: - if remove: - returning_method = 'RemoveContacts' - call_async(q, conn.ContactList, 'RemoveContacts', [holly]) - else: - returning_method = 'Unpublish' - call_async(q, conn.ContactList, 'Unpublish', [holly]) + if remove: + returning_method = 'RemoveContacts' + call_async(q, conn.ContactList, 'RemoveContacts', [holly]) else: - returning_method = 'RemoveMembers' - - if remove: - call_async(q, stored.Group, 'RemoveMembers', [holly], '') - else: - call_async(q, publish.Group, 'RemoveMembers', [holly], '') + returning_method = 'Unpublish' + call_async(q, conn.ContactList, 'Unpublish', [holly]) if remove: iq = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER, @@ -258,16 +221,15 @@ def test(q, bus, conn, stream, modern=True, remove=False): acknowledge_iq(stream, iq.stanza) - if modern: - q.expect('dbus-return', method='RemoveContacts') + q.expect('dbus-return', method='RemoveContacts') # FIXME: when we depend on a new enough tp-glib, expect RemoveMembers # to return here too send_roster_push(stream, 'holly@example.com', 'remove') q.expect_many( EventPattern('stream-iq', iq_type='result', iq_id='push'), - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [holly]]), + EventPattern('dbus-signal', signal='ContactsChangedWithID', + args=[{}, {}, { holly: 'holly@example.com' }]), ) else: q.expect_many( @@ -279,26 +241,18 @@ def test(q, bus, conn, stream, modern=True, remove=False): send_roster_push(stream, 'holly@example.com', 'to') q.expect_many( EventPattern('stream-iq', iq_type='result', iq_id='push'), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{holly: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), + }, { holly: 'holly@example.com' }, {}]), ) -def test_ancient(q, bus, conn, stream): - test(q, bus, conn, stream, modern=False) - -def test_ancient_remove(q, bus, conn, stream): - test(q, bus, conn, stream, modern=False, remove=True) - def test_modern(q, bus, conn, stream): - test(q, bus, conn, stream, modern=True) + test(q, bus, conn, stream) def test_modern_remove(q, bus, conn, stream): - test(q, bus, conn, stream, modern=True, remove=True) + test(q, bus, conn, stream, remove=True) if __name__ == '__main__': - exec_test(test_ancient) - exec_test(test_ancient_remove) exec_test(test_modern) exec_test(test_modern_remove) diff --git a/tests/twisted/roster/edit-before-roster.py b/tests/twisted/roster/edit-before-roster.py index cc0da227c..44dd72f1d 100644 --- a/tests/twisted/roster/edit-before-roster.py +++ b/tests/twisted/roster/edit-before-roster.py @@ -30,7 +30,7 @@ def test(q, bus, conn, stream): item.addElement('group', content='men') # Before we get the roster, try to change something. It won't work. - amy, bob, che = conn.RequestHandles(cs.HT_CONTACT, + amy, bob, che = conn.get_contact_handles_sync( ['amy@foo.com', 'bob@foo.com', 'che@foo.com']) call_async(q, conn.ContactGroups, 'AddToGroup', 'Amy & Bob', [amy, bob]) diff --git a/tests/twisted/roster/ensure.py b/tests/twisted/roster/ensure.py deleted file mode 100644 index 514991eca..000000000 --- a/tests/twisted/roster/ensure.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Test ensuring roster channels -""" - -from gabbletest import exec_test -from servicetest import call_async -import constants as cs -import ns - -def test(q, bus, conn, stream): - roster_event = q.expect('stream-iq', query_ns=ns.ROSTER) - roster_event.stanza['type'] = 'result' - - call_async(q, conn, "RequestHandles", cs.HT_GROUP, ['test']) - - event = q.expect('dbus-return', method='RequestHandles') - test_handle = event.value[0][0] - - # send an empty roster - stream.send(roster_event.stanza) - - call_async(q, conn.Requests, 'EnsureChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CONTACT_LIST, - cs.TARGET_HANDLE_TYPE: cs.HT_GROUP, - cs.TARGET_HANDLE: test_handle, - }) - call_async(q, conn.Requests, 'EnsureChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CONTACT_LIST, - cs.TARGET_HANDLE_TYPE: cs.HT_GROUP, - cs.TARGET_HANDLE: test_handle, - }) - - ret = q.expect('dbus-return', method='EnsureChannel') - ret2 = q.expect('dbus-return', method='EnsureChannel') - - # We don't test the NewChannels signal here - depending on exact timing, - # it might happen between the two EnsureChannel calls, or after the second - # one. - - yours, path, props = ret.value - yours2, path2, props2 = ret2.value - - assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CONTACT_LIST, props - assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_GROUP, props - assert props[cs.TARGET_HANDLE] == test_handle, props - assert props[cs.TARGET_ID] == 'test', props - - assert yours != yours2, (yours, yours2) - assert path == path2, (path, path2) - assert props == props2, (props, props2) - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/roster/groups-12791.py b/tests/twisted/roster/groups-12791.py index 5f80b057b..0bfaf9401 100644 --- a/tests/twisted/roster/groups-12791.py +++ b/tests/twisted/roster/groups-12791.py @@ -2,26 +2,12 @@ Test broken groups on the roster (regression test for fd.o #12791) """ -import dbus - from gabbletest import exec_test -from rostertest import expect_contact_list_signals, check_contact_list_signals -from servicetest import assertLength +from servicetest import assertLength, assertSameSets, EventPattern +from rostertest import check_contact_roster, contacts_changed_predicate, groups_created_predicate import constants as cs import ns -def _expect_group_channel(q, bus, conn, name, contacts): - event = q.expect('dbus-signal', signal='NewChannel') - path, type, handle_type, handle, suppress_handler = event.args - assert type == cs.CHANNEL_TYPE_CONTACT_LIST, type - assert handle_type == cs.HT_GROUP, handle_type - inspected = conn.InspectHandles(handle_type, [handle])[0] - assert inspected == name, (inspected, name) - chan = bus.get_object(conn.bus_name, path) - group_iface = dbus.Interface(chan, cs.CHANNEL_IFACE_GROUP) - inspected = conn.InspectHandles(cs.HT_CONTACT, group_iface.GetMembers()) - assert inspected == contacts, (inspected, contacts) - def test(q, bus, conn, stream): event = q.expect('stream-iq', query_ns=ns.ROSTER) event.stanza['type'] = 'result' @@ -61,24 +47,28 @@ def test(q, bus, conn, stream): stream.send(event.stanza) - pairs = expect_contact_list_signals(q, bus, conn, - ['publish', 'subscribe', 'stored'], - ['men', 'women', 'affected-by-fdo-12791']) + contacts = [ + ('amy@foo.com', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), + ('bob@foo.com', cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_YES, ''), + ('che@foo.com', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO, ''), + ] + + q.expect_many( + EventPattern('dbus-signal', signal='ContactsChangedWithID', + predicate=lambda e: contacts_changed_predicate(e, conn, contacts)), + EventPattern('dbus-signal', signal='GroupsCreated', + predicate=lambda e: groups_created_predicate(e, ['women', 'men', 'affected-by-fdo-12791'])), + ) + + contacts = conn.ContactList.GetContactListAttributes([cs.CONN_IFACE_CONTACT_GROUPS], False) + assertLength(3, contacts) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'publish', ['amy@foo.com', 'bob@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'subscribe', ['amy@foo.com', 'che@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'stored', ['amy@foo.com', 'bob@foo.com', 'che@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP, - 'men', ['bob@foo.com', 'che@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP, - 'women', ['amy@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP, - 'affected-by-fdo-12791', []) + check_contact_roster(conn, 'amy@foo.com', ['women']) + check_contact_roster(conn, 'bob@foo.com', ['men']) + check_contact_roster(conn, 'che@foo.com', ['men']) - assertLength(0, pairs) # i.e. we've checked all of them + groups = conn.Properties.Get(cs.CONN_IFACE_CONTACT_GROUPS, 'Groups') + assertSameSets(['men', 'women', 'affected-by-fdo-12791'], groups) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/roster/groups.py b/tests/twisted/roster/groups.py index a0ba99bc8..3225151a6 100644 --- a/tests/twisted/roster/groups.py +++ b/tests/twisted/roster/groups.py @@ -3,9 +3,10 @@ Test basic roster group functionality. """ from gabbletest import exec_test, acknowledge_iq, sync_stream -from rostertest import expect_contact_list_signals, check_contact_list_signals -from servicetest import (assertLength, EventPattern, assertEquals, call_async, +from servicetest import (EventPattern, assertEquals, call_async, sync_dbus, assertContains, assertDoesNotContain) +from rostertest import (groups_changed_predicate, groups_created_predicate, + check_contact_roster) import constants as cs import ns @@ -64,35 +65,27 @@ def test(q, bus, conn, stream): # of their groups. On a typical contact list, there are more contacts # than groups, so that'll work out smaller. - pairs, groups_changed = expect_contact_list_signals(q, bus, conn, [], - ['men', 'women'], - [ - EventPattern('dbus-signal', signal='GroupsChanged', - interface=cs.CONN_IFACE_CONTACT_GROUPS, - path=conn.object_path, - predicate=lambda e: 'women' in e.args[1]), - EventPattern('dbus-signal', signal='GroupsChanged', - interface=cs.CONN_IFACE_CONTACT_GROUPS, - path=conn.object_path, - predicate=lambda e: 'men' in e.args[1]), - ]) - - amy, bob, che = conn.RequestHandles(cs.HT_CONTACT, + q.expect_many( + EventPattern('dbus-signal', signal='GroupsCreated', + interface=cs.CONN_IFACE_CONTACT_GROUPS, + path=conn.object_path, + predicate=lambda e: groups_created_predicate(e, ['men', 'women'])), + EventPattern('dbus-signal', signal='GroupsChanged', + interface=cs.CONN_IFACE_CONTACT_GROUPS, + path=conn.object_path, + predicate=lambda e: groups_changed_predicate(e, conn, ['amy@foo.com'], ['women'], [])), + EventPattern('dbus-signal', signal='GroupsChanged', + interface=cs.CONN_IFACE_CONTACT_GROUPS, + path=conn.object_path, + predicate=lambda e: groups_changed_predicate(e, conn, ['bob@foo.com', 'che@foo.com'], ['men'], [])), + ) + + amy, bob, che = conn.get_contact_handles_sync( ['amy@foo.com', 'bob@foo.com', 'che@foo.com']) - assertEquals([[amy], ['women'], []], groups_changed[0].args) - assertEquals([[bob, che], ['men'], []], groups_changed[1].args) - q.expect('dbus-signal', signal='ContactListStateChanged', args=[cs.CONTACT_LIST_STATE_SUCCESS]) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP, - 'men', ['bob@foo.com', 'che@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_GROUP, - 'women', ['amy@foo.com']) - - assertLength(0, pairs) # i.e. we've checked all of them - # change Amy's groups call_async(q, conn.ContactGroups, 'SetContactGroups', amy, ['ladies', 'people starting with A']) @@ -170,13 +163,8 @@ def test(q, bus, conn, stream): sync_dbus(bus, q, conn) sync_stream(q, stream) - assertEquals({ - cs.CONN_IFACE_CONTACT_GROUPS + '/groups': - ['ladies', 'people starting with A'], - cs.CONN + '/contact-id': - 'amy@foo.com' }, - conn.Contacts.GetContactAttributes([amy], - [cs.CONN_IFACE_CONTACT_GROUPS], False)[amy]) + + check_contact_roster(conn, 'amy@foo.com', ['ladies', 'people starting with A']) # sanity check: after all that, we expect Amy to be in group 'ladies' only sync_dbus(bus, q, conn) diff --git a/tests/twisted/roster/initial-aliases.py b/tests/twisted/roster/initial-aliases.py index d1aeb42ab..0ad823462 100644 --- a/tests/twisted/roster/initial-aliases.py +++ b/tests/twisted/roster/initial-aliases.py @@ -8,7 +8,6 @@ from servicetest import ( from gabbletest import ( exec_test, make_result_iq ) -import constants as cs import ns def add_contact(iq, jid, alias): @@ -45,8 +44,8 @@ def test(q, bus, conn, stream): event = q.expect('dbus-signal', signal='AliasesChanged') added = event.args[0] - bob_handle, alice_handle = conn.RequestHandles(cs.HT_CONTACT, - [bob_jid, alice_jid]) + bob_handle, alice_handle = conn.get_contact_handles_sync( + [bob_jid, alice_jid]) assertLength(2, added) assertContains((bob_handle, bob_alias), added) diff --git a/tests/twisted/roster/push-from-contact.py b/tests/twisted/roster/push-from-contact.py index 36f583245..cf696d95a 100644 --- a/tests/twisted/roster/push-from-contact.py +++ b/tests/twisted/roster/push-from-contact.py @@ -4,9 +4,7 @@ Ensure that Gabble correctly ignores roster pushes from contacts. from servicetest import EventPattern from gabbletest import exec_test, acknowledge_iq -from rostertest import ( - make_roster_push, expect_contact_list_signals, check_contact_list_signals, -) +from rostertest import make_roster_push import ns import constants as cs @@ -17,10 +15,7 @@ def test(q, bus, conn, stream): event = q.expect('stream-iq', query_ns=ns.ROSTER) acknowledge_iq(stream, event.stanza) - pairs = expect_contact_list_signals(q, bus, conn, - ['stored']) - stored = check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'stored', []) + q.expect('dbus-signal', signal='ContactListStateChanged', args=[cs.CONTACT_LIST_STATE_SUCCESS]) # Some malicious peer sends us a roster push to try to trick us into # showing them on our roster. Gabble should know better than to trust it. @@ -29,12 +24,11 @@ def test(q, bus, conn, stream): stream.send(iq) q.forbid_events( - [ EventPattern('dbus-signal', signal='MembersChanged', - path=stored.object_path), - EventPattern('dbus-signal', signal='ContactsChanged'), + [ + EventPattern('dbus-signal', signal='ContactsChangedWithID'), ]) - e = q.expect('stream-iq', iq_type='error') + q.expect('stream-iq', iq_type='error') if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/roster/push-without-id.py b/tests/twisted/roster/push-without-id.py index ed373d327..acbf83232 100644 --- a/tests/twisted/roster/push-without-id.py +++ b/tests/twisted/roster/push-without-id.py @@ -6,9 +6,7 @@ we should interop with them. Think of it of like No_Reply in D-Bus... from servicetest import EventPattern, sync_dbus from gabbletest import exec_test, acknowledge_iq, sync_stream -from rostertest import ( - make_roster_push, expect_contact_list_signals, check_contact_list_signals, -) +from rostertest import make_roster_push import ns import constants as cs @@ -19,24 +17,18 @@ def test(q, bus, conn, stream): event = q.expect('stream-iq', query_ns=ns.ROSTER) acknowledge_iq(stream, event.stanza) - pairs = expect_contact_list_signals(q, bus, conn, - ['stored']) - stored = check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'stored', []) + q.expect('dbus-signal', signal='ContactListStateChanged', args=[cs.CONTACT_LIST_STATE_SUCCESS]) # The server sends us a roster push without an id=''. WTF! iq = make_roster_push(stream, jid, 'both') del iq['id'] stream.send(iq) - h = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + h = conn.get_contact_handle_sync(jid) q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [h], [], [], [], 0, 0], path=stored.object_path), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{ h: (cs.SUBSCRIPTION_STATE_YES, - cs.SUBSCRIPTION_STATE_YES, ''), }, - []], + cs.SUBSCRIPTION_STATE_YES, ''), }, {h: jid}, {}], ), ) @@ -52,9 +44,7 @@ def test(q, bus, conn, stream): stream.send(iq) q.forbid_events( - [ EventPattern('dbus-signal', signal='MembersChanged', - path=stored.object_path), - EventPattern('dbus-signal', signal='ContactsChanged'), + [ EventPattern('dbus-signal', signal='ContactsChangedWithID'), ]) # Make sure Gabble's got the evil push... sync_stream(q, stream) diff --git a/tests/twisted/roster/removed-from-rp-subscribe.py b/tests/twisted/roster/removed-from-rp-subscribe.py index 8589567b3..86e3113eb 100644 --- a/tests/twisted/roster/removed-from-rp-subscribe.py +++ b/tests/twisted/roster/removed-from-rp-subscribe.py @@ -4,34 +4,23 @@ Regression tests for rescinding outstanding subscription requests. from twisted.words.protocols.jabber.client import IQ -from servicetest import EventPattern, assertEquals, assertLength, call_async +from servicetest import EventPattern, assertEquals, call_async from gabbletest import exec_test, acknowledge_iq -from rostertest import expect_contact_list_signals, check_contact_list_signals import constants as cs import ns jid = 'marco@barisione.lit' -def test(q, bus, conn, stream, remove, local, modern): +def test(q, bus, conn, stream, remove, local): # Gabble asks for the roster; the server sends back an empty roster. event = q.expect('stream-iq', query_ns=ns.ROSTER) event.stanza['type'] = 'result' stream.send(event.stanza) - pairs = expect_contact_list_signals(q, bus, conn, - ['publish', 'subscribe', 'stored']) + q.expect('dbus-signal', signal='ContactListStateChanged', args=[cs.CONTACT_LIST_STATE_SUCCESS]) - check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'publish', []) - subscribe = check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'subscribe', []) - stored = check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'stored', []) - - assertLength(0, pairs) # i.e. we've checked all of them - - self_handle = conn.GetSelfHandle() - h = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") + h = conn.get_contact_handle_sync(jid) # Another client logged into our account (Gajim, say) wants to subscribe to # Marco's presence. First, per RFC 3921 it 'SHOULD perform a "roster set" @@ -55,12 +44,10 @@ def test(q, bus, conn, stream, remove, local, modern): # In response, Gabble should add Marco to stored: q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [h], [], [], [], 0, 0], path=stored.object_path), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{ h: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO, ''), }, - []], + { h :jid }, {}], ), ) @@ -77,13 +64,10 @@ def test(q, bus, conn, stream, remove, local, modern): # In response, Gabble should add Marco to subscribe:remote-pending: q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [], [], [h], self_handle, 0], - path=subscribe.object_path), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{ h: (cs.SUBSCRIPTION_STATE_ASK, cs.SUBSCRIPTION_STATE_NO, ''), - }, []], + }, { h:jid }, {}], ), ) @@ -93,10 +77,7 @@ def test(q, bus, conn, stream, remove, local, modern): # ...removes him from the roster... if local: # ...by telling Gabble to remove him from stored. - if modern: - call_async(q, conn.ContactList, 'RemoveContacts', [h]) - else: - call_async(q, stored.Group, 'RemoveMembers', [h], '') + call_async(q, conn.ContactList, 'RemoveContacts', [h]) event = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER) item = event.query.firstChildElement() @@ -122,18 +103,12 @@ def test(q, bus, conn, stream, remove, local, modern): # In response, Gabble should announce that Marco has been removed from # subscribe:remote-pending and stored:members: q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [h], [], [], 0, 0], - path=subscribe.object_path), - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [h], [], [], 0, 0], - path=stored.object_path), - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [h]], + EventPattern('dbus-signal', signal='ContactsChangedWithID', + args=[{}, {}, { h: jid }], ), ) - if local and modern: + if local: acknowledge_iq(stream, event.stanza) q.expect('dbus-return', method='RemoveContacts') # FIXME: when we depend on a new enough tp-glib we can expect @@ -142,17 +117,13 @@ def test(q, bus, conn, stream, remove, local, modern): # ...rescinds the subscription request... if local: # ...by telling Gabble to remove him from 'subscribe'. - if modern: - call_async(q, conn.ContactList, 'Unsubscribe', [h]) - else: - subscribe.Group.RemoveMembers([h], '') + call_async(q, conn.ContactList, 'Unsubscribe', [h]) events = [EventPattern('stream-presence', to=jid, presence_type='unsubscribe')] - if modern: - events.append(EventPattern('dbus-return', - method='Unsubscribe')) + events.append(EventPattern('dbus-return', + method='Unsubscribe')) event = q.expect_many(*events)[0] else: @@ -172,47 +143,28 @@ def test(q, bus, conn, stream, remove, local, modern): # type='unsubscribed'/> ack before doing so: empirical tests reveal # that it's never delivered. q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [h], [], [], 0, 0], - path=subscribe.object_path), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{ h: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO, ''), - }, []], + }, { h: jid}, {}], ), ) def test_remove_local(q, bus, conn, stream): - test(q, bus, conn, stream, remove=True, local=True, modern=True) + test(q, bus, conn, stream, remove=True, local=True) def test_unsubscribe_local(q, bus, conn, stream): - test(q, bus, conn, stream, remove=False, local=True, modern=True) + test(q, bus, conn, stream, remove=False, local=True) def test_remove_remote(q, bus, conn, stream): - test(q, bus, conn, stream, remove=True, local=False, modern=True) + test(q, bus, conn, stream, remove=True, local=False) def test_unsubscribe_remote(q, bus, conn, stream): - test(q, bus, conn, stream, remove=False, local=False, modern=True) - -def test_remove_local_old(q, bus, conn, stream): - test(q, bus, conn, stream, remove=True, local=True, modern=False) - -def test_unsubscribe_local_old(q, bus, conn, stream): - test(q, bus, conn, stream, remove=False, local=True, modern=False) - -def test_remove_remote_old(q, bus, conn, stream): - test(q, bus, conn, stream, remove=True, local=False, modern=False) - -def test_unsubscribe_remote_old(q, bus, conn, stream): - test(q, bus, conn, stream, remove=False, local=False, modern=False) + test(q, bus, conn, stream, remove=False, local=False) if __name__ == '__main__': exec_test(test_remove_local) exec_test(test_unsubscribe_local) exec_test(test_remove_remote) exec_test(test_unsubscribe_remote) - exec_test(test_remove_local_old) - exec_test(test_unsubscribe_local_old) - exec_test(test_remove_remote_old) - exec_test(test_unsubscribe_remote_old) diff --git a/tests/twisted/roster/request-group-after-roster.py b/tests/twisted/roster/request-group-after-roster.py deleted file mode 100644 index 2d5691957..000000000 --- a/tests/twisted/roster/request-group-after-roster.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Regression test for a bug where CreateChannel times out when requesting a group -channel after the roster has been received. -""" - -from gabbletest import exec_test, sync_stream -from servicetest import sync_dbus, call_async -import constants as cs -import ns - -def test(q, bus, conn, stream): - roster_event = q.expect('stream-iq', query_ns=ns.ROSTER) - roster_event.stanza['type'] = 'result' - - call_async(q, conn, "RequestHandles", cs.HT_GROUP, ['test']) - - event = q.expect('dbus-return', method='RequestHandles') - test_handle = event.value[0][0] - - # send an empty roster - stream.send(roster_event.stanza) - - sync_stream(q, stream) - sync_dbus(bus, q, conn) - - call_async(q, conn.Requests, 'CreateChannel', - { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CONTACT_LIST, - cs.TARGET_HANDLE_TYPE: cs.HT_GROUP, - cs.TARGET_HANDLE: test_handle, - }) - - event = q.expect('dbus-return', method='CreateChannel') - ret_path, ret_props = event.value - - event = q.expect('dbus-signal', signal='NewChannels') - path, props = event.args[0][0] - assert props[cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CONTACT_LIST, props - assert props[cs.TARGET_HANDLE_TYPE] == cs.HT_GROUP, props - assert props[cs.TARGET_HANDLE] == test_handle, props - assert props[cs.TARGET_ID] == 'test', props - - assert ret_path == path, (ret_path, path) - assert ret_props == props, (ret_props, props) - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/roster/request-group-before-roster.py b/tests/twisted/roster/request-group-before-roster.py deleted file mode 100644 index 0a736b22a..000000000 --- a/tests/twisted/roster/request-group-before-roster.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Regression test for a bug where RequestChannel times out when requesting a -group channel if the roster hasn't been received at the time of the call. -""" - -from gabbletest import exec_test, sync_stream -from servicetest import sync_dbus, call_async -import constants as cs -import ns - -def test(q, bus, conn, stream): - roster_event = q.expect('stream-iq', query_ns=ns.ROSTER) - roster_event.stanza['type'] = 'result' - - call_async(q, conn, "RequestHandles", cs.HT_GROUP, ['test']) - - event = q.expect('dbus-return', method='RequestHandles') - test_handle = event.value[0][0] - - call_async(q, conn, 'RequestChannel', cs.CHANNEL_TYPE_CONTACT_LIST, - cs.HT_GROUP, test_handle, True) - - # A previous incarnation of this test --- written with the intention that - # RequestChannel would be called before the roster was received, to expose - # a bug in Gabble triggered by that ordering --- was racy: if the D-Bus - # daemon happened to be particularly busy, the call to RequestChannel - # reached Gabble after the roster stanza. (The race was discovered when - # that reversed order triggered a newly-introduced instance of the - # opposite bug to the one the test was targetting!) So we sync the XMPP - # stream and D-Bus queue here. - sync_stream(q, stream) - sync_dbus(bus, q, conn) - - # send an empty roster - stream.send(roster_event.stanza) - - event = q.expect('dbus-return', method='RequestChannel') - path = event.value[0] - - while True: - event = q.expect('dbus-signal', signal='NewChannel') - assert event.args[0] == path, (event.args, path) - _, type, handle_type, handle, suppress_handler = event.args - if handle_type == cs.HT_GROUP and handle == test_handle: - break - -if __name__ == '__main__': - exec_test(test) diff --git a/tests/twisted/roster/test-google-roster.py b/tests/twisted/roster/test-google-roster.py index 257661b6e..cff985dc1 100644 --- a/tests/twisted/roster/test-google-roster.py +++ b/tests/twisted/roster/test-google-roster.py @@ -7,7 +7,7 @@ from gabbletest import ( acknowledge_iq, exec_test, sync_stream, make_result_iq, GoogleXmlStream, ) from rostertest import ( - expect_contact_list_signals, check_contact_list_signals, + check_contact_roster, contacts_changed_predicate, blocked_contacts_changed_predicate, ) from servicetest import ( call_async, sync_dbus, EventPattern, @@ -43,18 +43,6 @@ def add_roster_item(query, contact, state, ask, attrs={}): return item -def is_stored(event): - return event.path.endswith('/stored') - -def is_subscribe(event): - return event.path.endswith('/subscribe') - -def is_publish(event): - return event.path.endswith('/publish') - -def is_deny(event): - return event.path.endswith('/deny') - def test_inital_roster(q, bus, conn, stream): """ This part of the test checks that Gabble correctly alters on which lists @@ -104,44 +92,36 @@ def test_inital_roster(q, bus, conn, stream): # <https://bugs.launchpad.net/ubuntu/+source/telepathy-gabble/+bug/398293>, # where Gabble was incorrectly hiding valid contacts. - mutually_subscribed_contacts = ['lp-bug-398293@gmail.com', - 'blocked-but-subscribed@boards.ca', - 'music-is-math@boards.ca'] - rp_contacts = ['this-is-a-jid@badger.com'] + contacts = [ + ('lp-bug-398293@gmail.com', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), + ('blocked-but-subscribed@boards.ca', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), + ('music-is-math@boards.ca', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), + ('this-is-a-jid@badger.com', cs.SUBSCRIPTION_STATE_ASK, cs.SUBSCRIPTION_STATE_NO, '') + ] + blocked_contacts = ['blocked-but-subscribed@boards.ca', 'blocked-and-no-sub@boards.ca', 'music-is-math@boards.ca'] - pairs = expect_contact_list_signals(q, bus, conn, - ['publish', 'subscribe', 'stored', 'deny']) - - publish = check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'publish', mutually_subscribed_contacts) - subscribe = check_contact_list_signals(q, bus, conn, pairs.pop(0), - cs.HT_LIST, 'subscribe', mutually_subscribed_contacts, - rp_contacts=rp_contacts) - stored = check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'stored', mutually_subscribed_contacts + rp_contacts) - deny = check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'deny', blocked_contacts) - - assertLength(0, pairs) # i.e. we've checked all of them - - return (publish, subscribe, stored, deny) + q.expect_many( + EventPattern('dbus-signal', signal='ContactsChangedWithID', + predicate=lambda e: contacts_changed_predicate(e, conn, contacts)), + EventPattern('dbus-signal', signal='BlockedContactsChanged', + predicate=lambda e: blocked_contacts_changed_predicate(e, blocked_contacts, [])), + ) -def test_flickering(q, bus, conn, stream, subscribe): +def test_flickering(q, bus, conn, stream): """ Google's server is buggy; when asking to subscribe to somebody, the subscription state transitions "flicker" sometimes. Here, we test that Gabble is suppressing the flickers. """ - self_handle = conn.GetSelfHandle() contact = 'bob@foo.com' - handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') # request subscription - call_async(q, subscribe.Group, 'AddMembers', [handle], "") + call_async(q, conn.ContactList, 'RequestSubscription', [handle], '') event = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER) item = event.query.firstChildElement() @@ -177,26 +157,16 @@ def test_flickering(q, bus, conn, stream, subscribe): # Gabble should report this update to the UI. q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [handle], [], [], [], 0, cs.GC_REASON_NONE], - predicate=is_stored), - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [], [], [handle], self_handle, cs.GC_REASON_NONE], - predicate=is_subscribe), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{handle: (cs.SUBSCRIPTION_STATE_ASK, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), + }, {handle: contact}, {}]), ) # Gabble shouldn't report any changes to subscribe or stored's members in # response to the next two roster updates. change_events = [ - EventPattern('dbus-signal', signal='MembersChanged', - predicate=is_subscribe), - EventPattern('dbus-signal', signal='MembersChanged', - predicate=is_stored), - EventPattern('dbus-signal', signal='ContactsChanged'), + EventPattern('dbus-signal', signal='ContactsChangedWithID'), ] q.forbid_events(change_events) @@ -235,15 +205,10 @@ def test_flickering(q, bus, conn, stream, subscribe): stream.send(presence) # Gabble should report this update to the UI. - q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [handle], [], [], [], handle, cs.GC_REASON_NONE], - predicate=is_subscribe), - EventPattern('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{handle: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), - ) + }, {handle: contact}, {}]) # Gabble shouldn't report any changes to subscribe or stored's members in # response to the next two roster updates. @@ -265,7 +230,7 @@ def test_flickering(q, bus, conn, stream, subscribe): sync_dbus(bus, q, conn) q.unforbid_events(change_events) -def test_local_pending(q, bus, conn, stream, subscribe): +def test_local_pending(q, bus, conn, stream): """ When somebody asks to subscribe to us, Google sends the subscription request and then a roster update saying there is no subscription. @@ -274,7 +239,7 @@ def test_local_pending(q, bus, conn, stream, subscribe): """ contact = 'alice@foo.com' - handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + handle = conn.get_contact_handle_sync(contact) # Alice asks to subscribes to us presence = domish.Element(('jabber:client', 'presence')) @@ -282,19 +247,25 @@ def test_local_pending(q, bus, conn, stream, subscribe): presence['type'] = 'subscribe' stream.send(presence) - q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [], [handle], [], handle, cs.GC_REASON_NONE], - predicate=is_publish), - EventPattern('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{handle: (cs.SUBSCRIPTION_STATE_NO, - cs.SUBSCRIPTION_STATE_ASK, '')}, []]), - ) + cs.SUBSCRIPTION_STATE_ASK, '')}, {handle: contact}, {}]) + + def alice_state_changed(e): + # check that Alice's publish and subscribe state isn't changed + changes, ids, removal = e.args + + subscription = changes.get(handle) + if subscription is None: + return False + + subscribe, publish, request = subscription + return subscribe != cs.SUBSCRIPTION_STATE_NO and publish != cs.SUBSCRIPTION_STATE_ASK # Now we send the spurious roster update with subscribe="none" and verify # that nothing happens to her publish state in reaction to that - change_event = EventPattern('dbus-signal', signal='MembersChanged', - predicate=is_publish) + change_event = EventPattern('dbus-signal', signal='ContactsChangedWithID', + predicate=alice_state_changed) q.forbid_events([change_event]) iq = make_set_roster_iq(stream, 'test@localhost/Resource', contact, @@ -312,14 +283,9 @@ def test_local_pending(q, bus, conn, stream, subscribe): presence['type'] = 'unsubscribe' stream.send(presence) - q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [handle], [], [], handle, cs.GC_REASON_NONE], - predicate=is_publish), - EventPattern('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{handle: (cs.SUBSCRIPTION_STATE_NO, - cs.SUBSCRIPTION_STATE_REMOVED_REMOTELY, '')}, []]), - ) + cs.SUBSCRIPTION_STATE_REMOVED_REMOTELY, '')}, {handle: contact}, {}]) # Now we send a roster roster update with subscribe="none" again (which # doesn't change anything, it just confirms what we already knew) and @@ -342,7 +308,7 @@ remove_events = [ ) ] -def test_deny_simple(q, bus, conn, stream, stored, deny): +def test_deny_simple(q, bus, conn, stream): """ If we remove a blocked contact from 'stored', they shouldn't actually be removed from the roster: rather, we should cancel both subscription @@ -350,10 +316,12 @@ def test_deny_simple(q, bus, conn, stream, stored, deny): remaining on 'deny'. """ contact = 'blocked-but-subscribed@boards.ca' - handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] - assertContains(handle, - stored.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) - call_async(q, stored.Group, 'RemoveMembers', [handle], "") + handle = conn.get_contact_handle_sync(contact) + + check_contact_roster(conn, contact, [], + cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES) + + call_async(q, conn.ContactList, 'RemoveContacts', [handle]) q.forbid_events(remove_events) @@ -362,7 +330,7 @@ def test_deny_simple(q, bus, conn, stream, stored, deny): presence_type='unsubscribe'), EventPattern('stream-presence', to=contact, presence_type='unsubscribed'), - EventPattern('dbus-return', method='RemoveMembers'), + EventPattern('dbus-return', method='RemoveContacts'), ) # Our server sends roster pushes in response to our unsubscribe and @@ -374,48 +342,39 @@ def test_deny_simple(q, bus, conn, stream, stored, deny): # As a result they should drop off all three non-deny lists, but not fall # off deny: - q.expect_many( - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [handle]]), - *[ EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [handle], [], [], 0, cs.GC_REASON_NONE], - predicate=p) - for p in [is_stored, is_subscribe, is_publish] - ]) + q.expect('dbus-signal', signal='ContactsChangedWithID', args=[{}, {}, {handle: contact}]) assertContains(handle, - deny.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) + conn.ContactBlocking.RequestBlockedContacts().keys()) q.unforbid_events(remove_events) -def test_deny_overlap_one(q, bus, conn, stream, subscribe, stored, deny): +def test_deny_overlap_one(q, bus, conn, stream): """ Here's a tricker case: blocking a contact, and then removing them before the server's responded to the block request. """ - self_handle = conn.GetSelfHandle() # As we saw in test_flickering(), we have a subscription to Bob, # everything's peachy. contact = 'bob@foo.com' - handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync(contact) - assertContains(handle, - stored.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) - assertContains(handle, - subscribe.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) + check_contact_roster(conn, contact, [], + cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO) q.forbid_events(remove_events) # But then we have a falling out. In a blind rage, I block Bob: - call_async(q, deny.Group, 'AddMembers', [handle], "") + call_async(q, conn.ContactBlocking, 'BlockContacts', [handle], "") event = q.expect('stream-iq', query_ns=ns.ROSTER) item = event.query.firstChildElement() assertEquals(contact, item['jid']) assertEquals('B', item[(ns.GOOGLE_ROSTER, 't')]) - # Then — *before the server has replied* — I remove him from stored. - call_async(q, stored.Group, 'RemoveMembers', [handle], "") + # Then — *before the server has replied* — I remove him from the contact + # list. + call_async(q, conn.ContactList, 'RemoveContacts', [handle]) # subscription='remove' is still forbidden from above. So we sync to ensure # that Gabble's received RemoveMembers, and if it's going to send us a @@ -437,8 +396,8 @@ def test_deny_overlap_one(q, bus, conn, stream, subscribe, stored, deny): q.forbid_events(unsubscribed_events) q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', predicate=is_deny, - args=["", [handle], [], [], [], self_handle, 0]), + EventPattern('dbus-signal', signal='BlockedContactsChanged', + predicate=lambda e: blocked_contacts_changed_predicate(e, [contact], [])), EventPattern('stream-presence', to=contact, presence_type='unsubscribe'), ) @@ -448,26 +407,17 @@ def test_deny_overlap_one(q, bus, conn, stream, subscribe, stored, deny): "none", False, attrs={'gr:t': 'B'})) # As a result, Gabble makes Bob fall off subscribe and stored. - q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - predicate=is_subscribe, - args=["", [], [handle], [], [], 0, 0]), - EventPattern('dbus-signal', signal='MembersChanged', - predicate=is_stored, - args=["", [], [handle], [], [], 0, 0]), - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [handle]]), - ) + q.expect('dbus-signal', signal='ContactsChangedWithID', + args=[{}, {}, {handle: contact}]) # And he should definitely still be on deny. That rascal. assertContains(handle, - deny.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) + conn.ContactBlocking.RequestBlockedContacts().keys()) q.unforbid_events(unsubscribed_events) q.unforbid_events(remove_events) -def test_deny_overlap_two(q, bus, conn, stream, - subscribe, publish, stored, deny): +def test_deny_overlap_two(q, bus, conn, stream): """ Here's another tricky case: editing a contact (setting an alias, say), and then while that edit's in flight, blocking and remove the contact. @@ -475,14 +425,10 @@ def test_deny_overlap_two(q, bus, conn, stream, # This contact was on our roster when we started. contact = 'lp-bug-398293@gmail.com' - handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + handle = conn.get_contact_handle_sync(contact) - assertContains(handle, - stored.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) - assertContains(handle, - subscribe.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) - assertContains(handle, - publish.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) + check_contact_roster(conn, contact, [], + cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES) # Once again, at no point in this test should anyone be removed outright. q.forbid_events(remove_events) @@ -504,8 +450,8 @@ def test_deny_overlap_two(q, bus, conn, stream, ] q.forbid_events(patterns) - call_async(q, deny.Group, 'AddMembers', [handle], "") - call_async(q, stored.Group, 'RemoveMembers', [handle], "") + call_async(q, conn.ContactBlocking, 'BlockContacts', [handle], "") + call_async(q, conn.ContactList, 'RemoveContacts', [handle]) # Make sure if the edits are sent prematurely, we've got them. sync_stream(q, stream) @@ -524,27 +470,27 @@ def test_deny_overlap_two(q, bus, conn, stream, # And we're done. Clean up. q.unforbid_events(remove_events) -def test_deny_unblock_remove(q, bus, conn, stream, stored, deny): +def test_deny_unblock_remove(q, bus, conn, stream): """ Test unblocking a contact, and, while that request is pending, deleting them. """ - self_handle = conn.GetSelfHandle() # This contact was on our roster, blocked and subscribed, when we started. contact = 'music-is-math@boards.ca' - handle = conn.RequestHandles(cs.HT_CONTACT, [contact])[0] + handle = conn.get_contact_handle_sync(contact) + + check_contact_roster(conn, contact, [], + cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES) # They're blocked, and we have a bidi subscription, so they should be on # deny and stored. (We already checked this earlier, but we've been messing # with the roster so let's be sure the preconditions are okay...) assertContains(handle, - deny.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) - assertContains(handle, - stored.Properties.Get(cs.CHANNEL_IFACE_GROUP, "Members")) + conn.ContactBlocking.RequestBlockedContacts().keys()) # Unblock them. - call_async(q, deny.Group, 'RemoveMembers', [handle], "") + call_async(q, conn.ContactBlocking, 'UnblockContacts', [handle]) roster_event = q.expect('stream-iq', query_ns=ns.ROSTER) item = roster_event.query.firstChildElement() @@ -554,7 +500,7 @@ def test_deny_unblock_remove(q, bus, conn, stream, stored, deny): # If we now remove them from stored, the edit shouldn't be sent until the # unblock event has had a reply. q.forbid_events(remove_events) - call_async(q, stored.Group, 'RemoveMembers', [handle], "") + call_async(q, conn.ContactList, 'RemoveContacts', [handle]) # Make sure if the remove is sent prematurely, we catch it. sync_stream(q, stream) @@ -569,9 +515,8 @@ def test_deny_unblock_remove(q, bus, conn, stream, stored, deny): # removed from deny, and send a remove. _, roster_event = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [handle], [], [], self_handle, cs.GC_REASON_NONE], - predicate=is_deny), + EventPattern('dbus-signal', signal='BlockedContactsChanged', + predicate=lambda e: blocked_contacts_changed_predicate(e, [], [contact])), remove_events[0], ) item = roster_event.query.firstChildElement() @@ -581,11 +526,7 @@ def test_deny_unblock_remove(q, bus, conn, stream, stored, deny): 'remove', False, attrs={})) acknowledge_iq(stream, roster_event.stanza) - q.expect('dbus-signal', signal='MembersChanged', - args=['', [], [handle], [], [], 0, cs.GC_REASON_NONE], - predicate=is_stored) - -def test_contact_blocking(q, bus, conn, stream, stored, deny): +def test_contact_blocking(q, bus, conn, stream): """test ContactBlocking API""" assertContains(cs.CONN_IFACE_CONTACT_BLOCKING, conn.Properties.Get(cs.CONN, "Interfaces")) @@ -596,16 +537,15 @@ def test_contact_blocking(q, bus, conn, stream, stored, deny): assertLength(3, blocked) def test(q, bus, conn, stream): - publish, subscribe, stored, deny = test_inital_roster(q, bus, conn, stream) - - test_flickering(q, bus, conn, stream, subscribe) - test_local_pending(q, bus, conn, stream, subscribe) - test_deny_simple(q, bus, conn, stream, stored, deny) - test_deny_overlap_one(q, bus, conn, stream, subscribe, stored, deny) - test_deny_overlap_two(q, bus, conn, stream, - subscribe, publish, stored, deny) - test_deny_unblock_remove(q, bus, conn, stream, stored, deny) - test_contact_blocking(q, bus, conn, stream, stored, deny) + test_inital_roster(q, bus, conn, stream) + + test_flickering(q, bus, conn, stream) + test_local_pending(q, bus, conn, stream) + test_deny_simple(q, bus, conn, stream) + test_deny_overlap_one(q, bus, conn, stream) + test_deny_overlap_two(q, bus, conn, stream) + test_deny_unblock_remove(q, bus, conn, stream) + test_contact_blocking(q, bus, conn, stream) if __name__ == '__main__': exec_test(test, protocol=GoogleXmlStream) diff --git a/tests/twisted/roster/test-roster-item-deletion.py b/tests/twisted/roster/test-roster-item-deletion.py index 027446809..9e008f30d 100644 --- a/tests/twisted/roster/test-roster-item-deletion.py +++ b/tests/twisted/roster/test-roster-item-deletion.py @@ -3,25 +3,18 @@ Regression test for http://bugs.freedesktop.org/show_bug.cgi?id=19524 """ from gabbletest import exec_test, acknowledge_iq -from rostertest import (expect_contact_list_signals, - check_contact_list_signals, send_roster_push) -from servicetest import (assertLength, assertEquals, EventPattern, call_async) +from rostertest import (send_roster_push, check_contact_roster) +from servicetest import (assertEquals, EventPattern, call_async) import constants as cs import ns -def test_ancient(q, bus, conn, stream): - test(q, bus, conn, stream, False) - def test_modern(q, bus, conn, stream): - test(q, bus, conn, stream, True) - -def test_ancient_queued(q, bus, conn, stream): - test(q, bus, conn, stream, False, True) + test(q, bus, conn, stream) def test_modern_queued(q, bus, conn, stream): - test(q, bus, conn, stream, True, True) + test(q, bus, conn, stream, True) -def test(q, bus, conn, stream, modern=True, queued=False): +def test(q, bus, conn, stream, queued=False): event = q.expect('stream-iq', query_ns=ns.ROSTER) event.stanza['type'] = 'result' @@ -29,28 +22,18 @@ def test(q, bus, conn, stream, modern=True, queued=False): item['jid'] = 'quux@foo.com' item['subscription'] = 'none' - quux_handle = conn.RequestHandles(cs.HT_CONTACT, ['quux@foo.com'])[0] + quux_handle = conn.get_contact_handle_sync('quux@foo.com') stream.send(event.stanza) # slight implementation detail: TpBaseContactList emits ContactsChanged # before it announces its channels - q.expect('dbus-signal', signal='ContactsChanged', + q.expect('dbus-signal', signal='ContactsChangedWithID', interface=cs.CONN_IFACE_CONTACT_LIST, path=conn.object_path, args=[{quux_handle: - (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO, '')}, []]) - - pairs = expect_contact_list_signals(q, bus, conn, - ['publish', 'subscribe', 'stored']) - - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'publish', []) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'subscribe', []) - stored = check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'stored', ['quux@foo.com']) + (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO, '')}, {quux_handle: 'quux@foo.com'}, {}]) - assertLength(0, pairs) # i.e. we've checked all of them + check_contact_roster(conn, 'quux@foo.com', [], cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO) if queued: conn.Aliasing.SetAliases({quux_handle: 'Quux'}) @@ -64,10 +47,7 @@ def test(q, bus, conn, stream, modern=True, queued=False): iq_type='set', query_ns=ns.ROSTER), ] - if modern: - call_async(q, conn.ContactList, 'RemoveContacts', [quux_handle]) - else: - call_async(q, stored.Group, 'RemoveMembers', [quux_handle], '') + call_async(q, conn.ContactList, 'RemoveContacts', [quux_handle]) if queued: # finish off the previous thing we were doing, so removal can proceed @@ -81,24 +61,18 @@ def test(q, bus, conn, stream, modern=True, queued=False): send_roster_push(stream, 'quux@foo.com', 'remove') q.expect_many( - EventPattern('dbus-signal', interface=cs.CHANNEL_IFACE_GROUP, - path=stored.object_path, signal='MembersChanged', - args=['', [], [quux_handle], [], [], 0, 0]), EventPattern('dbus-signal', interface=cs.CONN_IFACE_CONTACT_LIST, - path=conn.object_path, signal='ContactsChanged', - args=[{}, [quux_handle]]), + path=conn.object_path, signal='ContactsChangedWithID', + args=[{}, {}, {quux_handle: 'quux@foo.com'}]), EventPattern('stream-iq', iq_id='push', iq_type='result'), ) acknowledge_iq(stream, event.stanza) - if modern: - q.expect('dbus-return', method='RemoveContacts') + q.expect('dbus-return', method='RemoveContacts') # FIXME: when we depend on a new enough tp-glib, RemoveMembers should # return at this point too if __name__ == '__main__': - exec_test(test_ancient) exec_test(test_modern) - exec_test(test_ancient_queued) exec_test(test_modern_queued) diff --git a/tests/twisted/roster/test-roster-subscribe.py b/tests/twisted/roster/test-roster-subscribe.py index 23979d385..43eb2ddff 100644 --- a/tests/twisted/roster/test-roster-subscribe.py +++ b/tests/twisted/roster/test-roster-subscribe.py @@ -5,91 +5,47 @@ Test subscribing to a contact's presence. from twisted.words.xish import domish -from servicetest import (EventPattern, assertLength, assertEquals, - call_async, wrap_channel, sync_dbus) +from servicetest import (EventPattern, assertEquals, call_async, sync_dbus) from gabbletest import (acknowledge_iq, exec_test, sync_stream) from rostertest import send_roster_push import constants as cs import ns -def test_ancient(q, bus, conn, stream): - test(q, bus, conn, stream, False) - def test_modern(q, bus, conn, stream): - test(q, bus, conn, stream, True) - -def test_ancient_remove(q, bus, conn, stream): - test(q, bus, conn, stream, False, True) + test(q, bus, conn, stream) def test_modern_remove(q, bus, conn, stream): - test(q, bus, conn, stream, True, True) - -def test_ancient_reject(q, bus, conn, stream): - test(q, bus, conn, stream, False, 'reject') + test(q, bus, conn, stream, True) def test_modern_reject(q, bus, conn, stream): - test(q, bus, conn, stream, True, 'reject') - -def test_ancient_reject_remove(q, bus, conn, stream): - test(q, bus, conn, stream, False, True, 'reject') + test(q, bus, conn, stream, False, 'reject') def test_modern_reject_remove(q, bus, conn, stream): - test(q, bus, conn, stream, True, True, 'reject') - -def test_ancient_revoke(q, bus, conn, stream): - test(q, bus, conn, stream, False, 'revoke') + test(q, bus, conn, stream, True, 'reject') def test_modern_revoke(q, bus, conn, stream): - test(q, bus, conn, stream, True, 'revoke') - -def test_ancient_revoke_remove(q, bus, conn, stream): - test(q, bus, conn, stream, False, True, 'revoke') + test(q, bus, conn, stream, 'revoke') def test_modern_revoke_remove(q, bus, conn, stream): - test(q, bus, conn, stream, True, True, 'revoke') + test(q, bus, conn, stream, True, 'revoke') -def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): +def test(q, bus, conn, stream, remove=False, remote='accept'): event = q.expect('stream-iq', query_ns=ns.ROSTER) # send back empty roster event.stanza['type'] = 'result' stream.send(event.stanza) - while True: - event = q.expect('dbus-signal', signal='NewChannel') - path, type, handle_type, handle, suppress_handler = event.args - - if type != cs.CHANNEL_TYPE_CONTACT_LIST: - continue - - chan_name = conn.InspectHandles(handle_type, [handle])[0] - - if chan_name == 'subscribe': - break - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'ContactList') - assertLength(0, chan.Group.GetMembers()) - - stored_path = conn.Requests.EnsureChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CONTACT_LIST, - cs.TARGET_HANDLE_TYPE: cs.HT_LIST, - cs.TARGET_ID: 'stored', - })[1] - stored = wrap_channel(bus.get_object(conn.bus_name, stored_path), - 'ContactList') + q.expect('dbus-signal', signal='ContactListStateChanged', args=[cs.CONTACT_LIST_STATE_SUCCESS]) # request subscription - alice, bob = conn.RequestHandles(cs.HT_CONTACT, + alice, bob = conn.get_contact_handles_sync( ['alice@foo.com', 'bob@foo.com']) # Repeated subscription requests are *not* idempotent: the second request # should nag the contact again. for first_time in True, False, False: - if modern: - call_async(q, conn.ContactList, 'RequestSubscription', [bob], - 'plz add kthx') - else: - call_async(q, chan.Group, 'AddMembers', [bob], - 'plz add kthx') + call_async(q, conn.ContactList, 'RequestSubscription', [bob], + 'plz add kthx') if first_time: event = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER) @@ -101,9 +57,8 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): EventPattern('stream-presence', presence_type='subscribe'), ] - if modern: - expectations.append(EventPattern('dbus-return', - method='RequestSubscription')) + expectations.append(EventPattern('dbus-return', + method='RequestSubscription')) event = q.expect_many(*expectations)[0] assertEquals('plz add kthx', event.presence_status) @@ -127,15 +82,16 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): stream.send(presence) q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [bob], [], [], bob, - cs.GC_REASON_PERMISSION_DENIED]), + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: e.args[0] == [] and e.args[1] == [bob] and + e.args[2] == [] and e.args[3] == [] and + e.args[4]['change-reason'] == cs.GC_REASON_PERMISSION_DENIED), #EventPattern('stream-presence'), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{bob: (cs.SUBSCRIPTION_STATE_REMOVED_REMOTELY, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), + }, {bob: 'bob@foo.com'}, {}]), ) send_roster_push(stream, 'bob@foo.com', 'to') @@ -148,13 +104,14 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): stream.send(presence) q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [bob], [], [], [], bob, 0]), + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: e.args[0] == [bob] and e.args[1] == [] and + e.args[2] == [] and e.args[3] == []), EventPattern('stream-presence'), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{bob: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), + }, {bob: 'bob@foo.com'}, {}]), ) send_roster_push(stream, 'bob@foo.com', 'to') @@ -188,15 +145,16 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): stream.send(presence) q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [], [bob], [], [], bob, - cs.GC_REASON_PERMISSION_DENIED]), + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: e.args[0] == [] and e.args[1] == [bob] and + e.args[2] == [] and e.args[3] == [] and + e.args[4]['change-reason'] == cs.GC_REASON_PERMISSION_DENIED), EventPattern('stream-presence'), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{bob: (cs.SUBSCRIPTION_STATE_REMOVED_REMOTELY, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), + }, {bob: 'bob@foo.com'}, {}]), ) # Else, Bob isn't actually as interesting as we thought. Never mind, @@ -206,26 +164,12 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): # (Unsubscribing from pending-subscribe is tested in # roster/removed-from-rp-subscribe.py so we don't test it here.) - # If Bob removed us, we have to use modern APIs from now on, because from - # the point of view of the old Group interface, removed remotely and - # removed locally are synonymous. - if remote in ('reject', 'revoke'): - modern = True - - if modern: - if remove: - returning_method = 'RemoveContacts' - call_async(q, conn.ContactList, 'RemoveContacts', [bob]) - else: - returning_method = 'Unsubscribe' - call_async(q, conn.ContactList, 'Unsubscribe', [bob]) + if remove: + returning_method = 'RemoveContacts' + call_async(q, conn.ContactList, 'RemoveContacts', [bob]) else: - returning_method = 'RemoveMembers' - - if remove: - call_async(q, stored.Group, 'RemoveMembers', [bob], '') - else: - call_async(q, chan.Group, 'RemoveMembers', [bob], '') + returning_method = 'Unsubscribe' + call_async(q, conn.ContactList, 'Unsubscribe', [bob]) if remove: iq = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER, @@ -233,16 +177,15 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): acknowledge_iq(stream, iq.stanza) - if modern: - q.expect('dbus-return', method='RemoveContacts') + q.expect('dbus-return', method='RemoveContacts') # FIXME: when we depend on a new enough tp-glib, expect RemoveMembers # to return here too send_roster_push(stream, 'bob@foo.com', 'remove') q.expect_many( EventPattern('stream-iq', iq_type='result', iq_id='push'), - EventPattern('dbus-signal', signal='ContactsChanged', - args=[{}, [bob]]), + EventPattern('dbus-signal', signal='ContactsChangedWithID', + args=[{}, {}, {bob: 'bob@foo.com'}]), ) else: q.expect_many( @@ -254,22 +197,16 @@ def test(q, bus, conn, stream, modern=True, remove=False, remote='accept'): send_roster_push(stream, 'bob@foo.com', 'none') q.expect_many( EventPattern('stream-iq', iq_type='result', iq_id='push'), - EventPattern('dbus-signal', signal='ContactsChanged', + EventPattern('dbus-signal', signal='ContactsChangedWithID', args=[{bob: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_NO, ''), - }, []]), + }, {bob: 'bob@foo.com'}, {}]), ) if __name__ == '__main__': - exec_test(test_ancient) exec_test(test_modern) - exec_test(test_ancient_remove) exec_test(test_modern_remove) - exec_test(test_ancient_revoke) exec_test(test_modern_revoke) - exec_test(test_ancient_revoke_remove) exec_test(test_modern_revoke_remove) - exec_test(test_ancient_reject) exec_test(test_modern_reject) - exec_test(test_ancient_reject_remove) exec_test(test_modern_reject_remove) diff --git a/tests/twisted/roster/test-roster.py b/tests/twisted/roster/test-roster.py index 04fee09d8..407eb2bfa 100644 --- a/tests/twisted/roster/test-roster.py +++ b/tests/twisted/roster/test-roster.py @@ -3,8 +3,8 @@ Test basic roster functionality. """ from gabbletest import exec_test -from rostertest import expect_contact_list_signals, check_contact_list_signals -from servicetest import (assertEquals, assertLength, call_async) +from rostertest import check_contact_roster, contacts_changed_predicate +from servicetest import (assertEquals, call_async) import constants as cs import ns @@ -37,23 +37,21 @@ def test(q, bus, conn, stream): # roster query twice. This used to crash Gabble. stream.send(event.stanza) + contacts = [ + ('amy@foo.com', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), + ('bob@foo.com', cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_YES, ''), + ('che@foo.com', cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO, ''), + ] + # slight implementation detail: TpBaseContactList emits ContactsChanged # before it announces its channels - s = q.expect('dbus-signal', signal='ContactsChanged', - interface=cs.CONN_IFACE_CONTACT_LIST, path=conn.object_path) + q.expect('dbus-signal', signal='ContactsChangedWithID', + interface=cs.CONN_IFACE_CONTACT_LIST, path=conn.object_path, + predicate=lambda e: contacts_changed_predicate(e, conn, contacts)) - amy, bob, che = conn.RequestHandles(cs.HT_CONTACT, + amy, bob, che = conn.get_contact_handles_sync( ['amy@foo.com', 'bob@foo.com', 'che@foo.com']) - assertEquals([{ - amy: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_YES, ''), - bob: (cs.SUBSCRIPTION_STATE_NO, cs.SUBSCRIPTION_STATE_YES, ''), - che: (cs.SUBSCRIPTION_STATE_YES, cs.SUBSCRIPTION_STATE_NO, ''), - }, []], s.args) - - pairs = expect_contact_list_signals(q, bus, conn, - ['publish', 'subscribe', 'stored']) - # this is emitted last, so clients can tell when the initial state dump # has finished q.expect('dbus-signal', signal='ContactListStateChanged', @@ -82,14 +80,5 @@ def test(q, bus, conn, stream): }, },), r.value) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'publish', ['amy@foo.com', 'bob@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'subscribe', ['amy@foo.com', 'che@foo.com']) - check_contact_list_signals(q, bus, conn, pairs.pop(0), cs.HT_LIST, - 'stored', ['amy@foo.com', 'bob@foo.com', 'che@foo.com']) - - assertLength(0, pairs) # i.e. we've checked all of them - if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/roster/test-save-alias-to-roster.py b/tests/twisted/roster/test-save-alias-to-roster.py index 2164915d5..0f67da0ae 100644 --- a/tests/twisted/roster/test-save-alias-to-roster.py +++ b/tests/twisted/roster/test-save-alias-to-roster.py @@ -3,15 +3,13 @@ Test that updating an alias saves it to the roster. """ -import dbus - from servicetest import EventPattern, call_async, assertEquals from gabbletest import ( acknowledge_iq, exec_test, make_result_iq, sync_stream, elem ) import constants as cs import ns -from rostertest import expect_contact_list_signals, send_roster_push +from rostertest import send_roster_push from pubsub import make_pubsub_event def send_pep_nick_reply(stream, stanza, nickname): @@ -52,22 +50,16 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) acknowledge_iq(stream, event2.stanza) - signals = expect_contact_list_signals(q, bus, conn, lists=['subscribe']) - old_signal, new_signal = signals[0] - path = old_signal.args[0] + q.expect('dbus-signal', signal='ContactListStateChanged', args=[cs.CONTACT_LIST_STATE_SUCCESS]) # request subscription - chan = bus.get_object(conn.bus_name, path) - group_iface = dbus.Interface(chan, cs.CHANNEL_IFACE_GROUP) - assert group_iface.GetMembers() == [] - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] - call_async(q, group_iface, 'AddMembers', [handle], '') + handle = conn.get_contact_handle_sync('bob@foo.com') + call_async(q, conn.ContactList, 'RequestSubscription', [handle], '') event = q.expect('stream-iq', iq_type='set', query_ns=ns.ROSTER) - item = event.query.firstChildElement() acknowledge_iq(stream, event.stanza) - q.expect('dbus-return', method='AddMembers') + q.expect('dbus-return', method='RequestSubscription') call_async(q, conn.Aliasing, 'RequestAliases', [handle]) @@ -88,7 +80,7 @@ def test(q, bus, conn, stream): # the current semantics where the alias is always meant to be something you # could show, even if it's just their JID), so let's forbid that. jid = 'parts@labor.lit' - handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + handle = conn.get_contact_handle_sync(jid) q.forbid_events([EventPattern('dbus-signal', signal='AliasesChanged', args=[[(handle, '')]])]) @@ -96,10 +88,11 @@ def test(q, bus, conn, stream): # I don't really have very strong opinions on whether Gabble should be # signalling that this contact's alias has *changed* per se, so am not # explicitly expecting that. - q.expect('dbus-signal', signal='MembersChanged') + q.expect('dbus-signal', signal='MembersChangedDetailed') # But if we ask for it, Gabble should probably send a PEP query. - assertEquals(jid, conn.Aliasing.GetAliases([handle])[handle]) + h2asv = conn.Contacts.GetContactAttributes([handle], [cs.CONN_IFACE_ALIASING], False) + assertEquals(jid, h2asv[handle][cs.ATTR_ALIAS]) event = q.expect('stream-iq', iq_type='get', query_ns=ns.PUBSUB, to=jid) nick = 'Constant Future' @@ -110,7 +103,7 @@ def test(q, bus, conn, stream): # because we've cached that they have no alias. Gabble shouldn't make # unsolicited PEP or vCard queries to them. jid = 'friendly@faith.plate' - handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + handle = conn.get_contact_handle_sync(jid) q.forbid_events([ EventPattern('stream-iq', query_ns=ns.PUBSUB, to=jid), @@ -148,7 +141,7 @@ def test(q, bus, conn, stream): # Here's a contact we haven't seen before, pushed to our roster with a # nickname already there. jid = 'glados@aperture.lit' - handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + handle = conn.get_contact_handle_sync(jid) nick = 'Potato' send_roster_push(stream, jid, 'both', name=nick) diff --git a/tests/twisted/rostertest.py b/tests/twisted/rostertest.py index 7e9f121ab..c3fb03c3b 100644 --- a/tests/twisted/rostertest.py +++ b/tests/twisted/rostertest.py @@ -1,8 +1,6 @@ from twisted.words.protocols.jabber.client import IQ -from gabbletest import (wrap_channel,) -from servicetest import (assertEquals, assertLength, EventPattern, - assertContains) +from servicetest import (assertEquals, assertSameSets) import constants as cs import ns @@ -29,142 +27,57 @@ def send_roster_push(stream, jid, subscription, ask_subscribe=False, name=None): ask_subscribe=ask_subscribe, name=name) stream.send(iq) -def get_contact_list_event_patterns(q, bus, conn, expected_handle_type, name): - expected_handle = conn.RequestHandles(expected_handle_type, [name])[0] +# check that @contact on @conn is in groups @groups with @subscribe and +# @publish as subscription states +def check_contact_roster(conn, contact, groups=None, subscribe=None, publish=None): + h = conn.get_contact_handle_sync(contact) + attrs = conn.Contacts.GetContactAttributes([h], + [cs.CONN_IFACE_CONTACT_LIST, cs.CONN_IFACE_CONTACT_GROUPS], True)[h] - def new_channel_predicate(e): - path, type, handle_type, handle, suppress_handler = e.args - if type != cs.CHANNEL_TYPE_CONTACT_LIST: - return False - if handle_type != expected_handle_type: - return False - if handle != expected_handle: - return False - return True - new_channel_repr = ('NewChannel(., ContactList, %u, "%s", .)' - % (expected_handle_type, name)) - new_channel_predicate.__repr__ = lambda: new_channel_repr - - def new_channels_predicate(e): - info, = e.args - if len(info) != 1: - return False - path, props = info[0] - if props.get(cs.CHANNEL_TYPE) != cs.CHANNEL_TYPE_CONTACT_LIST: - return False - if props.get(cs.TARGET_HANDLE_TYPE) != expected_handle_type: - return False - if props.get(cs.TARGET_HANDLE) != expected_handle: + if groups is not None: + assertSameSets(groups, attrs[cs.ATTR_GROUPS]) + if subscribe is not None: + assertEquals(subscribe, attrs[cs.ATTR_SUBSCRIBE]) + if publish is not None: + assertEquals(publish, attrs[cs.ATTR_PUBLISH]) + +# function to pass as 'ContactsChangedWithID' dbus-signal even predicate +# checking if the (contact-id, subscribe-state, publish-state, message) tuples +# from @contacts are the arguments of the signal. +def contacts_changed_predicate(e, conn, contacts): + changes, ids, removals = e.args + + if len(changes) != len(contacts): + return False + + for c in contacts: + i, subscribe, publish, msg = c + + h = conn.get_contact_handle_sync(i) + + if changes[h] != (subscribe, publish, msg): return False - return True - new_channels_repr = ('NewChannels(... ct=ContactList, ht=%u, name="%s"... )' - % (expected_handle_type, name)) - new_channels_predicate.__repr__ = lambda: new_channels_repr - - return ( - EventPattern('dbus-signal', signal='NewChannel', - predicate=new_channel_predicate), - EventPattern('dbus-signal', signal='NewChannels', - predicate=new_channels_predicate) - ) - -def expect_contact_list_signals(q, bus, conn, lists, groups=[], - expect_more=None): - assert lists or groups - - if expect_more is None: - eps = [] - else: - eps = expect_more[:] - - for name in lists: - eps.extend(get_contact_list_event_patterns(q, bus, conn, - cs.HT_LIST, name)) - - for name in groups: - eps.extend(get_contact_list_event_patterns(q, bus, conn, - cs.HT_GROUP, name)) - - events = q.expect_many(*eps) - ret = [] - more = [] - - if expect_more is not None: - for ep in expect_more: - more.append(events.pop(0)) - - for name in lists: - old_signal = events.pop(0) - new_signal = events.pop(0) - ret.append((old_signal, new_signal)) - - for name in groups: - old_signal = events.pop(0) - new_signal = events.pop(0) - ret.append((old_signal, new_signal)) - - assert len(events) == 0 - - if expect_more is not None: - return ret, more - - return ret - -def check_contact_list_signals(q, bus, conn, signals, - ht, name, contacts, lp_contacts=[], rp_contacts=[]): - """ - Looks at NewChannel and NewChannels signals for the contact list with ID - 'name' and checks that its members, lp members and rp members are exactly - 'contacts', 'lp_contacts' and 'rp_contacts'. - Returns a proxy for the channel. - """ - old_signal, new_signal = signals - - path, type, handle_type, handle, suppress_handler = old_signal.args - - assertEquals(cs.CHANNEL_TYPE_CONTACT_LIST, type) - assertEquals(name, conn.InspectHandles(handle_type, [handle])[0]) - - chan = wrap_channel(bus.get_object(conn.bus_name, path), - cs.CHANNEL_TYPE_CONTACT_LIST) - members = chan.Group.GetMembers() - - assertEquals(sorted(contacts), - sorted(conn.InspectHandles(cs.HT_CONTACT, members))) - - lp_handles = conn.RequestHandles(cs.HT_CONTACT, lp_contacts) - rp_handles = conn.RequestHandles(cs.HT_CONTACT, rp_contacts) - - # NB. comma: we're unpacking args. Thython! - info, = new_signal.args - assertLength(1, info) # one channel - path_, emitted_props = info[0] - - assertEquals(path_, path) - - assertEquals(cs.CHANNEL_TYPE_CONTACT_LIST, emitted_props[cs.CHANNEL_TYPE]) - assertEquals(ht, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals(handle, emitted_props[cs.TARGET_HANDLE]) - - channel_props = chan.Properties.GetAll(cs.CHANNEL) - assertEquals(handle, channel_props.get('TargetHandle')) - assertEquals(ht, channel_props.get('TargetHandleType')) - assertEquals(cs.CHANNEL_TYPE_CONTACT_LIST, channel_props.get('ChannelType')) - assertContains(cs.CHANNEL_IFACE_GROUP, channel_props.get('Interfaces')) - assertEquals(name, channel_props['TargetID']) - assertEquals(False, channel_props['Requested']) - assertEquals('', channel_props['InitiatorID']) - assertEquals(0, channel_props['InitiatorHandle']) - - group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) - assertContains('HandleOwners', group_props) - assertContains('Members', group_props) - assertEquals(members, group_props['Members']) - assertContains('LocalPendingMembers', group_props) - actual_lp_handles = [x[0] for x in group_props['LocalPendingMembers']] - assertEquals(sorted(lp_handles), sorted(actual_lp_handles)) - assertContains('RemotePendingMembers', group_props) - assertEquals(sorted(rp_handles), sorted(group_props['RemotePendingMembers'])) - assertContains('GroupFlags', group_props) - - return chan + + return True + +# function to pass as a 'BlockedContactsChanged' dbus-signal even predicate +# checking if the @blocked and @unblocked contacts match those from the +# signal +def blocked_contacts_changed_predicate(e, blocked, unblocked): + b, u = e.args + + return set(b.values()) == set(blocked) and set(u.values()) == set(unblocked) + +# function to pass as a 'GroupsCreated' dbus-signal even predicate +# checking if the created @groups match those from the signal +def groups_created_predicate(e, groups): + return set(e.args[0]) == set(groups) + +# function to pass as a 'GroupsChanged' dbus-signal even predicate +# checking if @contacts have been added/removed to/from the @added/@removed +# groups +def groups_changed_predicate(e, conn, contacts, added, removed): + c, a, r = e.args + handles = conn.get_contact_handles_sync(contacts) + + return set(handles) == set(c) and set(added) == set(a) and set(removed) == set(r) diff --git a/tests/twisted/run-test.sh.in b/tests/twisted/run-test.sh.in index 8dd5fd660..5392397a7 100644 --- a/tests/twisted/run-test.sh.in +++ b/tests/twisted/run-test.sh.in @@ -11,7 +11,7 @@ if test "x$GABBLE_TEST_UNINSTALLED" = x; then test_build="@gabbletestsdir@" config_file="@gabbletestsdir@/twisted/tools/servicedir/tmp-session-bus.conf" - PYTHONPATH="@gabbletestsdir@/twisted" + PYTHONPATH="@gabbletestsdir@/twisted:@gabbletestsdir@/twisted/jingle" export PYTHONPATH GABBLE_TWISTED_PATH="@gabbletestsdir@/twisted" @@ -31,6 +31,8 @@ else config_file="${test_build}/twisted/tools/servicedir-uninstalled/tmp-session-bus.conf" PYTHONPATH="${test_src}/twisted:${test_build}/twisted" + PYTHONPATH="$PYTHONPATH:${test_src}/twisted/jingle" + PYTHONPATH="$PYTHONPATH:${test_build}/twisted/jingle" export PYTHONPATH GABBLE_TWISTED_PATH="${test_src}/twisted" diff --git a/tests/twisted/sasl/abort.py b/tests/twisted/sasl/abort.py index 1cb03f311..9b00678fc 100644 --- a/tests/twisted/sasl/abort.py +++ b/tests/twisted/sasl/abort.py @@ -2,9 +2,7 @@ Test the server sasl aborting at different stages """ -import dbus - -from servicetest import EventPattern, assertEquals +from servicetest import EventPattern from gabbletest import exec_test, call_async import constants as cs from saslutil import SaslEventAuthenticator, connect_and_get_sasl_channel, \ diff --git a/tests/twisted/sasl/close.py b/tests/twisted/sasl/close.py index b50a7aee7..079d8d048 100644 --- a/tests/twisted/sasl/close.py +++ b/tests/twisted/sasl/close.py @@ -1,7 +1,5 @@ """Test the SASL channel being undispatchable.""" -import dbus - from servicetest import EventPattern from gabbletest import exec_test import constants as cs diff --git a/tests/twisted/sasl/complex.py b/tests/twisted/sasl/complex.py index c290cd83d..ac550db7d 100644 --- a/tests/twisted/sasl/complex.py +++ b/tests/twisted/sasl/complex.py @@ -3,7 +3,7 @@ Test the server sasl channel with the PLAIN mechanism """ import dbus -from servicetest import EventPattern, assertEquals, assertSameSets, call_async +from servicetest import EventPattern, assertSameSets, call_async from gabbletest import exec_test import constants as cs from saslutil import SaslEventAuthenticator, connect_and_get_sasl_channel @@ -108,7 +108,7 @@ def test_complex_success(q, bus, conn, stream, with_extra_data=True, args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) chan.Close() # ... and check that the Connection is still OK - conn.GetSelfHandle() + conn.Properties.Get(cs.CONN, "SelfHandle") def test_complex_success_data(q, bus, conn, stream): test_complex_success(q, bus, conn, stream, True) diff --git a/tests/twisted/sasl/jabber_auth.py b/tests/twisted/sasl/jabber_auth.py index 6857f06a7..d4e47eae7 100644 --- a/tests/twisted/sasl/jabber_auth.py +++ b/tests/twisted/sasl/jabber_auth.py @@ -2,20 +2,14 @@ Test the server sasl channel with Jabber auth pseudomechanisms """ -from twisted.words.xish import domish -from twisted.words.protocols.jabber import xmlstream from twisted.words.protocols.jabber.client import IQ -import hashlib - -import dbus - -from servicetest import (EventPattern, assertEquals, assertSameSets, +from servicetest import (assertEquals, assertSameSets, assertContains) from gabbletest import exec_test, JabberXmlStream, JabberAuthenticator import constants as cs import ns -from saslutil import expect_sasl_channel, abort_auth +from saslutil import expect_sasl_channel JID = "test@localhost" PASSWORD = "pass" diff --git a/tests/twisted/sasl/plain.py b/tests/twisted/sasl/plain.py index 2a3a24eee..7bdd6ca3b 100644 --- a/tests/twisted/sasl/plain.py +++ b/tests/twisted/sasl/plain.py @@ -2,13 +2,6 @@ Test the server sasl channel with the PLAIN mechanism """ -from twisted.words.xish import domish -from twisted.words.protocols.jabber import xmlstream - -from base64 import b64decode - -import dbus - from servicetest import EventPattern, assertEquals, assertContains, call_async from gabbletest import exec_test import constants as cs diff --git a/tests/twisted/sasl/saslutil.py b/tests/twisted/sasl/saslutil.py index 7d146146c..fcbd8f9e5 100644 --- a/tests/twisted/sasl/saslutil.py +++ b/tests/twisted/sasl/saslutil.py @@ -89,22 +89,14 @@ def connect_and_get_sasl_channel(q, bus, conn): return expect_sasl_channel(q, bus, conn) def expect_sasl_channel(q, bus, conn): - old_signal, new_signal = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel', - predicate=lambda e: - e.args[1] == cs.CHANNEL_TYPE_SERVER_AUTHENTICATION), - EventPattern('dbus-signal', signal='NewChannels', - predicate=lambda e: - e.args[0][0][1].get(cs.CHANNEL_TYPE) == - cs.CHANNEL_TYPE_SERVER_AUTHENTICATION), - ) - - path, type, handle_type, handle, suppress_handler = old_signal.args + new_signal = q.expect('dbus-signal', signal='NewChannels', + predicate=lambda e: e.args[0][0][1].get(cs.CHANNEL_TYPE) == + cs.CHANNEL_TYPE_SERVER_AUTHENTICATION) + + path, props = new_signal.args[0][0] chan = SaslChannelWrapper(bus.get_object(conn.bus_name, path)) assertLength(1, new_signal.args[0]) - assertEquals(path, new_signal.args[0][0][0]) - props = new_signal.args[0][0][1] assertEquals(cs.CHANNEL_IFACE_SASL_AUTH, props.get(cs.AUTH_METHOD)) return chan, props diff --git a/tests/twisted/sasl/telepathy-password.py b/tests/twisted/sasl/telepathy-password.py index 533dae7ef..65a3cd48f 100644 --- a/tests/twisted/sasl/telepathy-password.py +++ b/tests/twisted/sasl/telepathy-password.py @@ -42,7 +42,7 @@ def test_close_straight_after_accept(q, bus, conn, stream): interface=cs.CHANNEL_IFACE_SASL_AUTH, args=[cs.SASL_STATUS_SUCCEEDED, '', {}]) - e = q.expect('dbus-signal', signal='StatusChanged', + q.expect('dbus-signal', signal='StatusChanged', args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) if __name__ == '__main__': diff --git a/tests/twisted/servicetest.py b/tests/twisted/servicetest.py index 31c00f476..5ff61a468 100644 --- a/tests/twisted/servicetest.py +++ b/tests/twisted/servicetest.py @@ -1,6 +1,23 @@ +# Copyright (C) 2009 Nokia Corporation +# Copyright (C) 2009-2013 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 """ -Infrastructure code for testing connection managers. +Infrastructure code for testing Telepathy services. """ from twisted.internet import glib2reactor @@ -13,14 +30,17 @@ import os import pprint import unittest -import dbus.glib +import dbus +import dbus.lowlevel +from dbus.mainloop.glib import DBusGMainLoop +DBusGMainLoop(set_as_default=True) from twisted.internet import reactor import constants as cs -tp_name_prefix = 'org.freedesktop.Telepathy' -tp_path_prefix = '/org/freedesktop/Telepathy' +tp_name_prefix = cs.PREFIX +tp_path_prefix = cs.PATH_PREFIX class DictionarySupersetOf (object): """Utility class for expecting "a dictionary with at least these keys".""" @@ -177,7 +197,14 @@ class BaseEventQueue: t = time.time() while True: - event = self.wait([pattern.subqueue]) + try: + event = self.wait([pattern.subqueue]) + except TimeoutError: + self.log('timeout') + self.log('still expecting:') + self.log(' - %r' % pattern) + raise + self._check_forbidden(event) if pattern.match(event): @@ -289,6 +316,11 @@ class IteratingEventQueue(BaseEventQueue): def __init__(self, timeout=None): BaseEventQueue.__init__(self, timeout) + self._dbus_method_impls = [] + self._buses = [] + # a message filter which will claim we handled everything + self._dbus_dev_null = \ + lambda bus, message: dbus.lowlevel.HANDLER_RESULT_HANDLED def wait(self, queues=None): stop = [False] @@ -313,6 +345,127 @@ class IteratingEventQueue(BaseEventQueue): else: raise TimeoutError + def add_dbus_method_impl(self, cb, bus=None, **kwargs): + if bus is None: + bus = self._buses[0] + + self._dbus_method_impls.append( + (EventPattern('dbus-method-call', **kwargs), cb)) + + def dbus_emit(self, path, iface, name, *a, **k): + bus = k.pop('bus', self._buses[0]) + assert 'signature' in k, k + message = dbus.lowlevel.SignalMessage(path, iface, name) + message.append(*a, **k) + bus.send_message(message) + + def dbus_return(self, in_reply_to, *a, **k): + bus = k.pop('bus', self._buses[0]) + assert 'signature' in k, k + reply = dbus.lowlevel.MethodReturnMessage(in_reply_to) + reply.append(*a, **k) + bus.send_message(reply) + + def dbus_raise(self, in_reply_to, name, message=None, bus=None): + if bus is None: + bus = self._buses[0] + + reply = dbus.lowlevel.ErrorMessage(in_reply_to, name, message) + bus.send_message(reply) + + def attach_to_bus(self, bus): + if not self._buses: + # first-time setup + self._dbus_filter_bound_method = self._dbus_filter + + self._buses.append(bus) + + # Only subscribe to messages on the first bus connection (assumed to + # be the shared session bus connection used by the simulated connection + # manager and most of the test suite), not on subsequent bus + # connections (assumed to represent extra clients). + # + # When we receive a method call on the other bus connections, ignore + # it - the eavesdropping filter installed on the first bus connection + # will see it too. + # + # This is highly counter-intuitive, but it means our messages are in + # a guaranteed order (we don't have races between messages arriving on + # various connections). + if len(self._buses) > 1: + bus.add_message_filter(self._dbus_dev_null) + return + + try: + # for dbus > 1.5 + bus.add_match_string("eavesdrop=true,type='signal'") + except dbus.DBusException: + bus.add_match_string("type='signal'") + bus.add_match_string("type='method_call'") + else: + bus.add_match_string("eavesdrop=true,type='method_call'") + + bus.add_message_filter(self._dbus_filter_bound_method) + + bus.add_signal_receiver( + lambda *args, **kw: + self.append( + Event('dbus-signal', + path=unwrap(kw['path']), + signal=kw['member'], + args=map(unwrap, args), + interface=kw['interface'])), + None, + None, + None, + path_keyword='path', + member_keyword='member', + interface_keyword='interface', + byte_arrays=True, + ) + + def cleanup(self): + if self._buses: + self._buses[0].remove_message_filter(self._dbus_filter_bound_method) + for bus in self._buses[1:]: + bus.remove_message_filter(self._dbus_dev_null) + + self._buses = [] + self._dbus_method_impls = [] + + def _dbus_filter(self, bus, message): + if isinstance(message, dbus.lowlevel.MethodCallMessage): + + destination = message.get_destination() + sender = message.get_sender() + + if (destination == 'org.freedesktop.DBus' or + sender == self._buses[0].get_unique_name()): + # suppress reply and don't make an Event + return dbus.lowlevel.HANDLER_RESULT_HANDLED + + e = Event('dbus-method-call', message=message, + interface=message.get_interface(), path=message.get_path(), + raw_args=message.get_args_list(byte_arrays=True), + args=map(unwrap, message.get_args_list(byte_arrays=True)), + destination=str(destination), + method=message.get_member(), + sender=message.get_sender(), + handled=False) + + for pair in self._dbus_method_impls: + pattern, cb = pair + if pattern.match(e): + cb(e) + e.handled = True + break + + self.append(e) + + return dbus.lowlevel.HANDLER_RESULT_HANDLED + + return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED + class TestEventQueue(BaseEventQueue): def __init__(self, events): BaseEventQueue.__init__(self) @@ -423,17 +576,13 @@ def call_async(test, proxy, method, *args, **kw): kw.update({'reply_handler': reply_func, 'error_handler': error_func}) method_proxy(*args, **kw) -def sync_dbus(bus, q, conn): +def sync_dbus(bus, q, proxy): # Dummy D-Bus method call. We can't use DBus.Peer.Ping() because libdbus # replies to that message immediately, rather than handing it up to - # dbus-glib and thence Gabble, which means that Ping()ing Gabble doesn't - # ensure that it's processed all D-Bus messages prior to our ping. - # - # This won't do the right thing unless the proxy has a unique name. - assert conn.object.bus_name.startswith(':') - root_object = bus.get_object(conn.object.bus_name, '/', introspect=False) - call_async(q, - dbus.Interface(root_object, 'org.freedesktop.Telepathy.Tests'), + # dbus-glib and thence the application, which means that Ping()ing the + # application doesn't ensure that it's processed all D-Bus messages prior + # to our ping. + call_async(q, dbus.Interface(proxy, 'org.freedesktop.Telepathy.Tests'), 'DummySyncDBus') q.expect('dbus-error', method='DummySyncDBus') @@ -457,8 +606,25 @@ class ProxyWrapper: return getattr(self.default_interface, name) +class ConnWrapper(ProxyWrapper): + def inspect_contact_sync(self, handle): + return self.inspect_contacts_sync([handle])[0] + + def inspect_contacts_sync(self, handles): + h2asv = self.Contacts.GetContactAttributes(handles, [], True) + ret = [] + for h in handles: + ret.append(h2asv[h][cs.ATTR_CONTACT_ID]) + return ret + + def get_contact_handle_sync(self, identifier): + return self.Contacts.GetContactByID(identifier, [])[0] + + def get_contact_handles_sync(self, ids): + return [self.get_contact_handle_sync(i) for i in ids] + def wrap_connection(conn): - return ProxyWrapper(conn, tp_name_prefix + '.Connection', + return ConnWrapper(conn, tp_name_prefix + '.Connection', dict([ (name, tp_name_prefix + '.Connection.Interface.' + name) for name in ['Aliasing', 'Avatars', 'Capabilities', 'Contacts', @@ -467,18 +633,37 @@ def wrap_connection(conn): ('ContactCapabilities', cs.CONN_IFACE_CONTACT_CAPS), ('ContactInfo', cs.CONN_IFACE_CONTACT_INFO), ('Location', cs.CONN_IFACE_LOCATION), - ('Future', tp_name_prefix + '.Connection.FUTURE'), ('MailNotification', cs.CONN_IFACE_MAIL_NOTIFICATION), ('ContactList', cs.CONN_IFACE_CONTACT_LIST), ('ContactGroups', cs.CONN_IFACE_CONTACT_GROUPS), + ('ContactBlocking', cs.CONN_IFACE_CONTACT_BLOCKING), ('PowerSaving', cs.CONN_IFACE_POWER_SAVING), ('Addressing', cs.CONN_IFACE_ADDRESSING), + ('ClientTypes', cs.CONN_IFACE_CLIENT_TYPES), + ('Renaming', cs.CONN_IFACE_RENAMING), + ('Sidecars1', cs.CONN_IFACE_SIDECARS1), ])) +class ChannelWrapper(ProxyWrapper): + def send_msg_sync(self, txt): + message = [ + { 'message-type': cs.MT_NORMAL, }, + { 'content-type': 'text/plain', + 'content': txt + }] + self.Messages.SendMessage(message, 0) + def wrap_channel(chan, type_, extra=None): interfaces = { type_: tp_name_prefix + '.Channel.Type.' + type_, - 'Group': tp_name_prefix + '.Channel.Interface.Group', + 'Channel': cs.CHANNEL, + 'Group': cs.CHANNEL_IFACE_GROUP, + 'Hold': cs.CHANNEL_IFACE_HOLD, + 'Messages': cs.CHANNEL_IFACE_MESSAGES, + 'RoomConfig1': cs.CHANNEL_IFACE_ROOM_CONFIG, + 'ChatState': cs.CHANNEL_IFACE_CHAT_STATE, + 'Destroyable': cs.CHANNEL_IFACE_DESTROYABLE, + 'Password': cs.CHANNEL_IFACE_PASSWORD, } if extra: @@ -486,11 +671,14 @@ def wrap_channel(chan, type_, extra=None): (name, tp_name_prefix + '.Channel.Interface.' + name) for name in extra])) - return ProxyWrapper(chan, tp_name_prefix + '.Channel', interfaces) + return ChannelWrapper(chan, tp_name_prefix + '.Channel', interfaces) def wrap_content(chan, extra=None): - interfaces = { } + interfaces = { + 'DTMF': cs.CALL_CONTENT_IFACE_DTMF, + 'Media': cs.CALL_CONTENT_IFACE_MEDIA, + } if extra: interfaces.update(dict([ diff --git a/tests/twisted/sidecar-own-caps.py b/tests/twisted/sidecar-own-caps.py index 3cbed76fb..9e8b9cdfb 100644 --- a/tests/twisted/sidecar-own-caps.py +++ b/tests/twisted/sidecar-own-caps.py @@ -5,14 +5,14 @@ Test Gabble's implementation of sidecars own caps, using the test plugin. from twisted.words.protocols.jabber.client import IQ from twisted.words.xish import xpath -from servicetest import call_async, EventPattern, assertEquals, assertContains +from servicetest import call_async, EventPattern, assertEquals from gabbletest import exec_test, acknowledge_iq from caps_helper import compute_caps_hash import constants as cs import ns from config import PLUGINS_ENABLED -TEST_PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Test" +TEST_PLUGIN_IFACE = cs.PREFIX + ".Gabble.Plugin.Test" if not PLUGINS_ENABLED: print "NOTE: built without --enable-plugins, skipping" @@ -23,7 +23,7 @@ def test(q, bus, conn, stream): # created. pattern = EventPattern('stream-iq', to='sidecar.example.com', query_ns='http://example.com/sidecar') - call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") + call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] # The server said yes, so we should get a sidecar back! @@ -35,7 +35,6 @@ def test(q, bus, conn, stream): ver = compute_caps_hash(identities, features, {}) iq = IQ(stream, "get") - id = iq['id'] query = iq.addElement((ns.DISCO_INFO, 'query')) query['node'] = ns.GABBLE_CAPS + '#' + ver stream.send(iq) diff --git a/tests/twisted/sidecars.py b/tests/twisted/sidecars.py index caeed8dda..00b8c56af 100644 --- a/tests/twisted/sidecars.py +++ b/tests/twisted/sidecars.py @@ -9,7 +9,7 @@ from gabbletest import exec_test, send_error_reply, acknowledge_iq, sync_stream import constants as cs from config import PLUGINS_ENABLED -TEST_PLUGIN_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Test" +TEST_PLUGIN_IFACE = cs.PREFIX + ".Gabble.Plugin.Test" if not PLUGINS_ENABLED: print "NOTE: built without --enable-plugins, not testing plugins" @@ -18,7 +18,7 @@ if not PLUGINS_ENABLED: def test(q, bus, conn, stream): # Request a sidecar thate we support before we're connected; it should just # wait around until we're connected. - call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE) + call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE) if PLUGINS_ENABLED: # Now we're connected, the call we made earlier should return. @@ -28,30 +28,30 @@ def test(q, bus, conn, stream): assertEquals({}, props) # We should get the same sidecar if we request it again - path2, props2 = conn.Future.EnsureSidecar(TEST_PLUGIN_IFACE) + path2, props2 = conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE) assertEquals((path, props), (path2, props2)) else: # Only now does it fail. q.expect('dbus-error', method='EnsureSidecar') # This is not a valid interface name - call_async(q, conn.Future, 'EnsureSidecar', 'not an interface') + call_async(q, conn.Sidecars1, 'EnsureSidecar', 'not an interface') q.expect('dbus-error', name=cs.INVALID_ARGUMENT) # The test plugin makes no reference to this interface. - call_async(q, conn.Future, 'EnsureSidecar', 'unsupported.sidecar') + call_async(q, conn.Sidecars1, 'EnsureSidecar', 'unsupported.sidecar') q.expect('dbus-error', name=cs.NOT_IMPLEMENTED) if PLUGINS_ENABLED: # This sidecar does have some properties: - path, props = conn.Future.EnsureSidecar(TEST_PLUGIN_IFACE + ".Props") + path, props = conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE + ".Props") assertContains(TEST_PLUGIN_IFACE + ".Props.Greeting", props) # The plugin claims it implements this sidecar, but actually doesn't. # Check that we don't blow up (although this is no different from # Gabble's perspective to creating a sidecar failing because a network # service wasn't there, for instance). - call_async(q, conn.Future, 'EnsureSidecar', + call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".Buggy") q.expect('dbus-error', name=cs.NOT_IMPLEMENTED) @@ -59,7 +59,7 @@ def test(q, bus, conn, stream): # created. pattern = EventPattern('stream-iq', to='sidecar.example.com', query_ns='http://example.com/sidecar') - call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") + call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] sync_dbus(bus, q, conn) @@ -70,7 +70,7 @@ def test(q, bus, conn, stream): # Let's try again. The plugin should get a chance to ping the server # again. - call_async(q, conn.Future, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") + call_async(q, conn.Sidecars1, 'EnsureSidecar', TEST_PLUGIN_IFACE + ".IQ") e = q.expect_many(pattern)[0] # The server said yes, so we should get a sidecar back! @@ -80,7 +80,7 @@ def test(q, bus, conn, stream): # If we ask again once the plugin has been created, it should return at # once without any more network traffic. q.forbid_events([pattern]) - conn.Future.EnsureSidecar(TEST_PLUGIN_IFACE + ".IQ") + conn.Sidecars1.EnsureSidecar(TEST_PLUGIN_IFACE + ".IQ") sync_stream(q, stream) # TODO: test ensuring a sidecar that waits for something from the @@ -96,7 +96,7 @@ def test(q, bus, conn, stream): EventPattern('stream-closed'), ) - call_async(q, conn.Future, 'EnsureSidecar', 'zomg.what') + call_async(q, conn.Sidecars1, 'EnsureSidecar', 'zomg.what') # With older telepathy-glib this would be DISCONNECTED; # with newer telepathy-glib the Connection disappears from the bus # sooner, and you get UnknownMethod or something from dbus-glib. diff --git a/tests/twisted/test-debug.py b/tests/twisted/test-debug.py index d9c18183e..6c079a32c 100644 --- a/tests/twisted/test-debug.py +++ b/tests/twisted/test-debug.py @@ -3,15 +3,10 @@ Test the debug message interface. """ -import dbus - from servicetest import assertEquals, sync_dbus, call_async, ProxyWrapper from servicetest import EventPattern from gabbletest import exec_test import constants as cs -from config import DEBUGGING -path = '/org/freedesktop/Telepathy/debug' -iface = 'org.freedesktop.Telepathy.Debug' def test(q, bus, conn, stream): messages = [] @@ -19,35 +14,30 @@ def test(q, bus, conn, stream): def new_message(timestamp, domain, level, string): messages.append((timestamp, domain, level, string)) - debug = ProxyWrapper(bus.get_object(conn.bus_name, path), iface) + debug = ProxyWrapper(bus.get_object(conn.bus_name, cs.DEBUG_PATH), + cs.DEBUG_IFACE) debug.connect_to_signal('NewDebugMessage', new_message) - if not DEBUGGING: - # If we're built with --disable-debug, check that the Debug object - # isn't present. - call_async(q, debug, 'GetMessages') - q.expect('dbus-error', method='GetMessages') - return - assert len(debug.GetMessages()) > 0 # Turn signalling on and generate some messages. assert len(messages) == 0 - assert debug.Properties.Get(iface, 'Enabled') == False - debug.Properties.Set(iface, 'Enabled', True) + assert debug.Properties.Get(cs.DEBUG_IFACE, 'Enabled') == False + debug.Properties.Set(cs.DEBUG_IFACE, 'Enabled', True) - channel_path = conn.RequestChannel( - cs.CHANNEL_TYPE_TEXT, cs.HT_CONTACT, conn.GetSelfHandle(), True) - q.expect_many( - EventPattern ('dbus-signal', signal='NewChannel'), - EventPattern ('dbus-signal', signal = 'NewDebugMessage')) + channel_path, props = conn.Requests.CreateChannel({ + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_HANDLE: conn.Properties.Get(cs.CONN, "SelfHandle") + }) + q.expect('dbus-signal', signal = 'NewDebugMessage') assert len(messages) > 0 # Turn signalling off and check we don't get any more messages. - debug.Properties.Set(iface, 'Enabled', False) + debug.Properties.Set(cs.DEBUG_IFACE, 'Enabled', False) sync_dbus(bus, q, conn) snapshot = list(messages) @@ -55,9 +45,12 @@ def test(q, bus, conn, stream): channel.Close(dbus_interface=cs.CHANNEL) q.expect('dbus-signal', signal='Closed') - conn.RequestChannel( - cs.CHANNEL_TYPE_TEXT, cs.HT_CONTACT, conn.GetSelfHandle(), True) - q.expect('dbus-signal', signal='NewChannel') + channel_path, props = conn.Requests.CreateChannel({ + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_HANDLE: conn.Properties.Get(cs.CONN, "SelfHandle") + }) + q.expect('dbus-signal', signal='NewChannels') assertEquals (snapshot, messages) diff --git a/tests/twisted/test-fallback-socks5-proxy.py b/tests/twisted/test-fallback-socks5-proxy.py index d6ae78cb0..275352d43 100644 --- a/tests/twisted/test-fallback-socks5-proxy.py +++ b/tests/twisted/test-fallback-socks5-proxy.py @@ -2,7 +2,7 @@ import socket from gabbletest import ( - exec_test, elem, elem_iq, sync_stream, make_presence, send_error_reply, + exec_test, elem, elem_iq, make_presence, send_error_reply, make_result_iq, sync_stream) from servicetest import ( EventPattern, call_async, assertEquals, assertLength, diff --git a/tests/twisted/test-location.py b/tests/twisted/test-location.py index cb1817321..2a29700ab 100644 --- a/tests/twisted/test-location.py +++ b/tests/twisted/test-location.py @@ -17,6 +17,10 @@ import ns Rich_Presence_Access_Control_Type_Publish_List = 1 +def get_location(conn, contact): + h2asv = conn.Contacts.GetContactAttributes([contact], [cs.CONN_IFACE_LOCATION], False) + return h2asv[contact].get(cs.ATTR_LOCATION) + def test(q, bus, conn, stream): # we don't yet know we have PEP assertEquals(0, conn.Get(cs.CONN_IFACE_LOCATION, @@ -158,8 +162,7 @@ def test(q, bus, conn, stream): q.expect('dbus-error', method='SetLocation') # Request Bob's location - bob_handle = conn.RequestHandles(1, ['bob@foo.com'])[0] - call_async(q, conn.Location, 'GetLocations', [bob_handle]) + bob_handle = conn.get_contact_handle_sync('bob@foo.com') # Gabble should not send a pubsub query. The point of PEP is that we don't # have to do this. @@ -167,11 +170,9 @@ def test(q, bus, conn, stream): query_ns=ns.PUBSUB) q.forbid_events([ pubsub_get_pattern ]) - # GetLocations returns immediately. - get_locations = q.expect('dbus-return', method='GetLocations') - locations = get_locations.value[0] + location = get_location(conn, bob_handle) # Location isn't known yet - assertLength(0, locations) + assertEquals(None, location) # Sync the XMPP stream to ensure Gabble hasn't sent a query. sync_stream(q, stream) @@ -210,11 +211,10 @@ def test(q, bus, conn, stream): assertEquals(location['timestamp'], date) # Get location again; Gabble should return the cached location - locations = conn.Location.GetLocations([bob_handle]) - assertLength(1, locations) - assertEquals(locations[bob_handle], location) + loc = get_location(conn, bob_handle) + assertEquals(loc, location) - charles_handle = conn.RequestHandles(cs.HT_CONTACT, ['charles@foo.com'])[0] + charles_handle = conn.get_contact_handle_sync('charles@foo.com') # check that Contacts interface supports location attributes = conn.Contacts.GetContactAttributes( diff --git a/tests/twisted/text/destroy.py b/tests/twisted/text/destroy.py index f51a4c29c..0504d1d32 100644 --- a/tests/twisted/text/destroy.py +++ b/tests/twisted/text/destroy.py @@ -8,38 +8,29 @@ import dbus from twisted.words.xish import domish from gabbletest import exec_test -from servicetest import call_async, EventPattern +from servicetest import call_async, EventPattern, wrap_channel, assertEquals import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'foo@bar.com' - call_async(q, conn, 'RequestHandles', 1, [jid]) + foo_handle = conn.get_contact_handle_sync(jid) - event = q.expect('dbus-return', method='RequestHandles') - foo_handle = event.value[0][0] + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_HANDLE: foo_handle }) - call_async(q, conn, 'RequestChannel', - cs.CHANNEL_TYPE_TEXT, cs.HT_CONTACT, foo_handle, True) - - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), + ret, new_sig = q.expect_many( + EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) - text_chan = bus.get_object(conn.bus_name, ret.value[0]) + text_chan = wrap_channel(bus.get_object(conn.bus_name, ret.value[0]), 'Text') chan_iface = dbus.Interface(text_chan, cs.CHANNEL) - text_iface = dbus.Interface(text_chan, cs.CHANNEL_TYPE_TEXT) destroyable_iface = dbus.Interface(text_chan, cs.CHANNEL_IFACE_DESTROYABLE) - assert old_sig.args[0] == ret.value[0] - assert old_sig.args[1] == cs.CHANNEL_TYPE_TEXT - assert old_sig.args[2] == cs.HT_CONTACT - assert old_sig.args[3] == foo_handle - assert old_sig.args[4] == True # suppress handler - assert len(new_sig.args) == 1 assert len(new_sig.args[0]) == 1 # one channel assert len(new_sig.args[0][0]) == 2 # two struct members @@ -62,7 +53,7 @@ def test(q, bus, conn, stream): assert channel_props['InitiatorID'] == 'test@localhost',\ channel_props['InitiatorID'] - text_iface.Send(0, 'hey') + text_chan.send_msg_sync('hey') event = q.expect('stream-message') @@ -80,23 +71,14 @@ def test(q, bus, conn, stream): m.addElement('body', content='hello') stream.send(m) - event = q.expect('dbus-signal', signal='Received') - - hello_message_id = event.args[0] - hello_message_time = event.args[1] - assert event.args[2] == foo_handle - # message type: normal - assert event.args[3] == 0 - # flags: none - assert event.args[4] == 0 - # body - assert event.args[5] == 'hello' - - messages = text_chan.ListPendingMessages(False, - dbus_interface=cs.CHANNEL_TYPE_TEXT) - assert messages == \ - [(hello_message_id, hello_message_time, foo_handle, - 0, 0, 'hello')], messages + event = q.expect('dbus-signal', signal='MessageReceived') + + msg = event.args[0] + assertEquals(foo_handle, msg[0]['message-sender']) + assertEquals('hello', msg[1]['content']) + + messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages') + assertEquals([msg], messages) # destroy the channel without acking the message; it does not come back diff --git a/tests/twisted/text/ensure.py b/tests/twisted/text/ensure.py index e29906ebc..fcef90a69 100644 --- a/tests/twisted/text/ensure.py +++ b/tests/twisted/text/ensure.py @@ -9,13 +9,10 @@ from servicetest import call_async, EventPattern import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jids = ['foo@bar.com', 'truc@cafe.fr'] - call_async(q, conn, 'RequestHandles', 1, jids) - - event = q.expect('dbus-return', method='RequestHandles') - handles = event.value[0] + handles = conn.get_contact_handles_sync(jids) properties = conn.GetAll( cs.CONN_IFACE_REQUESTS, dbus_interface=cs.PROPERTIES_IFACE) @@ -39,9 +36,8 @@ def test_ensure_ensure(q, conn, self_handle, jid, handle): # Check that Ensuring a channel that doesn't exist succeeds call_async(q, conn.Requests, 'EnsureChannel', request_props (handle)) - 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'), ) @@ -54,15 +50,6 @@ def test_ensure_ensure(q, conn, self_handle, jid, handle): check_props(emitted_props, self_handle, handle, jid) - assert len(old_sig.args) == 5 - old_path, old_ct, old_ht, old_h, old_sh = old_sig.args - - assert old_path == path - assert old_ct == cs.CHANNEL_TYPE_TEXT - assert old_ht == cs.HT_CONTACT - assert old_h == handle - assert old_sh == True # suppress handler - assert len(new_sig.args) == 1 assert len(new_sig.args[0]) == 1 # one channel assert len(new_sig.args[0][0]) == 2 # two struct members @@ -98,9 +85,8 @@ def test_request_ensure(q, conn, self_handle, jid, handle): call_async(q, conn.Requests, 'CreateChannel', request_props(handle)) - ret, old_sig, new_sig = q.expect_many( + ret, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) @@ -109,15 +95,6 @@ def test_request_ensure(q, conn, self_handle, jid, handle): check_props(emitted_props, self_handle, handle, jid) - assert len(old_sig.args) == 5 - old_path, old_ct, old_ht, old_h, old_sh = old_sig.args - - assert old_path == path - assert old_ct == cs.CHANNEL_TYPE_TEXT - assert old_ht == cs.HT_CONTACT - assert old_h == handle - assert old_sh == True # suppress handler - assert len(new_sig.args) == 1 assert len(new_sig.args[0]) == 1 # one channel assert len(new_sig.args[0][0]) == 2 # two struct members diff --git a/tests/twisted/text/facebook-own-message.py b/tests/twisted/text/facebook-own-message.py index a695b3d92..5aaa14359 100644 --- a/tests/twisted/text/facebook-own-message.py +++ b/tests/twisted/text/facebook-own-message.py @@ -51,7 +51,7 @@ def test(q, bus, conn, stream): echo = header['delivery-echo'] echo_header, echo_body = echo - assertEquals(conn.GetSelfHandle(), echo_header['message-sender']) + assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), echo_header['message-sender']) assertEquals('text/plain', echo_body['content-type']) assertEquals(text, echo_body['content']) diff --git a/tests/twisted/text/initiate-requestotron.py b/tests/twisted/text/initiate-requestotron.py index 9bd2b0ab1..c969eaac1 100644 --- a/tests/twisted/text/initiate-requestotron.py +++ b/tests/twisted/text/initiate-requestotron.py @@ -10,10 +10,10 @@ from servicetest import (call_async, EventPattern, assertContains, import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'foo@bar.com' - foo_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + foo_handle = conn.get_contact_handle_sync(jid) properties = conn.GetAll( cs.CONN_IFACE_REQUESTS, dbus_interface=dbus.PROPERTIES_IFACE) @@ -31,9 +31,8 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE: foo_handle, }) - ret, old_sig, new_sig = q.expect_many( + ret, new_sig = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) @@ -51,12 +50,6 @@ def test(q, bus, conn, stream): assertEquals(cs.DELIVERY_REPORTING_SUPPORT_FLAGS_RECEIVE_FAILURES, emitted_props[cs.DELIVERY_REPORTING_SUPPORT]) - assert old_sig.args[0] == ret.value[0] - assert old_sig.args[1] == cs.CHANNEL_TYPE_TEXT - assert old_sig.args[2] == cs.HT_CONTACT - assert old_sig.args[3] == foo_handle - assert old_sig.args[4] == True # suppress handler - assert len(new_sig.args) == 1 assert len(new_sig.args[0]) == 1 # one channel assert len(new_sig.args[0][0]) == 2 # two struct members diff --git a/tests/twisted/text/initiate.py b/tests/twisted/text/initiate.py index edf493c1a..778dd6a58 100644 --- a/tests/twisted/text/initiate.py +++ b/tests/twisted/text/initiate.py @@ -7,35 +7,33 @@ import dbus from twisted.words.xish import domish from gabbletest import exec_test -from servicetest import call_async, EventPattern +from servicetest import call_async, EventPattern, assertEquals, wrap_channel import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'foo@bar.com' - call_async(q, conn, 'RequestHandles', cs.HT_CONTACT, [jid]) + foo_handle = conn.get_contact_handle_sync(jid) - event = q.expect('dbus-return', method='RequestHandles') - foo_handle = event.value[0][0] - - call_async(q, conn, 'RequestChannel', - cs.CHANNEL_TYPE_TEXT, cs.HT_CONTACT, foo_handle, True) + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_HANDLE: foo_handle }) ret, sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), + EventPattern('dbus-return', method='CreateChannel'), + EventPattern('dbus-signal', signal='NewChannels'), ) - text_chan = bus.get_object(conn.bus_name, ret.value[0]) + text_chan = wrap_channel(bus.get_object(conn.bus_name, ret.value[0]), 'Text') - assert sig.args[0] == ret.value[0], \ - (sig.args[0], ret.value[0]) - assert sig.args[1] == cs.CHANNEL_TYPE_TEXT, sig.args[1] + path, props = sig.args[0][0] + assertEquals(ret.value[0], path) + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) # check that handle type == contact handle - assert sig.args[2] == 1, sig.args[1] - assert sig.args[3] == foo_handle, (sig.args[3], foo_handle) - assert sig.args[4] == True # suppress handler + assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE]) + assertEquals(foo_handle, props[cs.TARGET_HANDLE]) # Exercise basic Channel Properties from spec 0.17.7 channel_props = text_chan.GetAll( @@ -58,7 +56,7 @@ def test(q, bus, conn, stream): assert channel_props['InitiatorID'] == 'test@localhost',\ channel_props['InitiatorID'] - dbus.Interface(text_chan, cs.CHANNEL_TYPE_TEXT).Send(0, 'hey') + text_chan.send_msg_sync('hey') event = q.expect('stream-message') @@ -76,14 +74,10 @@ def test(q, bus, conn, stream): m.addElement('body', content='hello') stream.send(m) - event = q.expect('dbus-signal', signal='Received') + event = q.expect('dbus-signal', signal='MessageReceived') - # message type: normal - assert event.args[3] == 0 - # flags: none - assert event.args[4] == 0 - # body - assert event.args[5] == 'hello' + msg = event.args[0] + assertEquals('hello', msg[1]['content']) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/text/receipts.py b/tests/twisted/text/receipts.py index 45c7d9f89..2c11af2e3 100644 --- a/tests/twisted/text/receipts.py +++ b/tests/twisted/text/receipts.py @@ -172,8 +172,7 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_ID: GUYBRUSH, })[0] - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['Messages']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # Let's start out with an empty roster, eh? e = q.expect('stream-iq', iq_type='get', query_ns=ns.ROSTER) diff --git a/tests/twisted/text/respawn.py b/tests/twisted/text/respawn.py index 0ba43571f..bb1b75495 100644 --- a/tests/twisted/text/respawn.py +++ b/tests/twisted/text/respawn.py @@ -7,33 +7,27 @@ import dbus from twisted.words.xish import domish from gabbletest import exec_test -from servicetest import call_async, EventPattern, assertEquals +from servicetest import call_async, EventPattern, assertEquals, wrap_channel import constants as cs def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'foo@bar.com' - foo_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + foo_handle = conn.get_contact_handle_sync(jid) - call_async(q, conn, 'RequestChannel', - cs.CHANNEL_TYPE_TEXT, cs.HT_CONTACT, foo_handle, True) + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, + cs.TARGET_HANDLE: foo_handle }) - ret, old_sig, new_sig = q.expect_many( - EventPattern('dbus-return', method='RequestChannel'), - EventPattern('dbus-signal', signal='NewChannel'), + ret, new_sig = q.expect_many( + EventPattern('dbus-return', method='CreateChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) - text_chan = bus.get_object(conn.bus_name, ret.value[0]) + text_chan = wrap_channel(bus.get_object(conn.bus_name, ret.value[0]), 'Text') chan_iface = dbus.Interface(text_chan, cs.CHANNEL) - text_iface = dbus.Interface(text_chan, cs.CHANNEL_TYPE_TEXT) - - assert old_sig.args[0] == ret.value[0] - assert old_sig.args[1] == cs.CHANNEL_TYPE_TEXT - assert old_sig.args[2] == cs.HT_CONTACT - assert old_sig.args[3] == foo_handle - assert old_sig.args[4] == True # suppress handler assert len(new_sig.args) == 1 assert len(new_sig.args[0]) == 1 # one channel @@ -58,7 +52,7 @@ def test(q, bus, conn, stream): assert channel_props['InitiatorID'] == 'test@localhost',\ channel_props['InitiatorID'] - text_iface.Send(0, 'hey') + text_chan.send_msg_sync('hey') event = q.expect('stream-message') @@ -76,23 +70,14 @@ def test(q, bus, conn, stream): m.addElement('body', content='hello') stream.send(m) - event = q.expect('dbus-signal', signal='Received') + event = q.expect('dbus-signal', signal='MessageReceived') - hello_message_id = event.args[0] - hello_message_time = event.args[1] - assert event.args[2] == foo_handle - # message type: normal - assert event.args[3] == 0 - # flags: none - assert event.args[4] == 0 - # body - assert event.args[5] == 'hello' + msg = event.args[0] + assertEquals(foo_handle, msg[0]['message-sender']) + assertEquals('hello', msg[1]['content']) - messages = text_chan.ListPendingMessages(False, - dbus_interface=cs.CHANNEL_TYPE_TEXT) - assert messages == \ - [(hello_message_id, hello_message_time, foo_handle, - 0, 0, 'hello')], messages + messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages') + assertEquals([msg], messages) # close the channel without acking the message; it comes back @@ -107,12 +92,12 @@ def test(q, bus, conn, stream): assert new.args[0] == text_chan.object_path,\ (new.args[0], text_chan.object_path) - event = q.expect('dbus-signal', signal='NewChannel') - assert event.args[0] == text_chan.object_path - assert event.args[1] == cs.CHANNEL_TYPE_TEXT - assert event.args[2] == cs.HT_CONTACT - assert event.args[3] == foo_handle - assert event.args[4] == False # suppress handler + event = q.expect('dbus-signal', signal='NewChannels') + path, props = event.args[0][0] + assertEquals(text_chan.object_path, path) + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE]) + assertEquals(foo_handle, props[cs.TARGET_HANDLE]) event = q.expect('dbus-return', method='Close') @@ -130,20 +115,16 @@ def test(q, bus, conn, stream): # the message is still there - messages = text_chan.ListPendingMessages(False, - dbus_interface=cs.CHANNEL_TYPE_TEXT) - assertEquals( - [(hello_message_id, hello_message_time, foo_handle, 0, 8, 'hello')], - messages) + messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages') + msg[0]['rescued'] = True + assertEquals([msg], messages) # acknowledge it - text_chan.AcknowledgePendingMessages([hello_message_id], - dbus_interface=cs.CHANNEL_TYPE_TEXT) + text_chan.Text.AcknowledgePendingMessages([msg[0]['pending-message-id']]) - messages = text_chan.ListPendingMessages(False, - dbus_interface=cs.CHANNEL_TYPE_TEXT) - assert messages == [] + messages = text_chan.Properties.Get(cs.CHANNEL_IFACE_MESSAGES, 'PendingMessages') + assertEquals([], messages) # close the channel again diff --git a/tests/twisted/text/send-error.py b/tests/twisted/text/send-error.py index f330c0ae7..40d417f39 100644 --- a/tests/twisted/text/send-error.py +++ b/tests/twisted/text/send-error.py @@ -1,30 +1,25 @@ """ -Test that an incoming <message><error/></> for a contact gives both a SendError -and a delivery report on a 1-1 text channel to that contact. +Test that an incoming <message><error/></> for a contact gives +a delivery report on a 1-1 text channel to that contact. """ from twisted.words.xish import domish from gabbletest import exec_test -from servicetest import call_async, EventPattern import constants as cs import ns def test_temporary_error(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'foo@bar.com' - call_async(q, conn, 'RequestHandles', 1, [jid]) + foo_handle = conn.get_contact_handle_sync(jid) - event = q.expect('dbus-return', method='RequestHandles') - foo_handle = event.value[0][0] - - path = conn.Requests.CreateChannel( + conn.Requests.CreateChannel( { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: foo_handle, })[0] - text_chan = bus.get_object(conn.bus_name, path) # <message from='foo@bar.com' type='error'> # <body>what is up, my good sir?</body> @@ -48,26 +43,10 @@ def test_temporary_error(q, bus, conn, stream): stream.send(m) - send_error, received, message_received = q.expect_many( - EventPattern('dbus-signal', signal='SendError'), - EventPattern('dbus-signal', signal='Received'), - EventPattern('dbus-signal', signal='MessageReceived'), - ) + message_received = q.expect('dbus-signal', signal='MessageReceived') expected_send_error = 4 # Too_Long - assert send_error.args[0] == expected_send_error, send_error.args - # FIXME: It doesn't look like it's possible to know what the original - # message type is, given that the type attribute of <message> is 'error' - # for error reports. - #assert send_error.args[2] == 0, send_error.args - assert send_error.args[3] == message_body, send_error.args - - assert received.args[2] == foo_handle, (received.args, foo_handle) - assert received.args[3] == 4, received.args # Channel_Text_Message_Type_Delivery_Report - assert received.args[4] == 2, received.args # Channel_Text_Message_Flag_Non_Text_Content - assert received.args[5] == '', received.args - delivery_report = message_received.args[0] assert len(delivery_report) == 1, delivery_report header = delivery_report[0] @@ -92,20 +71,16 @@ def test_temporary_error(q, bus, conn, stream): def test_permanent_error(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'wee@ninja.jp' - call_async(q, conn, 'RequestHandles', 1, [jid]) + ninja_handle = conn.get_contact_handle_sync(jid) - event = q.expect('dbus-return', method='RequestHandles') - ninja_handle = event.value[0][0] - - path = conn.Requests.CreateChannel( + conn.Requests.CreateChannel( { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: ninja_handle, })[0] - text_chan = bus.get_object(conn.bus_name, path) # <message from='wee@ninja.jp' type='error'> # <body>hello? is there anyone there?</body> @@ -128,26 +103,10 @@ def test_permanent_error(q, bus, conn, stream): stream.send(m) - send_error, received, message_received = q.expect_many( - EventPattern('dbus-signal', signal='SendError'), - EventPattern('dbus-signal', signal='Received'), - EventPattern('dbus-signal', signal='MessageReceived'), - ) + message_received = q.expect('dbus-signal', signal='MessageReceived') expected_send_error = 2 # Invalid_Contact - assert send_error.args[0] == expected_send_error, send_error.args - # FIXME: It doesn't look like it's possible to know what the original - # message type is, given that the type attribute of <message> is 'error' - # for error reports. - #assert send_error.args[2] == 0, send_error.args - assert send_error.args[3] == message_body, send_error.args - - assert received.args[2] == ninja_handle, (received.args, ninja_handle) - assert received.args[3] == 4, received.args # Channel_Text_Message_Type_Delivery_Report - assert received.args[4] == 2, received.args # Channel_Text_Message_Flag_Non_Text_Content - assert received.args[5] == '', received.args - delivery_report = message_received.args[0] assert len(delivery_report) == 1, delivery_report header = delivery_report[0] diff --git a/tests/twisted/text/send-to-correct-resource.py b/tests/twisted/text/send-to-correct-resource.py index f29fa51a1..8af7868a8 100644 --- a/tests/twisted/text/send-to-correct-resource.py +++ b/tests/twisted/text/send-to-correct-resource.py @@ -24,7 +24,7 @@ def test(q, bus, conn, stream): chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # When we start a conversation, Gabble should send to the bare JID. - chan.Text.Send(0, 'hey, you around?') + chan.send_msg_sync('hey, you around?') q.expect('stream-message', to=contact) # A particular resource replies. @@ -34,11 +34,11 @@ def test(q, bus, conn, stream): m.addElement('body', content="i'm on a beach at Gran Canaria!") stream.send(m) - q.expect('dbus-signal', signal='Received') + q.expect('dbus-signal', signal='MessageReceived') # Now that we got a reply from a particular resource, Gabble should reply # there. - chan.Text.Send(0, 'nice') + chan.send_msg_sync('nice') q.expect('stream-message', to=contact_a) # Now another resource messages us @@ -48,10 +48,10 @@ def test(q, bus, conn, stream): m.addElement('body', content="I brought my laptop to the Empathy hackfest") stream.send(m) - q.expect('dbus-signal', signal='Received') + q.expect('dbus-signal', signal='MessageReceived') # Gabble should have updated the resource it's sending to. - chan.Text.Send(0, "don't get sand in the keyboard") + chan.send_msg_sync("don't get sand in the keyboard") e = q.expect('stream-message', to=contact_b) # But actually that resource has gone offline: @@ -65,10 +65,10 @@ def test(q, bus, conn, stream): err.addElement((ns.STANZA, 'item-not-found')) stream.send(m) - q.expect('dbus-signal', signal='SendError') + q.expect('dbus-signal', signal='MessageReceived') # So as a result, Gabble should send the next message to the bare JID. - chan.Text.Send(0, "... i guess my warning was too late") + chan.send_msg_sync("... i guess my warning was too late") q.expect('stream-message', to=contact) if __name__ == '__main__': diff --git a/tests/twisted/text/test-chat-state.py b/tests/twisted/text/test-chat-state.py index c129fb7a3..4b0bf8f36 100644 --- a/tests/twisted/text/test-chat-state.py +++ b/tests/twisted/text/test-chat-state.py @@ -7,8 +7,7 @@ channels. from twisted.words.xish import domish from servicetest import (assertEquals, assertNotEquals, - assertLength, wrap_channel, EventPattern, call_async, - sync_dbus) + assertLength, wrap_channel, EventPattern, sync_dbus) from gabbletest import exec_test, make_result_iq, sync_stream, make_presence import constants as cs import ns @@ -38,19 +37,18 @@ def make_message(jid, body=None, state=None): return m def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") jid = 'foo@bar.com' full_jid = 'foo@bar.com/Foo' - foo_handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + foo_handle = conn.get_contact_handle_sync(jid) path = conn.Requests.CreateChannel( { cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: foo_handle, })[0] - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['ChatState', 'Destroyable']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') presence = make_presence(full_jid, status='hello', caps={ @@ -143,7 +141,7 @@ def test(q, bus, conn, stream): # XEP 0085: # every content message SHOULD contain an <active/> notification. - chan.Text.Send(0, 'hi.') + chan.send_msg_sync('hi.') stream_message = q.expect('stream-message') elem = stream_message.stanza @@ -169,10 +167,9 @@ def test(q, bus, conn, stream): # get a <gone/> notification, and the channel should respawn. chan.Close() - gone, _, _ = q.expect_many( + gone, _ = q.expect_many( EventPattern('stream-message'), EventPattern('dbus-signal', signal='Closed'), - EventPattern('dbus-signal', signal='NewChannel'), ) check_state_notification(gone.stanza, 'gone') @@ -194,8 +191,7 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: foo_handle, })[0] - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['ChatState', 'Destroyable']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # Close it immediately; the peer should again not get a <gone/> # notification, since we haven't sent any notifications on that channel. @@ -218,8 +214,7 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_ID: jid, })[0] - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['ChatState']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') stream.send(make_message(full_jid, body='i am invisible', state='active')) @@ -239,7 +234,7 @@ def test(q, bus, conn, stream): assertEquals(cs.CHAT_STATE_COMPOSING, state) assertEquals(self_handle, handle) - chan.Text.Send(0, 'very convincing') + chan.send_msg_sync('very convincing') stream_message = q.expect('stream-message', to=full_jid) check_state_notification(stream_message.stanza, 'active', allow_body=True) @@ -253,8 +248,7 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_ID: jid, })[0] - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['ChatState']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # We shouldn't send any notifications until we actually send a message. # But ChatStateChanged is still emitted locally @@ -273,7 +267,7 @@ def test(q, bus, conn, stream): q.unforbid_events([e]) # When we send a message, say we're active. - chan.Text.Send(0, 'is anyone there?') + chan.send_msg_sync('is anyone there?') stream_message = q.expect('stream-message', to=jid) check_state_notification(stream_message.stanza, 'active', allow_body=True) @@ -323,7 +317,7 @@ def test(q, bus, conn, stream): # support notifications. other_jid = jid + '/Library' stream.send(make_message(other_jid, body='grr, library computers')) - q.expect('dbus-signal', signal='Received') + q.expect('dbus-signal', signal='MessageReceived') # Okay, we should stop sending typing notifications. e = EventPattern('stream-message', to=other_jid) @@ -344,8 +338,7 @@ def test(q, bus, conn, stream): cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_ID: jid, })[0] - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text', - ['ChatState']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') # We shouldn't send any notifications until we actually send a message. e = EventPattern('stream-message', to=jid) @@ -357,13 +350,13 @@ def test(q, bus, conn, stream): q.unforbid_events([e]) # When we send a message, say we're active. - chan.Text.Send(0, '#n900 #maemo #zomg #woo #yay http://bit.ly/n900') + chan.send_msg_sync('#n900 #maemo #zomg #woo #yay http://bit.ly/n900') stream_message = q.expect('stream-message', to=jid) check_state_notification(stream_message.stanza, 'active', allow_body=True) # They reply without a chat state. stream.send(make_message(full_jid, body="posted.")) - q.expect('dbus-signal', signal='Received') + q.expect('dbus-signal', signal='MessageReceived') # Okay, we shouldn't send any more. e = EventPattern('stream-message', to=other_jid) @@ -374,7 +367,7 @@ def test(q, bus, conn, stream): sync_stream(q, stream) q.unforbid_events([e]) - chan.Text.Send(0, '@stephenfry simmer down') + chan.send_msg_sync('@stephenfry simmer down') message = q.expect('stream-message') states = [x for x in message.stanza.elements() if x.uri == ns.CHAT_STATES] assertLength(0, states) diff --git a/tests/twisted/text/test-text-delayed.py b/tests/twisted/text/test-text-delayed.py index 3818e06e2..605b2c148 100644 --- a/tests/twisted/text/test-text-delayed.py +++ b/tests/twisted/text/test-text-delayed.py @@ -8,7 +8,7 @@ import datetime from twisted.words.xish import domish from gabbletest import exec_test -from servicetest import EventPattern +from servicetest import assertEquals import constants as cs def test(q, bus, conn, stream): @@ -23,20 +23,14 @@ def test(q, bus, conn, stream): stream.send(m) - event = q.expect('dbus-signal', signal='NewChannel') - assert event.args[1] == cs.CHANNEL_TYPE_TEXT - assert event.args[2] == cs.HT_CONTACT - jid = conn.InspectHandles(cs.HT_CONTACT, [event.args[3]])[0] - assert jid == 'foo@bar.com' + event = q.expect('dbus-signal', signal='NewChannels') + path, props = event.args[0][0] + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE]) + jid = conn.inspect_contact_sync(props[cs.TARGET_HANDLE]) + assertEquals('foo@bar.com', jid) - received, message_received = q.expect_many( - EventPattern('dbus-signal', signal='Received'), - EventPattern('dbus-signal', signal='MessageReceived'), - ) - - assert (str(datetime.datetime.utcfromtimestamp(received.args[1])) - == '2007-05-17 16:15:01') - assert received.args[5] == 'hello' + message_received = q.expect('dbus-signal', signal='MessageReceived') message = message_received.args[0] header = message[0] diff --git a/tests/twisted/text/test-text-no-body.py b/tests/twisted/text/test-text-no-body.py index 2c4095f1c..34e54b7bb 100644 --- a/tests/twisted/text/test-text-no-body.py +++ b/tests/twisted/text/test-text-no-body.py @@ -7,6 +7,7 @@ new text channel. from twisted.words.xish import domish from gabbletest import exec_test +from servicetest import assertEquals import constants as cs import ns @@ -27,10 +28,11 @@ def test(q, bus, conn, stream): stream.send(m) # first message should be from Bob, not Alice - event = q.expect('dbus-signal', signal='NewChannel') - assert event.args[1] == cs.CHANNEL_TYPE_TEXT - jid = conn.InspectHandles(cs.HT_CONTACT, [event.args[3]])[0] - assert jid == 'bob@foo.com' + event = q.expect('dbus-signal', signal='NewChannels') + path, props = event.args[0][0] + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + jid = conn.inspect_contact_sync(props[cs.TARGET_HANDLE]) + assertEquals('bob@foo.com', jid) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/text/test-text.py b/tests/twisted/text/test-text.py index a820e135b..a6c42029f 100644 --- a/tests/twisted/text/test-text.py +++ b/tests/twisted/text/test-text.py @@ -8,10 +8,8 @@ import dbus from twisted.words.xish import domish from gabbletest import exec_test, elem -from servicetest import ( - EventPattern, wrap_channel, - assertEquals, assertNotEquals, assertLength, - ) +from servicetest import (EventPattern, wrap_channel, assertEquals, assertLength, + assertContains) import constants as cs def test(q, bus, conn, stream): @@ -25,52 +23,28 @@ def test(q, bus, conn, stream): m.addElement('body', content='hello') stream.send(m) - event = q.expect('dbus-signal', signal='NewChannel') - text_chan = wrap_channel( - bus.get_object(conn.bus_name, event.args[0]), 'Text', ['Messages']) - assert event.args[1] == cs.CHANNEL_TYPE_TEXT - assert event.args[2] == cs.HT_CONTACT - foo_at_bar_dot_com_handle = event.args[3] - jid = conn.InspectHandles(1, [foo_at_bar_dot_com_handle])[0] - assert jid == 'foo@bar.com' - assert event.args[4] == False # suppress handler + event = q.expect('dbus-signal', signal='NewChannels') + path, props = event.args[0][0] + text_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Text') + assertEquals(cs.CHANNEL_TYPE_TEXT, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_CONTACT, props[cs.TARGET_HANDLE_TYPE]) + foo_at_bar_dot_com_handle = props[cs.TARGET_HANDLE] + jid = conn.inspect_contact_sync(foo_at_bar_dot_com_handle) + assertEquals('foo@bar.com', jid) # Exercise basic Channel Properties from spec 0.17.7 channel_props = text_chan.Properties.GetAll(cs.CHANNEL) - assert channel_props.get('TargetHandle') == event.args[3],\ - (channel_props.get('TargetHandle'), event.args[3]) - assert channel_props.get('TargetHandleType') == cs.HT_CONTACT,\ - channel_props.get('TargetHandleType') - assert channel_props.get('ChannelType') == \ - cs.CHANNEL_TYPE_TEXT,\ - channel_props.get('ChannelType') - assert cs.CHANNEL_IFACE_CHAT_STATE in \ - channel_props.get('Interfaces', ()), \ - channel_props.get('Interfaces') - assert cs.CHANNEL_IFACE_MESSAGES in \ - channel_props.get('Interfaces', ()), \ - channel_props.get('Interfaces') - assert channel_props['TargetID'] == jid,\ - (channel_props['TargetID'], jid) - assert channel_props['Requested'] == False - assert channel_props['InitiatorHandle'] == event.args[3],\ - (channel_props['InitiatorHandle'], event.args[3]) - assert channel_props['InitiatorID'] == jid,\ - (channel_props['InitiatorID'], jid) - - received, message_received = q.expect_many( - EventPattern('dbus-signal', signal='Received'), - EventPattern('dbus-signal', signal='MessageReceived'), - ) - - # Check that C.T.Text.Received looks right - # message type: normal - assert received.args[3] == 0 - # flags: none - assert received.args[4] == 0 - # body - assert received.args[5] == 'hello' - + assertEquals(props[cs.TARGET_HANDLE], channel_props.get('TargetHandle')) + assertEquals(cs.HT_CONTACT, channel_props.get('TargetHandleType')) + assertEquals(cs.CHANNEL_TYPE_TEXT, channel_props.get('ChannelType')) + assertContains(cs.CHANNEL_IFACE_CHAT_STATE, channel_props.get('Interfaces')) + assertContains(cs.CHANNEL_IFACE_MESSAGES, channel_props.get('Interfaces')) + assertEquals(jid, channel_props['TargetID']) + assertEquals(False, channel_props['Requested']) + assertEquals(props[cs.INITIATOR_HANDLE], channel_props['InitiatorHandle']) + assertEquals(jid, channel_props['InitiatorID']) + + message_received = q.expect('dbus-signal', signal='MessageReceived') # Check that C.I.Messages.MessageReceived looks right. message = message_received.args[0] @@ -114,9 +88,8 @@ def test(q, bus, conn, stream): sent_token = text_chan.Messages.SendMessage(greeting, dbus.UInt32(0)) - stream_message, sent, message_sent = q.expect_many( + stream_message, message_sent = q.expect_many( EventPattern('stream-message'), - EventPattern('dbus-signal', signal='Sent'), EventPattern('dbus-signal', signal='MessageSent'), ) @@ -132,7 +105,7 @@ def test(q, bus, conn, stream): header = sent_message[0] assert header['message-type'] == 2, header # Notice assert header['message-token'] == sent_token, header - assertEquals(conn.GetSelfHandle(), header['message-sender']) + assertEquals(conn.Properties.Get(cs.CONN, "SelfHandle"), header['message-sender']) assertEquals('test@localhost', header['message-sender-id']) body = sent_message[1] assert body['content-type'] == 'text/plain', body @@ -140,16 +113,11 @@ def test(q, bus, conn, stream): assert message_sent.args[2] == sent_token - assert sent.args[1] == 2, sent.args # Notice - assert sent.args[2] == u'what up', sent.args - - # Send a message using Channel.Type.Text API text_chan.Text.Send(0, 'goodbye') - stream_message, sent, message_sent = q.expect_many( + stream_message, message_sent = q.expect_many( EventPattern('stream-message'), - EventPattern('dbus-signal', signal='Sent'), EventPattern('dbus-signal', signal='MessageSent'), ) @@ -170,9 +138,6 @@ def test(q, bus, conn, stream): assert body['content-type'] == 'text/plain', body assert body['content'] == u'goodbye', body - assert sent.args[1] == 0, sent.args # message type normal - assert sent.args[2] == u'goodbye', sent.args - # And now let's try a message with a malformed type='' attribute. malformed = elem( 'message', from_='foo@bar.com/fubber', type="'")( diff --git a/tests/twisted/tools/exec-with-log.sh.in b/tests/twisted/tools/exec-with-log.sh.in index 9210eecc5..28968cad1 100644 --- a/tests/twisted/tools/exec-with-log.sh.in +++ b/tests/twisted/tools/exec-with-log.sh.in @@ -46,7 +46,7 @@ elif test -n "$GABBLE_TEST_REFDBG"; then elif test -n "$GABBLE_TEST_STRACE"; then GABBLE_WRAPPER="strace -o strace.log" elif test -n "$GABBLE_TEST_BACKTRACE"; then - GABBLE_WRAPPER="gdb -x run_and_bt.gdb" + GABBLE_WRAPPER="gdb -x @abs_top_srcdir@/tests/twisted/tools/run_and_bt.gdb" fi # Prevent libproxy from hitting the network for wpad configuration diff --git a/tests/twisted/tubes/accept-muc-dbus-tube.py b/tests/twisted/tubes/accept-muc-dbus-tube.py index df5b81ed0..2606fa254 100644 --- a/tests/twisted/tubes/accept-muc-dbus-tube.py +++ b/tests/twisted/tubes/accept-muc-dbus-tube.py @@ -2,7 +2,7 @@ import dbus from servicetest import ( assertEquals, assertNotEquals, assertSameSets, - call_async, EventPattern, + call_async, EventPattern, wrap_channel ) from gabbletest import exec_test, acknowledge_iq, make_muc_presence import constants as cs @@ -11,6 +11,7 @@ from twisted.words.xish import xpath import ns from mucutil import join_muc_and_check +import tubetestutil as t def test(q, bus, conn, stream, access_control): iq_event = q.expect('stream-iq', to=None, query_ns='vcard-temp', @@ -19,7 +20,7 @@ def test(q, bus, conn, stream, access_control): acknowledge_iq(stream, iq_event.stanza) muc = 'chat@conf.localhost' - _, _, test_handle, bob_handle = \ + _, test_handle, bob_handle = \ join_muc_and_check(q, bus, conn, stream, muc) # Bob offers a stream tube @@ -63,22 +64,19 @@ def test(q, bus, conn, stream, access_control): cs.SOCKET_ACCESS_CONTROL_LOCALHOST], props[cs.DBUS_TUBE_SUPPORTED_ACCESS_CONTROLS]) - tube_chan = bus.get_object(conn.bus_name, path) - tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_IFACE_TUBE) - dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) - tube_chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) + tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube') # only Bob is in DBusNames dbus_names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assertEquals({bob_handle: bob_bus_name}, dbus_names) - call_async(q, dbus_tube_iface, 'Accept', access_control) + call_async(q, tube_chan.DBusTube, 'Accept', access_control) return_event, names_changed1, names_changed2, presence_event = q.expect_many( EventPattern('dbus-return', method='Accept'), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE), - EventPattern('stream-presence', to='chat@conf.localhost/test')) + EventPattern('stream-presence', to='chat@conf.localhost/test', predicate=lambda e: t.presence_contains_tube(e))) tube_addr = return_event.value[0] assert len(tube_addr) > 0 @@ -92,7 +90,7 @@ def test(q, bus, conn, stream, access_control): assertEquals('1', tube_node['id']) self_bus_name = tube_node['dbus-name'] - tubes_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) + tubes_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') assertNotEquals(0, tubes_self_handle) # both of us are in DBusNames now @@ -107,7 +105,7 @@ def test(q, bus, conn, stream, access_control): assertEquals({tubes_self_handle: self_bus_name}, added) assertEquals([], removed) - tube_chan_iface.Close() + tube_chan.Channel.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) diff --git a/tests/twisted/tubes/accept-muc-stream-tube.py b/tests/twisted/tubes/accept-muc-stream-tube.py index 7fc4aa0a6..a209ab08e 100644 --- a/tests/twisted/tubes/accept-muc-stream-tube.py +++ b/tests/twisted/tubes/accept-muc-stream-tube.py @@ -40,22 +40,22 @@ def test(q, bus, conn, stream, bytestream_cls, announce_socks5_proxy(q, stream, disco_event.stanza) - call_async(q, conn, 'RequestHandles', 2, - ['chat@conf.localhost']) - - event = q.expect('dbus-return', method='RequestHandles') - handles = event.value[0] - room_handle = handles[0] - # join the muc 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', - args=[u'', [], [], [], [2], 0, 0]), + cs.TARGET_ID: 'chat@conf.localhost'}) + + q.expect_many( + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + e.args[0] == [] and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + len(e.args[3]) == 1 and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + e.args[4]['contact-ids'][e.args[3][0]] == 'chat@conf.localhost/test'), EventPattern('stream-presence', to='chat@conf.localhost/test')) # Send presence for other member of room. @@ -64,12 +64,20 @@ def test(q, bus, conn, stream, bytestream_cls, # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', 'chat@conf.localhost', 'test')) - q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [2, 3], [], [], [], 0, 0]) - - assert conn.InspectHandles(1, [2]) == ['chat@conf.localhost/test'] - assert conn.InspectHandles(1, [3]) == ['chat@conf.localhost/bob'] - bob_handle = 3 + event = q.expect('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + len(e.args[0]) == 2 and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + e.args[3] == [] and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == + set(['chat@conf.localhost/test', 'chat@conf.localhost/bob'])) + + for h in event.args[0]: + if event.args[4]['contact-ids'][h] == 'chat@conf.localhost/bob': + bob_handle = h event = q.expect('dbus-return', method='CreateChannel') @@ -102,11 +110,7 @@ def test(q, bus, conn, stream, bytestream_cls, stream.send(presence) # text channel - event, new_event = q.expect_many( - EventPattern('dbus-signal', signal='NewChannel'), - EventPattern('dbus-signal', signal='NewChannels')) - - assert event.args[1] == cs.CHANNEL_TYPE_TEXT, event.args + new_event = q.expect('dbus-signal', signal='NewChannels') channels = new_event.args[0] assert len(channels) == 1 @@ -130,7 +134,6 @@ def test(q, bus, conn, stream, bytestream_cls, 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' assert props[cs.STREAM_TUBE_SERVICE] == 'echo' assert props[cs.TUBE_PARAMETERS] == {'s': 'hello', 'ay': 'hello', 'u': 123, 'i': -123} diff --git a/tests/twisted/tubes/accept-private-dbus-tube.py b/tests/twisted/tubes/accept-private-dbus-tube.py index dbbeb3bed..fb81cb63e 100644 --- a/tests/twisted/tubes/accept-private-dbus-tube.py +++ b/tests/twisted/tubes/accept-private-dbus-tube.py @@ -37,7 +37,7 @@ def test(q, bus, conn, stream, bytestream_cls, access_control): query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER)) - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") acknowledge_iq(stream, vcard_event.stanza) @@ -81,7 +81,7 @@ def test(q, bus, conn, stream, bytestream_cls, access_control): # RequestChannel are the ones we wanted. sync_dbus(bus, q, conn) - bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@localhost'])[0] + bob_handle = conn.get_contact_handle_sync('bob@localhost') # let's try to accept a D-Bus tube using the new API bytestream = bytestream_cls(stream, q, 'gamma', bob_full_jid, diff --git a/tests/twisted/tubes/check-create-tube-return.py b/tests/twisted/tubes/check-create-tube-return.py index 46db340c4..2f1e34aa9 100644 --- a/tests/twisted/tubes/check-create-tube-return.py +++ b/tests/twisted/tubes/check-create-tube-return.py @@ -39,9 +39,8 @@ def test(q, bus, conn, stream): stream.send(make_muc_presence('owner', 'moderator', muc, 'bob')) stream.send(make_muc_presence('none', 'participant', muc, 'test')) - ret, _, _ = q.expect_many( + ret, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) @@ -62,9 +61,8 @@ def test(q, bus, conn, stream): cs.TARGET_ID: muc, cs.DBUS_TUBE_SERVICE_NAME: 'com.example.LolDongs'}) - ret, _, _ = q.expect_many( + ret, _ = q.expect_many( EventPattern('dbus-return', method='CreateChannel'), - EventPattern('dbus-signal', signal='NewChannel'), EventPattern('dbus-signal', signal='NewChannels'), ) diff --git a/tests/twisted/tubes/close-muc-with-closed-tube.py b/tests/twisted/tubes/close-muc-with-closed-tube.py index ed08add64..c5a7a5da4 100644 --- a/tests/twisted/tubes/close-muc-with-closed-tube.py +++ b/tests/twisted/tubes/close-muc-with-closed-tube.py @@ -21,19 +21,22 @@ 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] - room_handle = handles[0] - # join the muc - call_async(q, conn, 'RequestChannel', - cs.CHANNEL_TYPE_TEXT, cs.HT_ROOM, room_handle, True) - - _, stream_event = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [], [], [], [2], 0, 0]), + call_async(q, conn.Requests, 'CreateChannel', { + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_TEXT, + cs.TARGET_HANDLE_TYPE: cs.HT_ROOM, + cs.TARGET_ID: 'chat@conf.localhost'}) + + q.expect_many( + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + e.args[0] == [] and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + len(e.args[3]) == 1 and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + e.args[4]['contact-ids'][e.args[3][0]] == 'chat@conf.localhost/test'), EventPattern('stream-presence', to='chat@conf.localhost/test')) # Send presence for other member of room. @@ -42,14 +45,22 @@ def test(q, bus, conn, stream): # Send presence for own membership of room. stream.send(make_muc_presence('none', 'participant', 'chat@conf.localhost', 'test')) - q.expect('dbus-signal', signal='MembersChanged', - args=[u'', [2, 3], [], [], [], 0, 0]) - - assert conn.InspectHandles(cs.HT_CONTACT, [2, 3]) == \ - ['chat@conf.localhost/test', 'chat@conf.localhost/bob'] - bob_handle = 3 - - event = q.expect('dbus-return', method='RequestChannel') + event = q.expect('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + len(e.args[0]) == 2 and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + e.args[3] == [] and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == + set(['chat@conf.localhost/test', 'chat@conf.localhost/bob'])) + + for h in event.args[0]: + if event.args[4]['contact-ids'][h] == 'chat@conf.localhost/bob': + bob_handle = h + + event = q.expect('dbus-return', method='CreateChannel') text_chan = bus.get_object(conn.bus_name, event.value[0]) # Bob offers a muc tube @@ -96,7 +107,6 @@ def test(q, bus, conn, stream): 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]) diff --git a/tests/twisted/tubes/ensure-si-tube.py b/tests/twisted/tubes/ensure-si-tube.py index dccb337cc..259c464a7 100644 --- a/tests/twisted/tubes/ensure-si-tube.py +++ b/tests/twisted/tubes/ensure-si-tube.py @@ -70,7 +70,7 @@ def test(q, bus, conn, stream): feature['var'] = ns.TUBES stream.send(result) - bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] + bob_handle = conn.get_contact_handle_sync('bob@localhost') def new_chan_predicate(e): types = [] diff --git a/tests/twisted/tubes/offer-muc-dbus-tube.py b/tests/twisted/tubes/offer-muc-dbus-tube.py index 06ccc2804..ff10045c9 100644 --- a/tests/twisted/tubes/offer-muc-dbus-tube.py +++ b/tests/twisted/tubes/offer-muc-dbus-tube.py @@ -6,7 +6,7 @@ import dbus from dbus.connection import Connection from dbus.lowlevel import SignalMessage -from servicetest import call_async, EventPattern, assertContains, assertEquals +from servicetest import call_async, EventPattern, assertContains, assertEquals, wrap_channel from gabbletest import exec_test, acknowledge_iq, elem, make_muc_presence, sync_stream import ns import constants as cs @@ -114,8 +114,8 @@ def test(q, bus, conn, stream, access_control): # check if we can request muc D-Bus tube t.check_conn_properties(q, conn) - self_handle = conn.GetSelfHandle() - self_name = conn.InspectHandles(1, [self_handle])[0] + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") + self_name = conn.inspect_contact_sync(self_handle) # offer a D-Bus tube to another room using new API muc = 'chat2@conf.localhost' @@ -146,32 +146,29 @@ def test(q, bus, conn, stream, access_control): dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assertContains((path, prop), all_channels) - tube_chan = bus.get_object(conn.bus_name, path) - dbus_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_DBUS_TUBE) - chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) - tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE, - byte_arrays=True) + tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'DBusTube') + tube_props = tube_chan.Properties.GetAll(cs.CHANNEL_IFACE_TUBE, byte_arrays=True) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # try to offer using a wrong access control try: - dbus_tube_iface.Offer(sample_parameters, cs.SOCKET_ACCESS_CONTROL_PORT) + tube_chan.DBusTube.Offer(sample_parameters, cs.SOCKET_ACCESS_CONTROL_PORT) except dbus.DBusException, e: assertEquals(e.get_dbus_name(), cs.INVALID_ARGUMENT) else: assert False # offer the tube - call_async(q, dbus_tube_iface, 'Offer', sample_parameters, access_control) + call_async(q, tube_chan.DBusTube, 'Offer', sample_parameters, access_control) presence_event, return_event, status_event, dbus_changed_event = q.expect_many( - EventPattern('stream-presence', to='chat2@conf.localhost/test'), + EventPattern('stream-presence', to='chat2@conf.localhost/test', predicate=lambda e: t.presence_contains_tube(e)), EventPattern('dbus-return', method='Offer'), EventPattern('dbus-signal', signal='TubeChannelStateChanged', args=[cs.TUBE_CHANNEL_STATE_OPEN]), EventPattern('dbus-signal', signal='DBusNamesChanged', interface=cs.CHANNEL_TYPE_DBUS_TUBE)) - tube_self_handle = tube_chan.GetSelfHandle(dbus_interface=cs.CHANNEL_IFACE_GROUP) + tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') assert tube_self_handle != 0 # handle presence_event @@ -188,7 +185,7 @@ def test(q, bus, conn, stream, access_control): dbus_tube_adr = return_event.value[0] bob_bus_name = ':2.Ym9i' - bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat2@conf.localhost/bob'])[0] + bob_handle = conn.get_contact_handle_sync('chat2@conf.localhost/bob') def bob_in_tube(): presence = elem('presence', from_='chat2@conf.localhost/bob', to='chat2@conf.localhost')( @@ -242,7 +239,7 @@ def test(q, bus, conn, stream, access_control): names = tube_chan.Get(cs.CHANNEL_TYPE_DBUS_TUBE, 'DBusNames', dbus_interface=cs.PROPERTIES_IFACE) assert names == {tube_self_handle: my_bus_name} - chan_iface.Close() + tube_chan.Channel.Close() _, _, event = q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed'), diff --git a/tests/twisted/tubes/offer-muc-stream-tube.py b/tests/twisted/tubes/offer-muc-stream-tube.py index 2188e82a9..1a3604563 100644 --- a/tests/twisted/tubes/offer-muc-stream-tube.py +++ b/tests/twisted/tubes/offer-muc-stream-tube.py @@ -5,7 +5,7 @@ import os import dbus -from servicetest import call_async, EventPattern, unwrap, assertContains, assertEquals +from servicetest import call_async, EventPattern, unwrap, assertContains, assertEquals, wrap_channel from gabbletest import acknowledge_iq, make_muc_presence import constants as cs import ns @@ -74,7 +74,7 @@ def test(q, bus, conn, stream, bytestream_cls, t.check_conn_properties(q, conn) - bob_handle = conn.RequestHandles(cs.HT_CONTACT, ['chat@conf.localhost/bob'])[0] + bob_handle = conn.get_contact_handle_sync('chat@conf.localhost/bob') address = t.create_server(q, address_type) @@ -101,7 +101,7 @@ def test(q, bus, conn, stream, bytestream_cls, cs.TARGET_ID: 'chat@conf.localhost', cs.STREAM_TUBE_SERVICE: 'newecho', } - _, _, new_tube_path, new_tube_props = \ + _, new_tube_path, new_tube_props = \ join_muc(q, bus, conn, stream, 'chat@conf.localhost', request) e = q.expect('dbus-signal', signal='NewChannels', @@ -120,23 +120,21 @@ def test(q, bus, conn, stream, bytestream_cls, dbus_interface=cs.PROPERTIES_IFACE, byte_arrays=True) assertContains((path, prop), all_channels) - tube_chan = bus.get_object(conn.bus_name, path) - stream_tube_iface = dbus.Interface(tube_chan, cs.CHANNEL_TYPE_STREAM_TUBE) - chan_iface = dbus.Interface(tube_chan, cs.CHANNEL) + tube_chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamTube') tube_props = tube_chan.GetAll(cs.CHANNEL_IFACE_TUBE, dbus_interface=cs.PROPERTIES_IFACE) assert tube_props['State'] == cs.TUBE_CHANNEL_STATE_NOT_OFFERED # offer the tube - call_async(q, stream_tube_iface, 'Offer', address_type, address, access_control, {'foo': 'bar'}) + call_async(q, tube_chan.StreamTube, 'Offer', address_type, address, access_control, {'foo': 'bar'}) stream_event, _, status_event = q.expect_many( - EventPattern('stream-presence', to='chat@conf.localhost/test'), + EventPattern('stream-presence', to='chat@conf.localhost/test', predicate=lambda e: t.presence_contains_tube(e)), 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]) == ['chat@conf.localhost/test'] + tube_self_handle = tube_chan.Properties.Get(cs.CHANNEL_IFACE_GROUP, 'SelfHandle') + assert conn.inspect_contact_sync(tube_self_handle) == 'chat@conf.localhost/test' presence = stream_event.stanza tubes_nodes = xpath.queryForNodes('/presence/tubes[@xmlns="%s"]' @@ -165,7 +163,7 @@ 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, ['chat@conf.localhost/bob'])[0] + bob_handle = conn.get_contact_handle_sync('chat@conf.localhost/bob') bytestream = connect_to_tube(stream, q, bytestream_cls, 'chat@conf.localhost', stream_tube_id) @@ -190,7 +188,7 @@ def test(q, bus, conn, stream, bytestream_cls, use_tube(q, bytestream, protocol, conn_id) - chan_iface.Close() + tube_chan.Channel.Close() q.expect_many( EventPattern('dbus-signal', signal='Closed'), EventPattern('dbus-signal', signal='ChannelClosed')) diff --git a/tests/twisted/tubes/offer-private-dbus-tube.py b/tests/twisted/tubes/offer-private-dbus-tube.py index bb61eb21c..ee4e190a7 100644 --- a/tests/twisted/tubes/offer-private-dbus-tube.py +++ b/tests/twisted/tubes/offer-private-dbus-tube.py @@ -202,8 +202,8 @@ def test(q, bus, conn, stream, bytestream_cls, access_control): t.check_conn_properties(q, conn) - self_handle = conn.GetSelfHandle() - alice_handle = conn.RequestHandles(cs.HT_CONTACT, ["alice@localhost"])[0] + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") + alice_handle = conn.get_contact_handle_sync('alice@localhost') # send Alice's presence caps = { 'ext': '', 'ver': '0.0.0', diff --git a/tests/twisted/tubes/offer-private-stream-tube.py b/tests/twisted/tubes/offer-private-stream-tube.py index de37041c2..807959d8e 100644 --- a/tests/twisted/tubes/offer-private-stream-tube.py +++ b/tests/twisted/tubes/offer-private-stream-tube.py @@ -51,7 +51,7 @@ def test(q, bus, conn, stream, bytestream_cls, query_name='vCard'), EventPattern('stream-iq', query_ns=ns.ROSTER)) - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") acknowledge_iq(stream, vcard_event.stanza) @@ -96,7 +96,7 @@ def test(q, bus, conn, stream, bytestream_cls, sync_dbus(bus, q, conn) # Test tubes with Bob. Bob has tube capabilities. - bob_handle = conn.RequestHandles(1, ['bob@localhost'])[0] + bob_handle = conn.get_contact_handle_sync('bob@localhost') # Try CreateChannel with correct properties # Gabble must succeed diff --git a/tests/twisted/tubes/test-get-available-tubes.py b/tests/twisted/tubes/test-get-available-tubes.py index 7b860ebfd..a5508486d 100644 --- a/tests/twisted/tubes/test-get-available-tubes.py +++ b/tests/twisted/tubes/test-get-available-tubes.py @@ -39,9 +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')) - members, event = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [2, 3], [], [], [], 0, 0]), + _, event = q.expect_many( + EventPattern('dbus-signal', signal='MembersChangedDetailed', + predicate=lambda e: + len(e.args[0]) == 2 and # added + e.args[1] == [] and # removed + e.args[2] == [] and # local pending + e.args[3] == [] and # remote pending + e.args[4].get('actor', 0) == 0 and + e.args[4].get('change-reason', 0) == 0 and + set([e.args[4]['contact-ids'][h] for h in e.args[0]]) == + set(['chat@conf.localhost/test', 'chat@conf.localhost/bob'])), EventPattern('dbus-return', method='CreateChannel')) path = event.value[0] diff --git a/tests/twisted/tubes/test-socks5-muc.py b/tests/twisted/tubes/test-socks5-muc.py index 4153801f8..54947ec55 100644 --- a/tests/twisted/tubes/test-socks5-muc.py +++ b/tests/twisted/tubes/test-socks5-muc.py @@ -27,7 +27,7 @@ def test(q, bus, conn, stream): announce_socks5_proxy(q, stream, disco_event.stanza) - text_chan = join_muc(q, bus, conn, stream, 'chat@conf.localhost') + join_muc(q, bus, conn, stream, 'chat@conf.localhost') # bob offers a stream tube stream_tube_id = 1 diff --git a/tests/twisted/tubes/tubetestutil.py b/tests/twisted/tubes/tubetestutil.py index 3eb86d9d5..3c53d1533 100644 --- a/tests/twisted/tubes/tubetestutil.py +++ b/tests/twisted/tubes/tubetestutil.py @@ -21,6 +21,7 @@ from twisted.internet import reactor from twisted.internet.protocol import Factory, Protocol from twisted.internet.error import CannotListenError from twisted.internet import tcp +from twisted.words.xish import xpath _to_cleanup = [] @@ -181,7 +182,7 @@ def check_channel_properties(q, bus, conn, channel, channel_type, assert channel_props['TargetID'] == contact_id assert channel_props['Requested'] == True assert channel_props['InitiatorID'] == 'test@localhost' - assert channel_props['InitiatorHandle'] == conn.GetSelfHandle() + assert channel_props['InitiatorHandle'] == conn.Properties.Get(cs.CONN, "SelfHandle") if channel_type == cs.CHANNEL_TYPE_TUBES: assert state is None @@ -373,3 +374,7 @@ def exec_stream_tube_test(test): def exec_dbus_tube_test(test): exec_tube_test(test, cs.SOCKET_ACCESS_CONTROL_CREDENTIALS) exec_tube_test(test, cs.SOCKET_ACCESS_CONTROL_LOCALHOST) + +def presence_contains_tube(e): + return xpath.queryForNodes('/presence/tubes[@xmlns="%s"]/tube' + % ns.TUBES, e.stanza) is not None diff --git a/tests/twisted/vcard/disconnect-during-pep.py b/tests/twisted/vcard/disconnect-during-pep.py index cb05ad5b3..38f7d002a 100644 --- a/tests/twisted/vcard/disconnect-during-pep.py +++ b/tests/twisted/vcard/disconnect-during-pep.py @@ -15,7 +15,7 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) - handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') call_async(q, conn.Aliasing, 'RequestAliases', [handle]) # First, Gabble sends a PEP query diff --git a/tests/twisted/vcard/get-contact-info.py b/tests/twisted/vcard/get-contact-info.py index 6c61ecd24..f546c350f 100644 --- a/tests/twisted/vcard/get-contact-info.py +++ b/tests/twisted/vcard/get-contact-info.py @@ -17,7 +17,7 @@ def test(q, bus, conn, stream): # returning an empty vcard will cause ContactInfoChanged to fire q.expect('dbus-signal', signal='ContactInfoChanged') - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') call_async(q, conn.ContactInfo, 'RefreshContactInfo', [handle]) event = q.expect('stream-iq', to='bob@foo.com', query_ns='vcard-temp', @@ -56,16 +56,8 @@ def test(q, bus, conn, stream): u'Exemplary Team']), ] # The request should be satisfied from the cache. - assertEquals( - {handle: contact_info}, conn.ContactInfo.GetContactInfo([handle])) - - # check the ContactAttribute - assertEquals( - {handle: {cs.CONN_IFACE_CONTACT_INFO + '/info': contact_info, - 'org.freedesktop.Telepathy.Connection/contact-id': 'bob@foo.com'}}, - conn.Contacts.GetContactAttributes([handle], - [cs.CONN_IFACE_CONTACT_INFO], False)) - + h2asv = conn.Contacts.GetContactAttributes([handle], [cs.CONN_IFACE_CONTACT_INFO], False) + assertEquals(contact_info, h2asv[handle][cs.ATTR_CONTACT_INFO]) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/vcard/overlapping-sets.py b/tests/twisted/vcard/overlapping-sets.py index a57ca9cc4..a6565095f 100644 --- a/tests/twisted/vcard/overlapping-sets.py +++ b/tests/twisted/vcard/overlapping-sets.py @@ -17,7 +17,7 @@ def test(q, bus, conn, stream): query_ns=ns.VCARD_TEMP, query_name='vCard') sync_stream(q, stream) - handle = conn.GetSelfHandle() + handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Robert the Bruce'}) sync_dbus(bus, q, conn) acknowledge_iq(stream, vcard_get_event.stanza) diff --git a/tests/twisted/vcard/refresh-contact-info.py b/tests/twisted/vcard/refresh-contact-info.py index 3fc87d3f0..84630da67 100644 --- a/tests/twisted/vcard/refresh-contact-info.py +++ b/tests/twisted/vcard/refresh-contact-info.py @@ -15,7 +15,7 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') call_async(q, conn.ContactInfo, 'RefreshContactInfo', [handle]) event = q.expect('stream-iq', to='bob@foo.com', query_ns='vcard-temp', diff --git a/tests/twisted/vcard/test-alias-empty-vcard.py b/tests/twisted/vcard/test-alias-empty-vcard.py index 8a03737f3..c711a07e3 100644 --- a/tests/twisted/vcard/test-alias-empty-vcard.py +++ b/tests/twisted/vcard/test-alias-empty-vcard.py @@ -14,7 +14,7 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') call_async(q, conn.Aliasing, 'RequestAliases', [handle]) # Nack PEP query. diff --git a/tests/twisted/vcard/test-alias-message.py b/tests/twisted/vcard/test-alias-message.py index 362036a0e..07f889bf2 100644 --- a/tests/twisted/vcard/test-alias-message.py +++ b/tests/twisted/vcard/test-alias-message.py @@ -14,15 +14,22 @@ from mucutil import join_muc, make_muc_presence import constants as cs import ns +def get_aliases(conn, contacts): + h2asv = conn.Contacts.GetContactAttributes(contacts, [cs.CONN_IFACE_ALIASING], False) + ret = {} + for h in contacts: + ret[h] = h2asv[h][cs.ATTR_ALIAS] + return ret + def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) jid = u'bora.horza.gobuchul@culture.lit' alias = u'Horza' - handle = conn.RequestHandles(cs.HT_CONTACT, [jid])[0] + handle = conn.get_contact_handle_sync(jid) # We don't have an interesting alias for Horza - assertEquals({handle: jid}, conn.Aliasing.GetAliases([handle])) + assertEquals({handle: jid}, get_aliases(conn, [handle])) # Horza sends us a message containing his preferred nickname. stream.send( @@ -39,7 +46,7 @@ def test(q, bus, conn, stream): channel = wrap_channel(bus.get_object(conn.bus_name, mr.path), 'Text') # So now we know his alias. - assertEquals({handle: alias}, conn.Aliasing.GetAliases([handle])) + assertEquals({handle: alias}, get_aliases(conn, [handle])) # Presumably to avoid non-contacts being able to make Gabble's memory # footprint grow forever, Gabble throws the alias away when we close the @@ -51,7 +58,7 @@ def test(q, bus, conn, stream): # FIXME: Gabble forgets the alias, but it doesn't signal that it has done # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', args=[[(handle, jid)]]) - assertEquals({handle: jid}, conn.Aliasing.GetAliases([handle])) + assertEquals({handle: jid}, get_aliases(conn, [handle])) # Basically the same test, but in a MUC. @@ -68,12 +75,12 @@ def test(q, bus, conn, stream): # make it explicit. Perhaps in future we might change this test to verify # that it doesn't "work". room_jid = 'clear-air-turbulence@culture.lit' - _, muc, _, _ = join_muc(q, bus, conn, stream, room_jid) + muc, _, _ = join_muc(q, bus, conn, stream, room_jid) bob_jid = room_jid + '/bob' - bob_handle = conn.RequestHandles(cs.HT_CONTACT, [bob_jid])[0] + bob_handle = conn.get_contact_handle_sync(bob_jid) - assertEquals({bob_handle: 'bob'}, conn.Aliasing.GetAliases([bob_handle])) + assertEquals({bob_handle: 'bob'}, get_aliases(conn, [bob_handle])) stream.send( elem('message', from_=bob_jid, type='groupchat')( @@ -86,7 +93,7 @@ def test(q, bus, conn, stream): args=[[(bob_handle, alias)]]), EventPattern('dbus-signal', signal='MessageReceived'),) - assertEquals({bob_handle: alias}, conn.Aliasing.GetAliases([bob_handle])) + assertEquals({bob_handle: alias}, get_aliases(conn, [bob_handle])) muc.Close() q.expect('stream-presence', to=room_jid + '/test') @@ -99,7 +106,7 @@ def test(q, bus, conn, stream): # so; it probably should. # q.expect('dbus-signal', signal='AliasesChanged', # args=[[(bob_handle, 'bob')]]) - assertEquals({bob_handle: 'bob'}, conn.Aliasing.GetAliases([bob_handle])) + assertEquals({bob_handle: 'bob'}, get_aliases(conn, [bob_handle])) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/vcard/test-alias-pep.py b/tests/twisted/vcard/test-alias-pep.py index 0adc2b9e6..201eeeeb1 100644 --- a/tests/twisted/vcard/test-alias-pep.py +++ b/tests/twisted/vcard/test-alias-pep.py @@ -15,7 +15,7 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) - handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') call_async(q, conn.Aliasing, 'RequestAliases', [handle]) event = q.expect('stream-iq', to='bob@foo.com', iq_type='get', diff --git a/tests/twisted/vcard/test-alias.py b/tests/twisted/vcard/test-alias.py index 7e8dff2ec..72d0bf5bc 100644 --- a/tests/twisted/vcard/test-alias.py +++ b/tests/twisted/vcard/test-alias.py @@ -13,7 +13,7 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') call_async(q, conn.Aliasing, 'RequestAliases', [handle]) # Nack PEP query. diff --git a/tests/twisted/vcard/test-avatar-async.py b/tests/twisted/vcard/test-avatar-async.py index 423e9ff8d..a3e250ab5 100644 --- a/tests/twisted/vcard/test-avatar-async.py +++ b/tests/twisted/vcard/test-avatar-async.py @@ -48,7 +48,7 @@ def test(q, bus, conn, stream): # When we start, there is no avatar acknowledge_iq(stream, iq_event.stanza) - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") # Another resource confirms we have no avatar. We don't request our vCard # because we already know there is no avatar @@ -66,7 +66,7 @@ def test(q, bus, conn, stream): q.unforbid_events([avatar_request_event, avatar_retrieved_event]) # Request on the first contact. Test the cache. - handle = conn.RequestHandles(cs.HT_CONTACT, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') test_get_avatar(q, bus, conn, stream, 'bob@foo.com', handle, in_cache=False) test_get_avatar(q, bus, conn, stream, 'bob@foo.com', handle, @@ -74,7 +74,7 @@ def test(q, bus, conn, stream): # Request another vCard and get resource-constraint busy_contact = 'jean@busy-server.com' - busy_handle = conn.RequestHandles(cs.HT_CONTACT, [busy_contact])[0] + busy_handle = conn.get_contact_handle_sync(busy_contact) conn.Avatars.RequestAvatars([busy_handle]) iq_event = q.expect('stream-iq', to=busy_contact, query_ns='vcard-temp', @@ -97,7 +97,7 @@ def test(q, bus, conn, stream): # Request on a different contact, on another server # We should get the avatar - handle = conn.RequestHandles(cs.HT_CONTACT, ['bob2@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob2@foo.com') test_get_avatar(q, bus, conn, stream, 'bob2@foo.com', handle) # Try again the contact on the busy server. @@ -180,26 +180,23 @@ def test(q, bus, conn, stream): # Gabble must reply without asking the vCard to the server because the # avatar must be in the cache q.forbid_events([avatar_request_event]) - data, mime = conn.Avatars.RequestAvatar(self_handle, byte_arrays=True) - assertEquals('\o/', data) - data, mime = conn.Avatars.RequestAvatar(handle, byte_arrays=True) - assertEquals('hello', data) + conn.Avatars.RequestAvatars([self_handle]) + e = q.expect('dbus-signal', signal='AvatarRetrieved') + assertEquals('\o/', e.args[2]) + conn.Avatars.RequestAvatars([handle]) + e = q.expect('dbus-signal', signal='AvatarRetrieved') + assertEquals('hello', e.args[2]) q.unforbid_events([avatar_request_event]) # First, ensure the pipeline is full contacts = ['random_user_%s@bigserver.com' % i for i in range(1, 100) ] - handles = conn.RequestHandles(cs.HT_CONTACT, contacts) + handles = conn.get_contact_handles_sync(contacts) conn.Avatars.RequestAvatars(handles) # Then, request yet another avatar. The request will time out before # the IQ is sent, which used to trigger a crash in Gabble - # (LP#445847). So, we assert that the error is NotAvailable (rather - # than the error returned when the service crashes). - try: - conn.Avatars.RequestAvatar(handles[-1]) - except dbus.DBusException, e: - assertEquals(cs.NOT_AVAILABLE, e.get_dbus_name()) - else: - assert False + # (LP#445847). + conn.Avatars.RequestAvatars([handles[-1]]) + sync_dbus(bus, q, conn) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/vcard/test-avatar-retrieved.py b/tests/twisted/vcard/test-avatar-retrieved.py index b612ca901..c332d5cfb 100644 --- a/tests/twisted/vcard/test-avatar-retrieved.py +++ b/tests/twisted/vcard/test-avatar-retrieved.py @@ -16,7 +16,7 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, iq_event.stanza) - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] + handle = conn.get_contact_handle_sync('bob@foo.com') conn.Avatars.RequestAvatars([handle]) conn.Avatars.RequestAvatars([handle]) conn.Avatars.RequestAvatars([handle]) diff --git a/tests/twisted/vcard/test-avatar-tokens.py b/tests/twisted/vcard/test-avatar-tokens.py index 59f01c092..281a733bc 100644 --- a/tests/twisted/vcard/test-avatar-tokens.py +++ b/tests/twisted/vcard/test-avatar-tokens.py @@ -5,7 +5,7 @@ Test GetAvatarTokens() and GetKnownAvatarTokens(). from twisted.words.xish import domish -from servicetest import unwrap, EventPattern +from servicetest import unwrap, assertEquals from gabbletest import exec_test, make_result_iq import ns import constants as cs @@ -41,11 +41,14 @@ def test(q, bus, conn, stream): stream.send(make_presence('che@foo.com', None)) q.expect('dbus-signal', signal='AvatarUpdated') - handles = conn.RequestHandles(1, [ + handles = conn.get_contact_handles_sync([ 'amy@foo.com', 'bob@foo.com', 'che@foo.com', 'daf@foo.com' ]) - tokens = unwrap(conn.Avatars.GetAvatarTokens(handles)) - assert tokens == ['SHA1SUM-FOR-AMY', 'SHA1SUM-FOR-BOB', '', ''] + h2asv = conn.Contacts.GetContactAttributes(handles, [cs.CONN_IFACE_AVATARS], False) + assertEquals('SHA1SUM-FOR-AMY', h2asv[handles[0]][cs.ATTR_AVATAR_TOKEN]) + assertEquals('SHA1SUM-FOR-BOB', h2asv[handles[1]][cs.ATTR_AVATAR_TOKEN]) + assertEquals('', h2asv[handles[2]][cs.ATTR_AVATAR_TOKEN]) + assertEquals(None, h2asv[handles[3]].get(cs.ATTR_AVATAR_TOKEN)) tokens = unwrap(conn.Avatars.GetKnownAvatarTokens(handles)) tokens = sorted(tokens.items()) diff --git a/tests/twisted/vcard/test-avatar.py b/tests/twisted/vcard/test-avatar.py index f72e8edb5..834c9e7fa 100644 --- a/tests/twisted/vcard/test-avatar.py +++ b/tests/twisted/vcard/test-avatar.py @@ -5,9 +5,8 @@ Test avatar support. import base64 -from servicetest import call_async, EventPattern +from servicetest import call_async, assertEquals from gabbletest import exec_test, acknowledge_iq, make_result_iq -import constants as cs def test(q, bus, conn, stream): event = q.expect('stream-iq', to=None, query_ns='vcard-temp', @@ -15,8 +14,8 @@ def test(q, bus, conn, stream): acknowledge_iq(stream, event.stanza) - handle = conn.RequestHandles(1, ['bob@foo.com'])[0] - call_async(q, conn.Avatars, 'RequestAvatar', handle, byte_arrays=True) + handle = conn.get_contact_handle_sync('bob@foo.com') + call_async(q, conn.Avatars, 'RequestAvatars', [handle]) event = q.expect('stream-iq', iq_type='get', to='bob@foo.com', query_ns='vcard-temp', query_name='vCard') @@ -26,8 +25,9 @@ def test(q, bus, conn, stream): photo.addElement('BINVAL', content=base64.b64encode('hello')) stream.send(result) - q.expect('dbus-return', method='RequestAvatar', - value=('hello', 'image/png')) + e = q.expect('dbus-signal', signal='AvatarRetrieved') + assertEquals('hello', e.args[2]) + assertEquals('image/png', e.args[3]) if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/vcard/test-set-alias.py b/tests/twisted/vcard/test-set-alias.py index 9545ef90c..8d69d5193 100644 --- a/tests/twisted/vcard/test-set-alias.py +++ b/tests/twisted/vcard/test-set-alias.py @@ -22,7 +22,7 @@ def validate_pep_update(pep_update, expected_nickname): assertLength(0, nick.children) def test(q, bus, conn, stream): - self_handle = conn.GetSelfHandle() + self_handle = conn.Properties.Get(cs.CONN, "SelfHandle") conn.Aliasing.SetAliases({self_handle: 'lala'}) expect_and_handle_get_vcard(q, stream) diff --git a/tests/twisted/vcard/test-vcard-cache.py b/tests/twisted/vcard/test-vcard-cache.py index 083f5b5e1..f1cbfcd98 100644 --- a/tests/twisted/vcard/test-vcard-cache.py +++ b/tests/twisted/vcard/test-vcard-cache.py @@ -17,8 +17,8 @@ def test(q, bus, conn, stream): # Request our alias and avatar, expect them to be resolved from cache. - handle = conn.GetSelfHandle() - call_async(q, conn.Avatars, 'RequestAvatar', handle) + handle = conn.Properties.Get(cs.CONN, "SelfHandle") + call_async(q, conn.Avatars, 'RequestAvatars', [handle]) call_async(q, conn.Aliasing, 'RequestAliases', [handle]) # FIXME - find out why RequestAliases returns before RequestAvatar even @@ -30,15 +30,10 @@ def test(q, bus, conn, stream): r1, r2 = q.expect_many( EventPattern('dbus-return', method='RequestAliases'), - EventPattern('dbus-error', method='RequestAvatar')) + EventPattern('dbus-return', method='RequestAvatars')) # Default alias is our jid assert r1.value[0] == ['test@localhost'] - # We don't have a vCard yet - assert r2.error.get_dbus_name() == cs.NOT_AVAILABLE, \ - r2.error.get_dbus_name() - assert r2.error.args[0] == 'contact vCard has no photo' - if __name__ == '__main__': exec_test(test) diff --git a/tests/twisted/vcard/test-vcard-race.py b/tests/twisted/vcard/test-vcard-race.py index 5ecd978e1..9fa61e686 100644 --- a/tests/twisted/vcard/test-vcard-race.py +++ b/tests/twisted/vcard/test-vcard-race.py @@ -18,6 +18,7 @@ from gabbletest import ( exec_test, expect_and_handle_get_vcard, expect_and_handle_set_vcard, make_result_iq, sync_stream) import ns +import constants as cs def test(q, bus, conn, stream): expect_and_handle_get_vcard(q, stream) @@ -27,7 +28,7 @@ def test(q, bus, conn, stream): # to reply and then set immediately. sync_stream(q, stream) - handle = conn.GetSelfHandle() + handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Aliasing, 'SetAliases', {handle: 'Some Guy'}) diff --git a/tests/twisted/vcard/update-get-failed.py b/tests/twisted/vcard/update-get-failed.py index 225b70ecf..7580f25c2 100644 --- a/tests/twisted/vcard/update-get-failed.py +++ b/tests/twisted/vcard/update-get-failed.py @@ -17,7 +17,7 @@ def test(q, bus, conn, stream): # Force Gabble to process the vCard before calling any methods. sync_stream(q, stream) - handle = conn.GetSelfHandle() + handle = conn.Properties.Get(cs.CONN, "SelfHandle") call_async(q, conn.Avatars, 'SetAvatar', 'william shatner', 'image/x-actor-name') diff --git a/tests/twisted/version.py b/tests/twisted/version.py index 8bd37d888..bbc2b92c9 100644 --- a/tests/twisted/version.py +++ b/tests/twisted/version.py @@ -4,7 +4,7 @@ Tests Gabble's implementation of XEP-0092. """ from twisted.words.xish import xpath -from servicetest import assertLength, assertEquals +from servicetest import assertLength from gabbletest import exec_test, elem_iq, elem import ns diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py index c7a93d371..a08afee06 100644 --- a/tools/c-constants-gen.py +++ b/tools/c-constants-gen.py @@ -3,7 +3,7 @@ from sys import argv, stdout, stderr import xml.dom.minidom -from libtpcodegen import file_set_contents +from libtpcodegen import file_set_contents, u from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path @@ -12,7 +12,7 @@ class Generator(object): self.prefix = prefix + '_' self.spec = get_by_path(dom, "spec")[0] - self.output_base = output_base + self.output_base = output_base self.__header = [] self.__docs = [] @@ -21,14 +21,14 @@ class Generator(object): 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)) + file_set_contents(self.output_base + '.h', u('').join(self.__header).encode('utf-8')) + file_set_contents(self.output_base + '-gtk-doc.h', u('').join(self.__docs).encode('utf-8')) def write(self, code): - self.__header.append(code.encode('utf-8')) + self.__header.append(code) def d(self, code): - self.__docs.append(code.encode('utf-8')) + self.__docs.append(code) # Header def do_header(self): diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py index f8465a62b..a0fecf083 100644 --- a/tools/glib-client-gen.py +++ b/tools/glib-client-gen.py @@ -27,9 +27,9 @@ 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 +from libtpcodegen import file_set_contents, key_by_name, u +from libglibcodegen import (Signature, type_to_gtype, + get_docstring, xml_escape, get_deprecated, copy_into_gvalue) NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" @@ -74,18 +74,12 @@ class Generator(object): 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): @@ -192,6 +186,7 @@ class Generator(object): self.b(' TpProxySignalConnection *sc)') self.b('{') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') self.b(' GValueArray *args = g_value_array_new (%d);' % len(args)) self.b(' GValue blank = { 0 };') self.b(' guint i;') @@ -200,6 +195,7 @@ class Generator(object): self.b('') self.b(' for (i = 0; i < %d; i++)' % len(args)) self.b(' g_value_array_append (args, &blank);') + self.b(' G_GNUC_END_IGNORE_DEPRECATIONS') self.b('') for i, arg in enumerate(args): @@ -209,36 +205,8 @@ class Generator(object): 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(' ' + copy_into_gvalue('args->values + %d' % i, + gtype, marshaller, name)) self.b('') self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);') @@ -288,12 +256,14 @@ class Generator(object): self.b(' weak_object);') self.b('') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') 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_GNUC_END_IGNORE_DEPRECATIONS') self.b(' g_object_unref (tpproxy);') self.b('}') @@ -559,11 +529,13 @@ class Generator(object): self.b(' return;') self.b(' }') self.b('') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') 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);') + self.b(' G_GNUC_END_IGNORE_DEPRECATIONS') for i, arg in enumerate(out_args): name, info, tp_type, elt = arg @@ -573,36 +545,8 @@ class Generator(object): 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(' ' + copy_into_gvalue('args->values + %d' % i, + gtype, marshaller, name)) self.b(' tp_proxy_pending_call_v0_take_results (user_data, ' 'NULL, args);') @@ -671,11 +615,13 @@ class Generator(object): self.b(' error, user_data, weak_object);') self.b('') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') 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(' G_GNUC_END_IGNORE_DEPRECATIONS') self.b('}') self.b('') @@ -948,11 +894,13 @@ class Generator(object): self.b('') + self.b(' G_GNUC_BEGIN_IGNORE_DEPRECATIONS') 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(' G_GNUC_END_IGNORE_DEPRECATIONS') self.b('}') self.b('') @@ -1191,7 +1139,7 @@ class Generator(object): self.b('') nodes = self.dom.getElementsByTagName('node') - nodes.sort(cmp_by_name) + nodes.sort(key=key_by_name) for node in nodes: self.do_interface(node) @@ -1244,9 +1192,9 @@ class Generator(object): 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)) + file_set_contents(self.basename + '.h', u('\n').join(self.__header).encode('utf-8')) + file_set_contents(self.basename + '-body.h', u('\n').join(self.__body).encode('utf-8')) + file_set_contents(self.basename + '-gtk-doc.h', u('\n').join(self.__docs).encode('utf-8')) def types_to_gtypes(types): return [type_to_gtype(t)[1] for t in types] diff --git a/tools/glib-client-marshaller-gen.py b/tools/glib-client-marshaller-gen.py index cb27d638a..cd9823bdf 100644 --- a/tools/glib-client-marshaller-gen.py +++ b/tools/glib-client-marshaller-gen.py @@ -31,23 +31,23 @@ class Generator(object): for signal in signals: self.do_signal(signal) - print 'void' - print '%s_register_dbus_glib_marshallers (void)' % self.prefix - print '{' + print('void') + print('%s_register_dbus_glib_marshallers (void)' % self.prefix) + print('{') - all = self.marshallers.keys() + all = list(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 */' + 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(' G_TYPE_%s,' % type.replace('VOID', 'NONE')) + print(' G_TYPE_INVALID);') - print '}' + print('}') def types_to_gtypes(types): diff --git a/tools/glib-errors-check-gen.py b/tools/glib-errors-check-gen.py index 553fc9caf..fad261ece 100644 --- a/tools/glib-errors-check-gen.py +++ b/tools/glib-errors-check-gen.py @@ -12,13 +12,13 @@ class Generator(object): 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);' + 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') @@ -28,30 +28,30 @@ class Generator(object): 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 '}' + 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:] diff --git a/tools/glib-errors-str-gen.py b/tools/glib-errors-str-gen.py index b2cf520bd..ddb1e16b7 100644 --- a/tools/glib-errors-str-gen.py +++ b/tools/glib-errors-str-gen.py @@ -3,7 +3,7 @@ import sys import xml.dom.minidom -from libtpcodegen import file_set_contents +from libtpcodegen import file_set_contents, u from libglibcodegen import NS_TP, get_docstring, xml_escape class Generator(object): @@ -17,18 +17,12 @@ class Generator(object): 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): @@ -72,9 +66,9 @@ class Generator(object): 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)) + file_set_contents(self.basename + '.h', u('\n').join(self.__header).encode('utf-8')) + file_set_contents(self.basename + '.c', u('\n').join(self.__body).encode('utf-8')) + file_set_contents(self.basename + '-gtk-doc.h', u('\n').join(self.__docs).encode('utf-8')) if __name__ == '__main__': argv = sys.argv[1:] diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py index 6fec0d3c4..c0ce20ddc 100644 --- a/tools/glib-ginterface-gen.py +++ b/tools/glib-ginterface-gen.py @@ -26,8 +26,8 @@ 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, \ +from libtpcodegen import file_set_contents, key_by_name, u +from libglibcodegen import Signature, type_to_gtype, \ NS_TP, dbus_gutils_wincaps_to_uscore @@ -85,18 +85,12 @@ class Generator(object): self.allow_havoc = allow_havoc 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 do_node(self, node): @@ -733,7 +727,7 @@ class Generator(object): def __call__(self): nodes = self.dom.getElementsByTagName('node') - nodes.sort(cmp_by_name) + nodes.sort(key=key_by_name) self.h('#include <glib-object.h>') self.h('#include <dbus/dbus-glib.h>') @@ -761,12 +755,12 @@ class Generator(object): 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)) + file_set_contents(self.basename + '.h', u('\n').join(self.__header).encode('utf-8')) + file_set_contents(self.basename + '.c', u('\n').join(self.__body).encode('utf-8')) + file_set_contents(self.basename + '-gtk-doc.h', u('\n').join(self.__docs).encode('utf-8')) def cmdline_error(): - print """\ + print("""\ usage: gen-ginterface [OPTIONS] xmlfile Prefix_ options: @@ -786,7 +780,7 @@ options: void symbol (DBusGMethodInvocation *context) and return some sort of "not implemented" error via dbus_g_method_return_error (context, ...) -""" +""") sys.exit(1) diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py index 21dfc6aa7..1477bd37b 100644 --- a/tools/glib-gtypes-generator.py +++ b/tools/glib-gtypes-generator.py @@ -23,7 +23,7 @@ import sys import xml.dom.minidom -from libtpcodegen import file_set_contents +from libtpcodegen import file_set_contents, u from libglibcodegen import escape_as_identifier, \ get_docstring, \ NS_TP, \ @@ -68,13 +68,13 @@ class GTypesGenerator(object): self.need_other_arrays = {} def h(self, code): - self.header.append(code.encode("utf-8")) + self.header.append(code) def c(self, code): - self.body.append(code.encode("utf-8")) + self.body.append(code) def d(self, code): - self.docs.append(code.encode('utf-8')) + self.docs.append(code) def do_mapping_header(self, mapping): members = mapping.getElementsByTagNameNS(NS_TP, 'member') @@ -292,9 +292,9 @@ 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)) + file_set_contents(self.output + '.h', u('').join(self.header).encode('utf-8')) + file_set_contents(self.output + '-body.h', u('').join(self.body).encode('utf-8')) + file_set_contents(self.output + '-gtk-doc.h', u('').join(self.docs).encode('utf-8')) if __name__ == '__main__': argv = sys.argv[1:] diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py index 410762cde..b67d7b4f0 100644 --- a/tools/glib-interfaces-gen.py +++ b/tools/glib-interfaces-gen.py @@ -3,7 +3,7 @@ from sys import argv, stdout, stderr import xml.dom.minidom -from libtpcodegen import file_set_contents +from libtpcodegen import file_set_contents, u from libglibcodegen import NS_TP, get_docstring, \ get_descendant_text, get_by_path @@ -24,22 +24,22 @@ class Generator(object): self.spec = get_by_path(dom, "spec")[0] def h(self, code): - self.decls.append(code.encode('utf-8')) + self.decls.append(code) def c(self, code): - self.impls.append(code.encode('utf-8')) + self.impls.append(code) def d(self, code): - self.docs.append(code.encode('utf-8')) + self.docs.append(code) 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)) + file_set_contents(self.implfile, u('').join(self.impls).encode('utf-8')) + file_set_contents(self.declfile, u('').join(self.decls).encode('utf-8')) + file_set_contents(self.docfile, u('').join(self.docs).encode('utf-8')) # Header def do_header(self, f): diff --git a/tools/gobject-foo.py b/tools/gobject-foo.py index 002a290ba..a2abd7667 100644 --- a/tools/gobject-foo.py +++ b/tools/gobject-foo.py @@ -87,4 +87,4 @@ if __name__ == '__main__': head, tail = argv - print '\n'.join(gobject_header(head, tail, as_interface=as_interface)) + print('\n'.join(gobject_header(head, tail, as_interface=as_interface))) diff --git a/tools/lcov.am b/tools/lcov.am index 80023cb78..d2d282ac3 100644 --- a/tools/lcov.am +++ b/tools/lcov.am @@ -7,7 +7,7 @@ lcov-report: lcov --directory @top_srcdir@ --output-file @top_builddir@/lcov.info \ --remove @top_builddir@/lcov.info.tmp telepathy-glib-scan.c rm @top_builddir@/lcov.info.tmp - $(mkdir_p) @top_builddir@/lcov.html + $(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" \ diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py index 6a9d21485..0b703a5a8 100644 --- a/tools/libglibcodegen.py +++ b/tools/libglibcodegen.py @@ -154,7 +154,7 @@ def type_to_gtype(s): return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False) elif s[:2] == 'a{': #some arbitrary hash tables if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'): - raise Exception, "can't index a hashtable off non-basic type " + s + raise Exception("can't index a hashtable off non-basic type " + s) first = type_to_gtype(s[2]) second = type_to_gtype(s[3:-1]) return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False) @@ -169,4 +169,27 @@ def type_to_gtype(s): return ("GValueArray *", gtype, "BOXED", True) # we just don't know .. - raise Exception, "don't know the GType for " + s + raise Exception("don't know the GType for " + s) + + +def copy_into_gvalue(gvaluep, gtype, marshaller, name): + if gtype == 'G_TYPE_STRING': + return 'g_value_set_string (%s, %s);' % (gvaluep, name) + elif marshaller == 'BOXED': + return 'g_value_set_boxed (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_UCHAR': + return 'g_value_set_uchar (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_BOOLEAN': + return 'g_value_set_boolean (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_INT': + return 'g_value_set_int (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_UINT': + return 'g_value_set_uint (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_INT64': + return 'g_value_set_int (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_UINT64': + return 'g_value_set_uint64 (%s, %s);' % (gvaluep, name) + elif gtype == 'G_TYPE_DOUBLE': + return 'g_value_set_double (%s, %s);' % (gvaluep, name) + else: + raise AssertionError("Don't know how to put %s in a GValue" % gtype) diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py index 7e9eb9a50..99de66340 100644 --- a/tools/libtpcodegen.py +++ b/tools/libtpcodegen.py @@ -21,6 +21,7 @@ please make any changes there. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os +import sys from string import ascii_letters, digits @@ -28,6 +29,20 @@ NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" _ASCII_ALNUM = ascii_letters + digits +if sys.version_info[0] >= 3: + def u(s): + """Return s, which must be a str literal with no non-ASCII characters. + This is like a more restricted form of the Python 2 u'' syntax. + """ + return s.encode('ascii').decode('ascii') +else: + def u(s): + """Return a Unicode version of s, which must be a str literal + (a bytestring) in which each byte is an ASCII character. + This is like a more restricted form of the u'' syntax. + """ + return s.decode('ascii') + def file_set_contents(filename, contents): try: os.remove(filename) @@ -38,13 +53,15 @@ def file_set_contents(filename, contents): except OSError: pass - open(filename + '.tmp', 'w').write(contents) + open(filename + '.tmp', 'wb').write(contents) os.rename(filename + '.tmp', filename) def cmp_by_name(node1, node2): return cmp(node1.getAttributeNode("name").nodeValue, node2.getAttributeNode("name").nodeValue) +def key_by_name(node): + return node.getAttributeNode("name").nodeValue def escape_as_identifier(identifier): """Escape the given string to be a valid D-Bus object path or service @@ -168,6 +185,9 @@ class _SignatureIter: self.remaining = string def next(self): + return self.__next__() + + def __next__(self): if self.remaining == '': raise StopIteration diff --git a/tools/make-version-script.py b/tools/make-version-script.py index 0d30aa323..4ced849fe 100644 --- a/tools/make-version-script.py +++ b/tools/make-version-script.py @@ -63,9 +63,9 @@ def main(abifiles, symbols=None, unreleased_version=None, if dpkg: assert dpkg_first_line is not None - print dpkg_first_line + print(dpkg_first_line) if dpkg_build_depends_package is not None: - print "* Build-Depends-Package: %s" % dpkg_build_depends_package + print("* Build-Depends-Package: %s" % dpkg_build_depends_package) for filename in abifiles: lines = open(filename, 'r').readlines() @@ -120,8 +120,8 @@ def main(abifiles, symbols=None, unreleased_version=None, lines = lines[cut:] if gnuld: - print "%s {" % version - print " global:" + print("%s {" % version) + print(" global:") for symbol in lines: symbol = symbol.strip() @@ -130,7 +130,7 @@ def main(abifiles, symbols=None, unreleased_version=None, continue if gnuld: - print " %s;" % symbol + print(" %s;" % symbol) elif dpkg: dpkg_symbols.append('%s@%s %s' % (symbol, version, release)) @@ -142,22 +142,22 @@ def main(abifiles, symbols=None, unreleased_version=None, if gnuld: if extends == '-': - print " local:" - print " *;" - print "};" + print(" local:") + print(" *;") + print("};") else: - print "} %s;" % extends - print + print("} %s;" % extends) + print("") if dpkg: dpkg_symbols.sort() dpkg_versions.sort() for x in dpkg_versions: - print " %s" % x + print(" %s" % x) for x in dpkg_symbols: - print " %s" % x + print(" %s" % x) if symbol_set is not None: missing = versioned_symbols - symbol_set @@ -182,13 +182,13 @@ def main(abifiles, symbols=None, unreleased_version=None, raise SystemExit(1) if gnuld: - print "%s {" % unreleased_version - print " global:" + print("%s {" % unreleased_version) + print(" global:") for symbol in unreleased: - print " %s;" % symbol + print(" %s;" % symbol) - print "} %s;" % version + print("} %s;" % version) if __name__ == '__main__': diff --git a/tools/xincludator.py b/tools/xincludator.py index 63e106ace..f9ed49ce4 100644 --- a/tools/xincludator.py +++ b/tools/xincludator.py @@ -1,17 +1,19 @@ #!/usr/bin/python +import sys from sys import argv, stdout, stderr import codecs, locale import os import xml.dom.minidom -stdout = codecs.getwriter('utf-8')(stdout) +if sys.version_info[0] < 3: + stdout = codecs.getwriter('utf-8')(stdout) NS_XI = 'http://www.w3.org/2001/XInclude' def xincludate(dom, base, dropns = []): remove_attrs = [] - for i in xrange(dom.documentElement.attributes.length): + for i in range(dom.documentElement.attributes.length): attr = dom.documentElement.attributes.item(i) if attr.prefix == 'xmlns': if attr.localName in dropns: @@ -34,6 +36,11 @@ if __name__ == '__main__': argv = argv[1:] dom = xml.dom.minidom.parse(argv[0]) xincludate(dom, argv[0]) - xml = dom.toxml() + + if sys.version_info[0] >= 3: + xml = dom.toxml(encoding=None) + else: + xml = dom.toxml() + stdout.write(xml) stdout.write('\n') |