Ethereal-dev: [Ethereal-dev] Extended filtering (patch)

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

From: Jirka Novak <j.novak@xxxxxxxxxxxx>
Date: Mon, 17 Dec 2001 13:23:34 +0100
Hallo,

I made Filter menu a little better and I would like to publish it to CVS tree. I add new "prepare" line at bottom of main window. There you can prepare filter expression by picking parts from packet list and combining it with prepare line (and, or, not, and not, ...). Next you can use it as usual. It's possible to load saved filter to normal filter line or to prepare line too.

							Jirka Novak
diff -c -r ethereal-2001-12-16/gtk/file_dlg.c ethereal-0.8.20/gtk/file_dlg.c
*** ethereal-2001-12-16/gtk/file_dlg.c	Thu Dec  6 04:09:28 2001
--- ethereal-0.8.20/gtk/file_dlg.c	Mon Dec 17 12:45:32 2001
***************
*** 83,89 ****
    static construct_args_t args = {
    	"Ethereal: Read Filter",
    	FALSE,
!   	FALSE
    };
  
    if (file_open_w != NULL) {
--- 83,90 ----
    static construct_args_t args = {
    	"Ethereal: Read Filter",
    	FALSE,
!   	FALSE,
! 	TRUE
    };
  
    if (file_open_w != NULL) {
diff -c -r ethereal-2001-12-16/gtk/filter_prefs.c ethereal-0.8.20/gtk/filter_prefs.c
*** ethereal-2001-12-16/gtk/filter_prefs.c	Wed Oct 24 08:13:06 2001
--- ethereal-0.8.20/gtk/filter_prefs.c	Mon Dec 17 12:45:32 2001
***************
*** 44,49 ****
--- 44,50 ----
  #include "dfilter_expr_dlg.h"
  
  #define E_FILT_PARENT_FILTER_TE_KEY "filter_parent_filter_te"
+ #define E_FILT_PARENT_PREPARE_TE_KEY "filter_parent_prepare_te"
  #define E_FILT_CONSTRUCT_ARGS_KEY   "filter_construct_args"
  #define E_FILT_LIST_ITEM_MODEL_KEY  "filter_list_item_model"
  #define E_FILT_LBL_KEY              "filter_label"
***************
*** 62,72 ****
  } filter_cb_data;
  
  static GtkWidget *filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
!     filter_list_type_t list, construct_args_t *construct_args);
  static void filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg);
  static void filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer dummy);
  static void filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy);
! static void filter_apply(GtkWidget *main_w);
  static void filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w);
  static void filter_dlg_close_cb(GtkWidget *close_bt, gpointer parent_w);
  static void filter_dlg_destroy(GtkWidget *win, gpointer data);
--- 63,74 ----
  } filter_cb_data;
  
  static GtkWidget *filter_dialog_new(GtkWidget *caller, GtkWidget *filter_te,
!     GtkWidget *prepare_te, filter_list_type_t list,
!     construct_args_t *construct_args);
  static void filter_dlg_dclick(GtkWidget *dummy, gpointer main_w_arg);
  static void filter_dlg_ok_cb(GtkWidget *ok_bt, gpointer dummy);
  static void filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy);
! static void filter_apply(GtkWidget *main_w, gboolean filter);
  static void filter_dlg_save_cb(GtkWidget *save_bt, gpointer parent_w);
  static void filter_dlg_close_cb(GtkWidget *close_bt, gpointer parent_w);
  static void filter_dlg_destroy(GtkWidget *win, gpointer data);
***************
*** 113,124 ****
  	GtkWidget *caller = gtk_widget_get_toplevel(w);
  	GtkWidget *filter_browse_w;
  	GtkWidget *parent_filter_te;
  	/* No Apply button, and "OK" just sets our text widget, it doesn't
  	   activate it (i.e., it doesn't cause us to try to open the file). */
  	static construct_args_t args = {
  		"Ethereal: Capture Filter",
  		FALSE,
! 		FALSE
  	};
  
  	/* Has a filter dialog box already been opened for that top-level
--- 115,128 ----
  	GtkWidget *caller = gtk_widget_get_toplevel(w);
  	GtkWidget *filter_browse_w;
  	GtkWidget *parent_filter_te;
+ 	GtkWidget *parent_prepare_te;
  	/* No Apply button, and "OK" just sets our text widget, it doesn't
  	   activate it (i.e., it doesn't cause us to try to open the file). */
  	static construct_args_t args = {
  		"Ethereal: Capture Filter",
  		FALSE,
! 		FALSE,
! 		TRUE
  	};
  
  	/* Has a filter dialog box already been opened for that top-level
***************
*** 134,143 ****
  
  	/* No.  Get the text entry attached to the button. */
  	parent_filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
  
  	/* Now create a new dialog, without an "Add Expression..." button. */
  	filter_browse_w = filter_dialog_new(caller, parent_filter_te,
! 	    CFILTER_LIST, &args);
  
  	/* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
  	   our caller. */
--- 138,148 ----
  
  	/* No.  Get the text entry attached to the button. */
  	parent_filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
+ 	parent_prepare_te = gtk_object_get_data(GTK_OBJECT(w), E_PREP_TE_PTR_KEY);
  
  	/* Now create a new dialog, without an "Add Expression..." button. */
  	filter_browse_w = filter_dialog_new(caller, parent_filter_te,
! 	    parent_prepare_te, CFILTER_LIST, &args);
  
  	/* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
  	   our caller. */
