Wireshark-dev: Re: [Wireshark-dev] [Patch] Add "Copy as Filter" menu item
From: Sake Blok <sake@xxxxxxxxxx>
Date: Thu, 8 Mar 2007 22:38:12 +0100
On Wed, Mar 07, 2007 at 10:36:00AM +0100, Ulf Lamping wrote:
> 
> I had a look at your patch and applied it to my personal tree, noting 
> some things:
> 
> 1) We already have a Copy submenu in both context menus, your function 
> belongs into this (e.g. /Copy/As Filter) - right below 
> Summary/Description IMHO

Done...

> 2) The Copy entry in the main menu belongs in Edit (e.g. /Edit/Copy/As 
> Filter) and not in Analyze (we need to add all the other Copy 
> functionality into this menu as well, probably later)

Done...

> Could you change this and send a new patch?

I have changed the patch according to your suggestions and also changed
the doc[book] files accordingly. I tested the patch and it does seem to
work fine on my test-system.

Could you take another look at it and submit it if it is OK now?

Thanks,


Sake
Index: doc/wireshark.pod
===================================================================
--- doc/wireshark.pod	(revision 21002)
+++ doc/wireshark.pod	(working copy)
@@ -731,6 +731,17 @@
 
 Exit the application.
 
+=item Edit:Copy:As Filter
+
+Create a display filter based on the data currently highlighted in the
+packet details and copy that filter to the clipboard.
+
+If that data is a field that can be tested in a display filter
+expression, the display filter will test that field; otherwise, the
+display filter will be based on the absolute offset within the packet.
+Therefore it could be unreliable if the packet contains protocols with
+variable-length headers, such as a source-routed token-ring packet.
+
 =item Edit:Find Packet
 
 Search forward or backward, starting with the currently selected packet
@@ -972,28 +983,27 @@
 
 =item Analyze:Apply as Filter
 
-Create a display filter, or add to the display filter strip at the
-bottom, a display filter based on the data currently highlighted in the
-packe details, and apply the filter.
+Create a display filter based on the data currently highlighted in the
+packet details and apply the filter.
 
 If that data is a field that can be tested in a display filter
 expression, the display filter will test that field; otherwise, the
-display filter will be based on absolute offset within the packet, and
-so could be unreliable if the packet contains protocols with
+display filter will be based on the absolute offset within the packet.
+Therefore it could be unreliable if the packet contains protocols with
 variable-length headers, such as a source-routed token-ring packet.
 
 The B<Selected> option creates a display filter that tests for a match
 of the data; the B<Not Selected> option creates a display filter that
 tests for a non-match of the data.  The B<And Selected>, B<Or Selected>,
 B<And Not Selected>, and B<Or Not Selected> options add to the end of
-the display filter in the strip at the bottom an AND or OR operator
-followed by the new display filter expression.
+the display filter in the strip at the top (or bottom) an AND or OR
+operator followed by the new display filter expression.
 
 =item Analyze:Prepare a Filter
 
-Create a display filter, or add to the display filter strip at the
-bottom, a display filter based on the data currently highlighted in the
-packet details, but don't apply the filter.
+Create a display filter based on the data currently highlighted in the
+packet details. The filter strip at the top (or bottom) is updated but 
+it is not yet applied.
 
 =item Analyze:Enabled Protocols
 
Index: docbook/wsug_src/WSUG_chapter_work.xml
===================================================================
--- docbook/wsug_src/WSUG_chapter_work.xml	(revision 21002)
+++ docbook/wsug_src/WSUG_chapter_work.xml	(working copy)
@@ -185,6 +185,16 @@
 		</entry>
 		  </row>
 		  <row>
+		    <entry><command>Copy as Filter</command></entry>
+		    <entry>Analyze</entry>
+	 	    <entry>
+	            <para>
+	 	      Prepare a display filter based on the currently selected item
+		      and copy that filter to the clipboard.
+	            </para>
+	 	    </entry>
+		  </row>
+		  <row>
 		<entry><command>Copy/ Bytes (Offset Hex Text)</command></entry>
 		<entry>-</entry>
 		<entry>
@@ -353,6 +363,16 @@
 	    </para>
 		</entry>
 	      </row>
+	      <row>
+		<entry><command>Copy/ As Filter</command></entry>
+		<entry>-</entry>
+		<entry>
+	    <para>
+		  Prepare a display filter based on the currently selected item
+		  and copy it to the clipboard.
+	    </para>
+		</entry>
+	      </row>
 		  <row>
 		<entry><command>Copy/ Bytes (Offset Hex Text)</command></entry>
 		<entry>-</entry>
