ANNOUNCEMENT: Live Wireshark University & Allegro Packets online APAC Wireshark Training Session
April 17th, 2024 | 14:30-16:00 SGT (UTC+8) | Online

Ethereal-dev: [Ethereal-dev] Global Color Filters - Request for Comments

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Richard Urwin <richard@xxxxxxxxxxxxxxx>
Date: Sat, 8 Mar 2003 14:16:40 +0000
I have the first part of this as a first cut, and I would like any comments 
that people have.

I have built it on Linux(MDK 9.0); it should work on Windows, but I didn't 
bring my win32 platform home this weekend.

Is this an acceptable format for the patch?
Does my coding style need changing?

The global colorfilters file resides in the "data directory"; /usr/local/etc 
on my machine. This needs superuser permission to create, but that is 
probably as required. Is this the correct place? Maybe we need to create an 
Ethereal subdirectory? Is there a better standard directory?

I intend to provide functionality to write the global file, but for this pass 
you will need to copy a standard colorfilters file there by hand. There is a 
debug simple_dialog that tells you when it has found it, and when it hasn't. 
(That won't be in the final cut.)

When the color filters dialog is invoked, all of the filters, global and local 
are displayed. When these filters are saved they are all saved to the local 
file, and the global file is not reread. So, on the current session, the user 
can remove the global filters if they wish. This (emergent) behavior seems to 
work well. What do you think? The next time Ethereal is started the global 
filters will again operate, giving the possibility of a difference in 
behavior that the user is not expecting. Is this a problem?


-- 
Richard Urwin
diff -ruX list ethereal-0.9.9/epan/filesystem.c ethereal/epan/filesystem.c
--- ethereal-0.9.9/epan/filesystem.c	2002-08-29 01:40:07.000000000 +0100
+++ ethereal/epan/filesystem.c	2003-03-07 23:13:54.000000000 +0000
@@ -580,3 +580,25 @@
 
 	return path;
 }
