--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/telepathygabble/src/search-mixin.c Tue Feb 02 01:10:06 2010 +0200
@@ -0,0 +1,497 @@
+/*
+ * search-mixin.c - Source for GabbleSearchMixin
+ * Copyright (C) 2006 Collabora Ltd.
+ *
+ * @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
+ * @author Robert McQueen <robert.mcqueen@collabora.co.uk>
+ * @author Senko Rasic <senko@senko.net>
+ *
+ * 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 "loudmouth/loudmouth.h"
+#include <dbus/dbus-glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "telepathy-constants.h"
+#include "telepathy-errors.h"
+
+
+#include "debug.h"
+#include "gabble-connection.h"
+#include "namespaces.h"
+#include "roster.h"
+#include "util.h"
+
+
+#include "search-mixin.h"
+#include "search-mixin-signals-marshal.h"
+
+
+#include "gabble_enums.h"
+
+#define _GNU_SOURCE /* Needed for strptime (_XOPEN_SOURCE can also be used). */
+
+#define DEBUG_FLAG GABBLE_DEBUG_SEARCH
+
+
+/* allocator */
+
+#ifdef DEBUG_FLAG
+//#define DEBUG(format, ...)
+#define DEBUGGING 0
+#define NODE_DEBUG(n, s)
+#endif /* DEBUG_FLAG */
+
+
+#ifdef EMULATOR
+#include "libgabble_wsd_solution.h"
+
+ GET_STATIC_VAR_FROM_TLS(offset_quark1,gabble_search_mixin,GQuark)
+ #define offset_quark1 (*GET_WSD_VAR_NAME(offset_quark1,gabble_search_mixin, s)())
+
+ GET_STATIC_VAR_FROM_TLS(offset_quark,gabble_search_mixin,GQuark)
+ #define offset_quark (*GET_WSD_VAR_NAME(offset_quark,gabble_search_mixin, s)())
+
+ GET_STATIC_VAR_FROM_TLS(alloc1,gabble_search_mixin,GabbleAllocator)
+ #define alloc1 (*GET_WSD_VAR_NAME(alloc1,gabble_search_mixin, s)())
+
+#endif
+
+/*
+Moved to gabble_enums.h
+typedef struct _GabbleAllocator GabbleAllocator;
+struct _GabbleAllocator
+{
+ gulong size;
+ guint limit;
+ guint count;
+};*/
+
+
+typedef struct _IsKeyValidUserData IsKeyValidUserData;
+
+struct _IsKeyValidUserData
+{
+ GError **error;
+ gchar **search_key_names;
+ gboolean is_key_found;
+};
+
+
+typedef struct _SearchKeyVarUserData SearchKeyVarUserData;
+
+struct _SearchKeyVarUserData
+{
+ LmMessageNode *x_node;
+ GabbleConnection *conn;
+
+};
+
+
+#define ga_new0(alloc, type) \
+ ((type *) gabble_allocator_alloc0 (alloc))
+
+static void
+gabble_allocator_init (GabbleAllocator *alloc, gulong size, guint limit)
+{
+ g_assert (alloc != NULL);
+ g_assert (size > 0);
+ g_assert (limit > 0);
+
+ alloc->size = size;
+ alloc->limit = limit;
+}
+
+static gpointer gabble_allocator_alloc0 (GabbleAllocator *alloc)
+{
+ gpointer ret;
+
+ g_assert (alloc != NULL);
+ g_assert (alloc->count <= alloc->limit);
+
+ if (alloc->count == alloc->limit)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = g_malloc0 (alloc->size);
+ alloc->count++;
+ }
+
+ return ret;
+}
+
+static void gabble_allocator_free (GabbleAllocator *alloc, gpointer thing)
+{
+ g_assert (alloc != NULL);
+ g_assert (thing != NULL);
+
+ g_free (thing);
+ alloc->count--;
+}
+
+
+/**
+ * gabble_search_mixin_class_get_offset_quark:
+ *
+ * Returns: the quark used for storing mixin offset on a GObjectClass
+ */
+GQuark
+gabble_search_mixin_class_get_offset_quark ()
+{
+#ifndef EMULATOR
+ static GQuark offset_quark1 = 0;
+#endif
+
+ if (!offset_quark1)
+ offset_quark1 = g_quark_from_static_string("SearchMixinClassOffsetQuark");
+ return offset_quark1;
+}
+
+/**
+ * gabble_search_mixin_get_offset_quark:
+ *
+ * Returns: the quark used for storing mixin offset on a GObject
+ */
+GQuark
+gabble_search_mixin_get_offset_quark ()
+{
+#ifndef EMULATOR
+ static GQuark offset_quark = 0;
+#endif
+
+ if (!offset_quark)
+ offset_quark = g_quark_from_static_string("SearchMixinOffsetQuark");
+ return offset_quark;
+}
+
+
+/* GabbleSearchMixin */
+void
+gabble_search_mixin_class_init (GObjectClass *obj_cls, glong offset)
+{
+ GabbleSearchMixinClass *mixin_cls;
+
+ g_assert (G_IS_OBJECT_CLASS (obj_cls));
+
+ g_type_set_qdata (G_OBJECT_CLASS_TYPE (obj_cls),
+ GABBLE_SEARCH_MIXIN_CLASS_OFFSET_QUARK,
+ GINT_TO_POINTER (offset));
+
+ mixin_cls = GABBLE_SEARCH_MIXIN_CLASS (obj_cls);
+
+
+ mixin_cls->search_result_received_signal_id = g_signal_new ("search-result-received",
+ G_OBJECT_CLASS_TYPE (obj_cls),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ search_mixin_marshal_VOID__UINT_BOXED,
+ G_TYPE_NONE,
+ 2, G_TYPE_UINT, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE ));
+
+ mixin_cls->search_state_changed_signal_id = g_signal_new ("search-state-changed",
+ G_OBJECT_CLASS_TYPE (obj_cls),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT );
+
+}
+
+void
+gabble_search_mixin_init (GObject *obj,
+ glong offset )
+{
+ GabbleSearchMixin *mixin;
+
+ g_assert (G_IS_OBJECT (obj));
+
+ g_type_set_qdata (G_OBJECT_TYPE (obj),
+ GABBLE_SEARCH_MIXIN_OFFSET_QUARK,
+ GINT_TO_POINTER (offset));
+
+ mixin = GABBLE_SEARCH_MIXIN (obj);
+
+ mixin->search_state = TP_CHANNEL_CONTACT_SEARCH_STATE_BEFORE;
+
+ }
+
+void
+gabble_search_mixin_finalize (GObject *obj)
+{
+ GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
+ /* free any data held directly by the object here */
+}
+
+static void
+setfield_foreach (gpointer key, gpointer value, gpointer user_data)
+{
+ const gchar *search_data_string = NULL;
+ SearchKeyVarUserData *key_var_struct = (SearchKeyVarUserData*)user_data;
+ LmMessageNode *field_node;
+ const gchar *search_key_var = NULL;
+ GType g_type = G_VALUE_TYPE (value);
+
+ switch (g_type)
+ {
+ case G_TYPE_STRING:
+ search_data_string = g_value_get_string(value);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ search_key_var = (gchar *) g_hash_table_lookup (key_var_struct->conn->search_key_ht,
+ key /*Label*/);
+ field_node = lm_message_node_add_child ( key_var_struct->x_node, "field", NULL );
+ lm_message_node_set_attribute ( field_node, "var", search_key_var );
+ lm_message_node_add_child ( field_node, "value", search_data_string );
+}
+static void
+gabble_search_keynames_are_valid ( gpointer key, gpointer value,
+ gpointer userdata )
+{
+ guint i;
+ const gchar *search_data_string = g_value_get_string(value);
+ IsKeyValidUserData *key_valid_struct = (IsKeyValidUserData*)userdata;
+ gchar **search_key_names = key_valid_struct->search_key_names;
+
+ if( !key_valid_struct->is_key_found )
+ return;
+
+ if( key == NULL )
+ {
+ key_valid_struct->is_key_found = FALSE;
+ return;
+ }
+
+
+ for (i = 0; search_key_names[i]; i++)
+ {
+ if (0 == strcmp (search_key_names[i], key))
+ {
+ g_message("searchkey %s is valid\n",key);
+ if( search_data_string )
+ g_message("value is %s\n",search_data_string);
+ return;
+ }
+ }
+ key_valid_struct->is_key_found = FALSE;
+ g_message("searchkey %s is invalid\n",key);
+ g_set_error ( key_valid_struct->error, TELEPATHY_ERRORS, InvalidArgument,
+ "invalid search key found : %s\n", key);
+}
+
+
+/**
+ * gabble_search_mixin_search
+ *
+ * Implements D-Bus method Search
+ * on interface org.freedesktop.Telepathy.Channel.Type.ContactSearch
+ *
+ * @error: Used to return a pointer to a GError detailing any error
+ * that occurred, D-Bus will throw the error only if this
+ * function returns false.
+ *
+ * Returns: TRUE if successful, FALSE if an error was thrown.
+ */
+gboolean gabble_search_mixin_search (GObject *obj,GHashTable *params,
+ GabbleConnection *conn,
+ GError **error)
+{
+ LmMessage *msg;
+ LmMessageNode *query_node;
+ LmMessageNode *x_node;
+ gboolean result;
+ const gchar *service = NULL;
+ GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
+ IsKeyValidUserData *user_data = NULL;
+ SearchKeyVarUserData *get_keyvar_userdata = NULL;
+
+
+ if (params == NULL)
+ {
+ g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
+ "invalid argument \n");
+ return FALSE;
+ }
+
+ if ( !g_hash_table_size(params) )
+ {
+ g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
+ "invalid argument, no key-value pair to do search\n");
+ return FALSE;
+ }
+
+ service = conn->search_service_jid;
+
+ if (service == NULL)
+ {
+ g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
+ "Search Service is not available\n");
+ return FALSE;
+ }
+
+ g_message("service is %s\n",service);
+
+ if (conn->search_key_names == NULL)
+ {
+ g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
+ "search key names not available");
+ return FALSE;
+ }
+
+ user_data = g_new0 (IsKeyValidUserData, 1);
+ user_data->is_key_found = TRUE;
+ user_data->error = error;
+ user_data->search_key_names = conn->search_key_names;
+
+ g_hash_table_foreach (params, gabble_search_keynames_are_valid, user_data );
+
+ if(!user_data->is_key_found)
+ {
+ g_free(user_data);
+ g_message("invalid searchkey found\n");
+ return FALSE;
+ }
+
+ g_free(user_data);
+
+ msg= lm_message_new_with_sub_type ( service,
+ LM_MESSAGE_TYPE_IQ,
+ LM_MESSAGE_SUB_TYPE_SET);
+ query_node = lm_message_node_add_child (msg->node, "query", NULL);
+
+ lm_message_node_set_attribute (query_node, "xmlns", NS_SEARCH);
+
+ x_node = lm_message_node_add_child ( query_node, "x", NULL );
+
+ lm_message_node_set_attributes (x_node,
+ "xmlns", NS_X_DATA,
+ "type", "submit",
+ NULL);
+
+ get_keyvar_userdata = g_new0 (SearchKeyVarUserData, 1);
+ get_keyvar_userdata->x_node = x_node;
+ get_keyvar_userdata->conn = conn;
+
+ g_hash_table_foreach (params, setfield_foreach, get_keyvar_userdata );
+
+ g_free(get_keyvar_userdata);
+
+ result = _gabble_connection_send (conn, msg, error);
+ lm_message_unref (msg);
+
+ if (!result)
+ return FALSE;
+
+ //this means for each search attempt, a new channel should be created
+ mixin->search_state = TP_CHANNEL_CONTACT_SEARCH_STATE_DURING;
+
+ //send search state changed signal if required
+ _gabble_search_mixin_emit_search_state_changed(obj,mixin->search_state);
+
+ return TRUE;
+}
+
+gboolean gabble_search_mixin_get_search_state ( GObject *obj,
+ guint *ret,
+ GError **error )
+{
+ GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
+ *ret = mixin->search_state;
+ return TRUE;
+}
+
+
+/**
+ * gabble_search_mixin_get_search_keys
+ *
+ * Implements D-Bus method GetSearchKeys
+ * on interface org.freedesktop.Telepathy.Channel.Type.ContactSearch
+ *
+ * @error: Used to return a pointer to a GError detailing any error
+ * that occurred, D-Bus will throw the error only if this
+ * function returns false.
+ *
+ * Returns: TRUE if successful, FALSE if an error was thrown.
+ */
+gboolean
+gabble_search_mixin_get_search_keys ( GObject *obj,
+ gchar **ret_instruction,
+ gchar ***ret_searchkeys,
+ GabbleConnection *conn,
+ GError **error
+ )
+{
+ //later this method should be modified to give
+ //types of search keys fields also
+
+ if (conn->search_key_names == NULL)
+ {
+ g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
+ "search keys not available");
+ return FALSE;
+ }
+
+ *ret_searchkeys = g_strdupv ((gchar **) conn->search_key_names);
+ *ret_instruction = g_strdup ( (gchar*)conn->search_instr);
+
+ g_message("conn->search_instr :%s\n",(gchar*)conn->search_instr);
+ g_message("ret_instruction :%s\n",(gchar*)*ret_instruction );
+
+ return TRUE;
+}
+
+
+void
+_gabble_search_mixin_emit_search_result_received (GObject *obj,
+ guint contact_handle,
+ GHashTable *values )
+{
+ GabbleSearchMixinClass *mixin_cls = GABBLE_SEARCH_MIXIN_CLASS (G_OBJECT_GET_CLASS
+ (obj));
+
+ g_signal_emit (obj, mixin_cls->search_result_received_signal_id, 0,
+ contact_handle,
+ values );
+}
+
+void
+_gabble_search_mixin_emit_search_state_changed (GObject *obj,
+ guint search_state )
+{
+ GabbleSearchMixinClass *mixin_cls = GABBLE_SEARCH_MIXIN_CLASS (G_OBJECT_GET_CLASS
+ (obj));
+ g_signal_emit (obj, mixin_cls->search_state_changed_signal_id, 0,
+ search_state );
+}
+
+void
+_gabble_search_mixin_set_search_state (GObject *obj, guint state )
+{
+ GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
+ mixin->search_state = state;
+}
+
+