Index: docbook/wsug_src/WSUG_chapter_use.xml
===================================================================
--- docbook/wsug_src/WSUG_chapter_use.xml	(revision 21002)
+++ docbook/wsug_src/WSUG_chapter_use.xml	(working copy)
@@ -574,6 +574,20 @@
 	    </thead>
 	    <tbody>
 	      <row>
+		<entry><command>Copy > As Filter</command></entry>
+		<entry></entry>
+		<entry><para>
+			This menu item will use the selected item in the detail view to
+			create a display filter. This display filter is then copied to
+			the clipboard.
+		  </para></entry>
+	      </row>
+	      <row>
+		<entry><command>------</command></entry>
+		<entry></entry>
+		<entry></entry>
+	      </row>
+	      <row>
 		<entry><command>Find Packet...</command></entry>
 		<entry>Ctrl+F</entry>
 		<entry><para>
Index: gtk/menu.c
===================================================================
--- gtk/menu.c	(revision 21002)
+++ gtk/menu.c	(working copy)
@@ -432,6 +432,9 @@
     ITEM_FACTORY_STOCK_ENTRY("/File/_Quit", "<control>Q", file_quit_cmd_cb,
                              0, GTK_STOCK_QUIT),
     ITEM_FACTORY_ENTRY("/_Edit", NULL, NULL, 0, "<Branch>", NULL),
+    ITEM_FACTORY_ENTRY("/Edit/Copy", NULL, NULL, 0, "<Branch>", NULL),
+    ITEM_FACTORY_ENTRY("/Edit/Copy/As Filter", NULL, match_selected_ptree_cb,
+                       MATCH_SELECTED_REPLACE|MATCH_SELECTED_COPY_ONLY, NULL, NULL),
 #if 0
     /* Un-#if this when we actually implement Cut/Copy/Paste. */
     ITEM_FACTORY_STOCK_ENTRY("/Edit/Cut", "<control>X", NULL,
@@ -440,8 +443,8 @@
                              0, GTK_STOCK_COPY),
     ITEM_FACTORY_STOCK_ENTRY("/Edit/Paste", "<control>V", NULL,
                              0, GTK_STOCK_PASTE),
-    ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>"),
 #endif
+    ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Find Packet...", "<control>F",
                              find_frame_cb, 0, GTK_STOCK_FIND),
     ITEM_FACTORY_ENTRY("/Edit/Find Ne_xt", "<control>N", find_next_cb, 0, NULL, NULL),