***************
*** 173,178 ****
--- 178,184 ----
  	GtkWidget *caller = gtk_widget_get_toplevel(w);
  	GtkWidget *filter_browse_w;
  	GtkWidget *parent_filter_te;
+ 	GtkWidget *parent_prepare_te;
  
  	/* Has a filter dialog box already been opened for that top-level
  	   widget? */
***************
*** 187,197 ****
  
  	/* No.  Get the text entry attached to the button. */
  	parent_filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
  
  	/* Now create a new dialog, possibly with an "Apply" button, and
  	   definitely with an "Add Expression..." button. */
  	filter_browse_w = filter_dialog_new(caller, parent_filter_te,
! 	    DFILTER_LIST, construct_args);
  
  	/* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
  	   our caller. */
--- 193,204 ----
  
  	/* No.  Get the text entry attached to the button. */
  	parent_filter_te = gtk_object_get_data(GTK_OBJECT(w), E_FILT_TE_PTR_KEY);
+ 	parent_prepare_te = gtk_object_get_data(GTK_OBJECT(w), E_PREP_TE_PTR_KEY);
  
  	/* Now create a new dialog, possibly with an "Apply" button, and
  	   definitely with an "Add Expression..." button. */
  	filter_browse_w = filter_dialog_new(caller, parent_filter_te,
! 	    parent_prepare_te, DFILTER_LIST, construct_args);
  
  	/* Set the E_FILT_CALLER_PTR_KEY for the new dialog to point to
  	   our caller. */
***************
*** 216,222 ****
  	static construct_args_t args = {
  		"Ethereal: Edit Capture Filter List",
  		FALSE,
! 		FALSE
  	};
  
  	/* Has a filter dialog box already been opened for editing
--- 223,230 ----
  	static construct_args_t args = {
  		"Ethereal: Edit Capture Filter List",
  		FALSE,
! 		FALSE,
! 		TRUE
  	};
  
  	/* Has a filter dialog box already been opened for editing
***************
*** 232,238 ****
  	 * a button next to some text entry field, so don't associate it
  	 * with a text entry field.
  	 */
! 	global_cfilter_w = filter_dialog_new(NULL, NULL, CFILTER_LIST, &args);
  }
  #endif
  
--- 240,246 ----
  	 * a button next to some text entry field, so don't associate it
  	 * with a text entry field.
  	 */
! 	global_cfilter_w = filter_dialog_new(NULL, NULL, NULL, CFILTER_LIST, &args);
  }
  #endif
  
***************
*** 248,254 ****
  	static construct_args_t args = {
  		"Ethereal: Edit Display Filter List",
  		FALSE,
! 		FALSE
  	};
  
  	/* Has a filter dialog box already been opened for editing
--- 256,263 ----
  	static construct_args_t args = {
  		"Ethereal: Edit Display Filter List",
  		FALSE,
! 		FALSE,
! 		TRUE
  	};
  
  	/* Has a filter dialog box already been opened for editing
***************
*** 264,270 ****
  	 * a button next to some text entry field, so don't associate it
  	 * with a text entry field.
  	 */
! 	global_dfilter_w = filter_dialog_new(NULL, NULL, DFILTER_LIST, &args);
  }
  
  /* List of capture filter dialogs, so that if the list of filters changes
--- 273,279 ----
  	 * a button next to some text entry field, so don't associate it
  	 * with a text entry field.
  	 */
! 	global_dfilter_w = filter_dialog_new(NULL, NULL, NULL, DFILTER_LIST, &args);
  }
  
  /* List of capture filter dialogs, so that if the list of filters changes
***************
*** 323,328 ****
--- 332,338 ----
  
  static GtkWidget *
  filter_dialog_new(GtkWidget *caller, GtkWidget *parent_filter_te,
+     GtkWidget *parent_prepare_te,
      filter_list_type_t list, construct_args_t *construct_args)
  {
  	GtkWidget	*main_w,		/* main window */
***************
*** 353,359 ****
  	GtkWidget	*l_select = NULL;
  	GList		*fl_entry;
  	filter_def	*filt;
! 	gchar		*filter_te_str = NULL;
  	GList		**filter_dialogs;
  	static filter_list_type_t cfilter_list = CFILTER_LIST;
  	static filter_list_type_t dfilter_list = DFILTER_LIST;
--- 363,369 ----
  	GtkWidget	*l_select = NULL;
  	GList		*fl_entry;
  	filter_def	*filt;
! 	gchar		*te_str = NULL;
  	GList		**filter_dialogs;
  	static filter_list_type_t cfilter_list = CFILTER_LIST;
  	static filter_list_type_t dfilter_list = DFILTER_LIST;
***************
*** 396,403 ****
  	gtk_widget_show(main_vb);
  
  	/* Make sure everything is set up */  
! 	if (parent_filter_te)
! 		filter_te_str = gtk_entry_get_text(GTK_ENTRY(parent_filter_te));
  
  	/* Container for each row of widgets */
  	filter_pg = gtk_vbox_new(FALSE, 5);
--- 406,419 ----
  	gtk_widget_show(main_vb);
  
  	/* Make sure everything is set up */  
