Re: SV: Update to the composite expert statistics

Greg Morris <[email protected]>
Newsgroups gmane.network.ethereal.devel
Message-ID <[email protected]>
Sorry, the original submission was based on 0.10.14. Here are updated diffs against the current svn.

Thanks,
Greg

>>> "Anders Broman" <[email protected]> 5/3/2006 7:15 AM >>>

Hi,
The patch fail to apply...

Brg
Anders

-----Ursprungligt meddelande-----
Från: [email protected]
[mailto:[email protected]] För Greg Morris
Skickat: den 27 april 2006 10:00
Till: [email protected]
Ämne: [Ethereal-dev] Update to the composite expert statistics


Is anyone reviewing the posting from March 16th? Is there anything I need to
change/do?

Attached is the original email...

Greg


_______________________________________________
Ethereal-dev mailing list
[email protected]
http://www.ethereal.com/mailman/listinfo/ethereal-dev

_______________________________________________
Ethereal-dev mailing list
[email protected]
http://www.ethereal.com/mailman/listinfo/ethereal-dev

_______________________________________________
Ethereal-dev mailing list
[email protected]
http://www.ethereal.com/mailman/listinfo/ethereal-dev
expert_comp_table.c.diff (text/plain, 34.7 KB)
Index: expert_comp_table.c
===================================================================
--- expert_comp_table.c	(revision 18081)
+++ expert_comp_table.c	(working copy)
@@ -37,8 +37,12 @@
 #include "compat_macros.h"
 #include "epan/packet_info.h"
 #include "expert_comp_table.h"
+
+#if (GTK_MAJOR_VERSION < 2)
 #include "image/clist_ascend.xpm"
 #include "image/clist_descend.xpm"
+#endif
+
 #include "simple_dialog.h"
 #include "globals.h"
 #include "gtk/find_dlg.h"
@@ -53,11 +57,51 @@
 
 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
 
+#define SORT_ALPHABETICAL 0
+
+#if (GTK_MAJOR_VERSION >= 2)
+static gint
+sort_iter_compare_func (GtkTreeModel *model,
+GtkTreeIter *a,
+GtkTreeIter *b,
+gpointer userdata)
+{
+    gint sortcol = GPOINTER_TO_INT(userdata);
+    gint ret = 0;
+    switch (sortcol)
+    {
+        case SORT_ALPHABETICAL:
+        {
+        gchar *name1, *name2;
+        gtk_tree_model_get(model, a, 0, &name1, -1);
+        gtk_tree_model_get(model, b, 0, &name2, -1);
+        if (name1 == NULL || name2 == NULL)
+        {
+            if (name1 == NULL && name2 == NULL)
+                break; /* both equal => ret = 0 */
+            ret = (name1 == NULL) ? -1 : 1;
+        }
+        else
+        {
+            ret = g_ascii_strcasecmp(name1,name2);
+        }
+        g_free(name1);
+        g_free(name2);
+        }
+        break;
+        default:
+        g_return_val_if_reached(0);
+    }
+    return ret;
+}
+#endif
+
 /* XXX - move this to a common header file */
 static const value_string expert_group_vals[] = {
 	{ PI_CHECKSUM,		"Checksum" },
 	{ PI_SEQUENCE,		"Sequence" },
 	{ PI_RESPONSE_CODE, "Response" },
+    { PI_REQUEST_CODE,  "Request" },
 	{ PI_UNDECODED,		"Undecoded" },
 	{ PI_MALFORMED,		"Malformed" },
 	{ PI_REASSEMBLE,	"Reassemble" },
@@ -65,6 +109,9 @@
 	{ 0, NULL }
 };
 
+
+#if (GTK_MAJOR_VERSION < 2)
+
 typedef struct column_arrows {
 	GtkWidget *table;
 	GtkWidget *ascend_pm;
@@ -140,39 +187,32 @@
 	return 0;
 }
 
+#else
+enum
+{
+   GROUP_COLUMN,
+   PROTOCOL_COLUMN,
+   SUMMARY_COLUMN,
+   COUNT_COLUMN,
+   N_COLUMNS
+};
+#endif
 
-#if (GTK_MAJOR_VERSION >= 2)
-static void
-copy_as_csv_cb(GtkWindow *win _U_, gpointer data)
+static gint find_summary_data(error_equiv_table *err, const expert_info_t *expert_data)
 {
-   guint32         i,j;
-   gchar           *table_entry;
-   GtkClipboard    *cb;
-   GString         *CSV_str = g_string_new("");
-
-   error_equiv_table *expert=(error_equiv_table *)data;
-
-   /* Add the column headers to the CSV data */
-   g_string_append(CSV_str,"Summary,Group,Protocol,Count"); /* add the column headings to the CSV string */
-   g_string_append(CSV_str,"\n");                        /* new row */
-
-   /* Add the column values to the CSV data */
-   for(i=0;i<expert->num_procs;i++){                     /* all rows            */
-    for(j=0;j<4;j++){                                    /* all columns         */
-     gtk_clist_get_text(expert->table,i,j,&table_entry); /* copy table item into string */
-     g_string_append(CSV_str,table_entry);               /* add the table entry to the CSV string */
-    if(j!=(4-1))
-     g_string_append(CSV_str,",");
+    gint i;
+    
+    /* First time thru values will be 0 */
+    if (err->num_procs==0) {
+        return -1;
     }
-    g_string_append(CSV_str,"\n");                       /* new row */
-   }
-
-   /* Now that we have the CSV data, copy it into the default clipboard */
-   cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);      /* Get the default clipboard */
-   gtk_clipboard_set_text(cb, CSV_str->str, -1);         /* Copy the CSV data into the clipboard */
-   g_string_free(CSV_str, TRUE);                         /* Free the memory */
+    for (i=0;i<err->num_procs;i++) {
+        if (strcmp(err->procedures[i].entries[2], expert_data->summary) == 0) {
+            return i;
+        }
+    }
+    return -1;
 }
