/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Linux Desktop Testing Project http://ldtp.freedesktop.org * * Author: * Veerapuram Varadhan * Nagappan Alagappan * * Copyright 2004 - 2006 Novell, Inc. * Copyright 2007 - 2008 Nagappan Alagappan * * This program 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 of the License, or (at your option) any later version. * * This program 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 program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110, USA. */ #include "ldtp.h" #include "remap.h" #include "ldtp-gui.h" #include "ldtp-utils.h" #include "ldtp-logger.h" #include "ldtp-command.h" #include "localization.h" #include "ldtp-gui-comp.h" #include "client-handler.h" #include "device.h" #include extern gboolean ldtp_debug; extern gint ldtp_gui_timeout; extern gint ldtp_obj_timeout; extern GHashTable *event_notifier; extern GHashTable *client_context; extern GHashTable *window_duration; extern gboolean ldtp_script_service; extern gboolean ldtp_external_xml_file; extern pthread_mutex_t cb_mutex; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static gboolean is_cctxt_registered_callback (gpointer key, gpointer value, gpointer user_data) { if (value && user_data && value == user_data) return TRUE; return FALSE; } static void register_window_creation_event (LDTPClientContext* cctxt, LDTPErrorCode* err) { if (!cctxt || !cctxt->req || !cctxt->req->context) *err = LDTP_ERROR_ARGUMENT_NULL; if (!event_notifier) event_notifier = g_hash_table_new_full (&g_str_hash, &g_str_equal, destroy_string, NULL); g_hash_table_insert (event_notifier, g_strdup ((gchar *)cctxt->req->context), cctxt); *err = LDTP_ERROR_SUCCESS; } static void unregister_window_creation_event (LDTPClientContext *cctxt, LDTPErrorCode *err) { g_print ("unregister_window_creation_event - %s - %d\n", __FILE__, __LINE__); if (!cctxt || !cctxt->req || !cctxt->req->context) { *err = LDTP_ERROR_ARGUMENT_NULL; g_print ("%s - %d - Argument NULL\n", __FILE__, __LINE__); return; } if (!event_notifier) { *err = LDTP_ERROR_EVENT_NOTIFIER_NOT_ENABLED; g_print ("%s - %d - Event notifier not enabled\n", __FILE__, __LINE__); return; } g_print ("Window: %s\n", cctxt->req->context); if (g_hash_table_find (event_notifier, search_title_based, cctxt->req->context) != NULL) { g_print ("Window unregistered\n"); g_hash_table_remove (event_notifier, cctxt->req->context); } *err = LDTP_ERROR_SUCCESS; } static char* write2file (char *content, long len) { char filename [] = "/tmp/LDTP-XML-XXXXXX"; int fd; if (content == NULL || len <= 0) { g_print ("Argument NULL\n"); return NULL; } if ((fd = mkstemp (filename)) < 0) { g_print ("Unable to create tmp file - mkstemp\n"); return NULL; } len = write (fd, content, len); close (fd); return g_strdup (filename); } void generate_response_packet (LDTPClientContext* cctxt, LDTPErrorCode* err, char **resp_pckt, uint32_t *resp_size) { uint32_t resp_len = 0; char buf [16]; char buf1 [16]; char *resp_xml = NULL; char *data_pckt = NULL; if (!cctxt || !cctxt->resp || !cctxt->req->request_id) { *err = LDTP_ERROR_ARGUMENT_NULL; return; } resp_len = XML_HEADER_LEN + RESPONSE_ELEMENT_LEN + RESPONSE_ID_ELEMENT_LEN + RESPONSE_ID_END_ELEMENT_LEN + STATUS_ELEMENT_LEN + ATTRIBUTE_CODE_ELEMENT_LEN + ATTRIBUTE_CODE_END_ELEMENT_LEN + ATTRIBUTE_MSG_ELEMENT_LEN + ATTRIBUTE_MSG_END_ELEMENT_LEN + STATUS_END_ELEMENT_LEN + RESPONSE_END_ELEMENT_LEN; g_print ("resp_len = %d\n", resp_len); if (cctxt->req->request_id) resp_len += strlen ((gchar *)cctxt->req->request_id); if (cctxt->resp->resp_status) resp_len += strlen (ldtp_error_get_message (cctxt->resp->resp_status)); memset (buf, 0x00, 16); sprintf (buf, "%d", cctxt->resp->resp_status); resp_len += strlen (buf); if (cctxt->resp->data && cctxt->resp->data_len > 0) { resp_len += DATA_ELEMENT_LEN + ATTRIBUTE_LENGTH_ELEMENT_LEN + ATTRIBUTE_LENGTH_END_ELEMENT_LEN + ATTRIBUTE_VALUE_ELEMENT_LEN + ATTRIBUTE_VALUE_END_ELEMENT_LEN + DATA_END_ELEMENT_LEN + cctxt->resp->data_len; memset (buf1, 0x00, 16); sprintf (buf1, "%ld", cctxt->resp->data_len); resp_len += strlen (buf1); } if (cctxt->resp->data && cctxt->resp->data_len > 0) { char *external_tmp_xml_file = getenv ("LDTP_EXTERNAL_TEMP_FILE"); if (!ldtp_script_service && (ldtp_external_xml_file || (external_tmp_xml_file != NULL && g_ascii_strcasecmp (external_tmp_xml_file, "1") == 0)) && cctxt->resp->data_len > 512) { char *filename = write2file (cctxt->resp->data, cctxt->resp->data_len); if (filename) { data_pckt = g_strconcat (ATTRIBUTE_FILE_ELEMENT, ATTRIBUTE_NAME_ELEMENT, filename, ATTRIBUTE_NAME_END_ELEMENT, ATTRIBUTE_FILE_END_ELEMENT, NULL); g_free (filename); } } else { data_pckt = g_strconcat (DATA_ELEMENT, ATTRIBUTE_LENGTH_ELEMENT, buf1, ATTRIBUTE_LENGTH_END_ELEMENT, ATTRIBUTE_VALUE_ELEMENT, cctxt->resp->data, ATTRIBUTE_VALUE_END_ELEMENT, DATA_END_ELEMENT, NULL); } } resp_xml = g_strdup_printf ("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", XML_HEADER, RESPONSE_ELEMENT, RESPONSE_ID_ELEMENT, cctxt->req->request_id, RESPONSE_ID_END_ELEMENT, STATUS_ELEMENT, ATTRIBUTE_CODE_ELEMENT, buf, ATTRIBUTE_CODE_END_ELEMENT, ATTRIBUTE_MSG_ELEMENT, ldtp_error_get_message (cctxt->resp->resp_status), ATTRIBUTE_MSG_END_ELEMENT, STATUS_END_ELEMENT, data_pckt ? data_pckt : "", RESPONSE_END_ELEMENT); if (data_pckt) g_free (data_pckt); *err = LDTP_ERROR_SUCCESS; *resp_size = strlen (resp_xml); *resp_pckt = resp_xml; } void generate_notification_packet (LDTPClientContext* cctxt, LDTPErrorCode* err, char **resp_pckt, uint32_t *resp_size) { uint32_t resp_len = 0; char buf [16]; char buf1 [16]; char *resp_xml = NULL; char *data_pckt = NULL; if (!cctxt || !cctxt->resp) { *err = LDTP_ERROR_ARGUMENT_NULL; return; } resp_len = XML_HEADER_LEN + NOTIFICATION_ELEMENT_LEN + STATUS_ELEMENT_LEN + ATTRIBUTE_CODE_ELEMENT_LEN + ATTRIBUTE_CODE_END_ELEMENT_LEN + ATTRIBUTE_MSG_ELEMENT_LEN + ATTRIBUTE_MSG_END_ELEMENT_LEN + STATUS_END_ELEMENT_LEN + NOTIFICATION_END_ELEMENT_LEN; /* Varadhan FIXME: Localization?? */ g_print ("resp_len = %d\n", resp_len); resp_len += strlen (ldtp_error_get_message (cctxt->resp->resp_status)); memset (buf, 0x00, 16); sprintf (buf, "%d", cctxt->resp->resp_status); resp_len += strlen (buf); if (cctxt->resp->data && cctxt->resp->data_len > 0) { resp_len += DATA_ELEMENT_LEN + ATTRIBUTE_LENGTH_ELEMENT_LEN + ATTRIBUTE_LENGTH_END_ELEMENT_LEN + ATTRIBUTE_VALUE_ELEMENT_LEN + ATTRIBUTE_VALUE_END_ELEMENT_LEN + DATA_END_ELEMENT_LEN + cctxt->resp->data_len; memset (buf1, 0x00, 16); sprintf (buf1, "%ld", cctxt->resp->data_len); resp_len += strlen (buf1); } if (cctxt->resp->data && cctxt->resp->data_len > 0) data_pckt = g_strconcat (DATA_ELEMENT, ATTRIBUTE_LENGTH_ELEMENT, buf1, ATTRIBUTE_LENGTH_END_ELEMENT, ATTRIBUTE_VALUE_ELEMENT, cctxt->resp->data, ATTRIBUTE_VALUE_END_ELEMENT, DATA_END_ELEMENT, NULL); resp_xml = g_strdup_printf ("%s%s%s%s%s%s%s%s%s%s%s%s", XML_HEADER, NOTIFICATION_ELEMENT, STATUS_ELEMENT, ATTRIBUTE_CODE_ELEMENT, buf, ATTRIBUTE_CODE_END_ELEMENT, ATTRIBUTE_MSG_ELEMENT, ldtp_error_get_message (cctxt->resp->resp_status), ATTRIBUTE_MSG_END_ELEMENT, STATUS_END_ELEMENT, data_pckt ? data_pckt : "", NOTIFICATION_END_ELEMENT); *err = LDTP_ERROR_SUCCESS; *resp_size = strlen (resp_xml); *resp_pckt = resp_xml; } void send_response (int sockfd, char *resp_xml, uint32_t resp_len, LDTPErrorCode *err) { char* resp_packet = NULL; //int i = 0; int pckt_len = 0; uint32_t resp_size = 0; resp_size = htonl (resp_len); resp_len += sizeof (resp_len); resp_packet = calloc (resp_len + 1, 1); memcpy (resp_packet, (void *)&resp_size, sizeof (resp_size)); uint32_t temp = ntohl (resp_size); g_print ("Sending..\n%d\n", temp); memcpy ((resp_packet + sizeof (resp_len)), resp_xml, resp_len - sizeof (resp_len)); g_print ("Response packet: %s\n", (resp_packet + sizeof (resp_len))); pckt_len = resp_len; /* If data sent in chunks from server to client, then the peek code in client was not able to continue reading the next chunk as the recv with peek option always returns the first chunk. */ ldtp_send (sockfd, resp_packet, resp_len, err); /* FIXME: Do not fragment memory. Use something similar to res-packet thingy. */ g_free (resp_packet); } static void add_item_to_list (gpointer key, gpointer value, gpointer list) { char **user_data = list; if (!key) return; char *data = *user_data; if (data) { gchar *tmp = NULL; gchar *escaped_xml_data = NULL; escaped_xml_data = escape_xml_character (key); /* FIXME: Avoid memory fragmentation */ tmp = g_strdup_printf ("%s%s", data, escaped_xml_data); g_free (escaped_xml_data); g_free (data); data = tmp; } else data = g_strdup_printf ("%s", (char *) key); *user_data = data; } static gboolean is_role_matching (gpointer key, gpointer value, gpointer list) { if (!value || !list) return FALSE; if (g_utf8_collate (value, list) == 0) return TRUE; return FALSE; } static void add_matching_item_to_list (gpointer key, gpointer value, gpointer list) { gchar *tmp = NULL; gchar *data = NULL; gchar *label = NULL; gchar *tmp_label = NULL; gchar *escaped_xml_data = NULL; MatchingList *list_item = list; if (!key || !value || !list) return; data = list_item->data; if (ldtp_debug && data) g_print ("key: %s - %s\n", (gchar *) key, data); if (list_item->children_ht && g_hash_table_lookup_extended (list_item->children_ht, key, NULL, NULL) == FALSE) { // If key doesn't exist in children_ht, then don't // process further return; } /* list_item->role == NULL ? then, let us add all of the entries to the list */ if (list_item->role == NULL || g_hash_table_find (value, is_role_matching, list_item->role)) { label = get_property (value, "label_by", NULL); if (!label) label = get_property (value, "label", NULL); if (!label) { tmp_label = g_strdup (key); } else { if (g_utf8_strchr (label, -1, '_')) { tmp = escape_character (label, '_'); tmp_label = g_strdup (tmp); g_free (tmp); } else { tmp_label = g_strdup (label); } } if (list_item->name && tmp_label && (g_utf8_collate (tmp_label, list_item->name) != 0 || g_pattern_match_simple (list_item->name, tmp_label) == FALSE)) { /* If name is not NULL and its label doesn't match, name, then let us not include in the list For example: name = Find, role = push_button in gedit application, just get, the label is Find and role type is push_button. */ if (tmp_label) g_free (tmp_label); return; } if (tmp_label) { g_free (tmp_label); tmp_label = NULL; } escaped_xml_data = escape_xml_character (key); if (data) { tmp = g_strdup_printf ("%s%s", data, escaped_xml_data); g_free (data); data = tmp; } else data = g_strdup_printf ("%s", escaped_xml_data); g_free (escaped_xml_data); list_item->data = data; } } #ifdef ENABLE_LOCALIZATION static void createpo (gchar *package_name, gchar *locale_dir, gchar *file_name, gchar *mode, FILE *log_fp, LDTPErrorCode *err) { gchar *locale_lang = NULL; locale_lang = getenv ("LANG"); if (locale_lang == NULL) { log_msg (LDTP_LOG_CAUSE, "Locale language environment not set - LANG", log_fp); *err = LDTP_ERROR_UTF8_ENGLISH_LANG; return; } else { gchar *tmp = NULL; gchar *mofilename = NULL; gchar *mopathfilename = NULL; struct stat dir_buf; gboolean folder_found = FALSE; if (g_ascii_strcasecmp (locale_lang, "en_US.UTF-8") == 0) { *err = LDTP_ERROR_UTF8_ENGLISH_LANG; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } if (stat (locale_dir, &dir_buf) != 0) { *err = LDTP_ERROR_UNABLE_TO_STAT_DIR; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } if (!S_ISDIR (dir_buf.st_mode)) { *err = LDTP_ERROR_UNABLE_TO_STAT_DIR; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } if (g_ascii_strcasecmp (mode, "mo") != 0) { *err = LDTP_ERROR_ONLY_MO_MODE_SUPPORTED; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } tmp = g_strdup_printf ("%s/%s", locale_dir, locale_lang); if (!tmp) { *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } mofilename = g_strdup_printf ("/LC_MESSAGES/%s.mo", package_name); if (!mofilename) { g_free (tmp); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("Checking in %s%s\n", tmp, mofilename); if ((stat (tmp, &dir_buf) == 0) && S_ISDIR (dir_buf.st_mode)) { mopathfilename = g_strdup_printf ("%s%s", tmp, mofilename); if (!mopathfilename) { g_free (tmp); g_free (mofilename); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("MO path filename: %s\n", mopathfilename); if ((stat (mopathfilename, &dir_buf) == 0) && S_ISREG (dir_buf.st_mode)) { folder_found = TRUE; } } if (!folder_found && g_utf8_strchr (tmp, -1, '.')) { gchar *stripped_data = strip_delim (tmp, '.'); g_free (mopathfilename); if (!stripped_data) { g_free (tmp); g_free (mofilename); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("MO Path sripped: %s\n", stripped_data); mopathfilename = g_strdup_printf ("%s%s", stripped_data, mofilename); g_free (stripped_data); if (!mopathfilename) { g_free (tmp); g_free (mofilename); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("MO path filename: %s\n", mopathfilename); if ((stat (mopathfilename, &dir_buf) == 0) && S_ISREG (dir_buf.st_mode)) { folder_found = TRUE; log_msg (LDTP_LOG_INFO, "Folder found", log_fp); } } if (!folder_found && g_utf8_strchr (tmp, -1, '_')) { gchar *stripped_data = strip_delim (tmp, '_'); g_free (mopathfilename); if (!stripped_data) { g_free (tmp); g_free (mofilename); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("MO Path sripped: %s\n", stripped_data); mopathfilename = g_strdup_printf ("%s%s", stripped_data, mofilename); g_free (stripped_data); if (!mopathfilename) { g_free (tmp); g_free (mofilename); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("MO path filename: %s\n", mopathfilename); if ((stat (mopathfilename, &dir_buf) == 0) && S_ISREG (dir_buf.st_mode)) { folder_found = TRUE; } } g_free (tmp); tmp = NULL; g_free (mofilename); mofilename = NULL; if (folder_found) { FILE *fp; gchar *unformat = NULL; gchar *data = NULL; log_msg (LDTP_LOG_INFO, mopathfilename, log_fp); unformat = g_strdup_printf ("msgunfmt %s -o %s", mopathfilename, file_name); g_free (mopathfilename); mopathfilename = NULL; if (!unformat) { *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } g_print ("Command: %s\n", unformat); fp = popen (unformat, "r"); if (!fp) { g_free (unformat); *err = LDTP_ERROR_UNABLE_TO_ALLOCATE_MEMORY; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } data = read_line (fileno (fp), err); if (data) g_print ("MO unformat command output: %s\n", data); g_free (data); g_free (unformat); pclose (fp); log_msg (LDTP_LOG_INFO, "Success", log_fp); return; } g_free (mopathfilename); } } static void deletepo (char *filename, FILE *log_fp, LDTPErrorCode *err) { if (unlink (filename) == 0) { log_msg (LDTP_LOG_INFO, "Successfully deleted file", log_fp); *err = LDTP_ERROR_SUCCESS; return; } else { *err = LDTP_ERROR_UNABLE_TO_DELETE_PO; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), log_fp); return; } } #endif static void bind_text (LDTPClientContext *cctxt, gchar *mode, LDTPErrorCode* err) { #ifdef ENABLE_LOCALIZATION gboolean temp_flag; gchar *filename = NULL; gchar *package_name = cctxt->req->context; gchar *locale_dir = cctxt->req->component; bindtextdomain (package_name, locale_dir); bind_textdomain_codeset (package_name, "UTF-8"); textdomain (package_name); /* * FIXME * Currently only mo files are handled */ if (g_ascii_strcasecmp (mode, "mo") == 0) { filename = g_strdup_printf ("%s/%s-%d.po", g_get_tmp_dir (), package_name, g_random_int_range (G_MININT, G_MAXINT)); createpo (package_name, locale_dir, filename, mode, cctxt->log_fp, err); if (*err != LDTP_ERROR_SUCCESS) { *err = LDTP_ERROR_UNABLE_TO_CREATE_PO; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } } else { filename = g_strdup_printf ("%s/%s", locale_dir, package_name); } temp_flag = init_catalog (filename, cctxt->log_fp); if (!cctxt->locale_set && temp_flag) cctxt->locale_set = temp_flag; if (g_ascii_strcasecmp (mode, "mo") == 0) deletepo (filename, cctxt->log_fp, err); g_free (filename); #else g_print ("Localization option not enabled in LDTP\n"); *err = LDTP_ERROR_INVALID_COMMAND; #endif } static void has_state (LDTPClientContext* cctxt, LDTPErrorCode* err) { guint i; char *state = NULL; long int state_id; AccessibleStateSet *state_set; guint len = g_slist_length (cctxt->req->arg_list); state_set = Accessible_getStateSet (cctxt->gui_handle->handle); if (len == 0) { *err = LDTP_ERROR_INVALID_STATE; goto error; } for (i = 0; i < len; i++) { state = g_slist_nth_data (cctxt->req->arg_list, i); if (state) { state_id = atol (state); g_print ("Command: %s - state_id: %ld\n", state, state_id); } else { *err = LDTP_ERROR_INVALID_STATE; goto error; } if (state_id == SPI_STATE_INVALID) { *err = LDTP_ERROR_INVALID_STATE; goto error; } if (AccessibleStateSet_contains (state_set, state_id) == FALSE) { *err = LDTP_ERROR_INVALID_STATE; goto error; } } *err = LDTP_ERROR_SUCCESS; error: AccessibleStateSet_unref (state_set); ldtp_gui_free_gui_handle (cctxt->gui_handle); cctxt->gui_handle = NULL; } static void get_all_states (LDTPClientContext* cctxt, LDTPErrorCode* err) { guint i; AccessibleStateSet *state_set; state_set = Accessible_getStateSet (cctxt->gui_handle->handle); if (!state_set) { *err = LDTP_ERROR_INVALID_STATE; goto error; } if (cctxt->resp->data) { g_free (cctxt->resp->data); cctxt->resp->data = NULL; } for (i = SPI_STATE_INVALID; i < SPI_STATE_LAST_DEFINED; i++) { if (AccessibleStateSet_contains (state_set, i)) { if (cctxt->resp->data) cctxt->resp->data = g_strdup_printf ("%s%d", cctxt->resp->data, i); else cctxt->resp->data = g_strdup_printf ("%d", i); } } if (cctxt->resp->data) { char *tmp = NULL; /* FRAME the output in XML format */ tmp = g_strdup_printf ("%s%s", XML_HEADER, cctxt->resp->data); g_free (cctxt->resp->data); cctxt->resp->data = NULL; if (tmp) { cctxt->resp->data = tmp; cctxt->resp->data_len = strlen (cctxt->resp->data); g_print ("LIST: %s - Data length: %ld\n", cctxt->resp->data, cctxt->resp->data_len); } else { *err = LDTP_ERROR_UNABLE_TO_GET_OBJECT_STATE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); goto error; } } else { *err = LDTP_ERROR_UNABLE_TO_GET_OBJECT_STATE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); goto error; } *err = LDTP_ERROR_SUCCESS; error: AccessibleStateSet_unref (state_set); ldtp_gui_free_gui_handle (cctxt->gui_handle); cctxt->gui_handle = NULL; } static void copy_hash_table (gpointer key, gpointer value, gpointer list) { if (!key || !value || !list) return; g_hash_table_insert (list, g_strdup (key), g_strdup (value)); } static void set_traversed (gpointer key, gpointer value, gpointer list) { if (!key || !value || !list) return; if (g_hash_table_lookup_extended (list, key, NULL, NULL)) { g_hash_table_replace (list, g_strdup (key), g_strdup ("1")); } } static void get_current_children (gpointer key, gpointer value, gpointer list) { guint i; guint length; gchar **token; gchar *children; GHashTable *component_ht; ChildrenList *children_list = list; if (!key || !value || !list || !children_list->context_ht || \ !children_list->tmp_ht) return; g_print ("Status: %d\n", g_hash_table_lookup_extended (children_list->context_ht, key, NULL, NULL)); if (g_hash_table_lookup_extended (children_list->context_ht, key, NULL, (gpointer) &component_ht)) { children = get_property (component_ht, "children", NULL); if (!children) return; g_print ("Children: %s\n", children); token = g_strsplit (children, " ", 0); if (token) { length = g_strv_length (token); for (i = 0; i < length; i++) { g_hash_table_insert (children_list->tmp_ht, g_strdup (token [i]), // Initialize the value // as 0, for yet to traverse g_strdup ("0")); } g_strfreev (token); } } } static gboolean all_node_traversed (gpointer key, gpointer value, gpointer list) { if (!key || !value) return FALSE; if (g_utf8_collate (value, "0") == 0) return TRUE; return FALSE; } static gchar* get_matching_child (LDTPClientContext *cctxt, GHashTable *context, gchar *component, gchar *role, gchar *parent, LDTPErrorCode *err) { guint i; guint length; char *data = NULL; gchar *children = NULL; gchar **token = NULL; ChildrenList children_list; MatchingList matching_list; GHashTable *tmp_ht = NULL; GHashTable *context_ht = context; GHashTable *matched_children = NULL; gboolean all_childrens_traversed = FALSE; GHashTable *component_ht = get_object_def (context, parent, NULL, cctxt->log_fp, FALSE); if (!component_ht) { update_cur_window_appmap_handle (cctxt, err); context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (context_ht) component_ht = get_object_def (context_ht, parent, NULL, cctxt->log_fp, FALSE); if (!component_ht) { g_print ("Unable to find component\n"); *err = LDTP_ERROR_UNABLE_TO_GET_COMPONENT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return NULL; } } children = get_property (component_ht, "children", cctxt->log_fp); if (!children) { g_print ("Current component doesn't have any children\n"); *err = LDTP_ERROR_UNABLE_TO_GET_PROPERTY; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return NULL; } token = g_strsplit (children, " ", 0); matched_children = g_hash_table_new_full (&g_str_hash, &g_str_equal, destroy_string, destroy_string); tmp_ht = g_hash_table_new_full (&g_str_hash, &g_str_equal, destroy_string, destroy_string); if (token) { length = g_strv_length (token); for (i = 0; i < length; i++) { g_hash_table_insert (matched_children, g_strdup (token [i]), // Initialize the value // as 0, for yet to traverse g_strdup ("0")); } g_strfreev (token); } // Make a copy of tmp_ht to matched_children, for iteration g_hash_table_foreach (matched_children, copy_hash_table, tmp_ht); if (tmp_ht == NULL) { g_print ("Unable to copy hash table\n"); g_hash_table_destroy (matched_children); return NULL; } // Base ht of the current context children_list.context_ht = context_ht; while (all_childrens_traversed == FALSE) { // New childrens will be added to this list children_list.tmp_ht = tmp_ht; // Get all current nodes children g_print ("Get current node children\n"); g_hash_table_foreach (matched_children, get_current_children, (gpointer) &children_list); tmp_ht = children_list.tmp_ht; // If tmp_ht key is in matched_children list, then // mark the value as traversed (1) g_print ("Set traversed to matching children\n"); g_hash_table_foreach (matched_children, set_traversed, tmp_ht); // Destroy existing copy of matched_children g_print ("Destroy matched children\n"); g_hash_table_destroy (matched_children); // Create new ht matched_children = g_hash_table_new_full (&g_str_hash, &g_str_equal, destroy_string, destroy_string); // Make a copy of tmp_ht to matched_children, for next iteration g_print ("Copy tmp_ht to matched_children\n"); g_hash_table_foreach (tmp_ht, copy_hash_table, matched_children); g_print ("Check all traversed node\n"); if (!g_hash_table_find (tmp_ht, all_node_traversed, NULL)) { // If all nodes are traversed, then NULL will // be returned, let us exit by that time all_childrens_traversed = TRUE; } } g_hash_table_destroy (tmp_ht); if (role && g_utf8_collate (role, "BY PASS GENERATEXML BUG") == 0) g_hash_table_foreach (matched_children, &add_item_to_list, (gpointer) &data); else { matching_list.data = data; matching_list.name = component == NULL ? NULL : \ g_utf8_collate (component, cctxt->req->context) == 0 ? NULL : component; if (matching_list.name) g_print ("List.Name: %s\n", matching_list.name); matching_list.role = role; matching_list.children_ht = matched_children; g_hash_table_foreach (context_ht, &add_matching_item_to_list, (gpointer) &matching_list); data = matching_list.data; } g_hash_table_destroy (matched_children); return data; } static void update_context_name (LDTPClientContext* cctxt) { if (!cctxt) return; if (cctxt->req && cctxt->req->context) { char *window_name = NULL; if (cctxt->app_handle) { // AC: avoiding more require to app level Accessible_unref (cctxt->app_handle); cctxt->app_handle = NULL; } cctxt->app_handle = get_window_handle (NULL, cctxt->app_under_test, cctxt->req->context, &window_name, NULL); if (window_name) { g_free (cctxt->req->context); cctxt->req->context = g_strdup (window_name); g_free (window_name); } } } static void handle_request (LDTPClientContext* cctxt, Packet* pckt, LDTPErrorCode* err) { static FILE *tmp_fp = NULL; LDTPRequest* ldtp_req = NULL; //LDTPResponse* ldtp_resp = NULL; LDTPGuiHandle* accessible = NULL; ldtp_req = cctxt->req; ldtp_request_fill_request (ldtp_req, pckt->packet, pckt->len, err); if (*err != LDTP_ERROR_SUCCESS) { /* FIXME: Error handling */ return; } if (ldtp_req->action_name == NULL) { *err = LDTP_ERROR_INVALID_COMMAND; return; } g_print ("Command: %s\n", ldtp_req->action_name); ldtp_req->command = atol (ldtp_req->action_name); if (ldtp_req->command == LDTP_CMD_INVALID) { *err = LDTP_ERROR_INVALID_COMMAND; return; } switch (ldtp_req->command) { case LDTP_CMD_SETLOCALE: if (cctxt->locale_lang) g_free (cctxt->locale_lang); cctxt->locale_lang = g_strdup (cctxt->req->context); cctxt->locale_set = TRUE; setlocale (LC_ALL, ""); return; case LDTP_CMD_LAUNCHAPP: { GError *error = NULL; gchar *standard_output; gint wait = atoi (cctxt->req->component); //Access gchar *env = g_slist_nth_data (cctxt->req->arg_list, 0); //Access gchar *cml = NULL; if (env && g_ascii_strcasecmp(env, "1") == 0) { g_setenv ("GTK_MODULES", "uiaccess:gail:atk-bridge", TRUE); g_setenv ("UIACCESS_MODULES", "alp_maxaccess", TRUE); g_setenv ("GNOME_ACCESSIBILITY", "1", TRUE); } if (cctxt->locale_lang) g_setenv ("LANG", cctxt->locale_lang, TRUE); //Access if ((cml = g_utf8_strchr(cctxt->req->context, -1, '&'))) { *cml = 0; // AC: FIXME If there are more than one &, it just run the first palce of str if (g_spawn_command_line_async (cctxt->req->context, &error)) { *err = LDTP_ERROR_SUCCESS; if (wait <= 0) wait = 5; sleep (wait); } else *err = LDTP_ERROR_UNABLE_TO_LAUNCH_APP; } else if (g_spawn_command_line_sync (cctxt->req->context, &standard_output, NULL, NULL, &error)) { sleep (wait); cctxt->resp->data = standard_output; cctxt->resp->data_len = strlen (cctxt->resp->data); } else { if (error) g_print ("%s\n", error->message); *err = LDTP_ERROR_UNABLE_TO_LAUNCH_APP; } return; } case LDTP_CMD_SETAPPMAP: case LDTP_CMD_INITAPPMAP: { char *appmap_filename = NULL; appmap_filename = g_slist_nth_data (cctxt->req->arg_list, 0); if (!appmap_filename) { *err = LDTP_ERROR_OPENING_APPMAP_FILE; return; } g_print ("Appmap file: %s\n", appmap_filename); if (cctxt->app_map) { ldtp_appmap_free (cctxt->app_map); cctxt->app_map = NULL; } cctxt->app_map = appmap_init (appmap_filename, cctxt->log_fp); if (!cctxt->app_map) *err = LDTP_ERROR_OPENING_APPMAP_FILE; return; } case LDTP_CMD_LOG: { char *log; char *mode = ""; log = (char *)cctxt->req->context; if (cctxt->req->component) mode = (char *)cctxt->req->component; /* If startlog is called only once, let us try to utilize tmp_fp for the rest of connections */ if (cctxt->log_fp == NULL) cctxt->log_fp = tmp_fp; if (g_ascii_strcasecmp (mode, "PASS") == 0) log_msg (LDTP_LOG_PASS, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "FAIL") == 0) log_msg (LDTP_LOG_FAIL, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "ERROR") == 0) log_msg (LDTP_LOG_ERROR, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "CAUSE") == 0) log_msg (LDTP_LOG_CAUSE, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "COMMENT") == 0) log_msg (LDTP_LOG_COMMENT, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "INFO") == 0) log_msg (LDTP_LOG_INFO, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "MEMINFO") == 0) log_msg (LDTP_LOG_MEMINFO, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "CPUINFO") == 0) log_msg (LDTP_LOG_CPUINFO, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "GROUPSTART") == 0) log_msg (LDTP_LOG_GROUP_START, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "GROUPSTATUS") == 0) log_msg (LDTP_LOG_GROUP_STATUS, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "GROUPEND") == 0) log_msg (LDTP_LOG_GROUP_END, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "SCRIPTSTART") == 0) log_msg (LDTP_LOG_SCRIPT_START, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "SCRIPTEND") == 0) log_msg (LDTP_LOG_SCRIPT_END, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "DATAFILENAME") == 0) log_msg (LDTP_LOG_DATA_FILENAME, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "WARNING") == 0) log_msg (LDTP_LOG_WARNING, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "TESTSTART") == 0) log_msg (LDTP_LOG_TESTSTART, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "TESTCASEID") == 0) log_msg (LDTP_LOG_TESTCASEID, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "TESTEND") == 0) log_msg (LDTP_LOG_TESTEND, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "BEGIN") == 0) log_msg (LDTP_LOG_BEGIN, log, cctxt->log_fp); else if (g_ascii_strcasecmp (mode, "END") == 0) log_msg (LDTP_LOG_END, log, cctxt->log_fp); else log_msg (LDTP_LOG_DEBUG, log, cctxt->log_fp); // Default is DEBUG mode return; } case LDTP_CMD_STARTLOG: { int overwrite = 1; if (cctxt->req->component) overwrite = atol ((char *)cctxt->req->component); // Open log file if (open_log_file ((char *)cctxt->req->context, overwrite == 0 ? LDTP_LOG_FILE_APPEND : LDTP_LOG_FILE_DELETE, &cctxt->log_fp)) *err = LDTP_ERROR_SUCCESS; else *err = LDTP_ERROR_OPENING_LOG_FILE; tmp_fp = cctxt->log_fp; return; } case LDTP_CMD_STOPLOG: close_log_file (&cctxt->log_fp); cctxt->log_fp = NULL; return; case LDTP_CMD_STOPSCRIPTENGINE: *err = LDTP_ERROR_STOP_SCRIPT_ENGINE; return; case LDTP_CMD_GENERATEMOUSEEVENT: { SPIBoolean flag; long x = 0, y = 0; gchar *mode = "b1c"; if (cctxt->req->context) x = strtol (cctxt->req->context, NULL, 10); if (cctxt->req->component) y = strtol (cctxt->req->component, NULL, 10); if (cctxt->req->arg_list) mode = g_slist_nth_data (cctxt->req->arg_list, 0); flag = SPI_generateMouseEvent (x, y, mode); if (flag) *err = LDTP_ERROR_SUCCESS; else *err = LDTP_ERROR_MOUSE_ACTION_FAILED; return; } case LDTP_CMD_GENERATEKEYEVENT: case LDTP_CMD_KEYPRESS: case LDTP_CMD_KEYRELEASE: *err = device_main (cctxt, cctxt->req->command); return; case LDTP_CMD_SETCONTEXT: set_new_context ((char *)cctxt->req->context, (char *)cctxt->req->component); return; case LDTP_CMD_WINDOWUPTIME: { GHashTable *window_up_time; if (g_hash_table_lookup_extended (window_duration, cctxt->req->context, NULL, (gpointer) &window_up_time)) { char *start_time = g_hash_table_lookup (window_up_time, "start_time"); char *end_time = g_hash_table_lookup (window_up_time, "end_time"); g_print ("WINDOWUPTIME: %s %s\n", start_time, end_time); cctxt->resp->data = g_strdup_printf ("%s-%s", end_time, start_time); cctxt->resp->data_len = strlen (cctxt->resp->data); } else g_print ("NULL\n"); return; } case LDTP_CMD_RELEASECONTEXT: release_last_context (); return; case LDTP_CMD_REINITLDTP: { int leaked; int init_error; if (cctxt->app_handle) { Accessible_unref (cctxt->app_handle); cctxt->app_handle = NULL; } if ((leaked = SPI_exit ())) printf ("Leaked %d SPI handles\n", leaked); sleep (2); init_error = SPI_init (); if (init_error) { printf ("Error: SPI Init %d\n", init_error); *err = LDTP_ERROR_UNABLE_TO_REINIT_LDTP; return; } *err = LDTP_ERROR_SUCCESS; return; } case LDTP_CMD_GUIEXIST: update_context_name (cctxt); ldtp_gui_gui_exist (cctxt, err); return; case LDTP_CMD_GUITIMEOUT: if (cctxt && cctxt->req && cctxt->req->context) { g_print ("GUI Time out: %s\n", cctxt->req->context); ldtp_gui_timeout = atoi (cctxt->req->context); *err = LDTP_ERROR_SUCCESS; return; } *err = LDTP_ERROR_SET_GUI_TIMEOUT_FAILED; return; case LDTP_CMD_OBJTIMEOUT: if (cctxt && cctxt->req && cctxt->req->context) { g_print ("OBJ Time out: %s\n", cctxt->req->context); ldtp_obj_timeout = atoi (cctxt->req->context); *err = LDTP_ERROR_SUCCESS; return; } *err = LDTP_ERROR_SET_OBJ_TIMEOUT_FAILED; return; case LDTP_CMD_WAITTILLGUIEXIST: update_context_name (cctxt); ldtp_gui_wait_till_gui_exist (cctxt, err); return; case LDTP_CMD_WAITTILLGUINOTEXIST: update_context_name (cctxt); ldtp_gui_wait_till_gui_not_exist (cctxt, err); return; case LDTP_CMD_APPUNDERTEST: if (cctxt && cctxt->req && cctxt->req->context) { g_print ("Application under test: %s\n", cctxt->req->context); if (cctxt->app_under_test) g_free (cctxt->app_under_test); cctxt->app_under_test = g_strdup (cctxt->req->context); *err = LDTP_ERROR_SUCCESS; return; } *err = LDTP_ERROR_SET_APP_UNDER_TEST_NAME_FAILED; return; case LDTP_CMD_DOESMENUITEMEXIST: case LDTP_CMD_MENUITEMENABLED: case LDTP_CMD_MENUCHECK: case LDTP_CMD_MENUUNCHECK: case LDTP_CMD_VERIFYMENUCHECK: case LDTP_CMD_VERIFYMENUUNCHECK: case LDTP_CMD_SELECTMENUITEM: if (g_utf8_strchr (ldtp_req->component, -1, ';')) { gchar **token = NULL; // If 1 is specified to 3rd arg, the result is not correct token = g_strsplit (ldtp_req->component, ";", 2); gchar *tmp = token [1]; cctxt->req->arg_list = g_slist_append (cctxt->req->arg_list, g_strdup (tmp)); g_free (ldtp_req->component); ldtp_req->component = g_strdup (token [0]); g_strfreev (token); } break; case LDTP_CMD_ONWINDOWCREATE: register_window_creation_event (cctxt, err); return; case LDTP_CMD_REMOVECALLBACK: unregister_window_creation_event (cctxt, err); return; case LDTP_CMD_REMAP: if (cctxt->req->component == NULL) { update_cur_window_appmap_handle (cctxt, err); } else { update_cur_context_appmap_handle (cctxt, err); } return; case LDTP_CMD_BINDTEXT: { gchar *mode = NULL; if (cctxt->req->arg_list) mode = g_slist_nth_data (cctxt->req->arg_list, 0); bind_text (cctxt, mode, err); return; } case LDTP_CMD_GETWINDOWSIZE: ldtp_gui_get_window_size (cctxt, err); return; case LDTP_CMD_GETAPPLIST: { gchar *data = NULL; GHashTable *table; table = get_app_list (); if (table) { g_hash_table_foreach (table, &add_item_to_list, (gpointer) &data); cctxt->resp->data = data; if (cctxt->resp->data) { char *tmp = NULL; /* FRAME the output in XML format */ tmp = g_strdup_printf ("%s%s", XML_HEADER, data); if (tmp) { g_free (data); cctxt->resp->data = tmp; cctxt->resp->data_len = strlen (cctxt->resp->data); g_print ("LIST: %s - Data length: %ld\n", cctxt->resp->data, cctxt->resp->data_len); } else { *err = LDTP_ERROR_UNABLE_TO_GET_APPLICATION_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } } else { *err = LDTP_ERROR_UNABLE_TO_GET_APPLICATION_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } g_hash_table_destroy (table); } else { *err = LDTP_ERROR_UNABLE_TO_GET_APPLICATION_LIST; g_print ("%s - %s\n", __FILE__, ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } return; } case LDTP_CMD_GETWINDOWLIST: { gchar *data = NULL; GHashTable *table; table = get_window_name_list (); if (table) { g_hash_table_foreach (table, &add_item_to_list, (gpointer)&data); cctxt->resp->data = data; if (cctxt->resp->data) { char *tmp = NULL; /* FRAME the output in XML format */ tmp = g_strdup_printf ("%s%s", XML_HEADER, data); if (tmp) { g_free (data); cctxt->resp->data = tmp; g_print ("LIST: %s\n", cctxt->resp->data); cctxt->resp->data_len = strlen (cctxt->resp->data); } else { *err = LDTP_ERROR_UNABLE_TO_GET_WINDOW_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } } else { *err = LDTP_ERROR_UNABLE_TO_GET_WINDOW_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } g_hash_table_destroy (table); } else { *err = LDTP_ERROR_UNABLE_TO_GET_WINDOW_LIST; g_print ("%s - %s\n", __FILE__, ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } return; } case LDTP_CMD_GETOBJECTLIST: { char *data = NULL; GHashTable *ht = NULL; update_context_name (cctxt); if (!cctxt->req->context) { *err = LDTP_ERROR_ARGUMENT_NULL; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } if (!cctxt->app_map) { /* if appmap not already initialised, do it now */ accessible = ldtp_gui_get_gui_handle (cctxt, err); // ldtp_gui_free_gui_handle (accessible); /* Maybe it got something wrong in ldtp_gui_get_gui_handle, but let us retry to getinfo if (*err != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } */ } if (cctxt->app_map) ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (!ht) { update_cur_window_appmap_handle (cctxt, err); ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (*err != LDTP_ERROR_SUCCESS) { g_print ("Unable to update context: %s in appmap", (char *)cctxt->req->context); return; } } if (!ht) { g_print ("Unable to find context\n"); *err = LDTP_ERROR_UNABLE_TO_GET_CONTEXT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } g_hash_table_foreach (ht, &add_item_to_list, (gpointer)&data); cctxt->resp->data = data; if (cctxt->resp->data) { char *tmp = NULL; /* FRAME the output in XML format */ tmp = g_strdup_printf ("%s%s", XML_HEADER, data); if (tmp) { g_free (data); cctxt->resp->data = tmp; // FIXME: Verified in us-en environment, need to verify in localization env cctxt->resp->data_len = strlen (cctxt->resp->data); if (ldtp_debug) g_print ("LIST: %ld - %s\n", cctxt->resp->data_len, cctxt->resp->data); } else { *err = LDTP_ERROR_UNABLE_TO_GET_OBJECT_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } } else { *err = LDTP_ERROR_UNABLE_TO_GET_OBJECT_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } return; } case LDTP_CMD_GETCHILD: { char *data = NULL; char *name = g_strdup (cctxt->req->component); char *role = NULL; char *parent = NULL; MatchingList list; GHashTable *context_ht = NULL; update_context_name (cctxt); if (!cctxt->req->context) { *err = LDTP_ERROR_ARGUMENT_NULL; g_print ("%s %s %d\n", ldtp_error_get_message (*err), __FILE__, __LINE__); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); if (name) g_free (name); return; } if (!cctxt->app_map) { /* if appmap not already initialised, do it now */ accessible = ldtp_gui_get_gui_handle (cctxt, err); if (accessible->handle != cctxt->app_handle) ldtp_gui_free_gui_handle (accessible); if (*err != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); if (name) g_free (name); return; } } context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (!context_ht) { update_cur_window_appmap_handle (cctxt, err); context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (*err != LDTP_ERROR_SUCCESS) { g_print ("Unable to update context: %s in appmap", (char *)cctxt->req->context); if (name) g_free (name); return; } } if (!context_ht) { g_print ("Unable to find context\n"); *err = LDTP_ERROR_UNABLE_TO_GET_CONTEXT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); if (name) g_free (name); return; } role = g_slist_nth_data (cctxt->req->arg_list, 0); parent = g_slist_nth_data (cctxt->req->arg_list, 1); if (parent) g_print ("Parent: %s\n", parent); if (parent != NULL && g_utf8_collate (parent, "") != 0) { cctxt->resp->data = get_matching_child (cctxt, context_ht, name, role, parent, err); } else { list.data = data; list.name = name == NULL ? NULL : \ g_utf8_collate (name, cctxt->req->context) == 0 ? NULL : name; if (list.name) g_print ("List.Name: %s\n", list.name); list.role = role; list.children_ht = NULL; g_hash_table_foreach (context_ht, &add_matching_item_to_list, (gpointer) &list); cctxt->resp->data = list.data; } if (cctxt->resp->data) { char *tmp = NULL; /* FRAME the output in XML format */ tmp = g_strdup_printf ("%s%s", XML_HEADER, cctxt->resp->data); if (tmp) { g_free (cctxt->resp->data); cctxt->resp->data = tmp; if (ldtp_debug) g_print ("LIST: %s\n", tmp); cctxt->resp->data_len = strlen (cctxt->resp->data); } else { g_free (cctxt->resp->data); *err = LDTP_ERROR_UNABLE_TO_GET_CHILD_WITH_PROVIDED_ROLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } } else { *err = LDTP_ERROR_UNABLE_TO_GET_CHILD_WITH_PROVIDED_ROLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } if (name) g_free (name); return; } case LDTP_CMD_GETOBJECTINFO: { char *data = NULL; GHashTable *context_ht = NULL; GHashTable *component_ht = NULL; // update_context_name (cctxt); // AC: if compoent existed previously, this will return a fake info. update_cur_window_appmap_handle (cctxt, err); if (!cctxt->req->context || !cctxt->req->component) { *err = LDTP_ERROR_ARGUMENT_NULL; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } if (!cctxt->app_map) { /* if appmap not already initialised, do it now */ accessible = ldtp_gui_get_gui_handle (cctxt, err); if (accessible->handle != cctxt->app_handle) ldtp_gui_free_gui_handle (accessible); if (*err != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } } context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (!context_ht) { update_cur_window_appmap_handle (cctxt, err); context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (*err != LDTP_ERROR_SUCCESS) { g_print ("Unable to update context: %s in appmap", (char *)cctxt->req->context); return; } } if (!context_ht) { g_print ("Unable to find context\n"); *err = LDTP_ERROR_UNABLE_TO_GET_CONTEXT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } component_ht = get_object_def (context_ht, (char *)cctxt->req->component, NULL, cctxt->log_fp, FALSE); if (!component_ht) { update_cur_window_appmap_handle (cctxt, err); context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (context_ht) component_ht = get_object_def (context_ht, (char *)cctxt->req->component, NULL, cctxt->log_fp, FALSE); if (!component_ht) { g_print ("Unable to find component\n"); *err = LDTP_ERROR_UNABLE_TO_GET_COMPONENT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } } g_hash_table_foreach (component_ht, &add_item_to_list, (gpointer)&data); cctxt->resp->data = data; if (cctxt->resp->data) { char *tmp = NULL; /* FRAME the output in XML format */ tmp = g_strdup_printf ("%s%s", XML_HEADER, data); if (tmp) { g_free (data); cctxt->resp->data = tmp; g_print ("LIST: %s\n", cctxt->resp->data); cctxt->resp->data_len = strlen (cctxt->resp->data); } else { *err = LDTP_ERROR_UNABLE_TO_GET_OBJECT_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } } else { *err = LDTP_ERROR_UNABLE_TO_GET_OBJECT_LIST; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); } return; } case LDTP_CMD_GETOBJECTPROPERTY: { char *property = NULL; char *obj_property = NULL; GHashTable *context_ht = NULL; GHashTable *component_ht = NULL; update_context_name (cctxt); if (!cctxt->req->context || !cctxt->req->component) { *err = LDTP_ERROR_ARGUMENT_NULL; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } if (cctxt && !cctxt->app_map) { /* if appmap not already initialised, do it now */ accessible = ldtp_gui_get_gui_handle (cctxt, err); if (accessible && cctxt && accessible->handle != cctxt->app_handle) ldtp_gui_free_gui_handle (accessible); if (*err != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } } context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (!context_ht) { update_cur_window_appmap_handle (cctxt, err); context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (*err != LDTP_ERROR_SUCCESS) { g_print ("Unable to update context: %s in appmap", (char *)cctxt->req->context); return; } } if (!context_ht) { g_print ("Unable to find context\n"); *err = LDTP_ERROR_UNABLE_TO_GET_CONTEXT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } component_ht = get_object_def (context_ht, (char *)cctxt->req->component, NULL, cctxt->log_fp, FALSE); if (!component_ht) { update_cur_window_appmap_handle (cctxt, err); context_ht = get_object_def (cctxt->app_map, (char *)cctxt->req->context, NULL, cctxt->log_fp, TRUE); if (context_ht) component_ht = get_object_def (context_ht, (char *)cctxt->req->component, NULL, cctxt->log_fp, TRUE); if (!component_ht) { g_print ("Unable to find component\n"); *err = LDTP_ERROR_UNABLE_TO_GET_COMPONENT_HANDLE; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } } property = g_slist_nth_data (cctxt->req->arg_list, 0); obj_property = get_property (component_ht, property, cctxt->log_fp); if (!obj_property) { g_print ("Unable to find property\n"); *err = LDTP_ERROR_UNABLE_TO_GET_PROPERTY; g_print ("%s\n", ldtp_error_get_message (*err)); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (*err), cctxt->log_fp); return; } cctxt->resp->data = g_strdup (obj_property); cctxt->resp->data_len = strlen (obj_property); return; } case LDTP_CMD_GENERATEMD5: { #ifdef ENABLE_ACCESS FILE *fp; int len = 0; guchar *buffer = 0; gchar *md5 = 0; fp = fopen (cctxt->req->context, "rb"); if (fp == NULL) return; fseek (fp, 0L, SEEK_END); len = ftell (fp); buffer = (guchar *) malloc (len * sizeof (guchar)); if (!buffer) return; rewind (fp); // Just to avoid compilation warning assigned fread // return value to cctxt->resp->data_len cctxt->resp->data_len = fread (buffer, 1, len , fp); fclose (fp); md5 = g_compute_checksum_for_data (G_CHECKSUM_MD5, buffer, len); g_print ("MD5 checksum of file: %s is: %s\n", cctxt->req->context, md5); g_free (buffer); cctxt->resp->data = md5; cctxt->resp->data_len = strlen (cctxt->resp->data); #else *err = LDTP_ERROR_COMMAND_NOT_SUPPORTED; #endif return; } case LDTP_CMD_GETFILE: { #ifdef ENABLE_ACCESS FILE *fp; int len = 0; guchar *buffer = 0; gchar *encoded = 0; fp = fopen (cctxt->req->context, "rb"); if (fp == NULL) return; fseek (fp, 0L, SEEK_END); len = ftell (fp); buffer = (guchar *) malloc (len * sizeof (guchar)); if (!buffer) return; rewind (fp); // Just to avoid compilation warning assigned fread // return value to cctxt->resp->data_len cctxt->resp->data_len = fread (buffer, 1, len , fp); fclose (fp); encoded = g_base64_encode (buffer, len); cctxt->resp->data = encoded; cctxt->resp->data_len = strlen (cctxt->resp->data); g_free (buffer); #else *err = LDTP_ERROR_COMMAND_NOT_SUPPORTED; #endif return; } } update_context_name (cctxt); /* 1) Get the Accessible object corresponding to "component-name". 2) Get the class-id and 3) Call the corresponding component main function with necessary arguments. */ pthread_mutex_lock (&mutex); accessible = ldtp_gui_get_gui_handle (cctxt, err); if (*err != LDTP_ERROR_SUCCESS) { /* FIXME: Error handling */ g_print ("Unable to get handle\n"); pthread_mutex_unlock (&mutex); return; } else { char *name = NULL; if (accessible && accessible->handle) name = Accessible_getRoleName (accessible->handle); if (name) { g_print ("Got gui handle - %s\n", name); SPI_freeString (name); } } /* Update the gui handle in the context */ cctxt->gui_handle = accessible; if (cctxt->req->command == LDTP_CMD_HASSTATE) { has_state (cctxt, err); pthread_mutex_unlock (&mutex); return; } if (cctxt->req->command == LDTP_CMD_GETALLSTATES) { get_all_states (cctxt, err); pthread_mutex_unlock (&mutex); return; } pthread_mutex_unlock (&mutex); //sleep (1); switch (cctxt->gui_handle->class_id) { case SPI_ROLE_COMBO_BOX: *err = combo_box_main (cctxt, cctxt->req->command); break; case SPI_ROLE_CHECK_BOX: *err = check_box_main (cctxt, cctxt->req->command); break; case SPI_ROLE_CHECK_MENU_ITEM: *err = check_menu_item_main (cctxt, cctxt->req->command); break; case SPI_ROLE_RADIO_BUTTON: *err = radio_button_main (cctxt, cctxt->req->command); break; case SPI_ROLE_RADIO_MENU_ITEM: *err = radio_menu_item_main (cctxt, cctxt->req->command); break; #ifdef ENABLE_NEWROLES case SPI_ROLE_LINK: *err = link_main (cctxt, cctxt->req->command); break; #endif case SPI_ROLE_PUSH_BUTTON: *err = push_button_main (cctxt, cctxt->req->command); break; case SPI_ROLE_TOGGLE_BUTTON: *err = toggle_button_main (cctxt, cctxt->req->command); break; case SPI_ROLE_EMBEDDED: *err = embedded_component_main (cctxt, cctxt->req->command); break; case SPI_ROLE_LIST: *err = list_main (cctxt, cctxt->req->command); break; case SPI_ROLE_TEXT: #ifdef ENABLE_NEWROLES case SPI_ROLE_ENTRY: #endif case SPI_ROLE_EDITBAR: case SPI_ROLE_PARAGRAPH: case SPI_ROLE_AUTOCOMPLETE: case SPI_ROLE_PASSWORD_TEXT: *err = text_main (cctxt, cctxt->req->command); break; case SPI_ROLE_PANEL: *err = panel_main (cctxt, cctxt->req->command); break; case SPI_ROLE_ICON: *err = icon_main (cctxt, cctxt->req->command); break; case SPI_ROLE_LAYERED_PANE: *err = layered_pane_main (cctxt, cctxt->req->command); break; case SPI_ROLE_LABEL: *err = label_main (cctxt, cctxt->req->command); break; case SPI_ROLE_MENU: *err = menu_main (cctxt, cctxt->req->command, (gchar *)ldtp_req->context); break; case SPI_ROLE_MENU_ITEM: *err = menu_item_main (cctxt, cctxt->req->command); break; case SPI_ROLE_PAGE_TAB_LIST: *err = page_tab_list_main (cctxt, cctxt->req->command); break; case CALENDAR_VIEW: *err = calendar_view_main (cctxt, cctxt->req->command); break; case SPI_ROLE_CALENDAR: *err = calendar_main (cctxt, cctxt->req->command); break; case SPI_ROLE_SPIN_BUTTON: *err = spin_button_main (cctxt, cctxt->req->command); break; case SPI_ROLE_TABLE: *err = table_main (cctxt, cctxt->req->command); break; case SPI_ROLE_TREE: case SPI_ROLE_TREE_TABLE: *err = tree_table_main (cctxt, cctxt->req->command); break; case SPI_ROLE_SCROLL_BAR: *err = scroll_bar_main (cctxt, cctxt->req->command); break; case SPI_ROLE_SCROLL_PANE: *err = scroll_pane_main (cctxt, cctxt->req->command); break; case SPI_ROLE_SLIDER: *err = slider_main (cctxt, cctxt->req->command); break; case SPI_ROLE_STATUS_BAR: *err = status_bar_main (cctxt, cctxt->req->command); break; case SPI_ROLE_TOOL_BAR: *err = tool_bar_main (cctxt, cctxt->req->command); break; case SPI_ROLE_PROGRESS_BAR: *err = progress_bar_main (cctxt, cctxt->req->command); break; #ifdef ENABLE_ACCESS case SPI_ROLE_TITLE_BAR: *err = title_bar_main (cctxt, cctxt->req->command, (gchar *)ldtp_req->context); break; case SPI_ROLE_REPEAT_BUTTON: *err = repeat_button_main (cctxt, cctxt->req->command); break; case SPI_ROLE_COMMANDBAR_BUTTON: *err = commandbar_button_main (cctxt, cctxt->req->command); break; case SPI_ROLE_DATE_SELECTOR: *err = date_selector_main (cctxt, cctxt->req->command); break; #endif default: if (cctxt->req->command == LDTP_CMD_KBDENTER) { *err = device_main (cctxt, cctxt->req->command); break; } else if (cctxt->req->command == LDTP_CMD_GRABFOCUS) { AccessibleComponent *accessibleComponent; accessibleComponent = Accessible_getComponent (cctxt->gui_handle->handle); if (accessibleComponent && cctxt->req->context) { g_print ("Window: %s - GrabFocus\n", cctxt->req->context); if (AccessibleComponent_grabFocus (accessibleComponent) == TRUE) *err = LDTP_ERROR_SUCCESS; else *err = LDTP_ERROR_UNABLE_TO_GRAB_FOCUS; Accessible_unref (accessibleComponent); break; } *err = LDTP_ERROR_UNABLE_TO_GRAB_FOCUS; break; } else if (cctxt->req->command == LDTP_CMD_GETOBJECTSIZE) { cctxt->resp->data_len = 0; cctxt->resp->data = get_size (cctxt->gui_handle->handle, err); if (cctxt->resp->data) cctxt->resp->data_len = g_utf8_strlen (cctxt->resp->data, -1); break; } else if (cctxt->req->command == LDTP_CMD_MOUSELEFTCLICK || cctxt->req->command == LDTP_CMD_MOUSERIGHTCLICK) { *err = device_main (cctxt, cctxt->req->command); break; } *err = LDTP_ERROR_ROLE_NOT_IMPLEMENTED; g_print ("Role not implemented: %s %d\n", __FILE__, __LINE__); break; } /* Need to update cctxt->resp with appropriate status_code and data. For this, we have to have a switch case on command-id, because not all commands return data. */ } void * handle_client (void *ptr) { int sock_fd = (int) ptr; char* packet = NULL; char* tmpptr = NULL; uint32_t packet_len; uint32_t packet_read; uint32_t pckt_len = 0; uint32_t i = 0; size_t bytes_read = 0; uint32_t resp_size = 0; char *resp_pckt = NULL; LDTPErrorCode status = 0; LDTPClientContext *cctxt = NULL; Packet *pckt = NULL; cctxt = g_new0 (LDTPClientContext, 1); if (!cctxt) // Access return NULL; cctxt->app_map = NULL; cctxt->app_handle = NULL; cctxt->req = g_new0 (LDTPRequest, 1); ldtp_request_init (cctxt->req); cctxt->resp = g_new0 (LDTPResponse, 1); cctxt->resp->data = NULL; cctxt->sock_fd = sock_fd; cctxt->log_fp = NULL; cctxt->locale_set = FALSE; while (1) { packet_len = 0; ldtp_read_sizet (sock_fd, &packet_len, &status); if (status != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (status), cctxt->log_fp); goto error; } packet_len = ntohl (packet_len); g_print ("Client packet len: %d\n", packet_len); if (packet_len <= 0) { status = LDTP_ERROR_PACKET_INVALID; log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (status), cctxt->log_fp); goto error; } packet = g_malloc0 (packet_len + 1); if (!packet) // ACCESS goto error; tmpptr = packet; pckt_len = packet_len; packet_read = 0; while (pckt_len > 0) { g_print ("i = %d\n", i); pckt_len = pckt_len > 512 ? 512 : pckt_len; ldtp_read_data (sock_fd, packet, pckt_len, &bytes_read, &status); if (status != LDTP_ERROR_SUCCESS) { /* FIXME: ldtp_log ("Connection: closed [%s:%d]\n", client->ip_address, client->socketfd); */ g_print ("Client closed connection\n"); log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (status), cctxt->log_fp); goto error; } if (packet && ldtp_debug) g_print ("Data read %d, packet-len = %d, bytes read = %d, data: %s\n", pckt_len, packet_len, bytes_read, packet); packet += bytes_read; packet_read += bytes_read; pckt_len = packet_len - packet_read; g_print ("Packet length remaing to read: %d\n", pckt_len); if (pckt_len <= 0 || bytes_read == 0) break; } packet = tmpptr; if (packet) g_print ("Received packet [%s] through %d of len: %d\n", packet, sock_fd, packet_len); pckt = g_new0 (Packet, 1); if (!pckt) goto error; pckt->packet = packet; pckt->len = packet_len; handle_request (cctxt, pckt, &status); ldtp_gui_free_gui_handle (cctxt->gui_handle); cctxt->gui_handle = NULL; if (cctxt->app_handle) { Accessible_unref (cctxt->app_handle); cctxt->app_handle = NULL; } if (status == LDTP_ERROR_STOP_SCRIPT_ENGINE) { goto error; } if (packet) g_free (packet); packet = NULL; if (pckt) g_free (pckt); pckt = NULL; cctxt->resp->resp_status = status; generate_response_packet (cctxt, &status, &resp_pckt, &resp_size); if (status != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (status), cctxt->log_fp); g_print ("Error generating response\n"); goto error; } send_response (cctxt->sock_fd, resp_pckt, resp_size, &status); if (status != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (status), cctxt->log_fp); g_print ("Error sending response\n"); goto error; } g_free (resp_pckt); if (cctxt->resp->data) { g_free (cctxt->resp->data); cctxt->resp->data = NULL; } if (cctxt->parent_name) { g_free (cctxt->parent_name); cctxt->parent_name = NULL; } cctxt->resp->data_len = 0; if (cctxt->req) ldtp_request_free (cctxt->req, 0); if (cctxt->window_name) { g_free (cctxt->window_name); cctxt->window_name = NULL; } } error: g_print ("handle_client: error:\n"); cctxt->resp->resp_status = status; if (cctxt->parent_name) { g_free (cctxt->parent_name); cctxt->parent_name = NULL; } if (cctxt->window_name) { g_free (cctxt->window_name); cctxt->window_name = NULL; } if (cctxt->app_under_test) { g_free (cctxt->app_under_test); cctxt->app_under_test = NULL; } if (status != LDTP_ERROR_CLIENT_DISCONNECTED) { generate_response_packet (cctxt, &status, &resp_pckt, &resp_size); if (status != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, ldtp_error_get_message (status), cctxt->log_fp); g_print ("Error generating response\n"); } else { send_response (cctxt->sock_fd, resp_pckt, resp_size, &status); if (status != LDTP_ERROR_SUCCESS) { log_msg (LDTP_LOG_CAUSE, "", cctxt->log_fp); g_print ("Error sending response **\n"); } if (resp_pckt) g_free (resp_pckt); } } pthread_mutex_lock (&cb_mutex); unregister_window_creation_event (cctxt, &status); pthread_mutex_unlock (&cb_mutex); if (cctxt && cctxt->req) ldtp_request_free (cctxt->req, 0); close_connection (sock_fd); if (packet) g_free (packet); if (pckt) g_free (pckt); ldtp_gui_free_gui_handle (cctxt->gui_handle); cctxt->gui_handle = NULL; if (cctxt->app_handle) { /* FIXME: If the server closes connection, before the client closes connection, then we get 1 SPI handle leak. Should be handled. */ Accessible_unref (cctxt->app_handle); cctxt->app_handle = NULL; } pthread_mutex_lock (&cb_mutex); if (client_context) { guint count = g_hash_table_foreach_remove (client_context, is_cctxt_registered_callback, cctxt); g_print ("Removed %d entries from client context hash table\n", count); } pthread_mutex_unlock (&cb_mutex); if (cctxt && cctxt->resp) status = cctxt->resp->resp_status; else status = LDTP_ERROR_PACKET_INVALID; g_free (cctxt->req); cctxt->req = NULL; g_free (cctxt->resp); cctxt->resp = NULL; g_free (cctxt->locale_lang); g_free (cctxt); cctxt = NULL; if (status == LDTP_ERROR_STOP_SCRIPT_ENGINE) { cleanup (0); } pthread_exit ((void *) 1); }