@@ -720,6 +723,8 @@
     ITEM_FACTORY_ENTRY("/Copy", NULL, NULL, 0, "<Branch>", NULL),
     ITEM_FACTORY_ENTRY("/Copy/Summary (Text)", NULL, packet_list_copy_summary_cb, CS_TEXT, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/Summary (CSV)", NULL, packet_list_copy_summary_cb, CS_CSV, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/As Filter", NULL, match_selected_plist_cb,
+                       MATCH_SELECTED_REPLACE|MATCH_SELECTED_COPY_ONLY, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/<separator>", NULL, NULL, 0, "<Separator>", NULL),
     ITEM_FACTORY_ENTRY("/Copy/Bytes (Offset Hex Text)", NULL, copy_hex_cb, CD_ALLINFO, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/Bytes (Offset Hex)", NULL, copy_hex_cb, CD_HEXCOLUMNS, NULL, NULL),
@@ -754,6 +759,7 @@
 
     ITEM_FACTORY_ENTRY("/Copy", NULL, NULL, 0, "<Branch>", NULL),
     ITEM_FACTORY_ENTRY("/Copy/Description", NULL, copy_selected_plist_cb, 0, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Copy/As Filter", NULL, match_selected_ptree_cb, MATCH_SELECTED_REPLACE|MATCH_SELECTED_COPY_ONLY, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/Bytes (Offset Hex Text)", NULL, copy_hex_cb, CD_ALLINFO | CD_FLAGS_SELECTEDONLY, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/Bytes (Offset Hex)", NULL, copy_hex_cb, CD_HEXCOLUMNS | CD_FLAGS_SELECTEDONLY, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Copy/Bytes (Printable Text Only)", NULL, copy_hex_cb, CD_TEXTONLY | CD_FLAGS_SELECTEDONLY, NULL, NULL),
@@ -2395,6 +2401,8 @@
       cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
   set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
       cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
+  set_menu_sensitivity(packet_list_menu_factory, "/Copy/As Filter",
+      cf->current_frame != NULL);
   set_menu_sensitivity(packet_list_menu_factory, "/Apply as Filter",
       cf->current_frame != NULL);
   set_menu_sensitivity(packet_list_menu_factory, "/Prepare a Filter",
@@ -2482,6 +2490,10 @@
 	  "/Go/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
 	set_menu_sensitivity(tree_view_menu_factory,
 	  "/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
+	set_menu_sensitivity(main_menu_factory, "/Edit/Copy/As Filter",
+	  proto_can_match_selected(cf->finfo_selected, cf->edt));
+	set_menu_sensitivity(tree_view_menu_factory, "/Copy/As Filter",
+	  proto_can_match_selected(cf->finfo_selected, cf->edt));
 	set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter",
 	  proto_can_match_selected(cf->finfo_selected, cf->edt));
 	set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter",
@@ -2503,6 +2515,8 @@
 	    "/Go/Go to Corresponding Packet", FALSE);
 	set_menu_sensitivity(tree_view_menu_factory,
 	    "/Go to Corresponding Packet", FALSE);
+	set_menu_sensitivity(main_menu_factory, "/Edit/Copy/As Filter", FALSE);
+	set_menu_sensitivity(tree_view_menu_factory, "/Copy/As Filter", FALSE);
 	set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter", FALSE);
 	set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter", FALSE);
 	set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter", FALSE);
Index: gtk/main.c
===================================================================
--- gtk/main.c	(revision 21002)
+++ gtk/main.c	(working copy)
@@ -247,8 +247,11 @@
     GtkWidget		*filter_te;
     char		*cur_filter, *new_filter;
 
-    if (!text)
+    if ((!text) || (0 == strlen(text))) {
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not acquire information to build a filter!\nTry expanding or choosing another item.");
 	return;
+    }
+
     g_assert(data);
     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
     g_assert(filter_te);
@@ -302,12 +305,20 @@
     /* Free up the copy we got of the old filter text. */
     g_free(cur_filter);
 
-    /* create a new one and set the display filter entry accordingly */
-    gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
+    /* Don't change the current display filter if we only want to copy the filter */
+    if (action&MATCH_SELECTED_COPY_ONLY) {
+	GString *gtk_text_str = g_string_new("");
+	g_string_sprintfa(gtk_text_str, "%s", new_filter);
+	copy_to_clipboard(gtk_text_str);
+	g_string_free(gtk_text_str, TRUE);
+    } else {
+	/* create a new one and set the display filter entry accordingly */
+	gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
 
-    /* Run the display filter so it goes in effect. */
-    if (action&MATCH_SELECTED_APPLY_NOW)
-	main_filter_packets(&cfile, new_filter, FALSE);
+	/* Run the display filter so it goes in effect. */
+	if (action&MATCH_SELECTED_APPLY_NOW)
+	    main_filter_packets(&cfile, new_filter, FALSE);
+    }
 
     /* Free up the new filter text. */
     g_free(new_filter);
@@ -321,8 +332,7 @@
     if (cfile.finfo_selected) {
         filter = proto_construct_match_selected_string(cfile.finfo_selected,
                                                        cfile.edt);
-        if (filter != NULL)
-            match_selected_cb_do((data ? data : w), action, filter);
+        match_selected_cb_do((data ? data : w), action, filter);
     }
 }
 
@@ -4638,6 +4648,8 @@
      * 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("/Edit/Copy/As Filter", E_DFILTER_TE_KEY,
+                         filter_te);
     set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
                          filter_te);
     set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
Index: gtk/main.h
===================================================================
--- gtk/main.h	(revision 21002)
+++ gtk/main.h	(working copy)
@@ -126,6 +126,9 @@
 /** "bitwise or" this with MATCH_SELECTED_E value for instant apply instead of prepare only */
 #define MATCH_SELECTED_APPLY_NOW    0x100
 
+/** "bitwise or" this with MATCH_SELECTED_E value for copy to clipboard instead of prepare only */
+#define MATCH_SELECTED_COPY_ONLY    0x200
+
 /** User highlited item in details window and then right clicked and selected the copy option 
  *
  * @param widget parent widget