-#endif
 
 /* action is encoded as 
    filter_action*256+filter_type
@@ -196,23 +236,48 @@
 static void
 error_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data, guint callback_action)
 {
-    int action, type, selection;
-    error_equiv_table *err = (error_equiv_table *)callback_data;
-    char str[256];
-    const char *current_filter;
+	int action, type, selection;
+	error_equiv_table *err = (error_equiv_table *)callback_data;
+	char str[256];
+	const char *current_filter;
 
+#if (GTK_MAJOR_VERSION >= 2)
+    GtkTreeIter iter;
+    GtkTreeModel *model;
+    const expert_info_t expert_data;
+#endif
+
     action=(callback_action>>8)&0xff;
-    type=callback_action&0xff;
+	type=callback_action&0xff;
 
-    selection=GPOINTER_TO_INT(g_list_nth_data(GTK_CLIST(err->table)->selection, 0));
-    if(selection>=(int)err->num_procs){
-        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No items are selected");
+
+#if (GTK_MAJOR_VERSION < 2)
+   	selection=GPOINTER_TO_INT(g_list_nth_data(GTK_CLIST(err->table)->selection, 0));
+#else
+    gtk_tree_selection_get_selected(err->select, &model, &iter);
+
+    gtk_tree_model_get (model, &iter, GROUP_COLUMN, &expert_data.group, -1);
+    gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &expert_data.protocol, -1);
+    gtk_tree_model_get (model, &iter, SUMMARY_COLUMN, &expert_data.summary, -1);
+    
+    if (strcmp((char *)expert_data.group, "Packet:")==0) {
+		simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You cannot filter or search for packet number. Click on a valid item header.");
         return;
     }
-    /* translate it back from row index to index in procedures array */
+
+    selection = find_summary_data(err, &expert_data);
+#endif
+
+	if(selection>=(int)err->num_procs){
+		simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "No items are selected");
+		return;
+	}
+#if (GTK_MAJOR_VERSION < 2)
+	/* translate it back from row index to index in procedures array */
     selection=GPOINTER_TO_INT(gtk_clist_get_row_data(err->table, selection));
+#endif
 
-    current_filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
+	current_filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
 
     /* Some expert data doesn't pass an expert item. Without this we cannot create a filter */
     /* But allow for searching of internet for error string */
@@ -223,9 +288,9 @@
                 return;
             }
         }
-        switch(type){
-        case 0:
-            /* selected */
+    	switch(type){
+    	case 0:
+    		/* selected */
             /* if no expert item was passed */
             if (err->procedures[selection].fvalue_value==NULL) {
                 g_snprintf(str, 255, "%s", err->procedures[selection].entries[2]);
@@ -235,9 +300,9 @@
                 /* expert item exists. Use it. */
                 g_snprintf(str, 255, "%s", err->procedures[selection].fvalue_value);
             }
-            break;
-        case 1:
-            /* not selected */
+    		break;
+    	case 1:
+    		/* not selected */
             /* if no expert item was passed */
             if (err->procedures[selection].fvalue_value==NULL) {
                 g_snprintf(str, 255, "!%s", err->procedures[selection].entries[2]);
@@ -247,50 +312,50 @@
                 /* expert item exists. Use it. */
                 g_snprintf(str, 255, "!(%s)", err->procedures[selection].fvalue_value);
             }
-            break;
+    		break;
             /* the remaining cases will only exist if the expert item exists so no need to check */
-        case 2:
-            /* and selected */
-            g_snprintf(str, 255, "(%s) && (%s)", current_filter, err->procedures[selection].fvalue_value);
-            break;
-        case 3:
-            /* or selected */
-            g_snprintf(str, 255, "(%s) || (%s)", current_filter, err->procedures[selection].fvalue_value);
-            break;
-        case 4:
-            /* and not selected */
-            g_snprintf(str, 255, "(%s) && !(%s)", current_filter, err->procedures[selection].fvalue_value);
-            break;
-        case 5:
-            /* or not selected */
-            g_snprintf(str, 255, "(%s) || !(%s)", current_filter, err->procedures[selection].fvalue_value);
-            break;
+    	case 2:
+    		/* and selected */
+    		g_snprintf(str, 255, "(%s) && (%s)", current_filter, err->procedures[selection].fvalue_value);
+    		break;
+    	case 3:
+    		/* or selected */
+    		g_snprintf(str, 255, "(%s) || (%s)", current_filter, err->procedures[selection].fvalue_value);
+    		break;
+    	case 4:
+    		/* and not selected */
+    		g_snprintf(str, 255, "(%s) && !(%s)", current_filter, err->procedures[selection].fvalue_value);
+    		break;
+    	case 5:
+    		/* or not selected */
+    		g_snprintf(str, 255, "(%s) || !(%s)", current_filter, err->procedures[selection].fvalue_value);
+    		break;
         default:
             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu type - %u", type);
-        }
+    	}
     }
 
-    switch(action){
-    case 0:
-        /* match */
-        main_filter_packets(&cfile, str, FALSE);
+	switch(action){
+	case 0:
+		/* match */
+		main_filter_packets(&cfile, str, FALSE);
         break;
-    case 1:
-        /* prepare */
+	case 1:
+		/* prepare */
         gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), str);