! 	if (construct_args->from_filter)
! 	{ if (parent_filter_te)
! 		te_str = gtk_entry_get_text(GTK_ENTRY(parent_filter_te));
! 	}
! 	else
! 	{ if (parent_prepare_te)
! 		te_str = gtk_entry_get_text(GTK_ENTRY(parent_prepare_te));
! 	}
  
  	/* Container for each row of widgets */
  	filter_pg = gtk_vbox_new(FALSE, 5);
***************
*** 499,506 ****
  		gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LIST_ITEM_MODEL_KEY,
  		    fl_entry);
  
! 		if (filter_te_str && filt->strval) {
! 			if (strcmp(filter_te_str, filt->strval) == 0)
  				l_select = nl_item;
  		}
  
--- 515,522 ----
  		gtk_object_set_data(GTK_OBJECT(nl_item), E_FILT_LIST_ITEM_MODEL_KEY,
  		    fl_entry);
  
! 		if (te_str && filt->strval) {
! 			if (strcmp(te_str, filt->strval) == 0)
  				l_select = nl_item;
  		}
  
***************
*** 542,555 ****
  
  	if (l_select) {
  		gtk_list_select_child(GTK_LIST(filter_l), l_select);
! 	} else if (filter_te_str && filter_te_str[0]) {
  		gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
! 		gtk_entry_set_text(GTK_ENTRY(filter_te), filter_te_str);
  	}
  
  	gtk_box_pack_start(GTK_BOX(main_vb), filter_pg, TRUE, TRUE, 0);
  	gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY,
  	    parent_filter_te);
  
  	bbox = gtk_hbutton_box_new();
  	gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
--- 558,573 ----
  
  	if (l_select) {
  		gtk_list_select_child(GTK_LIST(filter_l), l_select);
! 	} else if (te_str && te_str[0]) {
  		gtk_entry_set_text(GTK_ENTRY(name_te), "New filter");
! 		gtk_entry_set_text(GTK_ENTRY(filter_te), te_str);
  	}
  
  	gtk_box_pack_start(GTK_BOX(main_vb), filter_pg, TRUE, TRUE, 0);
  	gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY,
  	    parent_filter_te);
+ 	gtk_object_set_data(GTK_OBJECT(main_w), E_FILT_PARENT_PREPARE_TE_KEY,
+ 	    parent_prepare_te);
  
  	bbox = gtk_hbutton_box_new();
  	gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
***************
*** 582,588 ****
  	if (construct_args->wants_apply_button) {
  		apply_bt = gtk_button_new_with_label ("Apply");
  		gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
! 		    GTK_SIGNAL_FUNC(filter_dlg_apply_cb), NULL);
  		GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
  		gtk_box_pack_start(GTK_BOX(bbox), apply_bt, TRUE, TRUE, 0);
  		gtk_widget_show(apply_bt);
--- 600,615 ----
  	if (construct_args->wants_apply_button) {
  		apply_bt = gtk_button_new_with_label ("Apply");
  		gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
! 		    GTK_SIGNAL_FUNC(filter_dlg_apply_cb), (gpointer)0);
! 		GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
! 		gtk_box_pack_start(GTK_BOX(bbox), apply_bt, TRUE, TRUE, 0);
! 		gtk_widget_show(apply_bt);
! 	}
! 
! 	if (construct_args->wants_apply_button) {
! 		apply_bt = gtk_button_new_with_label ("To prepare");
! 		gtk_signal_connect(GTK_OBJECT(apply_bt), "clicked",
! 		    GTK_SIGNAL_FUNC(filter_dlg_apply_cb), (gpointer)1);
  		GTK_WIDGET_SET_FLAGS(apply_bt, GTK_CAN_DEFAULT);
  		gtk_box_pack_start(GTK_BOX(bbox), apply_bt, TRUE, TRUE, 0);
  		gtk_widget_show(apply_bt);
***************
*** 661,667 ****
  	/*
  	 * Apply the filter.
  	 */
! 	filter_apply(main_w);
  
  	/*
  	 * Now dismiss the dialog box.
--- 688,694 ----
  	/*
  	 * Apply the filter.
  	 */
! 	filter_apply(main_w,TRUE);
  
  	/*
  	 * Now dismiss the dialog box.
***************
*** 672,691 ****
  static void
  filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy)
  {
! 	filter_apply(gtk_widget_get_toplevel(apply_bt));
  }
  
  static void
! filter_apply(GtkWidget *main_w)
  {
  	construct_args_t *construct_args =
  	    gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_CONSTRUCT_ARGS_KEY);
  	GtkWidget  *parent_filter_te =
  	    gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY);
  	GtkWidget  *filter_te;
  	gchar      *filter_string;
  	
! 	if (parent_filter_te != NULL) {
  		/*
  		 * We have a text entry widget associated with this dialog
  		 * box; put the filter in our text entry widget into that
--- 699,723 ----
  static void
  filter_dlg_apply_cb(GtkWidget *apply_bt, gpointer dummy)
  {
! 	filter_apply(gtk_widget_get_toplevel(apply_bt),(gboolean)dummy);
  }
  
  static void
! filter_apply(GtkWidget *main_w, gboolean filter)
  {
  	construct_args_t *construct_args =
  	    gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_CONSTRUCT_ARGS_KEY);
  	GtkWidget  *parent_filter_te =
  	    gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_PARENT_FILTER_TE_KEY);
+ 	GtkWidget  *parent_prepare_te =
+ 	    gtk_object_get_data(GTK_OBJECT(main_w), E_FILT_PARENT_PREPARE_TE_KEY);
  	GtkWidget  *filter_te;
+ 	GtkWidget  *prepare_te;
  	gchar      *filter_string;
+ 	gchar      *prepare_string;
  	
! 	if (((parent_filter_te != NULL) && (!filter)) ||
! 	    ((parent_prepare_te != NULL) && (filter))) {
  		/*
  		 * We have a text entry widget associated with this dialog
  		 * box; put the filter in our text entry widget into that
***************
*** 696,706 ****
  		filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
  		    E_FILT_FILTER_TE_KEY);
  		filter_string = gtk_entry_get_text(GTK_ENTRY(filter_te));
! 		gtk_entry_set_text(GTK_ENTRY(parent_filter_te), filter_string);
! 		if (construct_args->activate_on_ok) {
! 			gtk_signal_emit_by_name(GTK_OBJECT(parent_filter_te),
! 			    "activate");
  		}
  	}
  }
  
--- 728,742 ----
  		filter_te = gtk_object_get_data(GTK_OBJECT(main_w),
  		    E_FILT_FILTER_TE_KEY);
  		filter_string = gtk_entry_get_text(GTK_ENTRY(filter_te));
! 		if (!filter)
! 		{ gtk_entry_set_text(GTK_ENTRY(parent_filter_te), filter_string);
! 		  if (construct_args->activate_on_ok) {
! 			  gtk_signal_emit_by_name(GTK_OBJECT(parent_filter_te),
! 			      "activate");
! 		  }
  		}
+ 		else
+ 		{ gtk_entry_set_text(GTK_ENTRY(parent_prepare_te), filter_string); }
  	}
  }
  
diff -c -r ethereal-2001-12-16/gtk/filter_prefs.h ethereal-0.8.20/gtk/filter_prefs.h
*** ethereal-2001-12-16/gtk/filter_prefs.h	Fri Feb 23 06:54:27 2001
--- ethereal-0.8.20/gtk/filter_prefs.h	Mon Dec 17 12:45:32 2001
***************
*** 37,42 ****
--- 37,43 ----
  	gboolean wants_apply_button;	/* if it should have an Apply button */
  	gboolean activate_on_ok;	/* if parent text widget should be
  					   activated on "Ok" or "Apply" */
+ 	gboolean from_filter;		/* Take from filter */
  } construct_args_t;
  
  void capture_filter_construct_cb(GtkWidget *w, gpointer user_data);
