Ethereal-dev: Re: [Ethereal-dev] New feature for ethereal
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: David Hampton <dhampton@xxxxxxx>
Date: Mon, 22 Jan 2001 09:07:51 -0800
Guy Harris wrote: > > On Sat, Jan 20, 2001 at 09:29:35PM -0800, David Hampton wrote: > > You're absolutely correct. Do you want me to correct it and resubmit > > the diffs? > > Yes, and change "No not decode" to "Do not decode" (which is what the > comments in the code say it should be) while you're at it. Done. Here are the new diffs. David
Index: packet-ethertype.c =================================================================== RCS file: /cvsroot/ethereal/packet-ethertype.c,v retrieving revision 1.11 diff -u -r1.11 packet-ethertype.c --- packet-ethertype.c 2001/01/18 08:38:10 1.11 +++ packet-ethertype.c 2001/01/22 17:04:27 @@ -117,6 +117,8 @@ /* Tvbuff for the payload after the Ethernet type. */ next_tvb = tvb_new_subset(tvb, offset_after_etype, -1, -1); + pinfo->ethertype = etype; + /* Remember how much data there is in it. */ length_before = tvb_reported_length(next_tvb); Index: epan/packet.c =================================================================== RCS file: /cvsroot/ethereal/epan/packet.c,v retrieving revision 1.18 diff -u -r1.18 packet.c --- packet.c 2001/01/13 06:34:33 1.18 +++ packet.c 2001/01/22 17:04:29 @@ -1009,6 +1009,7 @@ pi.net_dst.type = AT_NONE; pi.src.type = AT_NONE; pi.dst.type = AT_NONE; + pi.ethertype = 0; pi.ipproto = 0; pi.ptype = PT_NONE; pi.srcport = 0; @@ -1173,8 +1174,18 @@ dissector_t new; } dissector; int proto_index; -} dtbl_entry_t; +} dissector_entry_t; +struct dtbl_entry { + dissector_entry_t initial; + dissector_entry_t current; +}; + +static void +dissect_null(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ +} + /* Finds a dissector table by field name. */ static dissector_table_t find_dissector_table(const char *name) @@ -1196,9 +1207,11 @@ g_assert( sub_dissectors); dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); - dtbl_entry->is_old_dissector = TRUE; - dtbl_entry->dissector.old = dissector; - dtbl_entry->proto_index = proto; + dtbl_entry->current.is_old_dissector = TRUE; + dtbl_entry->current.dissector.old = dissector; + dtbl_entry->current.proto_index = proto; + dtbl_entry->initial = dtbl_entry->current; + proto_set_protocol_dissector(proto, dissector); /* do the table insertion */ g_hash_table_insert( sub_dissectors, GUINT_TO_POINTER( pattern), @@ -1216,9 +1229,11 @@ g_assert( sub_dissectors); dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); - dtbl_entry->is_old_dissector = FALSE; - dtbl_entry->dissector.new = dissector; - dtbl_entry->proto_index = proto; + dtbl_entry->current.is_old_dissector = FALSE; + dtbl_entry->current.dissector.new = dissector; + dtbl_entry->current.proto_index = proto; + dtbl_entry->initial = dtbl_entry->current; + proto_set_protocol_dissector(proto, dissector); /* do the table insertion */ g_hash_table_insert( sub_dissectors, GUINT_TO_POINTER( pattern), @@ -1288,6 +1303,78 @@ } } +void +dissector_change(const char *name, guint32 pattern, dissector_t dissector, + gboolean old, int proto) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + /* + * See if the entry already exists. If so, reuse it. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + if (dtbl_entry != NULL) { + dtbl_entry->current.is_old_dissector = old; + dtbl_entry->current.dissector.new = dissector ? dissector : dissect_null; + dtbl_entry->current.proto_index = proto; + return; + } + + /* + * Don't create an entry if there is no dissector - I.E. the + * user said not to decode something that wasn't being decoded + * in the first place. + */ + if (dissector == NULL) + return; + + dtbl_entry = g_malloc(sizeof (dtbl_entry_t)); + dtbl_entry->initial.is_old_dissector = FALSE; + dtbl_entry->initial.dissector.old = NULL; + dtbl_entry->initial.proto_index = -1; + dtbl_entry->current.is_old_dissector = old; + dtbl_entry->current.dissector.new = dissector; + dtbl_entry->current.proto_index = proto; + +/* do the table insertion */ + g_hash_table_insert( sub_dissectors, GUINT_TO_POINTER( pattern), + (gpointer)dtbl_entry); +} + +void +dissector_reset(const char *name, guint32 pattern) +{ + dissector_table_t sub_dissectors = find_dissector_table( name); + dtbl_entry_t *dtbl_entry; + +/* sanity check */ + g_assert( sub_dissectors); + + /* + * Find the entry. + */ + dtbl_entry = g_hash_table_lookup(sub_dissectors, + GUINT_TO_POINTER(pattern)); + + if (dtbl_entry == NULL) + return; + + /* + * Found - is there an initial value? + */ + if (dtbl_entry->initial.dissector.new != NULL) { + dtbl_entry->current = dtbl_entry->initial; + } else { + g_hash_table_remove(sub_dissectors, GUINT_TO_POINTER(pattern)); + g_free(dtbl_entry); + } +} + /* Look for a given port in a given dissector table and, if found, call the dissector with the arguments supplied, and return TRUE, otherwise return FALSE. @@ -1309,8 +1396,8 @@ /* * Is this protocol enabled? */ - if (dtbl_entry->proto_index != -1 && - !proto_is_protocol_enabled(dtbl_entry->proto_index)) { + if (dtbl_entry->current.proto_index != -1 && + !proto_is_protocol_enabled(dtbl_entry->current.proto_index)) { /* * No - pretend this dissector didn't exist, * so that other dissectors might have a chance @@ -1325,8 +1412,8 @@ saved_proto = pi.current_proto; saved_match_port = pi.match_port; pi.match_port = port; - if (dtbl_entry->is_old_dissector) - (*dtbl_entry->dissector.old)(pd, offset, fd, tree); + if (dtbl_entry->current.is_old_dissector) + (*dtbl_entry->current.dissector.old)(pd, offset, fd, tree); else { /* * Old dissector calling new dissector; use @@ -1337,12 +1424,12 @@ * let the "offset" argument handle stepping * through the packet? */ - if (dtbl_entry->proto_index != -1) { + if (dtbl_entry->current.proto_index != -1) { pi.current_proto = - proto_get_protocol_short_name(dtbl_entry->proto_index); + proto_get_protocol_short_name(dtbl_entry->current.proto_index); } tvb = tvb_create_from_top(offset); - (*dtbl_entry->dissector.new)(tvb, &pi, tree); + (*dtbl_entry->current.dissector.new)(tvb, &pi, tree); } pi.current_proto = saved_proto; pi.match_port = saved_match_port; @@ -1367,8 +1454,8 @@ /* * Is this protocol enabled? */ - if (dtbl_entry->proto_index != -1 && - !proto_is_protocol_enabled(dtbl_entry->proto_index)) { + if (dtbl_entry->current.proto_index != -1 && + !proto_is_protocol_enabled(dtbl_entry->current.proto_index)) { /* * No - pretend this dissector didn't exist, * so that other dissectors might have a chance @@ -1383,20 +1470,20 @@ saved_proto = pinfo->current_proto; saved_match_port = pinfo->match_port; pinfo->match_port = port; - if (dtbl_entry->is_old_dissector) { + if (dtbl_entry->current.is_old_dissector) { /* * New dissector calling old dissector; use * "tvb_compat()" to remap. */ tvb_compat(tvb, &pd, &offset); - (*dtbl_entry->dissector.old)(pd, offset, pinfo->fd, + (*dtbl_entry->current.dissector.old)(pd, offset, pinfo->fd, tree); } else { - if (dtbl_entry->proto_index != -1) { + if (dtbl_entry->current.proto_index != -1) { pinfo->current_proto = - proto_get_protocol_short_name(dtbl_entry->proto_index); + proto_get_protocol_short_name(dtbl_entry->current.proto_index); } - (*dtbl_entry->dissector.new)(tvb, pinfo, tree); + (*dtbl_entry->current.dissector.new)(tvb, pinfo, tree); } pinfo->current_proto = saved_proto; pinfo->match_port = saved_match_port; @@ -1405,6 +1492,168 @@ return FALSE; } +gboolean +dissector_get_old_flag (dtbl_entry_t *dtbl_entry) +{ + g_assert(dtbl_entry); + return(dtbl_entry->current.is_old_dissector); +} + +gint +dissector_get_proto (dtbl_entry_t *dtbl_entry) +{ + g_assert(dtbl_entry); + return(dtbl_entry->current.proto_index); +} + +gint +dissector_get_initial_proto (dtbl_entry_t *dtbl_entry) +{ + g_assert(dtbl_entry); + return(dtbl_entry->initial.proto_index); +} + +/**************************************************/ +/* */ +/* Routines to walk dissector tables */ +/* */ +/**************************************************/ + +typedef struct dissector_foreach_info { + gpointer caller_data; + DATFunc caller_func; + GHFunc next_func; + gchar *table_name; +} dissector_foreach_info_t; + +/* + * Walk all dissector tables calling a user supplied function on each + * entry. These three routines handle traversing the hash of hashes + * that is the dissector tables. + */ +static void +dissector_all_tables_foreach_func2 (gpointer key, gpointer value, gpointer user_data) +{ + dissector_foreach_info_t *info; + dtbl_entry_t *dtbl_entry; + + g_assert(value); + g_assert(user_data); + + dtbl_entry = value; + if (dtbl_entry->current.proto_index == -1) { + return; + } + + info = user_data; + info->caller_func(info->table_name, key, value, info->caller_data); +} + +static void +dissector_all_tables_foreach_func1 (gpointer key, gpointer value, gpointer user_data) +{ + GHashTable *hash_table; + dissector_foreach_info_t *info; + + g_assert(value); + g_assert(user_data); + + hash_table = value; + info = user_data; + info->table_name = (gchar*) key; + g_hash_table_foreach(hash_table, info->next_func, info); +} + +void +dissector_all_tables_foreach (DATFunc func, + gpointer user_data) +{ + dissector_foreach_info_t info; + + info.caller_data = user_data; + info.caller_func = func; + info.next_func = dissector_all_tables_foreach_func2; + g_hash_table_foreach(dissector_tables, dissector_all_tables_foreach_func1, &info); +} + +/* + * Walk one dissector table calling a user supplied function on each + * entry. + */ +void +dissector_table_foreach (char *name, + DATFunc func, + gpointer user_data) +{ + dissector_foreach_info_t info; + GHashTable *hash_table; + + hash_table = find_dissector_table(name); + g_assert(hash_table); + + info.table_name = name; + info.caller_func = func; + info.caller_data = user_data; + g_hash_table_foreach(hash_table, dissector_all_tables_foreach_func2, &info); +} + +/* + * Walk all dissector tables calling a user supplied function only on + * any entry that has been changed from its original state. These two + * routines (plus one above) handle traversing the hash of hashes that + * is the dissector tables. + */ +static void +dissector_all_tables_foreach_changed_func2 (gpointer key, gpointer value, gpointer user_data) +{ + dtbl_entry_t *dtbl_entry; + dissector_foreach_info_t *info; + + g_assert(value); + g_assert(user_data); + + dtbl_entry = value; + if (dtbl_entry->initial.proto_index == dtbl_entry->current.proto_index) { + return; + } + + info = user_data; + info->caller_func(info->table_name, key, value, info->caller_data); +} + +void +dissector_all_tables_foreach_changed (DATFunc func, + gpointer user_data) +{ + dissector_foreach_info_t info; + + info.caller_data = user_data; + info.caller_func = func; + info.next_func = dissector_all_tables_foreach_changed_func2; + g_hash_table_foreach(dissector_tables, dissector_all_tables_foreach_func1, &info); +} + +/* + * Walk one dissector table calling a user supplied function only on + * any entry that has been changed from its original state. + */ +void +dissector_table_foreach_changed (char *name, + DATFunc func, + gpointer user_data) +{ + dissector_foreach_info_t info; + GHashTable *hash_table; + + hash_table = find_dissector_table(name); + g_assert(hash_table); + + info.table_name = name; + info.caller_func = func; + info.caller_data = user_data; + g_hash_table_foreach(hash_table, dissector_all_tables_foreach_changed_func2, &info); +} + dissector_table_t register_dissector_table(const char *name) { @@ -1569,14 +1818,14 @@ * Nuke this and go back to storing a pointer to the dissector when * the last old-style dissector is gone. */ -typedef struct { +struct conv_dtbl_entry { gboolean is_old_dissector; union { old_dissector_t old; dissector_t new; } dissector; int proto_index; -} conv_dtbl_entry_t; +}; /* Finds a conversation dissector table by table name. */ static conv_dissector_list_t * @@ -1600,6 +1849,7 @@ dtbl_entry->is_old_dissector = TRUE; dtbl_entry->dissector.old = dissector; dtbl_entry->proto_index = proto; + proto_set_protocol_dissector(proto, dissector); /* do the table insertion */ *sub_dissectors = g_slist_append(*sub_dissectors, (gpointer)dtbl_entry); @@ -1618,6 +1868,7 @@ dtbl_entry->is_old_dissector = FALSE; dtbl_entry->dissector.new = dissector; dtbl_entry->proto_index = proto; + proto_set_protocol_dissector(proto, dissector); /* do the table insertion */ *sub_dissectors = g_slist_append(*sub_dissectors, (gpointer)dtbl_entry); @@ -1638,6 +1889,64 @@ *sub_dissectors = NULL; /* initially empty */ g_hash_table_insert(conv_dissector_lists, (gpointer)name, (gpointer) sub_dissectors); +} + +gboolean +conv_dissector_get_old_flag (conv_dtbl_entry_t *dtbl_entry) +{ + g_assert(dtbl_entry); + return(dtbl_entry->is_old_dissector); +} + +gint +conv_dissector_get_proto (conv_dtbl_entry_t *dtbl_entry) +{ + g_assert(dtbl_entry); + return(dtbl_entry->proto_index); +} + +void +dissector_conv_foreach (char *name, + DATFunc func, + gpointer user_data) +{ + conv_dissector_list_t *sub_dissectors = find_conv_dissector_list(name); + GSList *tmp; + + /* sanity check */ + g_assert(sub_dissectors != NULL); + + for (tmp = *sub_dissectors; tmp; tmp = g_slist_next(tmp)) { + func(name, 0, tmp->data, user_data); + } +} + +static void +dissector_all_conv_foreach_func1 (gpointer key, gpointer value, gpointer user_data) +{ + conv_dissector_list_t *sub_dissectors; + GSList *tmp; + dissector_foreach_info_t *info; + + g_assert(value); + g_assert(user_data); + + sub_dissectors = value; + for (tmp = *sub_dissectors; tmp; tmp = g_slist_next(tmp)) { + info = user_data; + info->caller_func(key, 0, tmp->data, info->caller_data); + } +} + +void +dissector_all_conv_foreach (DATFunc func, + gpointer user_data) +{ + dissector_foreach_info_t info; + + info.caller_data = user_data; + info.caller_func = func; + g_hash_table_foreach(conv_dissector_lists, dissector_all_conv_foreach_func1, &info); } /* Index: epan/packet.h =================================================================== RCS file: /cvsroot/ethereal/epan/packet.h,v retrieving revision 1.20 diff -u -r1.20 packet.h --- packet.h 2001/01/18 07:44:41 1.20 +++ packet.h 2001/01/22 17:04:29 @@ -170,6 +170,7 @@ address net_dst; /* network-layer destination address */ address src; /* source address (net if present, DL otherwise )*/ address dst; /* destination address (net if present, DL otherwise )*/ + guint32 ethertype; /* Ethernet Type Code, if this is an Ethernet packet */ guint32 ipproto; /* IP protocol, if this is an IP packet */ gboolean fragmented; /* TRUE if the protocol is only a fragment */ port_type ptype; /* type of the following two port numbers */ @@ -206,6 +207,18 @@ typedef void (*old_dissector_t)(const u_char *, int, frame_data *, proto_tree *); typedef void (*dissector_t)(tvbuff_t *, packet_info *, proto_tree *); +typedef void (*DATFunc) (gchar *table_name, gpointer key, gpointer value, gpointer user_data); + +/* Opaque structure - provides type checking but no access to components */ +typedef struct dtbl_entry dtbl_entry_t; + +gboolean dissector_get_old_flag (dtbl_entry_t *entry); +gint dissector_get_proto (dtbl_entry_t * entry); +gint dissector_get_initial_proto (dtbl_entry_t * entry); +void dissector_table_foreach_changed (char *name, DATFunc func, gpointer user_data); +void dissector_table_foreach (char *name, DATFunc func, gpointer user_data); +void dissector_all_tables_foreach_changed (DATFunc func, gpointer user_data); + /* a protocol uses the function to register a sub-dissector table */ dissector_table_t register_dissector_table(const char *name); @@ -221,6 +234,11 @@ void old_dissector_delete(const char *name, guint32 pattern, old_dissector_t dissector); void dissector_delete(const char *name, guint32 pattern, dissector_t dissector); +/* Reset a dissector in a sub-dissector table to its initial value. */ +void dissector_change(const char *abbrev, guint32 pattern, + dissector_t dissector, gboolean old, int proto); +void dissector_reset(const char *name, guint32 pattern); + /* Look for a given port in a given dissector table and, if found, call the dissector with the arguments supplied, and return TRUE, otherwise return FALSE. */ @@ -280,6 +298,14 @@ int proto); void conv_dissector_add(const char *name, dissector_t dissector, int proto); + +/* Opaque structure - provides type checking but no access to components */ +typedef struct conv_dtbl_entry conv_dtbl_entry_t; + +gboolean conv_dissector_get_old_flag (conv_dtbl_entry_t *entry); +gint conv_dissector_get_proto (conv_dtbl_entry_t * entry); +void dissector_conv_foreach(char *name, DATFunc func, gpointer user_data); +void dissector_all_conv_foreach(DATFunc func, gpointer user_data); /* Handle for dissectors you call directly. This handle is opaque outside of "packet.c". */ Index: epan/proto.c =================================================================== RCS file: /cvsroot/ethereal/epan/proto.c,v retrieving revision 1.4 diff -u -r1.4 proto.c --- proto.c 2001/01/03 06:55:58 1.4 +++ proto.c 2001/01/22 17:04:31 @@ -125,6 +125,7 @@ GList *last_field; /* pointer to end of list of fields */ gboolean is_enabled; /* TRUE if protocol is enabled */ gboolean can_disable; /* TRUE if protocol can be disabled */ + gpointer dissector; } protocol_t; /* List of all protocols */ @@ -1506,6 +1507,7 @@ protocol->fields = NULL; protocol->is_enabled = TRUE; /* protocol is enabled by default */ protocol->can_disable = TRUE; + protocol->dissector = NULL; protocols = g_list_insert_sorted(protocols, protocol, proto_compare_name); @@ -1595,6 +1597,8 @@ { protocol_t *protocol; + if (proto_id == -1) + return "(none)"; protocol = find_protocol_by_id(proto_id); return protocol->short_name; } @@ -1643,6 +1647,32 @@ protocol = find_protocol_by_id(proto_id); protocol->can_disable = FALSE; +} + +gpointer +proto_get_protocol_dissector(int proto_id) +{ + protocol_t *protocol; + + protocol = find_protocol_by_id(proto_id); + if (protocol == NULL) + return(NULL); + return protocol->dissector; +} + +void +proto_set_protocol_dissector(int proto_id, gpointer dissector) +{ + protocol_t *protocol; + + protocol = find_protocol_by_id(proto_id); + if (protocol != NULL) { + if (protocol->dissector != NULL) { + /* Already set */ + return; + } + protocol->dissector = dissector; + } } /* for use with static arrays only, since we don't allocate our own copies Index: epan/proto.h =================================================================== RCS file: /cvsroot/ethereal/epan/proto.h,v retrieving revision 1.3 diff -u -r1.3 proto.h --- proto.h 2001/01/03 06:55:59 1.3 +++ proto.h 2001/01/22 17:04:32 @@ -525,6 +525,9 @@ /* Disable disabling of protocol */ void proto_set_cant_disable(int proto_id); +gpointer proto_get_protocol_dissector(int proto_id); +void proto_set_protocol_dissector(int proto_id, gpointer dissector); + /* Get length of registered field according to field type. * 0 means undeterminable at registration time. * -1 means unknown field */ Index: gtk/Makefile.am =================================================================== RCS file: /cvsroot/ethereal/gtk/Makefile.am,v retrieving revision 1.32 diff -u -r1.32 Makefile.am --- Makefile.am 2001/01/02 01:32:21 1.32 +++ Makefile.am 2001/01/22 17:04:32 @@ -39,6 +39,8 @@ color_utils.h \ column_prefs.c \ column_prefs.h \ + decode_as_dlg.c \ + decode_as_dlg.h \ dfilter_expr_dlg.c \ dfilter_expr_dlg.h \ display_opts.c \ Index: gtk/decode_as_dlg.c =================================================================== RCS file: decode_as_dlg.c diff -N decode_as_dlg.c --- /dev/null Sat Oct 7 15:19:25 2000 +++ decode_as_dlg.c Mon Jan 22 11:04:33 2001 @@ -0,0 +1,1436 @@ +/* decode_as_dlg.c + * + * $Id: $ + * + * Routines to modify dissector tables on the fly. + * + * By David Hampton <dhampton@xxxxxxx> + * Copyright 2001 David Hampton + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gtk/gtk.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <errno.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include "decode_as_dlg.h" +#include "dlg_utils.h" +#include "globals.h" +#include "simple_dialog.h" +#include "packet.h" +#include "packet-ip.h" +#include "ui_util.h" + +#undef DEBUG + +/**************************************************/ +/* Typedefs & Enums */ +/**************************************************/ + +/* + * Enum used to track which radio button is currently selected in the + * dialog. These buttons are labeled "Decode" and "Do not decode". + */ +enum action_type { + /* The "Decode" button is currently selected. */ + E_DECODE_YES, + + /* The "Do not decode" button is currently selected. */ + E_DECODE_NO +}; + +/* + * Enum used to track which transport layer protocol menu item is + * currently selected in the dialog. These items are labeled "TCP", + * "UDP", and "TCP/UDP". + */ +enum tcpudp_type { + /* The "TCP" menu item is currently selected. */ + E_DECODE_TCP, + + /* The "TCP" menu item is currently selected. */ + E_DECODE_UDP, + + /* The "TCP/UDP" menu item is currently selected. */ + E_DECODE_TCPUDP +}; + +/* + * Enum used to track which transport layer port menu item is + * currently selected in the dialog. These items are labeled "source", + * "destination", and "source/destination". + */ +enum srcdst_type { + /* The "source port" menu item is currently selected. */ + E_DECODE_SPORT, + /* The "destination port" menu item is currently selected. */ + E_DECODE_DPORT, + /* The "source/destination port" menu item is currently selected. */ + E_DECODE_BPORT +}; + +#define E_DECODE_MIN_HEIGHT 100 +#define E_NOTEBOOK "notebook" + +#define E_MENU_TCPUDP "menu_tcp_udp" +#define E_MENU_SRCDST "menu_src_dst" + +#define E_PAGE_ACTION "notebook_page_action" +#define E_PAGE_CLIST "notebook_page_clist" +#define E_PAGE_TABLE "notebook_page_table_name" +#define E_PAGE_TITLE "notebook_page_title" +#define E_PAGE_VALUE "notebook_page_value" + +/* + * Clist columns for a "Select" clist + */ +#define E_CLIST_S_PROTO_NAME 0 +#define E_CLIST_S_TABLE 1 +#define E_CLIST_S_ISOLD 2 +/* The following is for debugging in decode_add_to_clist */ +#define E_CLIST_S_ISCONV 3 +#define E_CLIST_S_MAX E_CLIST_S_ISCONV +#define E_CLIST_S_COLUMNS (E_CLIST_S_MAX + 1) + +/* + * Clist columns for a "Display" clist + */ +#define E_CLIST_D_TABLE 0 +#define E_CLIST_D_PORT 1 +#define E_CLIST_D_INITIAL 2 +#define E_CLIST_D_CURRENT 3 +#define E_CLIST_D_MAX E_CLIST_D_CURRENT +#define E_CLIST_D_COLUMNS (E_CLIST_D_MAX + 1) + +/**************************************************/ +/* File Global Variables */ +/**************************************************/ + +/* + * Keep a static pointer to the current "Decode As" window. This is + * kept so that if somebody tries to do "Tools:Decode As" while + * there's already a "Decode As" window up, we just pop up the + * existing one, rather than creating a new one. + */ +static GtkWidget *decode_w = NULL; + +/* + * A static pointer to the current "Decode As:Show" window. This is + * kept so that if somebody tries to do clock the "Show Current" + * button or slect the "Display:User Specified Decodes" menu item + * while there's already a "Decode As:Show" window up, we just pop up + * the existing one, rather than creating a new one. + */ +static GtkWidget *decode_show_w = NULL; + +/* + * A list of the dialog items that only have meaning when the user has + * selected the "Decode" radio button. When the "Do not decode" + * button is selected these items should be dimmed. + */ +static GSList *decode_dimmable = NULL; + +/* + * A list of additional IP port numbers that are currently being + * decodes as either TCP or UDP. This is used to determine whether or + * not to include a "transport" page in the dialog notebook. This + * list never includes values for the standard TCP or UDP protocol + * numbers. + */ +static GSList *decode_as_tcpudp = NULL; + +/* + * Remember the "action" radio button that is currently selected in + * the dialog. This value is initialized when the dialog is created, + * modified in a callback routine, and read in the routine that + * handles a click in the "OK" button for the dialog. + */ +static enum action_type requested_action = -1; + +/**************************************************/ +/* Resett Changed Dissectors */ +/**************************************************/ + +/* + * Data structure for tracking which dissector need to be reset. This + * structure is necessary as a hash table entry cannot be removed + * while a g_hash_table_foreach walk is in progress. + */ +struct dissector_delete_item { + /* The name of the dissector table */ + const gchar *ddi_table_name; + /* The port number in the dissector table */ + gint ddi_port; +}; + +/* + * A typedef for the data structure to track the original dissector + * used for any given port on any given protocol. + */ +typedef struct dissector_delete_item dissector_delete_item_t; + +/* + * A list of dissectors that need to be reset. + */ +GSList *dissector_reset_list = NULL; + +/* + * This routine creates one entry in the list of protocol dissector + * that need to be reset. It is called by the g_hash_table_foreach + * routine once for each changed entry in a dissector table. + * Unfortunately it cannot delete the entry immediately as this screws + * up the foreach function, so it builds a list of dissectors to be + * reset once the foreach routine finishes. + * + * @param table_name The table name in which this dissector is found. + * + * @param key A pointer to the key for this entry in the dissector + * hash table. This is generally the numeric selector of the + * protocol, i.e. the ethernet type code, IP port number, TCP port + * number, etc. + * + * @param value A pointer to the value for this entry in the dissector + * hash table. This is an opaque pointer that can only be handed back + * to routine in the file packet.c + * + * @param user_data Unused. + */ +void +decode_build_reset_list (gchar *table_name, gpointer key, + gpointer value, gpointer user_data) +{ + dissector_delete_item_t *item; + + item = g_malloc(sizeof(dissector_delete_item_t)); + item->ddi_table_name = table_name; + item->ddi_port = GPOINTER_TO_INT(key); + dissector_reset_list = g_slist_prepend(dissector_reset_list, item); +} + +/* + * This routine resets any changed dissectors. it is called from the + * "Decode As" dialog box when the "reset changed" button is pressed. + * + * This routine uses auxiliary functions to perform the bulk of its + * work. These functions walk the dissector tables and build a list + * of dissectors that should be deleted. + * + * @param w Unknown + * @param data Unknown + */ +void +decode_reset_cb (GtkWidget * w, gpointer data) +{ + dissector_delete_item_t *item; + GSList *tmp; + + dissector_all_tables_foreach_changed(decode_build_reset_list, NULL); + + for (tmp = dissector_reset_list; tmp; tmp = g_slist_next(tmp)) { + item = tmp->data; + dissector_reset(item->ddi_table_name, item->ddi_port); + g_free(item); + } + g_slist_free(dissector_reset_list); + dissector_reset_list = NULL; + + simple_dialog(ESD_TYPE_INFO, NULL, + "All dissectors have been reset to their default values."); + + redissect_packets(&cfile); +} + + +/**************************************************/ +/* Show Changed Dissectors */ +/**************************************************/ + +/* + * This routine creates one entry in the list of protocol dissector + * that have been changed. It is called by the g_hash_foreach routine + * once for each changed entry in a dissector table. + * + * @param table_name The table name in which this dissector is found. + * + * @param key A pointer to the key for this entry in the dissector + * hash table. This is generally the numeric selector of the + * protocol, i.e. the ethernet type code, IP port number, TCP port + * number, etc. + * + * @param value A pointer to the value for this entry in the dissector + * hash table. This is an opaque pointer that can only be handed back + * to routine in the file packet.c + * + * @param user_data A pointer to the clist in which this information + * should be stored. + */ +void +decode_build_show_list (gchar *table_name, gpointer key, + gpointer value, gpointer user_data) +{ + GtkCList *clist; + gchar *current_proto_name, *initial_proto_name, *text[E_CLIST_D_COLUMNS]; + gchar string1[20]; + gint current_proto, initial_proto, row; + + g_assert(user_data); + g_assert(value); + + clist = (GtkCList *)user_data; + current_proto = dissector_get_proto(value); + current_proto_name = proto_get_protocol_short_name(current_proto); + initial_proto = dissector_get_initial_proto(value); + initial_proto_name = proto_get_protocol_short_name(initial_proto); + + text[E_CLIST_D_TABLE] = table_name; + sprintf(string1, "%d", GPOINTER_TO_INT(key)); + text[E_CLIST_D_PORT] = string1; + text[E_CLIST_D_INITIAL] = initial_proto_name; + text[E_CLIST_D_CURRENT] = current_proto_name; + row = gtk_clist_prepend(clist, text); +} + + +/* + * This routine is called when the user clicks the "OK" button in + * the "Decode Show:Show" dialog window. This routine then destroys the + * dialog box and performs other housekeeping functions. + * + * @param GtkWidget * A pointer to the "OK" button. + * + * @param gpointer A pointer to the dialog window. + */ +static void +decode_show_ok_cb (GtkWidget *ok_bt, gpointer parent_w) +{ + gtk_widget_destroy(GTK_WIDGET(parent_w)); +} + + +/* + * This routine is called when the user clicks the "Close" button in + * the "Decode As:Show" dialog window. This routine simply calls the + * cancel routine as if the user had clicked the cancel button instead + * of the close button. + * + * @param GtkWidget * A pointer to the dialog box. + * + * @param gpointer Unknown + */ +static gboolean +decode_show_delete_cb (GtkWidget *decode_w, gpointer dummy) +{ + decode_show_ok_cb(NULL, decode_show_w); + return FALSE; +} + + +/* + * This routine is called at the destruction of the "Decode As:Show" + * dialog box. It clears the pointer maintained by this file, so that + * the next time the user clicks the "Decode As:Show" button a new + * dialog box will be created. + * + * @param GtkWidget * A pointer to the dialog box. + * + * @param gpointer Unknown + */ +static void +decode_show_destroy_cb (GtkWidget *win, gpointer user_data) +{ + /* Note that we no longer have a "Decode As:Show" dialog box. */ + decode_show_w = NULL; +} + + +/* + * This routine creates the "Decode As:Show" dialog box. This dialog box + * shows the user which protocols have had their dissectors changed. + * + * @param w Unknown + * @param data Unknown + */ +void +decode_show_cb (GtkWidget * w, gpointer data) +{ + GtkWidget *main_vb, *bbox, *ok_bt, *scrolled_window; + GtkCList *clist; + gchar *titles[E_CLIST_D_COLUMNS] = {"Table", "Port", "Initial", "Current"}; + gint column; + + if (decode_show_w != NULL) { + /* There's already a "Decode As" dialog box; reactivate it. */ + reactivate_window(decode_show_w); + return; + } + + decode_show_w = dlg_window_new("Ethereal: Decode As: Show"); + gtk_signal_connect(GTK_OBJECT(decode_show_w), "delete_event", + GTK_SIGNAL_FUNC(decode_show_delete_cb), NULL); + gtk_signal_connect(GTK_OBJECT(decode_show_w), "destroy", + GTK_SIGNAL_FUNC(decode_show_destroy_cb), NULL); + + /* Container for each row of widgets */ + main_vb = gtk_vbox_new(FALSE, 2); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(decode_show_w), main_vb); + + { + /* Initialize clist */ + clist = GTK_CLIST(gtk_clist_new_with_titles(E_CLIST_D_COLUMNS, titles)); + gtk_clist_column_titles_passive(clist); + for (column = 0; column < E_CLIST_D_COLUMNS; column++) + gtk_clist_set_column_auto_resize(clist, column, TRUE); + gtk_clist_set_selection_mode(clist, GTK_SELECTION_EXTENDED); + + /* Add data */ + dissector_all_tables_foreach_changed(decode_build_show_list, clist); + gtk_clist_sort(clist); + + /* Put clist into a scrolled window */ + scrolled_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_WIDGET(clist)); + gtk_box_pack_start(GTK_BOX(main_vb), scrolled_window, TRUE, TRUE, 0); + /* Provide a minimum of a couple of rows worth of data */ + gtk_widget_set_usize(scrolled_window, 0, E_DECODE_MIN_HEIGHT); + } + + /* Button row: OK and cancel buttons */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 10); + + ok_bt = gtk_button_new_with_label("OK"); + gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", + GTK_SIGNAL_FUNC(decode_show_ok_cb), + GTK_OBJECT(decode_show_w)); + GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok_bt, FALSE, FALSE, 0); + gtk_widget_grab_default(ok_bt); + dlg_set_cancel(decode_show_w, ok_bt); + + gtk_widget_show_all(decode_show_w); +} + + +/**************************************************/ +/* Modify the dissector routines */ +/**************************************************/ + +/* + * Modify a single dissector. This routine first takes care of + * updating the internal table of original protocol/port/dissector + * combinations by adding a new entry (or removing an existing entry + * if the value is being set back to its default). This routine then + * performs the actual modification to the packet dissector tables. + * + * @param s Pointer to a string buffer. This buffer is used to build + * up a message indicating which ports have had their dissector + * changed. This output will be displayed all at once after all + * dissectors have been modified. + * + * @param table_name The table name in which the dissector should be + * modified. + * + * @param selector An enum value indication which selector value + * (i.e. IP protocol number, TCP port number, etc.)is to be changed. + * + * @param clist The CList in which all the selection information can + * be found. + * + * @return gchar * Pointer to the next free location in the string + * buffer. + */ +static gchar * +decode_change_one_dissector (gchar *s, gchar *table_name, gint selector, + GtkCList *clist) +{ + dissector_t dissector; + gboolean old; + gchar *abbrev, *oldstring; + gint row, proto_num; + + if (!clist->selection) { + proto_num = -1; + abbrev = "(NULL)"; + old = FALSE; + dissector = NULL; + } else { + row = GPOINTER_TO_INT(clist->selection->data); + proto_num = GPOINTER_TO_INT(gtk_clist_get_row_data(clist, row)); + gtk_clist_get_text(clist, row, E_CLIST_S_PROTO_NAME, &abbrev); + gtk_clist_get_text(clist, row, E_CLIST_S_ISOLD, &oldstring); + old = (strcmp(oldstring, "TRUE") == 0); + dissector = proto_get_protocol_dissector(proto_num); + if ((proto_num != -1) && (dissector == NULL)) { + simple_dialog(ESD_TYPE_CRIT, NULL, + "Protocol dissector structure disappeared"); + return(s); + } + } + + if (strcmp(abbrev, "(default)") == 0) { + dissector_reset(table_name, selector); + s += sprintf(s, "Reset %s port %5d.\n", table_name, selector); + } else { + dissector_change(table_name, selector, dissector, old, proto_num); + if (dissector != NULL) { + s += sprintf(s, "Decoding %s table entry %5d as %s.\n", + table_name, selector, abbrev); + } else { + s += sprintf(s, "Not decoding %s table entry %5d.\n", + table_name, selector); + } + } + return(s); +} + + + +/**************************************************/ +/* Action routines for the "Decode As..." dialog */ +/* - called when the OK button pressed */ +/* - one per notebook page */ +/**************************************************/ + + +#ifdef DEBUG +/* + * Print debugging information about clist selection. Extract all + * information from the clist entry that was selected and print it to + * a dialog window. + * + * @param clist The clist to dump. + * + * @param leadin A string to print at the start of each line. + */ +void +decode_debug (GtkCList *clist, gchar *leadin) +{ + gchar *string, *text[E_CLIST_S_COLUMNS]; + gint row, proto_num; + + string = g_malloc(1024); + if (clist->selection) { + row = GPOINTER_TO_INT(clist->selection->data); + gtk_clist_get_text(clist, row, E_CLIST_S_PROTO_NAME, &text[E_CLIST_S_PROTO_NAME]); + gtk_clist_get_text(clist, row, E_CLIST_S_TABLE, &text[E_CLIST_S_TABLE]); + gtk_clist_get_text(clist, row, E_CLIST_S_ISOLD, &text[E_CLIST_S_ISOLD]); + proto_num = GPOINTER_TO_INT(gtk_clist_get_row_data(clist, row)); + sprintf(string, "%s clist row %d: proto %d, name %s, table %s, old %s", + leadin, row, proto_num, text[E_CLIST_S_PROTO_NAME], + text[E_CLIST_S_TABLE], text[E_CLIST_S_ISOLD]); + } else { + sprintf(string, "%s clist row (none), aka do not decode", leadin); + } + simple_dialog(ESD_TYPE_INFO, NULL, string); + g_free(string); +} +#endif + + +/* + * This routine is called when the user clicks the "OK" button in the + * "Decode As..." dialog window and a 'simple' page is foremost. + * This routine takes care of making any changes requested to the + * dissector tables. This routine is currently used for IP and + * Ethertypes. Any 'single change' notebook page can use this + * routine. + * + * @param notebook_pg A pointer to the "network" notebook page. + */ +static void +decode_simple (GtkWidget *notebook_pg) +{ + GtkCList *clist; + gchar *string, *table_name; + gint value; + + clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(notebook_pg), E_PAGE_CLIST)); + if (requested_action == E_DECODE_NO) + gtk_clist_unselect_all(clist); + +#ifdef DEBUG + string = gtk_object_get_data(GTK_OBJECT(notebook_pg), E_PAGE_TITLE); + decode_debug(clist, string); +#endif + + string = g_malloc(1024); + table_name = gtk_object_get_data(GTK_OBJECT(notebook_pg), E_PAGE_TABLE); + value = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(notebook_pg), + E_PAGE_VALUE)); + decode_change_one_dissector(string, table_name, value, clist); + simple_dialog(ESD_TYPE_INFO, NULL, string); + g_free(string); +} + + +/* + * This routine is called when the user clicks the "OK" button in the + * "Decode As..." dialog window and the network page is foremost. + * This routine takes care of making any changes requested to the + * dissector tables. This routine uses the decode_simple() routine to + * perform the heavy lifting, and then updates a list of protocol that + * are being decoded as TCP/UDP. * + * + * @param notebook_pg A pointer to the "network" notebook page. + */ +static void +decode_network (GtkWidget *notebook_pg) +{ + GtkCList *clist; + GSList *item; + gint row, assigned, port_num; + + /* Do the real work */ + decode_simple(notebook_pg); + + /* Now tweak a local table of protocol ids currently decoded as TCP/UDP */ + port_num = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(notebook_pg), + E_PAGE_VALUE)); + clist = GTK_CLIST(gtk_object_get_data(GTK_OBJECT(notebook_pg), E_PAGE_CLIST)); + row = GPOINTER_TO_INT(clist->selection->data); + assigned = GPOINTER_TO_INT(gtk_clist_get_row_data(clist, row)); + + /* Ignore changes to the normal TCP and UDP protocol numbers */ + if ((port_num == IP_PROTO_TCP) || (port_num == IP_PROTO_UDP)) + return; + + /* Not decoding - remove any entry for this IP protocol number */ + if (requested_action == E_DECODE_NO) { + decode_as_tcpudp = + g_slist_remove(decode_as_tcpudp, GINT_TO_POINTER(port_num)); + return; + } + + /* Not assigning TCP or UDP - remove any entry for this IP protocol number */ + if ((assigned != IP_PROTO_TCP) && (assigned != IP_PROTO_UDP)) { + decode_as_tcpudp = + g_slist_remove(decode_as_tcpudp, GINT_TO_POINTER(port_num)); + return; + } + + /* Assigning TCP or UDP - add if not already present */ + item = g_slist_find(decode_as_tcpudp, GINT_TO_POINTER(port_num)); + if (!item) { + decode_as_tcpudp = + g_slist_prepend(decode_as_tcpudp, GINT_TO_POINTER(port_num)); + } +} + + +/* + * This routine is called when the user clicks the "OK" button in the + * "Decode As..." dialog window and the transport page is foremost. + * This routine takes care of making any changes requested to the TCP + * and UDP dissector tables. + * + * Note: The negative tests catch multiple cases. For example, if the + * user didn't select UDP, then they either selected TCP or TCP/UDP. + * Either way they *did* select TCP. + * + * @param notebook_pg A pointer to the "transport" notebook page. + */ +static void +decode_transport (GtkObject *notebook_pg) +{ + GtkWidget *menu, *menuitem; + GtkCList *clist; + gint requested_tcpudp, requested_srcdst; + gchar *s, *string; + + clist = GTK_CLIST(gtk_object_get_data(notebook_pg, E_PAGE_CLIST)); + if (requested_action == E_DECODE_NO) + gtk_clist_unselect_all(clist); + + menu = gtk_object_get_data(notebook_pg, E_MENU_TCPUDP); + menuitem = gtk_menu_get_active(GTK_MENU(menu)); + requested_tcpudp = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem))); + + menu = gtk_object_get_data(notebook_pg, E_MENU_SRCDST); + menuitem = gtk_menu_get_active(GTK_MENU(menu)); + requested_srcdst = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(menuitem))); + +#ifdef DEBUG + string = gtk_object_get_data(GTK_OBJECT(notebook_pg), E_PAGE_TITLE); + decode_debug(clist, string); +#endif + + string = s = g_malloc(1024); + if (requested_tcpudp != E_DECODE_UDP) { + if (requested_srcdst != E_DECODE_DPORT) + s = decode_change_one_dissector(s, "tcp.port", pi.srcport, clist); + if (requested_srcdst != E_DECODE_SPORT) + s = decode_change_one_dissector(s, "tcp.port", pi.destport, clist); + } + if (requested_tcpudp != E_DECODE_TCP) { + if (requested_srcdst != E_DECODE_DPORT) + s = decode_change_one_dissector(s, "udp.port", pi.srcport, clist); + if (requested_srcdst != E_DECODE_SPORT) + s = decode_change_one_dissector(s, "udp.port", pi.destport, clist); + } + simple_dialog(ESD_TYPE_INFO, NULL, string); + g_free(string); +} + +/**************************************************/ +/* Signals from the "Decode As..." dialog */ +/**************************************************/ + +/* + * This routine is called when the user clicks the "OK" button in the + * "Decode As..." dialog window. This routine calls various helper + * routines to set/clear dissector values as requested by the user. + * These routines accumulate information on what actions they have + * taken, and this summary information is printed by this routine. + * This routine then destroys the dialog box and performs other + * housekeeping functions. + * + * @param ok_bt A pointer to the "OK" button. + * + * @param parent_w A pointer to the dialog window. + */ +static void +decode_ok_cb (GtkWidget *ok_bt, gpointer parent_w) +{ + GtkWidget *notebook, *notebook_pg; + GtkSignalFunc func; + gint page_num; + + /* Call the right routine for the page that was currently in front. */ + notebook = gtk_object_get_data(GTK_OBJECT(parent_w), E_NOTEBOOK); + page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); + notebook_pg = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num); + + func = gtk_object_get_data(GTK_OBJECT(notebook_pg), E_PAGE_ACTION); + func(notebook_pg); + + /* Now destroy the "Decode As" dialog. */ + gtk_widget_destroy(GTK_WIDGET(parent_w)); + g_slist_free(decode_dimmable); + decode_dimmable = NULL; + + redissect_packets(&cfile); +} + + +/* + * This routine is called when the user clicks the "Cancel" button in + * the "Decode As..." dialog window. This routine then destroys the + * dialog box and performs other housekeeping functions. + * + * @param cancel_bt A pointer to the "Cancel" button. + * + * @param parent_w A pointer to the dialog window. + */ +static void +decode_cancel_cb (GtkWidget *cancel_bt, gpointer parent_w) +{ + gtk_widget_destroy(GTK_WIDGET(parent_w)); + g_slist_free(decode_dimmable); + decode_dimmable = NULL; +} + + +/* + * This routine is called when the user clicks the "Close" button in + * the "Decode As..." dialog window. This routine simply calls the + * cancel routine as if the user had clicked the cancel button instead + * of the close button. + * + * @param decode_w A pointer to the dialog box. + * + * @param dummy Unknown + */ +static gboolean +decode_delete_cb (GtkWidget *decode_w, gpointer dummy) +{ + decode_cancel_cb(NULL, decode_w); + return FALSE; +} + + +/* + * This routine is called at the destruction of the "Decode As..." + * dialog box. It clears the pointer maintained by this file, so that + * the next time the user selects the "Decode As..." menu item a new + * dialog box will be created. + * + * @param decode_w A pointer to the dialog box. + * + * @param user_data Unknown + * + * @return void + */ +static void +decode_destroy_cb (GtkWidget *win, gpointer user_data) +{ + /* Note that we no longer have a "Decode As" dialog box. */ + decode_w = NULL; +} + + +/**************************************************/ +/* Dialog setup - radio buttons */ +/**************************************************/ + +/* + * Update the requested action field of the dialog. This routine is + * called by GTK when either of the two radio buttons in the dialog is + * clicked. + * + * @param w The radio button that was clicked. + * + * @param data The enum value assigned to this radio button. This + * will be either E_DECODE_YES or E_DECODE_NO + */ +static void +decode_update_action (GtkWidget *w, gpointer data) +{ + GSList *tmp; + gboolean enable; + + requested_action = GPOINTER_TO_INT(data); + enable = (requested_action == E_DECODE_YES); + for (tmp = decode_dimmable; tmp; tmp = g_slist_next(tmp)) { + gtk_widget_set_sensitive(tmp->data, enable); + } +} + +/* + * This routine is called to create the "Decode" and "Do not decode" + * radio buttons. These buttons are installed into a vbox, and set up + * as a format group. + * + * @return GtkWidget * A pointer to the vbox containing the buttons + */ +static GtkWidget * +decode_add_yes_no (void) +{ + GtkWidget *format_vb, *radio_button; + GSList *format_grp; + + format_vb = gtk_vbox_new(FALSE, 2); + + radio_button = gtk_radio_button_new_with_label(NULL, "Decode"); + format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(radio_button)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE); + gtk_signal_connect(GTK_OBJECT(radio_button), "clicked", + GTK_SIGNAL_FUNC(decode_update_action), + GINT_TO_POINTER(E_DECODE_YES)); + gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0); + + radio_button = gtk_radio_button_new_with_label(format_grp, "Do not decode"); + format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(radio_button)); + gtk_signal_connect(GTK_OBJECT(radio_button), "clicked", + GTK_SIGNAL_FUNC(decode_update_action), + GINT_TO_POINTER(E_DECODE_NO)); + gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0); + + return(format_vb); +} + +/**************************************************/ +/* Dialog setup - simple menus */ +/**************************************************/ + +/* + * This routine is called to add the transport protocol selection menu + * to the dialog box. This is a three choice menu: TCP, UDP, and + * TCP/UDP. The default choice for the menu is set to the transport + * layer protocol of the currently selected packet. + * + * @param page A pointer notebook page that will contain all + * widgets created by this routine. + * + * @return GtkWidget * A pointer to the newly created option menu. + */ +static GtkWidget * +decode_add_tcpudp_menu (GtkWidget *page) +{ + GtkWidget *optmenu, *menu, *menuitem; + gint requested_tcpudp; + + optmenu = gtk_option_menu_new(); + menu = gtk_menu_new(); + menuitem = gtk_menu_item_new_with_label("TCP"); + gtk_object_set_user_data(GTK_OBJECT(menuitem), + GINT_TO_POINTER(E_DECODE_TCP)); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + menuitem = gtk_menu_item_new_with_label("UDP"); + gtk_object_set_user_data(GTK_OBJECT(menuitem), + GINT_TO_POINTER(E_DECODE_UDP)); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + menuitem = gtk_menu_item_new_with_label("TCP/UDP"); + gtk_object_set_user_data(GTK_OBJECT(menuitem), + GINT_TO_POINTER(E_DECODE_TCPUDP)); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + requested_tcpudp = (pi.ipproto == IP_PROTO_TCP) ? E_DECODE_TCP : E_DECODE_UDP; + gtk_menu_set_active(GTK_MENU(menu), requested_tcpudp == E_DECODE_UDP); + gtk_object_set_data(GTK_OBJECT(page), E_MENU_TCPUDP, menu); + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); + + return(optmenu); +} + + +/* + * This routine is called to add the transport port selection menu to + * the dialog box. This is a three choice menu: source, destination + * and both. The default choice for the menu is set to the source + * port number of the currently selected packet. + * + * @param page A pointer notebook page that will contain all + * widgets created by this routine. + * + * @return GtkWidget * A pointer to the newly created option menu. + */ +static GtkWidget * +decode_add_srcdst_menu (GtkWidget *page) +{ + GtkWidget *optmenu, *menu, *menuitem; + gchar tmp[100]; + + optmenu = gtk_option_menu_new(); + menu = gtk_menu_new(); + sprintf(tmp, "source (%d)", pi.srcport); + menuitem = gtk_menu_item_new_with_label(tmp); + gtk_object_set_user_data(GTK_OBJECT(menuitem), + GINT_TO_POINTER(E_DECODE_SPORT)); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + sprintf(tmp, "destination (%d)", pi.destport); + menuitem = gtk_menu_item_new_with_label(tmp); + gtk_object_set_user_data(GTK_OBJECT(menuitem), + GINT_TO_POINTER(E_DECODE_DPORT)); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + menuitem = gtk_menu_item_new_with_label("both"); + gtk_object_set_user_data(GTK_OBJECT(menuitem), + GINT_TO_POINTER(E_DECODE_BPORT)); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ + + gtk_object_set_data(GTK_OBJECT(page), E_MENU_SRCDST, menu); + gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); + + return(optmenu); +} + +/**************************************************/ +/* Dialog setup - clist based menus */ +/**************************************************/ + + +typedef struct decode_build_clist_info { + GtkCList *clist; + gboolean conv; +} decode_build_clist_info_t; + +/* + * This routine creates one entry in the list of protocol dissector + * that can be used. It is called by the g_hash_foreach routine once + * for each entry in a dissector table. It guarantees unique entries + * by iterating over the list of entries build up to this point, + * looking for a duplicate name. If there is no duplicate, then this + * entry is added to the list of possible dissectors. + * + * @param table_name The name of the dissector hash table currently + * being walked. + * + * @param key A pointer to the key for this entry in the + * dissector hash table. This is generally the numeric selector of + * the protocol, i.e. the ethernet type code, IP port number, TCP port + * number, etc. + * + * @param value A pointer to the value for this entry in the + * dissector hash table. This is an opaque pointer that can only be + * handed back to routines in the file packet.c + * + * @param user_data A data block passed into each instance of this + * routine. It contains information from the caller of the foreach + * routine, specifying information about the dissector table and where + * to store any information generated by this routine. + */ +void decode_add_to_clist (gchar *table_name, gpointer key, + gpointer value, gpointer user_data) +{ + GtkCList *clist; + gchar *proto_name, *isold, *isconv; + gchar *text[E_CLIST_S_COLUMNS]; + gint proto, row; + decode_build_clist_info_t *info; + + g_assert(user_data); + g_assert(value); + + info = user_data; + clist = info->clist; + if (info->conv) { + proto = conv_dissector_get_proto(value); + isold = conv_dissector_get_old_flag(value) ? "TRUE" : "FALSE"; + isconv = "TRUE"; + } else { + proto = dissector_get_proto(value); + isold = dissector_get_old_flag(value) ? "TRUE" : "FALSE"; + isconv = "FALSE"; + } + proto_name = proto_get_protocol_short_name(proto); + + row = gtk_clist_find_row_from_data(clist, GINT_TO_POINTER(proto)); + if (row != -1) { + return; + } + + text[E_CLIST_S_PROTO_NAME] = proto_name; + text[E_CLIST_S_TABLE] = table_name; + text[E_CLIST_S_ISOLD] = isold; + text[E_CLIST_S_ISCONV] = isconv; + row = gtk_clist_prepend(clist, text); + gtk_clist_set_row_data(clist, row, GINT_TO_POINTER(proto)); +} + + +/* + * This routine starts the creation of a CList on a notebook page. It + * creates both a scrolled window and a clist, adds the clist to the + * window, and attaches the clist as a data object on the page. + * + * @param page A pointer to the notebook page being created. + * + * @param clist_p Will be filled in with the address of a newly + * created CList. + * + * @param scrolled_win_p Will be filled in with the address of a newly + * created GtkScrolledWindow. + */ +void +decode_clist_menu_start (GtkWidget *page, GtkCList **clist_p, + GtkWidget **scrolled_win_p) +{ + gchar *titles[E_CLIST_S_COLUMNS] = {"Short Name", "Table Name", + "Is Old", "Is Conversation"}; + GtkCList *clist; + GtkWidget *window; + gint column; + + *clist_p = clist = + GTK_CLIST(gtk_clist_new_with_titles(E_CLIST_S_COLUMNS, titles)); + gtk_clist_column_titles_passive(clist); +#ifndef DEBUG + gtk_clist_column_titles_hide(clist); + for (column = 1; column < E_CLIST_S_COLUMNS; column++) + gtk_clist_set_column_visibility (clist, column, FALSE); +#endif + for (column = 0; column < E_CLIST_S_COLUMNS; column++) + gtk_clist_set_column_auto_resize(clist, column, TRUE); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_CLIST, clist); + + *scrolled_win_p = window = gtk_scrolled_window_new(NULL, NULL); + /* Provide a minimum of a couple of rows worth of data */ + gtk_widget_set_usize(window, 0, E_DECODE_MIN_HEIGHT); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(window), + GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(window), + GTK_WIDGET(clist)); +} + +/* + * This routine finishes the creation of a CList on a notebook page. + * It adds the default entry, sets the default entry as the + * highlighted entry, and sorts the CList. + * + * @param clist A pointer the the CList to finish. + */ +void +decode_clist_menu_finish (GtkCList *clist) +{ + gchar *text[E_CLIST_S_COLUMNS]; + gint row; + + text[E_CLIST_S_PROTO_NAME] = "(default)"; + text[E_CLIST_S_TABLE] = "(none)"; + text[E_CLIST_S_ISOLD] = "(who cares)"; + text[E_CLIST_S_ISCONV] = "(who cares)"; + row = gtk_clist_prepend(clist, text); + gtk_clist_set_row_data(clist, row, GINT_TO_POINTER(-1)); + + gtk_clist_select_row(clist, 0, -1); + gtk_clist_sort(clist); +} + +/* + * This routine is called to add the dissector selection list to a + * notebook page. This scrolled list contains an entry labeled + * "default", and an entry for each protocol that has had a dissector + * registered. The default choice for the list is set to the + * "default" choice, which will return the protocol/port selections to + * their original dissector(s). + * + * @param page A pointer to the notebook page currently being created. + * + * @param table_name The name of the dissector hash table to use to + * build this (clist) menu. + * + * @return GtkWidget * A pointer to the newly created clist within a + * scrolled window. + */ +static GtkWidget * +decode_add_simple_menu (GtkWidget *page, gchar *table_name) +{ + GtkWidget *scrolled_window; + GtkCList *clist; + decode_build_clist_info_t info; + + decode_clist_menu_start(page, &clist, &scrolled_window); + { + info.clist = clist; + info.conv = FALSE; + dissector_table_foreach(table_name, decode_add_to_clist, &info); + } + decode_clist_menu_finish(clist); + return(scrolled_window); +} + +/* + * This routine is called to add the dissector selection list to + * notebook page. This scrolled list contains an entry labeled + * "default", and an entry for each protocol that has had a dissector + * registered. The default choice for the list is set to the + * "default" choice, which will return the protocol/port selections to + * their original dissector(s). + * + * @param page A pointer to the notebook page currently being created. + * + * @return GtkWidget * A pointer to the newly created option menu. + */ +static GtkWidget * +decode_add_transport_menu (GtkWidget *page) +{ + GtkWidget *scrolled_window; + GtkCList *clist; + decode_build_clist_info_t info; + + decode_clist_menu_start(page, &clist, &scrolled_window); + { + info.clist = clist; + info.conv = FALSE; + dissector_table_foreach("tcp.port", decode_add_to_clist, &info); + dissector_table_foreach("udp.port", decode_add_to_clist, &info); + + info.conv = TRUE; + dissector_conv_foreach("udp", decode_add_to_clist, &info); + } + decode_clist_menu_finish(clist); + return(scrolled_window); +} + +/**************************************************/ +/* Dialog setup */ +/**************************************************/ + +/* + * This routine creates a somple notebook page ni the dialog box. + * This notebook page provides a promp specifying what is being + * changed and its current value (e.g. "IP Protocol number (17)"), and + * a clist specifying all the available choices. The list of choices + * is conditionally enabled, based upon the setting of the + * "decode"/"do not decode" radio buttons. + * + * @param prompt The prompt for this notebook page + * + * @param title A table name from which all dissector names will + * be extracted. + * + * @param table_name The name of the dissector hash table to use to + * build this page. + * + * @param value The protocol/port value that is to be changed. + * + * @return GtkWidget * A pointer to the notebook page created by this + * routine. + */ +static GtkWidget * +decode_add_simple_page (gchar *prompt, gchar *title, gchar *table_name, + gint value) +{ + GtkWidget *page, *label, *scrolled_window; + + page = gtk_hbox_new(FALSE, 5); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_ACTION, decode_simple); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_TABLE, table_name); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_TITLE, title); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_VALUE, GINT_TO_POINTER(value)); + + /* Always enabled */ + label = gtk_label_new(prompt); + gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0); + + /* Conditionally enabled - only when decoding packets */ + label = gtk_label_new("as"); + gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0); + decode_dimmable = g_slist_prepend(decode_dimmable, label); + scrolled_window = decode_add_simple_menu(page, table_name); + gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0); + decode_dimmable = g_slist_prepend(decode_dimmable, scrolled_window); + + return(page); +} + + +/* + * This routine creates the TCP/UDP notebook page in the dialog box. + * All items created by this routine are packed into a single + * horizontal box. First is a menu allowing the user to select the + * TCP or UDP transport layer protocol. Second is a menu allowing the + * user to select whether the source port, destination port, or both + * ports will have dissectors added for them. Last is a + * (conditionally enabled) popup menu listing all possible dissectors + * that can be used to decode the packets, and the choice or returning + * to the default dissector for these ports. + * + * The defaults for these items are the transport layer protocol of + * the currently selected packet, the source port of the currently + * selected packet, and the "default dissector". + * + * @return GtkWidget * A pointer to the notebook page created by + * this routine. + */ +static GtkWidget * +decode_add_tcpudp_page (void) +{ + GtkWidget *page, *label, *scrolled_window, *optmenu; + + page = gtk_hbox_new(FALSE, 5); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_ACTION, decode_transport); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_TITLE, "Transport"); + + /* Always enabled */ + optmenu = decode_add_tcpudp_menu(page); + gtk_box_pack_start(GTK_BOX(page), optmenu, TRUE, TRUE, 0); + optmenu = decode_add_srcdst_menu(page); + gtk_box_pack_start(GTK_BOX(page), optmenu, TRUE, TRUE, 0); + label = gtk_label_new("port(s)"); + gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0); + + /* Conditionally enabled - only when decoding packets */ + label = gtk_label_new("as"); + gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0); + decode_dimmable = g_slist_prepend(decode_dimmable, label); + scrolled_window = decode_add_transport_menu(page); + gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0); + decode_dimmable = g_slist_prepend(decode_dimmable, scrolled_window); + + return(page); +} + +/* + * Indicate if a transport page should be included, based upon the iP + * protocol number. + * + * @param ip_protocol The IP protocol number in question. + * + * @return gboolean TRUE if this protocol is being decoded as TCP or + * UDP. + */ +gboolean +decode_as_transport_ok (gint ip_protocol) +{ + if ((ip_protocol == IP_PROTO_TCP) || (ip_protocol == IP_PROTO_UDP)) + return(TRUE); + + if (g_slist_find(decode_as_tcpudp, GINT_TO_POINTER(ip_protocol))) + return(TRUE); + return(FALSE); +} + + +/* + * This routine creates the bulk of the "Decode As" dialog box. All + * items created by this routine are packed as pages into a notebook. + * There will be a page for each protocol layer that can be change. + * + * @param GtkWidget * A pointer to the widget in which the notebook + * should be installed. + */ +void +decode_add_notebook (GtkWidget *format_hb) +{ + GtkWidget *notebook, *page, *label; + gchar buffer[40]; + + /* Start a nootbook for flipping between sets of changes */ + notebook = gtk_notebook_new(); + gtk_container_add(GTK_CONTAINER(format_hb), notebook); + gtk_object_set_data(GTK_OBJECT(decode_w), E_NOTEBOOK, notebook); + + /* Add link level selection page */ + if (pi.ethertype) { + sprintf(buffer, "Ethertype %d", pi.ethertype); + page = decode_add_simple_page(buffer, "Link", "ethertype", pi.ethertype); + label = gtk_label_new("Link"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); + } + + /* Add network selection page */ + if (pi.ipproto) { + sprintf(buffer, "IP protocol %d", pi.ipproto); + page = decode_add_simple_page(buffer, "Network", "ip.proto", pi.ipproto); + gtk_object_set_data(GTK_OBJECT(page), E_PAGE_ACTION, decode_network); + label = gtk_label_new("Network"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); + } + + /* Add transport selection page */ + if (decode_as_transport_ok(pi.ipproto)) { + page = decode_add_tcpudp_page(); + label = gtk_label_new("Transport"); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); + } + + /* Select the last added page (selects first by default) */ + /* Notebook must be visible for set_page to work. */ + gtk_widget_show_all(notebook); + gtk_notebook_set_page(GTK_NOTEBOOK(notebook), -1); +} + + +/* + * This routine creates the "Decode As" dialog box. This dialog box + * asks the user which protocol to use for decoding the currently + * selected packet. This will affect the last packet that we called a + * dissection routine on belongs (this might be the most recently + * selected packet, or it might be the last packet in the file). + * + * This routine uses an auxiliary function to create the bulk of the + * dialog box, and then hand crafts the button box at the bottom of + * the dialog. + * + * @param w Unknown + * @param data Unknown + */ +void +decode_as_cb (GtkWidget * w, gpointer data) +{ + GtkWidget *main_vb, *format_hb, *bbox, *ok_bt, *cancel_bt, *button; + GtkWidget *button_vb; + + if (decode_w != NULL) { + /* There's already a "Decode As" dialog box; reactivate it. */ + reactivate_window(decode_w); + return; + } + + requested_action = E_DECODE_YES; + decode_w = dlg_window_new("Ethereal: Decode As"); + gtk_signal_connect(GTK_OBJECT(decode_w), "delete_event", + GTK_SIGNAL_FUNC(decode_delete_cb), NULL); + gtk_signal_connect(GTK_OBJECT(decode_w), "destroy", + GTK_SIGNAL_FUNC(decode_destroy_cb), NULL); + + /* Container for each row of widgets */ + main_vb = gtk_vbox_new(FALSE, 2); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(decode_w), main_vb); + + /* First row - Buttons and Notebook */ + { + format_hb = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(main_vb), format_hb, TRUE, TRUE, 10); + + button_vb = decode_add_yes_no(); + gtk_box_pack_start(GTK_BOX(format_hb), button_vb, TRUE, TRUE, 10); + + decode_add_notebook(format_hb); + } + + /* Button row: OK and cancel buttons */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 10); + + ok_bt = gtk_button_new_with_label("OK"); + gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", + GTK_SIGNAL_FUNC(decode_ok_cb), + GTK_OBJECT(decode_w)); + GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok_bt, FALSE, FALSE, 0); + gtk_widget_grab_default(ok_bt); + + button = gtk_button_new_with_label("Show Current"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(decode_show_cb), + GTK_OBJECT(decode_w)); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label("Reset Changes"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(decode_reset_cb), + GTK_OBJECT(decode_w)); + GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); + + cancel_bt = gtk_button_new_with_label("Cancel"); + gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked", + GTK_SIGNAL_FUNC(decode_cancel_cb), + GTK_OBJECT(decode_w)); + GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel_bt, FALSE, FALSE, 0); + + /* + * Catch the "key_press_event" signal in the window, so that + * we can catch the ESC key being pressed and act as if the + * "Cancel" button had been selected. + */ + dlg_set_cancel(decode_w, cancel_bt); + + gtk_widget_show_all(decode_w); +} + + +/* + * Local Variables: + * mode:c + * c-basic-offset: 4 + * End: + */ Index: gtk/decode_as_dlg.h =================================================================== RCS file: decode_as_dlg.h diff -N decode_as_dlg.h --- /dev/null Sat Oct 7 15:19:25 2000 +++ decode_as_dlg.h Mon Jan 22 11:04:33 2001 @@ -0,0 +1,33 @@ +/* decode_as_dlg.c + * + * $Id: $ + * + * Routines to modify dissector tables on the fly. + * + * By David Hampton <dhampton@xxxxxxx> + * Copyright 2001 David Hampton + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __DECODE_AS_DLG_H__ +#define __DECODE_AS_DLG_H__ + +void decode_as_cb(GtkWidget *, gpointer); +void decode_show_cb(GtkWidget *, gpointer); +void decode_as_register_tcpudp(gint); + +#endif Index: gtk/menu.c =================================================================== RCS file: /cvsroot/ethereal/gtk/menu.c,v retrieving revision 1.46 diff -u -r1.46 menu.c --- menu.c 2000/10/19 22:59:24 1.46 +++ menu.c 2001/01/22 17:04:33 @@ -55,6 +55,7 @@ #include "packet_win.h" #include "print.h" #include "follow_dlg.h" +#include "decode_as_dlg.h" #include "help_dlg.h" #include "proto_dlg.h" #include "keys.h" @@ -139,11 +140,13 @@ {"/Display/Collapse _All", NULL, GTK_MENU_FUNC(collapse_all_cb), 0, NULL}, {"/Display/_Expand All", NULL, GTK_MENU_FUNC(expand_all_cb), 0, NULL}, {"/Display/_Show Packet In New Window", NULL, GTK_MENU_FUNC(new_window_cb), 0, NULL}, + {"/Display/User Specified Decodes...", NULL, GTK_MENU_FUNC(decode_show_cb), 0, NULL}, {"/_Tools", NULL, NULL, 0, "<Branch>" }, #ifdef HAVE_PLUGINS {"/Tools/_Plugins...", NULL, GTK_MENU_FUNC(tools_plugins_cmd_cb), 0, NULL}, #endif {"/Tools/_Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Tools/_Decode As...", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, /* {"/Tools/Graph", NULL, NULL, 0, NULL}, future use */ {"/Tools/_Summary", NULL, GTK_MENU_FUNC(summary_open_cb), 0, NULL}, {"/_Help", NULL, NULL, 0, "<LastBranch>" }, @@ -159,6 +162,7 @@ static GtkItemFactoryEntry packet_list_menu_items[] = { {"/Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Decode As...", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, {"/Filters...", NULL, GTK_MENU_FUNC(filter_dialog_cb), 0, NULL}, {"/<separator>", NULL, NULL, 0, "<Separator>"}, {"/Colorize Display...", NULL, GTK_MENU_FUNC(color_display_cb), 0, NULL}, @@ -170,6 +174,7 @@ static GtkItemFactoryEntry tree_view_menu_items[] = { {"/Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Decode As...", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, {"/Filters...", NULL, GTK_MENU_FUNC(filter_dialog_cb), 0, NULL}, {"/<separator>", NULL, NULL, 0, "<Separator>"}, {"/Resolve Name", NULL, GTK_MENU_FUNC(resolve_name_cb), 0, NULL}, @@ -183,6 +188,7 @@ static GtkItemFactoryEntry hexdump_menu_items[] = { {"/Follow TCP Stream", NULL, GTK_MENU_FUNC(follow_stream_cb), 0, NULL}, + {"/Decode As...", NULL, GTK_MENU_FUNC(decode_as_cb), 0, NULL}, {"/Filters...", NULL, GTK_MENU_FUNC(filter_dialog_cb), 0, NULL} }; @@ -387,6 +393,7 @@ set_menu_sensitivity("/Display/Show Packet In New Window", have_selected_packet); set_menu_sensitivity("/Tools/Follow TCP Stream", have_selected_packet ? (pi.ipproto == 6) : FALSE); + set_menu_sensitivity("/Tools/Decode As...", have_selected_packet); set_menu_sensitivity("/Resolve Name", have_selected_packet && !g_resolving_actif); }
- Follow-Ups:
- Re: [Ethereal-dev] New feature for ethereal
- From: Guy Harris
- Re: [Ethereal-dev] New feature for ethereal
- From: Guy Harris
- Re: [Ethereal-dev] New feature for ethereal
- References:
- Re: [Ethereal-dev] New feature for ethereal
- From: David Hampton
- Re: [Ethereal-dev] New feature for ethereal
- From: Guy Harris
- Re: [Ethereal-dev] New feature for ethereal
- Prev by Date: Re: [Ethereal-dev] [WIN32] Python {} line too long
- Next by Date: [Ethereal-dev] New capture file format ideas?
- Previous by thread: Re: [Ethereal-dev] New feature for ethereal
- Next by thread: Re: [Ethereal-dev] New feature for ethereal
- Index(es):