-        break;
-    case 2:
-        /* find frame */
+		break;
+	case 2:
+		/* find frame */
         /* When trying to perform a find without expert item, we must pass
          * the expert string to the find window. The user might need to modify
          * the string and click on the text search to locate the packet in question.
          * So regardless of the type we will just bring up the find window and allow
          * the user to modify the search criteria and options.
          */
-        find_frame_with_filter(str);
-        break;
-    case 3:
-        /* find next */
+            find_frame_with_filter(str);
+		break;
+	case 3:
+		/* find next */
         /* In the case of find next, if there was no expert item, then most likely the expert
          * string was modified to locate the text inside the message. So we can't just perform
          * a find with the expert string or we will not really be performing a find next.
@@ -305,11 +370,11 @@
         else
         { 
             /* We have an expert item so just continue search without find dialog. */
-            find_previous_next_frame_with_filter(str, FALSE);
+		    find_previous_next_frame_with_filter(str, FALSE);
         }
-        break;
-    case 4:
-        /* find previous */
+		break;
+	case 4:
+		/* find previous */
         /* In the case of find previous, if there was no expert item, then most likely the expert
          * string was modified to locate the text inside the message. So we can't just perform
          * a find with the expert string or we will not really be performing a find previous.
@@ -324,25 +389,27 @@
         else
         { 
             /* We have an expert item so just continue search without find dialog. */
-            find_previous_next_frame_with_filter(str, TRUE);
+		    find_previous_next_frame_with_filter(str, TRUE);
         }
-        break;
-    case 5:
-        /* colorize procedure */
-        color_display_with_filter(str);
-        break;
-    case 6:
-        /* Lookup expert string on internet. Default search via www.google.com */
-        g_snprintf(str, 255, "http://www.google.com/search?hl=en&q=%s+'%s'", err->procedures[selection].entries[1], err->procedures[selection].entries[2]);
+		break;
+	case 5:
+		/* colorize procedure */
+		color_display_with_filter(str);
+		break;
+	case 6:
+		/* Lookup expert string on internet. Default search via www.google.com */
+		g_snprintf(str, 255, "http://www.google.com/search?hl=en&q=%s+'%s'", err->procedures[selection].entries[1], err->procedures[selection].entries[2]);
         browser_open_url(str);
-        break;
+		break;
+#if (GTK_MAJOR_VERSION < 2)
     case 7:
         /* Goto the first occurance (packet) in the trace */
         cf_goto_frame(&cfile, err->procedures[selection].packet_num);
         break;
+#endif
     default:
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Can't find menu action - %u", action);
-    }
+	}
 
 }
 
@@ -422,136 +489,215 @@
 	/* Search Internet */
 	ITEM_FACTORY_ENTRY("/Internet Search for Info Text", NULL,
 		error_select_filter_cb, 6*256+0, NULL, NULL),
-
-	/* Go to first packet matching this entry */
+#if (GTK_MAJOR_VERSION < 2)
+   	/* Go to first packet matching this entry */
 	ITEM_FACTORY_ENTRY("/Goto First Occurance", NULL,
 		error_select_filter_cb, 7*256+0, NULL, NULL),
+#endif
 };
 
+#if (GTK_MAJOR_VERSION >= 2)
 static void
+expert_goto_pkt_cb (GtkTreeSelection *selection, gpointer data)
+{
+        GtkTreeIter iter;
+        GtkTreeModel *model;
+        gchar *pkt;
+        gchar *grp;
+        error_equiv_table *err=data;
+
+        if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+                gtk_tree_model_get (model, &iter, PROTOCOL_COLUMN, &pkt, -1);
+                gtk_tree_model_get (model, &iter, GROUP_COLUMN, &grp, -1);
+
+                if (strcmp(grp, "Packet:")==0) {
+                    cf_goto_frame(&cfile, atoi(pkt));
+                }
+                g_free (pkt);
+                g_free (grp);
+        }
+}
+#endif
+
+static void
 error_create_popup_menu(error_equiv_table *err)
 {
 	GtkItemFactory *item_factory;
 
+
+#if (GTK_MAJOR_VERSION >= 2)
+    err->select = gtk_tree_view_get_selection (GTK_TREE_VIEW (err->tree_view));
+    gtk_tree_selection_set_mode (err->select, GTK_SELECTION_SINGLE);
+    g_signal_connect (G_OBJECT (err->select), "changed",
+                  G_CALLBACK (expert_goto_pkt_cb),
+                  err);
+#endif
 	item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
 
 	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);
 
 	err->menu = gtk_item_factory_get_widget(item_factory, "<main>");