***************
*** 45,50 ****
--- 46,52 ----
  void dfilter_dialog_cb(GtkWidget *w);
  
  #define E_FILT_TE_PTR_KEY	"filter_te_ptr"
+ #define E_PREP_TE_PTR_KEY	"prepare_te_ptr"
  #define E_FILT_CALLER_PTR_KEY	"filter_caller_ptr"
  #define E_FILT_DIALOG_PTR_KEY	"filter_dialog_ptr"
  
diff -c -r ethereal-2001-12-16/gtk/find_dlg.c ethereal-0.8.20/gtk/find_dlg.c
*** ethereal-2001-12-16/gtk/find_dlg.c	Thu Feb  1 21:21:21 2001
--- ethereal-0.8.20/gtk/find_dlg.c	Mon Dec 17 12:45:32 2001
***************
*** 79,85 ****
    static construct_args_t args = {
    	"Ethereal: Search Filter",
    	FALSE,
!   	TRUE
    };
  
    if (find_frame_w != NULL) {
--- 79,86 ----
    static construct_args_t args = {
    	"Ethereal: Search Filter",
    	FALSE,
!   	TRUE,
! 	TRUE
    };
  
    if (find_frame_w != NULL) {
diff -c -r ethereal-2001-12-16/gtk/keys.h ethereal-0.8.20/gtk/keys.h
*** ethereal-2001-12-16/gtk/keys.h	Sun Aug 20 23:55:57 2000
--- ethereal-0.8.20/gtk/keys.h	Mon Dec 17 12:45:32 2001
***************
*** 32,37 ****
--- 32,40 ----
  #define E_DFILTER_CM_KEY          "display_filter_combo"
  #define E_DFILTER_FL_KEY          "display_filter_list"
  #define E_RFILTER_TE_KEY          "read_filter_te"
+ #define E_DPREPARE_TE_KEY         "display_prepare_entry"
+ #define E_DPREPARE_CM_KEY         "display_prepare_combo"
+ #define E_DPREPARE_FL_KEY         "display_prepare_list"
  
  #define PRINT_CMD_LB_KEY          "printer_command_label"
  #define PRINT_CMD_TE_KEY          "printer_command_entry"
diff -c -r ethereal-2001-12-16/gtk/main.c ethereal-0.8.20/gtk/main.c
*** ethereal-2001-12-16/gtk/main.c	Wed Dec 12 22:38:58 2001
--- ethereal-0.8.20/gtk/main.c	Mon Dec 17 12:54:03 2001
***************
*** 221,245 ****
  
  /* Match selected byte pattern */
  void
! match_selected_cb(GtkWidget *w, gpointer data)
  {
!     char		*buf;
      GtkWidget		*filter_te;
  
!     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
  
      buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
  
      /* create a new one and set the display filter entry accordingly */
!     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
  
      /* Run the display filter so it goes in effect. */
!     filter_packets(&cfile, buf);
  
      /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
  }
  
  
  
  /* Run the current display filter on the current packet set, and
     redisplay. */
--- 221,313 ----
  
  /* Match selected byte pattern */
  void
! match_selected_cb_do(GtkWidget *w, gpointer data, int action)
  {
!     char		*buf, *ptr;
      GtkWidget		*filter_te;
  
!     if (MATCH_SELECTED_REPLACE_NOW == action)
!     { filter_te = gtk_object_get_data(GTK_OBJECT(data), E_DFILTER_TE_KEY); }
!     else
!     { filter_te = gtk_object_get_data(GTK_OBJECT(data), E_DPREPARE_TE_KEY); }
  
      buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
  
+     ptr=gtk_entry_get_text(GTK_ENTRY(filter_te));
+ 
+     switch (action)
+     { case MATCH_SELECTED_REPLACE:
+       case MATCH_SELECTED_REPLACE_NOW:
+                ptr=buf;
+            break;
+       case MATCH_SELECTED_AND:
+                if ((!ptr) || (0==strlen(ptr)))
+                { ptr=buf; }
+                else
+                { ptr=g_strconcat("(",ptr,") && (",buf,")",NULL); }
+            break;
+       case MATCH_SELECTED_OR:
+                if ((!ptr) || (0==strlen(ptr)))
+                { ptr=buf; }
+                else
+                { ptr=g_strconcat("(",ptr,") || (",buf,")",NULL); }
+            break;
+       case MATCH_SELECTED_NOT:
+                ptr=g_strconcat("!(",buf,")",NULL);
+            break;
+       case MATCH_SELECTED_AND_NOT:
+                if ((!ptr) || (0==strlen(ptr)))
+                { ptr=g_strconcat("!(",buf,")",NULL); }
+                else
+                { ptr=g_strconcat("(",ptr,") && !(",buf,")",NULL); }
+            break;
+       case MATCH_SELECTED_OR_NOT:
+                if ((!ptr) || (0==strlen(ptr)))
+                { ptr=g_strconcat("!(",buf,")",NULL); }
+                else
+                { ptr=g_strconcat("(",ptr,") || !(",buf,")",NULL); }
+            break;
+       default:
+            break;
+      }
+ 
      /* create a new one and set the display filter entry accordingly */
!     gtk_entry_set_text(GTK_ENTRY(filter_te), ptr);
  
      /* Run the display filter so it goes in effect. */
!     if (MATCH_SELECTED_REPLACE_NOW == action)
!     { filter_packets(&cfile, ptr); }
  
      /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
  }
  
+ void
+ match_selected_cb_replace(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_REPLACE); }
+ 
+ void
+ match_selected_cb_and(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_AND); }
+ 
+ void
+ match_selected_cb_or(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_OR); }
+ 
+ void
+ match_selected_cb_not(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_NOT); }
+ 
+ void
+ match_selected_cb_and_not(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_AND_NOT); }
+ 
+ void
+ match_selected_cb_or_not(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_OR_NOT); }
  
