/* * Copyright (c) 2015, EURECOM (www.eurecom.fr) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. 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. * * 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. * * The views and conclusions contained in the software and documentation are those * of the authors and should not be interpreted as representing official policies, * either expressed or implied, of the FreeBSD Project. */ #include #include #include #include #define G_LOG_DOMAIN ("UI") #include #include #include "logs.h" #include "itti_types.h" #include "rc.h" #include "ui_interface.h" #include "ui_main_screen.h" #include "ui_menu_bar.h" #include "ui_notifications.h" #include "ui_notif_dlg.h" #include "ui_callbacks.h" #include "ui_filters.h" #include "ui_tree_view.h" #include "locate_root.h" #include "xml_parse.h" #include "socket.h" static const itti_message_types_t itti_dump_xml_definition_end = ITTI_DUMP_XML_DEFINITION_END; static const itti_message_types_t itti_dump_message_type_end = ITTI_DUMP_MESSAGE_TYPE_END; static FILE *messages_file; static uint32_t message_number; static gboolean ui_abort; int ui_disable_connect_button(void) { /* Disable Connect button and enable disconnect button */ gtk_widget_set_sensitive (GTK_WIDGET (ui_main_data.connect), FALSE); gtk_widget_set_sensitive (GTK_WIDGET (ui_main_data.disconnect), TRUE); socket_abort_connection = FALSE; return RC_OK; } int ui_enable_connect_button(void) { /* Disable Disconnect button and enable connect button */ gtk_widget_set_sensitive (GTK_WIDGET (ui_main_data.connect), TRUE); gtk_widget_set_sensitive (GTK_WIDGET (ui_main_data.disconnect), FALSE); socket_abort_connection = TRUE; ui_set_sensitive_save_message_buttons (TRUE); ui_set_title (""); return RC_OK; } static void ui_change_cursor(gboolean busy) { static GdkWindow *window; if (busy) { GdkDisplay *display; GdkCursor *cursor; // gint x, y; cursor = gdk_cursor_new (GDK_WATCH); display = gdk_display_get_default (); window = gtk_widget_get_window (GTK_WIDGET(ui_main_data.window)); // window = gdk_display_get_window_at_pointer(display, &x, &y); gdk_window_set_cursor (window, cursor); gdk_display_sync (display); g_object_unref (cursor); // gtk_widget_set_sensitive (ui_main_data.window, FALSE); ui_gtk_flush_events (); } else { gdk_window_set_cursor (window, NULL); // gtk_widget_set_sensitive (ui_main_data.window, TRUE); ui_gtk_flush_events (); } } static void gtk_filter_add(GtkWidget *file_chooser, const gchar *title, const gchar *pattern) { GtkFileFilter *file_filter = gtk_file_filter_new (); gtk_file_filter_set_name (file_filter, title); gtk_file_filter_add_pattern (file_filter, pattern); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(file_chooser), file_filter); } int ui_messages_read(char *file_name) { int result = RC_OK; int source; int read_data = 0; void *input_data = NULL; size_t input_data_length = 0; int read_messages = 0; ui_change_cursor (TRUE); source = open (file_name, O_RDONLY); if (source < 0) { ui_notification_dialog (GTK_MESSAGE_ERROR, FALSE, "open messages", "Failed to open file \"%s\": %s", file_name, g_strerror (errno)); result = RC_FAIL; } else { itti_socket_header_t message_header; struct stat st; int size; double read_fraction = 0.f; if (stat (file_name, &st) < 0) { ui_notification_dialog (GTK_MESSAGE_ERROR, FALSE, "get file length", "Failed to retrieve length for file \"%s\": %s", file_name, g_strerror (errno)); result = RC_FAIL; } size = st.st_size; ui_callback_signal_clear_list (NULL, NULL); /* Initialize the progress bar */ ui_abort = FALSE; ui_progress_bar_set_fraction (0); do { read_data = read (source, &message_header, sizeof(itti_socket_header_t)); if (read_data == -1) { ui_notification_dialog (GTK_MESSAGE_ERROR, FALSE, "open messages", "Failed to read from file \"%s\": %s", file_name, g_strerror (errno)); result = RC_FAIL; break; } if (read_data == 0) { break; } if (read_data < sizeof(itti_socket_header_t)) { if (ui_notification_dialog (GTK_MESSAGE_WARNING, TRUE, "open messages", "Failed to read a complete message header from file \"%s\": %s", file_name, g_strerror (errno)) == RC_FAIL) { read_data = 0; } } else { read_fraction += (double) read_data / size; input_data_length = message_header.message_size - sizeof(itti_socket_header_t); g_debug("%x, %x, %zd", message_header.message_type, message_header.message_size, input_data_length); /* Checking for non-header part */ if (input_data_length > 0) { input_data = malloc (input_data_length); read_data = read (source, input_data, input_data_length); if (read_data < input_data_length) { if (ui_notification_dialog (GTK_MESSAGE_WARNING, TRUE, "open messages", "Failed to read a complete message from file \"%s\": %s", file_name, g_strerror (errno)) == RC_FAIL) { read_data = 0; } break; } read_fraction += (double) input_data_length / size; } switch (message_header.message_type) { case ITTI_DUMP_XML_DEFINITION: ui_gtk_flush_events (); if (memcmp (&(((char *) input_data)[input_data_length - sizeof (itti_message_types_t)]), &itti_dump_xml_definition_end, sizeof (itti_message_types_t)) == 0) { result = xml_parse_buffer (input_data, input_data_length - sizeof (itti_message_types_t)); if (result != RC_OK) { ui_notification_dialog (GTK_MESSAGE_ERROR, FALSE, "open messages", "Error in parsing XML definitions in file \"%s\": %s", file_name, rc_strings[-result]); read_data = 0; } ui_gtk_flush_events (); g_message("Parsed XML definition from file \"%s\"", file_name); } else { ui_notification_dialog (GTK_MESSAGE_ERROR, FALSE, "open messages", "Error in parsing XML definitions in file \"%s\", end mark is missing", file_name); } /* Data input buffer is kept in case user when to save the log file later */ break; case ITTI_DUMP_MESSAGE_TYPE: { itti_signal_header_t *itti_signal_header = input_data; buffer_t *buffer; if (memcmp (&(((char *) input_data)[input_data_length - sizeof (itti_message_types_t)]), &itti_dump_message_type_end, sizeof (itti_message_types_t)) == 0) { /* Create the new buffer */ if (buffer_new_from_data (&buffer, input_data + sizeof(itti_signal_header_t), input_data_length - sizeof(itti_signal_header_t) - sizeof(itti_message_types_t), 0) != RC_OK) { g_error("Failed to create new buffer"); g_assert_not_reached (); } sscanf (itti_signal_header->message_number_char, MESSAGE_NUMBER_CHAR_FORMAT, &buffer->message_number); ui_signal_add_to_list (buffer, ((read_messages % 1000) == 0) ? (gpointer) 1 : NULL); if ((read_messages % 100) == 0) { ui_progress_bar_set_fraction (read_fraction); ui_gtk_flush_events (); } read_messages++; } else { if (ui_notification_dialog (GTK_MESSAGE_WARNING, TRUE, "open messages", "Failed to read a message from file \"%s\", end mark is missing", file_name) == RC_FAIL) { read_data = 0; } break; } free (input_data); break; } case ITTI_STATISTIC_MESSAGE_TYPE: default: if (ui_notification_dialog (GTK_MESSAGE_WARNING, TRUE, "open messages", "Unknown (or not implemented) record type: %d in file \"%s\"", message_header.message_type, file_name) == RC_FAIL) { read_data = 0; } free (input_data); break; } } } while ((ui_abort == FALSE) && (read_data > 0)); if (read_messages > 0) { char *basename; /* Enable buttons to move in the list of signals */ ui_set_sensitive_move_buttons (TRUE); if (ui_main_data.follow_last) { /* Advance to the last signal */ ui_tree_view_select_row (ui_tree_view_get_filtered_number () - 1); } basename = g_path_get_basename (file_name); ui_set_title ("\"%s\"", basename); } else { result = RC_FAIL; } ui_progress_bar_terminate (); g_message("Read %d messages (%d to display) from file \"%s\"\n", read_messages, ui_tree_view_get_filtered_number(), file_name); close (source); } ui_change_cursor (FALSE); return result; } static void ui_message_write_callback(const gpointer buffer, const gchar *signal_name) { buffer_t *signal_buffer = (buffer_t *) buffer; itti_socket_header_t message_header; itti_signal_header_t itti_signal_header; uint32_t message_size; message_size = signal_buffer->size_bytes; message_header.message_size = sizeof(itti_socket_header_t) + sizeof(itti_signal_header) + message_size + sizeof(itti_message_types_t); message_header.message_type = ITTI_DUMP_MESSAGE_TYPE; sprintf(itti_signal_header.message_number_char, MESSAGE_NUMBER_CHAR_FORMAT, message_number); itti_signal_header.message_number_char[sizeof(itti_signal_header.message_number_char) - 1] = '\n'; message_number++; fwrite (&message_header, sizeof(message_header), 1, messages_file); fwrite (&itti_signal_header, sizeof(itti_signal_header), 1, messages_file); fwrite (signal_buffer->data, message_size, 1, messages_file); fwrite (&itti_dump_message_type_end, sizeof(itti_message_types_t), 1, messages_file); } static int ui_messages_file_write(char *file_name, gboolean filtered) { if (file_name == NULL) { g_warning("No name for log file"); return RC_FAIL; } messages_file = fopen (file_name, "w"); if (messages_file == NULL) { ui_notification_dialog (GTK_MESSAGE_ERROR, FALSE, "Failed to open file \"%s\": %s", file_name, g_strerror (errno)); return RC_FAIL; } /* Write XML definitions */ { itti_socket_header_t message_header; message_header.message_size = sizeof(itti_socket_header_t) + xml_raw_data_size + sizeof(itti_message_types_t); message_header.message_type = ITTI_DUMP_XML_DEFINITION; fwrite (&message_header, sizeof(message_header), 1, messages_file); fwrite (xml_raw_data, xml_raw_data_size, 1, messages_file); fwrite (&itti_dump_xml_definition_end, sizeof(itti_message_types_t), 1, messages_file); } /* Write messages */ { message_number = 1; ui_tree_view_foreach_message (ui_message_write_callback, filtered); } fclose (messages_file); return RC_OK; } int ui_messages_open_file_chooser(void) { int result = RC_OK; GtkWidget *filechooser; gboolean response_accept; char *filename; filechooser = gtk_file_chooser_dialog_new ("Select file", GTK_WINDOW (ui_main_data.window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_filter_add (filechooser, "Log files", "*.log"); gtk_filter_add (filechooser, "All files", "*"); /* Process the response */ response_accept = gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT; if (response_accept) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); } gtk_widget_destroy (filechooser); if (response_accept) { ui_set_sensitive_save_message_buttons (FALSE); result = ui_messages_read (filename); if (result == RC_OK) { /* Update messages file name for future use */ if (ui_main_data.messages_file_name != NULL) { g_free (ui_main_data.messages_file_name); } ui_main_data.messages_file_name = filename; ui_set_sensitive_save_message_buttons (TRUE); } else { g_free (filename); } } return result; } int ui_messages_save_file_chooser(gboolean filtered) { int result = RC_OK; GtkWidget *filechooser; /* Check if there is something to save */ if (xml_raw_data_size > 0) { static const char *title[] = { "Save file (all messages)", "Save file (filtered messages)", }; filechooser = gtk_file_chooser_dialog_new (title[filtered], GTK_WINDOW (ui_main_data.window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_filter_add (filechooser, "Log files", "*.log"); gtk_filter_add (filechooser, "All files", "*"); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (filechooser), TRUE); if (ui_main_data.messages_file_name != NULL) { gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser), ui_main_data.messages_file_name); } else { gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filechooser), "messages.log"); } /* Process the response */ if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); result = ui_messages_file_write (filename, filtered); if (result == RC_OK) { /* Update filters file name for future use */ if (ui_main_data.messages_file_name != NULL) { g_free (ui_main_data.messages_file_name); } ui_main_data.messages_file_name = filename; } else { g_free (filename); } } gtk_widget_destroy (filechooser); } return result; } int ui_filters_open_file_chooser(void) { int result = RC_OK; GtkWidget *filechooser; gboolean response_accept; char *filename; filechooser = gtk_file_chooser_dialog_new ("Select file", GTK_WINDOW (ui_main_data.window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_filter_add (filechooser, "Filters files", "*.xml"); gtk_filter_add (filechooser, "All files", "*"); /* Process the response */ response_accept = gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT; if (response_accept) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); } gtk_widget_destroy (filechooser); if (response_accept) { result = ui_filters_read (filename); if (result == RC_OK) { /* Update filters file name for future use */ if (ui_main_data.filters_file_name != NULL) { g_free (ui_main_data.filters_file_name); } ui_main_data.filters_file_name = filename; } else { g_free (filename); } } return result; } int ui_filters_save_file_chooser(void) { int result = RC_OK; GtkWidget *filechooser; filechooser = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (ui_main_data.window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); gtk_filter_add (filechooser, "Filters files", "*.xml"); gtk_filter_add (filechooser, "All files", "*"); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (filechooser), TRUE); if (ui_main_data.filters_file_name != NULL) { gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser), ui_main_data.filters_file_name); } else { gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filechooser), "filters.xml"); } /* Process the response */ if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); result = ui_filters_file_write (filename); if (result == RC_OK) { /* Update filters file name for future use */ if (ui_main_data.filters_file_name != NULL) { g_free (ui_main_data.filters_file_name); } ui_main_data.filters_file_name = filename; } else { g_free (filename); } } gtk_widget_destroy (filechooser); return result; } void ui_progressbar_window_destroy (void) { ui_abort = TRUE; ui_progress_bar_terminate(); } int ui_progress_bar_set_fraction(double fraction) { if (ui_abort == FALSE) { /* If not exist instantiate */ if (!ui_main_data.progressbar && !ui_main_data.progressbar_window) { ui_main_data.progressbar_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); /* Keep progress bar window on top of main window */ gtk_window_set_transient_for (GTK_WINDOW(ui_main_data.progressbar_window), GTK_WINDOW(ui_main_data.window)); /* Set the window at center of main window */ gtk_window_set_position (GTK_WINDOW(ui_main_data.progressbar_window), GTK_WIN_POS_CENTER_ON_PARENT); gtk_window_set_title (GTK_WINDOW(ui_main_data.progressbar_window), "Processing"); gtk_container_set_border_width (GTK_CONTAINER (ui_main_data.progressbar_window), 10); ui_main_data.progressbar = gtk_progress_bar_new (); gtk_container_add (GTK_CONTAINER (ui_main_data.progressbar_window), ui_main_data.progressbar); /* Assign the destroy event */ g_signal_connect(ui_main_data.progressbar_window, "destroy", ui_progressbar_window_destroy, NULL); gtk_widget_show_all (ui_main_data.progressbar_window); gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.stop_loading), TRUE); } gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(ui_main_data.progressbar), fraction); // ui_gtk_flush_events(); } return RC_OK; } int ui_progress_bar_terminate(void) { if (ui_main_data.progressbar) { gtk_widget_destroy (ui_main_data.progressbar); ui_main_data.progressbar = NULL; } if (ui_main_data.progressbar_window) { gtk_widget_destroy (ui_main_data.progressbar_window); ui_main_data.progressbar_window = NULL; } gtk_widget_set_sensitive(GTK_WIDGET(ui_main_data.stop_loading), FALSE); return RC_OK; }