-	SIGNAL_CONNECT(err->table, "button_press_event", error_show_popup_menu_cb, err);
+	SIGNAL_CONNECT(err->tree_view, "button_press_event", error_show_popup_menu_cb, err);
 }
 
 void
 init_error_table(error_equiv_table *err, guint16 num_procs, GtkWidget *vbox)
 {
-    guint16 i, j;
-    column_arrows *col_arrows;
-    GdkBitmap *ascend_bm, *descend_bm;
-    GdkPixmap *ascend_pm, *descend_pm;
-    GtkStyle *win_style;
-    GtkWidget *column_lb;
-#if (GTK_MAJOR_VERSION >= 2)
-    GtkWidget *copy_bt;
-#endif
+	guint16 i, j;
+#if (GTK_MAJOR_VERSION < 2)
+	column_arrows *col_arrows;
+	GdkBitmap *ascend_bm, *descend_bm;
+	GdkPixmap *ascend_pm, *descend_pm;
+	GtkStyle *win_style;
+	GtkWidget *column_lb;
+
     GtkTooltips *tooltips = gtk_tooltips_new();
-    const char *default_titles[] = { "Group", "Protocol", "Summary", "Count"};
+	const char *default_titles[] = { "Group", "Protocol", "Summary", "Count"};
 
-    err->scrolled_window=scrolled_window_new(NULL, NULL);
-    gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
+	err->scrolled_window=scrolled_window_new(NULL, NULL);
+	gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
 
-    err->table=(GtkCList *)gtk_clist_new(4);
+	err->table=(GtkCList *)gtk_clist_new(4);
 
-    gtk_widget_show(GTK_WIDGET(err->table));
-    gtk_widget_show(err->scrolled_window);
+	gtk_widget_show(GTK_WIDGET(err->table));
+	gtk_widget_show(err->scrolled_window);
 
-    col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * 4);
-    win_style = gtk_widget_get_style(err->scrolled_window);
-    ascend_pm = gdk_pixmap_create_from_xpm_d(err->scrolled_window->window,
-            &ascend_bm,
-            &win_style->bg[GTK_STATE_NORMAL],
-            (gchar **)clist_ascend_xpm);
-    descend_pm = gdk_pixmap_create_from_xpm_d(err->scrolled_window->window,
-            &descend_bm,
-            &win_style->bg[GTK_STATE_NORMAL],
-            (gchar **)clist_descend_xpm);
-    for (i = 0; i < 4; i++) {
-        col_arrows[i].table = gtk_table_new(2, 2, FALSE);
-        gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
-        column_lb = gtk_label_new(default_titles[i]);
-        gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
-        gtk_widget_show(column_lb);
+	col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * 4);
+	win_style = gtk_widget_get_style(err->scrolled_window);
+	ascend_pm = gdk_pixmap_create_from_xpm_d(err->scrolled_window->window,
+			&ascend_bm,
+			&win_style->bg[GTK_STATE_NORMAL],
+			(gchar **)clist_ascend_xpm);
+	descend_pm = gdk_pixmap_create_from_xpm_d(err->scrolled_window->window,
+			&descend_bm,
+			&win_style->bg[GTK_STATE_NORMAL],
+			(gchar **)clist_descend_xpm);
+	for (i = 0; i < 4; i++) {
+		col_arrows[i].table = gtk_table_new(2, 2, FALSE);
+		gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
+		column_lb = gtk_label_new(default_titles[i]);
+		gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
+		gtk_widget_show(column_lb);
 
-        col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
-        gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
-        col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
-        gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
-        if (i == 3) {
-            gtk_widget_show(col_arrows[i].descend_pm);
-        }
-        gtk_clist_set_column_widget(GTK_CLIST(err->table), i, col_arrows[i].table);
-        gtk_widget_show(col_arrows[i].table);
-    }
-    gtk_clist_column_titles_show(GTK_CLIST(err->table));
+		col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
+		gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
+		col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
+		gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
+		if (i == 3) {
+			gtk_widget_show(col_arrows[i].descend_pm);
+		}
+		gtk_clist_set_column_widget(GTK_CLIST(err->table), i, col_arrows[i].table);
+		gtk_widget_show(col_arrows[i].table);
+	}
+	gtk_clist_column_titles_show(GTK_CLIST(err->table));
 
-    gtk_clist_set_compare_func(err->table, error_sort_column);
-    gtk_clist_set_sort_column(err->table, 3);
-    gtk_clist_set_sort_type(err->table, GTK_SORT_DESCENDING);
+	gtk_clist_set_compare_func(err->table, error_sort_column);
+	gtk_clist_set_sort_column(err->table, 3);
+	gtk_clist_set_sort_type(err->table, GTK_SORT_DESCENDING);
 
 
-    /*XXX instead of this we should probably have some code to
-        dynamically adjust the width of the columns */
-    gtk_clist_set_column_width(err->table, 0, 75);
-    gtk_clist_set_column_width(err->table, 1, 75);
-    gtk_clist_set_column_width(err->table, 2, 400);
-    gtk_clist_set_column_width(err->table, 3, 50);
+	/*XXX instead of this we should probably have some code to
+		dynamically adjust the width of the columns */
+	gtk_clist_set_column_width(err->table, 0, 75);
+	gtk_clist_set_column_width(err->table, 1, 75);
+	gtk_clist_set_column_width(err->table, 2, 400);
+	gtk_clist_set_column_width(err->table, 3, 50);
 
 
-    gtk_clist_set_shadow_type(err->table, GTK_SHADOW_IN);
-    gtk_clist_column_titles_show(err->table);
-    gtk_container_add(GTK_CONTAINER(err->scrolled_window), (GtkWidget *)err->table);
+	gtk_clist_set_shadow_type(err->table, GTK_SHADOW_IN);
+	gtk_clist_column_titles_show(err->table);
+	gtk_container_add(GTK_CONTAINER(err->scrolled_window), (GtkWidget *)err->table);
 
-    SIGNAL_CONNECT(err->table, "click-column", error_click_column_cb, col_arrows);
+	SIGNAL_CONNECT(err->table, "click-column", error_click_column_cb, col_arrows);
 
-    gtk_widget_show(GTK_WIDGET(err->table));
-    gtk_widget_show(err->scrolled_window);
+	gtk_widget_show(GTK_WIDGET(err->table));
+#else
+    GtkTreeStore *store;
+    GtkWidget *tree;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *renderer;
+    GtkTreeSortable *sortable;
 
+    /* Create the store */
+    store = gtk_tree_store_new (4,       /* Total number of columns */
+                               G_TYPE_STRING,   /* Group              */
+                               G_TYPE_STRING,   /* Protocol           */
+                               G_TYPE_STRING,   /* Summary            */
+                               G_TYPE_STRING);  /* Count              */
 