+ void
+ match_selected_cb_replace_now(GtkWidget *w, gpointer data)
+ { match_selected_cb_do( w, data, MATCH_SELECTED_REPLACE_NOW); }
  
  /* Run the current display filter on the current packet set, and
     redisplay. */
***************
*** 277,293 ****
    }
  }
  
  /* redisplay with no display filter */
  static void
  filter_reset_cb(GtkWidget *w, gpointer data)
  {
    GtkWidget *filter_te = NULL;
  
!   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
!     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
    }
  
!   filter_packets(&cfile, NULL);
  }
  
  /* GTKClist compare routine, overrides default to allow numeric comparison */
--- 345,420 ----
    }
  }
  
+ /* Run the current display filter on the current packet set, and
+    redisplay. */
+ static void
+ prepare_activate_cb(GtkWidget *w, gpointer data)
+ {
+   GtkCombo  *prepare_cm = gtk_object_get_data(GTK_OBJECT(w), E_DPREPARE_CM_KEY);
+   GList     *prepare_list = gtk_object_get_data(GTK_OBJECT(w), E_DPREPARE_FL_KEY);
+   GList     *li, *nl = NULL;
+   gboolean   add_filter = TRUE;
+   
+   char *s = gtk_entry_get_text(GTK_ENTRY(w));
+   
+   /* GtkCombos don't let us get at their list contents easily, so we maintain
+      our own filter list, and feed it to gtk_combo_set_popdown_strings when
+      a new filter is added. */
+   li = g_list_first(prepare_list);
+   while (li) {
+     if (li->data && strcmp(s, li->data) == 0)
+       add_filter = FALSE;
+     li = li->next;
+   }
+ 
+   if (add_filter) {
+     prepare_list = g_list_append(prepare_list, g_strdup(s));
+     li = g_list_first(prepare_list);
+     while (li) {
+       nl = g_list_append(nl, strdup(li->data));
+       li = li->next;
+     }
+     gtk_combo_set_popdown_strings(prepare_cm, nl);
+     gtk_entry_set_text(GTK_ENTRY(prepare_cm->entry), g_list_last(prepare_list)->data);
+   }
+ }
+ 
  /* redisplay with no display filter */
  static void
  filter_reset_cb(GtkWidget *w, gpointer data)
  {
    GtkWidget *filter_te = NULL;
  
!   if (0==(int)data)
!   { if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
!       gtk_entry_set_text(GTK_ENTRY(filter_te), "");
!     }
!     filter_packets(&cfile, NULL);
    }
