From Jirka Novak:
authorguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 11 Jan 2002 08:21:02 +0000 (08:21 +0000)
committerguy <guy@f5534014-38df-0310-8fa8-9805f1628bb7>
Fri, 11 Jan 2002 08:21:02 +0000 (08:21 +0000)
Support for generating filter expressions based on packet list
    column values
Support for adding filter expressions generated from column or
    protocol tree field values to the current expression rather
    than replacing the current expression

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@4522 f5534014-38df-0310-8fa8-9805f1628bb7

AUTHORS
doc/ethereal.pod.template
epan/column-utils.c
epan/column_info.h
gtk/keys.h
gtk/main.c
gtk/main.h
gtk/menu.c

diff --git a/AUTHORS b/AUTHORS
index 59350437526e149bd153b1f77ac052a5dea67dda..eb71b4cbd32da23198b4760fc2203e24d3f8b186 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -991,6 +991,14 @@ Dinesh Dutt <ddutt[AT]cisco.com> {
 Nagarjuna Venna <nvenna[AT]Brixnet.com> {
        Only display the reason in BYE RTCP packets if it's present
 }
+
+Jirka Novak <j.novak[AT]netsystem.cz> {
+       Support for generating filter expressions based on packet list
+           column values
+       Support for adding filter expressions generated from column or
+           protocol tree field values to the current expression rather
+           than replacing the current expression
+}
        
 Alain Magloire <alainm[AT]rcsm.ece.mcgill.ca> was kind enough to
 give his permission to use his version of snprintf.c.
index cdedd603ff97720faac46a24ce6284fd36a6520c..f0b7af1b82f460e083b8640afcdab7bf8d8d58b4 100644 (file)
@@ -1279,6 +1279,7 @@ B<http://www.ethereal.com>.
   Jayaram V.R              <vjayar[AT]cisco.com>
   Dinesh Dutt              <ddutt[AT]cisco.com>
   Nagarjuna Venna          <nvenna[AT]Brixnet.com>
+  Jirka Novak              <j.novak[AT]netsystem.cz>
 
 Alain Magloire <alainm[AT]rcsm.ece.mcgill.ca> was kind enough to give his
 permission to use his version of snprintf.c.
index dbae5d6ee3bb532ef584cae75df43218f1eb3e1d..c332f5816abb6a782e1c3d721b6bd472700f3e82 100644 (file)
@@ -1,7 +1,7 @@
 /* column-utils.c
  * Routines for column utilities.
  *
- * $Id: column-utils.c,v 1.9 2001/12/10 02:15:54 guy Exp $
+ * $Id: column-utils.c,v 1.10 2002/01/11 08:21:00 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -64,6 +64,8 @@ col_init(column_info *col_info, gint num_cols)
   col_info->col_title  = (gchar **) g_malloc(sizeof(gchar *) * num_cols);
   col_info->col_data   = (gchar **) g_malloc(sizeof(gchar *) * num_cols);
   col_info->col_buf    = (gchar **) g_malloc(sizeof(gchar *) * num_cols);
+  col_info->col_expr   = (gchar **) g_malloc(sizeof(gchar *) * num_cols);
+  col_info->col_expr_val = (gchar **) g_malloc(sizeof(gchar *) * num_cols);
 }
 
 #if 0
@@ -115,6 +117,8 @@ col_clear(column_info *cinfo, gint el) {
     if (cinfo->fmt_matx[i][el]) {
       cinfo->col_buf[i][0] = 0;
       cinfo->col_data[i] = cinfo->col_buf[i];
+      cinfo->col_expr[i][0] = '\0';
+      cinfo->col_expr_val[i][0] = '\0';
     }
   }
 }
@@ -249,6 +253,8 @@ col_set_abs_date_time(frame_data *fd, column_info *cinfo, int col)
     cinfo->col_buf[col][0] = '\0';
   }
   cinfo->col_data[col] = cinfo->col_buf[col];
+  strcpy(cinfo->col_expr[col],"frame.time");
+  strcpy(cinfo->col_expr_val[col],cinfo->col_buf[col]);
 }
 
 static void
@@ -257,6 +263,8 @@ col_set_rel_time(frame_data *fd, column_info *cinfo, int col)
   display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
        fd->rel_secs, fd->rel_usecs, USECS);
   cinfo->col_data[col] = cinfo->col_buf[col];
+  strcpy(cinfo->col_expr[col],"frame.time_relative");
+  strcpy(cinfo->col_expr_val[col],cinfo->col_buf[col]);
 }
 
 static void
@@ -265,6 +273,8 @@ col_set_delta_time(frame_data *fd, column_info *cinfo, int col)
   display_signed_time(cinfo->col_buf[col], COL_MAX_LEN,
        fd->del_secs, fd->del_usecs, USECS);
   cinfo->col_data[col] = cinfo->col_buf[col];
+  strcpy(cinfo->col_expr[col],"frame.time_delta");
+  strcpy(cinfo->col_expr_val[col],cinfo->col_buf[col]);
 }
 
 /* To do: Add check_col checks to the col_add* routines */
@@ -287,6 +297,8 @@ col_set_abs_time(frame_data *fd, column_info *cinfo, int col)
     cinfo->col_buf[col][0] = '\0';
   }
   cinfo->col_data[col] = cinfo->col_buf[col];