-    err->num_procs=num_procs;
-    err->procedures=g_malloc(sizeof(error_procedure_t)*(num_procs+1));
-    for(i=0;i<num_procs;i++){
-        for(j=0;j<3;j++){
-            err->procedures[i].entries[j]=NULL; /* reset all values */
-        }
-    }
+    /* Create a view */
+    tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+    err->tree_view = GTK_TREE_VIEW(tree);
+    sortable = GTK_TREE_SORTABLE(store);
 
-#if (GTK_MAJOR_VERSION >= 2)
-    /* XXX - maybe we want to have a "Copy as CSV" stock button here? */
-    /*copy_bt = gtk_button_new_with_label ("Copy content to clipboard as CSV");*/
-    copy_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_COPY);
-    gtk_tooltips_set_tip(tooltips, copy_bt,
-        "Copy all expert information to the clipboard in CSV (Comma Seperated Values) format.", NULL);
-    SIGNAL_CONNECT(copy_bt, "clicked", copy_as_csv_cb,(gpointer *) err);
-    gtk_box_pack_start(GTK_BOX(vbox), copy_bt, FALSE, FALSE, 0);
+    /* Setup the sortable columns */
+    gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
+    gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
+    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW (tree), FALSE);
+
+    /* The view now holds a reference.  We can get rid of our own reference */
+    g_object_unref (G_OBJECT (store));
+
+    /* Create a cell render */
+    renderer = gtk_cell_renderer_text_new ();
+
+    /* Create the first column, associating the "text" attribute of the
+     * cell_renderer to the first column of the model */
+    column = gtk_tree_view_column_new_with_attributes ("Group", renderer, "text", GROUP_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 0);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    /* Add the column to the view. */
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+    /* Second column.. Protocol. */
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Protocol", renderer, "text", PROTOCOL_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 1);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+    /* Third column.. Summary. */
+    renderer = gtk_cell_renderer_text_new ();
+    column = gtk_tree_view_column_new_with_attributes ("Summary", renderer, "text", SUMMARY_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 2);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+    /* Last column.. Count. */
+    column = gtk_tree_view_column_new_with_attributes ("Count", renderer, "text", COUNT_COLUMN, NULL);
+    gtk_tree_view_column_set_sort_column_id(column, 3);
+    gtk_tree_view_column_set_resizable(column, TRUE);
+    gtk_tree_view_append_column (GTK_TREE_VIEW (err->tree_view), column);
+ 
+ 	err->scrolled_window=scrolled_window_new(NULL, NULL);
+
+    gtk_container_add(GTK_CONTAINER(err->scrolled_window), GTK_WIDGET (err->tree_view));
+
+	gtk_box_pack_start(GTK_BOX(vbox), err->scrolled_window, TRUE, TRUE, 0);
+
+    gtk_tree_view_set_search_column (err->tree_view, SUMMARY_COLUMN); /* Allow searching the summary */
+    gtk_tree_view_set_reorderable (err->tree_view, TRUE);   /* Allow user to reorder data with drag n drop */
+    
+    /* Now enable the sorting of each column */
+    gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(err->tree_view), TRUE);
+    gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(err->tree_view), TRUE);
+
+	gtk_container_add(GTK_CONTAINER(err->scrolled_window), GTK_WIDGET (err->tree_view));
 #endif
 
-    /* create popup menu for this table */
-    error_create_popup_menu(err);
-}
+	gtk_widget_show(err->scrolled_window);
 
-static gint find_summary_data(error_equiv_table *err, const expert_info_t *expert_data)
-{
-    gint i;
-    
-    /* First time thru values will be 0 */
-    if (err->num_procs==0 || err->procedures[0].entries[2]==0) {
-        return -1;
-    }
-    for (i=0;i<err->num_procs;i++) {
-        if (strcmp(err->procedures[i].entries[2], expert_data->summary) == 0) {
-            return i;
-        }
-    }
-    return -1;
+    err->num_procs=num_procs;
+	err->procedures=g_malloc(sizeof(error_procedure_t)*(num_procs+1));
+	for(i=0;i<num_procs;i++){
+		for(j=0;j<3;j++){
+			err->procedures[i].entries[j]=NULL; /* reset all values */
+		}
+	}
+
+	/* create popup menu for this table */
+  	error_create_popup_menu(err);
 }
 
 void
@@ -561,35 +707,88 @@
     guint16 j;
     gint row=0;
 
-    /* we have discovered a new procedure. Extend the table accordingly */
+#if (GTK_MAJOR_VERSION >= 2)
+    GtkTreeStore *store;
+#endif
+
+	/* we have discovered a new procedure. Extend the table accordingly */
     row = find_summary_data(err, expert_data);