+   else
+   { if (1==(int)data)
+     { if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DPREPARE_TE_KEY))) {
+         gtk_entry_set_text(GTK_ENTRY(filter_te), "");
+       }
+     }
+   }
+ 
+ }
  
! /* Apply prepared filter */
! static void
! prepare_use_cb(GtkWidget *w, gpointer data)
! {
!   GtkWidget *filter_te = NULL;
!   GtkWidget *prepare_te = NULL;
! 
!   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY)) &&
!       (prepare_te = gtk_object_get_data(GTK_OBJECT(w), E_DPREPARE_TE_KEY)))
!   {
!     gtk_entry_set_text(GTK_ENTRY(filter_te), gtk_entry_get_text(GTK_ENTRY(prepare_te)));
!     filter_activate_cb(filter_te,NULL);
!     prepare_activate_cb(prepare_te,NULL);
!   }
  }
  
  /* GTKClist compare routine, overrides default to allow numeric comparison */
***************
*** 1803,1811 ****
--- 1930,1942 ----
  {
    GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
                        *stat_hbox, *column_lb,
+                       *stat_hbox2, 
                        *filter_bt, *filter_cm, *filter_te,
+                       *filter_bt2, *prepare_cm, *prepare_te,
+                       *prepare_clear, *prepare_use,
                        *filter_reset;
    GList               *filter_list = NULL;
+   GList               *prepare_list = NULL;
    GtkAccelGroup       *accel;
    GtkStyle            *win_style;
    GdkBitmap           *ascend_bm, *descend_bm;
***************
*** 1818,1824 ****
    static construct_args_t args = {
    	"Ethereal: Display Filter",
    	TRUE,
!   	TRUE
    };
  
    /* Main window */  
--- 1949,1963 ----
    static construct_args_t args = {
    	"Ethereal: Display Filter",
    	TRUE,
!   	TRUE,
! 	TRUE
!   };
! 
!   static construct_args_t args2 = {
!   	"Ethereal: Display Filter",
!   	TRUE,
!   	TRUE,
! 	FALSE
    };
  
    /* Main window */  
***************
*** 1947,1964 ****
    filter_reset = gtk_button_new_with_label("Reset");
    gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
    gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
! 		     GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
    gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
    gtk_widget_show(filter_reset);
  
    /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
     * of any widget that ends up calling a callback which needs
     * that text entry pointer */
    set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
    set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
    set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
!   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
    set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
  
    info_bar = gtk_statusbar_new();
    main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
--- 2086,2149 ----
    filter_reset = gtk_button_new_with_label("Reset");
    gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
    gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
! 		     GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) 0);
    gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
    gtk_widget_show(filter_reset);
  
+   stat_hbox2 = gtk_hbox_new(FALSE, 1);
+   gtk_container_border_width(GTK_CONTAINER(stat_hbox2), 0);
+   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox2, FALSE, TRUE, 0);
+   gtk_widget_show(stat_hbox2);
+ 
+   filter_bt2 = gtk_button_new_with_label("Filter:");
+   gtk_signal_connect(GTK_OBJECT(filter_bt2), "clicked",
+     GTK_SIGNAL_FUNC(display_filter_construct_cb), &args2);
+   gtk_box_pack_start(GTK_BOX(stat_hbox2), filter_bt2, FALSE, TRUE, 0);
+   gtk_widget_show(filter_bt2);
+   
+   prepare_cm = gtk_combo_new();
+   prepare_list = g_list_append (prepare_list, "");
+   gtk_combo_set_popdown_strings(GTK_COMBO(prepare_cm), prepare_list);
+   gtk_combo_disable_activate(GTK_COMBO(prepare_cm));
+   prepare_te = GTK_COMBO(prepare_cm)->entry;
+   gtk_object_set_data(GTK_OBJECT(filter_bt), E_PREP_TE_PTR_KEY, prepare_te);
+   gtk_object_set_data(GTK_OBJECT(filter_bt2), E_PREP_TE_PTR_KEY, prepare_te);
+   gtk_object_set_data(GTK_OBJECT(filter_bt2), E_FILT_TE_PTR_KEY, filter_te);
+ 
+   gtk_object_set_data(GTK_OBJECT(prepare_te), E_DPREPARE_CM_KEY, prepare_cm);
+   gtk_object_set_data(GTK_OBJECT(prepare_te), E_DPREPARE_FL_KEY, prepare_list);
+ 
+   gtk_box_pack_start(GTK_BOX(stat_hbox2), prepare_cm, TRUE, TRUE, 3);
+   gtk_signal_connect(GTK_OBJECT(prepare_te), "activate",
+     GTK_SIGNAL_FUNC(prepare_activate_cb), (gpointer) NULL);
+   gtk_widget_show(prepare_cm);
+ 
+   prepare_use = gtk_button_new_with_label("Use");
+   gtk_object_set_data(GTK_OBJECT(prepare_use), E_DFILTER_TE_KEY, filter_te);
+   gtk_object_set_data(GTK_OBJECT(prepare_use), E_DPREPARE_TE_KEY, prepare_te);
+   gtk_signal_connect(GTK_OBJECT(prepare_use), "clicked",
+ 		     GTK_SIGNAL_FUNC(prepare_use_cb), (gpointer) NULL);
+   gtk_box_pack_start(GTK_BOX(stat_hbox2), prepare_use, FALSE, TRUE, 9);
+   gtk_widget_show(prepare_use);
+ 
+   prepare_clear = gtk_button_new_with_label("Clear");
+   gtk_object_set_data(GTK_OBJECT(prepare_clear), E_DPREPARE_TE_KEY, prepare_te);
+   gtk_signal_connect(GTK_OBJECT(prepare_clear), "clicked",
+ 		     GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) 1);
+   gtk_box_pack_start(GTK_BOX(stat_hbox2), prepare_clear, FALSE, TRUE, 1);
+   gtk_widget_show(prepare_clear);
+ 
+ 
    /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
     * of any widget that ends up calling a callback which needs
     * that text entry pointer */
    set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
    set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
    set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
