#include <emem.h> not req'd
[obnox/wireshark/wip.git] / gtk / expert_comp_table.c
1 /* expert_comp_table.c
2  * expert_comp_table   2005 Greg Morris
3  * Portions copied from service_response_time_table.c by Ronnie Sahlberg
4  * Helper routines common to all composite expert statistics
5  * tap.
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <string.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <math.h>
36
37 #include <gtk/gtk.h>
38
39 #include "epan/packet_info.h"
40 #include <epan/expert.h>
41
42 #include "../simple_dialog.h"
43 #include "../globals.h"
44 #include "../color.h"
45
46 #include "gtk/expert_comp_table.h"
47 #include "gtk/filter_utils.h"
48 #include "gtk/find_dlg.h"
49 #include "gtk/color_dlg.h"
50 #include "gtk/main.h"
51 #include "gtk/gui_utils.h"
52 #include "gtk/gtkglobals.h"
53 #include "gtk/webbrowser.h"
54
55
56 #define SORT_ALPHABETICAL 0
57
58 static gint
59 sort_iter_compare_func (GtkTreeModel *model,
60 GtkTreeIter *a,
61 GtkTreeIter *b,
62 gpointer userdata)
63 {
64     gint sortcol = GPOINTER_TO_INT(userdata);
65     gint ret = 0;
66     switch (sortcol)
67     {
68         case SORT_ALPHABETICAL:
69         {
70             gchar *name1, *name2;
71             gtk_tree_model_get(model, a, 0, &name1, -1);
72             gtk_tree_model_get(model, b, 0, &name2, -1);
73             if (name1 == NULL || name2 == NULL)
74             {
75                 if (name1 == NULL && name2 == NULL)
76                     break; /* both equal => ret = 0 */
77                 ret = (name1 == NULL) ? -1 : 1;
78             }
79             else
80             {
81                 ret = g_ascii_strcasecmp(name1,name2);
82             }
83             g_free(name1);
84             g_free(name2);
85             }
86             break;
87         default:
88             g_return_val_if_reached(0);
89     }
90     return ret;
91 }
92
93 enum
94 {
95    GROUP_COLUMN,
96    PROTOCOL_COLUMN,
97    SUMMARY_COLUMN,
98    COUNT_COLUMN,
99    N_COLUMNS
100 };
101
102 static gint find_summary_data(error_equiv_table *err, const expert_info_t *expert_data)
103 {
104     gint i;
105     
106     /* First time thru values will be 0 */
107     if (err->num_procs==0) {
108         return -1;
109     }
110     for (i=0;i<err->num_procs;i++) {
111         if (strcmp(err->procedures[i].entries[1], expert_data->protocol) == 0 &&
112             strcmp(err->procedures[i].entries[2], expert_data->summary) == 0) {
113             return i;
114         }
115     }
116     return -1;
117 }
118
119 static void
120 error_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data, guint callback_action)
121 {
122     int action, type, selection;
123     error_equiv_table *err = (error_equiv_table *)callback_data;
124     char str[256];
125     const char *current_filter;
126
127     GtkTreeIter iter;
128     GtkTreeModel *model;
129     const expert_info_t expert_data;
130
131     action=FILTER_ACTION(callback_action);
132     type=FILTER_ACTYPE(callback_action);
133
134
135     gtk_tree_selection_get_selected(err->select, &model, &iter);
136
137     gtk_tree_model_get (model, &iter, GROUP_COLUMN, &expert_data.group, -1);
138     gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &expert_data.protocol, -1);
139     gtk_tree_model_get (model, &iter, SUMMARY_COLUMN, &expert_data.summary, -1);
140     
141     if (strcmp((char *)(unsigned long)expert_data.group, "Packet:")==0) {
142         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You cannot filter or search for packet number. Click on a valid item header.");
143         return;
144     }
145
146     selection = find_summary_data(err, &expert_data);
147
148     if(selection>=(int)err->num_procs){
149         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No items are selected");
150         return;
151     }
152     current_filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
153
154     /* Some expert data doesn't pass an expert item. Without this we cannot create a filter */
155     /* But allow for searching of internet for error string */
156     if (action != 6 && action != 7) {
157         if (err->procedures[selection].fvalue_value==NULL) {
158             if (action != 2 && action != 3 && action != 4) {
159                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Wireshark cannot create a filter on this item - %s, try using find instead.", err->procedures[selection].entries[2]);
160                 return;
161             }
162         }
163         switch(type){
164         case ACTYPE_SELECTED:
165             /* if no expert item was passed */
166             if (err->procedures[selection].fvalue_value==NULL) {
167                 g_snprintf(str, 255, "%s", err->procedures[selection].entries[2]);
168             }
169             else
170             {
171                 /* expert item exists. Use it. */
172                 g_snprintf(str, 255, "%s", err->procedures[selection].fvalue_value);
173             }
174             break;
175         case ACTYPE_NOT_SELECTED:
176             /* if no expert item was passed */
177             if (err->procedures[selection].fvalue_value==NULL) {
178                 g_snprintf(str, 255, "!%s", err->procedures[selection].entries[2]);
179             }
180             else
181             {
182                 /* expert item exists. Use it. */
183                 g_snprintf(str, 255, "!(%s)", err->procedures[selection].fvalue_value);
184             }
185             break;
186             /* the remaining cases will only exist if the expert item exists so no need to check */
187         case ACTYPE_AND_SELECTED:
188             if ((!current_filter) || (0 == strlen(current_filter)))
189                 g_snprintf(str, 255, "%s", err->procedures[selection].fvalue_value);
190             else
191                 g_snprintf(str, 255, "(%s) && (%s)", current_filter, err->procedures[selection].fvalue_value);
192             break;
193         case ACTYPE_OR_SELECTED:
194             if ((!current_filter) || (0 == strlen(current_filter)))
195                 g_snprintf(str, 255, "%s", err->procedures[selection].fvalue_value);
196             else
197                 g_snprintf(str, 255, "(%s) || (%s)", current_filter, err->procedures[selection].fvalue_value);
198             break;
199         case ACTYPE_AND_NOT_SELECTED:
200             if ((!current_filter) || (0 == strlen(current_filter)))
201                 g_snprintf(str, 255, "!(%s)", err->procedures[selection].fvalue_value);
202             else
203                 g_snprintf(str, 255, "(%s) && !(%s)", current_filter, err->procedures[selection].fvalue_value);
204             break;
205         case ACTYPE_OR_NOT_SELECTED:
206             if ((!current_filter) || (0 == strlen(current_filter)))
207                 g_snprintf(str, 255, "!(%s)", err->procedures[selection].fvalue_value);
208             else
209                 g_snprintf(str, 255, "(%s) || !(%s)", current_filter, err->procedures[selection].fvalue_value);
210             break;
211         default:
212             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu type - %u", type);
213         }
214     }
215
216     switch(action){
217     case ACTION_MATCH:
218         main_filter_packets(&cfile, str, FALSE);
219         break;
220     case ACTION_PREPARE:
221         gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), str);
222         break;
223     case ACTION_FIND_FRAME:
224         /* When trying to perform a find without expert item, we must pass
225          * the expert string to the find window. The user might need to modify
226          * the string and click on the text search to locate the packet in question.
227          * So regardless of the type we will just bring up the find window and allow
228          * the user to modify the search criteria and options.
229          */
230         find_frame_with_filter(str);
231         break;
232     case ACTION_FIND_NEXT:
233         /* In the case of find next, if there was no expert item, then most likely the expert
234          * string was modified to locate the text inside the message. So we can't just perform
235          * a find with the expert string or we will not really be performing a find next.
236          * In an effort to allow the user to modify the string and/or continue searching, we
237          * will just present the user with the find window again with the default expert string.
238          * A better aproach would be to attempt in capturing the last find string and utilize this 
239          * with a find next/previous. Also a better approach might be to just send a <Ctl-N> keystroke.
240          */
241         if (err->procedures[selection].fvalue_value==NULL) {
242             find_frame_with_filter(str);
243         }
244         else
245         { 
246             /* We have an expert item so just continue search without find dialog. */
247             find_previous_next_frame_with_filter(str, FALSE);
248         }
249         break;
250     case ACTION_FIND_PREVIOUS:
251         /* In the case of find previous, if there was no expert item, then most likely the expert
252          * string was modified to locate the text inside the message. So we can't just perform
253          * a find with the expert string or we will not really be performing a find previous.
254          * In an effort to allow the user to modify the string and/or continue searching, we
255          * will just present the user with the find window again with the default expert string.
256          * A better aproach would be to attempt in capturing the last find string and utilize this 
257          * with a find next/previous. Also a better approach might be to just send a <Ctl-B> keystroke.
258          */
259         if (err->procedures[selection].fvalue_value==NULL) {
260             find_frame_with_filter(str);
261         }
262         else
263         { 
264             /* We have an expert item so just continue search without find dialog. */
265             find_previous_next_frame_with_filter(str, TRUE);
266         }
267         break;
268     case ACTION_COLORIZE:
269         color_display_with_filter(str);
270         break;
271     case ACTION_WEB_LOOKUP:
272         /* Lookup expert string on internet. Default search via www.google.com */
273         g_snprintf(str, 255, "http://www.google.com/search?hl=en&q=%s+'%s'", err->procedures[selection].entries[1], err->procedures[selection].entries[2]);
274         browser_open_url(str);
275         break;
276     default:
277         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu action - %u", action);
278     }
279 }
280
281 static gint
282 error_show_popup_menu_cb(void *widg _U_, GdkEvent *event, error_equiv_table *err)
283 {
284         GdkEventButton *bevent = (GdkEventButton *)event;
285
286         if(event->type==GDK_BUTTON_PRESS && bevent->button==3){
287                 gtk_menu_popup(GTK_MENU(err->menu), NULL, NULL, NULL, NULL, 
288                         bevent->button, bevent->time);
289         }
290
291         return FALSE;
292 }
293
294 static GtkItemFactoryEntry error_list_menu_items[] =
295 {
296         /* Match */
297         {"/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL,},
298         {"/Apply as Filter/Selected", NULL,
299                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_SELECTED, 0),
300                 NULL, NULL,},
301         {"/Apply as Filter/... not Selected", NULL,
302                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_NOT_SELECTED, 0),
303                 NULL, NULL,},
304         {"/Apply as Filter/.. and Selected", NULL,
305                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_AND_SELECTED, 0),
306                 NULL, NULL,},
307         {"/Apply as Filter/... or Selected", NULL,
308                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_OR_SELECTED, 0),
309                 NULL, NULL,},
310         {"/Apply as Filter/... and not Selected", NULL,
311                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_AND_NOT_SELECTED, 0),
312                 NULL, NULL,},
313         {"/Apply as Filter/... or not Selected", NULL,
314                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_MATCH(ACTYPE_OR_NOT_SELECTED, 0),
315                 NULL, NULL,},
316
317         /* Prepare */
318         {"/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL,},
319         {"/Prepare a Filter/Selected", NULL,
320                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_SELECTED, 0),
321                 NULL, NULL,},
322         {"/Prepare a Filter/Not Selected", NULL,
323                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_NOT_SELECTED, 0),
324                 NULL, NULL,},
325         {"/Prepare a Filter/... and Selected", NULL,
326                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_AND_SELECTED, 0),
327                 NULL, NULL,},
328         {"/Prepare a Filter/... or Selected", NULL,
329                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_OR_SELECTED, 0),
330                 NULL, NULL,},
331         {"/Prepare a Filter/... and not Selected", NULL,
332                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_AND_NOT_SELECTED, 0),
333                 NULL, NULL,},
334         {"/Prepare a Filter/... or not Selected", NULL,
335                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_PREPARE(ACTYPE_OR_NOT_SELECTED, 0),
336                 NULL, NULL,},
337
338         /* Find Frame */
339         {"/Find Frame", NULL, NULL, 0, "<Branch>", NULL,},
340         {"/Find Frame/Find Frame", NULL, NULL, 0, "<Branch>", NULL,},
341         {"/Find Frame/Find Frame/Selected", NULL,
342                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_FRAME(ACTYPE_SELECTED, 0),
343                 NULL, NULL,},
344         {"/Find Frame/Find Frame/Not Selected", NULL,
345                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_FRAME(ACTYPE_NOT_SELECTED, 0),
346                 NULL, NULL,},
347         /* Find Next */
348         {"/Find Frame/Find Next", NULL, NULL, 0, "<Branch>", NULL,},
349         {"/Find Frame/Find Next/Selected", NULL,
350                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_NEXT(ACTYPE_SELECTED, 0),
351                 NULL, NULL,},
352         {"/Find Frame/Find Next/Not Selected", NULL,
353                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_NEXT(ACTYPE_NOT_SELECTED, 0),
354                 NULL, NULL,},
355
356         /* Find Previous */
357         {"/Find Frame/Find Previous", NULL, NULL, 0, "<Branch>", NULL,},
358         {"/Find Frame/Find Previous/Selected", NULL,
359                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_PREVIOUS(ACTYPE_SELECTED, 0),
360                 NULL, NULL,},
361         {"/Find Frame/Find Previous/Not Selected", NULL,
362                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_FIND_PREVIOUS(ACTYPE_NOT_SELECTED, 0),
363                 NULL, NULL,},
364
365         /* Colorize Procedure */
366         {"/Colorize Procedure", NULL, NULL, 0, "<Branch>", NULL,},
367         {"/Colorize Procedure/Selected", NULL,
368                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_COLORIZE(ACTYPE_SELECTED, 0),
369                 NULL, NULL,},
370         {"/Colorize Procedure/Not Selected", NULL,
371                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_COLORIZE(ACTYPE_NOT_SELECTED, 0),
372                 NULL, NULL,},
373
374         /* Search Internet */
375         {"/Internet Search for Info Text", NULL,
376                 GTK_MENU_FUNC(error_select_filter_cb), CALLBACK_WEB_LOOKUP, NULL, NULL,}
377 };
378
379 static void
380 expert_goto_pkt_cb (GtkTreeSelection *selection, gpointer data _U_)
381 {
382         GtkTreeIter iter;
383         GtkTreeModel *model;
384         gchar *pkt;
385         gchar *grp;
386
387         if (gtk_tree_selection_get_selected (selection, &model, &iter))
388         {
389                 gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &pkt, -1);
390                 gtk_tree_model_get (model, &iter, GROUP_COLUMN, &grp, -1);
391
392                 if (strcmp(grp, "Packet:")==0) {
393                     cf_goto_frame(&cfile, atoi(pkt));
394                 }
395                 g_free (pkt);
396                 g_free (grp);
397         }
398 }
399
400 static void
401 error_create_popup_menu(error_equiv_table *err)
402 {
403     GtkItemFactory *item_factory;
404
405
406     err->select = gtk_tree_view_get_selection (GTK_TREE_VIEW (err->tree_view));
407     gtk_tree_selection_set_mode (err->select, GTK_SELECTION_SINGLE);
408     g_signal_connect (G_OBJECT (err->select), "changed",
409                   G_CALLBACK (expert_goto_pkt_cb),
410                   err);
411     item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
412
413     gtk_item_factory_create_items_ac(item_factory, sizeof(error_list_menu_items)/sizeof(error_list_menu_items[0]), error_list_menu_items, err, 2);
414
415     err->menu = gtk_item_factory_get_widget(item_factory, "<main>");
416     g_signal_connect(err->tree_view, "button_press_event", G_CALLBACK(error_show_popup_menu_cb), err);
417 }
418
419 void
420 init_error_table(error_equiv_table *err, guint16 num_procs, GtkWidget *vbox)
421 {
422     guint16 i, j;
423     GtkTreeStore *store;
424     GtkWidget *tree;
425     GtkTreeViewColumn *column;
426     GtkCellRenderer *renderer;
427     GtkTreeSortable *sortable;
428
429     /* Create the store */
430     store = gtk_tree_store_new (4,       /* Total number of columns */
431                                G_TYPE_STRING,   /* Group              */
432                                G_TYPE_STRING,   /* Protocol           */
433                                G_TYPE_STRING,   /* Summary            */
434                                G_TYPE_INT);     /* Count              */
435
436     /* Create a view */
437     tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
438     err->tree_view = GTK_TREE_VIEW(tree);
439     sortable = GTK_TREE_SORTABLE(store);
440
441     /* Setup the sortable columns */
442     gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
443     gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
444     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW (tree), FALSE);
445
446     /* The view now holds a reference.  We can get rid of our own reference */
447     g_object_unref (G_OBJECT (store));
448
449     /* Create a cell render */
450     renderer = gtk_cell_renderer_text_new ();
451
452     /* Create the first column, associating the "text" attribute of the
453      * cell_renderer to the first column of the model */
454     column = gtk_tree_view_column_new_with_attributes ("Group", renderer, "text", GROUP_COLUMN, NULL);
455     gtk_tree_view_column_set_sort_column_id(column, 0);
456     gtk_tree_view_column_set_resizable(column, TRUE);
457     /* Add the column to the view. */
458     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
459  
460     /* Second column.. Protocol. */
461     renderer = gtk_cell_renderer_text_new ();
462     column = gtk_tree_view_column_new_with_attributes ("Protocol", renderer, "text", PROTOCOL_COLUMN, NULL);
463     gtk_tree_view_column_set_sort_column_id(column, 1);
464     gtk_tree_view_column_set_resizable(column, TRUE);
465     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
466  
467     /* Third column.. Summary. */
468     renderer = gtk_cell_renderer_text_new ();
469     column = gtk_tree_view_column_new_with_attributes ("Summary", renderer, "text", SUMMARY_COLUMN, NULL);
470     gtk_tree_view_column_set_sort_column_id(column, 2);
471     gtk_tree_view_column_set_resizable(column, TRUE);
472     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
473  
474     /* Last column.. Count. */
475     column = gtk_tree_view_column_new_with_attributes ("Count", renderer, "text", COUNT_COLUMN, NULL);
476     gtk_tree_view_column_set_sort_column_id(column, 3);
477     gtk_tree_view_column_set_resizable(column, TRUE);
478     gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
479  
480     err->scrolled_window=scrolled_window_new(NULL, NULL);
481
482     gtk_container_add(GTK_CONTAINER(err->scrolled_window), GTK_WIDGET (err->tree_view));
483
484     gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
485
486     gtk_tree_view_set_search_column (err->tree_view, SUMMARY_COLUMN); /* Allow searching the summary */
487     gtk_tree_view_set_reorderable (err->tree_view, TRUE);   /* Allow user to reorder data with drag n drop */
488     
489     /* Now enable the sorting of each column */
490     gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(err->tree_view), TRUE);
491     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(err->tree_view), TRUE);
492
493     gtk_widget_show(err->scrolled_window);
494
495     err->num_procs=num_procs;
496     err->procedures=g_malloc(sizeof(error_procedure_t)*(num_procs+1));
497     for(i=0;i<num_procs;i++){
498         for(j=0;j<3;j++){
499             err->procedures[i].entries[j]=NULL; /* reset all values */
500         }
501     }
502
503     /* create popup menu for this table */
504     error_create_popup_menu(err);
505 }
506
507 void
508 init_error_table_row(error_equiv_table *err, const expert_info_t *expert_data)
509 {
510     guint16 old_num_procs=err->num_procs;
511     guint16 j;
512     gint row=0;
513
514     GtkTreeStore *store;
515
516     /* we have discovered a new procedure. Extend the table accordingly */
517     row = find_summary_data(err, expert_data);
518     if(row==-1){
519         /* First time we have seen this event so initialize memory table */
520         row = old_num_procs; /* Number of expert events since this is a new event */
521         err->procedures=g_realloc(err->procedures, (sizeof(error_procedure_t)*(old_num_procs+1)));
522         err->procedures[row].count=0; /* count of events for this item */
523         err->procedures[row].fvalue_value = NULL; /* Filter string value */
524         for(j=0;j<4;j++){
525             err->procedures[row].entries[j]=NULL;
526         }
527         
528         /* Create the item in our memory table */
529         err->procedures[row].entries[0]=(char *)g_strdup(val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"));  /* Group */
530         err->procedures[row].entries[1]=(char *)g_strdup(expert_data->protocol);    /* Protocol */
531         err->procedures[row].entries[2]=(char *)g_strdup(expert_data->summary);     /* Summary */
532
533         /* Create a new item in our tree view */
534         store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view)); /* Get store */
535         gtk_tree_store_append (store, &err->procedures[row].iter, NULL);  /* Acquire an iterator */
536         
537         gtk_tree_store_set (store, &err->procedures[row].iter,
538                     GROUP_COLUMN, (char *)g_strdup(val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)")),
539                     PROTOCOL_COLUMN, (char *)g_strdup(expert_data->protocol),
540                     SUMMARY_COLUMN, (char *)g_strdup(expert_data->summary), -1);
541
542         /* If an expert item was passed then build the filter string */
543         if (expert_data->pitem) {
544             char *filter;
545
546             filter = proto_construct_match_selected_string(expert_data->pitem->finfo, NULL);
547             if (filter != NULL)
548                 err->procedures[row].fvalue_value = g_strdup(filter);
549         }
550         /* Store the updated count of events */
551         err->num_procs = ++old_num_procs;
552     }
553
554     /* Update our memory table with event data */
555     err->procedures[row].count++; /* increment the count of events for this item */
556
557     /* Store the updated count for this event item */
558     err->procedures[row].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
559
560     /* Update the tree with new count for this event */
561     store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
562     gtk_tree_store_set(store, &err->procedures[row].iter, COUNT_COLUMN, err->procedures[row].count, -1);
563 }
564
565 void
566 add_error_table_data(error_equiv_table *err, const expert_info_t *expert_data)
567 {
568     error_procedure_t *errp;
569     gint index;
570     GtkTreeStore    *store;
571     GtkTreeIter      new_iter;
572
573     index = find_summary_data(err,expert_data);
574
575     /* We should never encounter a condition where we cannot find the expert data. If
576      * we do then we will just abort.
577      */
578     if (index == -1) {
579         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find expert data. Aborting");
580         return;
581     }
582     errp=&err->procedures[index];
583
584     store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
585
586     gtk_tree_store_append(store, &new_iter, &errp->iter);
587
588     gtk_tree_store_set(store, &new_iter,
589                            GROUP_COLUMN, "Packet:",
590                            PROTOCOL_COLUMN, (char *)g_strdup_printf("%d", expert_data->packet_num),
591                            -1);
592 }
593
594 void
595 reset_error_table_data(error_equiv_table *err)
596 {
597     guint16 i;
598     GtkTreeStore    *store;
599
600     for(i=0;i<err->num_procs;i++){
601         err->procedures[i].entries[0] = NULL;
602         err->procedures[i].entries[1] = NULL;
603         err->procedures[i].entries[2] = NULL;
604         err->procedures[i].entries[3] = NULL;
605         err->procedures[i].count=0;
606     }
607
608     store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
609     gtk_tree_store_clear(store);
610     err->num_procs = 0;
611 }
612
613 void
614 free_error_table_data(error_equiv_table *err)
615 {
616     guint16 i,j;
617
618     for(i=0;i<err->num_procs;i++){
619         for(j=0;j<4;j++){
620             if(err->procedures[i].entries[j]){
621                 err->procedures[i].entries[j]=NULL;
622             }
623             err->procedures[i].fvalue_value=NULL;
624             err->procedures[i].count=0;
625         }
626     }
627     err->procedures=NULL;
628     err->num_procs=0;
629 }