-    if(row==-1){
-        row = 0;
-        old_num_procs++;
-        err->procedures=g_realloc(err->procedures, (sizeof(error_procedure_t)*(old_num_procs+1)));
-        err->procedures[err->num_procs].count=0;
+	if(row==-1){
+        /* First time we have seen this event so initialize memory table */
+#if (GTK_MAJOR_VERSION < 2)
+            row = 0;
+            old_num_procs++;
+
+		    err->procedures=g_realloc(err->procedures, (sizeof(error_procedure_t)*(old_num_procs+1)));
+            err->procedures[err->num_procs].count=0;
+		    for(j=0;j<4;j++)
+            {
+    			err->procedures[err->num_procs].entries[j]=NULL;
+		    }
+            err->procedures[err->num_procs].packet_num = (guint32)expert_data->packet_num;                        /* First packet num */
+	    }
+	    err->procedures[err->num_procs].entries[0]=(char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"), NULL);   /* Group */
+        err->procedures[err->num_procs].entries[1]=(char *)g_strdup_printf("%s", expert_data->protocol, NULL);    /* Protocol */
+        err->procedures[err->num_procs].entries[2]=(char *)g_strdup_printf("%s", expert_data->summary, NULL);     /* Summary */
+    	err->procedures[err->num_procs].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
+        err->procedures[err->num_procs].fvalue_value = NULL;
+    }
+    /* Store the updated count of events */
+    err->num_procs = old_num_procs;
+#else
+        row = old_num_procs; /* Number of expert events since this is a new event */
+		err->procedures=g_realloc(err->procedures, (sizeof(error_procedure_t)*(old_num_procs+1)));
+        err->procedures[row].count=0; /* count of events for this item */
+        err->procedures[row].fvalue_value = NULL; /* Filter string value */
         for(j=0;j<4;j++){
-            err->procedures[err->num_procs].entries[j]=NULL;
+			err->procedures[row].entries[j]=NULL;
+		}
+        
+            /* Create the item in our memory table */
+            err->procedures[row].entries[0]=(char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"), NULL);  /* Group */
+            err->procedures[row].entries[1]=(char *)g_strdup_printf("%s", expert_data->protocol, NULL);    /* Protocol */
+            err->procedures[row].entries[2]=(char *)g_strdup_printf("%s", expert_data->summary, NULL);     /* Summary */
+
+        /* Create a new item in our tree view */
+        store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view)); /* Get store */
+        gtk_tree_store_append (store, &err->procedures[row].iter, NULL);  /* Acquire an iterator */
+        
+        gtk_tree_store_set (store, &err->procedures[row].iter,
+                    GROUP_COLUMN, (char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"), NULL),
+                    PROTOCOL_COLUMN, (char *)g_strdup_printf("%s", expert_data->protocol, NULL),
+                    SUMMARY_COLUMN, (char *)g_strdup_printf("%s", expert_data->summary, NULL), -1);
+
+        /* If an expert item was passed then build the filter string */
+        if (expert_data->pitem && strcmp(expert_data->pitem->finfo->value.ftype->name,"FT_NONE")!=0) {
+            err->procedures[row].fvalue_value = g_strdup_printf("%s", proto_construct_dfilter_string(expert_data->pitem->finfo, NULL));
         }
-        err->procedures[err->num_procs].packet_num = (guint32)expert_data->packet_num;                        /* First packet num */
-    }
-    err->procedures[err->num_procs].entries[0]=(char *)g_strdup_printf("%s", val_to_str(expert_data->group, expert_group_vals,"Unknown group (%u)"));   /* Group */
-    err->procedures[err->num_procs].entries[1]=(char *)g_strdup_printf("%s", expert_data->protocol);    /* Protocol */
-    err->procedures[err->num_procs].entries[2]=(char *)g_strdup_printf("%s", expert_data->summary);     /* Summary */
-    err->procedures[err->num_procs].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
-    err->procedures[err->num_procs].fvalue_value = NULL;
-    if (expert_data->pitem && strcmp(expert_data->pitem->finfo->value.ftype->name,"FT_NONE")!=0) {
-        err->procedures[err->num_procs].fvalue_value = g_strdup_printf("%s", proto_construct_dfilter_string(expert_data->pitem->finfo, NULL));
-    }
-    err->num_procs = old_num_procs;                                                           
+        /* Store the updated count of events */
+        err->num_procs = ++old_num_procs;
+	}
+
+    /* Update our memory table with event data */
+    err->procedures[row].count++; /* increment the count of events for this item */
+
+    /* Store the updated count for this event item */
+	err->procedures[row].entries[3]=(char *)g_strdup_printf("%d", err->procedures[row].count);     /* Count */
+
+    /* Update the tree with new count for this event */
+    store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
+    gtk_tree_store_set(store, &err->procedures[row].iter, COUNT_COLUMN, (char *)g_strdup_printf("%d", err->procedures[row].count), -1);
+#endif
 }
 
 void
 add_error_table_data(error_equiv_table *err, const expert_info_t *expert_data)
 {
-    error_procedure_t *errp;
+	error_procedure_t *errp;
+    gint index;
+#if (GTK_MAJOR_VERSION < 2)
     gint row;
-    gint index;
+#else
+    GtkTreeStore    *store;
+    GtkTreeIter      new_iter;
+#endif
 
     index = find_summary_data(err,expert_data);
 
@@ -600,79 +799,102 @@
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not find expert data. Aborting");
         return;
     }
-    errp=&err->procedures[index];
+	errp=&err->procedures[index];
 
-    /*
-     * If the count of calls for this procedure is currently zero, it's
-     * going to become non-zero, so add a row for it (we don't want
-     * rows for procedures that have no calls - especially if the
-     * procedure has no calls because the index doesn't correspond
-     * to a procedure, but is an unused/reserved value).
-     *
-     * (Yes, this means that the rows aren't in order by anything
-     * interesting.  That's why we have the table sorted by a column.)
-     */
-    if (errp->count==0){
-        row=gtk_clist_append(err->table, err->procedures[index].entries);
-        gtk_clist_set_row_data(err->table, row, (gpointer) index);
-    }
+#if (GTK_MAJOR_VERSION < 2)
+   	if (errp->count==0){
+		row=gtk_clist_append(err->table, err->procedures[index].entries);
+		gtk_clist_set_row_data(err->table, row, (gpointer) index);
+	}
     errp->count++;
     err->procedures[index].entries[3] = (char *)g_strdup_printf("%d", errp->count);