!   set_menu_object_data("/Edit/Filters...", E_PREP_TE_PTR_KEY, prepare_te);
    set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
+   gtk_object_set_data(GTK_OBJECT(popup_menu_object), E_DFILTER_TE_KEY, filter_te);
+   gtk_object_set_data(GTK_OBJECT(popup_menu_object), E_DPREPARE_TE_KEY, prepare_te);
  
    info_bar = gtk_statusbar_new();
    main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
diff -c -r ethereal-2001-12-16/gtk/main.h ethereal-0.8.20/gtk/main.h
*** ethereal-2001-12-16/gtk/main.h	Thu Nov 22 00:16:26 2001
--- ethereal-0.8.20/gtk/main.h	Mon Dec 17 12:45:32 2001
***************
*** 45,50 ****
--- 45,58 ----
  #define DEF_READY_MESSAGE " Ready to load file"
  #endif
  
+ #define MATCH_SELECTED_REPLACE		0
+ #define MATCH_SELECTED_AND		1
+ #define MATCH_SELECTED_OR		2
+ #define MATCH_SELECTED_NOT		3
+ #define MATCH_SELECTED_AND_NOT		4
+ #define MATCH_SELECTED_OR_NOT		5
+ #define MATCH_SELECTED_REPLACE_NOW	6
+ 
  typedef struct _selection_info {
    GtkWidget *tree;
    GtkWidget *text;
***************
*** 54,59 ****
--- 62,74 ----
  
  void about_ethereal( GtkWidget *, gpointer);
  void match_selected_cb( GtkWidget *, gpointer);
+ void match_selected_cb_replace( GtkWidget *, gpointer);
+ void match_selected_cb_and( GtkWidget *, gpointer);
+ void match_selected_cb_or( GtkWidget *, gpointer);
+ void match_selected_cb_not( GtkWidget *, gpointer);
+ void match_selected_cb_and_not( GtkWidget *, gpointer);
+ void match_selected_cb_or_not( GtkWidget *, gpointer);
+ void match_selected_cb_replace_now( GtkWidget *, gpointer);
  void file_quit_cmd_cb(GtkWidget *, gpointer);
  void file_print_cmd_cb(GtkWidget *, gpointer);
  void file_print_packet_cmd_cb(GtkWidget *, gpointer);
diff -c -r ethereal-2001-12-16/gtk/menu.c ethereal-0.8.20/gtk/menu.c
*** ethereal-2001-12-16/gtk/menu.c	Sat Dec  8 10:27:51 2001
--- ethereal-0.8.20/gtk/menu.c	Mon Dec 17 12:45:32 2001
***************
*** 139,145 ****
  #endif /* HAVE_LIBPCAP */
    {"/_Display", NULL, NULL, 0, "<Branch>" },
    {"/Display/_Options...", NULL, GTK_MENU_FUNC(display_opt_cb), 0, NULL},
!   {"/Display/_Match Selected", NULL, GTK_MENU_FUNC(match_selected_cb), 0, NULL},
    {"/Display/_Colorize Display...", NULL, GTK_MENU_FUNC(color_display_cb), 0, NULL},
    {"/Display/Collapse _All", NULL, GTK_MENU_FUNC(collapse_all_cb), 0, NULL},
    {"/Display/_Expand All", NULL, GTK_MENU_FUNC(expand_all_cb), 0, NULL},
--- 139,152 ----
  #endif /* HAVE_LIBPCAP */
    {"/_Display", NULL, NULL, 0, "<Branch>" },
    {"/Display/_Options...", NULL, GTK_MENU_FUNC(display_opt_cb), 0, NULL},
!   {"/Display/_Match", NULL, NULL, 0, "<Branch>" },
!   {"/Display/Match/Selected & Apply", NULL, GTK_MENU_FUNC(match_selected_cb_replace_now), 0, NULL},
!   {"/Display/Match/_Selected", NULL, GTK_MENU_FUNC(match_selected_cb_replace), 0, NULL},
!   {"/Display/Match/_Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_not), 0, NULL},
!   {"/Display/Match/_And", NULL, GTK_MENU_FUNC(match_selected_cb_and), 0, NULL},
!   {"/Display/Match/_Or", NULL, GTK_MENU_FUNC(match_selected_cb_or), 0, NULL},
!   {"/Display/Match/A_nd Not", NULL, GTK_MENU_FUNC(match_selected_cb_and_not), 0, NULL},
!   {"/Display/Match/O_r Not", NULL, GTK_MENU_FUNC(match_selected_cb_or_not), 0, NULL},
    {"/Display/_Colorize Display...", NULL, GTK_MENU_FUNC(color_display_cb), 0, NULL},
    {"/Display/Collapse _All", NULL, GTK_MENU_FUNC(collapse_all_cb), 0, NULL},
    {"/Display/_Expand All", NULL, GTK_MENU_FUNC(expand_all_cb), 0, NULL},
***************
*** 191,197 ****
  	{"/<separator>", NULL, NULL, 0, "<Separator>"},
  	{"/Resolve Name", NULL, GTK_MENU_FUNC(resolve_name_cb), 0, NULL},
  	{"/Protocol Properties...", NULL, GTK_MENU_FUNC(properties_cb), 0, NULL},
! 	{"/Match Selected", NULL, GTK_MENU_FUNC(match_selected_cb), 0, NULL},
  	{"/<separator>", NULL, NULL, 0, "<Separator>"},
  	{"/Collapse All", NULL, GTK_MENU_FUNC(collapse_all_cb), 0, NULL},
  	{"/Expand All", NULL, GTK_MENU_FUNC(expand_all_cb), 0, NULL}
--- 198,211 ----
  	{"/<separator>", NULL, NULL, 0, "<Separator>"},
  	{"/Resolve Name", NULL, GTK_MENU_FUNC(resolve_name_cb), 0, NULL},
  	{"/Protocol Properties...", NULL, GTK_MENU_FUNC(properties_cb), 0, NULL},
!         {"/Match", NULL, NULL, 0, "<Branch>" },
!         {"/Match/Selected & Apply", NULL, GTK_MENU_FUNC(match_selected_cb_replace_now), 0, NULL},
!         {"/Match/_Selected", NULL, GTK_MENU_FUNC(match_selected_cb_replace), 0, NULL},
!         {"/Match/_Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_not), 0, NULL},
!         {"/Match/_And", NULL, GTK_MENU_FUNC(match_selected_cb_and), 0, NULL},
!         {"/Match/_Or", NULL, GTK_MENU_FUNC(match_selected_cb_or), 0, NULL},
!         {"/Match/A_nd Not", NULL, GTK_MENU_FUNC(match_selected_cb_and_not), 0, NULL},
!         {"/Match/O_r Not", NULL, GTK_MENU_FUNC(match_selected_cb_or_not), 0, NULL},
  	{"/<separator>", NULL, NULL, 0, "<Separator>"},
  	{"/Collapse All", NULL, GTK_MENU_FUNC(collapse_all_cb), 0, NULL},
  	{"/Expand All", NULL, GTK_MENU_FUNC(expand_all_cb), 0, NULL}
***************
*** 240,256 ****
      /* popup */
  
      packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
!     gtk_item_factory_create_items_ac(packet_list_menu_factory, sizeof(packet_list_menu_items)/sizeof(packet_list_menu_items[0]), packet_list_menu_items, NULL, 2);
      gtk_object_set_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY, packet_list_menu_factory->widget);
      popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
  
      tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
!     gtk_item_factory_create_items_ac(tree_view_menu_factory, sizeof(tree_view_menu_items)/sizeof(tree_view_menu_items[0]), tree_view_menu_items, NULL, 2);
      gtk_object_set_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY, tree_view_menu_factory->widget);
      popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
  
      hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
!     gtk_item_factory_create_items_ac(hexdump_menu_factory, sizeof(hexdump_menu_items)/sizeof(hexdump_menu_items[0]), hexdump_menu_items, NULL, 2);
      gtk_object_set_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY, hexdump_menu_factory->widget);
      popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
      