+  strcpy(cinfo->col_expr[col],"frame.time");
+  strcpy(cinfo->col_expr_val[col],cinfo->col_buf[col]);
 }
 
 /* Add "command-line-specified" time.
@@ -319,13 +331,16 @@ col_set_cls_time(frame_data *fd, column_info *cinfo, int col)
 }
 
 static void
-col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res)
+col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res,
+            gboolean is_src)
 {
   guint32 ipv4_addr;
   struct e_in6_addr ipv6_addr;
   struct atalk_ddp_addr ddp_addr;
   struct sna_fid_type_4_addr sna_fid_type_4_addr;
 
+  pinfo->cinfo->col_expr[col][0] = '\0';
+  pinfo->cinfo->col_expr_val[col][0] = '\0';
   switch (addr->type) {
 
   case AT_ETHER:
@@ -335,6 +350,12 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res)
       strncpy(pinfo->cinfo->col_buf[col], ether_to_str(addr->data), COL_MAX_LEN);
     pinfo->cinfo->col_buf[col][COL_MAX_LEN - 1] = '\0';
     pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
+    if (is_src)
+      strcpy(pinfo->cinfo->col_expr[col], "eth.src");
+    else
+      strcpy(pinfo->cinfo->col_expr[col], "eth.dst");
+    strncpy(pinfo->cinfo->col_expr_val[col], ether_to_str(addr->data), COL_MAX_LEN);
+    pinfo->cinfo->col_expr_val[col][COL_MAX_LEN - 1] = '\0';
     break;
 
   case AT_IPv4:
@@ -345,6 +366,12 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res)
       strncpy(pinfo->cinfo->col_buf[col], ip_to_str(addr->data), COL_MAX_LEN);
     pinfo->cinfo->col_buf[col][COL_MAX_LEN - 1] = '\0';
     pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
+    if (is_src)
+      strcpy(pinfo->cinfo->col_expr[col], "ip.src");
+    else
+      strcpy(pinfo->cinfo->col_expr[col], "ip.dst");
+    strncpy(pinfo->cinfo->col_expr_val[col], ip_to_str(addr->data), COL_MAX_LEN);
+    pinfo->cinfo->col_expr_val[col][COL_MAX_LEN - 1] = '\0';
     break;
 
   case AT_IPv6:
@@ -355,6 +382,12 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res)
       strncpy(pinfo->cinfo->col_buf[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
     pinfo->cinfo->col_buf[col][COL_MAX_LEN - 1] = '\0';
     pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
+    if (is_src)
+      strcpy(pinfo->cinfo->col_expr[col], "ipv6.src");
+    else
+      strcpy(pinfo->cinfo->col_expr[col], "ipv6.dst");
+    strncpy(pinfo->cinfo->col_expr_val[col], ip6_to_str(&ipv6_addr), COL_MAX_LEN);
+    pinfo->cinfo->col_expr_val[col][COL_MAX_LEN - 1] = '\0';
     break;
 
   case AT_IPX:
@@ -362,6 +395,11 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res)
       ipx_addr_to_str(pntohl(&addr->data[0]), &addr->data[4]), COL_MAX_LEN);
     pinfo->cinfo->col_buf[col][COL_MAX_LEN - 1] = '\0';
     pinfo->cinfo->col_data[col] = pinfo->cinfo->col_buf[col];
+    if (is_src)
+      strcpy(pinfo->cinfo->col_expr[col], "ipx.src");
+    else
+      strcpy(pinfo->cinfo->col_expr[col], "ipx.dst");
+    strcpy(pinfo->cinfo->col_expr_val[col],pinfo->cinfo->col_buf[col]);
     break;
 
   case AT_SNA:
@@ -415,8 +453,10 @@ col_set_addr(packet_info *pinfo, int col, address *addr, gboolean is_res)
 
 static void
 col_set_port(packet_info *pinfo, int col, port_type ptype, guint32 port,
-               gboolean is_res)
+               gboolean is_res, gboolean is_src)
 {
+  pinfo->cinfo->col_expr[col][0] = '\0';
+  pinfo->cinfo->col_expr_val[col][0] = '\0';
   switch (ptype) {
 
   case PT_SCTP:
@@ -431,6 +471,12 @@ col_set_port(packet_info *pinfo, int col, port_type ptype, guint32 port,
       strncpy(pinfo->cinfo->col_buf[col], get_tcp_port(port), COL_MAX_LEN);
     else
       snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", port);
+    if (is_src)
+      strcpy(pinfo->cinfo->col_expr[col], "tcp.srcport");
+    else
+      strcpy(pinfo->cinfo->col_expr[col], "tcp.dstport");
+    snprintf(pinfo->cinfo->col_expr_val[col], COL_MAX_LEN, "%u", port);
+    pinfo->cinfo->col_expr_val[col][COL_MAX_LEN - 1] = '\0';
     break;
 
   case PT_UDP:
@@ -438,6 +484,12 @@ col_set_port(packet_info *pinfo, int col, port_type ptype, guint32 port,
       strncpy(pinfo->cinfo->col_buf[col], get_udp_port(port), COL_MAX_LEN);
     else
       snprintf(pinfo->cinfo->col_buf[col], COL_MAX_LEN, "%u", port);
+    if (is_src)
+      strcpy(pinfo->cinfo->col_expr[col], "udp.srcport");
+    else
+      strcpy(pinfo->cinfo->col_expr[col], "udp.dstport");
+    snprintf(pinfo->cinfo->col_expr_val[col], COL_MAX_LEN, "%u", port);
+    pinfo->cinfo->col_expr_val[col][COL_MAX_LEN - 1] = '\0';
     break;
 
   default:
@@ -458,6 +510,8 @@ fill_in_columns(packet_info *pinfo)
     case COL_NUMBER:
       snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "%u", pinfo->fd->num);
       pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+      strcpy(pinfo->cinfo->col_expr[i], "frame.number");
+      strcpy(pinfo->cinfo->col_expr_val[i], pinfo->cinfo->col_buf[i]);
       break;
 
     case COL_CLS_TIME:
@@ -482,74 +536,74 @@ fill_in_columns(packet_info *pinfo)
 
     case COL_DEF_SRC:
     case COL_RES_SRC:  /* COL_DEF_SRC is currently just like COL_RES_SRC */
