diff -r 000000000000 -r d0f3a028347a isolationserver/isoserver/src/isosearch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/isolationserver/isoserver/src/isosearch.c Tue Feb 02 01:10:06 2010 +0200 @@ -0,0 +1,634 @@ +/* +* ============================================================================ +* Name : isosearch.c +* Part of : isolation server. +* Version : %version: 17 % +* +* Copyright © 2007-2008 Nokia. All rights reserved. +* Redistribution and use in source and binary forms, with or without modification, +* are permitted provided that the following conditions are met: +* Redistributions of source code must retain the above copyright notice, this list +* of conditions and the following disclaimer.Redistributions in binary form must +* reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of the Nokia Corporation nor the names of its contributors may be used +* to endorse or promote products derived from this software without specific prior written +* permission. +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* ============================================================================ +* Template version: 1.0 +*/ + +/*! \file +* Impliments the functions in isosearch.h +*/ + +/*! \def For malloc +*/ +#include + +/*! \def For string operations +*/ +#include + +/*! \def For GHashTable +*/ +#include + +/*! \def For search related declarations +*/ +#include "isosearch.h" + +/*! \def For globalCon +*/ +#include "isoservermain.h" + +/*! \def For tp_chan_type_search_async +*/ +#include "tp-chan-type-search-gen.h" + +/*! \def For MSG_PRI_NORMAL +*/ +#include "msgqlib.h" + +/*! \def For message_hdr_req +*/ +#include "isoutils.h" + +/*! \def For RESPONSE_QUEUE +*/ +#include "msgliterals.h" + +/*! \struct key_value_struct isoserach.h +* \brief This struct is used for to form the msg buffer that will be sent to client +* \var msg As the key/value pairs are read those will be appended to msg +* \var len is the no. of bytes appended to msg +*/ +struct key_value_struct + { + gchar* msg; + gint len; + }; + +/*! \typedef struct key_value_struct to key_value_struct +* +*/ +typedef struct key_value_struct key_value_struct; + + +static void search_result_received_cb ( DBusGProxy *proxy, + guint contact_handle, + GHashTable *values, + gpointer user_data + ); + +static void search_state_changed_cb ( DBusGProxy *proxy, + guint search_state, + gpointer user_data + ); + +static void searchreply_cb( DBusGProxy *proxy, GError *error, gpointer userdata ); + + +static void do_search_again( GHashTable* search_hash ); + + + +/*! \brief This function called by action_parse_search parses rmsg and +* validates the arguments(key/value pairs). If value for any key found missing +* returns INVALID_PARAMETERES +* +* \param rmsg Message which is parsed +* \param rmsg_len message len +* \param search_hash parsed key/value pairs are filled into this hash table +* +* \return error if any else 0 +*/ +gint parse_for_search( gchar* rmsg, gint rmsg_len, GHashTable* search_hash ) + { + gint pointer_nav = 0; + gchar* value_str = NULL; + gchar* key_str = NULL; + gint err = 0; + GValue *value = NULL; + + iso_logger( "in parse_for_search"); + //Skip the header field + pointer_nav += sizeof( message_hdr_req ); + + while ( '\0' != *( rmsg + pointer_nav ) && pointer_nav < rmsg_len ) + { + //Copy the key + err = parse_a_string( rmsg, &key_str, &pointer_nav, rmsg_len ); + if ( err < 0 ) + { + //if error, return error + return err; + } + //End of message reached and no value found for + //corresponding key + if ( '\0' == *( rmsg + pointer_nav ) ) + { + return INVALID_PARAMETERES; + } + //Copy the value + err = parse_a_string( rmsg, &value_str, &pointer_nav, rmsg_len ); + if ( err < 0 ) + { + //if error, return error + return err; + } + + value = g_new0( GValue, 1 ); + g_value_init( value, G_TYPE_STRING ); + g_value_set_string ( value, value_str ); + + + //insert the key value pair into the hash table + g_hash_table_insert ( search_hash, key_str, value ); + } + iso_logger( "out parse_for_search"); + return 0; + } + +/*! \brief This function is called as a callback to search chan request +* This function creates a search channel and interface which are +* used for subsequent search requests. Logically this function is called +* only once per login session. +* \remark Not creating a search channel each time is a workaround +* +* \param proxy unused +* \param chan_object_path channel object path to create a new channel +* \param error if any +* \param user_data hash table entry(key/value pair) +* +* \return void +*/ + + void do_search_reply( DBusGProxy *proxy, char *chan_object_path, + GError *error, gpointer user_data ) + { + GHashTable *search_hash = ( GHashTable* ) user_data; + TpChan *search_chan = NULL; + DBusGProxy *search_iface = NULL; + + + UNUSED_FORMAL_PARAM( proxy ); + + iso_logger( "in do_search_reply"); + /* Create the object to represent the channel */ + if ( error ) + { + iso_logger( "Error in do_search_reply"); + //There was an error.. send it to client + send_response_to_client( globalCon.search_hdr_req, error->code, 0 ); + //Should error be returned to the client ? + return; + } + search_chan = tp_chan_new( globalCon.dbusConn, globalCon.connmgr_bus, chan_object_path, + TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, TP_CONN_HANDLE_TYPE_NONE, 0 ); + + globalCon.search_chan = search_chan; + + g_free(chan_object_path); + + + if ( NULL == search_chan ) + { + iso_logger( "returning because of search_chan"); + //search chan not created + //sending to client + send_response_to_client( globalCon.search_hdr_req, TP_SEARCH_CHAN_ERROR, 0 ); + return ; + } + //Get chan interface + search_iface = tp_chan_get_interface( search_chan, + TELEPATHY_CHAN_IFACE_CONTACTSEARCH_QUARK ); + + if ( NULL == search_iface ) + { + iso_logger( "returning because of search_iface"); + //interface for search chan not created + //send that to client + send_response_to_client( globalCon.search_hdr_req, TP_SEARCH_IFACE_ERROR, 0 ); + return ; + } + + //Register for the SearchResultReceived signal + //ownership of the srch_result->user_data is transfered + dbus_g_proxy_connect_signal( search_iface, "SearchResultReceived", + G_CALLBACK( search_result_received_cb ), + NULL, NULL ); + + + //Register for the SearchStateChanged signal + dbus_g_proxy_connect_signal( search_iface, "SearchStateChanged", + G_CALLBACK( search_state_changed_cb ), + NULL , NULL ); + //Call the search on tp + tp_chan_type_search_async( search_iface, search_hash , searchreply_cb, + NULL ); + + iso_logger( "out do_search_reply"); + + + } + + +/*! \brief This function is called by action_parse_search to search for fields +* \remark This function routes the searches to do_search_again if searched more +* than once. This is a workaround because we are getting the signal callbacks +* 'n'ths( where n is nth search ) time if search channel is created each time. +* +* \param search_hash Hash table having the search key and value pairs to be searched +* +* \return void +*/ + +gint do_search( GHashTable* search_hash ) + { + + iso_logger( "in do_search"); + + if(globalCon.search_chan == NULL) + { + tp_conn_request_channel_async( DBUS_G_PROXY( globalCon.conn ), + TP_IFACE_CHANNEL_TYPE_CONTACT_SEARCH, + TP_CONN_HANDLE_TYPE_NONE, 0, TRUE, + do_search_reply, (gpointer)search_hash ) ; + } + + else + { + iso_logger( "calling do_search_again"); + do_search_again(search_hash); + } + iso_logger( "out do_search"); + + return 0; + } + +/*! \brief This function is called if search is done more than once in same login session. +* \remark This is a workaround because we are getting the signal callbacks +* 'n'ths( where n is nth search ) time. +* +* \param search_hash Hash table having the search key and value pairs to be searched +* +* \return void +*/ +void do_search_again( GHashTable* search_hash ) + { + + DBusGProxy *search_iface = NULL; + + iso_logger( "in do_search_again"); + + if ( NULL == globalCon.search_chan ) + { + iso_logger( "returning because of search_chan"); + //search chan not created + //sending to client + send_response_to_client( globalCon.search_hdr_req, TP_SEARCH_CHAN_ERROR, 0 ); + return ; + } + //Get chan interface + search_iface = tp_chan_get_interface( globalCon.search_chan, + TELEPATHY_CHAN_IFACE_CONTACTSEARCH_QUARK ); + + if ( NULL == search_iface ) + { + iso_logger( "returning because of search_iface"); + //interface for search chan not created + //send that to client + send_response_to_client( globalCon.search_hdr_req, TP_SEARCH_IFACE_ERROR, 0 ); + return ; + } + + + //Call the search on tp + tp_chan_type_search_async( search_iface, search_hash, searchreply_cb, + NULL ); + + iso_logger( "out do_search_again"); + + + } + + +/* +! /brief This function is called by message_send_recv function in isoservermain.c if message type +* is ESearch. This function parses the rmsg, validates the parameter passed, if parameters are +* correct a search performed for them. else INVALID_PARAMETERES error is returned +* +* /param rmsg message buffer to be parsed +* /param rmsg_len the length of the rmsg +* /remark rmsg_len is not strlen(rmsg) +* /return returns error code or 0 on success +*/ +gint action_parse_search( gchar* rmsg, gint rmsg_len ) + { + + gint err = 0; + GHashTable* search_hash = NULL; + message_hdr_req* hdr_req = NULL; + //Allocate memory and set the memory to '\0' + iso_logger( "in action_parse_search"); + hdr_req = ( message_hdr_req* ) malloc ( sizeof ( message_hdr_req ) ); + + if ( NULL == hdr_req ) + { + return MEM_ALLOCATION_ERROR; + } + memset( hdr_req, '\0', sizeof( message_hdr_req ) ); + //Copy the header into message struct + memcpy( hdr_req, rmsg, sizeof( message_hdr_req ) ); + //Create the hash table + search_hash = g_hash_table_new( g_str_hash, g_str_equal ); + if ( NULL == search_hash ) + { + return MEM_ALLOCATION_ERROR; + } + //Parse the key value pairs to be searched into the hash + err = parse_for_search( rmsg, rmsg_len, search_hash ); + if ( !err ) + { + //Do the search on the fields + globalCon.search_hdr_req = hdr_req; + err = do_search( search_hash ); + } + iso_logger( "out action_parse_search"); + + return err; + } + +/*! \brief This function is called by search_results_recieved for each key/value +* pair of search result(one entry). This function appends the key/value pair +* to the message buffer in the key_value_struct(.msg) and increments +* the no. of bytes written to(key_value_struct.len) +* +* Format of response header(msg buffer) +* key1\0value1\0key2\0value2\0(key3\0value3\0) (3rd round append) +* +* \param key one field of the search entry +* \param value value for the above field +* \param user_data unused +* +* \return void +*/ + +void key_value_store( gpointer key, gpointer value, gpointer user_data ) + { + + key_value_struct* pairs = ( key_value_struct * ) user_data; + GValue* value1 = ( GValue* ) value; + const gchar *value_str = NULL; + const gchar *key_str = ( gchar* ) key; + + iso_logger( "in key_value_store"); + + value_str = g_value_get_string ( value1 ); + + if ( '\0' == *value_str ) + { + iso_logger( "No value"); + return; + } + + iso_logger( "key is %s", key_str ); + //copy The results key part + strcpy( pairs->msg + pairs->len, key_str ); + pairs->len += strlen( key_str ) + 1; + + iso_logger( "value is %s", value_str ); + //copy The results value part + strcpy( pairs->msg + pairs->len, value_str ); + pairs->len += strlen( value_str ) + 1; + iso_logger( "out key_value_store"); + } + + +/*! +* \brief This function is called when the search results are recieved +* This function is called for each contact found matching the +* search criteria. +* +* \param proxy unused +* \param contact_handle unused +* \param results Key value pair of one search result entry +* \param user_data unused +* +* \return void +*/ +static void search_result_received_cb ( DBusGProxy *proxy, + guint contact_handle, + GHashTable *results, + gpointer user_data + ) + { + message_hdr_resp hdr_resp; + //Get the header request + + message_hdr_req* hdr_request = globalCon.search_hdr_req; + key_value_struct pairs; + + gint pri = MSG_PRI_NORMAL; + gint result = 0; + gint timeout = NO_WAIT; + gint err = 0; + + //Create the handle + iso_logger( "in search_result_received_cb"); + + UNUSED_FORMAL_PARAM( proxy ); + UNUSED_FORMAL_PARAM( contact_handle ); + UNUSED_FORMAL_PARAM( user_data ); + + if ( g_hash_table_size( results ) <= 0 ) + { + iso_logger( "No results recieved"); + return; + } + + iso_logger("search result count for hash table %d", + g_hash_table_size( results ) ); + iso_logger("contact handle is %d", + contact_handle ); + + //Create the response header to be sent to client + //Copy the message header request + //Not copying from hdr req because it could have been modified + //in search_state_changed_cb + hdr_resp.hdr_req.message_type = ESearch; + hdr_resp.hdr_req.protocol_id = hdr_request->protocol_id; + hdr_resp.hdr_req.request_id = hdr_request->request_id; + hdr_resp.hdr_req.session_id = hdr_request->session_id; + //set continue flag + hdr_resp.continue_flag = 0; + hdr_resp.error_type = 0; + hdr_resp.response = 1; + //Allocate memory for the message and set memory to '\0' + pairs.msg = ( gchar* ) malloc ( MAX_PARAM_LEN ); + if ( NULL == pairs.msg ) + { + iso_logger( "malloc error @ pairs.msg" ); + return ; + } + memset( pairs.msg, '\0', MAX_PARAM_LEN ); + pairs.len = 0; + //Copy the response + memcpy( pairs.msg, &hdr_resp, sizeof ( message_hdr_resp ) ); + pairs.len += sizeof( message_hdr_resp ); + //Copy the contact name + iso_logger( "%s%d", "message type in search_result_received_cb", hdr_request->message_type ); + + + iso_logger( "%s", "start -------------------------------------------------" ); + + iso_logger( "%s", "contacts key value pair start" ); + + //Copy all the key/value pairs : + //no need to check for size here as it is already done at top + g_hash_table_foreach ( results, key_value_store, &pairs ); + + iso_logger( "%s", "end -------------------------------------------------" ); + + //End the message with a '\0' + pairs.len += 1; + pairs.msg[pairs.len] = '\0'; + //Send the message to client + result = MsgQSend( RESPONSE_QUEUE, pairs.msg, pairs.len, + pri, timeout, &err ); + + if ( result < 0 ) + { + + } + + //Free the hash table itself + g_hash_table_destroy ( results ); + + iso_logger( "in search_result_received_cb"); + } + +/*! \brief This function is a callback registered to searchstatechanged signal. +* This function is called by telepathygabble when status of the search is changed. +* +* \param proxy unused +* \param search_state state of the search +* \param user_data unused +* +* \return void +*/ +static void search_state_changed_cb ( DBusGProxy *proxy, + guint search_state, + gpointer user_data + ) + { + + gint err = 0; + //Get the header request + + iso_logger( "in search_state_changed_cb"); + + UNUSED_FORMAL_PARAM( proxy ); + UNUSED_FORMAL_PARAM( user_data ); + + + if ( 1 == search_state && globalCon.search_hdr_req ) + { + globalCon.search_hdr_req->message_type = ESearch_State_During; + err = send_response_to_client( globalCon.search_hdr_req, 0, 1 ); + if ( err ) + { + iso_logger( " 1 == search_state Error sending to client"); + //? + } + } + else if ( TP_CHANNEL_CONTACT_SEARCH_STATE_AFTER == search_state + && globalCon.search_hdr_req ) + { + globalCon.search_hdr_req->message_type = ESearch_State_Finished; + err = send_response_to_client( globalCon.search_hdr_req, 0, 1 ); + if ( err ) + { + iso_logger( "Error sending to client"); + //? + } + //Since the search is finished delete the hdr request + free ( globalCon.search_hdr_req ); + globalCon.search_hdr_req = NULL; + } + + + iso_logger( "out search_state_changed_cb"); + } + +/*! \brief Function called by telepathygabble when search channel is closed +* This function is regisered when calling the async function to close channel +* +* \param proxy unused +* \param error Error if any +* \param user_data unused +* +* \return void +*/ +void search_chan_closed_cb ( DBusGProxy *proxy, + GError *error, + gpointer user_data + ) + { + iso_logger( "in search_chan_closed_cb"); + UNUSED_FORMAL_PARAM( proxy ); + UNUSED_FORMAL_PARAM( error ); + UNUSED_FORMAL_PARAM( user_data ); + g_object_unref(globalCon.search_chan); + globalCon.search_chan = NULL; + iso_logger( "out search_chan_closed_cb"); + } + +/*! \brief Function called by telepathygabble when search request is sent to server. +* This function is can be thought of as an ack for search request from server. +* +* \param proxy unused +* \param error Network error if any +* \param user_data unused +* +* \return void +*/ +static void searchreply_cb( DBusGProxy *proxy, GError *error, gpointer userdata ) + { + + + iso_logger( "in searchreply_cb" ); + UNUSED_FORMAL_PARAM( proxy ); + UNUSED_FORMAL_PARAM( userdata ); + + if ( error ) + { + + iso_logger( "Error!!!!!" ); + //err cant be handled as of now/this is a special case + //where mem alloc is not possible when sending to client.. + send_response_to_client( globalCon.search_hdr_req, error->code, 0 ); + + tp_chan_close_async( DBUS_G_PROXY( globalCon.search_chan ), + search_chan_closed_cb, NULL ); + //Header request is deleted only in case of error + //Because the search_state_finished_cb will not be called + //In othr cases ownership of user_data is with search_state_finished_cb + + free ( globalCon.search_hdr_req ); + globalCon.search_hdr_req = NULL; + } + + iso_logger( "out searchreply_cb"); + + }