+
+/*
+ * Construct the path name of a global configuration file, given the
+ * file name.
+ *
+ */
+char *
+get_datafile_path(const char *filename, gboolean for_writing
+#ifndef WIN32
+	_U_
+#endif
+)
+{
+	char *path;
+
+	path = (gchar *) g_malloc(strlen(get_datafile_dir()) +
+	    strlen(filename) + 2);
+	sprintf(path, "%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(),
+	    filename);
+
+	return path;
+}
diff -ruX list ethereal-0.9.9/epan/filesystem.h ethereal/epan/filesystem.h
--- ethereal-0.9.9/epan/filesystem.h	2002-08-29 01:40:07.000000000 +0100
+++ ethereal/epan/filesystem.h	2003-03-08 12:52:30.000000000 +0000
@@ -77,6 +77,15 @@
 const char *get_datafile_dir(void);
 
 /*
+ * Construct the path name of a global configuration file, given the
+ * file name.
+ *
+ * "for_writing" is for compatibility with get_persconffile_path(),
+ * and is currently not used
+ */
+char *get_datafile_path(const char *filename, gboolean for_writing);
+
+/*
  * Get the directory in which files that, at least on UNIX, are
  * system files (such as "/etc/ethers") are stored; on Windows,
  * there's no "/etc" directory, so we get them from the Ethereal
diff -ruX list ethereal-0.9.9/gtk/color_dlg.c ethereal/gtk/color_dlg.c
--- ethereal-0.9.9/gtk/color_dlg.c	2003-01-18 02:07:20.000000000 +0000
+++ ethereal/gtk/color_dlg.c	2003-03-03 21:34:32.000000000 +0000
@@ -38,6 +38,7 @@
 #include "color_dlg.h"
 #include "color_utils.h"
 #include "file.h"
+#include "file_dlg.h"
 #include <epan/dfilter/dfilter.h>
 #include "simple_dialog.h"
 #include "dlg_utils.h"
@@ -152,6 +153,7 @@
   GtkWidget *color_ok;
   GtkWidget *color_apply;
   GtkWidget *color_save;
+  GtkWidget *color_saveas;
   GtkWidget *color_cancel;
 
 #if GTK_MAJOR_VERSION >= 2
@@ -385,6 +387,17 @@
   gtk_tooltips_set_tip(tooltips, color_save, ("Save all filters to disk"), NULL);
 
 #if GTK_MAJOR_VERSION < 2
+  color_saveas = gtk_button_new_with_label (("SaveAs"));
+#else
+  color_saveas = gtk_button_new_from_stock(GTK_STOCK_SAVE);
+#endif
+  gtk_widget_ref(color_saveas);
+  OBJECT_SET_DATA_FULL(color_win, "color_saveas", color_saveas, gtk_widget_unref);
+  gtk_widget_show(color_saveas);
+  gtk_box_pack_start(GTK_BOX (button_ok_hbox), color_saveas, FALSE, FALSE, 5);
+  gtk_tooltips_set_tip(tooltips, color_saveas, ("Save all filters to specified file"), NULL);
+
+#if GTK_MAJOR_VERSION < 2
   color_cancel = gtk_button_new_with_label (("Cancel"));
 #else
   color_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
@@ -419,6 +432,7 @@
   OBJECT_SET_DATA(color_delete, COLOR_FILTERS_CL, color_filters);
   SIGNAL_CONNECT(color_delete, "clicked", color_delete_cb, NULL);
   SIGNAL_CONNECT(color_save, "clicked", color_save_cb, NULL);
+  SIGNAL_CONNECT(color_saveas, "clicked", file_color_save_as_cmd_cb, NULL);
   SIGNAL_CONNECT(color_ok, "clicked", color_ok_cb, NULL);
   SIGNAL_CONNECT(color_apply, "clicked", color_apply_cb, NULL);
   SIGNAL_CONNECT(color_cancel, "clicked", color_cancel_cb, NULL);
diff -ruX list ethereal-0.9.9/gtk/color_filters.c ethereal/gtk/color_filters.c
--- ethereal-0.9.9/gtk/color_filters.c	2003-01-08 01:59:42.000000000 +0000
+++ ethereal/gtk/color_filters.c	2003-03-08 12:46:27.000000000 +0000
@@ -45,6 +45,7 @@
 #include "gtkglobals.h"
 
 static gboolean read_filters(void);
+static gboolean read_global_filters(void);
 
 GSList *filter_list;
 
@@ -53,6 +54,7 @@
 colfilter_init(void)
 {
 	read_filters();
+	read_global_filters();
 }
 
 /* Create a new filter */
@@ -108,9 +110,9 @@
 }
 
 
-/* read filters from the file */
+/* read filters from the given file */
 static gboolean