-      col_set_addr(pinfo, i, &pinfo->src, TRUE);
+      col_set_addr(pinfo, i, &pinfo->src, TRUE, TRUE);
       break;
 
     case COL_UNRES_SRC:
-      col_set_addr(pinfo, i, &pinfo->src, FALSE);
+      col_set_addr(pinfo, i, &pinfo->src, FALSE, TRUE);
       break;
 
     case COL_DEF_DL_SRC:
     case COL_RES_DL_SRC:
-      col_set_addr(pinfo, i, &pinfo->dl_src, TRUE);
+      col_set_addr(pinfo, i, &pinfo->dl_src, TRUE, TRUE);
       break;
 
     case COL_UNRES_DL_SRC:
-      col_set_addr(pinfo, i, &pinfo->dl_src, FALSE);
+      col_set_addr(pinfo, i, &pinfo->dl_src, FALSE, TRUE);
       break;
 
     case COL_DEF_NET_SRC:
     case COL_RES_NET_SRC:
-      col_set_addr(pinfo, i, &pinfo->net_src, TRUE);
+      col_set_addr(pinfo, i, &pinfo->net_src, TRUE, TRUE);
       break;
 
     case COL_UNRES_NET_SRC:
-      col_set_addr(pinfo, i, &pinfo->net_src, FALSE);
+      col_set_addr(pinfo, i, &pinfo->net_src, FALSE, TRUE);
       break;
 
     case COL_DEF_DST:
     case COL_RES_DST:  /* COL_DEF_DST is currently just like COL_RES_DST */
-      col_set_addr(pinfo, i, &pinfo->dst, TRUE);
+      col_set_addr(pinfo, i, &pinfo->dst, TRUE, FALSE);
       break;
 
     case COL_UNRES_DST:
-      col_set_addr(pinfo, i, &pinfo->dst, FALSE);
+      col_set_addr(pinfo, i, &pinfo->dst, FALSE, FALSE);
       break;
 
     case COL_DEF_DL_DST:
     case COL_RES_DL_DST:
-      col_set_addr(pinfo, i, &pinfo->dl_dst, TRUE);
+      col_set_addr(pinfo, i, &pinfo->dl_dst, TRUE, FALSE);
       break;
 
     case COL_UNRES_DL_DST:
-      col_set_addr(pinfo, i, &pinfo->dl_dst, FALSE);
+      col_set_addr(pinfo, i, &pinfo->dl_dst, FALSE, FALSE);
       break;
 
     case COL_DEF_NET_DST:
     case COL_RES_NET_DST:
-      col_set_addr(pinfo, i, &pinfo->net_dst, TRUE);
+      col_set_addr(pinfo, i, &pinfo->net_dst, TRUE, FALSE);
       break;
 
     case COL_UNRES_NET_DST:
-      col_set_addr(pinfo, i, &pinfo->net_dst, FALSE);
+      col_set_addr(pinfo, i, &pinfo->net_dst, FALSE, FALSE);
       break;
 
     case COL_DEF_SRC_PORT:
     case COL_RES_SRC_PORT:     /* COL_DEF_SRC_PORT is currently just like COL_RES_SRC_PORT */
-      col_set_port(pinfo, i, pinfo->ptype, pinfo->srcport, TRUE);
+      col_set_port(pinfo, i, pinfo->ptype, pinfo->srcport, TRUE, TRUE);
       break;
 
     case COL_UNRES_SRC_PORT:
