From 2de57dd662637f82791157a34d58b9bac0579f07 Mon Sep 17 00:00:00 2001
From: winckel <winckel@eurecom.fr>
Date: Mon, 13 Jan 2014 14:39:10 +0000
Subject: [PATCH] Added function to save filtered messages. Added an
 exclusifity flag for file choosers execution.

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4853 818b1a75-f10b-46b9-bf7c-635c3b92a50f
---
 .../utils/itti_analyzer/libparser/xml_parse.c |  17 +-
 .../utils/itti_analyzer/libparser/xml_parse.h |   7 +-
 .../itti_analyzer/libresolver/locate_root.h   |   2 +
 .../utils/itti_analyzer/libui/ui_callbacks.c  |   6 +-
 .../itti_analyzer/libui/ui_notifications.c    | 348 +++++++++++++-----
 .../itti_analyzer/libui/ui_notifications.h    |   4 +
 .../utils/itti_analyzer/libui/ui_tree_view.c  |  47 ++-
 .../utils/itti_analyzer/libui/ui_tree_view.h  |   3 +
 8 files changed, 324 insertions(+), 110 deletions(-)

diff --git a/common/utils/itti_analyzer/libparser/xml_parse.c b/common/utils/itti_analyzer/libparser/xml_parse.c
index 5862fce68f..37008640c9 100644
--- a/common/utils/itti_analyzer/libparser/xml_parse.c
+++ b/common/utils/itti_analyzer/libparser/xml_parse.c
@@ -29,8 +29,11 @@ extern int debug_parser;
 # define INDENT_START 0
 #endif
 
-types_t *xml_head;
-types_t *root;
+void       *xml_raw_data;
+uint32_t    xml_raw_data_size;
+
+types_t    *xml_head;
+types_t    *root;
 
 static int xml_parse_doc(xmlDocPtr doc);
 
@@ -667,13 +670,21 @@ static int free_elements(types_t *parent, int indent) {
     return RC_OK;
 }
 
