summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2013-10-30 15:12:46 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2013-10-30 15:12:46 +0000
commitc91f7e307c10a9c5851cff468065d75251ffd7dc (patch)
tree4644cde796566e13d06affa9c9f4c50fb2f18a78
parent1d0df665f77ed683f8b1fe1e769801716227f054 (diff)
-rw-r--r--docs/reference/telepathy-glib-sections.txt2
-rw-r--r--telepathy-glib/base-connection.c9
-rw-r--r--telepathy-glib/base-connection.h70
-rw-r--r--telepathy-glib/connection-manager.c126
-rw-r--r--telepathy-glib/connection-manager.h15
-rw-r--r--tests/dbus/cm.c48
-rw-r--r--tests/python/cm.py60
7 files changed, 328 insertions, 2 deletions
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index fb518c587..908ec02d9 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -4842,6 +4842,8 @@ tp_connection_manager_dup_protocol_names
tp_connection_manager_has_protocol
tp_connection_manager_get_protocol
tp_connection_manager_get_protocol_object
+tp_connection_manager_request_connection_async
+tp_connection_manager_request_connection_finish
TpConnectionManagerProtocol
tp_connection_manager_protocol_can_register
tp_connection_manager_protocol_dup_param_names
diff --git a/telepathy-glib/base-connection.c b/telepathy-glib/base-connection.c
index c44027951..5b418295c 100644
--- a/telepathy-glib/base-connection.c
+++ b/telepathy-glib/base-connection.c
@@ -122,6 +122,15 @@
*/
/**
+ * TpBaseConnectionClass::get_unique_connection_name:
+ * @self: The implementation, a subclass of TpBaseConnection
+ *
+ * Returns: (transfer full): a name for this connection which will be unique
+ * within this connection manager process, as a string which the caller must
+ * free with #g_free.
+ */
+
+/**
* TpBaseConnectionGetInterfacesImpl:
* @self: a #TpBaseConnection
*
diff --git a/telepathy-glib/base-connection.h b/telepathy-glib/base-connection.h
index 264f64213..1e35553aa 100644
--- a/telepathy-glib/base-connection.h
+++ b/telepathy-glib/base-connection.h
@@ -241,6 +241,76 @@ void tp_base_connection_add_client_interest (TpBaseConnection *self,
void tp_base_connection_add_possible_client_interest (TpBaseConnection *self,
GQuark token);
+/* ---- Implemented by subclasses to work around gobject-introspection ---- */
+
+#define TP_TYPE_INTROSPECTABLE_BASE_CONNECTION \
+ (tp_introspectable_base_connection_get_type ())
+
+#define TP_INTROSPECTABLE_BASE_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ TP_TYPE_INTROSPECTABLE_BASE_CONNECTION, TpIntrospectableBaseConnection))
+
+#define TP_IS_INTROSPECTABLE_BASE_CONNECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ TP_TYPE_INTROSPECTABLE_BASE_CONNECTION))
+
+#define TP_INTROSPECTABLE_BASE_CONNECTION_GET_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((obj), \
+ TP_TYPE_INTROSPECTABLE_BASE_CONNECTION, \
+ TpIntrospectableBaseConnectionInterface))
+
+_TP_AVAILABLE_IN_UNRELEASED
+GType tp_introspectable_base_connection_get_type (void);
+
+typedef struct _TpIntrospectableBaseConnection TpIntrospectableBaseConnection;
+typedef struct _TpIntrospectableBaseConnectionInterface
+ TpIntrospectableBaseConnectionInterface;
+
+struct _TpIntrospectableBaseConnectionInterface
+{
+ GTypeInterface parent;
+
+ gchar *(*introspectable_normalize_contact) (
+ TpIntrospectableBaseConnection *self,
+ const gchar *id,
+ gpointer context,
+ guint *domain,
+ gint *code,
+ gchar **message);
+ void (*introspectable_normalize_contact_async) (
+ TpIntrospectableBaseConnection *self,
+ const gchar *id,
+ gpointer context,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gchar *(*introspectable_normalize_contact_finish) (
+ TpIntrospectableBaseConnection *self,
+ GAsyncResult *result,
+ guint *domain,
+ gint *code,
+ gchar **message);
+
+ gchar *(*introspectable_normalize_room) (
+ TpIntrospectableBaseConnection *self,
+ const gchar *id,
+ gpointer context,
+ guint *domain,
+ gint *code,
+ gchar **message);
+ void (*introspectable_normalize_room_async) (
+ TpIntrospectableBaseConnection *self,
+ const gchar *id,
+ gpointer context,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gchar *(*introspectable_normalize_room_finish) (
+ TpIntrospectableBaseConnection *self,
+ GAsyncResult *result,
+ guint *domain,
+ gint *code,
+ gchar **message);
+};
+
G_END_DECLS
#endif /* #ifndef __TP_BASE_CONNECTION_H__*/
diff --git a/telepathy-glib/connection-manager.c b/telepathy-glib/connection-manager.c
index 2dd1c4ec8..1e49da581 100644
--- a/telepathy-glib/connection-manager.c
+++ b/telepathy-glib/connection-manager.c
@@ -32,12 +32,14 @@
#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/proxy-internal.h>
#include <telepathy-glib/proxy-subclass.h>
+#include "telepathy-glib/simple-client-factory.h"
#include "telepathy-glib/util.h"
#define DEBUG_FLAG TP_DEBUG_MANAGER
#include "telepathy-glib/debug-internal.h"
#include "telepathy-glib/protocol-internal.h"
#include "telepathy-glib/util-internal.h"
+#include "telepathy-glib/variant-util-internal.h"
#include "telepathy-glib/_gen/tp-cli-connection-manager-body.h"
@@ -2692,3 +2694,127 @@ tp_connection_manager_param_dup_default_variant (
return g_variant_ref_sink (dbus_g_value_build_g_variant (
&param->default_value));
}
+
+static void
+tp_connection_manager_request_connection_cb (TpConnectionManager *self,
+ const gchar *bus_name,
+ const gchar *object_path,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object G_GNUC_UNUSED)
+{
+ if (error == NULL)
+ {
+ TpSimpleClientFactory *factory;
+ TpConnection *conn;
+ GError *error2 = NULL;
+
+ factory = g_task_get_task_data (user_data);
+ conn = tp_simple_client_factory_ensure_connection (factory,
+ object_path, NULL, &error2);
+
+ if (G_UNLIKELY (conn == NULL))
+ {
+ g_task_return_error (user_data, error2);
+ return;
+ }
+
+ if (g_task_return_error_if_cancelled (user_data))
+ {
+ tp_connection_disconnect_async (conn, NULL, NULL);
+ g_object_unref (conn);
+ }
+ else
+ {
+ g_task_return_pointer (user_data, conn, g_object_unref);
+ }
+ }
+ else
+ {
+ g_task_return_error (user_data, g_error_copy (error));
+ }
+}
+
+/**
+ * tp_connection_manager_request_connection_async:
+ * @self: a connection manager
+ * @client_factory: a client factory to manufacture the #TpConnection
+ * @protocol_name: the short name of a protocol
+ * @vardict: the account parameters as a #GVariant of
+ * type %G_VARIANT_TYPE_VARDICT. If it is floating, ownership will
+ * be taken, as if via g_variant_ref_sink().
+ * @cancellable: (allow-none): may be used to cancel the async request
+ * @callback: (scope async): a callback to call when
+ * the request is satisfied
+ * @user_data: (closure) (allow-none): data to pass to @callback
+ *
+ * Return a new, unconnected connection to @protocol.
+ * tp_connection_connect_async() can be used connect it.
+ *
+ * This is a low-level function. Applications other than the
+ * Account Manager should normally operate by finding or creating a
+ * #TpAccount on the #TpAccountManager, connecting it
+ * using tp_account_request_presence_async() or
+ * using tp_account_manager_set_all_requested_presences(),
+ * and obtaining the #TpConnection (if required) with
+ * tp_account_get_connection().
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_connection_manager_request_connection_async (TpConnectionManager *self,
+ TpSimpleClientFactory *client_factory,
+ const gchar *protocol_name,
+ GVariant *vardict,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ GHashTable *asv;
+
+ g_return_if_fail (TP_IS_CONNECTION_MANAGER (self));
+ g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (client_factory));
+ g_return_if_fail (tp_connection_manager_check_valid_protocol_name (
+ protocol_name, NULL));
+ g_return_if_fail (vardict != NULL);
+ g_return_if_fail (g_variant_is_of_type (vardict, G_VARIANT_TYPE_VARDICT));
+ /* this makes no sense to call for its side-effects: you'll need to
+ * do something with the connection */
+ g_return_if_fail (callback != NULL);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, tp_connection_manager_request_connection_async);
+ g_task_set_task_data (task, g_object_ref (client_factory), g_object_unref);
+
+ g_variant_ref_sink (vardict);
+ asv = _tp_asv_from_vardict (vardict);
+ tp_cli_connection_manager_call_request_connection (self, -1,
+ protocol_name, asv,
+ tp_connection_manager_request_connection_cb, task, g_object_unref, NULL);
+ g_hash_table_unref (asv);
+ g_variant_unref (vardict);
+}
+
+/**
+ * tp_connection_manager_request_connection_finish:
+ * @self: a connection manager
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Interpret the result of tp_connection_manager_request_connection_async().
+ *
+ * Returns: (transfer full): the #TpConnection, or %NULL on error
+ * Since: 0.UNRELEASED
+ */
+TpConnection *
+tp_connection_manager_request_connection_finish (TpConnectionManager *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result,
+ tp_connection_manager_request_connection_async), NULL);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
diff --git a/telepathy-glib/connection-manager.h b/telepathy-glib/connection-manager.h
index ac89341c3..cba2aab67 100644
--- a/telepathy-glib/connection-manager.h
+++ b/telepathy-glib/connection-manager.h
@@ -224,6 +224,21 @@ _TP_DEPRECATED_IN_0_20
void tp_connection_manager_protocol_free (TpConnectionManagerProtocol *proto);
#endif
+_TP_AVAILABLE_IN_UNRELEASED
+void tp_connection_manager_request_connection_async (TpConnectionManager *self,
+ TpSimpleClientFactory *client_factory,
+ const gchar *protocol_name,
+ GVariant *vardict,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+_TP_AVAILABLE_IN_UNRELEASED G_GNUC_WARN_UNUSED_RESULT
+TpConnection *tp_connection_manager_request_connection_finish (
+ TpConnectionManager *self,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#include <telepathy-glib/_gen/tp-cli-connection-manager.h>
diff --git a/tests/dbus/cm.c b/tests/dbus/cm.c
index 3888277d2..fff255d62 100644
--- a/tests/dbus/cm.c
+++ b/tests/dbus/cm.c
@@ -1121,6 +1121,51 @@ test_list (Test *test,
g_assert (tp_connection_manager_has_protocol (test->spurious, "normal"));
}
+static void
+test_request_connection (Test *test,
+ gconstpointer data)
+{
+ TpSimpleClientFactory *factory;
+ GAsyncResult *res = NULL;
+ TpConnection *conn;
+
+ factory = tp_simple_client_factory_new (test->dbus);
+ g_assert (TP_IS_SIMPLE_CLIENT_FACTORY (factory));
+
+ test->error = NULL;
+ test->cm = tp_connection_manager_new (test->dbus,
+ TP_BASE_CONNECTION_MANAGER_GET_CLASS (test->service_cm)->cm_dbus_name,
+ NULL, &test->error);
+ g_assert (TP_IS_CONNECTION_MANAGER (test->cm));
+ g_assert_no_error (test->error);
+
+ tp_connection_manager_request_connection_async (test->cm,
+ factory, "foo", g_variant_new_parsed ("@a{sv} {}"),
+ NULL, tp_tests_result_ready_cb, &res);
+ tp_tests_run_until_result (&res);
+ conn = tp_connection_manager_request_connection_finish (test->cm,
+ res, &test->error);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED);
+ g_assert (conn == NULL);
+ g_clear_error (&test->error);
+ g_clear_object (&res);
+
+ tp_connection_manager_request_connection_async (test->cm,
+ factory, "example", g_variant_new_parsed ("{'account': <'herobrine'>}"),
+ NULL, tp_tests_result_ready_cb, &res);
+ tp_tests_run_until_result (&res);
+ conn = tp_connection_manager_request_connection_finish (test->cm,
+ res, &test->error);
+ g_assert_no_error (test->error);
+ g_assert (conn != NULL);
+ g_clear_object (&res);
+
+ tp_tests_connection_assert_disconnect_succeeds (conn);
+ g_clear_object (&conn);
+
+ g_object_unref (factory);
+}
+
int
main (int argc,
char **argv)
@@ -1191,5 +1236,8 @@ main (int argc,
g_test_add ("/cm/list", Test, GINT_TO_POINTER (USE_OLD_LIST),
setup, test_list, teardown);
+ g_test_add ("/cm/request-connection", Test, GINT_TO_POINTER (0), setup,
+ test_request_connection, teardown);
+
return tp_tests_run_with_bus ();
}
diff --git a/tests/python/cm.py b/tests/python/cm.py
index f9e09dfae..6a33e83f0 100644
--- a/tests/python/cm.py
+++ b/tests/python/cm.py
@@ -23,6 +23,44 @@ import unittest
from gi.repository import GLib
from gi.repository import TelepathyGLib as Tp
+class ExampleConnection(Tp.BaseConnection):
+ def do_create_channel_managers(self):
+ return []
+
+ def do_get_interfaces_always_present(self):
+ return Tp.BaseConnection.do_get_interfaces_always_present(self)
+
+ def do_get_unique_connection_name(self):
+ return Tp.BaseConnection.do_get_unique_connection_name(self)
+
+ def do_connecting(self):
+ print("connecting")
+
+ def do_connected(self):
+ print("connected")
+
+ def do_disconnected(self):
+ print("disconnected")
+
+ def _idle_shut_down_cb(self):
+ self.finish_shutdown()
+ return False
+
+ def do_shut_down(self):
+ GLib.idle_add(self._idle_shut_down_cb)
+
+ def _idle_fail_to_connect_cb(self):
+ self.disconnect_with_dbus_error_vardict(
+ "im.telepathy.JustAnExample.NotActuallyImplemented",
+ None, Tp.ConnectionStatusReason.NETWORK_ERROR)
+ return False
+
+ def do_start_connecting(self):
+ # Implementations of this method in Python must return True
+ # due to GNOME bug #710671
+ GLib.idle_add(self._idle_fail_to_connect_cb)
+ return True
+
class ExampleProtocol(Tp.BaseProtocol,
Tp.IntrospectableBaseProtocol,
Tp.ProtocolAddressing):
@@ -195,6 +233,7 @@ class TestIntrospectedCM(unittest.TestCase):
self.cm = None
self.dbus_daemon = Tp.DBusDaemon.dup()
+ self.factory = Tp.SimpleClientFactory.new(self.dbus_daemon)
cm_client = None
@@ -419,8 +458,25 @@ class TestIntrospectedCM(unittest.TestCase):
protocol.identify_account_finish(waiter.result)
self.assertEqual(trap.exception.code, Tp.Error.INVALID_ARGUMENT)
- # FIXME: test CM.NewConnection (there's no medium-level API,
- # and the high-level API needs an AccountManager)
+ waiter = Waiter()
+ cm_client.request_connection_async(self.factory, 'foo',
+ GLib.Variant('a{sv}', {
+ }), None, waiter.callback, waiter)
+ waiter.wait()
+ with self.assertRaises(GLib.GError) as trap:
+ cm_client.request_connection_finish(waiter.result)
+ self.assertEqual(trap.exception.code, Tp.Error.NOT_IMPLEMENTED)
+
+ waiter = Waiter()
+ cm_client.request_connection_async(self.factory, 'example',
+ GLib.Variant('a{sv}', {
+ 'account': GLib.Variant('s', ''),
+ 'foo': GLib.Variant('u', 42),
+ }), None, waiter.callback, waiter)
+ waiter.wait()
+ with self.assertRaises(GLib.GError) as trap:
+ cm_client.request_connection_finish(waiter.result)
+ self.assertEqual(trap.exception.code, Tp.Error.INVALID_ARGUMENT)
def tearDown(self):
if self.cm is not None: