[telepathy-glib/master] Add tp_account_parse_object_path
Will Thompson
will.thompson at collabora.co.uk
Mon Sep 28 07:39:13 PDT 2009
Signed-off-by: Jonny Lamb <jonny.lamb at collabora.co.uk>
---
docs/reference/telepathy-glib-sections.txt | 1 +
telepathy-glib/account.c | 107 ++++++++++++++++++++++++++++
telepathy-glib/account.h | 3 +
tests/dbus/account.c | 89 ++++++++++++++++++++++-
4 files changed, 197 insertions(+), 3 deletions(-)
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 9097d2b..48055db 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -2988,6 +2988,7 @@ TpAccount
TpAccountClass
tp_account_new
tp_account_init_known_interfaces
+tp_account_parse_object_path
tp_account_is_just_connected
tp_account_get_connection
tp_account_ensure_connection
diff --git a/telepathy-glib/account.c b/telepathy-glib/account.c
index 8e940b5..e7b23ae 100644
--- a/telepathy-glib/account.c
+++ b/telepathy-glib/account.c
@@ -2475,3 +2475,110 @@ tp_account_get_features (TpAccount *account)
{
return (const GQuark *) account->priv->features_array->data;
}
+
+static void
+set_or_free (gchar **target,
+ gchar *source)
+{
+ if (target != NULL)
+ *target = source;
+ else
+ g_free (source);
+}
+
+/**
+ * tp_parse_account_path:
+ * @object_path: a Telepathy Account's object path
+ * @cm: location at which to store the account's connection manager's name
+ * @protocol: location at which to store the account's protocol
+ * @account_id: location at which to store the account's unique identifier
+ * @error: location at which to return an error
+ *
+ * Validates and parses a Telepathy Account's object path, extracting the
+ * connection manager's name, the protocol, and the account's unique identifier
+ * from the path. This includes replacing underscores with hyphens in the
+ * protocol name, as defined in the Account specification.
+ *
+ * Any of the out parameters may be %NULL if not needed.
+ *
+ * Returns: %TRUE if @object_path was successfully parsed; %FALSE and sets
+ * @error otherwise.
+ */
+gboolean
+tp_account_parse_object_path (const gchar *object_path,
+ gchar **cm,
+ gchar **protocol,
+ gchar **account_id,
+ GError **error)
+{
+ const gchar *suffix;
+ gchar **segments;
+
+ if (!tp_dbus_check_valid_object_path (object_path, error))
+ return FALSE;
+
+ if (!g_str_has_prefix (object_path, TP_ACCOUNT_OBJECT_PATH_BASE))
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path does not start with the right prefix: %s",
+ object_path);
+ return FALSE;
+ }
+
+ suffix = object_path + strlen (TP_ACCOUNT_OBJECT_PATH_BASE);
+
+ segments = g_strsplit (suffix, "/", 0);
+
+ if (g_strv_length (segments) != 3)
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: should have 3 trailing components, "
+ "not %u", object_path, g_strv_length (segments));
+ goto free_segments_and_fail;
+ }
+
+ if (!g_ascii_isalpha (segments[0][0]))
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: CM name should start with a letter",
+ object_path);
+ goto free_segments_and_fail;
+ }
+
+ if (!g_ascii_isalpha (segments[1][0]))
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: "
+ "protocol name should start with a letter",
+ object_path);
+ goto free_segments_and_fail;
+ }
+
+ if (!g_ascii_isalpha (segments[2][0]) && segments[2][0] != '_')
+ {
+ g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+ "Account path '%s' is malformed: "
+ "account ID should start with a letter or underscore",
+ object_path);
+ goto free_segments_and_fail;
+ }
+
+ set_or_free (cm, segments[0]);
+
+ /* XXX: work around MC5 bug where it escapes with tp_escape_as_identifier
+ * rather than doing it properly. MC5 saves the object path in your config,
+ * so if you've ever used a buggy MC5, the path will be wrong forever.
+ */
+ g_strdelimit (segments[1], "_", '-');
+ set_or_free (protocol, segments[1]);
+
+ set_or_free (account_id, segments[2]);
+
+ /* Not g_strfreev because we stole or freed the individual strings */
+ g_free (segments);
+ return TRUE;
+
+free_segments_and_fail:
+ g_strfreev (segments);
+ return FALSE;
+}
diff --git a/telepathy-glib/account.h b/telepathy-glib/account.h
index fcc3d21..2af0077 100644
--- a/telepathy-glib/account.h
+++ b/telepathy-glib/account.h
@@ -72,6 +72,9 @@ GType tp_account_get_type (void);
TpAccount *tp_account_new (TpDBusDaemon *bus_daemon, const gchar *object_path,
GError **error);
+gboolean tp_account_parse_object_path (const gchar *object_path,
+ gchar **cm, gchar **protocol, gchar **account_id, GError **error);
+
void tp_account_init_known_interfaces (void);
gboolean tp_account_is_just_connected (TpAccount *account);
diff --git a/tests/dbus/account.c b/tests/dbus/account.c
index aeb8762..accc15f 100644
--- a/tests/dbus/account.c
+++ b/tests/dbus/account.c
@@ -10,6 +10,62 @@
#include <telepathy-glib/account.h>
#include <telepathy-glib/debug.h>
+#include <telepathy-glib/defs.h>
+
+static void
+test_parse_failure (gconstpointer test_data)
+{
+ GError *error = NULL;
+
+ g_assert (!tp_account_parse_object_path (test_data, NULL, NULL, NULL,
+ &error));
+ g_assert (error != NULL);
+ g_error_free (error);
+}
+
+typedef struct {
+ const gchar *path;
+ const gchar *cm;
+ const gchar *protocol;
+ const gchar *account_id;
+} TestParseData;
+
+static TestParseData *
+test_parse_data_new (const gchar *path,
+ const gchar *cm,
+ const gchar *protocol,
+ const gchar *account_id)
+{
+ TestParseData *t = g_slice_new (TestParseData);
+
+ t->path = path;
+ t->cm = cm;
+ t->protocol = protocol;
+ t->account_id = account_id;
+
+ return t;
+}
+
+static void
+test_parse_success (gconstpointer test_data)
+{
+ TestParseData *t = (TestParseData *) test_data;
+ gchar *cm, *protocol, *account_id;
+ GError *error = NULL;
+
+ g_assert (tp_account_parse_object_path (t->path, &cm, &protocol, &account_id,
+ &error));
+ g_assert_no_error (error);
+ g_assert_cmpstr (cm, ==, t->cm);
+ g_assert_cmpstr (protocol, ==, t->protocol);
+ g_assert_cmpstr (account_id, ==, t->account_id);
+
+ g_free (cm);
+ g_free (protocol);
+ g_free (account_id);
+
+ g_slice_free (TestParseData, t);
+}
typedef struct {
GMainLoop *mainloop;
@@ -23,9 +79,6 @@ static void
setup (Test *test,
gconstpointer data)
{
- g_type_init ();
- tp_debug_set_flags ("all");
-
test->mainloop = g_main_loop_new (NULL, FALSE);
test->dbus = tp_dbus_daemon_dup (NULL);
g_assert (test->dbus != NULL);
@@ -70,9 +123,39 @@ int
main (int argc,
char **argv)
{
+ g_type_init ();
+ tp_debug_set_flags ("all");
+
g_test_init (&argc, &argv, NULL);
g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+ g_test_add_data_func ("/account/parse/spaces",
+ "this is not an object path", test_parse_failure);
+ g_test_add_data_func ("/account/parse/no-prefix",
+ "/this/is/not/an/account/path", test_parse_failure);
+ g_test_add_data_func ("/account/parse/too-few-components",
+ "/org/freedesktop/Telepathy/Account/wrong", test_parse_failure);
+ g_test_add_data_func ("/account/parse/too-many-components",
+ "/org/freedesktop/Telepathy/Account/a/b/c/d", test_parse_failure);
+ g_test_add_data_func ("/account/parse/illegal-components",
+ "/org/freedesktop/Telepathy/Account/1/2/3", test_parse_failure);
+
+ g_test_add_data_func ("/account/parse/legal",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "gabble/jabber/badgers",
+ "gabble", "jabber", "badgers"),
+ test_parse_success);
+ g_test_add_data_func ("/account/parse/hyphenated-protocol",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "salut/local_xmpp/badgers",
+ "salut", "local-xmpp", "badgers"),
+ test_parse_success);
+ g_test_add_data_func ("/account/parse/underscored-account",
+ test_parse_data_new (
+ TP_ACCOUNT_OBJECT_PATH_BASE "haze/msn/_thisseemsunlikely",
+ "haze", "msn", "_thisseemsunlikely"),
+ test_parse_success);
+
g_test_add ("/account/new", Test, NULL, setup, test_new, teardown);
return g_test_run ();
--
1.5.6.5
More information about the telepathy-commits
mailing list