-int xml_parse_buffer(const char *xml_buffer, const int size) {
+int xml_parse_buffer(char *xml_buffer, const int size) {
     xmlDocPtr doc; /* the resulting document tree */
 
     if (xml_buffer == NULL) {
         return RC_NULL_POINTER;
     }
 
+    if (xml_raw_data != NULL)
+    {
+        /* Free previous raw data */
+        free (xml_raw_data);
+    }
+    xml_raw_data = xml_buffer;
+    xml_raw_data_size = size;
+
     if (xml_head != NULL)
     {
         /* Free previous definitions */
diff --git a/common/utils/itti_analyzer/libparser/xml_parse.h b/common/utils/itti_analyzer/libparser/xml_parse.h
index 5c726b91e7..d699ed5eeb 100644
--- a/common/utils/itti_analyzer/libparser/xml_parse.h
+++ b/common/utils/itti_analyzer/libparser/xml_parse.h
@@ -4,11 +4,14 @@
 #ifndef XML_PARSE_H_
 #define XML_PARSE_H_
 
-extern types_t *root;
+extern void        *xml_raw_data;
+extern uint32_t     xml_raw_data_size;
+
+extern types_t     *root;
 
 int xml_parse_file(const char *filename);
 
-int xml_parse_buffer(const char *xml_buffer, const int size);
+int xml_parse_buffer(char *xml_buffer, const int size);
 
 int dissect_signal(buffer_t *buffer, ui_set_signal_text_cb_t ui_set_signal_text_cb,
                    gpointer user_data);
diff --git a/common/utils/itti_analyzer/libresolver/locate_root.h b/common/utils/itti_analyzer/libresolver/locate_root.h
index 9d8c4ed8b1..9582b10192 100644
--- a/common/utils/itti_analyzer/libresolver/locate_root.h
+++ b/common/utils/itti_analyzer/libresolver/locate_root.h
@@ -1,6 +1,8 @@
 #ifndef LOCATE_ROOT_H_
 #define LOCATE_ROOT_H_
 
+#include "types.h"
+
 extern types_t *messages_id_enum;
 extern types_t *lte_time_type;
 extern types_t *lte_time_frame_type;
diff --git a/common/utils/itti_analyzer/libui/ui_callbacks.c b/common/utils/itti_analyzer/libui/ui_callbacks.c
index e358871890..5f1ece93d0 100644
--- a/common/utils/itti_analyzer/libui/ui_callbacks.c
+++ b/common/utils/itti_analyzer/libui/ui_callbacks.c
@@ -53,7 +53,9 @@ gboolean ui_callback_on_open_messages(GtkWidget *widget, gpointer data)
 gboolean ui_callback_on_save_messages(GtkWidget *widget, gpointer data)
 {
     g_message("Save messages event occurred");
-    // CHECK_FCT(ui_file_chooser());
+
+    CHECK_FCT(ui_messages_save_file_chooser());
+
     return TRUE;
 }
 
@@ -497,8 +499,6 @@ static gboolean ui_handle_socket_xml_definition(gint fd, void *data, size_t data
 
     xml_parse_buffer (xml_definition_message->xml_definition, xml_definition_message->xml_definition_length);
 
-    free (data);
-
     return TRUE;
 }
 
diff --git a/common/utils/itti_analyzer/libui/ui_notifications.c b/common/utils/itti_analyzer/libui/ui_notifications.c
index f775afbd85..15e98d6428 100644
--- a/common/utils/itti_analyzer/libui/ui_notifications.c
+++ b/common/utils/itti_analyzer/libui/ui_notifications.c
@@ -22,8 +22,13 @@
 #include "ui_filters.h"
 #include "ui_tree_view.h"
 
+#include "locate_root.h"
 #include "xml_parse.h"
 
+static gboolean chooser_running;
+static FILE *messages_file;
+static uint32_t message_number;
+
 int ui_disable_connect_button(void)
 {
     /* Disable Connect button and enable disconnect button */
@@ -74,14 +79,14 @@ static void ui_change_cursor(gboolean busy)
 
 static void gtk_filter_add(GtkWidget *file_chooser, const gchar *title, const gchar *pattern)
 {
-    GtkFileFilter *file_filter = gtk_file_filter_new();
+    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);
+    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 *filename)
+int ui_messages_read(char *file_name)
 {
     int result = RC_OK;
     int source;
@@ -92,10 +97,10 @@ int ui_messages_read(char *filename)
 
     ui_change_cursor (TRUE);
 
-    source = open (filename, O_RDONLY);
+    source = open (file_name, O_RDONLY);
     if (source < 0)
     {
-        ui_notification_dialog (GTK_MESSAGE_ERROR, "open messages", "Failed to open file \"%s\": %s", filename,
+        ui_notification_dialog (GTK_MESSAGE_ERROR, "open messages", "Failed to open file \"%s\": %s", file_name,
                                 g_strerror (errno));
         result = RC_FAIL;
     }
@@ -106,10 +111,10 @@ int ui_messages_read(char *filename)
         int size;
         double read_fraction = 0.f;
 
-        if (stat (filename, &st) < 0)
+        if (stat (file_name, &st) < 0)
         {
             ui_notification_dialog (GTK_MESSAGE_ERROR, "get file length",
-                                    "Failed to retrieve length for file \"%s\": %s", filename, g_strerror (errno));
+                                    "Failed to retrieve length for file \"%s\": %s", file_name, g_strerror (errno));
             result = RC_FAIL;
         }
         size = st.st_size;
@@ -127,19 +132,20 @@ int ui_messages_read(char *filename)
             if (read_data == -1)
             {
                 ui_notification_dialog (GTK_MESSAGE_ERROR, "open messages", "Failed to read from file \"%s\": %s",
-                                        filename, g_strerror (errno));
+                                        file_name, g_strerror (errno));
                 result = RC_FAIL;
                 break;
             }
 
             if (read_data == 0)
             {
-              break;
+                break;
             }
 
             if (read_data < sizeof(itti_socket_header_t))
             {
-                g_warning("Failed to read a complete message header from file \"%s\": %s", filename, g_strerror (errno));
+                g_warning(
+                        "Failed to read a complete message header from file \"%s\": %s", file_name, g_strerror (errno));
             }
             else
             {
@@ -157,7 +163,8 @@ int ui_messages_read(char *filename)
                     read_data = read (source, input_data, input_data_length);
                     if (read_data < input_data_length)
                     {
-                        g_warning("Failed to read a complete message from file \"%s\": %s", filename, g_strerror (errno));
+                        g_warning(
+                                "Failed to read a complete message from file \"%s\": %s", file_name, g_strerror (errno));
                         break;
                     }
 
@@ -190,6 +197,7 @@ int ui_messages_read(char *filename)
                         }
 
                         read_messages++;
+                        free (input_data);
                         break;
                     }
 
@@ -199,23 +207,24 @@ int ui_messages_read(char *filename)
                         if (result != RC_OK)
                         {
                             ui_notification_dialog (GTK_MESSAGE_ERROR, "open messages",
-                                                    "Error in parsing XML definitions in file \"%s\": %s", filename,
+                                                    "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\"", filename);
+                        g_message("Parsed XML definition from file \"%s\"", file_name);
+                        /* Data input buffer is kept in case user when to save the log file later */
                         break;
 
                     case ITTI_STATISTIC_MESSAGE_TYPE:
                     default:
                         ui_notification_dialog (GTK_MESSAGE_WARNING, "open messages",
                                                 "Unknown (or not implemented) record type: %d in file \"%s\"",
-                                                message_header.message_type, filename);
+                                                message_header.message_type, file_name);
+
+                        free (input_data);
                         break;
                 }
-
-                free (input_data);
             }
         } while (read_data > 0);
 