+#else
+
+    store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
+
+    gtk_tree_store_append(store, &new_iter, &errp->iter);
+
+    gtk_tree_store_set(store, &new_iter,
+                           GROUP_COLUMN, "Packet:",
+                           PROTOCOL_COLUMN, (char *)g_strdup_printf("%d", expert_data->packet_num),
+                           -1);
+#endif
 }
 
+
+#if (GTK_MAJOR_VERSION < 2)
 void
 draw_error_table_data(error_equiv_table *err)
 {
-    int i,j;
-    char *strp;
+	int i,j;
+	char *strp;
 
-    for(i=0;i<err->num_procs;i++){
-        /* ignore procedures with no calls (they don't have CList rows) */
-        if(err->procedures[i].count==0){
-            continue;
-        }
+	for(i=0;i<err->num_procs;i++){
+		/* ignore procedures with no calls (they don't have CList rows) */
+		if(err->procedures[i].count==0){
+			continue;
+		}
 
-        j=gtk_clist_find_row_from_data(err->table, (gpointer)i);
-        strp=g_strdup_printf("%d", err->procedures[i].count);
-        gtk_clist_set_text(err->table, j, 3, strp);
-        err->procedures[i].entries[3]=(char *)strp;
+		j=gtk_clist_find_row_from_data(err->table, (gpointer)i);
+		strp=g_strdup_printf("%d", err->procedures[i].count);
+		gtk_clist_set_text(err->table, j, 3, strp);
+		err->procedures[i].entries[3]=(char *)strp;
 
 
-    }
-    gtk_clist_sort(err->table);
+	}
+	gtk_clist_sort(err->table);
 }
+#endif
 
-
 void
 reset_error_table_data(error_equiv_table *err)
 {
-    guint16 i;
+	guint16 i;
+#if (GTK_MAJOR_VERSION >= 2)
+    GtkTreeStore    *store;
+#endif
 
-    for(i=0;i<err->num_procs;i++){
-        err->procedures[i].entries[0] = NULL;
-        err->procedures[i].entries[1] = NULL;
-        err->procedures[i].entries[2] = NULL;
-        err->procedures[i].entries[3] = NULL;
+	for(i=0;i<err->num_procs;i++){
+		err->procedures[i].entries[0] = NULL;
+		err->procedures[i].entries[1] = NULL;
+		err->procedures[i].entries[2] = NULL;
+		err->procedures[i].entries[3] = NULL;
+#if (GTK_MAJOR_VERSION < 2)
         err->procedures[i].packet_num=0;
-    }
-    gtk_clist_clear(err->table);
+#else
+        err->procedures[i].count=0;
+#endif
+
+	}
+
+#if (GTK_MAJOR_VERSION < 2)
+	gtk_clist_clear(err->table);
+#else
+    store = GTK_TREE_STORE(gtk_tree_view_get_model(err->tree_view));
+    gtk_tree_store_clear(store);
+#endif
     err->num_procs = 0;
 }
 
 void
 free_error_table_data(error_equiv_table *err)
 {
-    guint16 i,j;
+	guint16 i,j;
 
-    for(i=0;i<err->num_procs;i++){
-        for(j=0;j<4;j++){
-            if(err->procedures[i].entries[j]){
-                err->procedures[i].entries[j]=NULL;
-            }
+	for(i=0;i<err->num_procs;i++){
+		for(j=0;j<4;j++){
+			if(err->procedures[i].entries[j]){
+				err->procedures[i].entries[j]=NULL;
+			}
             err->procedures[i].fvalue_value=NULL;
+
+#if (GTK_MAJOR_VERSION < 2)
             err->procedures[i].packet_num=0;
-        }
-    }
-    err->procedures=NULL;
-    err->num_procs=0;
+#else
+            err->procedures[i].count=0;
+#endif
+		}
+	}
+	err->procedures=NULL;
+	err->num_procs=0;
 }
expert_comp_table.h.diff (text/plain, 2.1 KB)
Index: expert_comp_table.h
===================================================================
--- expert_comp_table.h	(revision 18081)
+++ expert_comp_table.h	(working copy)
@@ -36,7 +36,11 @@
 typedef struct _error_procedure_t {
 	char    *entries[4];       /**< column entries */
     char    *fvalue_value;     /**< filter value */
+#if (GTK_MAJOR_VERSION < 2)
 	guint32 packet_num;        /**< first packet number */
+#else
+    GtkTreeIter      iter;
+#endif
     guint16 count;             /**< number of expert items encountered
                                     for this entry */
 } error_procedure_t;
@@ -44,12 +48,32 @@
 /** Statistics table */
 typedef struct _error_equiv_table {
 	GtkWidget *scrolled_window;         /**< window widget */
-	GtkCList *table;                    /**< table widget */
+#if (GTK_MAJOR_VERSION < 2)
+    GtkCList *table;                    /**< table widget */
+#else
+    GtkTreeSelection *select;           /**< item selected */
+    GtkTreeView      *tree_view;        /**< Tree view */
+#endif
 	GtkWidget *menu;                    /**< context menu */
 	guint16 num_procs;                  /**< number of elements on procedures array */
 	error_procedure_t *procedures;      /**< the procedures array */
 }error_equiv_table;
 
