summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/Makefile.am1
-rw-r--r--docs/reference/telepathy-glib-docs.sgml1
-rw-r--r--docs/reference/telepathy-glib-sections.txt35
-rw-r--r--telepathy-glib/Makefile.am3
-rw-r--r--telepathy-glib/account-manager.c9
-rw-r--r--telepathy-glib/account.c11
-rw-r--r--telepathy-glib/channel-dispatch-operation.c13
-rw-r--r--telepathy-glib/channel-request.c24
-rw-r--r--telepathy-glib/channel.c13
-rw-r--r--telepathy-glib/connection.c13
-rw-r--r--telepathy-glib/introspection.am1
-rw-r--r--telepathy-glib/proxy.c45
-rw-r--r--telepathy-glib/proxy.h4
-rw-r--r--telepathy-glib/simple-client-factory-internal.h82
-rw-r--r--telepathy-glib/simple-client-factory.c1031
-rw-r--r--telepathy-glib/simple-client-factory.h174
-rw-r--r--telepathy-glib/telepathy-glib.h1
17 files changed, 1461 insertions, 0 deletions
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 5631bf684..4180c1e79 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -84,6 +84,7 @@ IGNORE_HFILES=\
proxy-internal.h \
proxy-introspectable.h \
signalled-message-internal.h \
+ simple-client-factory-internal.h \
util-internal.h
# Images to copy into HTML directory.
diff --git a/docs/reference/telepathy-glib-docs.sgml b/docs/reference/telepathy-glib-docs.sgml
index dd7621064..006e11c45 100644
--- a/docs/reference/telepathy-glib-docs.sgml
+++ b/docs/reference/telepathy-glib-docs.sgml
@@ -81,6 +81,7 @@
<xi:include href="xml/client-channel-factory.xml"/>
<xi:include href="xml/basic-proxy-factory.xml"/>
<xi:include href="xml/automatic-proxy-factory.xml"/>
+ <xi:include href="xml/simple-client-factory.xml"/>
<xi:include href="xml/client-message.xml"/>
<xi:include href="xml/signalled-message.xml"/>
<xi:include href="xml/text-channel.xml"/>
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 7e2d85c9c..3f4e698bd 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -2958,6 +2958,7 @@ TpProxyPendingCall
tp_proxy_pending_call_cancel
TpProxySignalConnection
tp_proxy_signal_connection_disconnect
+tp_proxy_get_factory
tp_proxy_get_dbus_daemon
tp_proxy_get_dbus_connection
tp_proxy_get_bus_name
@@ -5716,3 +5717,37 @@ TP_TYPE_FILE_TRANSFER_CHANNEL
TpFileTransferChannelPrivate
tp_file_transfer_channel_get_feature_quark_core
</SECTION>
+
+<SECTION>
+<FILE>simple-client-factory</FILE>
+<TITLE>simple-client-factory</TITLE>
+<INCLUDE>telepathy-glib/telepathy-glib.h</INCLUDE>
+TpSimpleClientFactory
+TpSimpleClientFactoryClass
+tp_simple_client_factory_new
+tp_simple_client_factory_get_dbus_daemon
+tp_simple_client_factory_ensure_account_manager
+tp_simple_client_factory_dup_account_manager_features
+tp_simple_client_factory_add_account_manager_features
+tp_simple_client_factory_ensure_account
+tp_simple_client_factory_dup_account_features
+tp_simple_client_factory_add_account_features
+tp_simple_client_factory_ensure_connection
+tp_simple_client_factory_dup_connection_features
+tp_simple_client_factory_add_connection_features
+tp_simple_client_factory_ensure_channel
+tp_simple_client_factory_dup_channel_features
+tp_simple_client_factory_add_channel_features
+tp_simple_client_factory_ensure_contact
+tp_simple_client_factory_dup_contact_features
+tp_simple_client_factory_add_contact_features
+<SUBSECTION Standard>
+TP_IS_SIMPLE_CLIENT_FACTORY
+TP_IS_SIMPLE_CLIENT_FACTORY_CLASS
+TP_SIMPLE_CLIENT_FACTORY
+TP_SIMPLE_CLIENT_FACTORY_CLASS
+TP_SIMPLE_CLIENT_FACTORY_GET_CLASS
+TP_TYPE_SIMPLE_CLIENT_FACTORY
+tp_simple_client_factory_get_type
+TpSimpleClientFactoryPrivate
+</SECTION>
diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am
index b63f03f83..da1309da7 100644
--- a/telepathy-glib/Makefile.am
+++ b/telepathy-glib/Makefile.am
@@ -91,6 +91,7 @@ our_headers = \
run.h \
signalled-message.h \
simple-approver.h \
+ simple-client-factory.h \
simple-handler.h \
simple-observer.h \
simple-password-manager.h \
@@ -239,6 +240,8 @@ libtelepathy_glib_internal_la_SOURCES = \
signalled-message.c \
signalled-message-internal.h \
simple-approver.c \
+ simple-client-factory.c \
+ simple-client-factory-internal.h \
simple-handler.c \
simple-observer.c \
simple-password-manager.c \
diff --git a/telepathy-glib/account-manager.c b/telepathy-glib/account-manager.c
index 1e3802f05..458da97c2 100644
--- a/telepathy-glib/account-manager.c
+++ b/telepathy-glib/account-manager.c
@@ -35,6 +35,7 @@
#define DEBUG_FLAG TP_DEBUG_ACCOUNTS
#include "telepathy-glib/debug-internal.h"
#include "telepathy-glib/proxy-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
#include "telepathy-glib/_gen/tp-cli-account-manager-body.h"
@@ -681,6 +682,13 @@ tp_account_manager_init_known_interfaces (void)
TpAccountManager *
tp_account_manager_new (TpDBusDaemon *bus_daemon)
{
+ return _tp_account_manager_new_with_factory (NULL, bus_daemon);
+}
+
+TpAccountManager *
+_tp_account_manager_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon)
+{
TpAccountManager *self;
g_return_val_if_fail (TP_IS_DBUS_DAEMON (bus_daemon), NULL);
@@ -690,6 +698,7 @@ tp_account_manager_new (TpDBusDaemon *bus_daemon)
"dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
"bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
"object-path", TP_ACCOUNT_MANAGER_OBJECT_PATH,
+ "factory", factory,
NULL));
return self;
diff --git a/telepathy-glib/account.c b/telepathy-glib/account.c
index b097e1ebc..275dfd2c8 100644
--- a/telepathy-glib/account.c
+++ b/telepathy-glib/account.c
@@ -36,6 +36,7 @@
#include "telepathy-glib/connection-internal.h"
#include "telepathy-glib/debug-internal.h"
#include "telepathy-glib/proxy-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
#include <telepathy-glib/util-internal.h>
#include "telepathy-glib/_gen/signals-marshal.h"
@@ -1838,6 +1839,15 @@ tp_account_new (TpDBusDaemon *bus_daemon,
const gchar *object_path,
GError **error)
{
+ return _tp_account_new_with_factory (NULL, bus_daemon, object_path, error);
+}
+
+TpAccount *
+_tp_account_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon,
+ const gchar *object_path,
+ GError **error)
+{
TpAccount *self;
g_return_val_if_fail (TP_IS_DBUS_DAEMON (bus_daemon), NULL);
@@ -1852,6 +1862,7 @@ tp_account_new (TpDBusDaemon *bus_daemon,
"dbus-connection", ((TpProxy *) bus_daemon)->dbus_connection,
"bus-name", TP_ACCOUNT_MANAGER_BUS_NAME,
"object-path", object_path,
+ "factory", factory,
NULL));
return self;
diff --git a/telepathy-glib/channel-dispatch-operation.c b/telepathy-glib/channel-dispatch-operation.c
index 8ccb65260..1c560a5e0 100644
--- a/telepathy-glib/channel-dispatch-operation.c
+++ b/telepathy-glib/channel-dispatch-operation.c
@@ -36,6 +36,7 @@
#define DEBUG_FLAG TP_DEBUG_DISPATCHER
#include "telepathy-glib/dbus-internal.h"
#include "telepathy-glib/debug-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
#include "telepathy-glib/_gen/signals-marshal.h"
#include "telepathy-glib/_gen/tp-cli-channel-dispatch-operation-body.h"
@@ -912,6 +913,17 @@ tp_channel_dispatch_operation_new (TpDBusDaemon *bus_daemon,
GHashTable *immutable_properties,
GError **error)
{
+ return _tp_channel_dispatch_operation_new_with_factory (NULL, bus_daemon,
+ object_path, immutable_properties, error);
+}
+
+TpChannelDispatchOperation *
+_tp_channel_dispatch_operation_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error)
+{
TpChannelDispatchOperation *self;
gchar *unique_name;
@@ -932,6 +944,7 @@ tp_channel_dispatch_operation_new (TpDBusDaemon *bus_daemon,
"bus-name", unique_name,
"object-path", object_path,
"cdo-properties", immutable_properties,
+ "factory", factory,
NULL));
g_free (unique_name);
diff --git a/telepathy-glib/channel-request.c b/telepathy-glib/channel-request.c
index 693b22100..99b44af5e 100644
--- a/telepathy-glib/channel-request.c
+++ b/telepathy-glib/channel-request.c
@@ -35,6 +35,7 @@
#define DEBUG_FLAG TP_DEBUG_DISPATCHER
#include "telepathy-glib/dbus-internal.h"
#include "telepathy-glib/debug-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
#include "telepathy-glib/_gen/tp-cli-channel-request-body.h"
@@ -573,6 +574,17 @@ tp_channel_request_new (TpDBusDaemon *bus_daemon,
GHashTable *immutable_properties,
GError **error)
{
+ return _tp_channel_request_new_with_factory (NULL, bus_daemon, object_path,
+ immutable_properties, error);
+}
+
+TpChannelRequest *
+_tp_channel_request_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error)
+{
TpChannelRequest *self;
gchar *unique_name;
@@ -593,6 +605,7 @@ tp_channel_request_new (TpDBusDaemon *bus_daemon,
"bus-name", unique_name,
"object-path", object_path,
"immutable-properties", immutable_properties,
+ "factory", factory,
NULL));
g_free (unique_name);
@@ -638,6 +651,17 @@ tp_channel_request_get_immutable_properties (TpChannelRequest *self)
return self->priv->immutable_properties;
}
+void
+_tp_channel_request_ensure_immutable_properties (TpChannelRequest *self,
+ GHashTable *immutable_properties)
+{
+ if (self->priv->immutable_properties == NULL && immutable_properties != NULL)
+ {
+ self->priv->immutable_properties = g_hash_table_ref (immutable_properties);
+ g_object_notify ((GObject *) self, "immutable-properties");
+ }
+}
+
/**
* tp_channel_request_get_account:
* @self: a #tpchannelrequest
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c
index a42cd45ba..011456c7b 100644
--- a/telepathy-glib/channel.c
+++ b/telepathy-glib/channel.c
@@ -32,6 +32,7 @@
#define DEBUG_FLAG TP_DEBUG_CHANNEL
#include "telepathy-glib/debug-internal.h"
#include "telepathy-glib/proxy-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
#include "telepathy-glib/_gen/signals-marshal.h"
#include "_gen/tp-cli-channel-body.h"
@@ -1787,6 +1788,17 @@ tp_channel_new_from_properties (TpConnection *conn,
const GHashTable *immutable_properties,
GError **error)
{
+ return _tp_channel_new_with_factory (NULL, conn, object_path,
+ immutable_properties, error);
+}
+
+TpChannel *
+_tp_channel_new_with_factory (TpSimpleClientFactory *factory,
+ TpConnection *conn,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error)
+{
TpProxy *conn_proxy = (TpProxy *) conn;
TpChannel *ret = NULL;
@@ -1809,6 +1821,7 @@ tp_channel_new_from_properties (TpConnection *conn,
"object-path", object_path,
"handle-type", (guint) TP_UNKNOWN_HANDLE_TYPE,
"channel-properties", immutable_properties,
+ "factory", factory,
NULL));
finally:
diff --git a/telepathy-glib/connection.c b/telepathy-glib/connection.c
index dd49ed344..b11ddcb11 100644
--- a/telepathy-glib/connection.c
+++ b/telepathy-glib/connection.c
@@ -42,6 +42,7 @@
#include "telepathy-glib/dbus-internal.h"
#include "telepathy-glib/debug-internal.h"
#include "telepathy-glib/proxy-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
#include "telepathy-glib/util-internal.h"
#include "telepathy-glib/_gen/signals-marshal.h"
@@ -1786,6 +1787,17 @@ tp_connection_new (TpDBusDaemon *dbus,
const gchar *object_path,
GError **error)
{
+ return _tp_connection_new_with_factory (NULL, dbus, bus_name, object_path,
+ error);
+}
+
+TpConnection *
+_tp_connection_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *dbus,
+ const gchar *bus_name,
+ const gchar *object_path,
+ GError **error)
+{
gchar *dup_path = NULL;
gchar *dup_name = NULL;
gchar *dup_unique_name = NULL;
@@ -1831,6 +1843,7 @@ tp_connection_new (TpDBusDaemon *dbus,
"dbus-daemon", dbus,
"bus-name", bus_name,
"object-path", object_path,
+ "factory", factory,
NULL));
finally:
diff --git a/telepathy-glib/introspection.am b/telepathy-glib/introspection.am
index 4dc6d9e46..de9bbcc94 100644
--- a/telepathy-glib/introspection.am
+++ b/telepathy-glib/introspection.am
@@ -38,6 +38,7 @@ INTROSPECTION_FILES = \
$(srcdir)/debug.c $(srcdir)/debug.h \
$(srcdir)/base-client.c $(srcdir)/base-client.h \
$(srcdir)/simple-approver.c $(srcdir)/simple-approver.h \
+ $(srcdir)/simple-client-factory.c $(srcdir)/simple-client-factory.h \
$(srcdir)/simple-handler.c $(srcdir)/simple-handler.h \
$(srcdir)/simple-observer.c $(srcdir)/simple-observer.h \
$(srcdir)/dbus-properties-mixin.c $(srcdir)/dbus-properties-mixin.h \
diff --git a/telepathy-glib/proxy.c b/telepathy-glib/proxy.c
index b64e9190d..f4e648a34 100644
--- a/telepathy-glib/proxy.c
+++ b/telepathy-glib/proxy.c
@@ -386,6 +386,8 @@ struct _TpProxyPrivate {
guint pending_will_announce_calls;
gboolean dispose_has_run;
+
+ TpSimpleClientFactory *factory;
};
G_DEFINE_TYPE (TpProxy, tp_proxy, G_TYPE_OBJECT)
@@ -397,6 +399,7 @@ enum
PROP_BUS_NAME,
PROP_OBJECT_PATH,
PROP_INTERFACES,
+ PROP_FACTORY,
N_PROPS
};
@@ -876,6 +879,9 @@ tp_proxy_get_property (GObject *object,
g_value_take_boxed (value, g_ptr_array_free (strings, FALSE));
}
break;
+ case PROP_FACTORY:
+ g_value_set_object (value, self->priv->factory);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -941,6 +947,10 @@ tp_proxy_set_property (GObject *object,
g_assert (self->object_path == NULL);
self->object_path = g_value_dup_string (value);
break;
+ case PROP_FACTORY:
+ g_assert (self->priv->factory == NULL);
+ self->priv->factory = g_value_dup_object (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -1119,6 +1129,7 @@ tp_proxy_dispose (GObject *object)
tp_proxy_invalidate (self, &e);
tp_clear_object (&self->dbus_daemon);
+ tp_clear_object (&self->priv->factory);
G_OBJECT_CLASS (tp_proxy_parent_class)->dispose (object);
}
@@ -1324,6 +1335,20 @@ tp_proxy_class_init (TpProxyClass *klass)
param_spec);
/**
+ * TpProxy:factory:
+ *
+ * The #TpSimpleClientFactory that has been used to create this proxy,
+ * or %NULL if proxy was not created through a factory.
+ */
+ param_spec = g_param_spec_object ("factory", "Simple Client Factory",
+ "The TpSimpleClientFactory used to create this proxy",
+ TP_TYPE_SIMPLE_CLIENT_FACTORY,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
+ g_object_class_install_property (object_class, PROP_FACTORY,
+ param_spec);
+
+ /**
* TpProxy::interface-added: (skip)
* @self: the proxy object
* @id: the GQuark representing the interface
@@ -1366,6 +1391,26 @@ tp_proxy_class_init (TpProxyClass *klass)
}
/**
+ * tp_proxy_get_factory:
+ * @self: a #TpProxy or subclass
+ *
+ * <!-- -->
+ *
+ * Returns: (transfer none): the same value as #TpProxy:factory property
+ *
+ * Since: 0.UNRELEASED
+ */
+TpSimpleClientFactory *
+tp_proxy_get_factory (gpointer self)
+{
+ TpProxy *proxy = self;
+
+ g_return_val_if_fail (TP_IS_PROXY (self), NULL);
+
+ return proxy->priv->factory;
+}
+
+/**
* tp_proxy_get_dbus_daemon:
* @self: a #TpProxy or subclass
*
diff --git a/telepathy-glib/proxy.h b/telepathy-glib/proxy.h
index 8b0cdfb3f..c170c4a86 100644
--- a/telepathy-glib/proxy.h
+++ b/telepathy-glib/proxy.h
@@ -32,6 +32,8 @@ G_BEGIN_DECLS
/* Forward declaration of a subclass - from dbus.h */
typedef struct _TpDBusDaemon TpDBusDaemon;
+/* Forward declaration - from simple-client-factory.h */
+typedef struct _TpSimpleClientFactory TpSimpleClientFactory;
typedef struct _TpProxyPrivate TpProxyPrivate;
@@ -154,6 +156,8 @@ GType tp_proxy_get_type (void);
gboolean tp_proxy_has_interface_by_id (gpointer self, GQuark iface);
gboolean tp_proxy_has_interface (gpointer self, const gchar *iface);
+TpSimpleClientFactory *tp_proxy_get_factory (gpointer self);
+
TpDBusDaemon *tp_proxy_get_dbus_daemon (gpointer self);
DBusGConnection *tp_proxy_get_dbus_connection (gpointer self);
diff --git a/telepathy-glib/simple-client-factory-internal.h b/telepathy-glib/simple-client-factory-internal.h
new file mode 100644
index 000000000..8facf8940
--- /dev/null
+++ b/telepathy-glib/simple-client-factory-internal.h
@@ -0,0 +1,82 @@
+/*
+ * Simple client factory internal
+ *
+ * Copyright © 2011 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TP_SIMPLE_CLIENT_FACTORY_INTERNAL_H__
+#define __TP_SIMPLE_CLIENT_FACTORY_INTERNAL_H__
+
+#include <telepathy-glib/simple-client-factory.h>
+
+G_BEGIN_DECLS
+
+void _tp_simple_client_factory_insert_proxy (TpSimpleClientFactory *self,
+ gpointer proxy);
+
+TpChannelRequest *_tp_simple_client_factory_ensure_channel_request (
+ TpSimpleClientFactory *self,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error);
+
+TpChannelDispatchOperation *
+_tp_simple_client_factory_ensure_channel_dispatch_operation (
+ TpSimpleClientFactory *self,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error);
+
+TpAccountManager *_tp_account_manager_new_with_factory (
+ TpSimpleClientFactory *factory, TpDBusDaemon *bus_daemon);
+
+TpAccount *_tp_account_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon,
+ const gchar *object_path,
+ GError **error);
+
+TpConnection *_tp_connection_new_with_factory (TpSimpleClientFactory *factory,
+ TpDBusDaemon *dbus,
+ const gchar *bus_name,
+ const gchar *object_path,
+ GError **error);
+
+TpChannel *_tp_channel_new_with_factory (TpSimpleClientFactory *factory,
+ TpConnection *conn,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+
+TpChannelRequest *_tp_channel_request_new_with_factory (
+ TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error);
+void _tp_channel_request_ensure_immutable_properties (TpChannelRequest *self,
+ GHashTable *immutable_properties);
+
+TpChannelDispatchOperation *_tp_channel_dispatch_operation_new_with_factory (
+ TpSimpleClientFactory *factory,
+ TpDBusDaemon *bus_daemon,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error);
+
+G_END_DECLS
+
+#endif
diff --git a/telepathy-glib/simple-client-factory.c b/telepathy-glib/simple-client-factory.c
new file mode 100644
index 000000000..4bf6b1eab
--- /dev/null
+++ b/telepathy-glib/simple-client-factory.c
@@ -0,0 +1,1031 @@
+/*
+ * Simple client factory
+ *
+ * Copyright © 2011 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:simple-client-factory
+ * @title: TpSimpleClientFactory
+ * @short_description: simple client factory
+ * @see_also: #TpAutomaticClientFactory
+ *
+ * This factory constructs various #TpProxy subclasses as well as #TpContact. It
+ * guarantees uniqueness of those objects. It is also used to describe the
+ * features desired for each of those object classes.
+ *
+ * Note that the factory will not prepare the desired features, it is caller's
+ * responsibility to do so. By default only core features are requested.
+ *
+ * Currently supported classes are #TpAccountManager, #TpAccount, #TpConnection,
+ * #TpChannel and #TpContact. Those objects should always be acquired through a
+ * factory and not created directly.
+ *
+ * One can subclass #TpSimpleClientFactory and override some of its virtual
+ * methods to construct more specialized objects. See #TpAutomaticClientFactory
+ * for more specialized factory.
+ *
+ * Since: 0.UNRELEASED
+ */
+
+/**
+ * TpSimpleClientFactory:
+ *
+ * Data structure representing a #TpSimpleClientFactory
+ *
+ * Since: 0.UNRELEASED
+ */
+
+/**
+ * TpSimpleClientFactoryClass:
+ * @parent_class: the parent class
+ *
+ * The class of a #TpSimpleClientFactory.
+ *
+ * Since: 0.UNRELEASED
+ */
+
+/**
+ * TpSimpleClientFactoryClass:
+ * @parent_class: the parent
+ * @create_account_manager: virtual method used to create a #TpAccountManager;
+ * see tp_simple_client_factory_ensure_account_manager()
+ * @dup_account_manager_features: virtual method returning account manager
+ * features that have to be prepared on newly created account manager;
+ * see tp_simple_client_factory_dup_account_features()
+ * @create_account: virtual method used to create a #TpAccount;
+ * see tp_simple_client_factory_ensure_account()
+ * @dup_account_features: virtual method returning account features that
+ * have to be prepared on newly created accounts;
+ * see tp_simple_client_factory_dup_account_features()
+ * @create_connection: virtual method used to create a #TpConnection;
+ * see tp_simple_client_factory_ensure_connection()
+ * @dup_connection_features: virtual method returning connection features that
+ * have to be prepared on newly created connections;
+ * see tp_simple_client_factory_dup_connection_features()
+ * @create_channel: virtual method used to create a #TpChannel;
+ * see tp_simple_client_factory_ensure_channel()
+ * @dup_channel_features: virtual method returning connection features that
+ * have to be prepared on newly created channel;
+ * see tp_simple_client_factory_dup_channel_features()
+ * @create_contact: virtual method used to create a #TpContact;
+ * see tp_simple_client_factory_ensure_contact()
+ * @dup_contact_features: virtual method returning contact features that
+ * have to be prepared on newly created contacts;
+ * see tp_simple_client_factory_dup_contact_features()
+ *
+ * V-Table for #TpSimpleClientFactory sub-classing
+ *
+ * Since: 0.UNRELEASED
+ */
+
+#include "telepathy-glib/simple-client-factory.h"
+
+#include <telepathy-glib/util.h>
+
+#define DEBUG_FLAG TP_DEBUG_CLIENT
+#include "telepathy-glib/connection-internal.h"
+#include "telepathy-glib/contact-internal.h"
+#include "telepathy-glib/debug-internal.h"
+#include "telepathy-glib/simple-client-factory-internal.h"
+#include "telepathy-glib/util-internal.h"
+
+struct _TpSimpleClientFactoryPrivate
+{
+ TpDBusDaemon *dbus;
+ /* Owned object-path -> weakref to TpProxy */
+ GHashTable *proxy_cache;
+ GArray *desired_account_manager_features;
+ GArray *desired_account_features;
+ GArray *desired_connection_features;
+ GArray *desired_channel_features;
+ GArray *desired_contact_features;
+};
+
+enum
+{
+ PROP_DBUS_DAEMON = 1,
+ N_PROPS
+};
+
+G_DEFINE_TYPE (TpSimpleClientFactory, tp_simple_client_factory, G_TYPE_OBJECT)
+
+static void
+proxy_invalidated_cb (TpProxy *proxy,
+ guint domain,
+ gint code,
+ gchar *message,
+ TpSimpleClientFactory *self)
+{
+ g_hash_table_remove (self->priv->proxy_cache,
+ tp_proxy_get_object_path (proxy));
+}
+
+static void
+insert_proxy (TpSimpleClientFactory *self,
+ gpointer proxy)
+{
+ if (proxy == NULL)
+ return;
+
+ g_hash_table_insert (self->priv->proxy_cache,
+ (gpointer) tp_proxy_get_object_path (proxy), proxy);
+
+ /* This assume that invalidated signal is emitted from TpProxy dispose. May
+ * change in a future API break? */
+ tp_g_signal_connect_object (proxy, "invalidated",
+ G_CALLBACK (proxy_invalidated_cb), self, 0);
+}
+
+static gpointer
+lookup_proxy (TpSimpleClientFactory *self,
+ const gchar *object_path)
+{
+ return g_hash_table_lookup (self->priv->proxy_cache, object_path);
+}
+
+void
+_tp_simple_client_factory_insert_proxy (TpSimpleClientFactory *self,
+ gpointer proxy)
+{
+ g_return_if_fail (lookup_proxy (self,
+ tp_proxy_get_object_path (proxy)) == NULL);
+
+ insert_proxy (self, proxy);
+}
+
+static TpAccountManager *
+create_account_manager_impl (TpSimpleClientFactory *self)
+{
+ return _tp_account_manager_new_with_factory (self, self->priv->dbus);
+}
+
+static GArray *
+dup_account_manager_features_impl (TpSimpleClientFactory *self,
+ TpAccountManager *manager)
+{
+ return _tp_quark_array_copy (
+ (GQuark *) self->priv->desired_account_manager_features->data);
+}
+
+static TpAccount *
+create_account_impl (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties G_GNUC_UNUSED,
+ GError **error)
+{
+ return _tp_account_new_with_factory (self, self->priv->dbus, object_path,
+ error);
+}
+
+static GArray *
+dup_account_features_impl (TpSimpleClientFactory *self,
+ TpAccount *account)
+{
+ return _tp_quark_array_copy (
+ (GQuark *) self->priv->desired_account_features->data);
+}
+
+static TpConnection *
+create_connection_impl (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties G_GNUC_UNUSED,
+ GError **error)
+{
+ return _tp_connection_new_with_factory (self, self->priv->dbus, NULL,
+ object_path, error);
+}
+
+static GArray *
+dup_connection_features_impl (TpSimpleClientFactory *self,
+ TpConnection *connection)
+{
+ return _tp_quark_array_copy (
+ (GQuark *) self->priv->desired_connection_features->data);
+}
+
+static TpChannel *
+create_channel_impl (TpSimpleClientFactory *self,
+ TpConnection *conn,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error)
+{
+ return _tp_channel_new_with_factory (self, conn, object_path,
+ immutable_properties, error);
+}
+
+static GArray *
+dup_channel_features_impl (TpSimpleClientFactory *self,
+ TpChannel *channel)
+{
+ return _tp_quark_array_copy (
+ (GQuark *) self->priv->desired_channel_features->data);
+}
+
+static TpContact *
+create_contact_impl (TpSimpleClientFactory *self,
+ TpConnection *connection,
+ TpHandle handle,
+ const gchar *identifier)
+{
+ return _tp_contact_new (connection, handle, identifier);
+}
+
+static GArray *
+dup_contact_features_impl (TpSimpleClientFactory *self,
+ TpConnection *connection)
+{
+ GArray *array;
+
+ array = g_array_sized_new (FALSE, FALSE, sizeof (TpContactFeature),
+ self->priv->desired_contact_features->len);
+ g_array_append_vals (array, self->priv->desired_contact_features->data,
+ self->priv->desired_contact_features->len);
+
+ return array;
+}
+
+static void
+tp_simple_client_factory_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
+
+ switch (property_id)
+ {
+ case PROP_DBUS_DAEMON:
+ g_value_set_object (value, self->priv->dbus);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_simple_client_factory_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
+
+ switch (property_id)
+ {
+ case PROP_DBUS_DAEMON:
+ g_assert (self->priv->dbus == NULL); /* construct only */
+ self->priv->dbus = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_simple_client_factory_constructed (GObject *object)
+{
+ TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
+
+ g_assert (TP_IS_DBUS_DAEMON (self->priv->dbus));
+
+ G_OBJECT_CLASS (tp_simple_client_factory_parent_class)->constructed (object);
+}
+
+static void
+tp_simple_client_factory_finalize (GObject *object)
+{
+ TpSimpleClientFactory *self = (TpSimpleClientFactory *) object;
+
+ g_clear_object (&self->priv->dbus);
+ tp_clear_pointer (&self->priv->proxy_cache, g_hash_table_unref);
+ tp_clear_pointer (&self->priv->desired_account_manager_features,
+ g_array_unref);
+ tp_clear_pointer (&self->priv->desired_account_features, g_array_unref);
+ tp_clear_pointer (&self->priv->desired_connection_features, g_array_unref);
+ tp_clear_pointer (&self->priv->desired_channel_features, g_array_unref);
+ tp_clear_pointer (&self->priv->desired_contact_features, g_array_unref);
+
+ G_OBJECT_CLASS (tp_simple_client_factory_parent_class)->finalize (object);
+}
+
+static void
+tp_simple_client_factory_init (TpSimpleClientFactory *self)
+{
+ GQuark feature;
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TYPE_SIMPLE_CLIENT_FACTORY,
+ TpSimpleClientFactoryPrivate);
+
+ self->priv->proxy_cache = g_hash_table_new (g_str_hash, g_str_equal);
+
+ self->priv->desired_account_manager_features = g_array_new (TRUE, FALSE,
+ sizeof (GQuark));
+ feature = TP_ACCOUNT_MANAGER_FEATURE_CORE;
+ g_array_append_val (self->priv->desired_account_manager_features, feature);
+
+ self->priv->desired_account_features = g_array_new (TRUE, FALSE,
+ sizeof (GQuark));
+ feature = TP_ACCOUNT_FEATURE_CORE;
+ g_array_append_val (self->priv->desired_account_features, feature);
+
+ self->priv->desired_connection_features = g_array_new (TRUE, FALSE,
+ sizeof (GQuark));
+ feature = TP_CONNECTION_FEATURE_CORE;
+ g_array_append_val (self->priv->desired_connection_features, feature);
+
+ self->priv->desired_channel_features = g_array_new (TRUE, FALSE,
+ sizeof (GQuark));
+ feature = TP_CHANNEL_FEATURE_CORE;
+ g_array_append_val (self->priv->desired_channel_features, feature);
+
+ self->priv->desired_contact_features = g_array_new (FALSE, FALSE,
+ sizeof (TpContactFeature));
+}
+
+static void
+tp_simple_client_factory_class_init (TpSimpleClientFactoryClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ GParamSpec *param_spec;
+
+ g_type_class_add_private (klass, sizeof (TpSimpleClientFactoryPrivate));
+
+ object_class->get_property = tp_simple_client_factory_get_property;
+ object_class->set_property = tp_simple_client_factory_set_property;
+ object_class->constructed = tp_simple_client_factory_constructed;
+ object_class->finalize = tp_simple_client_factory_finalize;
+
+ klass->create_account_manager = create_account_manager_impl;
+ klass->dup_account_manager_features = dup_account_manager_features_impl;
+ klass->create_account = create_account_impl;
+ klass->dup_account_features = dup_account_features_impl;
+ klass->create_connection = create_connection_impl;
+ klass->dup_connection_features = dup_connection_features_impl;
+ klass->create_channel = create_channel_impl;
+ klass->dup_channel_features = dup_channel_features_impl;
+ klass->create_contact = create_contact_impl;
+ klass->dup_contact_features = dup_contact_features_impl;
+
+ /**
+ * TpSimpleClientFactory:dbus-daemon:
+ *
+ * The D-Bus daemon for this object.
+ */
+ param_spec = g_param_spec_object ("dbus-daemon", "D-Bus daemon",
+ "The D-Bus daemon used by this object",
+ TP_TYPE_DBUS_DAEMON,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK);
+ g_object_class_install_property (object_class, PROP_DBUS_DAEMON,
+ param_spec);
+}
+
+/**
+ * tp_simple_client_factory_new:
+ * @dbus: a #TpDBusDaemon
+ *
+ * Convenient function to create a new #TpSimpleClientFactory instance.
+ *
+ * Returns: a new #TpSimpleClientFactory
+ *
+ * Since: 0.UNRELEASED
+ */
+TpSimpleClientFactory *
+tp_simple_client_factory_new (TpDBusDaemon *dbus)
+{
+ return g_object_new (TP_TYPE_SIMPLE_CLIENT_FACTORY,
+ "dbus-daemon", dbus,
+ NULL);
+}
+
+/**
+ * tp_simple_client_factory_get_dbus_daemon:
+ * @self: a #TpSimpleClientFactory object
+ *
+ * <!-- -->
+ *
+ * Returns: (transfer none): same value as #TpSimpleClientFactory:dbus-daemon
+ * property
+ *
+ * Since: 0.UNRELEASED
+ */
+TpDBusDaemon *
+tp_simple_client_factory_get_dbus_daemon (TpSimpleClientFactory *self)
+{
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+
+ return self->priv->dbus;
+}
+
+/**
+ * tp_simple_client_factory_ensure_account_manager:
+ * @self: a #TpSimpleClientFactory object
+ *
+ * The returned #TpAccountManager is cached; the same #TpAccountManager object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpAccountManager is not guaranteed
+ * to be ready on return.
+ *
+ * Returns: (transfer full): a reference on a new or existing #TpAccountManager;
+ * see tp_account_manager_new().
+ *
+ * Since: 0.UNRELEASED
+ */
+TpAccountManager *
+tp_simple_client_factory_ensure_account_manager (TpSimpleClientFactory *self)
+{
+ TpAccountManager *manager;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+
+ manager = lookup_proxy (self, TP_ACCOUNT_MANAGER_OBJECT_PATH);
+ if (manager != NULL)
+ return g_object_ref (manager);
+
+ manager = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_account_manager (
+ self);
+ insert_proxy (self, manager);
+
+ return manager;
+}
+
+/**
+ * tp_simple_client_factory_dup_account_manager_features:
+ * @self: a #TpSimpleClientFactory object
+ * @manager: a #TpAccountManager
+ *
+ * Return a zero terminated #GArray containing the #TpAccountManager features
+ * that should be prepared on @manager.
+ *
+ * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
+ * #GArray
+ *
+ * Since: 0.UNRELEASED
+ */
+GArray *
+tp_simple_client_factory_dup_account_manager_features (
+ TpSimpleClientFactory *self,
+ TpAccountManager *manager)
+{
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT_MANAGER (manager), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (manager) == self, NULL);
+
+ return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_account_manager_features
+ (self, manager);
+}
+
+/**
+ * tp_simple_client_factory_add_account_manager_features:
+ * @self: a #TpSimpleClientFactory object
+ * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
+ * of desired features, ending with 0; %NULL is equivalent to an array
+ * containing only 0
+ *
+ * Add @features to the desired features to be prepared on #TpAccountManager
+ * object. Those features will be added to the features already returned be
+ * tp_simple_client_factory_dup_account_manager_features().
+ *
+ * It is not necessary to add %TP_ACCOUNT_MANAGER_FEATURE_CORE as it is already
+ * included by default.
+ *
+ * Note that existing proxy won't be upgraded unless done manually using
+ * tp_proxy_prepare_async().
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_simple_client_factory_add_account_manager_features (
+ TpSimpleClientFactory *self,
+ const GQuark *features)
+{
+ g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
+
+ _tp_quark_array_merge (self->priv->desired_account_manager_features, features,
+ -1);
+}
+
+/**
+ * tp_simple_client_factory_ensure_account:
+ * @self: a #TpSimpleClientFactory object
+ * @object_path: the non-NULL object path of this account
+ * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
+ * the immutable properties of the account. Currently unused.
+ * @error: Used to raise an error if @object_path is not valid
+ *
+ * The returned #TpAccount is cached; the same #TpAccount object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpAccount is not guaranteed
+ * to be ready on return.
+ *
+ * Caller is responsible to call tp_proxy_prepare_async() with the desired
+ * features as given by tp_simple_client_factory_dup_account_features().
+ *
+ * Returns: (transfer full): a reference on a new or existing #TpAccount;
+ * see tp_account_new().
+ *
+ * Since: 0.UNRELEASED
+ */
+TpAccount *
+tp_simple_client_factory_ensure_account (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error)
+{
+ TpAccount *account;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+
+ account = lookup_proxy (self, object_path);
+ if (account != NULL)
+ return g_object_ref (account);
+
+ account = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_account (self,
+ object_path, immutable_properties, error);
+ insert_proxy (self, account);
+
+ return account;
+}
+
+/**
+ * tp_simple_client_factory_dup_account_features:
+ * @self: a #TpSimpleClientFactory object
+ * @account: a #TpAccount
+ *
+ * Return a zero terminated #GArray containing the #TpAccount features that
+ * should be prepared on @account.
+ *
+ * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
+ * #GArray
+ *
+ * Since: 0.UNRELEASED
+ */
+GArray *
+tp_simple_client_factory_dup_account_features (TpSimpleClientFactory *self,
+ TpAccount *account)
+{
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (account) == self, NULL);
+
+ return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_account_features (self,
+ account);
+}
+
+/**
+ * tp_simple_client_factory_add_account_features:
+ * @self: a #TpSimpleClientFactory object
+ * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
+ * of desired features, ending with 0; %NULL is equivalent to an array
+ * containing only 0
+ *
+ * Add @features to the desired features to be prepared on #TpAccount
+ * objects. Those features will be added to the features already returned be
+ * tp_simple_client_factory_dup_account_features().
+ *
+ * It is not necessary to add %TP_ACCOUNT_FEATURE_CORE as it is already
+ * included by default.
+ *
+ * Note that existing proxies won't be upgraded unless done manually using
+ * tp_proxy_prepare_async().
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_simple_client_factory_add_account_features (
+ TpSimpleClientFactory *self,
+ const GQuark *features)
+{
+ g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
+
+ _tp_quark_array_merge (self->priv->desired_account_features, features, -1);
+}
+
+/**
+ * tp_simple_client_factory_ensure_connection:
+ * @self: a #TpSimpleClientFactory object
+ * @object_path: the non-NULL object path of this connection
+ * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
+ * the immutable properties of the connection. Currently unused.
+ * @error: Used to raise an error if @object_path is not valid
+ *
+ * The returned #TpConnection is cached; the same #TpConnection object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpConnection is not guaranteed
+ * to be ready on return.
+ *
+ * Caller is responsible to call tp_proxy_prepare_async() with the desired
+ * features as given by tp_simple_client_factory_dup_connection_features().
+ *
+ * Returns: (transfer full): a reference on a new or existing #TpConnection;
+ * see tp_connection_new().
+ *
+ * Since: 0.UNRELEASED
+ */
+TpConnection *
+tp_simple_client_factory_ensure_connection (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error)
+{
+ TpConnection *connection;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+
+ connection = lookup_proxy (self, object_path);
+ if (connection != NULL)
+ return g_object_ref (connection);
+
+ connection = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_connection (
+ self, object_path, immutable_properties, error);
+ insert_proxy (self, connection);
+
+ return connection;
+}
+
+/**
+ * tp_simple_client_factory_dup_connection_features:
+ * @self: a #TpSimpleClientFactory object
+ * @connection: a #TpConnection
+ *
+ * Return a zero terminated #GArray containing the #TpConnection features that
+ * should be prepared on @connection.
+ *
+ * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
+ * #GArray
+ *
+ * Since: 0.UNRELEASED
+ */
+GArray *
+tp_simple_client_factory_dup_connection_features (TpSimpleClientFactory *self,
+ TpConnection *connection)
+{
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
+
+ return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_connection_features (
+ self, connection);
+}
+
+/**
+ * tp_simple_client_factory_add_connection_features:
+ * @self: a #TpSimpleClientFactory object
+ * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
+ * of desired features, ending with 0; %NULL is equivalent to an array
+ * containing only 0
+ *
+ * Add @features to the desired features to be prepared on #TpConnection
+ * objects. Those features will be added to the features already returned be
+ * tp_simple_client_factory_dup_connection_features().
+ *
+ * It is not necessary to add %TP_CONNECTION_FEATURE_CORE as it is already
+ * included by default.
+ *
+ * Note that existing proxies won't be upgraded unless done manually using
+ * tp_proxy_prepare_async().
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_simple_client_factory_add_connection_features (
+ TpSimpleClientFactory *self,
+ const GQuark *features)
+{
+ g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
+
+ _tp_quark_array_merge (self->priv->desired_connection_features, features, -1);
+}
+
+/**
+ * tp_simple_client_factory_ensure_channel:
+ * @self: a #TpSimpleClientFactory object
+ * @connection: a #TpConnection
+ * @object_path: the non-NULL object path of this connection
+ * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
+ * the immutable properties of the channel
+ * @error: Used to raise an error if @object_path is not valid
+ *
+ * The returned #TpChannel is cached; the same #TpChannel object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpChannel is not guaranteed
+ * to be ready on return.
+ *
+ * Caller is responsible to call tp_proxy_prepare_async() with the desired
+ * features as given by tp_simple_client_factory_dup_channel_features().
+ *
+ * Returns: (transfer full): a reference on a new or existing #TpChannel;
+ * see tp_channel_new_with_properties().
+ *
+ * Since: 0.UNRELEASED
+ */
+TpChannel *
+tp_simple_client_factory_ensure_channel (TpSimpleClientFactory *self,
+ TpConnection *connection,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error)
+{
+ TpChannel *channel;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+
+ channel = lookup_proxy (self, object_path);
+ if (channel != NULL)
+ return g_object_ref (channel);
+
+ channel = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_channel (self,
+ connection, object_path, immutable_properties, error);
+ insert_proxy (self, channel);
+
+ return channel;
+}
+
+/**
+ * tp_simple_client_factory_dup_channel_features:
+ * @self: a #TpSimpleClientFactory object
+ * @channel: a #TpChannel
+ *
+ * Return a zero terminated #GArray containing the #TpChannel features that
+ * should be prepared on @channel.
+ *
+ * Returns: (transfer full) (element-type GLib.Quark): a newly allocated
+ * #GArray
+ *
+ * Since: 0.UNRELEASED
+ */
+GArray *
+tp_simple_client_factory_dup_channel_features (TpSimpleClientFactory *self,
+ TpChannel *channel)
+{
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (channel) == self, NULL);
+
+ return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_channel_features (
+ self, channel);
+}
+
+/**
+ * tp_simple_client_factory_add_channel_features:
+ * @self: a #TpSimpleClientFactory object
+ * @features: (transfer none) (array zero-terminated=1) (allow-none): an array
+ * of desired features, ending with 0; %NULL is equivalent to an array
+ * containing only 0
+ *
+ * Add @features to the desired features to be prepared on #TpChannel
+ * objects. Those features will be added to the features already returned be
+ * tp_simple_client_factory_dup_channel_features().
+ *
+ * It is not necessary to add %TP_CHANNEL_FEATURE_CORE as it is already
+ * included by default.
+ *
+ * Note that existing proxies won't be upgraded unless done manually using
+ * tp_proxy_prepare_async().
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_simple_client_factory_add_channel_features (
+ TpSimpleClientFactory *self,
+ const GQuark *features)
+{
+ g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
+
+ _tp_quark_array_merge (self->priv->desired_channel_features, features, -1);
+}
+
+/**
+ * tp_simple_client_factory_ensure_contact:
+ * @self: a #TpSimpleClientFactory object
+ * @connection: a #TpConnection
+ * @handle: a #TpHandle
+ * @identifier: a string representing the contact's identifier
+ *
+ * The returned #TpContact is cached; the same #TpContact object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpContact is not guaranteed
+ * to be ready on return.
+ *
+ * Caller is responsible to call tp_connection_upgrade_contacts() with the
+ * desired features as given by tp_simple_client_factory_dup_contact_features().
+ *
+ * For this to work properly tp_connection_has_immortal_handles() has to return
+ * %TRUE for @connection.
+ *
+ * Returns: (transfer full): a reference on a new or existing #TpContact.
+ *
+ * Since: 0.UNRELEASED
+ */
+TpContact *
+tp_simple_client_factory_ensure_contact (TpSimpleClientFactory *self,
+ TpConnection *connection,
+ TpHandle handle,
+ const gchar *identifier)
+{
+ TpContact *contact;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
+ g_return_val_if_fail (tp_connection_has_immortal_handles (connection), NULL);
+ g_return_val_if_fail (handle != 0, NULL);
+ g_return_val_if_fail (identifier != NULL, NULL);
+
+ contact = _tp_connection_lookup_contact (connection, handle);
+ if (contact != NULL)
+ return g_object_ref (contact);
+
+ contact = TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->create_contact (self,
+ connection, handle, identifier);
+ _tp_connection_add_contact (connection, handle, contact);
+
+ return contact;
+}
+
+/**
+ * tp_simple_client_factory_dup_contact_features:
+ * @self: a #TpSimpleClientFactory object
+ * @connection: a #TpConnection
+ *
+ * Return a #GArray containing the #TpContactFeature that should be prepared on
+ * all contacts of @connection.
+ *
+ * Returns: (transfer full) (element-type TelepathyGLib.ContactFeature): a newly
+ * allocated #GArray
+ *
+ * Since: 0.UNRELEASED
+ */
+GArray *
+tp_simple_client_factory_dup_contact_features (TpSimpleClientFactory *self,
+ TpConnection *connection)
+{
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (tp_proxy_get_factory (connection) == self, NULL);
+
+ return TP_SIMPLE_CLIENT_FACTORY_GET_CLASS (self)->dup_contact_features (
+ self, connection);
+}
+
+/**
+ * tp_simple_client_factory_add_contact_features:
+ * @self: a #TpSimpleClientFactory object
+ * @n_features: The number of features in @features (may be 0)
+ * @features: (array length=n_features) (allow-none): an array of desired
+ * features (may be %NULL if @n_features is 0)
+ *
+ * Add @features to the desired features to be prepared on #TpContact
+ * objects. Those features will be added to the features already returned be
+ * tp_simple_client_factory_dup_contact_features().
+ *
+ * Note that existing contacts won't be upgraded unless done manually using
+ * tp_connection_upgrade_contacts().
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_simple_client_factory_add_contact_features (TpSimpleClientFactory *self,
+ guint n_features, const TpContactFeature *features)
+{
+ guint i;
+
+ g_return_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self));
+
+ /* Add features into desired_contact_features avoiding dups */
+ for (i = 0; i < n_features; i++)
+ {
+ guint j;
+ gboolean found = FALSE;
+
+ for (j = 0; j < self->priv->desired_contact_features->len; j++)
+ {
+ if (features[i] == g_array_index (
+ self->priv->desired_contact_features, TpContactFeature, j))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ g_array_append_val (self->priv->desired_contact_features, features[i]);
+ }
+}
+
+/**
+ * tp_simple_client_factory_ensure_channel_request:
+ * @self: a #TpSimpleClientFactory object
+ * @object_path: the non-NULL object path of this connection
+ * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
+ * the immutable properties of the channel request
+ * @error: Used to raise an error if @object_path is not valid
+ *
+ * The returned #TpChannelRequest is cached; the same #TpChannelRequest object
+ * will be returned by this function repeatedly, as long as at least one
+ * reference exists. Note that the returned #TpChannelRequest is not guaranteed
+ * to be ready on return.
+ *
+ * Caller is responsible to call tp_proxy_prepare_async().
+ *
+ * Returns: (transfer full): a reference on a new or existing #TpChannelRequest;
+ * see tp_channel_request_new().
+ *
+ * Since: 0.UNRELEASED
+ */
+TpChannelRequest *
+_tp_simple_client_factory_ensure_channel_request (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error)
+{
+ TpChannelRequest *request;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+
+ request = lookup_proxy (self, object_path);
+ if (request != NULL)
+ {
+ /* A common usage is request_and_handle, in that case EnsureChannel
+ * returns only the object-path of the ChannelRequest but not properties.
+ * The TpChannelRequest will be created with no properties, then when
+ * handling we get the properties and we reuse the same TpChannelRequest
+ * object, and we can give it the immutable-properties. */
+ _tp_channel_request_ensure_immutable_properties (request,
+ immutable_properties);
+ return g_object_ref (request);
+ }
+
+ request = _tp_channel_request_new_with_factory (self, self->priv->dbus,
+ object_path, immutable_properties, error);
+ insert_proxy (self, request);
+
+ return request;
+}
+
+/**
+ * tp_simple_client_factory_ensure_channel_dispatch_operation:
+ * @self: a #TpSimpleClientFactory object
+ * @object_path: the non-NULL object path of this connection
+ * @immutable_properties: (transfer none) (element-type utf8 GObject.Value):
+ * the immutable properties of the channel dispatch operation
+ * @error: Used to raise an error if @object_path is not valid
+ *
+ * The returned #TpChannelDispatchOperation is cached; the same
+ * #TpChannelDispatchOperation object will be returned by this function
+ * repeatedly, as long as at least one reference exists. Note that the returned
+ * #TpChannelDispatchOperation is not guaranteed to be ready on return.
+ *
+ * Caller is responsible to call tp_proxy_prepare_async().
+ *
+ * Returns: (transfer full): a reference on a new or existing
+ * #TpChannelDispatchOperation; see tp_channel_dispatch_operation_new().
+ *
+ * Since: 0.UNRELEASED
+ */
+TpChannelDispatchOperation *
+_tp_simple_client_factory_ensure_channel_dispatch_operation (
+ TpSimpleClientFactory *self,
+ const gchar *object_path,
+ GHashTable *immutable_properties,
+ GError **error)
+{
+ TpChannelDispatchOperation *dispatch;
+
+ g_return_val_if_fail (TP_IS_SIMPLE_CLIENT_FACTORY (self), NULL);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
+
+ dispatch = lookup_proxy (self, object_path);
+ if (dispatch != NULL)
+ return g_object_ref (dispatch);
+
+ dispatch = _tp_channel_dispatch_operation_new_with_factory (self,
+ self->priv->dbus, object_path, immutable_properties, error);
+ insert_proxy (self, dispatch);
+
+ return dispatch;
+}
diff --git a/telepathy-glib/simple-client-factory.h b/telepathy-glib/simple-client-factory.h
new file mode 100644
index 000000000..36cb5c830
--- /dev/null
+++ b/telepathy-glib/simple-client-factory.h
@@ -0,0 +1,174 @@
+/*
+ * Simple client factory
+ *
+ * Copyright © 2011 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __TP_SIMPLE_CLIENT_FACTORY_H__
+#define __TP_SIMPLE_CLIENT_FACTORY_H__
+
+#include <telepathy-glib/account-manager.h>
+#include <telepathy-glib/account.h>
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/channel-dispatch-operation.h>
+#include <telepathy-glib/channel-request.h>
+#include <telepathy-glib/connection.h>
+#include <telepathy-glib/contact.h>
+#include <telepathy-glib/dbus-daemon.h>
+
+G_BEGIN_DECLS
+
+/* TpSimpleClientFactory is typedef'd in proxy.h */
+typedef struct _TpSimpleClientFactoryPrivate TpSimpleClientFactoryPrivate;
+typedef struct _TpSimpleClientFactoryClass TpSimpleClientFactoryClass;
+
+struct _TpSimpleClientFactoryClass {
+ /*<public>*/
+ GObjectClass parent_class;
+
+ /* TpAccountManager */
+ TpAccountManager * (*create_account_manager) (TpSimpleClientFactory *self);
+ GArray * (*dup_account_manager_features) (TpSimpleClientFactory *self,
+ TpAccountManager *manager);
+
+ /* TpAccount */
+ TpAccount * (*create_account) (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+ GArray * (*dup_account_features) (TpSimpleClientFactory *self,
+ TpAccount *account);
+
+ /* TpConnection */
+ TpConnection * (*create_connection) (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+ GArray * (*dup_connection_features) (TpSimpleClientFactory *self,
+ TpConnection *connection);
+
+ /* TpChannel */
+ TpChannel * (*create_channel) (TpSimpleClientFactory *self,
+ TpConnection *conn,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+ GArray * (*dup_channel_features) (TpSimpleClientFactory *self,
+ TpChannel *channel);
+
+ /* TpContact */
+ TpContact * (*create_contact) (TpSimpleClientFactory *self,
+ TpConnection *connection,
+ TpHandle handle,
+ const gchar *identifier);
+ GArray * (*dup_contact_features) (TpSimpleClientFactory *self,
+ TpConnection *connection);
+
+ /*<private>*/
+ GCallback padding[20];
+};
+
+struct _TpSimpleClientFactory {
+ /*<private>*/
+ GObject parent;
+ TpSimpleClientFactoryPrivate *priv;
+};
+
+GType tp_simple_client_factory_get_type (void);
+
+#define TP_TYPE_SIMPLE_CLIENT_FACTORY \
+ (tp_simple_client_factory_get_type ())
+#define TP_SIMPLE_CLIENT_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_SIMPLE_CLIENT_FACTORY, \
+ TpSimpleClientFactory))
+#define TP_SIMPLE_CLIENT_FACTORY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TYPE_SIMPLE_CLIENT_FACTORY, \
+ TpSimpleClientFactoryClass))
+#define TP_IS_SIMPLE_CLIENT_FACTORY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_SIMPLE_CLIENT_FACTORY))
+#define TP_IS_SIMPLE_CLIENT_FACTORY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TYPE_SIMPLE_CLIENT_FACTORY))
+#define TP_SIMPLE_CLIENT_FACTORY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_SIMPLE_CLIENT_FACTORY, \
+ TpSimpleClientFactoryClass))
+
+TpSimpleClientFactory * tp_simple_client_factory_new (TpDBusDaemon *dbus);
+
+TpDBusDaemon *tp_simple_client_factory_get_dbus_daemon (
+ TpSimpleClientFactory *self);
+
+/* TpAccountManager */
+TpAccountManager *tp_simple_client_factory_ensure_account_manager (
+ TpSimpleClientFactory *self);
+GArray *tp_simple_client_factory_dup_account_manager_features (
+ TpSimpleClientFactory *self,
+ TpAccountManager *manager);
+void tp_simple_client_factory_add_account_manager_features (
+ TpSimpleClientFactory *self,
+ const GQuark *features);
+
+/* TpAccount */
+TpAccount *tp_simple_client_factory_ensure_account (TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+GArray *tp_simple_client_factory_dup_account_features (
+ TpSimpleClientFactory *self,
+ TpAccount *account);
+void tp_simple_client_factory_add_account_features (TpSimpleClientFactory *self,
+ const GQuark *features);
+
+/* TpConnection */
+TpConnection *tp_simple_client_factory_ensure_connection (
+ TpSimpleClientFactory *self,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+GArray *tp_simple_client_factory_dup_connection_features (
+ TpSimpleClientFactory *self,
+ TpConnection *connection);
+void tp_simple_client_factory_add_connection_features (
+ TpSimpleClientFactory *self,
+ const GQuark *features);
+
+/* TpChannel */
+TpChannel *tp_simple_client_factory_ensure_channel (TpSimpleClientFactory *self,
+ TpConnection *connection,
+ const gchar *object_path,
+ const GHashTable *immutable_properties,
+ GError **error);
+GArray *tp_simple_client_factory_dup_channel_features (
+ TpSimpleClientFactory *self,
+ TpChannel *channel);
+void tp_simple_client_factory_add_channel_features (TpSimpleClientFactory *self,
+ const GQuark *features);
+
+/* TpContact */
+TpContact *tp_simple_client_factory_ensure_contact (TpSimpleClientFactory *self,
+ TpConnection *connection,
+ TpHandle handle,
+ const gchar *identifier);
+GArray *tp_simple_client_factory_dup_contact_features (
+ TpSimpleClientFactory *self,
+ TpConnection *connection);
+void tp_simple_client_factory_add_contact_features (TpSimpleClientFactory *self,
+ guint n_features,
+ const TpContactFeature *features);
+
+G_END_DECLS
+
+#endif
diff --git a/telepathy-glib/telepathy-glib.h b/telepathy-glib/telepathy-glib.h
index e93c370d5..6409d3921 100644
--- a/telepathy-glib/telepathy-glib.h
+++ b/telepathy-glib/telepathy-glib.h
@@ -58,6 +58,7 @@
#include <telepathy-glib/proxy.h>
#include <telepathy-glib/signalled-message.h>
#include <telepathy-glib/simple-approver.h>
+#include <telepathy-glib/simple-client-factory.h>
#include <telepathy-glib/simple-handler.h>
#include <telepathy-glib/simple-observer.h>
#include <telepathy-glib/stream-tube-channel.h>