-read_filters(void)
+read_filters_file(gpointer file_arg)
 {
 	/* TODO: Lots more syntax checking on the file */
 	/* I hate these fixed length names! TODO: make more dynamic */
@@ -121,23 +123,9 @@
 	guint16 fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
 	GdkColor fg_color, bg_color;
 	color_filter_t *colorf;
-	gchar *path;
-	FILE *f;
+//	gchar *path;
 	dfilter_t *temp_dfilter;
-
-	/* decide what file to open (from dfilter code) */
-	path = get_persconffile_path("colorfilters", FALSE);
-	if ((f = fopen(path, "r")) == NULL) {
-		if (errno != ENOENT) {
-			simple_dialog(ESD_TYPE_CRIT, NULL,
-			    "Could not open filter file\n\"%s\": %s.", path,
-			    strerror(errno));
-		}
-		g_free((gchar *)path);
-		return FALSE;
-	}
-	g_free((gchar *)path);
-	path = NULL;
+	FILE *f = file_arg;
 
 	do {
 		if (fgets(buf,sizeof buf, f) == NULL)
@@ -196,6 +184,63 @@
 	return TRUE;
 }
 
+/* read filters from the filter file */
+static gboolean
+read_filters(void)
+{
+	gchar *path;
+	FILE *f;
+
+	/* decide what file to open (from dfilter code) */
+	path = get_persconffile_path("colorfilters", FALSE);
+	if ((f = fopen(path, "r")) == NULL) {
+		if (errno != ENOENT) {
+			simple_dialog(ESD_TYPE_CRIT, NULL,
+			    "Could not open filter file\n\"%s\": %s.", path,
+			    strerror(errno));
+		}
+		g_free((gchar *)path);
+		return FALSE;
+	}
+	g_free((gchar *)path);
+	path = NULL;
+
+	return read_filters_file(f);
+}
+
+/* read filters from the filter file */
+static gboolean
+read_global_filters(void)
+{
+	gchar *path;
+	FILE *f;
+
+	/* decide what file to open (from dfilter code) */
+	path = get_datafile_path("colorfilters", FALSE);
+	if ((f = fopen(path, "r")) == NULL) {
+		if (errno != ENOENT) {
+			simple_dialog(ESD_TYPE_CRIT, NULL,
+			    "Could not open global filter file\n\"%s\": %s.", path,
+			    strerror(errno));
+		}
+		else
+			simple_dialog(ESD_TYPE_CRIT, NULL,
+			    "Could not open global filter file\n\"%s\": %s.", path,
+			    strerror(errno));
+
+		g_free((gchar *)path);
+		return FALSE;
+	}
+	else
+		simple_dialog(ESD_TYPE_CRIT, NULL,
+			    "Opened global filter file\n\"%s\".", path);
+
+	g_free((gchar *)path);
+	path = NULL;
+
+	return read_filters_file(f);
+}
+
 static void
 write_filter(gpointer filter_arg, gpointer file_arg)
 {
@@ -213,6 +258,18 @@
 	    colorf->fg_color.blue);
 }
 
+/* save filters in given file */
+gboolean
+write_filters_file(gpointer file_arg)
+{
+	FILE *f = file_arg;
+
+        fprintf(f,"# DO NOT EDIT THIS FILE!  It was created by Ethereal\n");
+        g_slist_foreach(filter_list, write_filter, f);
+	fclose(f);
+	return TRUE;
+}
+
 /* save filters in filter file */
 gboolean
 write_filters(void)
@@ -238,8 +295,6 @@
 		    path, strerror(errno));
 		return FALSE;
 	}
-        fprintf(f,"# DO NOT EDIT THIS FILE!  It was created by Ethereal\n");
-        g_slist_foreach(filter_list, write_filter, f);
-	fclose(f);
-	return TRUE;
+        
+	return write_filters_file(f);
 }
diff -ruX list ethereal-0.9.9/gtk/file_dlg.c ethereal/gtk/file_dlg.c
--- ethereal-0.9.9/gtk/file_dlg.c	2003-01-18 02:07:21.000000000 +0000
+++ ethereal/gtk/file_dlg.c	2003-03-03 21:49:42.000000000 +0000
@@ -48,6 +48,8 @@
 static void select_file_type_cb(GtkWidget *w, gpointer data);
 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
 static void file_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
+static void file_color_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
+static void file_color_save_as_destroy_cb(GtkWidget *win, gpointer user_data);
 
 #define E_FILE_M_RESOLVE_KEY	  "file_dlg_mac_resolve_key"
 #define E_FILE_N_RESOLVE_KEY	  "file_dlg_network_resolve_key"
@@ -659,3 +661,189 @@
      we should free up our copy. */
   g_free(filename);
 }