@@ -232,13 +241,13 @@ int ui_messages_read(char *filename)
                 ui_tree_view_select_row (ui_tree_view_get_filtered_number () - 1);
             }
 
-            basename = g_path_get_basename (filename);
+            basename = g_path_get_basename (file_name);
             ui_set_title ("\"%s\"", basename);
         }
 
         ui_progress_bar_terminate ();
 
-        g_message("Read %d messages (%d to display) from file \"%s\"\n", read_messages, ui_tree_view_get_filtered_number(), filename);
+        g_message("Read %d messages (%d to display) from file \"%s\"\n", read_messages, ui_tree_view_get_filtered_number(), file_name);
 
         close (source);
     }
@@ -248,43 +257,166 @@ int ui_messages_read(char *filename)
     return result;
 }
 
-int ui_messages_open_file_chooser(void)
+static void ui_message_write_callback(const gpointer buffer, const gchar *signal_name)
 {
-    int result = RC_OK;
-    GtkWidget *filechooser;
-    gboolean accept;
-    char *filename;
+    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;
 
-    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", "*");
+    message_header.message_size = sizeof(itti_socket_header_t) + sizeof(itti_signal_header) + message_size;
+    message_header.message_type = ITTI_DUMP_MESSAGE_TYPE;
+
+    itti_signal_header.message_number = message_number;
+    message_number++;
+    memset (itti_signal_header.signal_name, 0, sizeof(itti_signal_header.signal_name));
+    strncpy (itti_signal_header.signal_name, signal_name, sizeof(itti_signal_header.signal_name));
+
+    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);
+}
+
+static int ui_messages_file_write(char *file_name)
+{
+    if (file_name == NULL)
+    {
+        g_warning("No name for log file");
+        return RC_FAIL;
+    }
 
-    /* Process the response */
-    accept = gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT;
+    messages_file = fopen (file_name, "w");
+    if (messages_file == NULL)
+    {
+        g_warning("Failed to open file \"%s\": %s", file_name, g_strerror (errno));
+        return RC_FAIL;
+    }
 
-    if (accept)
+    /* Write XML definitions */
     {
-        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
+        itti_socket_header_t message_header;
+
+        message_header.message_size = xml_raw_data_size + sizeof(itti_socket_header_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);
     }
-    gtk_widget_destroy (filechooser);
-    if (accept)
+
+    /* Write messages */
     {
-        result = ui_messages_read (filename);
-        if (result == RC_OK)
+        message_number = 1;
+        ui_tree_view_foreach_message (ui_message_write_callback, TRUE);
+    }
+
+    fclose (messages_file);
+
+    return RC_OK;
+}
+
+int ui_messages_open_file_chooser(void)
+{
+    int result = RC_OK;
+
+    if (chooser_running == FALSE)
+    {
+        GtkWidget *filechooser;
+        gboolean accept;
+        char *filename;
+
+        chooser_running = TRUE;
+        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 */
+        accept = gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT;
+
+        if (accept)
         {
-            /* Update messages file name for future use */
-            if (ui_main_data.messages_file_name != NULL)
+            filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
+        }
+        gtk_widget_destroy (filechooser);
+        if (accept)
+        {
+            result = ui_messages_read (filename);
+            if (result == RC_OK)
             {
-                g_free (ui_main_data.messages_file_name);
+                /* 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;
+            }
+            else
+            {
+                g_free (filename);
             }
-            ui_main_data.messages_file_name = filename;
         }
-        else
+        chooser_running = FALSE;
+    }
+    return result;
+}
+
+int ui_messages_save_file_chooser(void)
+{
+    int result = RC_OK;
+
+    if (chooser_running == FALSE)
+    {
+        GtkWidget *filechooser;
+
+        chooser_running = TRUE;
+
+        /* Check if there is something to save */
+        if (xml_raw_data_size > 0)
         {
-            g_free (filename);
+            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, "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);
+                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);
         }
+        chooser_running = FALSE;
     }
 
     return result;
@@ -293,40 +425,47 @@ int ui_messages_open_file_chooser(void)
 int ui_filters_open_file_chooser(void)
 {
     int result = RC_OK;
-    GtkWidget *filechooser;
-    gboolean 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", "*");
+    if (chooser_running == FALSE)
+    {
+        GtkWidget *filechooser;
+        gboolean accept;
+        char *filename;
 
-    /* Process the response */
-    accept = gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT;
+        chooser_running = TRUE;
 
-    if (accept)
-    {
-        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
-    }
-    gtk_widget_destroy (filechooser);
-    if (accept)
-    {
-        result = ui_filters_read (filename);
-        if (result == RC_OK)
+        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 */
+        accept = gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT;
+
+        if (accept)
         {
-            /* 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;
+            filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
         }
-        else
+        gtk_widget_destroy (filechooser);
+        if (accept)
         {
-            g_free (filename);
+            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);
+            }
         }
+        chooser_running = FALSE;
     }
 
     return result;
@@ -334,48 +473,55 @@ int ui_filters_open_file_chooser(void)
 
 int ui_filters_save_file_chooser(void)
 {
-    GtkWidget *filechooser;
     int result = RC_OK;
 
-    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", "*");
+    if (chooser_running == FALSE)
+    {
+        GtkWidget *filechooser;
 
-    gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (filechooser), TRUE);
+        chooser_running = 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");
-    }
+        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", "*");
 
-    /* Process the response */
-    if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT)
-    {
-        char *filename;
+        gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (filechooser), TRUE);
 
-        filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
-        result = ui_filters_file_write (filename);
-        if (result == RC_OK)
+        if (ui_main_data.filters_file_name != NULL)
         {
-            /* 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;
+            gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filechooser), ui_main_data.filters_file_name);
         }
         else
         {
-            g_free (filename);
+            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);
+        chooser_running = FALSE;
     }
-    gtk_widget_destroy (filechooser);
 
     return result;
 }
diff --git a/common/utils/itti_analyzer/libui/ui_notifications.h b/common/utils/itti_analyzer/libui/ui_notifications.h
index c90da8ac3c..d8fc807bd1 100644
--- a/common/utils/itti_analyzer/libui/ui_notifications.h
+++ b/common/utils/itti_analyzer/libui/ui_notifications.h
@@ -1,6 +1,8 @@
 #ifndef UI_NOTIFICATIONS_H_
 #define UI_NOTIFICATIONS_H_
 
+typedef void (*message_write_callback_t)  (const gpointer buffer, const gchar *signal_name);
+
 int ui_disable_connect_button(void);
 
 int ui_enable_connect_button(void);
@@ -9,6 +11,8 @@ int ui_messages_read(char *filename);
 
 int ui_messages_open_file_chooser(void);
 
+int ui_messages_save_file_chooser(void);
+
 int ui_filters_open_file_chooser(void);
 
 int ui_filters_save_file_chooser(void);
diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.c b/common/utils/itti_analyzer/libui/ui_tree_view.c
index 920832b8c6..5c7419e326 100644
--- a/common/utils/itti_analyzer/libui/ui_tree_view.c
+++ b/common/utils/itti_analyzer/libui/ui_tree_view.c
@@ -450,7 +450,7 @@ int ui_tree_view_new_signal_ind(const uint32_t message_number, const gchar *lte_
 
     ui_tree_view_add_to_list (ui_main_data.messages_list, lte_time, message_number, message_id, message_name,
                               origin_task_id, origin_task_name, destination_task_id, destination_task_name, instance_id, instance_name,
-                              (buffer_t *) buffer);
+                              buffer);
 
     return RC_OK;
 }
@@ -526,6 +526,51 @@ void ui_tree_view_refilter()
     g_info("ui_tree_view_refilter: last message %d, %d messages displayed", ui_store.filtered_last_msg, ui_store.filtered_msg_number);
 }
 
+typedef struct foreach_message_params_s
+{
+    message_write_callback_t   callback;
+    gboolean                    filter;
+} foreach_message_params_t;
+
+static gboolean foreach_message(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
+{
+    foreach_message_params_t *params = (foreach_message_params_t *) data;
+    const gchar *signal_name;
+    uint32_t message_id;
+    uint32_t origin_task_id;
+    uint32_t destination_task_id;
+    uint32_t instance;
+    gpointer buffer = NULL;
+
+    gtk_tree_model_get (model, iter, COL_MESSAGE, &signal_name, COL_MESSAGE_ID, &message_id, COL_FROM_TASK_ID, &origin_task_id, COL_TO_TASK_ID,
+                        &destination_task_id, COL_INSTANCE_ID, &instance, COL_BUFFER, &buffer, -1);
+
+    if (params->filter == TRUE)
+    {
+        gboolean enabled = FALSE;
+
+        enabled = ui_filters_message_enabled (message_id, origin_task_id, destination_task_id, instance);
+        if (enabled == FALSE)
+        {
+            buffer = NULL;
+        }
+    }
+
+    if (buffer != NULL)
+    {
+        params->callback(buffer, signal_name);
+    }
+
+    return FALSE;
+}
+
+void ui_tree_view_foreach_message(message_write_callback_t callback, gboolean filter)
+{
+    foreach_message_params_t params = {callback, filter};
+
+    gtk_tree_model_foreach (GTK_TREE_MODEL(ui_store.store), foreach_message, (void *) &params);
+}
+
 guint ui_tree_view_get_filtered_number(void)
 {
     return ui_store.filtered_msg_number;
diff --git a/common/utils/itti_analyzer/libui/ui_tree_view.h b/common/utils/itti_analyzer/libui/ui_tree_view.h
index f0e39d4fb8..3787368f10 100644
--- a/common/utils/itti_analyzer/libui/ui_tree_view.h
+++ b/common/utils/itti_analyzer/libui/ui_tree_view.h
@@ -2,6 +2,7 @@
 #define UI_TREE_VIEW_H_
 
 #include "ui_filters.h"
+#include "ui_notifications.h"
 
 typedef enum col_type_e
 {
@@ -64,6 +65,8 @@ void ui_tree_view_select_row(gint row);
 
 void ui_tree_view_refilter(void);
 
+void ui_tree_view_foreach_message(message_write_callback_t callback, gboolean filter);
+
 guint ui_tree_view_get_filtered_number(void);
 
 #endif /* UI_TREE_VIEW_H_ */
-- 
GitLab