+typedef struct _expert_tapdata_s {
+	GtkWidget	*win;
+	GtkWidget	*scrolled_window;
+	GtkCList	*table;
+	GtkWidget	*label;
+	GList		*all_events;
+	GList		*new_events;
+	guint32		disp_events;
+	guint32		chat_events;
+	guint32		note_events;
+	guint32		warn_events;
+	guint32		error_events;
+	int			severity_report_level;
+} expert_tapdata_t;
+
 /** Init an err table data structure.
  *
  * @param err the err table to init
@@ -90,3 +114,8 @@
  */
 void free_error_table_data(error_equiv_table *err);
 
+/* Function is located in expert_dlg.c */
+extern void expert_dlg_init_table(expert_tapdata_t * etd, GtkWidget *vbox);
+extern void expert_dlg_reset(void *tapdata);
+extern int expert_dlg_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pointer);
+extern void expert_dlg_draw(void *data);
expert_comp_dlg.c.diff (text/plain, 4.1 KB)
Index: expert_comp_dlg.c
===================================================================
--- expert_comp_dlg.c	(revision 18081)
+++ expert_comp_dlg.c	(working copy)
@@ -52,6 +52,7 @@
     GtkWidget *note_label;
     GtkWidget *warn_label;
     GtkWidget *error_label;
+    GtkWidget *all_label;
     error_equiv_table chat_table;
     error_equiv_table note_table;
     error_equiv_table warn_table;
@@ -119,11 +120,12 @@
     default:
         return 0; /* Don't draw */
     }
+
     return 1; /* Draw */
 }
 
 
-
+#if (GTK_MAJOR_VERSION < 2)
 static void
 error_draw(void *pss)
 {
@@ -134,6 +136,7 @@
     draw_error_table_data(&ss->note_table);
     draw_error_table_data(&ss->chat_table);
 }
+#endif
 
 void protect_thread_critical_region(void);
 void unprotect_thread_critical_region(void);
@@ -141,9 +144,11 @@
 win_destroy_cb(GtkWindow *win _U_, gpointer data)
 {
     expert_comp_dlg_t *ss=(expert_comp_dlg_t *)data;
+	expert_tapdata_t * etd=(expert_tapdata_t *)data;
 
     protect_thread_critical_region();
     remove_tap_listener(ss);
+    remove_tap_listener(etd);
     unprotect_thread_critical_region();
 
     free_error_table_data(&ss->error_table);
@@ -151,9 +156,25 @@
     free_error_table_data(&ss->note_table);
     free_error_table_data(&ss->chat_table);
     g_free(ss);
+
 }
 
+
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
 static void
+expert_dlg_destroy_cb(GtkWindow *win _U_, gpointer data)
+{
+	expert_tapdata_t *etd=(expert_tapdata_t *)data;
+
+	protect_thread_critical_region();
+	remove_tap_listener(etd);
+	unprotect_thread_critical_region();
+
+	g_free(etd);
+}
+
+static void
 expert_comp_init(const char *optarg, void* userdata _U_)
 {
     expert_comp_dlg_t *ss;
@@ -164,9 +185,20 @@
     GtkWidget *vbox;
     GtkWidget *bbox;
     GtkWidget *close_bt;
+	expert_tapdata_t * etd;
     
     ss=g_malloc(sizeof(expert_comp_dlg_t));
 
+	etd=g_malloc(sizeof(expert_tapdata_t));
+	etd->all_events = NULL;
+	etd->new_events = NULL;
+	etd->disp_events = 0;
+	etd->chat_events = 0;
+	etd->note_events = 0;
+	etd->warn_events = 0;
+	etd->error_events = 0;
+	etd->severity_report_level = PI_CHAT;
+
     ss->win=window_new(GTK_WINDOW_TOPLEVEL, "err");
     gtk_window_set_default_size(GTK_WINDOW(ss->win), 700, 300);
 
@@ -183,7 +215,7 @@
     ss->error_label = gtk_label_new("Errors: 0");
     gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), temp_page, ss->error_label);
 
-    /* We must display TOP LEVEL Widget before calling init_srt_table() */
+    /* We must display TOP LEVEL Widget before calling init_table() */
     gtk_widget_show_all(ss->win);
     init_error_table(&ss->error_table, 0, temp_page);
     /* Warnings */
@@ -201,9 +233,41 @@
     ss->chat_label = gtk_label_new("Chats: 0");
     gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), temp_page, ss->chat_label);
     init_error_table(&ss->chat_table, 0, temp_page);
+    /* Details */
+    temp_page = gtk_vbox_new(FALSE, 6);
+    ss->all_label = gtk_label_new("Details");
+    gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), temp_page, ss->all_label);
 
+	etd->label=gtk_label_new("Please wait ...");
+	gtk_misc_set_alignment(GTK_MISC(etd->label), 0.0, 0.5);
+
+    etd->win=ss->win;
+    expert_dlg_init_table(etd, temp_page);
+
+
+    /* Add tap listener functions for expert details, From expert_dlg.c*/
+
+	error_string=register_tap_listener("expert", etd, NULL /* fstring */,
+		expert_dlg_reset,
+		expert_dlg_packet,
+		expert_dlg_draw);
+	if(error_string){
+		simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
+		g_string_free(error_string, TRUE);
+		g_free(etd);
+		return;
+	}
+
+	SIGNAL_CONNECT(etd->win, "delete_event", window_delete_event_cb, NULL);
+	SIGNAL_CONNECT(etd->win, "destroy", expert_dlg_destroy_cb, etd);
+
     /* Register the tap listener */
+
+#if (GTK_MAJOR_VERSION < 2)
     error_string=register_tap_listener("expert", ss, filter, error_reset, error_packet, error_draw);
+#else
+    error_string=register_tap_listener("expert", ss, filter, error_reset, error_packet, NULL);
+#endif
     if(error_string){
         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
         g_string_free(error_string, TRUE);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.