-      col_set_port(pinfo, i, pinfo->ptype, pinfo->srcport, FALSE);
+      col_set_port(pinfo, i, pinfo->ptype, pinfo->srcport, FALSE, TRUE);
       break;
 
     case COL_DEF_DST_PORT:
     case COL_RES_DST_PORT:     /* COL_DEF_DST_PORT is currently just like COL_RES_DST_PORT */
-      col_set_port(pinfo, i, pinfo->ptype, pinfo->destport, TRUE);
+      col_set_port(pinfo, i, pinfo->ptype, pinfo->destport, TRUE, FALSE);
       break;
 
     case COL_UNRES_DST_PORT:
-      col_set_port(pinfo, i, pinfo->ptype, pinfo->destport, FALSE);
+      col_set_port(pinfo, i, pinfo->ptype, pinfo->destport, FALSE, FALSE);
       break;
 
     case COL_PROTOCOL: /* currently done by dissectors */
@@ -559,6 +613,8 @@ fill_in_columns(packet_info *pinfo)
     case COL_PACKET_LENGTH:
       snprintf(pinfo->cinfo->col_buf[i], COL_MAX_LEN, "%u", pinfo->fd->pkt_len);
       pinfo->cinfo->col_data[i] = pinfo->cinfo->col_buf[i];
+      strcpy(pinfo->cinfo->col_expr[i], "frame.pkt_len");
+      strcpy(pinfo->cinfo->col_expr_val[i], pinfo->cinfo->col_buf[i]);
       break;
 
     case NUM_COL_FMTS: /* keep compiler happy - shouldn't get here */
index 48ad0383d1dd6aaa7863872b327a34ad52735016..cfe0c24a5c5a019da775f0b586d2af18a7b3ac68 100644 (file)
@@ -1,7 +1,7 @@
 /* column.h
  * Definitions for column structures and routines
  *
- * $Id: column_info.h,v 1.1 2001/04/01 03:42:00 hagbard Exp $
+ * $Id: column_info.h,v 1.2 2002/01/11 08:21:00 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -40,6 +40,8 @@ typedef struct _column_info {
   gchar    **col_title; /* Column titles */
   gchar    **col_data;  /* Column data */
   gchar    **col_buf;   /* Buffer into which to copy data for column */
+  gchar    **col_expr;  /* Filter expression */
+  gchar    **col_expr_val;  /* Value for filter expression */
   gboolean   writable;  /* Are we stil writing to the columns? */
 } column_info;
 
index 2c563a827b2395897c729adb34b87c33d80847d0..d4686fe9a93175a4eb2161c73a7968060c53af74 100644 (file)
@@ -1,7 +1,7 @@
 /* keys.h
  * Key definitions for various objects
  *
- * $Id: keys.h,v 1.11 2000/08/20 21:55:57 deniel Exp $
+ * $Id: keys.h,v 1.12 2002/01/11 08:21:02 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@zing.org>
@@ -32,6 +32,9 @@
 #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_MPACKET_LIST_KEY       "menu_packet_list"
+#define E_MPACKET_LIST_ROW_KEY   "menu_packet_list_row"
+#define E_MPACKET_LIST_COL_KEY   "menu_packet_list_col"
 
 #define PRINT_CMD_LB_KEY          "printer_command_label"
 #define PRINT_CMD_TE_KEY          "printer_command_entry"
index c59570fbb15336d081be170c61ee562844ccfc17..d1ec5fb830e2b2b5796dbece16ed963fc6ad01da 100644 (file)
@@ -1,6 +1,6 @@
 /* main.c
  *
- * $Id: main.c,v 1.227 2002/01/11 07:40:31 guy Exp $
+ * $Id: main.c,v 1.228 2002/01/11 08:21:02 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -222,25 +222,310 @@ set_fonts(GdkFont *regular, GdkFont *bold)
 
 /* Match selected byte pattern */
 void