--- 254,270 ----
      /* popup */
  
      packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
!     gtk_item_factory_create_items_ac(packet_list_menu_factory, sizeof(packet_list_menu_items)/sizeof(packet_list_menu_items[0]), packet_list_menu_items, popup_menu_object, 2);
      gtk_object_set_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY, packet_list_menu_factory->widget);
      popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
  
      tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
!     gtk_item_factory_create_items_ac(tree_view_menu_factory, sizeof(tree_view_menu_items)/sizeof(tree_view_menu_items[0]), tree_view_menu_items, popup_menu_object, 2);
      gtk_object_set_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY, tree_view_menu_factory->widget);
      popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
  
      hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
!     gtk_item_factory_create_items_ac(hexdump_menu_factory, sizeof(hexdump_menu_items)/sizeof(hexdump_menu_items[0]), hexdump_menu_items, popup_menu_object, 2);
      gtk_object_set_data(GTK_OBJECT(popup_menu_object), PM_HEXDUMP_KEY, hexdump_menu_factory->widget);
      popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
      
***************
*** 427,436 ****
  	} else {
  	  properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
  	}
! 	set_menu_sensitivity("/Display/Match Selected",
  	  proto_can_match_selected(finfo_selected));
    } else
! 	set_menu_sensitivity("/Display/Match Selected", FALSE);
  
    set_menu_sensitivity("/Protocol Properties...", have_selected_tree && properties);
  }
--- 441,450 ----
  	} else {
  	  properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
  	}
! 	set_menu_sensitivity("/Display/Match",
  	  proto_can_match_selected(finfo_selected));
    } else
! 	set_menu_sensitivity("/Display/Match", FALSE);
  
    set_menu_sensitivity("/Protocol Properties...", have_selected_tree && properties);
  }