/* * util.c - Code for Salut utility functions * Copyright (C) 2006-2007 Collabora Ltd. * Copyright (C) 2006-2007 Nokia Corporation * * 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 */ #include "config.h" #include "util.h" #include #include #include #include #include #include #include "contact.h" #ifdef HAVE_UUID # include #endif struct _xmpp_node_extract_property_data { const gchar *prop; GHashTable *properties; }; static gboolean xmpp_node_extract_property (WockyNode *node, gpointer user_data) { struct _xmpp_node_extract_property_data *data = (struct _xmpp_node_extract_property_data *) user_data; const gchar *name; const gchar *type; const gchar *value; GValue *gvalue; if (tp_strdiff (node->name, data->prop)) return TRUE; name = wocky_node_get_attribute (node, "name"); if (!name) return TRUE; type = wocky_node_get_attribute (node, "type"); value = node->content; if (type == NULL || value == NULL) return TRUE; if (!tp_strdiff (type, "bytes")) { GArray *arr; guchar *decoded; gsize len; decoded = g_base64_decode (value, &len); if (!decoded) return TRUE; arr = g_array_new (FALSE, FALSE, sizeof (guchar)); g_array_append_vals (arr, decoded, len); gvalue = tp_g_value_slice_new (DBUS_TYPE_G_UCHAR_ARRAY); g_value_take_boxed (gvalue, arr); g_hash_table_insert (data->properties, g_strdup (name), gvalue); g_free (decoded); } else if (!tp_strdiff (type, "str")) { gvalue = tp_g_value_slice_new (G_TYPE_STRING); g_value_set_string (gvalue, value); g_hash_table_insert (data->properties, g_strdup (name), gvalue); } else if (!tp_strdiff (type, "int")) { gvalue = tp_g_value_slice_new (G_TYPE_INT); g_value_set_int (gvalue, strtol (value, NULL, 10)); g_hash_table_insert (data->properties, g_strdup (name), gvalue); } else if (!tp_strdiff (type, "uint")) { gvalue = tp_g_value_slice_new (G_TYPE_UINT); g_value_set_uint (gvalue, strtoul (value, NULL, 10)); g_hash_table_insert (data->properties, g_strdup (name), gvalue); } else if (!tp_strdiff (type, "bool")) { gboolean val; if (!tp_strdiff (value, "0")) { val = FALSE; } else if (!tp_strdiff (value, "1")) { val = TRUE; } else { g_debug ("invalid boolean value: %s", value); return TRUE; } gvalue = tp_g_value_slice_new (G_TYPE_BOOLEAN); g_value_set_boolean (gvalue, val); g_hash_table_insert (data->properties, g_strdup (name), gvalue); } return TRUE; } /** * salut_wocky_node_extract_properties * * Map a XML node to a properties hash table * * Example: * * * prop1_value * 7 * * * salut_wocky_node_extract_properties (node, "prop"); * * --> { "prop1" : "prop1_value", "prop2" : 7 } * * Returns a hash table mapping names to GValue of the specified type. * Valid types are: str, int, uint, bytes, b. * */ GHashTable * salut_wocky_node_extract_properties (WockyNode *node, const gchar *prop) { GHashTable *properties; struct _xmpp_node_extract_property_data data; properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) tp_g_value_slice_free); if (node == NULL) return properties; data.prop = prop; data.properties = properties; wocky_node_each_child (node, xmpp_node_extract_property, &data); return properties; } struct _set_child_from_property_data { WockyNode *node; const gchar *prop; }; static void set_child_from_property (gpointer key, gpointer value, gpointer user_data) { GValue *gvalue = value; struct _set_child_from_property_data *data = (struct _set_child_from_property_data *) user_data; WockyNode *child; const char *type = NULL; if (G_VALUE_TYPE (gvalue) == G_TYPE_STRING) { type = "str"; } else if (G_VALUE_TYPE (gvalue) == G_TYPE_INT) { type = "int"; } else if (G_VALUE_TYPE (gvalue) == G_TYPE_UINT) { type = "uint"; } else if (G_VALUE_TYPE (gvalue) == DBUS_TYPE_G_UCHAR_ARRAY) { type = "bytes"; } else if (G_VALUE_TYPE (gvalue) == G_TYPE_BOOLEAN) { type = "bool"; } else { /* a type we don't know how to handle: ignore it */ g_critical ("property with unknown type \"%s\"", g_type_name (G_VALUE_TYPE (gvalue))); return; } child = wocky_node_add_child (data->node, data->prop); if (G_VALUE_TYPE (gvalue) == G_TYPE_STRING) { wocky_node_set_content (child, g_value_get_string (gvalue)); } else if (G_VALUE_TYPE (gvalue) == G_TYPE_INT) { gchar *str; str = g_strdup_printf ("%d", g_value_get_int (gvalue)); wocky_node_set_content (child, str); g_free (str); } else if (G_VALUE_TYPE (gvalue) == G_TYPE_UINT) { gchar *str; str = g_strdup_printf ("%u", g_value_get_uint (gvalue)); wocky_node_set_content (child, str); g_free (str); } else if (G_VALUE_TYPE (gvalue) == DBUS_TYPE_G_UCHAR_ARRAY) { GArray *arr; gchar *str; type = "bytes"; arr = g_value_get_boxed (gvalue); str = g_base64_encode ((const guchar *) arr->data, arr->len); wocky_node_set_content (child, str); g_free (str); } else if (G_VALUE_TYPE (gvalue) == G_TYPE_BOOLEAN) { gboolean val; val = g_value_get_boolean (gvalue); if (val) wocky_node_set_content (child, "1"); else wocky_node_set_content (child, "0"); } else { g_assert_not_reached (); } wocky_node_set_attribute (child, "name", key); wocky_node_set_attribute (child, "type", type); } /** * * wocky_node_set_children_from_properties * * Map a properties hash table to a XML node. * * Example: * * properties = { "prop1" : "prop1_value", "prop2" : 7 } * * salut_wocky_node_add_children_from_properties (node, properties, * "prop"); * * --> * prop1_value * 7 * * */ void salut_wocky_node_add_children_from_properties (WockyNode *node, GHashTable *properties, const gchar *prop) { struct _set_child_from_property_data data; data.node = node; data.prop = prop; g_hash_table_foreach (properties, set_child_from_property, &data); } gchar * salut_generate_id (void) { #ifdef HAVE_UUID /* generate random UUIDs */ uuid_t uu; gchar *str; str = g_new0 (gchar, 37); uuid_generate_random (uu); uuid_unparse_lower (uu, str); return str; #else /* generate from the time, a counter, and a random integer */ static gulong last = 0; GTimeVal tv; g_get_current_time (&tv); return g_strdup_printf ("%lx.%lx/%lx/%x", tv.tv_sec, tv.tv_usec, last++, g_random_int ()); #endif }