summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--docs/reference/telepathy-glib-sections.txt20
-rw-r--r--examples/client/approver.c5
-rw-r--r--m4/tp-linker-flag.m42
-rw-r--r--spec/Channel_Dispatcher.xml147
-rw-r--r--spec/Channel_Interface_SMS.xml78
-rw-r--r--spec/Connection_Interface_Location.xml2
-rw-r--r--spec/all.xml2
-rw-r--r--telepathy-glib/account-manager.c2
-rw-r--r--telepathy-glib/account.c60
-rw-r--r--telepathy-glib/base-client-internal.h3
-rw-r--r--telepathy-glib/base-client.c28
-rw-r--r--telepathy-glib/base-client.h5
-rw-r--r--telepathy-glib/channel-dispatch-operation.c162
-rw-r--r--telepathy-glib/channel-dispatch-operation.h16
-rw-r--r--telepathy-glib/channel.c39
-rw-r--r--telepathy-glib/connection-avatars.c38
-rw-r--r--telepathy-glib/connection-contact-info.c43
-rw-r--r--telepathy-glib/connection-internal.h14
-rw-r--r--telepathy-glib/connection.c121
-rw-r--r--telepathy-glib/group-mixin.c42
-rw-r--r--telepathy-glib/proxy-internal.h18
-rw-r--r--telepathy-glib/proxy.c602
-rw-r--r--telepathy-glib/proxy.h26
-rw-r--r--telepathy-glib/text-channel.c77
-rw-r--r--tests/dbus/Makefile.am3
-rw-r--r--tests/dbus/account-channel-request.c6
-rw-r--r--tests/dbus/base-client.c114
-rw-r--r--tests/dbus/call-example.c6
-rw-r--r--tests/dbus/callable-example.c3
-rw-r--r--tests/dbus/channel-dispatch-operation.c6
-rw-r--r--tests/dbus/channel-dispatcher.c3
-rw-r--r--tests/dbus/channel-request.c3
-rw-r--r--tests/dbus/channel.c6
-rw-r--r--tests/dbus/client-channel-factory.c6
-rw-r--r--tests/dbus/client.c3
-rw-r--r--tests/dbus/cm.c3
-rw-r--r--tests/dbus/connection-interests.c3
-rw-r--r--tests/dbus/connection.c3
-rw-r--r--tests/dbus/contact-lists.c3
-rw-r--r--tests/dbus/contacts-slow-path.c6
-rw-r--r--tests/dbus/contacts.c14
-rw-r--r--tests/dbus/dbus.c6
-rw-r--r--tests/dbus/get-interface-after-invalidate.c3
-rw-r--r--tests/dbus/group-mixin.c14
-rw-r--r--tests/dbus/params-cm.c3
-rw-r--r--tests/dbus/protocol-objects.c3
-rw-r--r--tests/dbus/proxy-preparation.c399
-rw-r--r--tests/dbus/self-handle.c5
-rw-r--r--tests/dbus/simple-approver.c6
-rw-r--r--tests/dbus/simple-handler.c6
-rw-r--r--tests/dbus/simple-observer.c6
-rw-r--r--tests/dbus/stream-tube.c6
-rw-r--r--tests/dbus/text-channel.c6
-rw-r--r--tests/dtmf-player.c3
-rw-r--r--tests/lib/Makefile.am2
-rw-r--r--tests/lib/my-conn-proxy.c333
-rw-r--r--tests/lib/my-conn-proxy.h115
-rw-r--r--tests/lib/util.c11
-rw-r--r--tests/lib/util.h3
60 files changed, 2207 insertions, 468 deletions
diff --git a/configure.ac b/configure.ac
index 7340cb34..568fd9bb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -183,7 +183,7 @@ AM_CONDITIONAL([OUT_OF_TREE_BUILD], [test "z$ac_srcdir" != z.])
dnl Check for Glib
PKG_CHECK_MODULES(GLIB,
- [glib-2.0 >= 2.25.16, gobject-2.0 >= 2.25.16, gio-2.0 >= 2.25.16])
+ [glib-2.0 >= 2.28.0, gobject-2.0 >= 2.28.0, gio-2.0 >= 2.28.0])
dnl Check for GIO-Unix
PKG_CHECK_MODULES(GIO_UNIX, [gio-unix-2.0],
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index d95ce7fb..723d1d59 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -468,6 +468,9 @@ TP_SVC_CHANNEL_INTERFACE_PASSWORD_GET_CLASS
TpSvcChannelInterfaceSMS
TpSvcChannelInterfaceSMSClass
tp_svc_channel_interface_sms_emit_sms_channel_changed
+tp_svc_channel_interface_sms_get_sms_length_impl
+tp_svc_channel_interface_sms_implement_get_sms_length
+tp_svc_channel_interface_sms_return_from_get_sms_length
<SUBSECTION Standard>
tp_svc_channel_interface_sms_get_type
TP_TYPE_SVC_CHANNEL_INTERFACE_SMS
@@ -2937,6 +2940,7 @@ tp_iface_quark_connection_interface_service_point
<TITLE>proxy</TITLE>
<INCLUDE>telepathy-glib/proxy.h</INCLUDE>
TpProxy
+TpProxyPrepareAsync
TpProxyFeature
TpProxyClassFeatureListFunc
TpProxyClass
@@ -2970,6 +2974,7 @@ TP_IS_PROXY_CLASS
TP_PROXY
TP_PROXY_CLASS
TP_PROXY_GET_CLASS
+TpProxyFeaturePrivate
</SECTION>
<SECTION>
@@ -3225,6 +3230,9 @@ tp_cli_channel_interface_password_signal_callback_password_flags_changed
<SUBSECTION>
tp_cli_channel_interface_sms_connect_to_sms_channel_changed
tp_cli_channel_interface_sms_signal_callback_sms_channel_changed
+tp_cli_channel_interface_sms_call_get_sms_length
+tp_cli_channel_interface_sms_callback_for_get_sms_length
+tp_cli_channel_interface_sms_run_get_sms_length
</SECTION>
<SECTION>
@@ -4440,6 +4448,10 @@ tp_cli_channel_dispatcher_callback_for_ensure_channel
tp_cli_channel_dispatcher_call_ensure_channel
tp_cli_channel_dispatcher_callback_for_ensure_channel_with_hints
tp_cli_channel_dispatcher_call_ensure_channel_with_hints
+tp_cli_channel_dispatcher_call_delegate_channels
+tp_cli_channel_dispatcher_call_present_channel
+tp_cli_channel_dispatcher_callback_for_delegate_channels
+tp_cli_channel_dispatcher_callback_for_present_channel
<SUBSECTION>
tp_cli_channel_dispatcher_interface_operation_list_signal_callback_dispatch_operation_finished
tp_cli_channel_dispatcher_interface_operation_list_connect_to_dispatch_operation_finished
@@ -4475,6 +4487,12 @@ tp_svc_channel_dispatcher_implement_ensure_channel
tp_svc_channel_dispatcher_return_from_ensure_channel_with_hints
tp_svc_channel_dispatcher_ensure_channel_with_hints_impl
tp_svc_channel_dispatcher_implement_ensure_channel_with_hints
+tp_svc_channel_dispatcher_delegate_channels_impl
+tp_svc_channel_dispatcher_implement_delegate_channels
+tp_svc_channel_dispatcher_implement_present_channel
+tp_svc_channel_dispatcher_present_channel_impl
+tp_svc_channel_dispatcher_return_from_delegate_channels
+tp_svc_channel_dispatcher_return_from_present_channel
<SUBSECTION>
TpSvcChannelDispatcherInterfaceOperationList
TpSvcChannelDispatcherInterfaceOperationListClass
@@ -4524,6 +4542,8 @@ tp_channel_dispatch_operation_handle_with_time_async
tp_channel_dispatch_operation_handle_with_time_finish
tp_channel_dispatch_operation_claim_async
tp_channel_dispatch_operation_claim_finish
+tp_channel_dispatch_operation_claim_with_async
+tp_channel_dispatch_operation_claim_with_finish
<SUBSECTION Standard>
TP_CHANNEL_DISPATCH_OPERATION
TP_CHANNEL_DISPATCH_OPERATION_CLASS
diff --git a/examples/client/approver.c b/examples/client/approver.c
index f100f52c..1a48fced 100644
--- a/examples/client/approver.c
+++ b/examples/client/approver.c
@@ -59,7 +59,7 @@ claim_cb (GObject *source,
GPtrArray *channels;
guint i;
- if (!tp_channel_dispatch_operation_claim_finish (cdo, result, &error))
+ if (!tp_channel_dispatch_operation_claim_with_finish (cdo, result, &error))
{
g_print ("Claim() failed: %s\n", error->message);
g_error_free (error);
@@ -137,7 +137,8 @@ add_dispatch_operation_cb (TpSimpleApprover *self,
{
g_print ("Dissaprove channels\n");
- tp_channel_dispatch_operation_claim_async (cdo, claim_cb, NULL);
+ tp_channel_dispatch_operation_claim_with_async (cdo,
+ TP_BASE_CLIENT (self), claim_cb, NULL);
}
else
{
diff --git a/m4/tp-linker-flag.m4 b/m4/tp-linker-flag.m4
index 23eb41ad..8fd35068 100644
--- a/m4/tp-linker-flag.m4
+++ b/m4/tp-linker-flag.m4
@@ -22,7 +22,7 @@ AC_DEFUN([TP_LINKER_FLAG],
save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $1"
- AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], []), [flag_ok=yes], [flag_ok=no])
+ AC_COMPILE_IFELSE(AC_LANG_SOURCE([]), [flag_ok=yes], [flag_ok=no])
LDFLAGS="$save_LDFLAGS"
diff --git a/spec/Channel_Dispatcher.xml b/spec/Channel_Dispatcher.xml
index 2dd000b4..2de52800 100644
--- a/spec/Channel_Dispatcher.xml
+++ b/spec/Channel_Dispatcher.xml
@@ -168,10 +168,10 @@
<tp:possible-errors>
<tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
<tp:docstring>
- The Preferred_Handler is syntactically invalid or does
+ The <var>Preferred_Handler</var> is syntactically invalid or does
not start with <code>org.freedesktop.Telepathy.Client.</code>,
- the Account does not exist, or one of the Requested_Properties
- is invalid
+ the <var>Account</var> does not exist, or one of the
+ <var>Requested_Properties</var> is invalid
</tp:docstring>
</tp:error>
</tp:possible-errors>
@@ -240,10 +240,10 @@
<tp:possible-errors>
<tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
<tp:docstring>
- The Preferred_Handler is syntactically invalid or does
+ The <var>Preferred_Handler</var> is syntactically invalid or does
not start with <code>org.freedesktop.Telepathy.Client.</code>,
- the Account does not exist, or one of the Requested_Properties
- is invalid
+ the <var>Account</var> does not exist, or one of the
+ <var>Requested_Properties</var> is invalid
</tp:docstring>
</tp:error>
</tp:possible-errors>
@@ -418,10 +418,10 @@
<tp:possible-errors>
<tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
<tp:docstring>
- The Preferred_Handler is syntactically invalid or does
+ The <var>Preferred_Handler</var> is syntactically invalid or does
not start with <code>org.freedesktop.Telepathy.Client.</code>,
- the Account does not exist, or one of the Requested_Properties
- is invalid
+ the <var>Account</var> does not exist, or one of the
+ <var>Requested_Properties</var> is invalid
</tp:docstring>
</tp:error>
</tp:possible-errors>
@@ -559,16 +559,139 @@
<tp:possible-errors>
<tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
<tp:docstring>
- The Preferred_Handler is syntactically invalid or does
+ The <var>Preferred_Handler</var> is syntactically invalid or does
not start with <code>org.freedesktop.Telepathy.Client.</code>,
- the Account does not exist, or one of the Requested_Properties
- is invalid
+ the <var>Account</var> does not exist, or one of the
+ <var>Requested_Properties</var> is invalid
+ </tp:docstring>
+ </tp:error>
+ </tp:possible-errors>
+
+ </method>
+
+ <method name="DelegateChannels"
+ tp:name-for-bindings="Delegate_Channels">
+ <tp:added version="0.23.1" />
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>Called by a
+ <tp:dbus-ref namespace="org.freedesktop.Telepathy.Client">Handler</tp:dbus-ref>
+ to redispatch a bunch of channels it is currently handling.</p>
+
+ <p>If another
+ <tp:dbus-ref namespace="org.freedesktop.Telepathy.Client">Handler</tp:dbus-ref>
+ can be found,
+ <tp:dbus-ref namespace="org.freedesktop.Telepathy.Client.Handler">HandleChannels</tp:dbus-ref>
+ will be called on it and this function will succeed. In that case,
+ the original <tp:dbus-ref namespace="org.freedesktop.Telepathy.Client">Handler</tp:dbus-ref>
+ does not longer handle those channels.</p>
+
+ <p>If this method fails, the original
+ <tp:dbus-ref namespace="org.freedesktop.Telepathy.Client">Handler</tp:dbus-ref>
+ is still handling the channels.</p>
+
+ </tp:docstring>
+
+ <arg direction="in" name="Channels" type="ao">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The list of channels to redispatch. The caller has to be the current
+ <tp:dbus-ref namespace="org.freedesktop.Telepathy.Client">Handler</tp:dbus-ref>
+ of all of these channels
+ </p>
+ </tp:docstring>
+ </arg>
+
+ <arg direction="in" name="User_Action_Time" type="x"
+ tp:type="User_Action_Timestamp">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The time at which user action occurred, or 0 if this channels
+ delegation is for some reason not involving user action.</p>
+
+ <p>This parameter is used in the same way as the corresponding
+ parameter to
+ <tp:member-ref>CreateChannelWithHints</tp:member-ref>.</p>
+ </tp:docstring>
+ </arg>
+
+ <arg direction="in" name="Preferred_Handler" type="s"
+ tp:type="DBus_Well_Known_Name">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>Either the well-known bus name (starting with
+ <code>org.freedesktop.Telepathy.Client.</code>)
+ of the preferred new handler for these
+ channels, or an empty string to indicate that any handler would be
+ acceptable. The behaviour and rationale are the same as for the
+ corresponding parameter to
+ <tp:member-ref>CreateChannelWithHints</tp:member-ref>.</p>
+
+ </tp:docstring>
+ </arg>
+
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
+ <tp:docstring>
+ The Preferred_Handler is syntactically invalid or does
+ not start with <code>org.freedesktop.Telepathy.Client.</code> or
+ the Account does not exist.
+ </tp:docstring>
+ </tp:error>
+
+ <tp:error name="org.freedesktop.Telepathy.Error.NotYours">
+ <tp:docstring>
+ The caller is not currently handling the channels.
+ </tp:docstring>
+ </tp:error>
+
+ <tp:error name="org.freedesktop.Telepathy.Error.NotCapable">
+ <tp:docstring>
+ There is no other suitable Handler.
</tp:docstring>
</tp:error>
</tp:possible-errors>
</method>
+ <method name="PresentChannel"
+ tp:name-for-bindings="Present_Channel">
+ <tp:added version="0.23.1" />
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>Equivalent of calling
+ <tp:dbus-ref namespace="org.freedesktop.Telepathy.ChannelDispatcher">EnsureChannel</tp:dbus-ref>
+ with a <var>Requested_Properties</var> which would result in ensuring
+ <var>Channel</var>.</p>
+
+ <p>If <var>Channel</var> is handled, its handler will be asked to present it the user
+ (e.g. bring it into the foreground).</p>
+ </tp:docstring>
+
+ <arg direction="in" name="Channel" type="o">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The channel to present.</p>
+ </tp:docstring>
+ </arg>
+
+ <arg direction="in" name="User_Action_Time" type="x"
+ tp:type="User_Action_Timestamp">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The time at which user action occurred, or 0 if this channel
+ request is for some reason not involving user action.</p>
+
+ <p>This parameter is used in the same way as the corresponding
+ parameter to
+ <tp:member-ref>EnsureChannelWithHints</tp:member-ref>.</p>
+ </tp:docstring>
+ </arg>
+
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
+ <tp:docstring>
+ The Account does not exist, the Channel does not exist or it
+ does not belong to the Account.
+ </tp:docstring>
+ </tp:error>
+
+ </tp:possible-errors>
+ </method>
+
<property name="SupportsRequestHints"
tp:name-for-bindings="Supports_Request_Hints"
type="b" access="read">
diff --git a/spec/Channel_Interface_SMS.xml b/spec/Channel_Interface_SMS.xml
index 235046c3..480a2a77 100644
--- a/spec/Channel_Interface_SMS.xml
+++ b/spec/Channel_Interface_SMS.xml
@@ -205,5 +205,83 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
<tp:member-ref>SMSChannel</tp:member-ref> property.
</tp:docstring>
</signal>
+
+ <method name="GetSMSLength"
+ tp:name-for-bindings="Get_SMS_Length">
+ <tp:added version="0.23.1"/>
+
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>Returns the number of 140 octet chunks required to send a message
+ via SMS, as well as the number of remaining characters available in
+ the final chunk and, if possible, an estimate of the cost.</p>
+
+ <tp:rationale>
+ <p>There are a number of different SMS encoding mechanisms, and the
+ client doesn't know which mechanisms an individual CM might support.
+ This method allows the client, without any knowledge of the
+ encoding mechanism, to provide length details to the user.</p>
+ </tp:rationale>
+
+ <p>Clients SHOULD limit the frequency with which this method is called
+ and SHOULD NOT call it for every keystroke. Clients MAY estimate the
+ remaining size between single keystrokes.</p>
+ </tp:docstring>
+
+ <arg name="Message" type="aa{sv}" tp:type="Message_Part[]" direction="in">
+ <tp:docstring>
+ The message the user wishes to send.
+ </tp:docstring>
+ </arg>
+
+ <arg name="Chunks_Required" type="u" direction="out">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The number of 140 octet chunks required to send this message.</p>
+
+ <p>For example, in the GSM standard 7-bit encoding, a 162 character
+ message would require 2 chunks.</p>
+ </tp:docstring>
+ </arg>
+
+ <arg name="Remaining_Characters" type="i" direction="out">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The number of further characters that can be fit in the final
+ chunk. A negative value indicates that the message will be
+ truncated by <code>abs(Remaining_Characters)</code>. The value
+ <code>MIN_INT32</code> (<code>-2<sup>31</sup></code>)
+ indicates the message will be truncated by an unknown amount.</p>
+
+ <p>For example, in the GSM standard 7-bit encoding, a 162 character
+ message would return 144 remaining characters (because of the
+ space required for the multipart SMS header).</p>
+ </tp:docstring>
+ </arg>
+
+ <arg name="Estimated_Cost" type="i" direction="out">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The estimated cost of sending this message. The currency and
+ scale of this value are the same as the
+ <tp:dbus-ref namespace="ofdT.Connection.Interface">Balance.AccountBalance</tp:dbus-ref>
+ property.</p>
+
+ <p>A value of <code>-1</code> indicates the cost could not be
+ estimated.</p>
+
+ </tp:docstring>
+ </arg>
+
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented">
+ <tp:docstring>
+ Raised when the method is not available on this channel.
+ Clients MAY choose to make their own estimation.
+ </tp:docstring>
+ </tp:error>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidArgument">
+ <tp:docstring>
+ Raised when the content cannot be encoded into a valid SMS.
+ </tp:docstring>
+ </tp:error>
+ </tp:possible-errors>
+ </method>
</interface>
</node>
diff --git a/spec/Connection_Interface_Location.xml b/spec/Connection_Interface_Location.xml
index fe549234..c4fd68c3 100644
--- a/spec/Connection_Interface_Location.xml
+++ b/spec/Connection_Interface_Location.xml
@@ -60,7 +60,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<!-- Potentially to be reinstated later:
http://bugs.freedesktop.org/show_bug.cgi?id=19585
- <tp:enum name="Location_Accuracy_Level" type="i">
+ <tp:enum name="Location_Accuracy_Level" type="u">
<tp:docstring>
A location accuracy level. This should be kept in sync with
GeoclueAccuracyLevel in the Geoclue project.
diff --git a/spec/all.xml b/spec/all.xml
index d1493eb5..e23c6c6f 100644
--- a/spec/all.xml
+++ b/spec/all.xml
@@ -3,7 +3,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<tp:title>Telepathy D-Bus Interface Specification</tp:title>
-<tp:version>0.22.2</tp:version>
+<tp:version>0.23.1</tp:version>
<tp:copyright>Copyright © 2005-2011 Collabora Limited</tp:copyright>
<tp:copyright>Copyright © 2005-2011 Nokia Corporation</tp:copyright>
diff --git a/telepathy-glib/account-manager.c b/telepathy-glib/account-manager.c
index c0329143..1e3802f0 100644
--- a/telepathy-glib/account-manager.c
+++ b/telepathy-glib/account-manager.c
@@ -166,7 +166,7 @@ _tp_account_manager_list_features (TpProxyClass *cls G_GNUC_UNUSED)
{
features[FEAT_CORE].name = TP_ACCOUNT_MANAGER_FEATURE_CORE;
features[FEAT_CORE].core = TRUE;
- /* no need for a start_preparing function - the constructor starts it */
+ /* no need for a prepare_async function - the constructor starts it */
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
diff --git a/telepathy-glib/account.c b/telepathy-glib/account.c
index e7e294e5..b097e1eb 100644
--- a/telepathy-glib/account.c
+++ b/telepathy-glib/account.c
@@ -172,8 +172,15 @@ enum {
PROP_STORAGE_RESTRICTIONS
};
-static void tp_account_maybe_prepare_addressing (TpProxy *proxy);
-static void tp_account_maybe_prepare_storage (TpProxy *proxy);
+static void tp_account_prepare_addressing_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+static void tp_account_prepare_storage_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
/**
* TP_ACCOUNT_FEATURE_CORE:
@@ -275,15 +282,15 @@ _tp_account_list_features (TpProxyClass *cls G_GNUC_UNUSED)
{
features[FEAT_CORE].name = TP_ACCOUNT_FEATURE_CORE;
features[FEAT_CORE].core = TRUE;
- /* no need for a start_preparing function - the constructor starts it */
+ /* no need for a prepare_async function - the constructor starts it */
features[FEAT_ADDRESSING].name = TP_ACCOUNT_FEATURE_ADDRESSING;
- features[FEAT_ADDRESSING].start_preparing =
- tp_account_maybe_prepare_addressing;
+ features[FEAT_ADDRESSING].prepare_async =
+ tp_account_prepare_addressing_async;
features[FEAT_STORAGE].name = TP_ACCOUNT_FEATURE_STORAGE;
- features[FEAT_STORAGE].start_preparing =
- tp_account_maybe_prepare_storage;
+ features[FEAT_STORAGE].prepare_async =
+ tp_account_prepare_storage_async;
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
@@ -413,6 +420,7 @@ _tp_account_got_all_storage_cb (TpProxy *proxy,
GObject *object)
{
TpAccount *self = TP_ACCOUNT (proxy);
+ GSimpleAsyncResult *result = user_data;
if (error != NULL)
DEBUG ("Error getting Storage properties: %s", error->message);
@@ -435,23 +443,26 @@ _tp_account_got_all_storage_cb (TpProxy *proxy,
if (self->priv->storage_provider == NULL)
self->priv->storage_provider = g_strdup ("");
- _tp_proxy_set_feature_prepared (proxy, TP_ACCOUNT_FEATURE_STORAGE, TRUE);
+ g_simple_async_result_complete (result);
}
static void
-tp_account_maybe_prepare_storage (TpProxy *proxy)
+tp_account_prepare_storage_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpAccount *self = TP_ACCOUNT (proxy);
+ GSimpleAsyncResult *result;
- if (self->priv->storage_provider != NULL)
- return;
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ tp_account_prepare_storage_async);
- if (!_tp_proxy_is_preparing (proxy, TP_ACCOUNT_FEATURE_STORAGE))
- return;
+ g_assert (self->priv->storage_provider == NULL);
tp_cli_dbus_properties_call_get_all (self, -1,
TP_IFACE_ACCOUNT_INTERFACE_STORAGE,
- _tp_account_got_all_storage_cb, NULL, NULL, G_OBJECT (self));
+ _tp_account_got_all_storage_cb, result, g_object_unref, G_OBJECT (self));
}
static void
@@ -783,9 +794,6 @@ _tp_account_update (TpAccount *account,
}
_tp_proxy_set_feature_prepared (proxy, TP_ACCOUNT_FEATURE_CORE, TRUE);
-
- tp_account_maybe_prepare_storage (proxy);
- tp_account_maybe_prepare_addressing (proxy);
}
static void
@@ -3721,6 +3729,7 @@ _tp_account_got_all_addressing_cb (TpProxy *proxy,
GObject *object)
{
TpAccount *self = TP_ACCOUNT (proxy);
+ GSimpleAsyncResult *result = user_data;
if (error != NULL)
{
@@ -3735,23 +3744,26 @@ _tp_account_got_all_addressing_cb (TpProxy *proxy,
if (self->priv->uri_schemes == NULL)
self->priv->uri_schemes = g_new0 (gchar *, 1);
- _tp_proxy_set_feature_prepared (proxy, TP_ACCOUNT_FEATURE_ADDRESSING, TRUE);
+ g_simple_async_result_complete (result);
}
static void
-tp_account_maybe_prepare_addressing (TpProxy *proxy)
+tp_account_prepare_addressing_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpAccount *self = TP_ACCOUNT (proxy);
+ GSimpleAsyncResult *result;
- if (self->priv->uri_schemes != NULL)
- return;
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ tp_account_prepare_addressing_async);
- if (!_tp_proxy_is_preparing (proxy, TP_ACCOUNT_FEATURE_ADDRESSING))
- return;
+ g_assert (self->priv->uri_schemes == NULL);
tp_cli_dbus_properties_call_get_all (self, -1,
TP_IFACE_ACCOUNT_INTERFACE_ADDRESSING,
- _tp_account_got_all_addressing_cb, NULL, NULL, NULL);
+ _tp_account_got_all_addressing_cb, result, g_object_unref, NULL);
}
/**
diff --git a/telepathy-glib/base-client-internal.h b/telepathy-glib/base-client-internal.h
index a464b6a6..776e3a75 100644
--- a/telepathy-glib/base-client-internal.h
+++ b/telepathy-glib/base-client-internal.h
@@ -28,6 +28,9 @@ G_BEGIN_DECLS
void _tp_base_client_set_only_for_account (TpBaseClient *self,
TpAccount *account);
+void _tp_base_client_now_handling_channels (TpBaseClient *self,
+ GPtrArray *channels);
+
G_END_DECLS
#endif
diff --git a/telepathy-glib/base-client.c b/telepathy-glib/base-client.c
index b7ca1236..9f82b905 100644
--- a/telepathy-glib/base-client.c
+++ b/telepathy-glib/base-client.c
@@ -1922,14 +1922,14 @@ chan_invalidated_cb (TpChannel *channel,
}
static void
-ctx_done_cb (TpHandleChannelsContext *context,
- TpBaseClient *self)
+add_handled_channels (TpBaseClient *self,
+ GPtrArray *channels)
{
guint i;
- for (i = 0; i < context->channels->len; i++)
+ for (i = 0; i < channels->len; i++)
{
- TpChannel *channel = g_ptr_array_index (context->channels, i);
+ TpChannel *channel = g_ptr_array_index (channels, i);
if (tp_proxy_get_invalidated (channel) == NULL)
{
@@ -1946,6 +1946,13 @@ ctx_done_cb (TpHandleChannelsContext *context,
}
static void
+ctx_done_cb (TpHandleChannelsContext *context,
+ TpBaseClient *self)
+{
+ add_handled_channels (self, context->channels);
+}
+
+static void
handle_channels_context_prepare_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
@@ -2785,3 +2792,16 @@ tp_base_client_is_handling_channel (TpBaseClient *self,
g_list_free (channels);
return found;
}
+
+void
+_tp_base_client_now_handling_channels (TpBaseClient *self,
+ GPtrArray *channels)
+{
+ g_return_if_fail (TP_IS_BASE_CLIENT (self));
+ g_return_if_fail (channels != NULL);
+
+ /* It only makes sense to update HandledChannels if the client is
+ * a Handler */
+ if (self->priv->flags & CLIENT_IS_HANDLER)
+ add_handled_channels (self, channels);
+}
diff --git a/telepathy-glib/base-client.h b/telepathy-glib/base-client.h
index 1925b66e..192a3222 100644
--- a/telepathy-glib/base-client.h
+++ b/telepathy-glib/base-client.h
@@ -30,7 +30,6 @@
#include <telepathy-glib/client-channel-factory.h>
#include <telepathy-glib/handle-channels-context.h>
#include <telepathy-glib/observe-channels-context.h>
-#include <telepathy-glib/channel-dispatch-operation.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/defs.h>
@@ -38,6 +37,10 @@
G_BEGIN_DECLS
+/* forward declaration, see channel-dispatch-operation.h for the rest */
+typedef struct _TpChannelDispatchOperation
+ TpChannelDispatchOperation;
+
typedef struct _TpBaseClient TpBaseClient;
typedef struct _TpBaseClientClass TpBaseClientClass;
typedef struct _TpBaseClientPrivate TpBaseClientPrivate;
diff --git a/telepathy-glib/channel-dispatch-operation.c b/telepathy-glib/channel-dispatch-operation.c
index 61708838..1c9366d0 100644
--- a/telepathy-glib/channel-dispatch-operation.c
+++ b/telepathy-glib/channel-dispatch-operation.c
@@ -22,6 +22,7 @@
#include "telepathy-glib/channel-dispatch-operation.h"
#include "telepathy-glib/channel-dispatch-operation-internal.h"
+#include <telepathy-glib/base-client-internal.h>
#include <telepathy-glib/channel.h>
#include <telepathy-glib/defs.h>
#include <telepathy-glib/errors.h>
@@ -30,6 +31,7 @@
#include <telepathy-glib/proxy-internal.h>
#include <telepathy-glib/proxy-subclass.h>
#include <telepathy-glib/util.h>
+#include <telepathy-glib/util-internal.h>
#define DEBUG_FLAG TP_DEBUG_DISPATCHER
#include "telepathy-glib/dbus-internal.h"
@@ -114,8 +116,6 @@ struct _TpChannelDispatchOperationPrivate {
GPtrArray *channels;
GStrv possible_handlers;
GHashTable *immutable_properties;
-
- gboolean preparing_core;
};
enum
@@ -587,12 +587,11 @@ get_dispatch_operation_prop_cb (TpProxy *proxy,
GObject *weak_object)
{
TpChannelDispatchOperation *self = (TpChannelDispatchOperation *) proxy;
+ GSimpleAsyncResult *result = user_data;
gboolean prepared = TRUE;
GPtrArray *channels;
GError *e = NULL;
- self->priv->preparing_core = FALSE;
-
if (error != NULL)
{
DEBUG ("Failed to fetch ChannelDispatchOperation properties: %s",
@@ -667,8 +666,10 @@ get_dispatch_operation_prop_cb (TpProxy *proxy,
g_object_notify ((GObject *) self, "cdo-properties");
out:
- _tp_proxy_set_feature_prepared (proxy,
- TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE, prepared);
+ if (e != NULL)
+ g_simple_async_result_set_from_error (result, e);
+
+ g_simple_async_result_complete (result);
if (!prepared)
{
@@ -678,26 +679,21 @@ out:
}
static void
-maybe_prepare_core (TpProxy *proxy)
+prepare_core_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpChannelDispatchOperation *self = (TpChannelDispatchOperation *) proxy;
+ GSimpleAsyncResult *result;
- if (tp_proxy_is_prepared (proxy, TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE))
- return; /* already done */
-
- if (self->priv->preparing_core)
- return; /* already running */
-
- if (!_tp_proxy_is_preparing (proxy,
- TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE))
- return; /* not interested right now */
-
- self->priv->preparing_core = TRUE;
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_core_async);
tp_cli_dbus_properties_call_get_all (self, -1,
TP_IFACE_CHANNEL_DISPATCH_OPERATION,
get_dispatch_operation_prop_cb,
- NULL, NULL, NULL);
+ result, g_object_unref, NULL);
}
enum {
@@ -715,7 +711,7 @@ tp_channel_dispatch_operation_list_features (TpProxyClass *cls G_GNUC_UNUSED)
features[FEAT_CORE].name = TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE;
features[FEAT_CORE].core = TRUE;
- features[FEAT_CORE].start_preparing = maybe_prepare_core;
+ features[FEAT_CORE].prepare_async = prepare_core_async;
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
@@ -1207,15 +1203,17 @@ claim_cb (TpChannelDispatchOperation *self,
* method becomes the handler for the channel.
*
* If successful, this method will cause the #TpProxy::invalidated signal
- * to be emitted, in the same wayas for
+ * to be emitted, in the same way as for
* tp_channel_dispatch_operation_handle_with_async().
*
* This method may fail because the dispatch operation has already
- * been completed. Again, see tp_channel_dispatch_operation_claim_async()
+ * been completed. Again, see tp_channel_dispatch_operation_handle_with_async()
* for more details. The approver MUST NOT attempt to interact with
* the channels further in this case.
*
* Since: 0.11.5
+ * Deprecated: since 0.15.UNRELEASED. Use
+ * tp_channel_dispatch_operation_claim_with_async()
*/
void
tp_channel_dispatch_operation_claim_async (
@@ -1245,6 +1243,8 @@ tp_channel_dispatch_operation_claim_async (
* Returns: %TRUE if the Claim() call was successful, otherwise %FALSE
*
* Since: 0.11.5
+ * Deprecated: since 0.15.UNRELEASED. Use
+ * tp_channel_dispatch_operation_claim_with_finish()
*/
gboolean
tp_channel_dispatch_operation_claim_finish (
@@ -1392,3 +1392,121 @@ gboolean
return TRUE;
}
+
+static void
+claim_with_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpChannelDispatchOperation *self = (TpChannelDispatchOperation *) source;
+ GSimpleAsyncResult *main_result = user_data;
+ GError *error = NULL;
+ TpBaseClient *client;
+
+ if (!tp_proxy_prepare_finish (self, result, &error))
+ {
+ g_simple_async_result_take_error (main_result, error);
+ goto out;
+ }
+
+ client = g_simple_async_result_get_op_res_gpointer (main_result);
+
+ _tp_base_client_now_handling_channels (client, self->priv->channels);
+
+out:
+ g_simple_async_result_complete (main_result);
+ g_object_unref (main_result);
+}
+
+static void
+claim_with_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpChannelDispatchOperation *self = (TpChannelDispatchOperation *) source;
+ GSimpleAsyncResult *main_result = user_data;
+ GError *error = NULL;
+ GQuark features[] = { TP_CHANNEL_DISPATCH_OPERATION_FEATURE_CORE, 0 };
+
+ if (!tp_channel_dispatch_operation_claim_finish (self, result, &error))
+ {
+ g_simple_async_result_take_error (main_result, error);
+ g_simple_async_result_complete (main_result);
+ g_object_unref (main_result);
+ return;
+ }
+
+ /* We have to prepare the CDO to be able to get the list of its channels */
+ tp_proxy_prepare_async (self, features, claim_with_prepare_cb,
+ main_result);
+}
+
+/**
+ * tp_channel_dispatch_operation_claim_with_async:
+ * @self: a #TpChannelDispatchOperation
+ * @client: the #TpBaseClient claiming @self
+ * @callback: a callback to call when the call returns
+ * @user_data: data to pass to @callback
+ *
+ * Called by an approver to claim channels for handling internally.
+ * If this method is called successfully, the process calling this
+ * method becomes the handler for the channel.
+ *
+ * If successful, this method will cause the #TpProxy::invalidated signal
+ * to be emitted, in the same way as for
+ * tp_channel_dispatch_operation_handle_with_async().
+ *
+ * This method may fail because the dispatch operation has already
+ * been completed. Again, see tp_channel_dispatch_operation_handle_with_async()
+ * for more details. The approver MUST NOT attempt to interact with
+ * the channels further in this case.
+ *
+ * This is an improved version of tp_channel_dispatch_operation_claim_async()
+ * as it tells @client about the new channels being handled.
+ *
+ * Since: 0.15.UNRELEASED
+ */
+void
+tp_channel_dispatch_operation_claim_with_async (
+ TpChannelDispatchOperation *self,
+ TpBaseClient *client,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_return_if_fail (TP_IS_CHANNEL_DISPATCH_OPERATION (self));
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data,
+ tp_channel_dispatch_operation_claim_with_async);
+
+ g_simple_async_result_set_op_res_gpointer (result, g_object_ref (client),
+ g_object_unref);
+
+ tp_channel_dispatch_operation_claim_async (self, claim_with_cb,
+ result);
+}
+
+/**
+ * tp_channel_dispatch_operation_claim_with_finish:
+ * @self: a #TpChannelDispatchOperation
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes an async call to Claim() initiated using
+ * tp_channel_dispatch_operation_claim_with_async().
+ *
+ * Returns: %TRUE if the Claim() call was successful, otherwise %FALSE
+ *
+ * Since: 0.15.UNRELEASED
+ */
+gboolean
+tp_channel_dispatch_operation_claim_with_finish (
+ TpChannelDispatchOperation *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ _tp_implement_finish_void (self, \
+ tp_channel_dispatch_operation_claim_with_async)
+}
diff --git a/telepathy-glib/channel-dispatch-operation.h b/telepathy-glib/channel-dispatch-operation.h
index 30bd1110..605f98f0 100644
--- a/telepathy-glib/channel-dispatch-operation.h
+++ b/telepathy-glib/channel-dispatch-operation.h
@@ -23,6 +23,7 @@
#define TP_CHANNEL_DISPATCH_OPERATION_H
#include <telepathy-glib/account.h>
+#include <telepathy-glib/base-client.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/dbus.h>
#include <telepathy-glib/defs.h>
@@ -30,8 +31,8 @@
G_BEGIN_DECLS
-typedef struct _TpChannelDispatchOperation
- TpChannelDispatchOperation;
+
+/* TpChannelDispatchOperation is defined in base-client.h */
typedef struct _TpChannelDispatchOperationClass
TpChannelDispatchOperationClass;
typedef struct _TpChannelDispatchOperationPrivate
@@ -130,6 +131,17 @@ gboolean tp_channel_dispatch_operation_handle_with_time_finish (
GAsyncResult *result,
GError **error);
+void tp_channel_dispatch_operation_claim_with_async (
+ TpChannelDispatchOperation *self,
+ TpBaseClient *client,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean tp_channel_dispatch_operation_claim_with_finish (
+ TpChannelDispatchOperation *self,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#include <telepathy-glib/_gen/tp-cli-channel-dispatch-operation.h>
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c
index 21bfc3fd..724b17ac 100644
--- a/telepathy-glib/channel.c
+++ b/telepathy-glib/channel.c
@@ -686,6 +686,7 @@ tp_channel_get_initial_chat_states_cb (TpProxy *proxy,
GObject *weak_object)
{
TpChannel *self = TP_CHANNEL (proxy);
+ GSimpleAsyncResult *result = user_data;
if (error == NULL && G_VALUE_HOLDS (value, TP_HASH_TYPE_CHAT_STATE_MAP))
{
@@ -695,31 +696,22 @@ tp_channel_get_initial_chat_states_cb (TpProxy *proxy,
/* else just ignore it and assume everyone was initially in the default
* Inactive state, unless we already saw a signal for them */
- _tp_proxy_set_feature_prepared (proxy, TP_CHANNEL_FEATURE_CHAT_STATES, TRUE);
+ g_simple_async_result_complete (result);
}
static void
-tp_channel_maybe_prepare_chat_states (TpProxy *proxy)
+tp_channel_prepare_chat_states_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpChannel *self = (TpChannel *) proxy;
+ GSimpleAsyncResult *result;
- if (self->priv->chat_states != NULL)
- return; /* already done */
-
- if (!_tp_proxy_is_preparing (proxy, TP_CHANNEL_FEATURE_CHAT_STATES))
- return; /* not interested right now */
-
- if (!self->priv->ready)
- return; /* will try again when ready */
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ tp_channel_prepare_chat_states_async);
- if (!tp_proxy_has_interface_by_id (proxy,
- TP_IFACE_QUARK_CHANNEL_INTERFACE_CHAT_STATE))
- {
- /* not going to happen */
- _tp_proxy_set_feature_prepared (proxy, TP_CHANNEL_FEATURE_CHAT_STATES,
- FALSE);
- return;
- }
+ g_assert (self->priv->chat_states == NULL);
/* chat states? yes please! */
self->priv->chat_states = g_hash_table_new (NULL, NULL);
@@ -730,7 +722,7 @@ tp_channel_maybe_prepare_chat_states (TpProxy *proxy)
tp_cli_dbus_properties_call_get (self, -1,
TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE, "ChatStates",
tp_channel_get_initial_chat_states_cb,
- NULL, NULL, NULL);
+ result, g_object_unref, NULL);
}
void
@@ -764,8 +756,6 @@ _tp_channel_continue_introspection (TpChannel *self)
TP_CHANNEL_FEATURE_GROUP,
tp_proxy_has_interface_by_id (self,
TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP));
-
- tp_channel_maybe_prepare_chat_states ((TpProxy *) self);
}
else
{
@@ -1358,6 +1348,7 @@ static const TpProxyFeature *
tp_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED)
{
static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
+ static GQuark need_chat_states[2] = {0, 0};
if (G_LIKELY (features[0].name != 0))
return features;
@@ -1368,8 +1359,10 @@ tp_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED)
features[FEAT_GROUP].name = TP_CHANNEL_FEATURE_GROUP;
features[FEAT_CHAT_STATES].name = TP_CHANNEL_FEATURE_CHAT_STATES;
- features[FEAT_CHAT_STATES].start_preparing =
- tp_channel_maybe_prepare_chat_states;
+ features[FEAT_CHAT_STATES].prepare_async =
+ tp_channel_prepare_chat_states_async;
+ need_chat_states[0] = TP_IFACE_QUARK_CHANNEL_INTERFACE_CHAT_STATE;
+ features[FEAT_CHAT_STATES].interfaces_needed = need_chat_states;
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
diff --git a/telepathy-glib/connection-avatars.c b/telepathy-glib/connection-avatars.c
index 21028017..d75e3918 100644
--- a/telepathy-glib/connection-avatars.c
+++ b/telepathy-glib/connection-avatars.c
@@ -59,12 +59,12 @@ tp_connection_get_avatar_requirements_cb (TpProxy *proxy,
GObject *weak_object)
{
TpConnection *self = (TpConnection *) proxy;
-
- self->priv->fetching_avatar_requirements = FALSE;
+ GSimpleAsyncResult *result = user_data;
if (error != NULL)
{
DEBUG ("Failed to get avatar requirements properties: %s", error->message);
+ g_simple_async_result_set_from_error (result, error);
goto finally;
}
@@ -83,40 +83,26 @@ tp_connection_get_avatar_requirements_cb (TpProxy *proxy,
tp_asv_get_uint32 (properties, "MaximumAvatarBytes", NULL));
finally:
- _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS,
- self->priv->avatar_requirements != NULL);
+ g_simple_async_result_complete (result);
}
void
-_tp_connection_maybe_prepare_avatar_requirements (TpProxy *proxy)
+_tp_connection_prepare_avatar_requirements_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpConnection *self = (TpConnection *) proxy;
+ GSimpleAsyncResult *result;
- if (self->priv->avatar_requirements != NULL)
- return; /* already done */
-
- if (!_tp_proxy_is_preparing (proxy, TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS))
- return; /* not interested right now */
-
- if (!self->priv->ready)
- return; /* will try again when ready */
-
- if (self->priv->fetching_avatar_requirements)
- return; /* Another Get operation is running */
-
- if (!tp_proxy_has_interface_by_id (proxy,
- TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS))
- {
- _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS,
- FALSE);
- return;
- }
+ g_assert (self->priv->avatar_requirements == NULL);
- self->priv->fetching_avatar_requirements = TRUE;
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ _tp_connection_prepare_avatar_requirements_async);
tp_cli_dbus_properties_call_get_all (self, -1,
TP_IFACE_CONNECTION_INTERFACE_AVATARS,
- tp_connection_get_avatar_requirements_cb, NULL, NULL, NULL);
+ tp_connection_get_avatar_requirements_cb, result, g_object_unref, NULL);
}
/**
diff --git a/telepathy-glib/connection-contact-info.c b/telepathy-glib/connection-contact-info.c
index f684a0a6..cebbe93c 100644
--- a/telepathy-glib/connection-contact-info.c
+++ b/telepathy-glib/connection-contact-info.c
@@ -427,15 +427,15 @@ tp_connection_get_contact_info_cb (TpProxy *proxy,
GObject *weak_object)
{
TpConnection *self = (TpConnection *) proxy;
+ GSimpleAsyncResult *result = user_data;
GPtrArray *specs;
gboolean valid;
- gboolean success = FALSE;
guint i;
if (error != NULL)
{
DEBUG ("Failed to get contact info properties: %s", error->message);
- goto finally;
+ g_simple_async_result_set_from_error (result, error);
}
g_assert (self->priv->contact_info_supported_fields == NULL);
@@ -449,6 +449,8 @@ tp_connection_get_contact_info_cb (TpProxy *proxy,
if (!valid || specs == NULL)
{
DEBUG ("Some properties are missing on the ContactInfo interface");
+ g_simple_async_result_set_error (result, TP_ERRORS, TP_ERROR_CONFUSED,
+ "Some properties are missing on the ContactInfo interface");
goto finally;
}
@@ -468,44 +470,25 @@ tp_connection_get_contact_info_cb (TpProxy *proxy,
_tp_contact_info_field_spec_new (name, parameters, flags, max));
}
- success = TRUE;
-
finally:
-
- if (!success)
- self->priv->contact_info_fetched = FALSE;
-
- _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_CONTACT_INFO,
- success);
+ g_simple_async_result_complete (result);
}
void
-_tp_connection_maybe_prepare_contact_info (TpProxy *proxy)
+_tp_connection_prepare_contact_info_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpConnection *self = (TpConnection *) proxy;
+ GSimpleAsyncResult *result;
- if (self->priv->contact_info_fetched)
- return; /* already done */
-
- if (!_tp_proxy_is_preparing (proxy, TP_CONNECTION_FEATURE_CONTACT_INFO))
- return; /* not interested right now */
-
- if (!self->priv->ready)
- return; /* will try again when ready */
-
- if (!tp_proxy_has_interface_by_id (proxy,
- TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_INFO))
- {
- _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_CONTACT_INFO,
- FALSE);
- return;
- }
-
- self->priv->contact_info_fetched = TRUE;
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ _tp_connection_prepare_contact_info_async);
tp_cli_dbus_properties_call_get_all (self, -1,
TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
- tp_connection_get_contact_info_cb, NULL, NULL, NULL);
+ tp_connection_get_contact_info_cb, result, g_object_unref, NULL);
}
/**
diff --git a/telepathy-glib/connection-internal.h b/telepathy-glib/connection-internal.h
index d4554195..92dddfa4 100644
--- a/telepathy-glib/connection-internal.h
+++ b/telepathy-glib/connection-internal.h
@@ -66,9 +66,6 @@ struct _TpConnectionPrivate {
GList *contact_info_supported_fields;
TpProxyPendingCall *introspection_call;
- unsigned fetching_rcc:1;
- unsigned fetching_avatar_requirements:1;
- unsigned contact_info_fetched:1;
unsigned ready:1;
unsigned has_immortal_handles:1;
@@ -103,12 +100,19 @@ TpContact *_tp_connection_lookup_contact (TpConnection *self, TpHandle handle);
void _tp_contact_connection_invalidated (TpContact *contact);
/* connection-contact-info.c */
-void _tp_connection_maybe_prepare_contact_info (TpProxy *proxy);
+void _tp_connection_prepare_contact_info_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
TpContactInfoFieldSpec *_tp_contact_info_field_spec_new (const gchar *name,
GStrv parameters, TpContactInfoFieldFlags flags, guint max);
/* connection-avatars.c */
-void _tp_connection_maybe_prepare_avatar_requirements (TpProxy *proxy);
+void _tp_connection_prepare_avatar_requirements_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
G_END_DECLS
diff --git a/telepathy-glib/connection.c b/telepathy-glib/connection.c
index f11f198a..faf243d5 100644
--- a/telepathy-glib/connection.c
+++ b/telepathy-glib/connection.c
@@ -297,8 +297,7 @@ tp_connection_get_rcc_cb (TpProxy *proxy,
GObject *weak_object)
{
TpConnection *self = (TpConnection *) proxy;
-
- self->priv->fetching_rcc = FALSE;
+ GSimpleAsyncResult *result = user_data;
if (error != NULL)
{
@@ -328,46 +327,74 @@ tp_connection_get_rcc_cb (TpProxy *proxy,
FALSE);
finally:
- _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_CAPABILITIES,
- TRUE);
+ g_simple_async_result_complete (result);
g_object_notify ((GObject *) self, "capabilities");
}
static void
-tp_connection_maybe_prepare_capabilities (TpProxy *proxy)
+tp_connection_prepare_capabilities_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpConnection *self = (TpConnection *) proxy;
+ GSimpleAsyncResult *result;
- if (self->priv->capabilities != NULL)
- return; /* already done */
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ tp_connection_prepare_capabilities_async);
- if (!_tp_proxy_is_preparing (proxy, TP_CONNECTION_FEATURE_CAPABILITIES))
- return; /* not interested right now */
+ g_assert (self->priv->capabilities == NULL);
- if (!self->priv->ready)
- return; /* will try again when ready */
+ tp_cli_dbus_properties_call_get (self, -1,
+ TP_IFACE_CONNECTION_INTERFACE_REQUESTS, "RequestableChannelClasses",
+ tp_connection_get_rcc_cb, result, g_object_unref, NULL);
+}
- if (self->priv->fetching_rcc)
- return; /* Another Get operation is running */
+static void
+signal_connected (TpConnection *self)
+{
+ /* we shouldn't have gone to status CONNECTED for any reason
+ * that isn't REQUESTED :-) */
+ DEBUG ("%p: CORE and CONNECTED ready", self);
+ self->priv->status = TP_CONNECTION_STATUS_CONNECTED;
+ self->priv->status_reason = TP_CONNECTION_STATUS_REASON_REQUESTED;
+ self->priv->ready = TRUE;
+
+ _tp_proxy_set_feature_prepared ((TpProxy *) self,
+ TP_CONNECTION_FEATURE_CONNECTED, TRUE);
+ _tp_proxy_set_feature_prepared ((TpProxy *) self,
+ TP_CONNECTION_FEATURE_CORE, TRUE);
+
+ g_object_notify ((GObject *) self, "status");
+ g_object_notify ((GObject *) self, "status-reason");
+ g_object_notify ((GObject *) self, "connection-ready");
+}
- if (!tp_proxy_has_interface_by_id (proxy,
- TP_IFACE_QUARK_CONNECTION_INTERFACE_REQUESTS))
+static void
+will_announced_connected_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpConnection *self = (TpConnection *) source;
+ GError *error = NULL;
+
+ if (!_tp_proxy_will_announce_connected_finish ((TpProxy *) self, result,
+ &error))
{
- /* Connection doesn't support Requests; set an empty TpCapabilities
- * object as all calls to CreateChannel/EnsureChannel will fail. */
+ DEBUG ("_tp_connection_prepare_contact_info_async failed: %s",
+ error->message);
- self->priv->capabilities = _tp_capabilities_new (NULL, FALSE);
- _tp_proxy_set_feature_prepared (proxy, TP_CONNECTION_FEATURE_CAPABILITIES,
- TRUE);
- return;
+ g_error_free (error);
}
- self->priv->fetching_rcc = TRUE;
+ if (tp_proxy_get_invalidated (self) != NULL)
+ {
+ DEBUG ("Connection has been invalidated; we're done");
+ return;
+ }
- tp_cli_dbus_properties_call_get (self, -1,
- TP_IFACE_CONNECTION_INTERFACE_REQUESTS, "RequestableChannelClasses",
- tp_connection_get_rcc_cb, NULL, NULL, NULL);
+ signal_connected (self);
}
static void
@@ -390,25 +417,10 @@ tp_connection_continue_introspection (TpConnection *self)
return;
}
- /* signal CONNECTED; we shouldn't have gone to status CONNECTED for any
- * reason that isn't REQUESTED :-) */
- DEBUG ("%p: CORE and CONNECTED ready", self);
- self->priv->status = TP_CONNECTION_STATUS_CONNECTED;
- self->priv->status_reason = TP_CONNECTION_STATUS_REASON_REQUESTED;
- self->priv->ready = TRUE;
-
- _tp_proxy_set_feature_prepared ((TpProxy *) self,
- TP_CONNECTION_FEATURE_CONNECTED, TRUE);
- _tp_proxy_set_feature_prepared ((TpProxy *) self,
- TP_CONNECTION_FEATURE_CORE, TRUE);
-
- g_object_notify ((GObject *) self, "status");
- g_object_notify ((GObject *) self, "status-reason");
- g_object_notify ((GObject *) self, "connection-ready");
-
- tp_connection_maybe_prepare_capabilities ((TpProxy *) self);
- _tp_connection_maybe_prepare_avatar_requirements ((TpProxy *) self);
- _tp_connection_maybe_prepare_contact_info ((TpProxy *) self);
+ /* We'll announce CONNECTED state soon, but first give a chance to
+ * prepared feature to be updated, if needed */
+ _tp_proxy_will_announce_connected_async ((TpProxy *) self,
+ will_announced_connected_cb, NULL);
}
else
{
@@ -1262,6 +1274,9 @@ static const TpProxyFeature *
tp_connection_list_features (TpProxyClass *cls G_GNUC_UNUSED)
{
static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
+ static GQuark need_requests[2] = {0, 0};
+ static GQuark need_avatars[2] = {0, 0};
+ static GQuark need_contact_info[2] = {0, 0};
if (G_LIKELY (features[0].name != 0))
return features;
@@ -1272,16 +1287,22 @@ tp_connection_list_features (TpProxyClass *cls G_GNUC_UNUSED)
features[FEAT_CONNECTED].name = TP_CONNECTION_FEATURE_CONNECTED;
features[FEAT_CAPABILITIES].name = TP_CONNECTION_FEATURE_CAPABILITIES;
- features[FEAT_CAPABILITIES].start_preparing =
- tp_connection_maybe_prepare_capabilities;
+ features[FEAT_CAPABILITIES].prepare_async =
+ tp_connection_prepare_capabilities_async;
+ need_requests[0] = TP_IFACE_QUARK_CONNECTION_INTERFACE_REQUESTS;
+ features[FEAT_CAPABILITIES].interfaces_needed = need_requests;
features[FEAT_AVATAR_REQUIREMENTS].name = TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS;
- features[FEAT_AVATAR_REQUIREMENTS].start_preparing =
- _tp_connection_maybe_prepare_avatar_requirements;
+ features[FEAT_AVATAR_REQUIREMENTS].prepare_async =
+ _tp_connection_prepare_avatar_requirements_async;
+ need_avatars[0] = TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS;
+ features[FEAT_AVATAR_REQUIREMENTS].interfaces_needed = need_avatars;
features[FEAT_CONTACT_INFO].name = TP_CONNECTION_FEATURE_CONTACT_INFO;
- features[FEAT_CONTACT_INFO].start_preparing =
- _tp_connection_maybe_prepare_contact_info;
+ features[FEAT_CONTACT_INFO].prepare_async =
+ _tp_connection_prepare_contact_info_async;
+ need_contact_info[0] = TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_INFO;
+ features[FEAT_CONTACT_INFO].interfaces_needed = need_contact_info;
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
diff --git a/telepathy-glib/group-mixin.c b/telepathy-glib/group-mixin.c
index 8120b98b..e2123e75 100644
--- a/telepathy-glib/group-mixin.c
+++ b/telepathy-glib/group-mixin.c
@@ -1390,7 +1390,7 @@ local_pending_remove (TpGroupMixin *mixin,
static void
-add_members_in_array (GHashTable *member_ids,
+add_members_in_array (GHashTable *contact_ids,
TpHandleRepoIface *repo,
const GArray *handles)
{
@@ -1401,61 +1401,61 @@ add_members_in_array (GHashTable *member_ids,
TpHandle handle = g_array_index (handles, TpHandle, i);
const gchar *id = tp_handle_inspect (repo, handle);
- g_hash_table_insert (member_ids, GUINT_TO_POINTER (handle), (gchar *) id);
+ g_hash_table_insert (contact_ids, GUINT_TO_POINTER (handle), (gchar *) id);
}
}
static gboolean
-maybe_add_member_ids (TpGroupMixin *mixin,
+maybe_add_contact_ids (TpGroupMixin *mixin,
const GArray *add,
const GArray *local_pending,
const GArray *remote_pending,
TpHandle actor,
GHashTable *details)
{
- GHashTable *member_ids;
+ GHashTable *contact_ids;
/* If the library user had its own ideas about which members' IDs to include
* in the change details, we'll leave that intact.
*/
- if (tp_asv_lookup (details, "member-ids") != NULL)
+ if (tp_asv_lookup (details, "contact-ids") != NULL)
return FALSE;
/* The library user didn't include the new members' IDs in details; let's add
* the IDs of the handles being added to the group (but not removed, as per
* the spec) and of the actor.
*/
- member_ids = g_hash_table_new (NULL, NULL);
+ contact_ids = g_hash_table_new (NULL, NULL);
- add_members_in_array (member_ids, mixin->handle_repo, add);
- add_members_in_array (member_ids, mixin->handle_repo, local_pending);
- add_members_in_array (member_ids, mixin->handle_repo, remote_pending);
+ add_members_in_array (contact_ids, mixin->handle_repo, add);
+ add_members_in_array (contact_ids, mixin->handle_repo, local_pending);
+ add_members_in_array (contact_ids, mixin->handle_repo, remote_pending);
if (actor != 0)
{
const gchar *id = tp_handle_inspect (mixin->handle_repo, actor);
- g_hash_table_insert (member_ids, GUINT_TO_POINTER (actor), (gchar *) id);
+ g_hash_table_insert (contact_ids, GUINT_TO_POINTER (actor), (gchar *) id);
}
- g_hash_table_insert (details, "member-ids",
+ g_hash_table_insert (details, "contact-ids",
tp_g_value_slice_new_take_boxed (TP_HASH_TYPE_HANDLE_IDENTIFIER_MAP,
- member_ids));
+ contact_ids));
return TRUE;
}
static void
-remove_member_ids (GHashTable *details)
+remove_contact_ids (GHashTable *details)
{
- GValue *member_ids_v = g_hash_table_lookup (details, "member-ids");
+ GValue *contact_ids_v = g_hash_table_lookup (details, "contact-ids");
- g_assert (member_ids_v != NULL);
- g_hash_table_steal (details, "member-ids");
+ g_assert (contact_ids_v != NULL);
+ g_hash_table_steal (details, "contact-ids");
- tp_g_value_slice_free (member_ids_v);
+ tp_g_value_slice_free (contact_ids_v);
}
@@ -1472,7 +1472,7 @@ emit_members_changed_signals (GObject *channel,
{
TpGroupMixin *mixin = TP_GROUP_MIXIN (channel);
GHashTable *details_ = (GHashTable *) details; /* Cast the pain away! */
- gboolean added_member_ids;
+ gboolean added_contact_ids;
if (DEBUGGING)
{
@@ -1502,7 +1502,7 @@ emit_members_changed_signals (GObject *channel,
g_free (remote_str);
}
- added_member_ids = maybe_add_member_ids (mixin, add, local_pending,
+ added_contact_ids = maybe_add_contact_ids (mixin, add, local_pending,
remote_pending, actor, details_);
tp_svc_channel_interface_group_emit_members_changed (channel, message,
@@ -1525,8 +1525,8 @@ emit_members_changed_signals (GObject *channel,
}
}
- if (added_member_ids)
- remove_member_ids (details_);
+ if (added_contact_ids)
+ remove_contact_ids (details_);
}
diff --git a/telepathy-glib/proxy-internal.h b/telepathy-glib/proxy-internal.h
index 949ba233..4fce531f 100644
--- a/telepathy-glib/proxy-internal.h
+++ b/telepathy-glib/proxy-internal.h
@@ -27,16 +27,6 @@ GError *_tp_proxy_take_and_remap_error (TpProxy *self, GError *error)
typedef void (*TpProxyProc) (TpProxy *);
-struct _TpProxyFeature {
- /*<public>*/
- GQuark name;
- gboolean core;
- TpProxyProc start_preparing;
- /*<private>*/
- GCallback _reserved[4];
- gpointer priv;
-};
-
gboolean _tp_proxy_is_preparing (gpointer self,
GQuark feature);
void _tp_proxy_set_feature_prepared (TpProxy *self,
@@ -45,4 +35,12 @@ void _tp_proxy_set_feature_prepared (TpProxy *self,
void _tp_proxy_set_features_failed (TpProxy *self,
const GError *error);
+void _tp_proxy_will_announce_connected_async (TpProxy *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean _tp_proxy_will_announce_connected_finish (TpProxy *self,
+ GAsyncResult *result,
+ GError **error);
+
#endif
diff --git a/telepathy-glib/proxy.c b/telepathy-glib/proxy.c
index f80dcf7a..b64e9190 100644
--- a/telepathy-glib/proxy.c
+++ b/telepathy-glib/proxy.c
@@ -208,10 +208,36 @@ tp_dbus_errors_quark (void)
*/
/**
+ * TpProxyPrepareAsync:
+ * @proxy: the object on which @feature has to be prepared
+ * @feature: a #GQuark representing the feature to prepare
+ * @callback: called when the feature has been prepared, or the preparation
+ * failed
+ * @user_data: data to pass to @callback
+ *
+ * Function called when @feature has to be prepared for @proxy.
+ */
+
+/**
* TpProxyFeature:
- *
- * Structure representing a feature. This is currently opaque to code outside
- * telepathy-glib itself.
+ * @name: a #GQuark representing the name of the feature
+ * @core: if %TRUE, every non-core feature of the class depends on this one,
+ * and every feature (core or not) in subclasses depends on this one
+ * @prepare_async: called when the feature has to be prepared
+ * @prepare_before_signalling_connected_async: only relevant for
+ * TpConnection sub-classes; same as @prepare_async but for
+ * features wanting to have a chance to prepare themself before the
+ * TpConnection object announce its %TP_CONNECTION_STATUS_CONNECTED status
+ * @interfaces_needed: an array of #GQuark representing interfaces which have
+ * to be implemented on the object in order to be able to prepare the feature
+ * @depends_on: an array of #GQuark representing other features which have to
+ * be prepared before trying to prepare this feature
+ * @can_retry: If %TRUE, allow retrying preparation of this feature even if it
+ * failed once already; if %FALSE any attempt of preparing the feature after
+ * the preparation already failed once will immediately fail with re-calling
+ * @prepare_async
+ *
+ * Structure representing a feature.
*
* Since: 0.11.3
*/
@@ -245,6 +271,11 @@ struct _TpProxyInterfaceAddLink {
TpProxyInterfaceAddLink *next;
};
+struct _TpProxyFeaturePrivate
+{
+ gpointer unused;
+};
+
/**
* TpProxyInvokeFunc:
* @self: the #TpProxy on which the D-Bus method was invoked
@@ -280,16 +311,25 @@ struct _TpProxyInterfaceAddLink {
*/
typedef enum {
+ /* Not a feature */
FEATURE_STATE_INVALID = GPOINTER_TO_INT (NULL),
+ /* Nobody cares */
FEATURE_STATE_UNWANTED,
+ /* Want to prepare, waiting for dependencies to be satisfied (or maybe
+ * just poll_features being called) */
FEATURE_STATE_WANTED,
+ /* Want to prepare, have called prepare_async */
+ FEATURE_STATE_TRYING,
+ /* Couldn't prepare, gave up */
FEATURE_STATE_FAILED,
+ /* Prepared */
FEATURE_STATE_READY
} FeatureState;
typedef struct {
GSimpleAsyncResult *result;
GArray *features;
+ gboolean core;
} TpProxyPrepareRequest;
static TpProxyPrepareRequest *
@@ -302,6 +342,7 @@ tp_proxy_prepare_request_new (GSimpleAsyncResult *result,
req->result = g_object_ref (result);
req->features = _tp_quark_array_copy (features);
+ g_assert (req->features != NULL);
return req;
}
@@ -333,12 +374,16 @@ struct _TpProxyPrivate {
/* feature => FeatureState */
GData *features;
- /* List of TpProxyPrepareRequest */
- GList *prepare_requests;
- /* A request containing all core features, borrowed from the head of
- * prepare_requests, or NULL if prepared; nothing else is allowed
- * to become prepared until this one does.*/
- TpProxyPrepareRequest *prepare_core;
+ /* Queue of TpProxyPrepareRequest. The first requests are the core one,
+ * sorted from the most upper super class to the subclass core features.
+ * This is needed to guarantee than subclass features are not prepared
+ * until the super class features have been prepared. */
+ GQueue *prepare_requests;
+
+ GSimpleAsyncResult *will_announce_connected_result;
+ /* Number of pending calls blocking will_announce_connected_result to be
+ * completed */
+ guint pending_will_announce_calls;
gboolean dispose_has_run;
};
@@ -524,7 +569,7 @@ tp_proxy_emit_invalidated (gpointer p)
/* make all pending tp_proxy_prepare_async calls fail */
tp_proxy_poll_features (self, NULL);
- g_assert (self->priv->prepare_requests == NULL);
+ g_assert_cmpuint (g_queue_get_length (self->priv->prepare_requests), ==, 0);
/* Don't clear the datalist until after we've emitted the signal, so
* the pending call and signal connection friend classes can still get
@@ -907,6 +952,8 @@ tp_proxy_init (TpProxy *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_PROXY,
TpProxyPrivate);
+
+ self->priv->prepare_requests = g_queue_new ();
}
static GQuark
@@ -939,6 +986,22 @@ tp_proxy_set_feature_state (TpProxy *self,
GINT_TO_POINTER (state));
}
+static void
+assert_feature_validity (TpProxy *self,
+ const TpProxyFeature *feature)
+{
+ g_assert (feature != NULL);
+
+ /* Core features can't have depends, their depends are implicit */
+ if (feature->core)
+ g_assert (feature->depends_on == NULL || feature->depends_on[0] == 0);
+
+ /* prepare_before_signalling_connected_async only make sense for
+ * TpConnection subclasses */
+ if (feature->prepare_before_signalling_connected_async != NULL)
+ g_assert (TP_IS_CONNECTION (self));
+}
+
static GObject *
tp_proxy_constructor (GType type,
guint n_params,
@@ -951,12 +1014,9 @@ tp_proxy_constructor (GType type,
TpProxyInterfaceAddLink *iter;
GType proxy_parent_type = G_TYPE_FROM_CLASS (tp_proxy_parent_class);
GType ancestor_type;
- GArray *core_features;
_tp_register_dbus_glib_marshallers ();
- core_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
-
for (ancestor_type = type;
ancestor_type != proxy_parent_type && ancestor_type != 0;
ancestor_type = g_type_parent (ancestor_type))
@@ -964,6 +1024,7 @@ tp_proxy_constructor (GType type,
TpProxyClass *ancestor = g_type_class_peek (ancestor_type);
const TpProxyFeature *features;
guint i;
+ GArray *core_features;
for (iter = g_type_get_qdata (ancestor_type,
interface_added_cb_quark ());
@@ -980,8 +1041,12 @@ tp_proxy_constructor (GType type,
if (features == NULL)
continue;
+ core_features = g_array_new (TRUE, FALSE, sizeof (GQuark));
+
for (i = 0; features[i].name != 0; i++)
{
+ assert_feature_validity (self, &features[i]);
+
tp_proxy_set_feature_state (self, features[i].name,
FEATURE_STATE_UNWANTED);
@@ -990,6 +1055,22 @@ tp_proxy_constructor (GType type,
g_array_append_val (core_features, features[i].name);
}
}
+
+ if (core_features->len > 0)
+ {
+ TpProxyPrepareRequest *req;
+
+ req = tp_proxy_prepare_request_new (NULL,
+ (const GQuark *) core_features->data);
+ req->core = TRUE;
+
+ g_queue_push_head (self->priv->prepare_requests, req);
+
+ DEBUG ("%p: request %p represents core features on %s", self, req,
+ g_type_name (ancestor_type));
+ }
+
+ g_array_free (core_features, TRUE);
}
g_return_val_if_fail (self->dbus_connection != NULL, NULL);
@@ -1017,19 +1098,6 @@ tp_proxy_constructor (GType type,
g_return_val_if_fail (self->bus_name[0] == ':', NULL);
}
- if (core_features->len > 0)
- {
- self->priv->prepare_core = tp_proxy_prepare_request_new (NULL,
- (const GQuark *) core_features->data);
- self->priv->prepare_requests = g_list_prepend (
- self->priv->prepare_requests,
- self->priv->prepare_core);
- DEBUG ("%p: request %p represents core features", self,
- self->priv->prepare_core);
- }
-
- g_array_free (core_features, TRUE);
-
return (GObject *) self;
}
@@ -1069,8 +1137,8 @@ tp_proxy_finalize (GObject *object)
g_error_free (self->invalidated);
/* invalidation ensures that these have gone away */
- g_assert (self->priv->prepare_requests == NULL);
- g_assert (self->priv->prepare_core == NULL);
+ g_assert_cmpuint (g_queue_get_length (self->priv->prepare_requests), ==, 0);
+ tp_clear_pointer (&self->priv->prepare_requests, g_queue_free);
g_free (self->bus_name);
g_free (self->object_path);
@@ -1580,7 +1648,126 @@ _tp_proxy_is_preparing (gpointer self,
state = tp_proxy_get_feature_state (self, feature);
g_return_val_if_fail (state != FEATURE_STATE_INVALID, FALSE);
- return (state == FEATURE_STATE_WANTED);
+ return (state == FEATURE_STATE_WANTED || state == FEATURE_STATE_TRYING);
+}
+
+static gboolean
+check_feature_interfaces (TpProxy *self,
+ GQuark name)
+{
+ const TpProxyFeature *feature = tp_proxy_subclass_get_feature (
+ G_OBJECT_TYPE (self), name);
+ guint i;
+
+ if (feature->interfaces_needed == NULL)
+ return TRUE;
+
+ for (i = 0; feature->interfaces_needed[i] != 0; i++)
+ {
+ if (!tp_proxy_has_interface_by_id (self, feature->interfaces_needed[i]))
+ {
+ DEBUG ("Proxy doesn't implement %s, can't prepare feature %s",
+ g_quark_to_string (feature->interfaces_needed[i]),
+ g_quark_to_string (name));
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Returns %TRUE if all the deps of @name are ready
+ * @can_retry: if %TRUE dependencies which have failed but have
+ * TpProxyFeature.can_retry won't be considered as having failed so we'll
+ * still have a change to retry preparing those.
+ * @failed: (out): %TRUE if one of @name's dep can't be prepared and so
+ * @name can't be either
+ */
+static gboolean
+check_depends_ready (TpProxy *self,
+ GQuark name,
+ gboolean can_retry,
+ gboolean *failed)
+{
+ const TpProxyFeature *feature = tp_proxy_subclass_get_feature (
+ G_OBJECT_TYPE (self), name);
+ guint i;
+ gboolean ready = TRUE;
+
+ g_assert (failed != NULL);
+ *failed = FALSE;
+
+ if (feature->depends_on == NULL)
+ return TRUE;
+
+ for (i = 0; feature->depends_on[i] != 0; i++)
+ {
+ GQuark dep = feature->depends_on[i];
+ const TpProxyFeature *dep_feature = tp_proxy_subclass_get_feature (
+ G_OBJECT_TYPE (self), dep);
+ FeatureState dep_state;
+
+ dep_state = tp_proxy_get_feature_state (self, dep);
+ switch (dep_state)
+ {
+ case FEATURE_STATE_INVALID:
+ DEBUG ("Can't prepare %s, because %s (a dependency) is "
+ "invalid", g_quark_to_string (name), g_quark_to_string (dep));
+
+ *failed = TRUE;
+ return FALSE;
+
+ case FEATURE_STATE_FAILED:
+ if (!can_retry || !dep_feature->can_retry)
+ {
+ DEBUG ("Can't prepare %s, because %s (a dependency) is "
+ "failed to prepare",
+ g_quark_to_string (name), g_quark_to_string (dep));
+
+ *failed = TRUE;
+ return FALSE;
+ }
+
+ DEBUG ("retry preparing dep: %s", g_quark_to_string (dep));
+ tp_proxy_set_feature_state (self, dep, FEATURE_STATE_WANTED);
+ ready = FALSE;
+ break;
+
+ case FEATURE_STATE_UNWANTED:
+ case FEATURE_STATE_WANTED:
+ case FEATURE_STATE_TRYING:
+ ready = FALSE;
+ break;
+
+ case FEATURE_STATE_READY:
+ break;
+ }
+ }
+
+ return ready;
+}
+
+static void
+depends_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpProxy *self = (TpProxy *) source;
+
+ tp_proxy_poll_features (self, NULL);
+}
+
+static void
+prepare_depends (TpProxy *self,
+ GQuark name)
+{
+ const TpProxyFeature *feature;
+
+ feature = tp_proxy_subclass_get_feature (G_OBJECT_TYPE (self), name);
+ g_assert (feature->depends_on != NULL);
+
+ tp_proxy_prepare_async (self, feature->depends_on, depends_prepare_cb, NULL);
}
/**
@@ -1649,7 +1836,6 @@ tp_proxy_prepare_async (gpointer self,
{
TpProxy *proxy = self;
GSimpleAsyncResult *result = NULL;
- const GError *error;
guint i;
g_return_if_fail (TP_IS_PROXY (self));
@@ -1660,26 +1846,39 @@ tp_proxy_prepare_async (gpointer self,
for (i = 0; features[i] != 0; i++)
{
FeatureState state = tp_proxy_get_feature_state (self, features[i]);
+ const TpProxyFeature *feature = tp_proxy_subclass_get_feature (
+ G_OBJECT_TYPE (self), features[i]);
+ /* We just skip unknown features, which have state FEATURE_STATE_INVALID
+ * (this doesn't seem ideal, but is
+ * consistent with TpAccountManager's existing behaviour) */
if (state == FEATURE_STATE_INVALID)
{
- /* just skip unknown features (this doesn't seem ideal, but is
- * consistent with TpAccountManager's existing behaviour) */
continue;
}
-
- if (state == FEATURE_STATE_UNWANTED)
+ else if (state == FEATURE_STATE_UNWANTED ||
+ (state == FEATURE_STATE_FAILED && feature->can_retry))
{
- const TpProxyFeature *feat_struct = tp_proxy_subclass_get_feature (
- G_OBJECT_TYPE (self), features[i]);
+ gboolean failed;
- g_return_if_fail (feat_struct != NULL);
+ /* Check deps. We only offer there the chance to retry a previously
+ * failed dependency. Doing it in tp_proxy_poll_features() could
+ * result in an infinite loop if we'd depends on 2 features which
+ * are constantly failing. */
+ if (!check_depends_ready (self, features[i], TRUE, &failed))
+ {
+ if (failed)
+ {
+ /* We can't prepare the feature because of its deps */
+ tp_proxy_set_feature_state (self, features[i],
+ FEATURE_STATE_FAILED);
+ continue;
+ }
- DEBUG ("%p: %s newly wanted", self, g_quark_to_string (features[i]));
- tp_proxy_set_feature_state (self, features[i], FEATURE_STATE_WANTED);
+ prepare_depends (self, features[i]);
+ }
- if (feat_struct->start_preparing != NULL)
- feat_struct->start_preparing (self);
+ tp_proxy_set_feature_state (self, features[i], FEATURE_STATE_WANTED);
}
}
@@ -1687,21 +1886,18 @@ tp_proxy_prepare_async (gpointer self,
result = g_simple_async_result_new (self, callback, user_data,
tp_proxy_prepare_async);
- error = tp_proxy_get_invalidated (self);
-
- if (error != NULL)
+ if (proxy->invalidated != NULL)
{
if (result != NULL)
{
- g_simple_async_result_set_from_error (result, error);
+ g_simple_async_result_set_from_error (result, proxy->invalidated);
g_simple_async_result_complete_in_idle (result);
}
goto finally;
}
- proxy->priv->prepare_requests = g_list_append (
- proxy->priv->prepare_requests,
+ g_queue_push_tail (proxy->priv->prepare_requests,
tp_proxy_prepare_request_new (result, features));
tp_proxy_poll_features (proxy, NULL);
@@ -1745,11 +1941,167 @@ tp_proxy_prepare_finish (gpointer self,
return TRUE;
}
+static gboolean
+prepare_finish (TpProxy *self,
+ GAsyncResult *result,
+ gpointer source,
+ GError **error)
+{
+ _tp_implement_finish_void (self, source);
+}
+
+static void
+feature_prepared_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpProxy *self = (TpProxy *) source;
+ TpProxyFeature *feature = user_data;
+ GError *error = NULL;
+ gboolean prepared = TRUE;
+
+ if (!prepare_finish (self, result, feature->prepare_async, &error))
+ {
+ DEBUG ("Failed to prepare %s: %s", g_quark_to_string (feature->name),
+ error->message);
+
+ prepared = FALSE;
+ g_error_free (error);
+ }
+
+ _tp_proxy_set_feature_prepared (self, feature->name, prepared);
+}
+
+static void
+prepare_feature (TpProxy *self,
+ const TpProxyFeature *feature)
+{
+ if (feature->prepare_async == NULL)
+ return;
+
+ feature->prepare_async (self, feature, feature_prepared_cb,
+ (gpointer) feature);
+}
+
+static gboolean
+core_prepared (TpProxy *self)
+{
+ /* All the core features have been prepared if the head of the
+ * prepare_requests queue is NOT a core feature */
+ TpProxyPrepareRequest *req = g_queue_peek_head (self->priv->prepare_requests);
+
+ if (req == NULL)
+ return TRUE;
+
+ return !req->core;
+}
+
+/* Returns %TRUE if all the features requested in @req have complete their
+ * preparation */
+static gboolean
+request_is_complete (TpProxy *self,
+ TpProxyPrepareRequest *req)
+{
+ guint i;
+ gboolean complete = TRUE;
+
+ for (i = 0; i < req->features->len; i++)
+ {
+ GQuark feature = g_array_index (req->features, GQuark, i);
+ FeatureState state = tp_proxy_get_feature_state (self, feature);
+ const TpProxyFeature *feat_struct = tp_proxy_subclass_get_feature (
+ G_OBJECT_TYPE (self), feature);
+
+ switch (state)
+ {
+ case FEATURE_STATE_UNWANTED:
+ /* this can only happen in the special pseudo-request for the
+ * core features, which blocks everything */
+ g_assert (req->core);
+ complete = FALSE;
+
+ /* fall through to treat it as WANTED */
+ case FEATURE_STATE_WANTED:
+ if (core_prepared (self) ||
+ req->core)
+ {
+ gboolean failed;
+
+ /* Check if we have the required interfaces. We can't do that
+ * in tp_proxy_prepare_async() as CORE have to be prepared */
+ if (!check_feature_interfaces (self, feature))
+ {
+ tp_proxy_set_feature_state (self, feature,
+ FEATURE_STATE_FAILED);
+ continue;
+ }
+
+ if (check_depends_ready (self, feature, FALSE, &failed))
+ {
+ /* We can prepare it now */
+ DEBUG ("%p: calling callback for %s", self,
+ g_quark_to_string (feature));
+
+ tp_proxy_set_feature_state (self, feature,
+ FEATURE_STATE_TRYING);
+
+ prepare_feature (self, feat_struct);
+ complete = FALSE;
+ }
+ else if (failed)
+ {
+ tp_proxy_set_feature_state (self, feature,
+ FEATURE_STATE_FAILED);
+ }
+ else
+ {
+ /* We have to wait until the deps finish their
+ * preparation. */
+ complete = FALSE;
+ }
+ }
+ break;
+
+ case FEATURE_STATE_TRYING:
+ complete = FALSE;
+ break;
+
+ case FEATURE_STATE_INVALID:
+ case FEATURE_STATE_FAILED:
+ case FEATURE_STATE_READY:
+ /* nothing more to do */
+ break;
+ }
+ }
+
+ return complete;
+}
+
+static void
+finish_all_requests (TpProxy *self,
+ const GError *error)
+{
+ GList *iter;
+ GQueue *tmp = g_queue_copy (self->priv->prepare_requests);
+
+ g_queue_clear (self->priv->prepare_requests);
+
+ for (iter = tmp->head; iter != NULL; iter = g_list_next (iter))
+ {
+ tp_proxy_prepare_request_finish (iter->data, error);
+ }
+
+ g_queue_clear (tmp);
+}
+
/*
* tp_proxy_poll_features:
* @self: a proxy
* @error: if not %NULL, fail all feature requests with this error
*
+ * For each feature in state WANTED, if its dependencies have been satisfied,
+ * call the callback and advance it to state TRYING.
+ *
* For each feature request, see if it's finished yet.
*
* Called every time the set of prepared/failed features changes,
@@ -1766,71 +2118,53 @@ tp_proxy_poll_features (TpProxy *self,
GList *iter;
GList *next;
- if (self->priv->prepare_requests == NULL)
+ if (g_queue_get_length (self->priv->prepare_requests) == 0)
return;
- if (error == NULL)
- {
- error_source = "invalidated";
- error = self->invalidated;
- }
+ g_object_ref (self);
- if (error != NULL)
+ for (iter = self->priv->prepare_requests->head; iter != NULL; iter = next)
{
- DEBUG ("%p: %s, ending all requests", self, error_source);
- iter = self->priv->prepare_requests;
- self->priv->prepare_core = NULL;
- self->priv->prepare_requests = NULL;
+ TpProxyPrepareRequest *req = iter->data;
+ TpProxyPrepareRequest *head = g_queue_peek_head (
+ self->priv->prepare_requests);
- for ( ; iter != NULL; iter = g_list_delete_link (iter, iter))
+ if (error == NULL)
{
- tp_proxy_prepare_request_finish (iter->data, error);
+ error_source = "invalidated";
+ error = self->invalidated;
}
- }
- for (iter = self->priv->prepare_requests; iter != NULL; iter = next)
- {
- TpProxyPrepareRequest *req = iter->data;
- gboolean wait = FALSE;
- guint i;
+ if (error != NULL)
+ {
+ DEBUG ("%p: %s, ending all requests", self, error_source);
+
+ finish_all_requests (self, error);
+ break;
+ }
next = iter->next;
- /* prepare_core is always the first in the list (if present), so it
- * will always have been checked by the time we reach any later one */
- if (self->priv->prepare_core != NULL && req != self->priv->prepare_core)
+ /* Core features have to be prepared first, in superclass-to-subclass
+ * order. The next core feature to be prepared, if any, is always at the
+ * head of prepare_requests. */
+ if (!core_prepared (self) &&
+ req != head)
{
DEBUG ("%p: core features not ready yet, nothing prepared", self);
continue;
}
- for (i = 0; i < req->features->len; i++)
- {
- FeatureState state = tp_proxy_get_feature_state (self,
- g_array_index (req->features, GQuark, i));
-
- if (state == FEATURE_STATE_UNWANTED || state == FEATURE_STATE_WANTED)
- {
- wait = TRUE;
- break;
- }
- }
-
- if (!wait)
+ if (request_is_complete (self, req))
{
DEBUG ("%p: request %p prepared", self, req);
- self->priv->prepare_requests = g_list_delete_link (
- self->priv->prepare_requests, iter);
-
- if (req == self->priv->prepare_core)
- {
- DEBUG ("%p: core features ready", self);
- self->priv->prepare_core = NULL;
- }
+ g_queue_delete_link (self->priv->prepare_requests, iter);
tp_proxy_prepare_request_finish (req, NULL);
}
}
+
+ g_object_unref (self);
}
/*
@@ -1885,3 +2219,91 @@ _tp_proxy_set_features_failed (TpProxy *self,
g_return_if_fail (error != NULL);
tp_proxy_poll_features (self, error);
}
+
+static void
+check_announce_connected (TpProxy *self,
+ gboolean in_idle)
+{
+ if (self->priv->pending_will_announce_calls != 0)
+ return;
+
+ if (in_idle)
+ {
+ g_simple_async_result_complete_in_idle (
+ self->priv->will_announce_connected_result);
+ }
+ else
+ {
+ g_simple_async_result_complete (
+ self->priv->will_announce_connected_result);
+ }
+
+ tp_clear_object (&self->priv->will_announce_connected_result);
+}
+
+static void
+prepare_before_signalling_connected_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TpProxy *self = user_data;
+
+ /* We don't care if the call succeeded or not as it was already prepared */
+ self->priv->pending_will_announce_calls--;
+
+ check_announce_connected (self, FALSE);
+}
+
+static void foreach_feature (GQuark name,
+ gpointer data,
+ gpointer user_data)
+{
+ FeatureState state = GPOINTER_TO_INT (data);
+ TpProxy *self = user_data;
+ const TpProxyFeature *feature;
+
+ if (state != FEATURE_STATE_READY)
+ return;
+
+ feature = tp_proxy_subclass_get_feature (G_OBJECT_TYPE (self), name);
+
+ if (feature->prepare_before_signalling_connected_async == NULL)
+ return;
+
+ self->priv->pending_will_announce_calls++;
+
+ feature->prepare_before_signalling_connected_async (self, feature,
+ prepare_before_signalling_connected_cb, self);
+}
+
+/*
+ * _tp_proxy_will_announce_connected_async:
+ *
+ * Called by connection.c when the connection became connected and we're about
+ * to announce it. But before we have to wait for all the prepared features to
+ * process their prepare_before_signalling_connected_async, if any.
+ */
+void
+_tp_proxy_will_announce_connected_async (TpProxy *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_assert (TP_IS_CONNECTION (self));
+ g_assert (self->priv->will_announce_connected_result == NULL);
+
+ self->priv->will_announce_connected_result = g_simple_async_result_new (
+ (GObject *) self, callback, user_data,
+ _tp_proxy_will_announce_connected_async);
+
+ g_datalist_foreach (&self->priv->features, foreach_feature, self);
+
+ check_announce_connected (self, TRUE);
+}
+
+gboolean
+_tp_proxy_will_announce_connected_finish (TpProxy *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ _tp_implement_finish_void (self, _tp_proxy_will_announce_connected_async)
+}
diff --git a/telepathy-glib/proxy.h b/telepathy-glib/proxy.h
index 0f350d8d..8b0cdfb3 100644
--- a/telepathy-glib/proxy.h
+++ b/telepathy-glib/proxy.h
@@ -71,8 +71,32 @@ struct _TpProxy {
typedef struct _TpProxyClass TpProxyClass;
-/* defined in proxy-internal.h for now */
typedef struct _TpProxyFeature TpProxyFeature;
+typedef struct _TpProxyFeaturePrivate TpProxyFeaturePrivate;
+
+typedef void (* TpProxyPrepareAsync) (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+struct _TpProxyFeature {
+ /*<public>*/
+ GQuark name;
+ gboolean core;
+
+ TpProxyPrepareAsync prepare_async;
+ TpProxyPrepareAsync prepare_before_signalling_connected_async;
+
+ const GQuark *interfaces_needed;
+ /* Features we depend on */
+ const GQuark *depends_on;
+
+ gboolean can_retry;
+
+ /*<private>*/
+ GCallback _reserved[4];
+ TpProxyFeaturePrivate *priv;
+};
/* XXX: hide this from the g-i scanner, since vapigen can't cope */
#ifndef __GI_SCANNER__
diff --git a/telepathy-glib/text-channel.c b/telepathy-glib/text-channel.c
index dec83cdd..5cf42421 100644
--- a/telepathy-glib/text-channel.c
+++ b/telepathy-glib/text-channel.c
@@ -581,6 +581,17 @@ got_pending_senders_contact (TpTextChannel *self,
}
static void
+free_parts_list (GList *parts_list)
+{
+ GList *l;
+
+ for (l = parts_list; l != NULL; l = g_list_next (l))
+ g_boxed_free (TP_ARRAY_TYPE_MESSAGE_PART_LIST, l->data);
+
+ g_list_free (parts_list);
+}
+
+static void
got_pending_senders_contact_by_handle_cb (TpConnection *connection,
guint n_contacts,
TpContact * const *contacts,
@@ -590,8 +601,10 @@ got_pending_senders_contact_by_handle_cb (TpConnection *connection,
gpointer user_data,
GObject *weak_object)
{
- TpTextChannel *self = (TpTextChannel *) weak_object;
+ GSimpleAsyncResult *result = (GSimpleAsyncResult *) weak_object;
GList *parts_list = user_data;
+ TpTextChannel *self = TP_TEXT_CHANNEL (g_async_result_get_source_object (
+ G_ASYNC_RESULT (result)));
if (error != NULL)
{
@@ -621,8 +634,10 @@ got_pending_senders_contact_by_id_cb (TpConnection *connection,
gpointer user_data,
GObject *weak_object)
{
- TpTextChannel *self = (TpTextChannel *) weak_object;
+ GSimpleAsyncResult *result = (GSimpleAsyncResult *) weak_object;
GList *parts_list = user_data;
+ TpTextChannel *self = TP_TEXT_CHANNEL (g_async_result_get_source_object (
+ G_ASYNC_RESULT (result)));
if (error != NULL)
{
@@ -650,18 +665,6 @@ out:
TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, TRUE);
}
-static void
-free_parts_list (gpointer data)
-{
- GList *parts_list = data;
- GList *l;
-
- for (l = parts_list; l != NULL; l = g_list_next (l))
- g_boxed_free (TP_ARRAY_TYPE_MESSAGE_PART_LIST, l->data);
-
- g_list_free (parts_list);
-}
-
/* There is no TP_ARRAY_TYPE_PENDING_TEXT_MESSAGE_LIST_LIST (fdo #32433) */
#define ARRAY_TYPE_PENDING_TEXT_MESSAGE_LIST_LIST dbus_g_type_get_collection (\
"GPtrArray", TP_ARRAY_TYPE_MESSAGE_PART_LIST)
@@ -673,7 +676,8 @@ get_pending_messages_cb (TpProxy *proxy,
gpointer user_data,
GObject *weak_object)
{
- TpTextChannel *self = user_data;
+ TpTextChannel *self = (TpTextChannel *) proxy;
+ GSimpleAsyncResult *result = user_data;
guint i;
GPtrArray *messages;
TpIntSet *senders;
@@ -686,18 +690,20 @@ get_pending_messages_cb (TpProxy *proxy,
{
DEBUG ("Failed to get PendingMessages property: %s", error->message);
- _tp_proxy_set_feature_prepared (proxy,
- TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, FALSE);
- return;
+ g_simple_async_result_set_error (result, error->domain, error->code,
+ "Failed to get PendingMessages property: %s", error->message);
+
+ g_simple_async_result_complete (result);
}
if (!G_VALUE_HOLDS (value, ARRAY_TYPE_PENDING_TEXT_MESSAGE_LIST_LIST))
{
DEBUG ("PendingMessages property is of the wrong type");
- _tp_proxy_set_feature_prepared (proxy,
- TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, FALSE);
- return;
+ g_simple_async_result_set_error (result, TP_ERRORS, TP_ERROR_CONFUSED,
+ "PendingMessages property is of the wrong type");
+
+ g_simple_async_result_complete (result);
}
senders = tp_intset_new ();
@@ -739,8 +745,7 @@ get_pending_messages_cb (TpProxy *proxy,
if (tp_intset_size (senders) == 0)
{
- _tp_proxy_set_feature_prepared (proxy,
- TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, TRUE);
+ g_simple_async_result_complete (result);
}
else
{
@@ -753,13 +758,14 @@ get_pending_messages_cb (TpProxy *proxy,
DEBUG ("Pending messages may be re-ordered, please fix CM (%s)",
tp_proxy_get_object_path (conn));
+ /* Pass ownership of parts_list to the callback */
if (sender_ids->len == g_list_length (parts_list))
{
/* Use the sender ID rather than the handles */
tp_connection_get_contacts_by_id (conn, sender_ids->len,
(const gchar * const *) sender_ids->pdata,
0, NULL, got_pending_senders_contact_by_id_cb, parts_list,
- free_parts_list, G_OBJECT (self));
+ (GDestroyNotify) free_parts_list, G_OBJECT (result));
}
else
{
@@ -768,7 +774,7 @@ get_pending_messages_cb (TpProxy *proxy,
tp_connection_get_contacts_by_handle (conn, tmp->len,
(TpHandle *) tmp->data,
0, NULL, got_pending_senders_contact_by_handle_cb, parts_list,
- free_parts_list, G_OBJECT (self));
+ (GDestroyNotify) free_parts_list, G_OBJECT (result));
g_array_unref (tmp);
}
@@ -779,10 +785,17 @@ get_pending_messages_cb (TpProxy *proxy,
}
static void
-tp_text_channel_prepare_pending_messages (TpProxy *proxy)
+tp_text_channel_prepare_pending_messages_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
TpChannel *channel = (TpChannel *) proxy;
GError *error = NULL;
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ tp_text_channel_prepare_pending_messages_async);
tp_cli_channel_interface_messages_connect_to_message_received (channel,
message_received_cb, proxy, NULL, G_OBJECT (proxy), &error);
@@ -804,15 +817,15 @@ tp_text_channel_prepare_pending_messages (TpProxy *proxy)
tp_cli_dbus_properties_call_get (proxy, -1,
TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "PendingMessages",
- get_pending_messages_cb, proxy, NULL, G_OBJECT (proxy));
+ get_pending_messages_cb, result, g_object_unref, G_OBJECT (proxy));
return;
fail:
- g_error_free (error);
+ g_simple_async_result_take_error (result, error);
- _tp_proxy_set_feature_prepared (proxy,
- TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES, FALSE);
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
}
enum {
@@ -830,8 +843,8 @@ tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED)
features[FEAT_PENDING_MESSAGES].name =
TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES;
- features[FEAT_PENDING_MESSAGES].start_preparing =
- tp_text_channel_prepare_pending_messages;
+ features[FEAT_PENDING_MESSAGES].prepare_async =
+ tp_text_channel_prepare_pending_messages_async;
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am
index db9d0b9c..cf0d3e33 100644
--- a/tests/dbus/Makefile.am
+++ b/tests/dbus/Makefile.am
@@ -43,6 +43,7 @@ noinst_PROGRAMS = \
test-params-cm \
test-properties \
test-protocol-objects \
+ test-proxy-preparation \
test-self-handle \
test-self-presence \
test-simple-approver \
@@ -190,9 +191,9 @@ test_simple_handler_SOURCES = simple-handler.c
test_stream_tube_SOURCES = stream-tube.c
-
test_client_channel_factory_SOURCES = client-channel-factory.c
+test_proxy_preparation_SOURCES = proxy-preparation.c
# this one uses internal ABI
test_cm_message_SOURCES = \
diff --git a/tests/dbus/account-channel-request.c b/tests/dbus/account-channel-request.c
index 20e05ecc..7d673d9c 100644
--- a/tests/dbus/account-channel-request.c
+++ b/tests/dbus/account-channel-request.c
@@ -955,11 +955,7 @@ int
main (int argc,
char **argv)
{
- g_type_init ();
- tp_tests_abort_after (10);
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
/* Request and handle tests */
diff --git a/tests/dbus/base-client.c b/tests/dbus/base-client.c
index 7a8fb047..6e3c2581 100644
--- a/tests/dbus/base-client.c
+++ b/tests/dbus/base-client.c
@@ -441,7 +441,7 @@ no_return_cb (TpClient *proxy,
out:
test->wait--;
- if (test->wait <= 0)
+ if (test->wait == 0)
g_main_loop_quit (test->mainloop);
}
@@ -534,6 +534,7 @@ test_observer (Test *test,
channels, "/", requests_satisified, info,
no_return_cb, test, NULL, NULL);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
@@ -552,6 +553,7 @@ test_observer (Test *test,
channels, "/", requests_satisified, info,
no_return_cb, test, NULL, NULL);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_error (test->error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT);
g_clear_error (&test->error);
@@ -567,6 +569,7 @@ test_observer (Test *test,
tp_tests_text_channel_null_close (test->text_chan_service);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
@@ -675,6 +678,7 @@ test_approver (Test *test,
channels, CDO_PATH, properties,
no_return_cb, test, NULL, NULL);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
@@ -709,6 +713,7 @@ test_approver (Test *test,
tp_tests_text_channel_null_close (test->text_chan_service_2);
+ test->wait++;
g_object_unref (test->text_chan_service_2);
test->text_chan_service_2 = NULL;
@@ -740,6 +745,7 @@ test_approver (Test *test,
tp_tests_simple_channel_dispatch_operation_lost_channel (test->cdo_service,
test->text_chan);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
@@ -880,6 +886,7 @@ test_handler (Test *test,
channels, requests_satisified, 0, info,
no_return_cb, test, NULL, NULL);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
@@ -1076,6 +1083,7 @@ test_handler_requests (Test *test,
channels, requests_satisified, 0, info,
no_return_cb, test, NULL, NULL);
+ test->wait++;
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
@@ -1109,15 +1117,109 @@ test_handler_requests (Test *test,
g_hash_table_unref (info);
}
+static void
+claim_with_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ tp_channel_dispatch_operation_claim_with_finish (
+ TP_CHANNEL_DISPATCH_OPERATION (source), result, &test->error);
+
+ test->wait--;
+ if (test->wait == 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+test_channel_dispatch_operation_claim_with_async (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ GPtrArray *channels;
+ GHashTable *properties;
+ static const char *interfaces[] = { NULL };
+ static const gchar *possible_handlers[] = {
+ TP_CLIENT_BUS_NAME_BASE ".Badger", NULL, };
+ TpChannelDispatchOperation *cdo;
+ GList *handled;
+
+ /* Register an Approver and Handler */
+ tp_base_client_take_approver_filter (test->base_client, tp_asv_new (
+ TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+ TP_IFACE_CHANNEL_TYPE_TEXT,
+ NULL));
+
+ tp_base_client_take_handler_filter (test->base_client, tp_asv_new (
+ TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+ TP_IFACE_CHANNEL_TYPE_TEXT,
+ NULL));
+
+ tp_base_client_register (test->base_client, &test->error);
+ g_assert_no_error (test->error);
+
+ /* Call AddDispatchOperation */
+ channels = g_ptr_array_sized_new (2);
+ add_channel_to_ptr_array (channels, test->text_chan);
+ add_channel_to_ptr_array (channels, test->text_chan_2);
+
+ properties = tp_asv_new (
+ TP_PROP_CHANNEL_DISPATCH_OPERATION_INTERFACES,
+ G_TYPE_STRV, interfaces,
+ TP_PROP_CHANNEL_DISPATCH_OPERATION_CONNECTION,
+ DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (test->connection),
+ TP_PROP_CHANNEL_DISPATCH_OPERATION_ACCOUNT,
+ DBUS_TYPE_G_OBJECT_PATH, tp_proxy_get_object_path (test->account),
+ TP_PROP_CHANNEL_DISPATCH_OPERATION_POSSIBLE_HANDLERS,
+ G_TYPE_STRV, possible_handlers,
+ NULL);
+
+ tp_proxy_add_interface_by_id (TP_PROXY (test->client),
+ TP_IFACE_QUARK_CLIENT_APPROVER);
+
+ tp_cli_client_approver_call_add_dispatch_operation (test->client, -1,
+ channels, CDO_PATH, properties,
+ no_return_cb, test, NULL, NULL);
+
+ test->wait++;
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ cdo = test->simple_client->add_dispatch_ctx->dispatch_operation;
+ g_assert (TP_IS_CHANNEL_DISPATCH_OPERATION (cdo));
+
+ handled = tp_base_client_get_handled_channels (test->base_client);
+ g_assert (handled == NULL);
+
+ /* Claim the CDO, as the client is also a Handler, it is now handling the
+ * channels */
+ tp_channel_dispatch_operation_claim_with_async (cdo, test->base_client,
+ claim_with_cb, test);
+
+ test->wait++;
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ handled = tp_base_client_get_handled_channels (test->base_client);
+ g_assert_cmpuint (g_list_length (handled), ==, 2);
+ g_list_free (handled);
+
+ g_assert (tp_base_client_is_handling_channel (test->base_client,
+ test->text_chan));
+ g_assert (tp_base_client_is_handling_channel (test->base_client,
+ test->text_chan_2));
+
+ g_ptr_array_foreach (channels, free_channel_details, NULL);
+ g_ptr_array_free (channels, TRUE);
+ g_hash_table_unref (properties);
+}
+
int
main (int argc,
char **argv)
{
- g_type_init ();
- tp_tests_abort_after (10);
- tp_debug_set_flags ("all");
+ tp_tests_init (&argc, &argv);
- g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/base-client/basics", Test, NULL, setup, test_basics, teardown);
@@ -1131,6 +1233,8 @@ main (int argc,
teardown);
g_test_add ("/base-client/handler-requests", Test, NULL, setup,
test_handler_requests, teardown);
+ g_test_add ("/cdo/claim_with", Test, NULL, setup,
+ test_channel_dispatch_operation_claim_with_async, teardown);
return g_test_run ();
}
diff --git a/tests/dbus/call-example.c b/tests/dbus/call-example.c
index ccbe981a..0e3cfb7a 100644
--- a/tests/dbus/call-example.c
+++ b/tests/dbus/call-example.c
@@ -1085,12 +1085,10 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_set_prgname ("call-example");
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+ g_set_prgname ("call-example");
- g_type_init ();
future_cli_init ();
g_test_add ("/call/basics", Test, NULL, setup, test_basics, teardown);
diff --git a/tests/dbus/callable-example.c b/tests/dbus/callable-example.c
index 8ee33618..b3703f5f 100644
--- a/tests/dbus/callable-example.c
+++ b/tests/dbus/callable-example.c
@@ -1548,8 +1548,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/callable/basics", Test, NULL, setup, test_basics, teardown);
diff --git a/tests/dbus/channel-dispatch-operation.c b/tests/dbus/channel-dispatch-operation.c
index 0e6ed82e..4f7f9e27 100644
--- a/tests/dbus/channel-dispatch-operation.c
+++ b/tests/dbus/channel-dispatch-operation.c
@@ -655,6 +655,9 @@ test_claim (Test *test,
g_main_loop_run (test->mainloop);
g_assert_no_error (test->error);
+
+ /* tp_channel_dispatch_operation_claim_with_async() is tested in
+ * tests/dbus/base-client.c */
}
static void
@@ -780,8 +783,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/cdo/new", Test, NULL, setup, test_new, teardown);
diff --git a/tests/dbus/channel-dispatcher.c b/tests/dbus/channel-dispatcher.c
index 3e60e901..e84ba805 100644
--- a/tests/dbus/channel-dispatcher.c
+++ b/tests/dbus/channel-dispatcher.c
@@ -65,8 +65,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/cd/new", Test, NULL, setup, test_new, teardown);
diff --git a/tests/dbus/channel-request.c b/tests/dbus/channel-request.c
index ad3e2ff6..7aba2e29 100644
--- a/tests/dbus/channel-request.c
+++ b/tests/dbus/channel-request.c
@@ -368,8 +368,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/cr/new", Test, NULL, setup, test_new, teardown);
diff --git a/tests/dbus/channel.c b/tests/dbus/channel.c
index d7b2932a..fab026ae 100644
--- a/tests/dbus/channel.c
+++ b/tests/dbus/channel.c
@@ -416,11 +416,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/channel/leave/contact/unprepared/no-reason", Test, NULL, setup,
diff --git a/tests/dbus/client-channel-factory.c b/tests/dbus/client-channel-factory.c
index fecf98a6..e68ec0cc 100644
--- a/tests/dbus/client-channel-factory.c
+++ b/tests/dbus/client-channel-factory.c
@@ -250,11 +250,7 @@ int
main (int argc,
char **argv)
{
- g_type_init ();
- tp_tests_abort_after (10);
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/client-channel-factory/basic/creation", Test, NULL, setup,
diff --git a/tests/dbus/client.c b/tests/dbus/client.c
index e06a3d26..4b88ddae 100644
--- a/tests/dbus/client.c
+++ b/tests/dbus/client.c
@@ -66,8 +66,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/client/new", Test, NULL, setup, test_new, teardown);
diff --git a/tests/dbus/cm.c b/tests/dbus/cm.c
index 60e67570..ca0d1ad9 100644
--- a/tests/dbus/cm.c
+++ b/tests/dbus/cm.c
@@ -1017,8 +1017,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add_func ("/cm/valid-name", test_valid_name);
diff --git a/tests/dbus/connection-interests.c b/tests/dbus/connection-interests.c
index 7655f39b..75d65ae3 100644
--- a/tests/dbus/connection-interests.c
+++ b/tests/dbus/connection-interests.c
@@ -392,8 +392,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (5);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_add ("/conn/interest", Test, NULL, setup, test_interest, teardown);
g_test_add ("/conn/interested-client", Test, NULL, setup,
diff --git a/tests/dbus/connection.c b/tests/dbus/connection.c
index 95584161..b4dc04e9 100644
--- a/tests/dbus/connection.c
+++ b/tests/dbus/connection.c
@@ -399,8 +399,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_add ("/conn/prepare", Test, NULL, setup, test_prepare, teardown);
g_test_add ("/conn/fail_to_prepare", Test, NULL, setup, test_fail_to_prepare,
diff --git a/tests/dbus/contact-lists.c b/tests/dbus/contact-lists.c
index b741e88e..61fa2232 100644
--- a/tests/dbus/contact-lists.c
+++ b/tests/dbus/contact-lists.c
@@ -2319,8 +2319,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (60);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_add ("/contact-lists/nothing",
Test, NULL, setup, test_nothing, teardown);
diff --git a/tests/dbus/contacts-slow-path.c b/tests/dbus/contacts-slow-path.c
index 18cdb459..bb291ec3 100644
--- a/tests/dbus/contacts-slow-path.c
+++ b/tests/dbus/contacts-slow-path.c
@@ -1299,11 +1299,7 @@ int
main (int argc,
char **argv)
{
- g_type_init ();
- tp_debug_set_flags ("all");
- tp_tests_abort_after (10);
- g_set_prgname ("contacts-slow-path");
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/contacts-slow-path/by-handle", Fixture, NULL, setup,
diff --git a/tests/dbus/contacts.c b/tests/dbus/contacts.c
index ba2bc73c..54c6ad38 100644
--- a/tests/dbus/contacts.c
+++ b/tests/dbus/contacts.c
@@ -1977,20 +1977,16 @@ test_prepare_contact_caps_without_request (Fixture *f,
for (i = 0; i < 3; i++)
{
TpCapabilities *caps;
- GPtrArray *classes;
g_assert_cmpuint (tp_contact_get_handle (contacts[i]), ==, handles[i]);
g_assert_cmpstr (tp_contact_get_identifier (contacts[i]), ==,
ids[i]);
- MYASSERT (tp_contact_has_feature (contacts[i],
+ MYASSERT (!tp_contact_has_feature (contacts[i],
TP_CONTACT_FEATURE_CAPABILITIES), "");
caps = tp_contact_get_capabilities (contacts[i]);
- MYASSERT (caps != NULL, "");
- MYASSERT (!tp_capabilities_is_specific_to_contact (caps), "");
- classes = tp_capabilities_get_channel_classes (caps);
- g_assert_cmpuint (classes->len, ==, 0);
+ MYASSERT (caps == NULL, "");
}
g_assert (result.error == NULL);
@@ -2310,11 +2306,7 @@ int
main (int argc,
char **argv)
{
- g_type_init ();
- tp_debug_set_flags ("all");
- tp_tests_abort_after (10);
- g_set_prgname ("contacts");
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
#define ADD(x) \
diff --git a/tests/dbus/dbus.c b/tests/dbus/dbus.c
index a347f418..da7525fb 100644
--- a/tests/dbus/dbus.c
+++ b/tests/dbus/dbus.c
@@ -332,11 +332,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- tp_debug_set_flags ("all");
-
- g_type_init ();
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_add_func ("/dbus/validation", test_validation);
g_test_add_func ("/dbus-daemon/properties", test_properties);
diff --git a/tests/dbus/get-interface-after-invalidate.c b/tests/dbus/get-interface-after-invalidate.c
index 9027d4ac..36abe354 100644
--- a/tests/dbus/get-interface-after-invalidate.c
+++ b/tests/dbus/get-interface-after-invalidate.c
@@ -34,8 +34,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_add_func ("/test-get-interface-after-invalidate",
test_get_interface_after_invalidate);
diff --git a/tests/dbus/group-mixin.c b/tests/dbus/group-mixin.c
index 558be19f..51153be6 100644
--- a/tests/dbus/group-mixin.c
+++ b/tests/dbus/group-mixin.c
@@ -195,8 +195,7 @@ static void
details_contains_ids_for (const GHashTable *details,
TpHandle *hs)
{
- const GValue *member_ids_v;
- GHashTable *member_ids;
+ GHashTable *contact_ids;
const gchar *id;
guint n = 0;
TpHandle *h;
@@ -204,19 +203,20 @@ details_contains_ids_for (const GHashTable *details,
if (details == NULL)
return;
- member_ids_v = tp_asv_lookup (details, "member-ids");
- member_ids = g_value_get_boxed (member_ids_v);
+ contact_ids = tp_asv_get_boxed (details, "contact-ids",
+ TP_HASH_TYPE_HANDLE_IDENTIFIER_MAP);
+ g_assert (contact_ids != NULL);
for (h = hs; *h != 0; h++)
{
n++;
- id = g_hash_table_lookup (member_ids, GUINT_TO_POINTER (*h));
+ id = g_hash_table_lookup (contact_ids, GUINT_TO_POINTER (*h));
MYASSERT (id != NULL, ": id for %u in map", *h);
g_assert_cmpstr (id, ==, tp_handle_inspect (contact_repo, *h));
}
- MYASSERT (g_hash_table_size (member_ids) == n, ": %u member IDs", n);
+ MYASSERT (g_hash_table_size (contact_ids) == n, ": %u contact IDs", n);
}
static void
@@ -360,7 +360,7 @@ camel_removed (const GArray *added,
TpHandle h;
/* camel2 is the actor. camel shouldn't be in the ids, because they were
* removed and the spec says that you can leave those out, and we want
- * tp-glib's automatic construction of member-ids to work in the #ubuntu
+ * tp-glib's automatic construction of contact-ids to work in the #ubuntu
* case.
*/
TpHandle hs[] = { camel2, 0 };
diff --git a/tests/dbus/params-cm.c b/tests/dbus/params-cm.c
index 39132c89..280b853e 100644
--- a/tests/dbus/params-cm.c
+++ b/tests/dbus/params-cm.c
@@ -342,8 +342,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/params-cm/set-params", Test, NULL, setup, test_set_params,
diff --git a/tests/dbus/protocol-objects.c b/tests/dbus/protocol-objects.c
index ecea32f3..5e499a04 100644
--- a/tests/dbus/protocol-objects.c
+++ b/tests/dbus/protocol-objects.c
@@ -431,8 +431,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/protocol-objects/protocol-properties", Test, NULL, setup,
diff --git a/tests/dbus/proxy-preparation.c b/tests/dbus/proxy-preparation.c
new file mode 100644
index 00000000..c331030a
--- /dev/null
+++ b/tests/dbus/proxy-preparation.c
@@ -0,0 +1,399 @@
+/* Tests of TpBaseClient
+ *
+ * Copyright © 2010-2011 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "tests/lib/util.h"
+#include "tests/lib/simple-account.h"
+#include "tests/lib/simple-conn.h"
+#include "tests/lib/my-conn-proxy.h"
+
+typedef struct {
+ GMainLoop *mainloop;
+ TpDBusDaemon *dbus;
+
+ /* Service side objects */
+ TpBaseConnection *base_connection;
+
+ /* Client side objects */
+ TpConnection *connection;
+ TpTestsMyConnProxy *my_conn;
+
+ GError *error /* initialized where needed */;
+ gint wait;
+} Test;
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ test->mainloop = g_main_loop_new (NULL, FALSE);
+ test->dbus = tp_tests_dbus_daemon_dup_or_die ();
+
+ test->error = NULL;
+
+ /* Create (service and client sides) connection objects */
+ tp_tests_create_and_connect_conn (TP_TESTS_TYPE_SIMPLE_CONNECTION,
+ "me@test.com", &test->base_connection, &test->connection);
+
+ test->my_conn = g_object_new (TP_TESTS_TYPE_MY_CONN_PROXY,
+ "dbus-daemon", test->dbus,
+ "bus-name", tp_proxy_get_bus_name (test->connection),
+ "object-path", tp_proxy_get_object_path (test->connection),
+ NULL);
+}
+
+static void
+disconnect_and_destroy_conn (Test *test)
+{
+ tp_cli_connection_run_disconnect (TP_CONNECTION (test->my_conn), -1,
+ &test->error, NULL);
+ g_assert_no_error (test->error);
+
+ tp_clear_object (&test->connection);
+ tp_clear_object (&test->base_connection);
+ tp_clear_object (&test->my_conn);
+
+}
+
+static void
+teardown (Test *test,
+ gconstpointer data)
+{
+ g_clear_error (&test->error);
+
+ tp_clear_object (&test->dbus);
+ g_main_loop_unref (test->mainloop);
+ test->mainloop = NULL;
+
+ disconnect_and_destroy_conn (test);
+}
+
+static void
+prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ tp_proxy_prepare_finish (TP_PROXY (source), result, &test->error);
+
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+test_prepare_capabilities (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Prepare capabilities on a new proxy. CORE should be automatically prepared
+ * *before* checking if Requests is implemented as
+ * tp_proxy_has_interface_by_id() can't work without CORE. */
+ GQuark features[] = { TP_CONNECTION_FEATURE_CAPABILITIES, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn, TP_CONNECTION_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_CONNECTION_FEATURE_CAPABILITIES));
+}
+
+static void
+test_prepare_core (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Test than preparing the 'top' core feature prepare the other core
+ * features as well */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_CORE, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (test->my_conn, TP_CONNECTION_FEATURE_CORE));
+
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_CONNECTION_FEATURE_CAPABILITIES));
+}
+
+static void
+test_depends (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Test if A is automatically prepared when preparing B */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_B, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_A));
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_B));
+}
+
+static void
+test_wrong_iface (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Feature can't be prepared because proxy doesn't support the right
+ * interface */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_WRONG_IFACE, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_WRONG_IFACE));
+}
+
+static void
+test_bad_dep (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Feature can't be prepared because it depends on an unpreparable
+ * feature */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_BAD_DEP, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_WRONG_IFACE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_BAD_DEP));
+}
+
+static void
+test_fail (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Feature preparation fails */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL));
+}
+
+static void
+test_fail_dep (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* Feature can't be prepared because its deps can't be prepared */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL_DEP, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL_DEP));
+}
+
+static void
+test_retry (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* We have the prepare the feature twice */
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY, 0 };
+
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY));
+
+ /* second attempt */
+ test->my_conn->retry_feature_success = TRUE;
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY));
+}
+
+static void
+test_retry_dep (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ /* RETRY_DEP depends on a feature having can_retry and which failed, so
+ * preparing RETRY_DEP will re-prepare it successfully */
+ GQuark features_retry[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY, 0 };
+ GQuark features_retry_dep[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP, 0 };
+
+ /* Try preparing TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY, will fail */
+ tp_proxy_prepare_async (test->my_conn, features_retry, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY));
+ g_assert (!tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP));
+
+ /* Try prepare TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP, will re-prepare
+ * TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY */
+ test->my_conn->retry_feature_success = TRUE;
+ tp_proxy_prepare_async (test->my_conn, features_retry_dep, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY));
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP));
+}
+
+static void
+recreate_connection (Test *test)
+{
+ gchar *name;
+ gchar *conn_path;
+
+ disconnect_and_destroy_conn (test);
+
+ test->base_connection = tp_tests_object_new_static_class (
+ TP_TESTS_TYPE_SIMPLE_CONNECTION,
+ "account", "me@test.com",
+ "protocol", "simple",
+ NULL);
+ g_assert (test->base_connection != NULL);
+
+ g_assert (tp_base_connection_register (test->base_connection, "simple",
+ &name, &conn_path, &test->error));
+ g_assert_no_error (test->error);
+
+ test->connection = tp_connection_new (test->dbus, name, conn_path,
+ &test->error);
+ g_assert_no_error (test->error);
+
+ test->my_conn = g_object_new (TP_TESTS_TYPE_MY_CONN_PROXY,
+ "dbus-daemon", test->dbus,
+ "bus-name", tp_proxy_get_bus_name (test->connection),
+ "object-path", tp_proxy_get_object_path (test->connection),
+ NULL);
+ g_assert (test->my_conn != NULL);
+
+ g_free (name);
+ g_free (conn_path);
+}
+
+static void
+test_before_connected (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ GQuark features[] = { TP_TESTS_MY_CONN_PROXY_FEATURE_BEFORE_CONNECTED, 0 };
+ GQuark connected[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
+
+ /* We need a not yet connected connection */
+ recreate_connection (test);
+
+ g_assert_cmpuint (test->my_conn->before_connected_state, ==,
+ BEFORE_CONNECTED_STATE_UNPREPARED);
+
+ /* Connection is not yet connected, prepare the feature */
+ tp_proxy_prepare_async (test->my_conn, features, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert (tp_proxy_is_prepared (test->my_conn,
+ TP_TESTS_MY_CONN_PROXY_FEATURE_BEFORE_CONNECTED));
+
+ g_assert_cmpuint (test->my_conn->before_connected_state, ==,
+ BEFORE_CONNECTED_STATE_NOT_CONNECTED);
+
+ tp_cli_connection_call_connect (test->connection, -1, NULL, NULL, NULL, NULL);
+
+ /* Wait that CONNECTED is announced */
+ tp_proxy_prepare_async (test->my_conn, connected, prepare_cb, test);
+
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ /* state has been updated */
+ g_assert_cmpuint (test->my_conn->before_connected_state, ==,
+ BEFORE_CONNECTED_STATE_CONNECTED);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ tp_tests_init (&argc, &argv);
+ g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+
+ g_test_add ("/proxy-preparation/prepare-capabilities", Test, NULL, setup,
+ test_prepare_capabilities, teardown);
+ g_test_add ("/proxy-preparation/prepare-core", Test, NULL, setup,
+ test_prepare_core, teardown);
+ g_test_add ("/proxy-preparation/depends", Test, NULL, setup,
+ test_depends, teardown);
+ g_test_add ("/proxy-preparation/wrong-iface", Test, NULL, setup,
+ test_wrong_iface, teardown);
+ g_test_add ("/proxy-preparation/bad-dep", Test, NULL, setup,
+ test_bad_dep, teardown);
+ g_test_add ("/proxy-preparation/fail", Test, NULL, setup,
+ test_fail, teardown);
+ g_test_add ("/proxy-preparation/fail-dep", Test, NULL, setup,
+ test_fail_dep, teardown);
+ g_test_add ("/proxy-preparation/retry", Test, NULL, setup,
+ test_retry, teardown);
+ g_test_add ("/proxy-preparation/retry-dep", Test, NULL, setup,
+ test_retry_dep, teardown);
+ g_test_add ("/proxy-preparation/before-connected", Test, NULL, setup,
+ test_before_connected, teardown);
+
+ return g_test_run ();
+}
diff --git a/tests/dbus/self-handle.c b/tests/dbus/self-handle.c
index ccb7cdc3..ef55e095 100644
--- a/tests/dbus/self-handle.c
+++ b/tests/dbus/self-handle.c
@@ -350,11 +350,8 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
+ tp_tests_init (&argc, &argv);
g_set_prgname ("self-handle");
- g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/self-handle", Fixture, NULL, setup_and_connect,
diff --git a/tests/dbus/simple-approver.c b/tests/dbus/simple-approver.c
index a1865148..1cd725e1 100644
--- a/tests/dbus/simple-approver.c
+++ b/tests/dbus/simple-approver.c
@@ -487,11 +487,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/simple-/properties", Test, NULL, setup, test_properties,
diff --git a/tests/dbus/simple-handler.c b/tests/dbus/simple-handler.c
index 461667cb..211c3e51 100644
--- a/tests/dbus/simple-handler.c
+++ b/tests/dbus/simple-handler.c
@@ -503,11 +503,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/simple-handler/properties", Test, NULL, setup, test_properties,
diff --git a/tests/dbus/simple-observer.c b/tests/dbus/simple-observer.c
index eac24e4f..1d0abb29 100644
--- a/tests/dbus/simple-observer.c
+++ b/tests/dbus/simple-observer.c
@@ -469,11 +469,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/simple-observer/properties", Test, NULL, setup, test_properties,
diff --git a/tests/dbus/stream-tube.c b/tests/dbus/stream-tube.c
index 534bdc42..57c2dcf4 100644
--- a/tests/dbus/stream-tube.c
+++ b/tests/dbus/stream-tube.c
@@ -1014,11 +1014,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
have_ipv6 = check_ipv6_support ();
diff --git a/tests/dbus/text-channel.c b/tests/dbus/text-channel.c
index 880de6bc..88f6e750 100644
--- a/tests/dbus/text-channel.c
+++ b/tests/dbus/text-channel.c
@@ -604,11 +604,7 @@ int
main (int argc,
char **argv)
{
- tp_tests_abort_after (10);
- g_type_init ();
- tp_debug_set_flags ("all");
-
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add ("/text-channel/creation", Test, NULL, setup,
diff --git a/tests/dtmf-player.c b/tests/dtmf-player.c
index 4574c146..3ed49faf 100644
--- a/tests/dtmf-player.c
+++ b/tests/dtmf-player.c
@@ -302,8 +302,7 @@ main (int argc,
#define FIXTURE_TEST(x) \
g_test_add (TEST_PREFIX #x, Fixture, NULL, setup, test_ ## x, teardown)
- tp_tests_abort_after (10);
- g_test_init (&argc, &argv, NULL);
+ tp_tests_init (&argc, &argv);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
g_test_add_func (TEST_PREFIX "to_char", test_to_char);
diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am
index 803d8d39..057641b0 100644
--- a/tests/lib/Makefile.am
+++ b/tests/lib/Makefile.am
@@ -19,6 +19,8 @@ libtp_glib_tests_la_SOURCES = \
echo-im-manager.h \
echo-im-manager.c \
myassert.h \
+ my-conn-proxy.h \
+ my-conn-proxy.c \
params-cm.h \
params-cm.c \
simple-account.c \
diff --git a/tests/lib/my-conn-proxy.c b/tests/lib/my-conn-proxy.c
new file mode 100644
index 00000000..e49cd27b
--- /dev/null
+++ b/tests/lib/my-conn-proxy.c
@@ -0,0 +1,333 @@
+/*
+ * my-conn-proxy.c - a simple subclass of TpConnection
+ *
+ * Copyright (C) 2010-2011 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+
+#include "my-conn-proxy.h"
+
+#include <telepathy-glib/proxy-internal.h>
+
+G_DEFINE_TYPE (TpTestsMyConnProxy, tp_tests_my_conn_proxy,
+ TP_TYPE_CONNECTION)
+
+static void
+tp_tests_my_conn_proxy_init (TpTestsMyConnProxy *self)
+{
+}
+
+enum {
+ FEAT_CORE,
+ FEAT_A,
+ FEAT_B,
+ FEAT_WRONG_IFACE,
+ FEAT_BAD_DEP,
+ FEAT_FAIL,
+ FEAT_FAIL_DEP,
+ FEAT_RETRY,
+ FEAT_RETRY_DEP,
+ FEAT_BEFORE_CONNECTED,
+ N_FEAT
+};
+
+static void
+prepare_core_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ /* superclass core features are prepared first */
+ g_assert (tp_proxy_is_prepared (proxy, TP_CONNECTION_FEATURE_CORE));
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_core_async);
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+prepare_a_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_a_async);
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+prepare_b_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_A));
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_b_async);
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+cannot_be_prepared_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+prepare_fail_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+
+ result = g_simple_async_result_new_error ((GObject *) proxy, callback,
+ user_data, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "No feature for you!");
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+prepare_retry_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TpTestsMyConnProxy *self = (TpTestsMyConnProxy *) proxy;
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_retry_async);
+
+ if (!self->retry_feature_success)
+ {
+ /* Fail the first time we try to prepare the feature */
+ g_simple_async_result_set_error (result, TP_ERRORS,
+ TP_ERROR_NOT_YET, "Nah");
+ }
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+prepare_retry_dep_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_retry_dep_async);
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+prepare_before_connected_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TpTestsMyConnProxy *self = (TpTestsMyConnProxy *) proxy;
+ GSimpleAsyncResult *result;
+
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_before_connected_async);
+
+ if (tp_connection_get_status (TP_CONNECTION (self), NULL) ==
+ TP_CONNECTION_STATUS_CONNECTED)
+ self->before_connected_state = BEFORE_CONNECTED_STATE_CONNECTED;
+ else
+ self->before_connected_state = BEFORE_CONNECTED_STATE_NOT_CONNECTED;
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static void
+prepare_before_connected_before_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ TpTestsMyConnProxy *self = (TpTestsMyConnProxy *) proxy;
+ GSimpleAsyncResult *result;
+
+ g_assert (tp_proxy_is_prepared (proxy, TP_TESTS_MY_CONN_PROXY_FEATURE_CORE));
+
+ g_assert_cmpuint (tp_connection_get_status (TP_CONNECTION (proxy), NULL), ==,
+ TP_CONNECTION_STATUS_CONNECTING);
+
+ result = g_simple_async_result_new ((GObject *) proxy, callback, user_data,
+ prepare_before_connected_before_async);
+
+ self->before_connected_state = BEFORE_CONNECTED_STATE_CONNECTED;
+
+ g_simple_async_result_complete_in_idle (result);
+ g_object_unref (result);
+}
+
+static const TpProxyFeature *
+list_features (TpProxyClass *cls G_GNUC_UNUSED)
+{
+ static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
+ static GQuark need_a[2] = {0, 0};
+ static GQuark need_channel_core[2] = {0, 0};
+ static GQuark need_wrong_iface[2] = {0, 0};
+ static GQuark need_fail[2] = {0, 0};
+ static GQuark need_retry[2] = {0, 0};
+
+ if (G_LIKELY (features[0].name != 0))
+ return features;
+
+ features[FEAT_CORE].name = TP_TESTS_MY_CONN_PROXY_FEATURE_CORE;
+ features[FEAT_CORE].core = TRUE;
+ features[FEAT_CORE].prepare_async = prepare_core_async;
+
+ features[FEAT_A].name = TP_TESTS_MY_CONN_PROXY_FEATURE_A;
+ features[FEAT_A].prepare_async = prepare_a_async;
+
+ features[FEAT_B].name = TP_TESTS_MY_CONN_PROXY_FEATURE_B;
+ features[FEAT_B].prepare_async = prepare_b_async;
+ need_a[0] = TP_TESTS_MY_CONN_PROXY_FEATURE_A;
+ features[FEAT_B].depends_on = need_a;
+
+ features[FEAT_WRONG_IFACE].name = TP_TESTS_MY_CONN_PROXY_FEATURE_WRONG_IFACE;
+ features[FEAT_WRONG_IFACE].prepare_async = cannot_be_prepared_async;
+ need_channel_core[0] = TP_CHANNEL_FEATURE_CORE;
+ features[FEAT_WRONG_IFACE].interfaces_needed = need_channel_core;
+
+ features[FEAT_BAD_DEP].name = TP_TESTS_MY_CONN_PROXY_FEATURE_BAD_DEP;
+ features[FEAT_BAD_DEP].prepare_async = cannot_be_prepared_async;
+ need_wrong_iface[0] = TP_TESTS_MY_CONN_PROXY_FEATURE_WRONG_IFACE;
+ features[FEAT_BAD_DEP].depends_on = need_wrong_iface;
+
+ features[FEAT_FAIL].name = TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL;
+ features[FEAT_FAIL].prepare_async = prepare_fail_async;
+
+ features[FEAT_FAIL_DEP].name = TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL_DEP;
+ features[FEAT_FAIL_DEP].prepare_async = cannot_be_prepared_async;
+ need_fail[0] = TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL;
+ features[FEAT_FAIL_DEP].depends_on = need_fail;
+
+ features[FEAT_RETRY].name = TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY;
+ features[FEAT_RETRY].prepare_async = prepare_retry_async;
+ features[FEAT_RETRY].can_retry = TRUE;
+
+ features[FEAT_RETRY_DEP].name = TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP;
+ need_retry[0] = TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY;
+ features[FEAT_RETRY_DEP].prepare_async = prepare_retry_dep_async;
+ features[FEAT_RETRY_DEP].depends_on = need_retry;
+
+ features[FEAT_BEFORE_CONNECTED].name =
+ TP_TESTS_MY_CONN_PROXY_FEATURE_BEFORE_CONNECTED;
+ features[FEAT_BEFORE_CONNECTED].prepare_async =
+ prepare_before_connected_async;
+ features[FEAT_BEFORE_CONNECTED].prepare_before_signalling_connected_async =
+ prepare_before_connected_before_async;
+
+ return features;
+}
+
+static void
+tp_tests_my_conn_proxy_class_init (TpTestsMyConnProxyClass *klass)
+{
+ TpProxyClass *proxy_class = (TpProxyClass *) klass;
+
+ proxy_class->list_features = list_features;
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_core (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-core");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_a (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-a");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_b (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-b");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_wrong_iface (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-wrong_iface");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_bad_dep (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-bad-dep");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_fail (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-fail");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_fail_dep (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-fail-dep");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_retry (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-retry");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_retry_dep (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-retry-dep");
+}
+
+GQuark
+tp_tests_my_conn_proxy_get_feature_quark_before_connected (void)
+{
+ return g_quark_from_static_string ("tp-my-conn-proxy-feature-before-connected");
+}
diff --git a/tests/lib/my-conn-proxy.h b/tests/lib/my-conn-proxy.h
new file mode 100644
index 00000000..cfc82160
--- /dev/null
+++ b/tests/lib/my-conn-proxy.h
@@ -0,0 +1,115 @@
+/*
+ * my-conn-proxy.h - header for a simple subclass of TpConnection
+ *
+ * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#ifndef __TP_TESTS_MY_CONN_PROXY_H__
+#define __TP_TESTS_MY_CONN_PROXY_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/telepathy-glib.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _TpTestsMyConnProxy TpTestsMyConnProxy;
+typedef struct _TpTestsMyConnProxyClass TpTestsMyConnProxyClass;
+typedef struct _TpTestsMyConnProxyPrivate TpTestsMyConnProxyPrivate;
+
+struct _TpTestsMyConnProxyClass {
+ TpConnectionClass parent_class;
+};
+
+typedef enum
+{
+ BEFORE_CONNECTED_STATE_UNPREPARED = 0,
+ BEFORE_CONNECTED_STATE_NOT_CONNECTED,
+ BEFORE_CONNECTED_STATE_CONNECTED,
+} TpTestsMyConnProxyBeforeConnectedState;
+
+
+struct _TpTestsMyConnProxy {
+ TpConnection parent;
+
+ gboolean retry_feature_success;
+ TpTestsMyConnProxyBeforeConnectedState before_connected_state;
+};
+
+GType tp_tests_my_conn_proxy_get_type (void);
+
+/* TYPE MACROS */
+#define TP_TESTS_TYPE_MY_CONN_PROXY \
+ (tp_tests_my_conn_proxy_get_type ())
+#define TP_TESTS_MY_CONN_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_MY_CONN_PROXY, \
+ TpTestsMyConnProxy))
+#define TP_TESTS_MY_CONN_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_MY_CONN_PROXY, \
+ TpTestsMyConnProxyClass))
+#define TP_TESTS_SIMPLE_IS_MY_CONN_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_MY_CONN_PROXY))
+#define TP_TESTS_SIMPLE_IS_MY_CONN_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_MY_CONN_PROXY))
+#define TP_TESTS_MY_CONN_PROXY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_MY_CONN_PROXY, \
+ TpTestsMyConnProxyClass))
+
+/* Core feature */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_CORE \
+ (tp_tests_my_conn_proxy_get_feature_quark_core ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_core (void) G_GNUC_CONST;
+
+/* No depends */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_A \
+ (tp_tests_my_conn_proxy_get_feature_quark_a ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_a (void) G_GNUC_CONST;
+
+/* Depends on A */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_B \
+ (tp_tests_my_conn_proxy_get_feature_quark_b ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_b (void) G_GNUC_CONST;
+
+/* Depends on an unimplemented iface */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_WRONG_IFACE \
+ (tp_tests_my_conn_proxy_get_feature_quark_wrong_iface ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_wrong_iface (void) G_GNUC_CONST;
+
+/* Depends on WRONG_IFACE */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_BAD_DEP \
+ (tp_tests_my_conn_proxy_get_feature_quark_bad_dep ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_bad_dep (void) G_GNUC_CONST;
+
+/* Fail during preparation */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL \
+ (tp_tests_my_conn_proxy_get_feature_quark_fail ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_fail (void) G_GNUC_CONST;
+
+/* Depends on FAIL */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_FAIL_DEP \
+ (tp_tests_my_conn_proxy_get_feature_quark_fail_dep ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_fail_dep (void) G_GNUC_CONST;
+
+/* Fail at first attempt but succeed after */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY \
+ (tp_tests_my_conn_proxy_get_feature_quark_retry ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_retry (void) G_GNUC_CONST;
+
+/* Depends on FEATURE_RETRY */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_RETRY_DEP \
+ (tp_tests_my_conn_proxy_get_feature_quark_retry_dep ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_retry_dep (void) G_GNUC_CONST;
+
+/* Can be prepared before the connection is connected and block announcing the
+ * connected state */
+#define TP_TESTS_MY_CONN_PROXY_FEATURE_BEFORE_CONNECTED \
+ (tp_tests_my_conn_proxy_get_feature_quark_before_connected ())
+GQuark tp_tests_my_conn_proxy_get_feature_quark_before_connected (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* #ifndef __TP_TESTS_MY_CONN_PROXY_H__ */
diff --git a/tests/lib/util.c b/tests/lib/util.c
index 27b4c1e5..fc2ecdb0 100644
--- a/tests/lib/util.c
+++ b/tests/lib/util.c
@@ -289,3 +289,14 @@ tp_tests_abort_after (guint sec)
alarm (sec + 2);
#endif
}
+
+void
+tp_tests_init (int *argc,
+ char ***argv)
+{
+ g_type_init ();
+ tp_tests_abort_after (10);
+ tp_debug_set_flags ("all");
+
+ g_test_init (argc, argv, NULL);
+}
diff --git a/tests/lib/util.h b/tests/lib/util.h
index 7eab77dc..689cf91f 100644
--- a/tests/lib/util.h
+++ b/tests/lib/util.h
@@ -54,4 +54,7 @@ void tp_tests_result_ready_cb (GObject *object,
void tp_tests_abort_after (guint sec);
+void tp_tests_init (int *argc,
+ char ***argv);
+
#endif /* #ifndef __TP_TESTS_LIB_UTIL_H__ */