telepathygabble/src/search-mixin.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /*
       
     2  * search-mixin.c - Source for GabbleSearchMixin
       
     3  * Copyright (C) 2006 Collabora Ltd.
       
     4  * 
       
     5  *   @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
       
     6  *   @author Robert McQueen <robert.mcqueen@collabora.co.uk>
       
     7  *   @author Senko Rasic <senko@senko.net>
       
     8  *
       
     9  * This library is free software; you can redistribute it and/or
       
    10  * modify it under the terms of the GNU Lesser General Public
       
    11  * License as published by the Free Software Foundation; either
       
    12  * version 2.1 of the License, or (at your option) any later version.
       
    13  *
       
    14  * This library is distributed in the hope that it will be useful,
       
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    17  * Lesser General Public License for more details.
       
    18  *
       
    19  * You should have received a copy of the GNU Lesser General Public
       
    20  * License along with this library; if not, write to the Free Software
       
    21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    22  */
       
    23 
       
    24 
       
    25 #include "loudmouth/loudmouth.h"
       
    26 #include <dbus/dbus-glib.h>
       
    27 #include <stdio.h>
       
    28 #include <stdlib.h>
       
    29 #include <string.h>
       
    30 #include <time.h>
       
    31 
       
    32 #include "telepathy-constants.h"
       
    33 #include "telepathy-errors.h"
       
    34 
       
    35 
       
    36 #include "debug.h"
       
    37 #include "gabble-connection.h"
       
    38 #include "namespaces.h"
       
    39 #include "roster.h"
       
    40 #include "util.h"
       
    41 
       
    42 
       
    43 #include "search-mixin.h"
       
    44 #include "search-mixin-signals-marshal.h"
       
    45 
       
    46 
       
    47 #include "gabble_enums.h"
       
    48 
       
    49 #define _GNU_SOURCE /* Needed for strptime (_XOPEN_SOURCE can also be used). */
       
    50 
       
    51 #define DEBUG_FLAG GABBLE_DEBUG_SEARCH
       
    52 
       
    53 
       
    54 /* allocator */
       
    55 
       
    56 #ifdef DEBUG_FLAG
       
    57 //#define DEBUG(format, ...)
       
    58 #define DEBUGGING 0
       
    59 #define NODE_DEBUG(n, s)
       
    60 #endif /* DEBUG_FLAG */
       
    61 
       
    62 
       
    63 #ifdef EMULATOR
       
    64 #include "libgabble_wsd_solution.h"
       
    65 
       
    66 	GET_STATIC_VAR_FROM_TLS(offset_quark1,gabble_search_mixin,GQuark)
       
    67 	#define offset_quark1 (*GET_WSD_VAR_NAME(offset_quark1,gabble_search_mixin, s)())	
       
    68 	
       
    69 	GET_STATIC_VAR_FROM_TLS(offset_quark,gabble_search_mixin,GQuark)
       
    70 	#define offset_quark (*GET_WSD_VAR_NAME(offset_quark,gabble_search_mixin, s)())	
       
    71 	
       
    72 	GET_STATIC_VAR_FROM_TLS(alloc1,gabble_search_mixin,GabbleAllocator)
       
    73 	#define alloc1 (*GET_WSD_VAR_NAME(alloc1,gabble_search_mixin, s)())		
       
    74 	
       
    75 #endif
       
    76 
       
    77 /*
       
    78 Moved to gabble_enums.h
       
    79 typedef struct _GabbleAllocator GabbleAllocator;
       
    80 struct _GabbleAllocator
       
    81 {
       
    82   gulong size;
       
    83   guint limit;
       
    84   guint count;
       
    85 };*/
       
    86 
       
    87 
       
    88 typedef struct _IsKeyValidUserData IsKeyValidUserData;
       
    89 
       
    90 struct _IsKeyValidUserData
       
    91 {
       
    92   GError **error;
       
    93   gchar **search_key_names;
       
    94   gboolean is_key_found;
       
    95 };
       
    96 
       
    97 
       
    98 typedef struct _SearchKeyVarUserData SearchKeyVarUserData;
       
    99 
       
   100 struct _SearchKeyVarUserData
       
   101 {
       
   102   LmMessageNode *x_node;
       
   103   GabbleConnection *conn;
       
   104   
       
   105 };
       
   106 
       
   107 
       
   108 #define ga_new0(alloc, type) \
       
   109     ((type *) gabble_allocator_alloc0 (alloc))
       
   110 
       
   111 static void
       
   112 gabble_allocator_init (GabbleAllocator *alloc, gulong size, guint limit)
       
   113 {
       
   114   g_assert (alloc != NULL);
       
   115   g_assert (size > 0);
       
   116   g_assert (limit > 0);
       
   117 
       
   118   alloc->size = size;
       
   119   alloc->limit = limit;
       
   120 }
       
   121 
       
   122 static gpointer gabble_allocator_alloc0 (GabbleAllocator *alloc)
       
   123 {
       
   124   gpointer ret;
       
   125 
       
   126   g_assert (alloc != NULL);
       
   127   g_assert (alloc->count <= alloc->limit);
       
   128 
       
   129   if (alloc->count == alloc->limit)
       
   130     {
       
   131       ret = NULL;
       
   132     }
       
   133   else
       
   134     {
       
   135       ret = g_malloc0 (alloc->size);
       
   136       alloc->count++;
       
   137     }
       
   138 
       
   139   return ret;
       
   140 }
       
   141 
       
   142 static void gabble_allocator_free (GabbleAllocator *alloc, gpointer thing)
       
   143 {
       
   144   g_assert (alloc != NULL);
       
   145   g_assert (thing != NULL);
       
   146 
       
   147   g_free (thing);
       
   148   alloc->count--;
       
   149 }
       
   150 
       
   151 
       
   152 /**
       
   153  * gabble_search_mixin_class_get_offset_quark:
       
   154  *
       
   155  * Returns: the quark used for storing mixin offset on a GObjectClass
       
   156  */
       
   157 GQuark
       
   158 gabble_search_mixin_class_get_offset_quark ()
       
   159 {
       
   160 #ifndef EMULATOR  
       
   161   static GQuark offset_quark1 = 0;
       
   162 #endif
       
   163   
       
   164   if (!offset_quark1)
       
   165     offset_quark1 = g_quark_from_static_string("SearchMixinClassOffsetQuark");
       
   166   return offset_quark1;
       
   167 }
       
   168 
       
   169 /**
       
   170  * gabble_search_mixin_get_offset_quark:
       
   171  *
       
   172  * Returns: the quark used for storing mixin offset on a GObject
       
   173  */
       
   174 GQuark
       
   175 gabble_search_mixin_get_offset_quark ()
       
   176 {
       
   177 #ifndef EMULATOR  
       
   178   static GQuark offset_quark = 0;
       
   179 #endif
       
   180   
       
   181   if (!offset_quark)
       
   182     offset_quark = g_quark_from_static_string("SearchMixinOffsetQuark");
       
   183   return offset_quark;
       
   184 }
       
   185 
       
   186 
       
   187 /* GabbleSearchMixin */
       
   188 void
       
   189 gabble_search_mixin_class_init (GObjectClass *obj_cls, glong offset)
       
   190 {
       
   191   GabbleSearchMixinClass *mixin_cls;
       
   192 
       
   193   g_assert (G_IS_OBJECT_CLASS (obj_cls));
       
   194 
       
   195   g_type_set_qdata (G_OBJECT_CLASS_TYPE (obj_cls),
       
   196       GABBLE_SEARCH_MIXIN_CLASS_OFFSET_QUARK,
       
   197       GINT_TO_POINTER (offset));
       
   198 
       
   199   mixin_cls = GABBLE_SEARCH_MIXIN_CLASS (obj_cls);
       
   200 
       
   201 
       
   202   mixin_cls->search_result_received_signal_id = g_signal_new ("search-result-received",
       
   203                 G_OBJECT_CLASS_TYPE (obj_cls),
       
   204                 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   205                 0,
       
   206                 NULL, NULL,
       
   207                 search_mixin_marshal_VOID__UINT_BOXED,
       
   208                 G_TYPE_NONE,
       
   209                 2, G_TYPE_UINT, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE ));
       
   210 
       
   211   mixin_cls->search_state_changed_signal_id = g_signal_new ("search-state-changed",
       
   212                 G_OBJECT_CLASS_TYPE (obj_cls),
       
   213                 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   214                 0,
       
   215                 NULL, NULL,
       
   216                 g_cclosure_marshal_VOID__UINT,
       
   217                 G_TYPE_NONE, 1, G_TYPE_UINT );
       
   218 
       
   219 }
       
   220 
       
   221 void
       
   222 gabble_search_mixin_init (GObject *obj,
       
   223                         	glong offset )
       
   224 {
       
   225   GabbleSearchMixin *mixin;
       
   226 
       
   227   g_assert (G_IS_OBJECT (obj));
       
   228 
       
   229   g_type_set_qdata (G_OBJECT_TYPE (obj),
       
   230                     GABBLE_SEARCH_MIXIN_OFFSET_QUARK,
       
   231                     GINT_TO_POINTER (offset));
       
   232 
       
   233   mixin = GABBLE_SEARCH_MIXIN (obj);
       
   234   
       
   235   mixin->search_state = TP_CHANNEL_CONTACT_SEARCH_STATE_BEFORE;
       
   236 
       
   237  }
       
   238 
       
   239 void
       
   240 gabble_search_mixin_finalize (GObject *obj)
       
   241 {
       
   242   GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
       
   243   /* free any data held directly by the object here */
       
   244 }
       
   245 
       
   246 static void
       
   247 setfield_foreach (gpointer key, gpointer value, gpointer user_data)
       
   248 {
       
   249   const gchar *search_data_string = NULL;  
       
   250   SearchKeyVarUserData *key_var_struct = (SearchKeyVarUserData*)user_data;
       
   251   LmMessageNode *field_node;  
       
   252   const gchar *search_key_var = NULL;
       
   253   GType g_type = G_VALUE_TYPE (value);
       
   254   
       
   255   switch (g_type) 
       
   256   {
       
   257     case G_TYPE_STRING:
       
   258     	search_data_string =  g_value_get_string(value);
       
   259     	break;
       
   260     default:
       
   261           g_assert_not_reached ();
       
   262   }
       
   263   
       
   264   search_key_var = (gchar *) g_hash_table_lookup (key_var_struct->conn->search_key_ht,
       
   265               										 key /*Label*/);
       
   266   field_node = lm_message_node_add_child ( key_var_struct->x_node, "field", NULL );
       
   267   lm_message_node_set_attribute ( field_node, "var", search_key_var );
       
   268   lm_message_node_add_child ( field_node, "value", search_data_string ); 
       
   269 }
       
   270 static void 
       
   271 gabble_search_keynames_are_valid ( gpointer key, gpointer value,
       
   272                          			gpointer userdata )
       
   273 {
       
   274   guint i;
       
   275   const gchar *search_data_string =  g_value_get_string(value);
       
   276   IsKeyValidUserData *key_valid_struct = (IsKeyValidUserData*)userdata;
       
   277   gchar **search_key_names = key_valid_struct->search_key_names;
       
   278 
       
   279   if( !key_valid_struct->is_key_found )
       
   280   	return;
       
   281   
       
   282   if( key == NULL )
       
   283 	  {
       
   284 	  	key_valid_struct->is_key_found = FALSE;
       
   285 	  	return;
       
   286 	  }
       
   287 	   
       
   288 	  
       
   289   for (i = 0; search_key_names[i]; i++)
       
   290     {
       
   291       if (0 == strcmp (search_key_names[i], key))
       
   292 	      {
       
   293 	      g_message("searchkey %s is valid\n",key);
       
   294 	      if( search_data_string )
       
   295 	      	g_message("value is %s\n",search_data_string);
       
   296 	      return;	
       
   297 	      }
       
   298     }
       
   299  key_valid_struct->is_key_found = FALSE;
       
   300  g_message("searchkey %s is invalid\n",key);
       
   301  g_set_error ( key_valid_struct->error, TELEPATHY_ERRORS, InvalidArgument,
       
   302 		              "invalid search key found : %s\n", key);
       
   303 }
       
   304 
       
   305 
       
   306 /**
       
   307  * gabble_search_mixin_search
       
   308  *
       
   309  * Implements D-Bus method Search
       
   310  * on interface org.freedesktop.Telepathy.Channel.Type.ContactSearch
       
   311  *
       
   312  * @error: Used to return a pointer to a GError detailing any error
       
   313  *         that occurred, D-Bus will throw the error only if this
       
   314  *         function returns false.
       
   315  *
       
   316  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   317  */
       
   318 gboolean gabble_search_mixin_search (GObject *obj,GHashTable *params,
       
   319 									 GabbleConnection *conn,
       
   320                                  	 GError **error)
       
   321 {
       
   322   LmMessage *msg;
       
   323   LmMessageNode *query_node;
       
   324   LmMessageNode *x_node;
       
   325   gboolean result;
       
   326   const gchar *service = NULL;
       
   327   GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
       
   328   IsKeyValidUserData *user_data = NULL;
       
   329   SearchKeyVarUserData *get_keyvar_userdata = NULL;
       
   330      
       
   331 
       
   332   if (params == NULL)
       
   333       {
       
   334        g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
       
   335 	              "invalid argument \n");
       
   336   	   return FALSE;	
       
   337       }
       
   338   
       
   339   if ( !g_hash_table_size(params) )
       
   340       {
       
   341        g_set_error (error, TELEPATHY_ERRORS, InvalidArgument,
       
   342 	              "invalid argument, no key-value pair to do search\n");
       
   343   	   return FALSE;	
       
   344       }
       
   345   
       
   346   service = conn->search_service_jid;
       
   347   
       
   348   if (service == NULL)
       
   349       {
       
   350        g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
       
   351 	              "Search Service is not available\n");
       
   352   	   return FALSE;	
       
   353       }
       
   354       
       
   355   g_message("service is %s\n",service);
       
   356   
       
   357   if (conn->search_key_names == NULL)
       
   358       {
       
   359        g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
       
   360 	              "search key names not available");
       
   361   	   return FALSE;	
       
   362       }
       
   363   
       
   364   user_data = g_new0 (IsKeyValidUserData, 1);
       
   365   user_data->is_key_found = TRUE;
       
   366   user_data->error = error;
       
   367   user_data->search_key_names = conn->search_key_names;
       
   368   
       
   369   g_hash_table_foreach (params, gabble_search_keynames_are_valid, user_data );
       
   370   
       
   371   if(!user_data->is_key_found)
       
   372 	  {
       
   373 	  g_free(user_data);
       
   374 	  g_message("invalid searchkey found\n");
       
   375 	  return FALSE;		              
       
   376 	  }
       
   377   
       
   378   g_free(user_data);
       
   379   
       
   380   msg= lm_message_new_with_sub_type ( service,
       
   381                                       LM_MESSAGE_TYPE_IQ,
       
   382                                       LM_MESSAGE_SUB_TYPE_SET);
       
   383   query_node = lm_message_node_add_child (msg->node, "query", NULL);
       
   384   
       
   385   lm_message_node_set_attribute (query_node, "xmlns", NS_SEARCH);
       
   386  
       
   387   x_node = lm_message_node_add_child ( query_node, "x", NULL );
       
   388 
       
   389   lm_message_node_set_attributes (x_node,
       
   390                       "xmlns", NS_X_DATA,
       
   391                       "type", "submit",
       
   392                       NULL);
       
   393                       
       
   394   get_keyvar_userdata = g_new0 (SearchKeyVarUserData, 1);
       
   395   get_keyvar_userdata->x_node = x_node;
       
   396   get_keyvar_userdata->conn = conn;
       
   397 
       
   398   g_hash_table_foreach (params, setfield_foreach, get_keyvar_userdata );
       
   399   
       
   400   g_free(get_keyvar_userdata);	                                  	
       
   401 	 
       
   402   result = _gabble_connection_send (conn, msg, error);
       
   403   lm_message_unref (msg);
       
   404 
       
   405   if (!result)
       
   406     return FALSE;
       
   407   
       
   408   //this means for each search attempt, a new channel should be created
       
   409   mixin->search_state = TP_CHANNEL_CONTACT_SEARCH_STATE_DURING;
       
   410   
       
   411   //send search state changed signal if required
       
   412   _gabble_search_mixin_emit_search_state_changed(obj,mixin->search_state);
       
   413 
       
   414    return TRUE;
       
   415 }
       
   416 
       
   417 gboolean gabble_search_mixin_get_search_state (	GObject *obj, 
       
   418 												guint *ret,
       
   419                         						GError **error )
       
   420 {
       
   421   GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);
       
   422   *ret = mixin->search_state; 
       
   423   return TRUE;
       
   424 }
       
   425 
       
   426 
       
   427 /**
       
   428  * gabble_search_mixin_get_search_keys
       
   429  *
       
   430  * Implements D-Bus method GetSearchKeys
       
   431  * on interface org.freedesktop.Telepathy.Channel.Type.ContactSearch
       
   432  *
       
   433  * @error: Used to return a pointer to a GError detailing any error
       
   434  *         that occurred, D-Bus will throw the error only if this
       
   435  *         function returns false.
       
   436  *
       
   437  * Returns: TRUE if successful, FALSE if an error was thrown.
       
   438  */
       
   439 gboolean
       
   440 gabble_search_mixin_get_search_keys (	GObject *obj,
       
   441 										gchar **ret_instruction, 
       
   442 										gchar ***ret_searchkeys,
       
   443 										GabbleConnection *conn,
       
   444 		                        		GError **error
       
   445                         	  		   )
       
   446 {
       
   447   //later this method should be modified to give 
       
   448   //types of search keys fields also
       
   449   
       
   450   if (conn->search_key_names == NULL)
       
   451       {
       
   452        g_set_error (error, TELEPATHY_ERRORS, NotAvailable,
       
   453 	              "search keys not available");
       
   454   	   return FALSE;	
       
   455       }
       
   456   
       
   457   *ret_searchkeys = g_strdupv ((gchar **) conn->search_key_names);
       
   458   *ret_instruction = g_strdup ( (gchar*)conn->search_instr);
       
   459 
       
   460   g_message("conn->search_instr :%s\n",(gchar*)conn->search_instr);
       
   461   g_message("ret_instruction  :%s\n",(gchar*)*ret_instruction );
       
   462 
       
   463   return TRUE;
       
   464 }
       
   465 
       
   466 
       
   467 void
       
   468 _gabble_search_mixin_emit_search_result_received (GObject *obj,
       
   469                                                  guint contact_handle,
       
   470                              				     GHashTable *values )
       
   471 {
       
   472   GabbleSearchMixinClass *mixin_cls = GABBLE_SEARCH_MIXIN_CLASS (G_OBJECT_GET_CLASS
       
   473       (obj));
       
   474 
       
   475   g_signal_emit (obj, mixin_cls->search_result_received_signal_id, 0,
       
   476                  contact_handle,
       
   477                  values );
       
   478 }
       
   479 
       
   480 void
       
   481 _gabble_search_mixin_emit_search_state_changed (GObject *obj,
       
   482                                                  guint search_state )
       
   483 {
       
   484   GabbleSearchMixinClass *mixin_cls = GABBLE_SEARCH_MIXIN_CLASS (G_OBJECT_GET_CLASS
       
   485       (obj));
       
   486   g_signal_emit (obj, mixin_cls->search_state_changed_signal_id, 0,
       
   487                  search_state );
       
   488 }
       
   489 
       
   490 void
       
   491 _gabble_search_mixin_set_search_state (GObject *obj, guint state )
       
   492 {
       
   493   GabbleSearchMixin *mixin = GABBLE_SEARCH_MIXIN (obj);  
       
   494   mixin->search_state = state;
       
   495 }
       
   496 
       
   497