summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2013-10-28 13:27:03 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2013-11-11 16:49:08 +0000
commit1c491dae9d8f6a90b4d1398dfc8914d8f4ff20a7 (patch)
tree12d2647df35487b2bfee1279486351cf1882d041
parenta48cf1a835d94ea6220d67883eca4071e686a4a7 (diff)
TpProtocol: add high-level API for the Addressing interface
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=71048 Reviewed-by: Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
-rw-r--r--docs/reference/telepathy-glib-sections.txt7
-rw-r--r--examples/cm/echo-message-parts/protocol.c68
-rw-r--r--telepathy-glib/protocol.c246
-rw-r--r--telepathy-glib/protocol.h35
-rw-r--r--tests/dbus/protocol-objects.c60
5 files changed, 403 insertions, 13 deletions
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index df104212c..36845e623 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -6180,6 +6180,13 @@ tp_protocol_normalize_contact_finish
<SUBSECTION>
tp_protocol_get_avatar_requirements
<SUBSECTION>
+tp_protocol_get_addressable_uri_schemes
+tp_protocol_get_addressable_vcard_fields
+tp_protocol_normalize_contact_uri_async
+tp_protocol_normalize_contact_uri_finish
+tp_protocol_normalize_vcard_address_async
+tp_protocol_normalize_vcard_address_finish
+<SUBSECTION>
tp_cli_protocol_call_identify_account
tp_cli_protocol_call_normalize_contact
tp_cli_protocol_callback_for_identify_account
diff --git a/examples/cm/echo-message-parts/protocol.c b/examples/cm/echo-message-parts/protocol.c
index ae8894a26..7917ba000 100644
--- a/examples/cm/echo-message-parts/protocol.c
+++ b/examples/cm/echo-message-parts/protocol.c
@@ -226,6 +226,72 @@ dup_supported_vcard_fields (TpBaseProtocol *self)
return g_strdupv ((GStrv) addressing_vcard_fields);
}
+static gchar *
+normalize_vcard_address (TpBaseProtocol *self,
+ const gchar *vcard_field,
+ const gchar *vcard_address,
+ GError **error)
+{
+ if (g_ascii_strcasecmp (vcard_field, "x-jabber") == 0)
+ {
+ /* This is not really how you normalize a JID but it's good enough
+ * for an example. In real life you'd do syntax-checking beyond
+ * "is it empty?", stringprep, and so on. Here, we just assume
+ * non-empty means valid, and lower-case means normalized. */
+
+ if (tp_str_empty (vcard_address))
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "The empty string is not a valid JID");
+ return NULL;
+ }
+
+ return g_utf8_strdown (vcard_address, -1);
+ }
+ else
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
+ "Don't know how to normalize vCard field: %s", vcard_field);
+ return NULL;
+ }
+}
+
+static gchar *
+normalize_contact_uri (TpBaseProtocol *self,
+ const gchar *uri,
+ GError **error)
+{
+ gchar *scheme = g_uri_parse_scheme (uri);
+
+ if (g_ascii_strcasecmp (scheme, "xmpp") == 0)
+ {
+ gchar *ret = NULL;
+ gchar *id;
+
+ id = normalize_vcard_address (self, "x-jabber", uri + 5, error);
+
+ if (id != NULL)
+ ret = g_strdup_printf ("%s:%s", scheme, id);
+
+ g_free (scheme);
+ g_free (id);
+ return ret;
+ }
+ else if (scheme == NULL)
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Not a valid URI: %s", uri);
+ return NULL;
+ }
+ else
+ {
+ g_set_error (error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED,
+ "Don't know how to normalize URIs of that scheme: %s", scheme);
+ g_free (scheme);
+ return NULL;
+ }
+}
+
static void
example_echo_2_protocol_class_init (
ExampleEcho2ProtocolClass *klass)
@@ -248,4 +314,6 @@ addressing_iface_init (TpProtocolAddressingInterface *iface)
{
iface->dup_supported_vcard_fields = dup_supported_vcard_fields;
iface->dup_supported_uri_schemes = dup_supported_uri_schemes;
+ iface->normalize_vcard_address = normalize_vcard_address;
+ iface->normalize_contact_uri = normalize_contact_uri;
}
diff --git a/telepathy-glib/protocol.c b/telepathy-glib/protocol.c
index 7296db8b3..9b23aab27 100644
--- a/telepathy-glib/protocol.c
+++ b/telepathy-glib/protocol.c
@@ -146,6 +146,8 @@ struct _TpProtocolPrivate
TpCapabilities *capabilities;
TpAvatarRequirements *avatar_req;
gchar *cm_name;
+ GStrv addressable_vcard_fields;
+ GStrv addressable_uri_schemes;
};
enum
@@ -160,6 +162,8 @@ enum
PROP_AUTHENTICATION_TYPES,
PROP_AVATAR_REQUIREMENTS,
PROP_CM_NAME,
+ PROP_ADDRESSABLE_VCARD_FIELDS,
+ PROP_ADDRESSABLE_URI_SCHEMES,
N_PROPS
};
@@ -294,6 +298,15 @@ tp_protocol_get_property (GObject *object,
g_value_set_string (value, tp_protocol_get_cm_name (self));
break;
+ case PROP_ADDRESSABLE_VCARD_FIELDS:
+ g_value_set_boxed (value, tp_protocol_get_addressable_vcard_fields (
+ self));
+ break;
+
+ case PROP_ADDRESSABLE_URI_SCHEMES:
+ g_value_set_boxed (value, tp_protocol_get_addressable_uri_schemes (self));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -395,6 +408,8 @@ tp_protocol_finalize (GObject *object)
g_free (self->priv->english_name);
g_free (self->priv->icon_name);
g_free (self->priv->cm_name);
+ g_strfreev (self->priv->addressable_vcard_fields);
+ g_strfreev (self->priv->addressable_uri_schemes);
if (self->priv->protocol_properties != NULL)
g_hash_table_unref (self->priv->protocol_properties);
@@ -455,6 +470,19 @@ title_case (const gchar *s)
return g_strdup_printf ("%s%s", buf, g_utf8_next_char (s));
}
+static GStrv
+asv_strdupv_or_empty (const GHashTable *asv,
+ const gchar *key)
+{
+ const gchar * const *strings = tp_asv_get_boxed (asv, key, G_TYPE_STRV);
+ static const gchar * const no_strings[] = { NULL };
+
+ if (strings != NULL)
+ return g_strdupv ((GStrv) strings);
+ else
+ return g_strdupv ((GStrv) no_strings);
+}
+
static void
tp_protocol_constructed (GObject *object)
{
@@ -465,7 +493,6 @@ tp_protocol_constructed (GObject *object)
const gchar *s;
const GPtrArray *rccs;
gboolean had_immutables = TRUE;
- const gchar * const *auth_types = NULL;
const gchar * const *interfaces;
if (chain_up != NULL)
@@ -527,19 +554,9 @@ tp_protocol_constructed (GObject *object)
if (rccs != NULL)
self->priv->capabilities = _tp_capabilities_new (rccs, FALSE);
- auth_types = tp_asv_get_boxed (
+ self->priv->authentication_types = asv_strdupv_or_empty (
self->priv->protocol_properties,
- TP_PROP_PROTOCOL_AUTHENTICATION_TYPES, G_TYPE_STRV);
-
- if (auth_types != NULL)
- {
- self->priv->authentication_types = g_strdupv ((GStrv) auth_types);
- }
- else
- {
- gchar *tmp[] = { NULL };
- self->priv->authentication_types = g_strdupv (tmp);
- }
+ TP_PROP_PROTOCOL_AUTHENTICATION_TYPES);
interfaces = tp_asv_get_strv (self->priv->protocol_properties,
TP_PROP_PROTOCOL_INTERFACES);
@@ -568,6 +585,17 @@ tp_protocol_constructed (GObject *object)
TP_PROP_PROTOCOL_INTERFACE_AVATARS_MAXIMUM_AVATAR_BYTES, NULL));
}
+ if (tp_proxy_has_interface_by_id (self,
+ TP_IFACE_QUARK_PROTOCOL_INTERFACE_ADDRESSING))
+ {
+ self->priv->addressable_vcard_fields = asv_strdupv_or_empty (
+ self->priv->protocol_properties,
+ TP_PROP_PROTOCOL_INTERFACE_ADDRESSING_ADDRESSABLE_VCARD_FIELDS);
+ self->priv->addressable_uri_schemes = asv_strdupv_or_empty (
+ self->priv->protocol_properties,
+ TP_PROP_PROTOCOL_INTERFACE_ADDRESSING_ADDRESSABLE_URI_SCHEMES);
+ }
+
/* become ready immediately */
_tp_proxy_set_feature_prepared (proxy, TP_PROTOCOL_FEATURE_PARAMETERS,
had_immutables);
@@ -780,6 +808,45 @@ tp_protocol_class_init (TpProtocolClass *klass)
NULL,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * TpProtocol:addressable-vcard-fields:
+ *
+ * A non-%NULL #GStrv of vCard fields supported by this protocol.
+ * If this protocol does not support addressing contacts by a vCard field,
+ * the list is empty.
+ *
+ * For instance, a SIP connection manager that supports calling contacts
+ * by SIP URI (vCard field SIP) or telephone number (vCard field TEL)
+ * might have { "sip", "tel", NULL }.
+ *
+ * Since: 0.UNRELEASED
+ */
+ g_object_class_install_property (object_class, PROP_ADDRESSABLE_VCARD_FIELDS,
+ g_param_spec_boxed ("addressable-vcard-fields",
+ "AddressableVCardFields",
+ "A list of vCard fields",
+ G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * TpProtocol:addressable-uri-schemes:
+ *
+ * A non-%NULL #GStrv of URI schemes supported by this protocol.
+ * If this protocol does not support addressing contacts by URI,
+ * the list is empty.
+ *
+ * For instance, a SIP connection manager that supports calling contacts
+ * by SIP URI (sip:alice&commat;example.com, sips:bob&commat;example.com)
+ * or telephone number (tel:+1-555-0123) might have
+ * { "sip", "sips", "tel", NULL }.
+ *
+ * Since: 0.UNRELEASED
+ */
+ g_object_class_install_property (object_class, PROP_ADDRESSABLE_URI_SCHEMES,
+ g_param_spec_boxed ("addressable-uri-schemes",
+ "AddressableURISchemes",
+ "A list of URI schemes",
+ G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
proxy_class->list_features = tp_protocol_list_features;
proxy_class->must_have_unique_name = FALSE;
proxy_class->interface = TP_IFACE_QUARK_PROTOCOL;
@@ -1932,3 +1999,156 @@ tp_protocol_identify_account_finish (TpProtocol *self,
return g_task_propagate_pointer (G_TASK (result), error);
}
+
+/**
+ * tp_protocol_normalize_contact_uri_async:
+ * @self: a protocol
+ * @uri: a contact URI, possibly invalid
+ * @cancellable: (allow-none): may be used to cancel the async request
+ * @callback: (scope async): a callback to call when the request is satisfied
+ * @user_data: (closure) (allow-none): data to pass to @callback
+ *
+ * Perform best-effort offline contact normalization, for a contact in
+ * the form of a URI. This method will fail if the URI is not in a
+ * scheme supported by this protocol or connection manager.
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_protocol_normalize_contact_uri_async (TpProtocol *self,
+ const gchar *uri,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_if_fail (TP_IS_PROTOCOL (self));
+ g_return_if_fail (uri != NULL);
+ /* this makes no sense to call for its side-effects */
+ g_return_if_fail (callback != NULL);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, tp_protocol_normalize_contact_uri_async);
+
+ tp_cli_protocol_interface_addressing_call_normalize_contact_uri (self, -1,
+ uri, tp_protocol_async_string_cb, task, g_object_unref, NULL);
+}
+
+/**
+ * tp_protocol_normalize_contact_uri_finish:
+ * @self: a protocol
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Interpret the result of tp_protocol_normalize_contact_uri_async().
+ *
+ * Returns: (transfer full): the normalized form of @uri,
+ * or %NULL on error
+ * Since: 0.UNRELEASED
+ */
+gchar *
+tp_protocol_normalize_contact_uri_finish (TpProtocol *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result,
+ tp_protocol_normalize_contact_uri_async), NULL);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+/**
+ * tp_protocol_normalize_vcard_address_async:
+ * @self: a protocol
+ * @field: a vCard field
+ * @value: an address that is a value of @field
+ * @cancellable: (allow-none): may be used to cancel the async request
+ * @callback: (scope async): a callback to call when the request is satisfied
+ * @user_data: (closure) (allow-none): data to pass to @callback
+ *
+ * Perform best-effort offline contact normalization, for a contact in
+ * the form of a vCard field. This method will fail if the vCard field
+ * is not supported by this protocol or connection manager.
+ *
+ * Since: 0.UNRELEASED
+ */
+void
+tp_protocol_normalize_vcard_address_async (TpProtocol *self,
+ const gchar *field,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_if_fail (TP_IS_PROTOCOL (self));
+ g_return_if_fail (!tp_str_empty (field));
+ g_return_if_fail (value != NULL);
+ /* this makes no sense to call for its side-effects */
+ g_return_if_fail (callback != NULL);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, tp_protocol_normalize_vcard_address_async);
+
+ tp_cli_protocol_interface_addressing_call_normalize_vcard_address (self, -1,
+ field, value, tp_protocol_async_string_cb, task, g_object_unref, NULL);
+}
+
+/**
+ * tp_protocol_normalize_vcard_address_finish:
+ * @self: a protocol
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Interpret the result of tp_protocol_normalize_vcard_address_async().
+ *
+ * Returns: (transfer full): the normalized form of @value,
+ * or %NULL on error
+ * Since: 0.UNRELEASED
+ */
+gchar *
+tp_protocol_normalize_vcard_address_finish (TpProtocol *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (g_task_is_valid (result, self), NULL);
+ g_return_val_if_fail (g_async_result_is_tagged (result,
+ tp_protocol_normalize_vcard_address_async), NULL);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+/**
+ * tp_protocol_get_addressable_vcard_fields:
+ * @self: a protocol object
+ *
+ * <!-- -->
+ *
+ * Returns: (transfer none): the value of #TpProtocol:addressable-vcard-fields
+ * Since: 0.UNRELEASED
+ */
+const gchar * const *
+tp_protocol_get_addressable_vcard_fields (TpProtocol *self)
+{
+ g_return_val_if_fail (TP_IS_PROTOCOL (self), NULL);
+ return (const gchar * const *) self->priv->addressable_vcard_fields;
+}
+
+/**
+ * tp_protocol_get_addressable_uri_schemes:
+ * @self: a protocol object
+ *
+ * <!-- -->
+ *
+ * Returns: (transfer none): the value of #TpProtocol:addressable-uri-schemes
+ * Since: 0.UNRELEASED
+ */
+const gchar * const *
+tp_protocol_get_addressable_uri_schemes (TpProtocol *self)
+{
+ g_return_val_if_fail (TP_IS_PROTOCOL (self), NULL);
+ return (const gchar * const *) self->priv->addressable_uri_schemes;
+}
diff --git a/telepathy-glib/protocol.h b/telepathy-glib/protocol.h
index 05f77814e..8555144fd 100644
--- a/telepathy-glib/protocol.h
+++ b/telepathy-glib/protocol.h
@@ -113,6 +113,16 @@ const gchar * const *
/* gtk-doc sucks */
tp_protocol_get_authentication_types (TpProtocol *self);
+_TP_AVAILABLE_IN_UNRELEASED
+const gchar * const *
+/* ... */
+tp_protocol_get_addressable_vcard_fields (TpProtocol *self);
+
+_TP_AVAILABLE_IN_UNRELEASED
+const gchar * const *
+/* ... */
+tp_protocol_get_addressable_uri_schemes (TpProtocol *self);
+
#define TP_PROTOCOL_FEATURE_CORE \
(tp_protocol_get_feature_quark_core ())
GQuark tp_protocol_get_feature_quark_core (void) G_GNUC_CONST;
@@ -149,6 +159,31 @@ gchar *tp_protocol_identify_account_finish (TpProtocol *self,
GAsyncResult *result,
GError **error);
+_TP_AVAILABLE_IN_UNRELEASED
+void tp_protocol_normalize_contact_uri_async (TpProtocol *self,
+ const gchar *uri,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+_TP_AVAILABLE_IN_UNRELEASED
+gchar *tp_protocol_normalize_contact_uri_finish (TpProtocol *self,
+ GAsyncResult *result,
+ GError **error);
+
+_TP_AVAILABLE_IN_UNRELEASED
+void tp_protocol_normalize_vcard_address_async (TpProtocol *self,
+ const gchar *field,
+ const gchar *value,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+_TP_AVAILABLE_IN_UNRELEASED
+gchar *tp_protocol_normalize_vcard_address_finish (TpProtocol *self,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#include <telepathy-glib/_gen/tp-cli-protocol.h>
diff --git a/tests/dbus/protocol-objects.c b/tests/dbus/protocol-objects.c
index fee4afe4b..b1c0fdaca 100644
--- a/tests/dbus/protocol-objects.c
+++ b/tests/dbus/protocol-objects.c
@@ -565,6 +565,66 @@ test_normalize (Test *test,
g_assert_cmpstr (s, ==, NULL);
g_clear_object (&result);
g_clear_error (&test->error);
+
+ tp_protocol_normalize_contact_uri_async (test->protocol,
+ "xmpp:MiXeDcAsE", NULL, tp_tests_result_ready_cb, &result);
+ tp_tests_run_until_result (&result);
+ s = tp_protocol_normalize_contact_uri_finish (test->protocol, result,
+ &test->error);
+ g_assert_no_error (test->error);
+ g_assert_cmpstr (s, ==, "xmpp:mixedcase");
+ g_clear_object (&result);
+ g_free (s);
+
+ tp_protocol_normalize_contact_uri_async (test->protocol,
+ "xmpp:", NULL, tp_tests_result_ready_cb, &result);
+ tp_tests_run_until_result (&result);
+ s = tp_protocol_normalize_contact_uri_finish (test->protocol, result,
+ &test->error);
+ g_assert_cmpstr (s, ==, NULL);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT);
+ g_clear_object (&result);
+ g_clear_error (&test->error);
+
+ tp_protocol_normalize_contact_uri_async (test->protocol,
+ "http://example.com", NULL, tp_tests_result_ready_cb, &result);
+ tp_tests_run_until_result (&result);
+ s = tp_protocol_normalize_contact_uri_finish (test->protocol, result,
+ &test->error);
+ g_assert_cmpstr (s, ==, NULL);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED);
+ g_clear_object (&result);
+ g_clear_error (&test->error);
+
+ tp_protocol_normalize_vcard_address_async (test->protocol,
+ "x-jabber", "MiXeDcAsE", NULL, tp_tests_result_ready_cb, &result);
+ tp_tests_run_until_result (&result);
+ s = tp_protocol_normalize_vcard_address_finish (test->protocol, result,
+ &test->error);
+ g_assert_no_error (test->error);
+ g_assert_cmpstr (s, ==, "mixedcase");
+ g_clear_object (&result);
+ g_free (s);
+
+ tp_protocol_normalize_vcard_address_async (test->protocol,
+ "x-jabber", "", NULL, tp_tests_result_ready_cb, &result);
+ tp_tests_run_until_result (&result);
+ s = tp_protocol_normalize_vcard_address_finish (test->protocol, result,
+ &test->error);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT);
+ g_assert_cmpstr (s, ==, NULL);
+ g_clear_object (&result);
+ g_clear_error (&test->error);
+
+ tp_protocol_normalize_vcard_address_async (test->protocol,
+ "x-skype", "", NULL, tp_tests_result_ready_cb, &result);
+ tp_tests_run_until_result (&result);
+ s = tp_protocol_normalize_vcard_address_finish (test->protocol, result,
+ &test->error);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_NOT_IMPLEMENTED);
+ g_assert_cmpstr (s, ==, NULL);
+ g_clear_object (&result);
+ g_clear_error (&test->error);
}
static void