-match_selected_cb(GtkWidget *w, gpointer data)
+match_selected_cb_do(gpointer data, int action, gchar *text)
 {
-    char               *buf;
+    char               *ptr;
     GtkWidget          *filter_te;
 
-    filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
+    if (!text)
+       return;
+    g_assert(data);
+    filter_te = gtk_object_get_data(GTK_OBJECT(data), E_DFILTER_TE_KEY);
+    g_assert(filter_te);
 
-    buf = proto_alloc_dfilter_string(finfo_selected, cfile.pd);
+    ptr = gtk_entry_get_text(GTK_ENTRY(filter_te));
+
+    switch (action&MATCH_SELECTED_MASK) {
+
+    case MATCH_SELECTED_REPLACE:
+       ptr = text;
+       break;
+
+    case MATCH_SELECTED_AND:
+       if ((!ptr) || (0 == strlen(ptr)))
+           ptr = text;
+       else
+           ptr = g_strconcat("(", ptr, ") && (", text, ")", NULL);
+       break;
+
+    case MATCH_SELECTED_OR:
+       if ((!ptr) || (0 == strlen(ptr)))
+           ptr = text;
+       else
+           ptr = g_strconcat("(", ptr, ") || (", text, ")", NULL);
+       break;
+
+    case MATCH_SELECTED_NOT:
+       ptr = g_strconcat("!(", text, ")", NULL);
+       break;
+
+    case MATCH_SELECTED_AND_NOT:
+       if ((!ptr) || (0 == strlen(ptr)))
+           ptr = g_strconcat("!(", text, ")", NULL);
+       else
+           ptr = g_strconcat("(", ptr, ") && !(", text, ")", NULL);
+       break;
+
+    case MATCH_SELECTED_OR_NOT:
+       if ((!ptr) || (0 == strlen(ptr)))
+           ptr = g_strconcat("!(", text, ")", NULL);
+       else
+           ptr = g_strconcat("(", ptr, ") || !(", text, ")", NULL);
+       break;
+
+    default:
+       break;
+    }
 
     /* create a new one and set the display filter entry accordingly */
-    gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
+    gtk_entry_set_text(GTK_ENTRY(filter_te), ptr);
 
     /* Run the display filter so it goes in effect. */
-    filter_packets(&cfile, buf);
+    if (action&MATCH_SELECTED_APPLY_NOW)
+       filter_packets(&cfile, ptr);
+
+    /* Don't g_free(text) here. filter_packets() will do it the next time
+       it's called. */
+    /* XXX - what about ptr? */
+}
+
+void
+match_selected_cb_replace(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+match_selected_cb_and(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+match_selected_cb_or(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+match_selected_cb_not(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+match_selected_cb_and_not(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+match_selected_cb_or_not(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_OR_NOT,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+prepare_selected_cb_replace(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_REPLACE,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+prepare_selected_cb_and(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_AND,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+prepare_selected_cb_or(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_OR,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+prepare_selected_cb_not(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_NOT,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
 
-    /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
+void
+prepare_selected_cb_and_not(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_AND_NOT,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+void
+prepare_selected_cb_or_not(GtkWidget *w, gpointer data)
+{
+    if (finfo_selected)
+       match_selected_cb_do((data ? data : w),
+           MATCH_SELECTED_OR_NOT,
+           proto_alloc_dfilter_string(finfo_selected, cfile.pd));
+}
+
+static gchar *
+get_text_from_packet_list(gpointer data)
+{
+    gint       row = (gint)gtk_object_get_data(GTK_OBJECT(data), E_MPACKET_LIST_ROW_KEY);
+    gint       column = (gint)gtk_object_get_data(GTK_OBJECT(data), E_MPACKET_LIST_COL_KEY);
+    frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
+    epan_dissect_t *edt;
+    gchar      *buf=NULL;
+    int         len;
+
+    if (fdata != NULL) {
+       wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
+                      cfile.pd, fdata->cap_len);
+
+       edt = epan_dissect_new(FALSE, FALSE);
+       epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
+                        &cfile.cinfo);
+       epan_dissect_fill_in_columns(edt);
+
+       if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
+           strlen(cfile.cinfo.col_expr_val[column]) != 0) {
+           len = strlen(cfile.cinfo.col_expr[column]) +
+                 strlen(cfile.cinfo.col_expr_val[column]) + 5;
+           buf = g_malloc0(len);
+           snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
+                    cfile.cinfo.col_expr_val[column]);
+       }
+
+       epan_dissect_free(edt);
+    }
+           
+    return buf;
+}
+
+void
+match_selected_cb_replace2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
+        get_text_from_packet_list(data));
+}
+
+void
+match_selected_cb_and2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
+        get_text_from_packet_list(data));
+}
+
+void
+match_selected_cb_or2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
+        get_text_from_packet_list(data));
+}
+
+void
+match_selected_cb_not2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
+        get_text_from_packet_list(data));
+}
+
+void
+match_selected_cb_and_not2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
+        get_text_from_packet_list(data));
+}
+
+void
+match_selected_cb_or_not2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
+        get_text_from_packet_list(data));
 }
 
+void
+prepare_selected_cb_replace2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_REPLACE,
+        get_text_from_packet_list(data));
+}
 
+void
+prepare_selected_cb_and2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_AND,
+        get_text_from_packet_list(data));
+}
+
+void
+prepare_selected_cb_or2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_OR,
+        get_text_from_packet_list(data));
+}
+
+void
+prepare_selected_cb_not2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_NOT,
+        get_text_from_packet_list(data));
+}
+
+void
+prepare_selected_cb_and_not2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_AND_NOT,
+        get_text_from_packet_list(data));
+}
+
+void
+prepare_selected_cb_or_not2(GtkWidget *w, gpointer data)
+{
+    match_selected_cb_do(data,
+        MATCH_SELECTED_OR_NOT,
+        get_text_from_packet_list(data));
+}
 
 /* Run the current display filter on the current packet set, and
    redisplay. */