+
+/******************** Color Filters *********************************/
+/*
+ * Keep a static pointer to the current "Save Capture File As" window, if
+ * any, so that if somebody tries to do "File:Save" or "File:Save As"
+ * while there's already a "Save Capture File As" window up, we just pop
+ * up the existing one, rather than creating a new one.
+ */
+static GtkWidget *file_color_save_as_w;
+
+void
+file_color_save_as_cmd_cb(GtkWidget *w _U_, gpointer data _U_)
+{
+  GtkWidget *ok_bt, *main_vb, *ft_hb, *ft_lb;
+  GtkWidget *ft_menu, *ft_menu_item;
+
+  if (file_color_save_as_w != NULL) {
+    /* There's already an "Save Capture File As" dialog box; reactivate it. */
+    reactivate_window(file_color_save_as_w);
+    return;
+  }
+
+  /* Default to saving all packets, in the file's current format. */
+  filtered = FALSE;
+  marked   = FALSE;
+  filetype = cfile.cd_t;
+
+  file_color_save_as_w = gtk_file_selection_new ("Ethereal: Save Color Filters As");
+  SIGNAL_CONNECT(file_color_save_as_w, "destroy", file_color_save_as_destroy_cb, NULL);
+
+  /* If we've opened a file, start out by showing the files in the directory
+     in which that file resided. */
+  if (last_open_dir)
+    gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_save_as_w), last_open_dir);
+
+  /* Connect the ok_button to file_save_as_ok_cb function and pass along a
+     pointer to the file selection box widget */
+  ok_bt = GTK_FILE_SELECTION (file_color_save_as_w)->ok_button;
+  SIGNAL_CONNECT(ok_bt, "clicked", file_color_save_as_ok_cb, file_color_save_as_w);
+
+  /* Container for each row of widgets */
+  main_vb = gtk_vbox_new(FALSE, 3);
+  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+  gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(file_color_save_as_w)->action_area),
+    main_vb, FALSE, FALSE, 0);
+  gtk_widget_show(main_vb);
+
+  /*
+   * XXX - should this be sensitive only if the current display filter
+   * has rejected some packets, so that not all packets are currently
+   * being displayed, and if it has accepted some packets, so that some
+   * packets are currently being displayed?
+   *
+   * I'd say "no", as that complicates the UI code, and as one could,
+   * I guess, argue that the user may want to "save all the displayed
+   * packets" even if there aren't any, i.e. save an empty file.
+   */
+//  filter_cb = gtk_check_button_new_with_label("Save only packets currently being displayed");
+//  gtk_container_add(GTK_CONTAINER(main_vb), filter_cb);
+//  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_cb), FALSE);
+//  SIGNAL_CONNECT(filter_cb, "toggled", toggle_filtered_cb, NULL);
+//  gtk_widget_set_sensitive(filter_cb, can_save_with_wiretap(filetype));
+//  gtk_widget_show(filter_cb);
+
+  /*
+   * The argument above could, I guess, be applied to the marked packets,
+   * except that you can't easily tell whether there are any marked
+   * packets, so I could imagine users doing "Save only marked packets"
+   * when there aren't any marked packets, not knowing that they'd
+   * failed to mark them, so I'm more inclined to have the "Save only
+   * marked packets" toggle button enabled only if there are marked
+   * packets to save.
+   */
+//  mark_cb = gtk_check_button_new_with_label("Save only marked packets");
+//  gtk_container_add(GTK_CONTAINER(main_vb), mark_cb);
+//  marked = FALSE;
+//  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(mark_cb), FALSE);
+//  SIGNAL_CONNECT(mark_cb, "toggled", toggle_marked_cb, NULL);
+//  gtk_widget_show(mark_cb);
+
+  /* File type row */
+  ft_hb = gtk_hbox_new(FALSE, 3);
+  gtk_container_add(GTK_CONTAINER(main_vb), ft_hb);
+  gtk_widget_show(ft_hb);
+
+  ft_lb = gtk_label_new("File type:   Color Filter");
+  gtk_box_pack_start(GTK_BOX(ft_hb), ft_lb, FALSE, FALSE, 0);
+  gtk_widget_show(ft_lb);
+
+// ****** We only have one file type - dont need to do this
+//  ft_om = gtk_option_menu_new();
+
+  /* Generate the list of file types we can save. */
+//  set_file_type_list(ft_om);
+// *************************************************************************
+// inlined from set_file_type_list
+//
+//  ft_menu = gtk_menu_new();
+//
+//  ft_menu_item = gtk_menu_item_new_with_label("color filter");
+//  SIGNAL_CONNECT(ft_menu_item, "activate", select_file_type_cb,
+//                   GINT_TO_POINTER(0));
+//  gtk_menu_append(GTK_MENU(ft_menu), ft_menu_item);
+//  gtk_widget_show(ft_menu_item);
+//
+//  gtk_option_menu_set_menu(GTK_OPTION_MENU(ft_om), ft_menu);
+//  gtk_option_menu_set_history(GTK_OPTION_MENU(ft_om), 0);
+
+
+// ***************************************************************************88
+  gtk_box_pack_start(GTK_BOX(ft_hb), ft_om, FALSE, FALSE, 0);
+  gtk_widget_show(ft_om);
+
+  /*
+   * Set the sensitivity of the "Save only marked packets" toggle
+   * button
+   *
+   * This has to be done after we create the file type menu option,
+   * as the routine that sets it also sets that menu.
+   */
+//  file_set_save_marked_sensitive();
+
+  /* Connect the cancel_button to destroy the widget */
+  SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(file_color_save_as_w)->cancel_button,
+                        "clicked", (GtkSignalFunc)gtk_widget_destroy,
+                        file_color_save_as_w);
+
+  /* Catch the "key_press_event" signal in the window, so that we can catch
+     the ESC key being pressed and act as if the "Cancel" button had
+     been selected. */
+  dlg_set_cancel(file_color_save_as_w, GTK_FILE_SELECTION(file_color_save_as_w)->cancel_button);
+
+  gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_color_save_as_w), "");
+
+  gtk_widget_show(file_color_save_as_w);
+}
+
+static void
+file_color_save_as_ok_cb(GtkWidget *w _U_, GtkFileSelection *fs) {
+  gchar	*cf_name;
+  gchar	*dirname;
+
+  cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
+
+  /* Perhaps the user specified a directory instead of a file.
+     Check whether they did. */
+  if (test_for_directory(cf_name) == EISDIR) {
+        /* It's a directory - set the file selection box to display that
+           directory, and leave the selection box displayed. */
+        set_last_open_dir(cf_name);
+        g_free(cf_name);
+        gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
+        return;
+  }
+
+  /* Write out the packets (all, or only the ones that are currently
+     displayed or marked) to the file with the specified name. */
+
+// *****************This does the save *****************************
+//  if (! save_cap_file(cf_name, &cfile, filtered, marked, filetype)) {
+//    /* The write failed; don't dismiss the open dialog box,
+//       just leave it around so that the user can, after they
+//       dismiss the alert box popped up for the error, try again. */
+//    g_free(cf_name);
+//    return;
+//  }
+
+  /* The write succeeded; get rid of the file selection box. */
+  gtk_widget_hide(GTK_WIDGET (fs));
+  gtk_widget_destroy(GTK_WIDGET (fs));
+
+  /* Save the directory name for future file dialogs. */
+//  ***************** This would mess up the last capture file directory setting **********
+//  ***********We need our own setting
+//  dirname = get_dirname(cf_name);  /* Overwrites cf_name */
+//  set_last_open_dir(dirname);
+  g_free(cf_name);
+}
+
+static void
+file_color_save_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+  file_color_save_as_w = NULL;
+}
+
+
diff -ruX list ethereal-0.9.9/gtk/file_dlg.h ethereal/gtk/file_dlg.h
--- ethereal-0.9.9/gtk/file_dlg.h	2002-08-29 01:40:08.000000000 +0100
+++ ethereal/gtk/file_dlg.h	2003-03-03 21:33:32.000000000 +0000
@@ -31,6 +31,8 @@
 void file_close_cmd_cb(GtkWidget *, gpointer);
 void file_reload_cmd_cb(GtkWidget *, gpointer);
 
+void file_color_save_as_cmd_cb(GtkWidget *, gpointer);
+
 /*
  * Set the "Save only marked packets" toggle button as appropriate for
  * the current output file type and count of marked packets.