From 498eecbd726ee3a2587441a3089ffc38d9d367dd Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Thu, 17 Apr 2014 08:33:59 -0400 Subject: [PATCH 1/5] TpBaseProtocol: GVariant-ify TpCMParamSpec This drops related unused and weird code as well. It makes it a little bit closer to being introspectable. --- .../telepathy-glib/telepathy-glib-sections.txt | 16 +- examples/cm/call/protocol.c | 84 ++- examples/cm/call/protocol.h | 3 - examples/cm/channelspecific/protocol.c | 83 ++- examples/cm/channelspecific/protocol.h | 4 - examples/cm/contactlist/protocol.c | 83 ++- examples/cm/contactlist/protocol.h | 4 - examples/cm/echo-message-parts/protocol.c | 58 +- examples/cm/echo-message-parts/protocol.h | 4 - examples/cm/extended/protocol.c | 58 +- examples/cm/extended/protocol.h | 4 - telepathy-glib/base-connection-manager.c | 212 ------- telepathy-glib/base-connection-manager.h | 16 - telepathy-glib/base-protocol.c | 619 +++++++-------------- telepathy-glib/base-protocol.h | 87 ++- telepathy-glib/introspection.am | 1 + telepathy-glib/versions/main-1.0.abi | 3 +- 17 files changed, 507 insertions(+), 832 deletions(-) diff --git a/docs/reference/telepathy-glib/telepathy-glib-sections.txt b/docs/reference/telepathy-glib/telepathy-glib-sections.txt index 08f17e7..42a6967 100644 --- a/docs/reference/telepathy-glib/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib/telepathy-glib-sections.txt @@ -65,13 +65,15 @@ TpBaseConnectionPrivate TpBaseConnectionManager telepathy-glib/telepathy-glib.h base-connection-manager + TpCMParamFilter tp_cm_param_filter_string_nonempty tp_cm_param_filter_uint_nonzero -TpCMParamSetter -tp_cm_param_setter_offset TpCMParamSpec -TpCMProtocolSpec +tp_cm_param_spec_new +tp_cm_param_spec_ref +tp_cm_param_spec_unref + TpBaseConnectionManager TpBaseConnectionManagerClass TpBaseConnectionManagerNewConnFunc @@ -88,6 +90,8 @@ TP_BASE_CONNECTION_MANAGER_CLASS TP_IS_BASE_CONNECTION_MANAGER_CLASS TP_BASE_CONNECTION_MANAGER_GET_CLASS TpBaseConnectionManagerPrivate +TP_TYPE_CM_PARAM_SPEC +tp_cm_param_spec_get_type
@@ -4614,12 +4618,12 @@ TpBasePasswordChannelPrivate TpBaseProtocol tp_base_protocol_get_name tp_base_protocol_get_immutable_properties -tp_base_protocol_get_parameters +tp_base_protocol_dup_parameters tp_base_protocol_get_statuses tp_base_protocol_new_connection TpBaseProtocolClass -TpBaseProtocolGetParametersFunc +TpBaseProtocolDupParametersFunc TpBaseProtocolNewConnectionFunc TpBaseProtocolNormalizeContactFunc TpBaseProtocolIdentifyAccountFunc @@ -4646,6 +4650,8 @@ TpBaseProtocolNormalizeURIFunc TpBaseProtocolPrivate TpBaseProtocolClassPrivate + +TpProtocolAddressing
diff --git a/examples/cm/call/protocol.c b/examples/cm/call/protocol.c index 6806d7f..1673607 100644 --- a/examples/cm/call/protocol.c +++ b/examples/cm/call/protocol.c @@ -18,6 +18,11 @@ #include "call-manager.h" #include "conn.h" +struct _ExampleCallProtocolPrivate +{ + GPtrArray *params; +}; + G_DEFINE_TYPE (ExampleCallProtocol, example_call_protocol, TP_TYPE_BASE_PROTOCOL) @@ -26,6 +31,8 @@ static void example_call_protocol_init ( ExampleCallProtocol *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CALL_PROTOCOL, + ExampleCallProtocolPrivate); } gboolean @@ -48,38 +55,44 @@ example_call_protocol_check_contact_id (const gchar *id, return TRUE; } -static gboolean +static GVariant * account_param_filter (const TpCMParamSpec *paramspec, - GValue *value, + GVariant *value, + gpointer user_data, GError **error) { - const gchar *id = g_value_get_string (value); + const gchar *id = g_variant_get_string (value, NULL); - return example_call_protocol_check_contact_id (id, NULL, error); -} + if (example_call_protocol_check_contact_id (id, NULL, error)) + return value; -static const TpCMParamSpec example_call_example_params[] = { - { "account", "s", G_TYPE_STRING, - TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, - NULL, /* no default */ - 0, /* unused, formerly struct offset */ - account_param_filter, - NULL, /* filter data, unused here */ - NULL }, /* setter data, now unused */ - { "simulation-delay", "u", G_TYPE_UINT, - TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, - GUINT_TO_POINTER (1000), /* default */ - 0, /* unused, formerly struct offset */ - NULL, /* no filter */ - NULL, /* filter data, unused here */ - NULL }, /* setter data, now unused */ - { NULL } -}; + return NULL; +} -static const TpCMParamSpec * -get_parameters (TpBaseProtocol *self) +static GPtrArray * +dup_parameters (TpBaseProtocol *base) { - return example_call_example_params; + ExampleCallProtocol *self = (ExampleCallProtocol *) base; + + if (self->priv->params == NULL) + { + self->priv->params = g_ptr_array_new_full (2, + (GDestroyNotify) tp_cm_param_spec_unref); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("account", + TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, + g_variant_new_string (""), + account_param_filter, NULL, NULL)); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("simulation-delay", + TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, + g_variant_new_uint32 (1000), + NULL, NULL, NULL)); + } + + return g_ptr_array_ref (self->priv->params); } static TpBaseConnection * @@ -167,15 +180,28 @@ get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, } static void +finalize (GObject *object) +{ + ExampleCallProtocol *self = (ExampleCallProtocol *) object; + + g_clear_pointer (&self->priv->params, g_ptr_array_unref); + + G_OBJECT_CLASS (example_call_protocol_parent_class)->finalize (object); +} + +static void example_call_protocol_class_init ( ExampleCallProtocolClass *klass) { - TpBaseProtocolClass *base_class = - (TpBaseProtocolClass *) klass; + GObjectClass *oclass = (GObjectClass *) klass; + TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; - base_class->get_parameters = get_parameters; - base_class->new_connection = new_connection; + g_type_class_add_private (klass, sizeof (ExampleCallProtocolPrivate)); + oclass->finalize = finalize; + + base_class->dup_parameters = dup_parameters; + base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; base_class->identify_account = identify_account; base_class->get_connection_details = get_connection_details; diff --git a/examples/cm/call/protocol.h b/examples/cm/call/protocol.h index adfe8a6..17fdaae 100644 --- a/examples/cm/call/protocol.h +++ b/examples/cm/call/protocol.h @@ -19,12 +19,9 @@ G_BEGIN_DECLS typedef struct _ExampleCallProtocol ExampleCallProtocol; typedef struct _ExampleCallProtocolPrivate ExampleCallProtocolPrivate; typedef struct _ExampleCallProtocolClass ExampleCallProtocolClass; -typedef struct _ExampleCallProtocolClassPrivate ExampleCallProtocolClassPrivate; struct _ExampleCallProtocolClass { TpBaseProtocolClass parent_class; - - ExampleCallProtocolClassPrivate *priv; }; struct _ExampleCallProtocol { diff --git a/examples/cm/channelspecific/protocol.c b/examples/cm/channelspecific/protocol.c index 1052084..5cf0246 100644 --- a/examples/cm/channelspecific/protocol.c +++ b/examples/cm/channelspecific/protocol.c @@ -18,6 +18,11 @@ #include "conn.h" #include "room-manager.h" +struct _ExampleCSHProtocolPrivate +{ + GPtrArray *params; +}; + G_DEFINE_TYPE (ExampleCSHProtocol, example_csh_protocol, TP_TYPE_BASE_PROTOCOL) @@ -26,6 +31,8 @@ static void example_csh_protocol_init ( ExampleCSHProtocol *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CSH_PROTOCOL, + ExampleCSHProtocolPrivate); } /* For this example, we imagine that global handles look like @@ -88,38 +95,44 @@ example_csh_protocol_check_contact_id (const gchar *id, return TRUE; } -static gboolean +static GVariant * account_param_filter (const TpCMParamSpec *paramspec, - GValue *value, + GVariant *value, + gpointer user_data, GError **error) { - const gchar *id = g_value_get_string (value); + const gchar *id = g_variant_get_string (value, NULL); - return example_csh_protocol_check_contact_id (id, NULL, error); -} + if (example_csh_protocol_check_contact_id (id, NULL, error)) + return value; -static const TpCMParamSpec example_csh_example_params[] = { - { "account", "s", G_TYPE_STRING, - TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, - NULL, /* no default */ - 0, /* unused, formerly struct offset */ - account_param_filter, - NULL, /* filter data, unused here */ - NULL }, /* setter data, now unused */ - { "simulation-delay", "u", G_TYPE_UINT, - TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, - GUINT_TO_POINTER (500), /* default */ - 0, /* unused, formerly struct offset */ - NULL, /* no filter */ - NULL, /* filter data, unused here */ - NULL }, /* setter data, now unused */ - { NULL } -}; + return NULL; +} -static const TpCMParamSpec * -get_parameters (TpBaseProtocol *self) +static GPtrArray * +dup_parameters (TpBaseProtocol *base) { - return example_csh_example_params; + ExampleCSHProtocol *self = (ExampleCSHProtocol *) base; + + if (self->priv->params == NULL) + { + self->priv->params = g_ptr_array_new_full (2, + (GDestroyNotify) tp_cm_param_spec_unref); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("account", + TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, + g_variant_new_string (""), + account_param_filter, NULL, NULL)); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("simulation-delay", + TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, + g_variant_new_uint32 (500), + NULL, NULL, NULL)); + } + + return g_ptr_array_ref (self->priv->params); } static TpBaseConnection * @@ -207,13 +220,27 @@ get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, } static void +finalize (GObject *object) +{ + ExampleCSHProtocol *self = (ExampleCSHProtocol *) object; + + g_clear_pointer (&self->priv->params, g_ptr_array_unref); + + G_OBJECT_CLASS (example_csh_protocol_parent_class)->finalize (object); +} + +static void example_csh_protocol_class_init ( ExampleCSHProtocolClass *klass) { - TpBaseProtocolClass *base_class = - (TpBaseProtocolClass *) klass; + GObjectClass *oclass = (GObjectClass *) klass; + TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; + + g_type_class_add_private (klass, sizeof (ExampleCSHProtocolPrivate)); + + oclass->finalize = finalize; - base_class->get_parameters = get_parameters; + base_class->dup_parameters = dup_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; diff --git a/examples/cm/channelspecific/protocol.h b/examples/cm/channelspecific/protocol.h index 507c02d..c86358a 100644 --- a/examples/cm/channelspecific/protocol.h +++ b/examples/cm/channelspecific/protocol.h @@ -21,13 +21,9 @@ typedef struct _ExampleCSHProtocolPrivate ExampleCSHProtocolPrivate; typedef struct _ExampleCSHProtocolClass ExampleCSHProtocolClass; -typedef struct _ExampleCSHProtocolClassPrivate - ExampleCSHProtocolClassPrivate; struct _ExampleCSHProtocolClass { TpBaseProtocolClass parent_class; - - ExampleCSHProtocolClassPrivate *priv; }; struct _ExampleCSHProtocol { diff --git a/examples/cm/contactlist/protocol.c b/examples/cm/contactlist/protocol.c index eb0b2b6..bdb2acf 100644 --- a/examples/cm/contactlist/protocol.c +++ b/examples/cm/contactlist/protocol.c @@ -18,6 +18,11 @@ #include "conn.h" #include "contact-list.h" +struct _ExampleContactListProtocolPrivate +{ + GPtrArray *params; +}; + G_DEFINE_TYPE (ExampleContactListProtocol, example_contact_list_protocol, TP_TYPE_BASE_PROTOCOL) @@ -26,6 +31,8 @@ static void example_contact_list_protocol_init ( ExampleContactListProtocol *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_CONTACT_LIST_PROTOCOL, + ExampleContactListProtocolPrivate); } gboolean @@ -48,38 +55,44 @@ example_contact_list_protocol_check_contact_id (const gchar *id, return TRUE; } -static gboolean +static GVariant * account_param_filter (const TpCMParamSpec *paramspec, - GValue *value, + GVariant *value, + gpointer user_data, GError **error) { - const gchar *id = g_value_get_string (value); + const gchar *id = g_variant_get_string (value, NULL); - return example_contact_list_protocol_check_contact_id (id, NULL, error); -} + if (example_contact_list_protocol_check_contact_id (id, NULL, error)) + return value; -static const TpCMParamSpec example_contact_list_example_params[] = { - { "account", "s", G_TYPE_STRING, - TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, - NULL, /* no default */ - 0, /* unused, formerly struct offset */ - account_param_filter, - NULL, /* filter data, unused here */ - NULL }, /* setter data, now unused */ - { "simulation-delay", "u", G_TYPE_UINT, - TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, - GUINT_TO_POINTER (1000), /* default */ - 0, /* unused, formerly struct offset */ - NULL, /* no filter */ - NULL, /* filter data, unused here */ - NULL }, /* setter data, now unused */ - { NULL } -}; + return NULL; +} -static const TpCMParamSpec * -get_parameters (TpBaseProtocol *self) +static GPtrArray * +dup_parameters (TpBaseProtocol *base) { - return example_contact_list_example_params; + ExampleContactListProtocol *self = (ExampleContactListProtocol *) base; + + if (self->priv->params == NULL) + { + self->priv->params = g_ptr_array_new_full (2, + (GDestroyNotify) tp_cm_param_spec_unref); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("account", + TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, + g_variant_new_string (""), + account_param_filter, NULL, NULL)); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("simulation-delay", + TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT, + g_variant_new_uint32 (1000), + NULL, NULL, NULL)); + } + + return g_ptr_array_ref (self->priv->params); } static TpBaseConnection * @@ -167,13 +180,27 @@ get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, } static void +finalize (GObject *object) +{ + ExampleContactListProtocol *self = (ExampleContactListProtocol *) object; + + g_clear_pointer (&self->priv->params, g_ptr_array_unref); + + G_OBJECT_CLASS (example_contact_list_protocol_parent_class)->finalize (object); +} + +static void example_contact_list_protocol_class_init ( ExampleContactListProtocolClass *klass) { - TpBaseProtocolClass *base_class = - (TpBaseProtocolClass *) klass; + GObjectClass *oclass = (GObjectClass *) klass; + TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; + + g_type_class_add_private (klass, sizeof (ExampleContactListProtocolPrivate)); + + oclass->finalize = finalize; - base_class->get_parameters = get_parameters; + base_class->dup_parameters = dup_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; diff --git a/examples/cm/contactlist/protocol.h b/examples/cm/contactlist/protocol.h index 897f6e0..ceee4ab 100644 --- a/examples/cm/contactlist/protocol.h +++ b/examples/cm/contactlist/protocol.h @@ -21,13 +21,9 @@ typedef struct _ExampleContactListProtocolPrivate ExampleContactListProtocolPrivate; typedef struct _ExampleContactListProtocolClass ExampleContactListProtocolClass; -typedef struct _ExampleContactListProtocolClassPrivate - ExampleContactListProtocolClassPrivate; struct _ExampleContactListProtocolClass { TpBaseProtocolClass parent_class; - - ExampleContactListProtocolClassPrivate *priv; }; struct _ExampleContactListProtocol { diff --git a/examples/cm/echo-message-parts/protocol.c b/examples/cm/echo-message-parts/protocol.c index 5c1c294..b5a9054 100644 --- a/examples/cm/echo-message-parts/protocol.c +++ b/examples/cm/echo-message-parts/protocol.c @@ -16,6 +16,11 @@ #include "conn.h" #include "im-manager.h" +struct _ExampleEcho2ProtocolPrivate +{ + GPtrArray *params; +}; + static void addressing_iface_init (TpProtocolAddressingInterface *iface); G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Protocol, example_echo_2_protocol, @@ -42,23 +47,28 @@ static void example_echo_2_protocol_init ( ExampleEcho2Protocol *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_ECHO_2_PROTOCOL, + ExampleEcho2ProtocolPrivate); } -static const TpCMParamSpec example_echo_2_example_params[] = { - { "account", "s", G_TYPE_STRING, - TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, - NULL, /* no default */ - 0, /* formerly struct offset, now unused */ - tp_cm_param_filter_string_nonempty, /* filter - empty strings disallowed */ - NULL, /* filter data, unused for our filter */ - NULL /* setter data, now unused */ }, - { NULL } -}; - -static const TpCMParamSpec * -get_parameters (TpBaseProtocol *self) +static GPtrArray * +dup_parameters (TpBaseProtocol *base) { - return example_echo_2_example_params; + ExampleEcho2Protocol *self = (ExampleEcho2Protocol *) base; + + if (self->priv->params == NULL) + { + self->priv->params = g_ptr_array_new_full (1, + (GDestroyNotify) tp_cm_param_spec_unref); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("account", + TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, + g_variant_new_string (""), + tp_cm_param_filter_string_nonempty, NULL, NULL)); + } + + return g_ptr_array_ref (self->priv->params); } static TpBaseConnection * @@ -282,13 +292,27 @@ normalize_contact_uri (TpBaseProtocol *self, } static void +finalize (GObject *object) +{ + ExampleEcho2Protocol *self = (ExampleEcho2Protocol *) object; + + g_clear_pointer (&self->priv->params, g_ptr_array_unref); + + G_OBJECT_CLASS (example_echo_2_protocol_parent_class)->finalize (object); +} + +static void example_echo_2_protocol_class_init ( ExampleEcho2ProtocolClass *klass) { - TpBaseProtocolClass *base_class = - (TpBaseProtocolClass *) klass; + GObjectClass *oclass = (GObjectClass *) klass; + TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; + + g_type_class_add_private (klass, sizeof (ExampleEcho2ProtocolPrivate)); + + oclass->finalize = finalize; - base_class->get_parameters = get_parameters; + base_class->dup_parameters = dup_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; diff --git a/examples/cm/echo-message-parts/protocol.h b/examples/cm/echo-message-parts/protocol.h index 50f922f..5053bf1 100644 --- a/examples/cm/echo-message-parts/protocol.h +++ b/examples/cm/echo-message-parts/protocol.h @@ -21,13 +21,9 @@ typedef struct _ExampleEcho2ProtocolPrivate ExampleEcho2ProtocolPrivate; typedef struct _ExampleEcho2ProtocolClass ExampleEcho2ProtocolClass; -typedef struct _ExampleEcho2ProtocolClassPrivate - ExampleEcho2ProtocolClassPrivate; struct _ExampleEcho2ProtocolClass { TpBaseProtocolClass parent_class; - - ExampleEcho2ProtocolClassPrivate *priv; }; struct _ExampleEcho2Protocol { diff --git a/examples/cm/extended/protocol.c b/examples/cm/extended/protocol.c index 66ebcac..65cad5f 100644 --- a/examples/cm/extended/protocol.c +++ b/examples/cm/extended/protocol.c @@ -17,6 +17,11 @@ #include "conn.h" +struct _ExampleExtendedProtocolPrivate +{ + GPtrArray *params; +}; + G_DEFINE_TYPE (ExampleExtendedProtocol, example_extended_protocol, TP_TYPE_BASE_PROTOCOL) @@ -25,23 +30,28 @@ static void example_extended_protocol_init ( ExampleExtendedProtocol *self) { + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EXAMPLE_TYPE_EXTENDED_PROTOCOL, + ExampleExtendedProtocolPrivate); } -static const TpCMParamSpec example_extended_example_params[] = { - { "account", "s", G_TYPE_STRING, - TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, - NULL, /* no default */ - 0, /* formerly struct offset, now unused */ - tp_cm_param_filter_string_nonempty, /* filter - empty strings disallowed */ - NULL, /* filter data, unused for our filter */ - NULL /* setter data, now unused */ }, - { NULL } -}; - -static const TpCMParamSpec * -get_parameters (TpBaseProtocol *self) +static GPtrArray * +dup_parameters (TpBaseProtocol *base) { - return example_extended_example_params; + ExampleExtendedProtocol *self = (ExampleExtendedProtocol *) base; + + if (self->priv->params == NULL) + { + self->priv->params = g_ptr_array_new_full (1, + (GDestroyNotify) tp_cm_param_spec_unref); + + g_ptr_array_add (self->priv->params, + tp_cm_param_spec_new ("account", + TP_CONN_MGR_PARAM_FLAG_REQUIRED | TP_CONN_MGR_PARAM_FLAG_REGISTER, + g_variant_new_string (""), + tp_cm_param_filter_string_nonempty, NULL, NULL)); + } + + return g_ptr_array_ref (self->priv->params); } static TpBaseConnection * @@ -151,13 +161,27 @@ get_connection_details (TpBaseProtocol *self G_GNUC_UNUSED, } static void +finalize (GObject *object) +{ + ExampleExtendedProtocol *self = (ExampleExtendedProtocol *) object; + + g_clear_pointer (&self->priv->params, g_ptr_array_unref); + + G_OBJECT_CLASS (example_extended_protocol_parent_class)->finalize (object); +} + +static void example_extended_protocol_class_init ( ExampleExtendedProtocolClass *klass) { - TpBaseProtocolClass *base_class = - (TpBaseProtocolClass *) klass; + GObjectClass *oclass = (GObjectClass *) klass; + TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass; + + g_type_class_add_private (klass, sizeof (ExampleExtendedProtocolPrivate)); + + oclass->finalize = finalize; - base_class->get_parameters = get_parameters; + base_class->dup_parameters = dup_parameters; base_class->new_connection = new_connection; base_class->normalize_contact = normalize_contact; diff --git a/examples/cm/extended/protocol.h b/examples/cm/extended/protocol.h index 80a3cfb..fb13dc8 100644 --- a/examples/cm/extended/protocol.h +++ b/examples/cm/extended/protocol.h @@ -18,13 +18,9 @@ G_BEGIN_DECLS typedef struct _ExampleExtendedProtocol ExampleExtendedProtocol; typedef struct _ExampleExtendedProtocolPrivate ExampleExtendedProtocolPrivate; typedef struct _ExampleExtendedProtocolClass ExampleExtendedProtocolClass; -typedef struct _ExampleExtendedProtocolClassPrivate - ExampleExtendedProtocolClassPrivate; struct _ExampleExtendedProtocolClass { TpBaseProtocolClass parent_class; - - ExampleExtendedProtocolClassPrivate *priv; }; struct _ExampleExtendedProtocol { diff --git a/telepathy-glib/base-connection-manager.c b/telepathy-glib/base-connection-manager.c index 97a6991..51d845a 100644 --- a/telepathy-glib/base-connection-manager.c +++ b/telepathy-glib/base-connection-manager.c @@ -51,33 +51,6 @@ #include "telepathy-glib/debug-internal.h" /** - * TpCMProtocolSpec: - * @name: The name which should be passed to RequestConnection for this - * protocol. - * @parameters: An array of #TpCMParamSpec representing the valid parameters - * for this protocol, terminated by a #TpCMParamSpec whose name - * entry is NULL. - * @params_new: A function which allocates an opaque data structure to store - * the parsed parameters for this protocol. The offset fields - * in the members of the @parameters array refer to offsets - * within this opaque structure. - * @params_free: A function which deallocates the opaque data structure - * provided by #params_new, including deallocating its - * data members (currently, only strings) if necessary. - * @set_param: A function which sets a parameter within the opaque data - * structure provided by #params_new. If %NULL, - * tp_cm_param_setter_offset() will be used. (New in 0.7.0 - - * previously, code equivalent to tp_cm_param_setter_offset() was - * always used.) - * - * Structure representing a connection manager protocol. - * - * In addition to the fields documented here, there are three gpointer fields - * which must currently be %NULL. A meaning may be defined for these in a - * future version of telepathy-glib. - */ - -/** * TpBaseConnectionManager: * * A base class for connection managers. There are no interesting public @@ -534,191 +507,6 @@ tp_base_connection_manager_get_protocol (TpBaseConnectionManager *self, } /** - * tp_cm_param_setter_offset: - * @paramspec: A parameter specification with offset set to some - * meaningful value. - * @value: The value for that parameter, either provided by the user or - * constructed from the parameter's default. - * @params: An opaque data structure such that the address at (@params + - * @paramspec->offset) is a valid pointer to a variable of the - * appropriate type. - * - * A #TpCMParamSetter which sets parameters by dereferencing an offset - * from @params. If @paramspec->offset is G_MAXSIZE, the parameter is - * deemed obsolete, and is accepted but ignored. - * - * Since: 0.7.0 - */ -void -tp_cm_param_setter_offset (const TpCMParamSpec *paramspec, - const GValue *value, - gpointer params) -{ - char *params_mem = params; - - if (paramspec->offset == G_MAXSIZE) - { - /* quietly ignore any obsolete params provided */ - return; - } - - switch (paramspec->dtype[0]) - { - case DBUS_TYPE_STRING: - { - gchar **save_to = (gchar **) (params_mem + paramspec->offset); - const gchar *str; - - g_assert (paramspec->gtype == G_TYPE_STRING); - str = g_value_get_string (value); - g_free (*save_to); - if (str == NULL) - { - *save_to = g_strdup (""); - } - else - { - *save_to = g_value_dup_string (value); - } - if (DEBUGGING) - { - if (strstr (paramspec->name, "password") != NULL) - DEBUG ("%s = ", paramspec->name); - else - DEBUG ("%s = \"%s\"", paramspec->name, *save_to); - } - } - break; - - case DBUS_TYPE_INT16: - case DBUS_TYPE_INT32: - { - gint *save_to = (gint *) (params_mem + paramspec->offset); - gint i = g_value_get_int (value); - - g_assert (paramspec->gtype == G_TYPE_INT); - *save_to = i; - DEBUG ("%s = %d = 0x%x", paramspec->name, i, i); - } - break; - - case DBUS_TYPE_UINT16: - case DBUS_TYPE_UINT32: - { - guint *save_to = (guint *) (params_mem + paramspec->offset); - guint i = g_value_get_uint (value); - - g_assert (paramspec->gtype == G_TYPE_UINT); - *save_to = i; - DEBUG ("%s = %u = 0x%x", paramspec->name, i, i); - } - break; - - case DBUS_TYPE_INT64: - { - gint64 *save_to = (gint64 *) (params_mem + paramspec->offset); - gint64 i = g_value_get_int64 (value); - - g_assert (paramspec->gtype == G_TYPE_INT64); - *save_to = i; - DEBUG ("%s = %" G_GINT64_FORMAT, paramspec->name, i); - } - break; - - case DBUS_TYPE_UINT64: - { - guint64 *save_to = (guint64 *) (params_mem + paramspec->offset); - guint64 i = g_value_get_uint64 (value); - - g_assert (paramspec->gtype == G_TYPE_UINT64); - *save_to = i; - DEBUG ("%s = %" G_GUINT64_FORMAT, paramspec->name, i); - } - break; - - case DBUS_TYPE_DOUBLE: - { - gdouble *save_to = (gdouble *) (params_mem + paramspec->offset); - gdouble i = g_value_get_double (value); - - g_assert (paramspec->gtype == G_TYPE_DOUBLE); - *save_to = i; - DEBUG ("%s = %f", paramspec->name, i); - } - break; - - case DBUS_TYPE_OBJECT_PATH: - { - gchar **save_to = (gchar **) (params_mem + paramspec->offset); - - g_assert (paramspec->gtype == DBUS_TYPE_G_OBJECT_PATH); - g_free (*save_to); - - *save_to = g_value_dup_boxed (value); - DEBUG ("%s = \"%s\"", paramspec->name, *save_to); - } - break; - - case DBUS_TYPE_BOOLEAN: - { - gboolean *save_to = (gboolean *) (params_mem + paramspec->offset); - gboolean b = g_value_get_boolean (value); - - g_assert (paramspec->gtype == G_TYPE_BOOLEAN); - g_assert (b == TRUE || b == FALSE); - *save_to = b; - DEBUG ("%s = %s", paramspec->name, b ? "TRUE" : "FALSE"); - } - break; - - case DBUS_TYPE_ARRAY: - switch (paramspec->dtype[1]) - { - case DBUS_TYPE_STRING: - { - GStrv *save_to = (GStrv *) (params_mem + paramspec->offset); - - g_strfreev (*save_to); - *save_to = g_value_dup_boxed (value); - - if (DEBUGGING) - { - gchar *joined = g_strjoinv (", ", *save_to); - - DEBUG ("%s = [%s]", paramspec->name, joined); - g_free (joined); - } - } - break; - - case DBUS_TYPE_BYTE: - { - GArray **save_to = (GArray **) (params_mem + paramspec->offset); - - if (*save_to != NULL) - { - g_array_unref (*save_to); - } - *save_to = g_value_dup_boxed (value); - DEBUG ("%s = ...[%u]", paramspec->name, (*save_to)->len); - } - break; - - default: - ERROR ("encountered unhandled D-Bus array type %s on " - "argument %s", paramspec->dtype, paramspec->name); - g_assert_not_reached (); - } - break; - - default: - ERROR ("encountered unhandled D-Bus type %s on argument %s", - paramspec->dtype, paramspec->name); - g_assert_not_reached (); - } -} - -/** * tp_base_connection_manager_request_connection * * Implements D-Bus method RequestConnection diff --git a/telepathy-glib/base-connection-manager.h b/telepathy-glib/base-connection-manager.h index 1c57494..0fae8e4 100644 --- a/telepathy-glib/base-connection-manager.h +++ b/telepathy-glib/base-connection-manager.h @@ -35,22 +35,6 @@ G_BEGIN_DECLS -void tp_cm_param_setter_offset (const TpCMParamSpec *paramspec, - const GValue *value, gpointer params); - -typedef struct { - const gchar *name; - const TpCMParamSpec *parameters; - gpointer (*params_new) (void); - void (*params_free) (gpointer); - TpCMParamSetter set_param; - - /**/ - gpointer _future1; - gpointer _future2; - gpointer _future3; -} TpCMProtocolSpec; - typedef struct _TpBaseConnectionManager TpBaseConnectionManager; typedef struct _TpBaseConnectionManagerPrivate TpBaseConnectionManagerPrivate; typedef struct _TpBaseConnectionManagerClass TpBaseConnectionManagerClass; diff --git a/telepathy-glib/base-protocol.c b/telepathy-glib/base-protocol.c index e62aa2f..b6071b3 100644 --- a/telepathy-glib/base-protocol.c +++ b/telepathy-glib/base-protocol.c @@ -43,229 +43,185 @@ /** * TpCMParamSpec: * @name: Name as passed over D-Bus - * @dtype: D-Bus type signature. We currently support 16- and 32-bit integers - * (@gtype is INT), 16- and 32-bit unsigned integers (gtype is UINT), - * strings (gtype is STRING) and booleans (gtype is BOOLEAN). - * @gtype: GLib type, derived from @dtype as above + * @dtype: D-Bus type signature. * @flags: Some combination of #TpConnMgrParamFlags - * @def: Default value, as a (const gchar *) for string parameters, or - using #GINT_TO_POINTER or #GUINT_TO_POINTER for integer parameters - * @offset: Offset of the parameter in the opaque data structure, if - * appropriate. The member at that offset is expected to be a gint, - * guint, (gchar *) or gboolean, depending on @gtype. The default - * parameter setter, #tp_cm_param_setter_offset, uses this field. - * @filter: A callback which is used to validate or normalize the user-provided - * value before it is written into the opaque data structure - * @filter_data: Arbitrary opaque data intended for use by the filter function - * @setter_data: Arbitrary opaque data intended for use by the setter function - * instead of or in addition to @offset. + * @def: Default value, as a #GVariant * * Structure representing a connection manager parameter, as accepted by * RequestConnection. - * - * In addition to the fields documented here, there is one gpointer field - * which must currently be %NULL. A meaning may be defined for it in a - * future version of telepathy-glib. */ /** * TpCMParamFilter: - * @paramspec: The parameter specification. The filter is likely to use - * name (for the error message if the value is invalid) and filter_data. - * @value: The value for that parameter provided by the user. - * May be changed to contain a different value of the same type, if - * some sort of normalization is required + * @paramspec: The parameter specification. + * @value: (transfer full): A #GVariant containing the value for that parameter + * provided by the user. + * @user_data: data passed to tp_cm_param_spec_new() * @error: Used to raise %TP_ERROR_INVALID_ARGUMENT if the given value is * rejected * * Signature of a callback used to validate and/or normalize user-provided * CM parameter values. * - * Returns: %TRUE to accept, %FALSE (with @error set) to reject - */ - -/** - * TpCMParamSetter: - * @paramspec: The parameter specification. The setter is likely to use - * some combination of the name, offset and setter_data fields. - * @value: The value for that parameter provided by the user. - * @params: An opaque data structure, created by - * #TpCMProtocolSpec.params_new. - * - * The signature of a callback used to set a parameter within the opaque - * data structure used for a protocol. + * The callback is responsible of unreffing @value if it returns %NULL or + * another #GVariant. * - * Since: 0.7.0 + * Returns: (transfer full): @value or another floating #GVariant of the same + * type to accept, %NULL (with @error set) to reject */ -static GValue * -param_default_value (const TpCMParamSpec *param) -{ - GValue *value; - - value = tp_g_value_slice_new (param->gtype); - - /* If HAS_DEFAULT is false, we don't really care what the value is, so we'll - * just use whatever's in the user-supplied param spec. As long as we're - * careful to accept NULL, that should be fine. */ - - switch (param->dtype[0]) - { - case DBUS_TYPE_STRING: - g_assert (param->gtype == G_TYPE_STRING); - if (param->def == NULL) - g_value_set_static_string (value, ""); - else - g_value_set_static_string (value, param->def); - break; - - case DBUS_TYPE_INT16: - case DBUS_TYPE_INT32: - g_assert (param->gtype == G_TYPE_INT); - g_value_set_int (value, GPOINTER_TO_INT (param->def)); - break; - - case DBUS_TYPE_UINT16: - case DBUS_TYPE_UINT32: - g_assert (param->gtype == G_TYPE_UINT); - g_value_set_uint (value, GPOINTER_TO_UINT (param->def)); - break; - - case DBUS_TYPE_UINT64: - g_assert (param->gtype == G_TYPE_UINT64); - g_value_set_uint64 (value, param->def == NULL ? 0 - : *(const guint64 *) param->def); - break; - - case DBUS_TYPE_INT64: - g_assert (param->gtype == G_TYPE_INT64); - g_value_set_int64 (value, param->def == NULL ? 0 - : *(const gint64 *) param->def); - break; - - case DBUS_TYPE_DOUBLE: - g_assert (param->gtype == G_TYPE_DOUBLE); - g_value_set_double (value, param->def == NULL ? 0.0 - : *(const double *) param->def); - break; - - case DBUS_TYPE_OBJECT_PATH: - g_assert (param->gtype == DBUS_TYPE_G_OBJECT_PATH); - g_value_set_static_boxed (value, param->def == NULL ? "/" - : param->def); - break; - - case DBUS_TYPE_ARRAY: - switch (param->dtype[1]) - { - case DBUS_TYPE_STRING: - g_assert (param->gtype == G_TYPE_STRV); - g_value_set_static_boxed (value, param->def); - break; - - case DBUS_TYPE_BYTE: - g_assert (param->gtype == DBUS_TYPE_G_UCHAR_ARRAY); - if (param->def == NULL) - { - GArray *array = g_array_new (FALSE, FALSE, sizeof (guint8)); - g_value_take_boxed (value, array); - } - else - { - g_value_set_static_boxed (value, param->def); - } - break; - - default: - ERROR ("encountered unknown type %s on argument %s", - param->dtype, param->name); - } - break; - - case DBUS_TYPE_BOOLEAN: - g_assert (param->gtype == G_TYPE_BOOLEAN); - g_value_set_boolean (value, GPOINTER_TO_INT (param->def)); - break; - - default: - ERROR ("encountered unknown type %s on argument %s", - param->dtype, param->name); - } - - return value; -} - -GValueArray * -_tp_cm_param_spec_to_dbus (const TpCMParamSpec *paramspec) -{ - GValueArray *susv; - GValue *value = param_default_value (paramspec); - - susv = tp_value_array_build (4, - G_TYPE_STRING, paramspec->name, - G_TYPE_UINT, paramspec->flags, - G_TYPE_STRING, paramspec->dtype, - G_TYPE_VALUE, value, - G_TYPE_INVALID); - - tp_g_value_slice_free (value); - - return susv; -} - /** * tp_cm_param_filter_uint_nonzero: * @paramspec: The parameter specification for a guint parameter - * @value: A GValue containing a guint, which will not be altered + * @value: (transfer full): A #GVariant containing a guint32 + * @user_data: unused * @error: Used to return an error if the guint is 0 * * A #TpCMParamFilter which rejects zero, useful for server port numbers. * - * Returns: %TRUE to accept, %FALSE (with @error set) to reject + * Returns: (transfer full): @value to accept, %NULL (with @error set) to reject */ -gboolean +GVariant * tp_cm_param_filter_uint_nonzero (const TpCMParamSpec *paramspec, - GValue *value, + GVariant *value, + gpointer user_data, GError **error) { - if (g_value_get_uint (value) == 0) + if (g_variant_get_uint32 (value) == 0) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account parameter '%s' may not be set to zero", paramspec->name); - return FALSE; + g_variant_unref (value); + return NULL; } - return TRUE; + return value; } /** * tp_cm_param_filter_string_nonempty: * @paramspec: The parameter specification for a string parameter - * @value: A GValue containing a string, which will not be altered + * @value: (transfer full): A GVariant containing a string + * @user_data: unused * @error: Used to return an error if the string is empty * * A #TpCMParamFilter which rejects empty strings. * - * Returns: %TRUE to accept, %FALSE (with @error set) to reject + * Returns: (transfer full): @value to accept, %NULL (with @error set) to reject */ -gboolean +GVariant * tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, - GValue *value, + GVariant *value, + gpointer user_data, GError **error) { - const gchar *str = g_value_get_string (value); + const gchar *str = g_variant_get_string (value, NULL); - if (str == NULL || str[0] == '\0') + if (tp_str_empty (str)) { g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "Account parameter '%s' may not be set to an empty string", paramspec->name); - return FALSE; + g_variant_unref (value); + return NULL; } - return TRUE; + return value; +} + + +/** + * tp_cm_param_spec_new: + * @name: The parameter's name + * @flags: #TpConnMgrParamFlags + * @def: A #GVariant for the default value + * @filter: (allow-none) (scope notified): A filter function to validate + * parameter's value + * @user_data: (allow-none): data to pass to @filter + * @destroy: (allow-none): called with @user_data as its argument when the + * #TpCMParamSpec is freed. + * + * Create a new #TpCMParamSpec. @def must not be %NULL even if + * %TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT is not set, in which case any dummy value + * of the desired type is fine. If @def is floating, it is consumed. + * + * Returns: (transfer full): a new #TpCMParamSpec + * Since: 0.UNRELEASED + */ +TpCMParamSpec * +tp_cm_param_spec_new (const gchar *name, + TpConnMgrParamFlags flags, + GVariant *def, + TpCMParamFilter filter, + gpointer user_data, + GDestroyNotify destroy) +{ + TpCMParamSpec *self; + + g_return_val_if_fail (!tp_str_empty (name), NULL); + g_return_val_if_fail (def != NULL, NULL); + + self = g_slice_new0 (TpCMParamSpec); + self->name = g_strdup (name); + self->dtype = g_variant_get_type_string (def); + self->flags = flags; + self->def = g_variant_ref_sink (def); + + self->filter = filter; + self->user_data = user_data; + self->destroy = destroy; + + self->ref_count = 1; + + return self; } /** + * tp_cm_param_spec_ref: + * @self: a #TpCMParamSpec + * + * Increment @self's ref count. + * + * Returns: (transfer full): @self + * Since: 0.UNRELEASED + */ +TpCMParamSpec * +tp_cm_param_spec_ref (TpCMParamSpec *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + g_atomic_int_inc (&self->ref_count); + + return self; +} + +/** + * tp_cm_param_spec_unref: + * @self: a #TpCMParamSpec + * + * Unref @self and free it if ref count reach 0. + * + * Since: 0.UNRELEASED + */ +void +tp_cm_param_spec_unref (TpCMParamSpec *self) +{ + g_return_if_fail (self != NULL); + + if (g_atomic_int_dec_and_test (&self->ref_count)) + { + if (self->destroy != NULL) + self->destroy (self->user_data); + g_free (self->name); + g_variant_unref (self->def); + g_slice_free (TpCMParamSpec, self); + } +} + +G_DEFINE_BOXED_TYPE (TpCMParamSpec, tp_cm_param_spec, + tp_cm_param_spec_ref, + tp_cm_param_spec_unref) + +/** * SECTION:base-protocol * @title: TpBaseProtocol * @short_description: base class for #TpSvcProtocol implementations @@ -286,18 +242,17 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, */ /** - * TpBaseProtocolGetParametersFunc: + * TpBaseProtocolDupParametersFunc: * @self: a protocol * * Signature of a virtual method to get the allowed parameters for connections * to a protocol. * - * Returns the parameters supported by this protocol, as an array of structs - * which must remain valid at least as long as @self exists (it will typically - * be a global static array). + * Returns the parameters supported by this protocol, as an array of + * #TpCMParamSpec* which must remain valid at least as long as @self exists. * - * Returns: (transfer none) (array zero-terminated=1): a description of the - * parameters supported by this protocol + * Returns: (transfer container) (element-type TelepathyGLib.CMParamSpec): a + * description of the parameters supported by this protocol * * Since: 0.11.11 */ @@ -314,7 +269,7 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, * * Implementations of #TpBaseProtocolClass.new_connection may assume that * the parameters in @asv conform to the specifications given by - * #TpBaseProtocolClass.get_parameters. + * #TpBaseProtocolClass.dup_parameters. * * Returns: (transfer full): a new connection, or %NULL on error * @@ -349,7 +304,7 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, * * Implementations of #TpBaseProtocolClass.identify_account may assume that * the parameters in @asv conform to the specifications given by - * #TpBaseProtocolClass.get_parameters. + * #TpBaseProtocolClass.dup_parameters. * * Returns: (transfer full): a unique name for the account, or %NULL on error * @@ -441,7 +396,7 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, * Signature of a virtual method to get the supported vCard fields supported by * #self. * - * Returns: (allow-none) (out) (transfer full): a list of vCard fields in lower + * Returns: (allow-none) (transfer full): a list of vCard fields in lower * case, e.g. [x-sip, tel] * * Since: 0.17.2 @@ -454,7 +409,7 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, * Signature of a virtual method to get the supported URI schemes supported by * #self. * - * Returns: (allow-none) (out) (transfer full): a list of uri schemes, e.g. [sip, sips, tel] + * Returns: (allow-none) (transfer full): a list of uri schemes, e.g. [sip, sips, tel] * * Since: 0.17.2 */ @@ -496,9 +451,9 @@ tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, * @parent_class: the parent class * @is_stub: if %TRUE, this protocol will not be advertised on D-Bus (for * internal use by #TpBaseConnection) - * @get_parameters: a callback used to implement - * tp_base_protocol_get_parameters(), which all subclasses must provide; - * see the documentation of that method for details + * @dup_parameters: a callback used to implement + * tp_base_protocol_dup_parameters(), which all subclasses must provide; see + * the documentation of that method for details * @new_connection: a callback used to implement * tp_base_protocol_new_connection(), which all subclasses must provide; * see the documentation of that method for details @@ -759,9 +714,9 @@ tp_base_protocol_get_name (TpBaseProtocol *self) * Note that in particular, tp_asv_set_string() and similar functions should * not be used with this hash table. * - * Returns: a hash table mapping (gchar *) fully-qualified property names to - * GValues, which must be freed by the caller (at which point its - * contents will also be freed). + * Returns: (transfer container): a hash table mapping (gchar *) fully-qualified + * property names to GValues, which must be freed by the caller (at which point + * its contents will also be freed). * * Since: 0.11.11 */ @@ -1068,17 +1023,26 @@ protocol_properties_getter (GObject *object, { case PP_PARAMETERS: { - GPtrArray *ret = g_ptr_array_new (); - const TpCMParamSpec *parameter; + GVariantBuilder builder; + GVariant *variant; + GPtrArray *parameters; + guint i; - for (parameter = tp_base_protocol_get_parameters (self); - parameter->name != NULL; - parameter++) + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(susv)")); + parameters = tp_base_protocol_dup_parameters (self); + for (i = 0; i < parameters->len; i++) { - g_ptr_array_add (ret, _tp_cm_param_spec_to_dbus (parameter)); + TpCMParamSpec *param = g_ptr_array_index (parameters, i); + + g_variant_builder_add (&builder, "(susv)", param->name, + param->flags, param->dtype, param->def); } + g_ptr_array_unref (parameters); - g_value_take_boxed (value, ret); + variant = g_variant_ref_sink (g_variant_builder_end (&builder)); + g_value_unset (value); + dbus_g_value_parse_g_variant (variant, value); + g_variant_unref (variant); } break; @@ -1260,43 +1224,45 @@ tp_base_protocol_get_statuses (TpBaseProtocol *self) } /** - * tp_base_protocol_get_parameters: + * tp_base_protocol_dup_parameters: * @self: a Protocol object * * Returns the parameters supported by this protocol, as an array of structs * which must remain valid at least as long as @self exists (it will typically * be a global static array). * - * Returns: (transfer none) (array zero-terminated=1): a description of the - * parameters supported by this protocol + * Returns: (transfer container) (element-type TelepathyGLib.CMParamSpec): a + * description of the parameters supported by this protocol * * Since: 0.11.11 */ -const TpCMParamSpec * -tp_base_protocol_get_parameters (TpBaseProtocol *self) +GPtrArray * +tp_base_protocol_dup_parameters (TpBaseProtocol *self) { TpBaseProtocolClass *cls = TP_BASE_PROTOCOL_GET_CLASS (self); g_return_val_if_fail (cls != NULL, NULL); - g_return_val_if_fail (cls->get_parameters != NULL, NULL); + g_return_val_if_fail (cls->dup_parameters != NULL, NULL); - return cls->get_parameters (self); + return cls->dup_parameters (self); } static gboolean -_tp_cm_param_spec_check_all_allowed (const TpCMParamSpec *parameters, +_tp_cm_param_spec_check_all_allowed (GPtrArray *parameters, GHashTable *asv, GError **error) { GHashTable *tmp = g_hash_table_new (g_str_hash, g_str_equal); - const TpCMParamSpec *iter; + guint i; gboolean ret = TRUE; tp_g_hash_table_update (tmp, asv, NULL, NULL); - for (iter = parameters; iter->name != NULL; iter++) + for (i = 0; i < parameters->len; i++) { - g_hash_table_remove (tmp, iter->name); + TpCMParamSpec *param = g_ptr_array_index (parameters, i); + + g_hash_table_remove (tmp, param->name); } if (g_hash_table_size (tmp) != 0) @@ -1328,189 +1294,20 @@ _tp_cm_param_spec_check_all_allowed (const TpCMParamSpec *parameters, return ret; } -static GValue * -_tp_cm_param_spec_coerce (const TpCMParamSpec *param_spec, - GHashTable *asv, - GError **error) -{ - const gchar *name = param_spec->name; - const GValue *value = tp_asv_lookup (asv, name); - - if (tp_asv_lookup (asv, name) == NULL) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s not found in parameters", name); - return NULL; - } - - switch (param_spec->dtype[0]) - { - case DBUS_TYPE_BOOLEAN: - case DBUS_TYPE_OBJECT_PATH: - case DBUS_TYPE_STRING: - case DBUS_TYPE_ARRAY: - { - /* These types only accept an exactly-matching GType. */ - - if (G_VALUE_TYPE (value) != param_spec->gtype) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s has type %s, but %s was expected", - name, G_VALUE_TYPE_NAME (value), - g_type_name (param_spec->gtype)); - return NULL; - } - - return tp_g_value_slice_dup (value); - } - - case DBUS_TYPE_INT16: - case DBUS_TYPE_INT32: - { - /* Coerce any sensible integer to G_TYPE_INT */ - gboolean valid; - gint i; - - i = tp_asv_get_int32 (asv, name, &valid); - - if (!valid) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s has a non-integer type or is out of range (type=%s)", - name, G_VALUE_TYPE_NAME (value)); - return NULL; - } - - if (param_spec->dtype[0] == DBUS_TYPE_INT16 && - (i < -0x8000 || i > 0x7fff)) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s is out of range for a 16-bit signed integer", name); - return NULL; - } - - return tp_g_value_slice_new_int (i); - } - - case DBUS_TYPE_BYTE: - case DBUS_TYPE_UINT16: - case DBUS_TYPE_UINT32: - { - /* Coerce any sensible integer to G_TYPE_UINT */ - gboolean valid; - guint i; - - i = tp_asv_get_uint32 (asv, name, &valid); - - if (!valid) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s has a non-integer type or is out of range (type=%s)", - name, G_VALUE_TYPE_NAME (value)); - return NULL; - } - - if (param_spec->dtype[0] == DBUS_TYPE_BYTE && i > 0xff) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s is out of range for a byte", name); - return NULL; - } - - if (param_spec->dtype[0] == DBUS_TYPE_UINT16 && i > 0xffff) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s is out of range for a 16-bit unsigned integer", name); - return NULL; - } - - if (param_spec->dtype[0] == DBUS_TYPE_BYTE) - return tp_g_value_slice_new_byte (i); - else - return tp_g_value_slice_new_uint (i); - } - - case DBUS_TYPE_INT64: - { - /* Coerce any sensible integer to G_TYPE_INT64 */ - gboolean valid; - gint64 i; - - i = tp_asv_get_int64 (asv, name, &valid); - - if (!valid) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s is not a valid 64-bit signed integer (type=%s)", name, - G_VALUE_TYPE_NAME (value)); - return NULL; - } - - return tp_g_value_slice_new_int64 (i); - } - - case DBUS_TYPE_UINT64: - { - /* Coerce any sensible integer to G_TYPE_UINT64 */ - gboolean valid; - guint64 i; - - i = tp_asv_get_uint64 (asv, name, &valid); - - if (!valid) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s is not a valid 64-bit unsigned integer (type=%s)", name, - G_VALUE_TYPE_NAME (value)); - return NULL; - } - - return tp_g_value_slice_new_uint64 (i); - } - - case DBUS_TYPE_DOUBLE: - { - /* Coerce any sensible number to G_TYPE_DOUBLE */ - gboolean valid; - gdouble d; - - d = tp_asv_get_double (asv, name, &valid); - - if (!valid) - { - g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, - "%s is not a valid double (type=%s)", name, - G_VALUE_TYPE_NAME (value)); - return NULL; - } - - return tp_g_value_slice_new_double (d); - } - - default: - { - g_error ("%s: encountered unhandled D-Bus type %s on argument %s", - G_STRFUNC, param_spec->dtype, param_spec->name); - } - } - - g_assert_not_reached (); -} - static GHashTable * tp_base_protocol_sanitize_parameters (TpBaseProtocol *self, GHashTable *asv, GError **error) { + GVariantBuilder builder; + GVariant *combined_variant; GHashTable *combined; - const TpCMParamSpec *parameters; + GPtrArray *parameters; guint i; guint mandatory_flag; - parameters = tp_base_protocol_get_parameters (self); - - combined = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify) tp_g_value_slice_free); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + parameters = tp_base_protocol_dup_parameters (self); if (!_tp_cm_param_spec_check_all_allowed (parameters, asv, error)) goto except; @@ -1524,45 +1321,44 @@ tp_base_protocol_sanitize_parameters (TpBaseProtocol *self, mandatory_flag = TP_CONN_MGR_PARAM_FLAG_REQUIRED; } - for (i = 0; parameters[i].name != NULL; i++) + for (i = 0; i < parameters->len; i++) { - const gchar *name = parameters[i].name; + TpCMParamSpec *param = g_ptr_array_index (parameters, i); + const gchar *name = param->name; + const GValue *value = tp_asv_lookup (asv, name); - if (tp_asv_lookup (asv, name) != NULL) + if (value != NULL) { + GVariant *coerced; + /* coerce to the expected type */ - GValue *coerced = _tp_cm_param_spec_coerce (parameters + i, asv, - error); + coerced = tp_variant_convert (dbus_g_value_build_g_variant (value), + G_VARIANT_TYPE (param->dtype)); if (coerced == NULL) goto except; - if (G_UNLIKELY (G_VALUE_TYPE (coerced) != parameters[i].gtype)) - { - g_error ("parameter %s should have been coerced to %s, got %s", - name, g_type_name (parameters[i].gtype), - G_VALUE_TYPE_NAME (coerced)); - } - - if (parameters[i].filter != NULL) + if (param->filter != NULL) { GError *error2 = NULL; - if (!(parameters[i].filter (parameters + i, coerced, &error2))) + coerced = param->filter (param, coerced, param->user_data, + &error2); + + if (coerced == NULL) { DEBUG ("parameter %s rejected by filter: %s", name, error2->message); - tp_g_value_slice_free (coerced); g_propagate_error (error, error2); goto except; } - } - if (G_UNLIKELY (G_VALUE_TYPE (coerced) != parameters[i].gtype)) - { - g_error ("parameter %s filter changed its type from %s to %s", - name, g_type_name (parameters[i].gtype), - G_VALUE_TYPE_NAME (coerced)); + if (!g_variant_is_of_type (coerced, + G_VARIANT_TYPE (param->dtype))) + { + g_error ("parameter %s filter changed its type from %s to %s", + name, param->dtype, g_variant_get_type_string (coerced)); + } } if (DEBUGGING) @@ -1570,16 +1366,17 @@ tp_base_protocol_sanitize_parameters (TpBaseProtocol *self, gchar *to_free = NULL; const gchar *contents = ""; - if (!(parameters[i].flags & TP_CONN_MGR_PARAM_FLAG_SECRET)) - contents = to_free = g_strdup_value_contents (coerced); + if (!(param->flags & TP_CONN_MGR_PARAM_FLAG_SECRET)) + contents = to_free = g_variant_print (coerced, TRUE); DEBUG ("using specified value for %s: %s", name, contents); g_free (to_free); } - g_hash_table_insert (combined, g_strdup (name), coerced); + g_variant_builder_add (&builder, "{sv}", name, coerced); + g_variant_unref (coerced); } - else if ((parameters[i].flags & mandatory_flag) != 0) + else if ((param->flags & mandatory_flag) != 0) { DEBUG ("missing mandatory account parameter %s", name); g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT, @@ -1587,22 +1384,26 @@ tp_base_protocol_sanitize_parameters (TpBaseProtocol *self, name); goto except; } - else if ((parameters[i].flags & TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT) != 0) + else if ((param->flags & TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT) != 0) { - GValue *value = param_default_value (parameters + i); - - g_hash_table_insert (combined, g_strdup (name), value); + g_variant_builder_add (&builder, "{sv}", name, param->def); } else { /* no default */ } } + g_ptr_array_unref (parameters); + + combined_variant = g_variant_ref_sink (g_variant_builder_end (&builder)); + combined = tp_asv_from_vardict (combined_variant); + g_variant_unref (combined_variant); return combined; except: - g_hash_table_unref (combined); + g_ptr_array_unref (parameters); + g_variant_builder_clear (&builder); return NULL; } @@ -1613,11 +1414,11 @@ except: * provided via D-Bus * @error: used to return an error if %NULL is returned * - * Create a new connection using the #TpBaseProtocolClass.get_parameters and + * Create a new connection using the #TpBaseProtocolClass.dup_parameters and * #TpBaseProtocolClass.new_connection implementations provided by a subclass. * This is used to implement the RequestConnection() D-Bus method. * - * If the parameters in @asv do not fit the result of @get_parameters (unknown + * If the parameters in @asv do not fit the result of @dup_parameters (unknown * parameters are given, types are inappropriate, required parameters are * not given, or a #TpCMParamSpec.filter fails), then this method raises an * error and @new_connection is not called. @@ -1627,7 +1428,7 @@ except: * filled in where available, and parameters' types converted to the #GType * specified by #TpCMParamSpec.gtype. * - * Returns: a new connection, or %NULL on error + * Returns: (transfer full): a new connection, or %NULL on error * * Since: 0.11.11 */ diff --git a/telepathy-glib/base-protocol.h b/telepathy-glib/base-protocol.h index c00701d..316c83e 100644 --- a/telepathy-glib/base-protocol.h +++ b/telepathy-glib/base-protocol.h @@ -35,45 +35,43 @@ G_BEGIN_DECLS typedef struct _TpCMParamSpec TpCMParamSpec; -typedef void (*TpCMParamSetter) (const TpCMParamSpec *paramspec, - const GValue *value, gpointer params); +typedef GVariant *(*TpCMParamFilter) (const TpCMParamSpec *paramspec, + GVariant *value, gpointer user_data, GError **error); -typedef gboolean (*TpCMParamFilter) (const TpCMParamSpec *paramspec, - GValue *value, GError **error); +GVariant *tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, + GVariant *value, gpointer user_data, GError **error); -gboolean tp_cm_param_filter_string_nonempty (const TpCMParamSpec *paramspec, - GValue *value, GError **error); - -gboolean tp_cm_param_filter_uint_nonzero (const TpCMParamSpec *paramspec, - GValue *value, GError **error); - -/* XXX: This should be driven by GTypes, but the GType is insufficiently - * descriptive: if it's UINT we can't tell whether the D-Bus type is - * UInt32, UInt16 or possibly even Byte. So we have the D-Bus type too. - * - * As it stands at the moment it could be driven by the *D-Bus* type, but - * in future we may want to have more than one possible GType for a D-Bus - * type, e.g. converting arrays of string into either a strv or a GPtrArray. - * So, we keep the redundancy for future expansion. - */ +GVariant *tp_cm_param_filter_uint_nonzero (const TpCMParamSpec *paramspec, + GVariant *value, gpointer user_data, GError **error); struct _TpCMParamSpec { - const gchar *name; + gchar *name; const gchar *dtype; - GType gtype; - guint flags; - gconstpointer def; - gsize offset; + TpConnMgrParamFlags flags; + GVariant *def; - TpCMParamFilter filter; - gconstpointer filter_data; + /**/ + gpointer _future[5]; - gconstpointer setter_data; + TpCMParamFilter filter; + gpointer user_data; + GDestroyNotify destroy; - /**/ - gpointer _future1; + guint ref_count; }; +TpCMParamSpec *tp_cm_param_spec_new (const gchar *name, + TpConnMgrParamFlags flags, + GVariant *def, + TpCMParamFilter filter, + gpointer user_data, + GDestroyNotify destroy); +TpCMParamSpec *tp_cm_param_spec_ref (TpCMParamSpec *self); +void tp_cm_param_spec_unref (TpCMParamSpec *self); + +GType tp_cm_param_spec_get_type (void) G_GNUC_CONST; +#define TP_TYPE_CM_PARAM_SPEC (tp_cm_param_spec_get_type ()) + typedef struct _TpBaseProtocol TpBaseProtocol; typedef struct _TpBaseProtocolClass TpBaseProtocolClass; typedef struct _TpBaseProtocolPrivate TpBaseProtocolPrivate; @@ -104,8 +102,7 @@ struct _TpBaseProtocol TpBaseProtocolPrivate *priv; }; -typedef const TpCMParamSpec *(*TpBaseProtocolGetParametersFunc) ( - TpBaseProtocol *self); +typedef GPtrArray *(*TpBaseProtocolDupParametersFunc) (TpBaseProtocol *self); typedef TpBaseConnection *(*TpBaseProtocolNewConnectionFunc) ( TpBaseProtocol *self, @@ -142,24 +139,13 @@ struct _TpBaseProtocolClass GDBusObjectSkeletonClass parent_class; gboolean is_stub; - const TpCMParamSpec *(*get_parameters) (TpBaseProtocol *self); - TpBaseConnection *(*new_connection) (TpBaseProtocol *self, - GHashTable *asv, - GError **error); - - gchar *(*normalize_contact) (TpBaseProtocol *self, - const gchar *contact, - GError **error); - gchar *(*identify_account) (TpBaseProtocol *self, - GHashTable *asv, - GError **error); - - void (*get_connection_details) (TpBaseProtocol *self, - GStrv *connection_interfaces, - GType **channel_manager_types, - gchar **icon_name, - gchar **english_name, - gchar **vcard_field); + TpBaseProtocolDupParametersFunc dup_parameters; + TpBaseProtocolNewConnectionFunc new_connection; + + TpBaseProtocolNormalizeContactFunc normalize_contact; + TpBaseProtocolIdentifyAccountFunc identify_account; + + TpBaseProtocolGetConnectionDetailsFunc get_connection_details; const TpPresenceStatusSpec * (*get_statuses) (TpBaseProtocol *self); @@ -175,7 +161,7 @@ struct _TpBaseProtocolClass const gchar *tp_base_protocol_get_name (TpBaseProtocol *self); GHashTable *tp_base_protocol_get_immutable_properties (TpBaseProtocol *self); -const TpCMParamSpec *tp_base_protocol_get_parameters (TpBaseProtocol *self); +GPtrArray *tp_base_protocol_dup_parameters (TpBaseProtocol *self); const TpPresenceStatusSpec *tp_base_protocol_get_statuses (TpBaseProtocol *self); TpBaseConnection *tp_base_protocol_new_connection (TpBaseProtocol *self, @@ -196,6 +182,7 @@ TpBaseConnection *tp_base_protocol_new_connection (TpBaseProtocol *self, TP_TYPE_PROTOCOL_ADDRESSING, TpProtocolAddressingInterface)) typedef struct _TpProtocolAddressingInterface TpProtocolAddressingInterface; +typedef struct _TpProtocolAddressing TpProtocolAddressing; typedef GStrv (*TpBaseProtocolDupSupportedVCardFieldsFunc) (TpBaseProtocol *self); diff --git a/telepathy-glib/introspection.am b/telepathy-glib/introspection.am index ab0a5bf..d083bb8 100644 --- a/telepathy-glib/introspection.am +++ b/telepathy-glib/introspection.am @@ -59,6 +59,7 @@ TelepathyGLib_1_gir_FILES = \ $(srcdir)/observe-channel-context.c $(srcdir)/observe-channel-context.h \ $(srcdir)/add-dispatch-operation-context.c $(srcdir)/add-dispatch-operation-context.h \ $(srcdir)/protocol.c $(srcdir)/protocol.h \ + $(srcdir)/base-protocol.c $(srcdir)/base-protocol.h \ $(srcdir)/base-connection.c $(srcdir)/base-connection.h \ $(srcdir)/handle-repo.c $(srcdir)/handle-repo.h $(srcdir)/handle-set.c \ $(srcdir)/stream-tube-channel.c $(srcdir)/stream-tube-channel.h \ diff --git a/telepathy-glib/versions/main-1.0.abi b/telepathy-glib/versions/main-1.0.abi index 899d682..faa7572 100644 --- a/telepathy-glib/versions/main-1.0.abi +++ b/telepathy-glib/versions/main-1.0.abi @@ -332,7 +332,7 @@ tp_base_media_call_stream_update_sending_state tp_base_password_channel_get_type tp_base_protocol_get_immutable_properties tp_base_protocol_get_name -tp_base_protocol_get_parameters +tp_base_protocol_dup_parameters tp_base_protocol_get_statuses tp_base_protocol_get_type tp_base_protocol_new_connection @@ -572,7 +572,6 @@ tp_cm_message_set_sender tp_cm_message_take_message tp_cm_param_filter_string_nonempty tp_cm_param_filter_uint_nonzero -tp_cm_param_setter_offset tp_connection_add_client_interest tp_connection_add_client_interest_by_id tp_connection_add_to_group_async -- 2.1.0