@@ -251,8 +536,10 @@ filter_activate_cb(GtkWidget *w, gpointer data)
   GList     *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
   GList     *li, *nl = NULL;
   gboolean   add_filter = TRUE;
+  char *s = NULL;
   
-  char *s = gtk_entry_get_text(GTK_ENTRY(w));
+  g_assert(data);
+  s = gtk_entry_get_text(GTK_ENTRY(data));
   
   /* 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
@@ -287,7 +574,6 @@ filter_reset_cb(GtkWidget *w, gpointer 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);
 }
 
@@ -1457,6 +1743,8 @@ main(int argc, char *argv[])
       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
     else
       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
+    cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
+    cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
   }
 
 #ifdef HAVE_LIBPCAP
@@ -1872,6 +2160,7 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
                       *stat_hbox, *column_lb,
                       *filter_bt, *filter_cm, *filter_te,
+                      *filter_apply,
                       *filter_reset;
   GList               *filter_list = NULL;
   GtkAccelGroup       *accel;
@@ -2016,24 +2305,45 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
-    GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
+    GTK_SIGNAL_FUNC(filter_activate_cb), filter_te);
   gtk_widget_show(filter_cm);
 
   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_SIGNAL_FUNC(filter_reset_cb), NULL);
   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
   gtk_widget_show(filter_reset);
 
+  filter_apply = gtk_button_new_with_label("Apply");
+  gtk_object_set_data(GTK_OBJECT(filter_apply), E_DFILTER_CM_KEY, filter_cm);
+  gtk_object_set_data(GTK_OBJECT(filter_apply), E_DFILTER_FL_KEY, filter_list);
+  gtk_signal_connect(GTK_OBJECT(filter_apply), "clicked",
+                     GTK_SIGNAL_FUNC(filter_activate_cb), filter_te);
+  gtk_box_pack_start(GTK_BOX(stat_hbox), filter_apply, FALSE, TRUE, 1);
+  gtk_widget_show(filter_apply);
+
   /* 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);
+  set_menu_object_data("/Display/Match/Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Match/Not Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Match/And Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Match/Or Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Match/And Not Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Match/Or Not Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Prepare/Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Prepare/Not Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Prepare/And Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Prepare/Or Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Prepare/And Not Selected", E_DFILTER_TE_KEY, filter_te);
+  set_menu_object_data("/Display/Prepare/Or Not Selected", 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_MPACKET_LIST_KEY, packet_list);
 
   info_bar = gtk_statusbar_new();
   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
index 65662d3bd02c782ce24aeaa588b64f412f1f7b77..363a8340fa86e409f4dcd6e9f6023a7848b90fb6 100644 (file)
@@ -1,7 +1,7 @@
 /* main.h
  * Global defines, etc.
  *
- * $Id: main.h,v 1.25 2001/12/31 04:41:50 gerald Exp $
+ * $Id: main.h,v 1.26 2002/01/11 08:21:02 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #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_MASK            0x0ff
+#define MATCH_SELECTED_APPLY_NOW       0x100
+
 typedef struct _selection_info {
   GtkWidget *tree;
   GtkWidget *text;
@@ -51,7 +61,30 @@ typedef struct _selection_info {
 extern GtkStyle *item_style;
 
 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 prepare_selected_cb_replace( GtkWidget *, gpointer);
+void prepare_selected_cb_and( GtkWidget *, gpointer);
+void prepare_selected_cb_or( GtkWidget *, gpointer);
+void prepare_selected_cb_not( GtkWidget *, gpointer);
+void prepare_selected_cb_and_not( GtkWidget *, gpointer);
+void prepare_selected_cb_or_not( GtkWidget *, gpointer);
+void match_selected_cb_replace2( GtkWidget *, gpointer);
+void match_selected_cb_and2( GtkWidget *, gpointer);
+void match_selected_cb_or2( GtkWidget *, gpointer);
+void match_selected_cb_not2( GtkWidget *, gpointer);
+void match_selected_cb_and_not2( GtkWidget *, gpointer);
+void match_selected_cb_or_not2( GtkWidget *, gpointer);
+void prepare_selected_cb_replace2( GtkWidget *, gpointer);
+void prepare_selected_cb_and2( GtkWidget *, gpointer);
+void prepare_selected_cb_or2( GtkWidget *, gpointer);
+void prepare_selected_cb_not2( GtkWidget *, gpointer);
+void prepare_selected_cb_and_not2( GtkWidget *, gpointer);
+void prepare_selected_cb_or_not2( GtkWidget *, gpointer);
 void file_quit_cmd_cb(GtkWidget *, gpointer);
 void file_print_cmd_cb(GtkWidget *, gpointer);
 void file_print_packet_cmd_cb(GtkWidget *, gpointer);
index d9cf44cbd6f6a3e5332bdad150b3a1653ecf7773..76e8e579afe6be292fc80e71ba0cde0a94e673b0 100644 (file)
@@ -1,7 +1,7 @@
 /* menu.c
  * Menu routines
  *
- * $Id: menu.c,v 1.59 2002/01/11 07:40:31 guy Exp $
+ * $Id: menu.c,v 1.60 2002/01/11 08:21:02 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -141,7 +141,20 @@ static GtkItemFactoryEntry menu_items[] =
 #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/_Match", NULL, NULL, 0, "<Branch>" },
+  {"/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 Selected", NULL, GTK_MENU_FUNC(match_selected_cb_and), 0, NULL},
+  {"/Display/Match/_Or Selected", NULL, GTK_MENU_FUNC(match_selected_cb_or), 0, NULL},
+  {"/Display/Match/A_nd Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_and_not), 0, NULL},
+  {"/Display/Match/O_r Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_or_not), 0, NULL},
+  {"/Display/_Prepare", NULL, NULL, 0, "<Branch>" },
+  {"/Display/Prepare/_Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_replace), 0, NULL},
+  {"/Display/Prepare/_Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_not), 0, NULL},
+  {"/Display/Prepare/_And Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_and), 0, NULL},
+  {"/Display/Prepare/_Or Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_or), 0, NULL},
+  {"/Display/Prepare/A_nd Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_and_not), 0, NULL},
+  {"/Display/Prepare/O_r Not Selected", NULL, GTK_MENU_FUNC(prepare_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},
@@ -178,6 +191,20 @@ static GtkItemFactoryEntry packet_list_menu_items[] =
        {"/Display Filters...", NULL, GTK_MENU_FUNC(dfilter_dialog_cb), 0, NULL},
        {"/<separator>", NULL, NULL, 0, "<Separator>"},
        {"/Mark Frame", NULL, GTK_MENU_FUNC(mark_frame_cb), 0, NULL},
+        {"/Match", NULL, NULL, 0, "<Branch>" },
+        {"/Match/_Selected", NULL, GTK_MENU_FUNC(match_selected_cb_replace2), 0, NULL},
+        {"/Match/_Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_not2), 0, NULL},
+        {"/Match/_And Selected", NULL, GTK_MENU_FUNC(match_selected_cb_and2), 0, NULL},
+        {"/Match/_Or Selected", NULL, GTK_MENU_FUNC(match_selected_cb_or2), 0, NULL},
+        {"/Match/A_nd Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_and_not2), 0, NULL},
+        {"/Match/O_r Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_or_not2), 0, NULL},
+        {"/Prepare", NULL, NULL, 0, "<Branch>" },
+        {"/Prepare/_Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_replace2), 0, NULL},
+        {"/Prepare/_Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_not2), 0, NULL},
+        {"/Prepare/_And Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_and2), 0, NULL},
+        {"/Prepare/_Or Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_or2), 0, NULL},
+        {"/Prepare/A_nd Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_and_not2), 0, NULL},
+        {"/Prepare/O_r Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_or_not2), 0, NULL},
        {"/<separator>", NULL, NULL, 0, "<Separator>"},
        {"/Colorize Display...", NULL, GTK_MENU_FUNC(color_display_cb), 0, NULL},
        {"/Print...", NULL, GTK_MENU_FUNC(file_print_cmd_cb), 0, NULL},
@@ -193,7 +220,20 @@ static GtkItemFactoryEntry tree_view_menu_items[] =
        {"/<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},
+        {"/Match", NULL, NULL, 0, "<Branch>" },
+        {"/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 Selected", NULL, GTK_MENU_FUNC(match_selected_cb_and), 0, NULL},
+        {"/Match/_Or Selected", NULL, GTK_MENU_FUNC(match_selected_cb_or), 0, NULL},
+        {"/Match/A_nd Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_and_not), 0, NULL},
+        {"/Match/O_r Not Selected", NULL, GTK_MENU_FUNC(match_selected_cb_or_not), 0, NULL},
+        {"/Prepare", NULL, NULL, 0, "<Branch>" },
+        {"/Prepare/_Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_replace), 0, NULL},
+        {"/Prepare/_Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_not), 0, NULL},
+        {"/Prepare/_And Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_and), 0, NULL},
+        {"/Prepare/_Or Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_or), 0, NULL},
+        {"/Prepare/A_nd Not Selected", NULL, GTK_MENU_FUNC(prepare_selected_cb_and_not), 0, NULL},
+        {"/Prepare/O_r Not Selected", NULL, GTK_MENU_FUNC(prepare_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}
@@ -242,17 +282,17 @@ menus_init(void) {
     /* 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_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, NULL, 2);
+    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, NULL, 2);
+    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);
     
@@ -282,18 +322,40 @@ set_menu_sensitivity_meat(GtkItemFactory *ifactory, gchar *path, gint val) {
        }
 }
 
+/* Enable/disable menu sensitivity                       */
+/* /menu/path            - old functionality             */
+/* <MenuName>/menu/path  - new functionality             */
+/* MenuName: <Main>, <PacketList>, <TreeView>, <HexDump> */
 static void
 set_menu_sensitivity (gchar *path, gint val) {
   GSList *menu_list = popup_menu_list;
-  gchar *shortpath = strrchr(path, '/');
-
-  set_menu_sensitivity_meat(factory, path, val);
-
-  while (menu_list != NULL) {
-       set_menu_sensitivity_meat(menu_list->data, shortpath, val);
-       menu_list = g_slist_next(menu_list);
+  gchar *prefix;
+  gchar *shortpath;
+
+  if ('<' == *path) {
+    /* New functionality => selective enable/disable per menu */
+    prefix=strchr(path, '/');
+    shortpath=strrchr(prefix, '/');
+
+    if (0 == strncmp(path, "<Main>", 6))
+      set_menu_sensitivity_meat(factory, prefix, val);
+    else if (0 == strncmp(path, "<PacketList>", 12))
+      set_menu_sensitivity_meat(packet_list_menu_factory, shortpath, val);
+    else if (0 == strncmp(path, "<TreeView>", 10))
+      set_menu_sensitivity_meat(tree_view_menu_factory, shortpath, val);
+    else if (0 == strncmp(path, "<HexDump>", 9))
+      set_menu_sensitivity_meat(hexdump_menu_factory, shortpath, val);
+  } else {
+    /* Old functionality => enable/disable all menus with same shortpath */
+    shortpath = strrchr(path, '/');
+
+    set_menu_sensitivity_meat(factory, path, val);
+
+    while (menu_list != NULL) {
+         set_menu_sensitivity_meat(menu_list->data, shortpath, val);
+         menu_list = g_slist_next(menu_list);
+    }
   }
-  
 }
 
 void
@@ -322,6 +384,8 @@ popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
        GtkWidget *menu = NULL;
        GdkEventButton *event_button = NULL;
+       GtkCList *packet_list = NULL;
+       gint row, column;
 
        if(widget == NULL || event == NULL || data == NULL) {
                return FALSE;
@@ -334,6 +398,19 @@ popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
         * I guess, like a CList with one column(?) and the expander widget
         * as a pixmap.
         */
+       /* Check if we are on packet_list object */
+       if (widget == gtk_object_get_data(GTK_OBJECT(popup_menu_object),
+               E_MPACKET_LIST_KEY)) {
+         packet_list=GTK_CLIST(widget);
+         if (gtk_clist_get_selection_info(GTK_CLIST(packet_list),
+             ((GdkEventButton *)event)->x,
+             ((GdkEventButton *)event)->y,&row,&column)) {
+           gtk_object_set_data(GTK_OBJECT(popup_menu_object),
+               E_MPACKET_LIST_ROW_KEY, (gpointer *)row);
+           gtk_object_set_data(GTK_OBJECT(popup_menu_object),
+               E_MPACKET_LIST_COL_KEY, (gpointer *)column);
+         }
+       }
        menu = (GtkWidget *)data;
        if(event->type == GDK_BUTTON_PRESS) {
                event_button = (GdkEventButton *) event;
@@ -392,6 +469,8 @@ set_menus_for_captured_packets(gboolean have_captured_packets)
   set_menu_sensitivity("/Display/Colorize Display...", have_captured_packets);
   set_menu_sensitivity("/Tools/Summary", have_captured_packets);
   set_menu_sensitivity("/Tools/Protocol Hierarchy Statistics", have_captured_packets);
+  set_menu_sensitivity("<PacketList>/Display/Match", have_captured_packets);
+  set_menu_sensitivity("<PacketList>/Display/Prepare", have_captured_packets);
 }
 
 /* Enable or disable menu items based on whether a packet is selected. */
@@ -416,7 +495,7 @@ set_menus_for_selected_packet(gboolean have_selected_packet)
 }
 
 /* Enable or disable menu items based on whether a tree row is selected
-   and and on whether a "Match Selected" can be done. */
+   and and on whether a "Match" can be done. */
 void
 set_menus_for_selected_tree_row(gboolean have_selected_tree)
 {
@@ -429,10 +508,20 @@ set_menus_for_selected_tree_row(gboolean have_selected_tree)
        } else {
          properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
        }
-       set_menu_sensitivity("/Display/Match Selected",
+       set_menu_sensitivity("<Main>/Display/Match",
+         proto_can_match_selected(finfo_selected));
+       set_menu_sensitivity("<TreeView>/Display/Match",
+         proto_can_match_selected(finfo_selected));
+       set_menu_sensitivity("<Main>/Display/Prepare",
          proto_can_match_selected(finfo_selected));
-  } else
-       set_menu_sensitivity("/Display/Match Selected", FALSE);
+       set_menu_sensitivity("<TreeView>/Display/Prepare",
+         proto_can_match_selected(finfo_selected));
+  } else {
+       set_menu_sensitivity("<Main>/Display/Match", FALSE);
+       set_menu_sensitivity("<TreeView>/Display/Match", FALSE);
+       set_menu_sensitivity("<Main>/Display/Prepare", FALSE);
+       set_menu_sensitivity("<TreeView>/Display/Prepare", FALSE);
+  }
 
   set_menu_sensitivity("/Protocol Properties...", have_selected_tree && properties);
 }