/* decode_as_dlg.c * * $Id$ * * Routines to modify dissector tables on the fly. * * By David Hampton * 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 #include #include "decode_as_dlg.h" #include "dlg_utils.h" #include "globals.h" #include "simple_dialog.h" #include #include #include "gui_utils.h" #include #include "compat_macros.h" #include "decode_as_dcerpc.h" #include "help_dlg.h" #undef DEBUG /**************************************************/ /* Typedefs & Enums */ /**************************************************/ /* * 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, /* For SCTP only. This MUST be the last entry! */ E_DECODE_PPID }; #define E_DECODE_MIN_HEIGHT 300 #define E_NOTEBOOK "notebook" #define E_MENU_SRCDST "menu_src_dst" #define E_PAGE_DPORT "dport" #define E_PAGE_SPORT "sport" #define E_PAGE_PPID "ppid" /* * Columns for a "Display" list */ #define E_LIST_D_TABLE 0 #define E_LIST_D_SELECTOR 1 #define E_LIST_D_INITIAL 2 #define E_LIST_D_CURRENT 3 #define E_LIST_D_MAX E_LIST_D_CURRENT #define E_LIST_D_COLUMNS (E_LIST_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. */ GSList *decode_dimmable = 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. */ enum action_type requested_action = -1; /**************************************************/ /* Global Functions */ /**************************************************/ /* init this module */ void decode_as_init(void) { decode_dcerpc_init(); } /**************************************************/ /* Reset 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 type of the selector in that dissector table */ ftenum_t ddi_selector_type; /* The selector in the dissector table */ union { guint sel_uint; char *sel_string; } ddi_selector; }; /* * 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 - but it's unused. * * @param user_data Unused. */ static void decode_build_reset_list (gchar *table_name, ftenum_t selector_type, gpointer key, gpointer value _U_, gpointer user_data _U_) { dissector_delete_item_t *item; item = g_malloc(sizeof(dissector_delete_item_t)); item->ddi_table_name = table_name; item->ddi_selector_type = selector_type; switch (selector_type) { case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: item->ddi_selector.sel_uint = GPOINTER_TO_UINT(key); break; case FT_STRING: case FT_STRINGZ: item->ddi_selector.sel_string = key; break; default: g_assert_not_reached(); } dissector_reset_list = g_slist_prepend(dissector_reset_list, item); } /**************************************************/ /* Show Changed Dissectors */ /**************************************************/ #if GTK_MAJOR_VERSION >= 2 #define SORT_ALPHABETICAL 0 static gint sort_iter_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata) { gint sortcol = GPOINTER_TO_INT(userdata); gint ret = 0; switch (sortcol) { case SORT_ALPHABETICAL: { gchar *name1, *name2; gtk_tree_model_get(model, a, 0, &name1, -1); gtk_tree_model_get(model, b, 0, &name2, -1); if (name1 == NULL || name2 == NULL) { if (name1 == NULL && name2 == NULL) break; /* both equal => ret = 0 */ ret = (name1 == NULL) ? -1 : 1; } else { ret = g_ascii_strcasecmp(name1,name2); } g_free(name1); g_free(name2); } break; default: g_return_val_if_reached(0); } return ret; } #endif void decode_add_to_show_list ( gpointer list_data, const gchar *table_name, gchar *selector_name, const gchar *initial_proto_name, const gchar *current_proto_name) { const gchar *text[E_LIST_D_COLUMNS]; #if GTK_MAJOR_VERSION < 2 GtkCList *clist; gint row; #else GtkListStore *store; GtkTreeIter iter; #endif #if GTK_MAJOR_VERSION < 2 clist = (GtkCList *)list_data; #else store = (GtkListStore *)list_data; #endif text[E_LIST_D_TABLE] = table_name; text[E_LIST_D_SELECTOR] = selector_name; text[E_LIST_D_INITIAL] = initial_proto_name; text[E_LIST_D_CURRENT] = current_proto_name; #if GTK_MAJOR_VERSION < 2 row = gtk_clist_prepend(clist, (gchar **) text); #else gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, E_LIST_D_TABLE, text[E_LIST_D_TABLE], E_LIST_D_SELECTOR, text[E_LIST_D_SELECTOR], E_LIST_D_INITIAL, text[E_LIST_D_INITIAL], E_LIST_D_CURRENT, text[E_LIST_D_CURRENT], -1); #endif } /* * 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 list in which this information * should be stored. */ static void decode_build_show_list (gchar *table_name, ftenum_t selector_type, gpointer key, gpointer value, gpointer user_data) { dissector_handle_t current, initial; const gchar *current_proto_name, *initial_proto_name; gchar *selector_name; gchar string1[20]; g_assert(user_data); g_assert(value); current = dtbl_entry_get_handle(value); if (current == NULL) current_proto_name = "(none)"; else current_proto_name = dissector_handle_get_short_name(current); initial = dtbl_entry_get_initial_handle(value); if (initial == NULL) initial_proto_name = "(none)"; else initial_proto_name = dissector_handle_get_short_name(initial); switch (selector_type) { case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: switch (get_dissector_table_base(table_name)) { case BASE_DEC: g_snprintf(string1, sizeof(string1), "%u", GPOINTER_TO_UINT(key)); break; case BASE_HEX: switch (get_dissector_table_selector_type(table_name)) { case FT_UINT8: g_snprintf(string1, sizeof(string1), "0x%02x", GPOINTER_TO_UINT(key)); break; case FT_UINT16: g_snprintf(string1, sizeof(string1), "0x%04x", GPOINTER_TO_UINT(key)); break; case FT_UINT24: g_snprintf(string1, sizeof(string1), "0x%06x", GPOINTER_TO_UINT(key)); break; case FT_UINT32: g_snprintf(string1, sizeof(string1), "0x%08x", GPOINTER_TO_UINT(key)); break; default: g_assert_not_reached(); break; } break; case BASE_OCT: g_snprintf(string1, sizeof(string1), "%#o", GPOINTER_TO_UINT(key)); break; } selector_name = string1; break; case FT_STRING: case FT_STRINGZ: selector_name = key; break; default: g_assert_not_reached(); selector_name = NULL; break; } decode_add_to_show_list ( user_data, get_dissector_table_ui_name(table_name), selector_name, initial_proto_name, current_proto_name); } /* clear all settings */ static void decode_clear_all(void) { 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; switch (item->ddi_selector_type) { case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: dissector_reset(item->ddi_table_name, item->ddi_selector.sel_uint); break; case FT_STRING: case FT_STRINGZ: dissector_reset_string(item->ddi_table_name, item->ddi_selector.sel_string); break; default: g_assert_not_reached(); } g_free(item); } g_slist_free(dissector_reset_list); dissector_reset_list = NULL; decode_dcerpc_reset_all(); cf_redissect_packets(&cfile); } /* * This routine is called when the user clicks the "OK" button in * the "Decode As:Show..." dialog window. This routine 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 _U_, gpointer parent_w) { window_destroy(GTK_WIDGET(parent_w)); } /* * This routine is called when the user clicks the "Clear" button in * the "Decode As:Show..." dialog window. This routine resets all the * dissector values and then destroys the dialog box and performs * other housekeeping functions. * * @param GtkWidget * A pointer to the "Clear" button. * * @param gpointer A pointer to the dialog window. */ static void decode_show_clear_cb (GtkWidget *clear_bt _U_, gpointer parent_w) { decode_clear_all(); window_destroy(GTK_WIDGET(parent_w)); } /* * This routine is called when the user clicks the X at the top right end in * the "Decode As:Show..." dialog window. This routine simply calls the * ok routine as if the user had clicked the ok button. * * @param GtkWidget * A pointer to the dialog box. * * @param gpointer Unknown */ static gboolean decode_show_delete_cb (GtkWidget *decode_w _U_, gpointer dummy _U_) { 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 _U_, gpointer user_data _U_) { /* 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 _U_, gpointer data _U_) { GtkWidget *main_vb, *bbox, *ok_bt, *clear_bt, *help_bt, *scrolled_window; const gchar *titles[E_LIST_D_COLUMNS] = { "Table", "Value", "Initial", "Current" }; gint column; #if GTK_MAJOR_VERSION < 2 GtkCList *list; #else GtkListStore *store; GtkTreeView *list; GtkCellRenderer *renderer; GtkTreeViewColumn *tc; GtkTreeIter iter; #endif 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"); /* Provide a minimum of a couple of rows worth of data */ gtk_window_set_default_size(GTK_WINDOW(decode_show_w), -1, E_DECODE_MIN_HEIGHT); /* 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 list */ #if GTK_MAJOR_VERSION < 2 list = GTK_CLIST(gtk_clist_new_with_titles(E_LIST_D_COLUMNS, (gchar **) titles)); gtk_clist_column_titles_passive(list); for (column = 0; column < E_LIST_D_COLUMNS; column++) gtk_clist_set_column_auto_resize(list, column, TRUE); gtk_clist_set_selection_mode(list, GTK_SELECTION_EXTENDED); #else store = gtk_list_store_new(E_LIST_D_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store))); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE); gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(list), FALSE); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(list), GTK_SELECTION_MULTIPLE); for (column = 0; column < E_LIST_D_COLUMNS; column++) { renderer = gtk_cell_renderer_text_new(); tc = gtk_tree_view_column_new_with_attributes(titles[column], renderer, "text", column, NULL); gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column(list, tc); } #endif /* Add data */ #if GTK_MAJOR_VERSION < 2 dissector_all_tables_foreach_changed(decode_build_show_list, list); gtk_clist_sort(list); decode_dcerpc_add_show_list(list); #else dissector_all_tables_foreach_changed(decode_build_show_list, store); g_object_unref(G_OBJECT(store)); decode_dcerpc_add_show_list(store); #endif /* Put clist into a scrolled window */ scrolled_window = scrolled_window_new(NULL, NULL); /* this will result to set the width of the dialog to the required size */ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); #if GTK_MAJOR_VERSION >= 2 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); #endif gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(list)); gtk_box_pack_start(GTK_BOX(main_vb), scrolled_window, TRUE, TRUE, 0); } /* Button row */ if(topic_available(HELP_DECODE_AS_SHOW_DIALOG)) { bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CLEAR, GTK_STOCK_HELP, NULL); } else { bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CLEAR, NULL); } gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0); gtk_widget_show(bbox); ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK); SIGNAL_CONNECT(ok_bt, "clicked", decode_show_ok_cb, decode_show_w); clear_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLEAR); SIGNAL_CONNECT(clear_bt, "clicked", decode_show_clear_cb, decode_show_w); if(topic_available(HELP_DECODE_AS_SHOW_DIALOG)) { help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP); SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_DECODE_AS_SHOW_DIALOG); } /* set ok as default, this button won't change anything */ window_set_cancel_button(decode_show_w, ok_bt, NULL); SIGNAL_CONNECT(decode_show_w, "delete_event", decode_show_delete_cb, NULL); SIGNAL_CONNECT(decode_show_w, "destroy", decode_show_destroy_cb, NULL); #if GTK_MAJOR_VERSION < 2 gtk_widget_set_sensitive(clear_bt, (list->rows != 0)); #else gtk_widget_set_sensitive(clear_bt, gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)); #endif gtk_widget_show_all(decode_show_w); window_present(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 list The List in which all the selection information can * be found. * * @return gchar * Pointer to the next free location in the string * buffer. */ static void decode_change_one_dissector(gchar *table_name, guint selector, GtkWidget *list) { dissector_handle_t handle; gchar *abbrev; #if GTK_MAJOR_VERSION < 2 gint row; #else GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; #endif #if GTK_MAJOR_VERSION < 2 if (!GTK_CLIST(list)->selection) { abbrev = NULL; handle = NULL; } else { row = GPOINTER_TO_INT(GTK_CLIST(list)->selection->data); handle = gtk_clist_get_row_data(GTK_CLIST(list), row); gtk_clist_get_text(GTK_CLIST(list), row, E_LIST_S_PROTO_NAME, &abbrev); } #else selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE) { abbrev = NULL; handle = NULL; } else { gtk_tree_model_get(model, &iter, E_LIST_S_PROTO_NAME, &abbrev, E_LIST_S_TABLE+1, &handle, -1); } #endif if (abbrev != NULL && strcmp(abbrev, "(default)") == 0) { dissector_reset(table_name, selector); } else { dissector_change(table_name, selector, handle); } #if GTK_MAJOR_VERSION >= 2 if (abbrev != NULL) g_free(abbrev); #endif } /**************************************************/ /* 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. */ static void decode_debug (GtkCList *clist, gchar *leadin) { gchar *string, *text[E_LIST_S_COLUMNS]; dissector_handle_t handle; gint row; if (clist->selection) { row = GPOINTER_TO_INT(clist->selection->data); gtk_clist_get_text(clist, row, E_LIST_S_PROTO_NAME, &text[E_LIST_S_PROTO_NAME]); gtk_clist_get_text(clist, row, E_LIST_S_TABLE, &text[E_LIST_S_TABLE]); handle = gtk_clist_get_row_data(clist, row); string = g_strdup_printf("%s clist row %d: , name %s, table %s", leadin, row, text[E_LIST_S_PROTO_NAME], text[E_LIST_S_TABLE]); } else { string = g_strdup_printf("%s clist row (none), aka do not decode", leadin); } simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 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) { GtkWidget *list; #ifdef DEBUG gchar *string; #endif gchar *table_name; guint value; list = OBJECT_GET_DATA(notebook_pg, E_PAGE_LIST); if (requested_action == E_DECODE_NO) #if GTK_MAJOR_VERSION < 2 gtk_clist_unselect_all(GTK_CLIST(list)); #else gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(list))); #endif #ifdef DEBUG string = OBJECT_GET_DATA(notebook_pg, E_PAGE_TITLE); decode_debug(GTK_CLIST(list), string); #endif table_name = OBJECT_GET_DATA(notebook_pg, E_PAGE_TABLE); value = GPOINTER_TO_UINT(OBJECT_GET_DATA(notebook_pg, E_PAGE_VALUE)); decode_change_one_dissector(table_name, value, list); } /* * 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 * or UDP dissector tables. * * @param notebook_pg A pointer to the "transport" notebook page. */ static void decode_transport(GtkWidget *notebook_pg) { GtkWidget *menu, *menuitem; GtkWidget *list; gchar *table_name; gint requested_srcdst, requested_port, ppid; gpointer portp; list = OBJECT_GET_DATA(notebook_pg, E_PAGE_LIST); if (requested_action == E_DECODE_NO) #if GTK_MAJOR_VERSION < 2 gtk_clist_unselect_all(GTK_CLIST(list)); #else gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(list))); #endif menu = OBJECT_GET_DATA(notebook_pg, E_MENU_SRCDST); menuitem = gtk_menu_get_active(GTK_MENU(menu)); requested_srcdst = GPOINTER_TO_INT(OBJECT_GET_DATA(menuitem, "user_data")); #ifdef DEBUG string = OBJECT_GET_DATA(notebook_pg, E_PAGE_TITLE); decode_debug(GTK_CLIST(list), string); #endif table_name = OBJECT_GET_DATA(notebook_pg, E_PAGE_TABLE); if (requested_srcdst >= E_DECODE_PPID) { if (requested_srcdst == E_DECODE_PPID) ppid = 0; else if (requested_srcdst - E_DECODE_PPID - 1 < MAX_NUMBER_OF_PPIDS) ppid = cfile.edt->pi.ppid[requested_srcdst - E_DECODE_PPID - 1]; else return; decode_change_one_dissector(table_name, ppid, list); return; } if (requested_srcdst != E_DECODE_DPORT) { portp = OBJECT_GET_DATA(notebook_pg, E_PAGE_SPORT); if (portp != NULL) { requested_port = GPOINTER_TO_INT(portp); decode_change_one_dissector(table_name, requested_port, list); } } if (requested_srcdst != E_DECODE_SPORT) { portp = OBJECT_GET_DATA(notebook_pg, E_PAGE_DPORT); if (portp != NULL) { requested_port = GPOINTER_TO_INT(portp); decode_change_one_dissector(table_name, requested_port, list); } } } /**************************************************/ /* 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 _U_, gpointer parent_w) { GtkWidget *notebook, *notebook_pg; void (* func)(GtkWidget *); gint page_num; void *binding = NULL; /* Call the right routine for the page that was currently in front. */ notebook = OBJECT_GET_DATA(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 = OBJECT_GET_DATA(notebook_pg, E_PAGE_ACTION); func(notebook_pg); /* Now destroy the "Decode As" dialog. */ notebook_pg = OBJECT_GET_DATA(parent_w, E_PAGE_DCERPC); if(notebook_pg) { binding = OBJECT_GET_DATA(notebook_pg, E_PAGE_BINDING); } if(binding) { decode_dcerpc_binding_free(binding); } window_destroy(GTK_WIDGET(parent_w)); g_slist_free(decode_dimmable); decode_dimmable = NULL; cf_redissect_packets(&cfile); } /* * This routine is called when the user clicks the "Apply" 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. * * @param apply_bt A pointer to the "Apply" button. * * @param parent_w A pointer to the dialog window. */ static void decode_apply_cb (GtkWidget *apply_bt _U_, gpointer parent_w) { GtkWidget *notebook, *notebook_pg; void (* func)(GtkWidget *); gint page_num; /* Call the right routine for the page that was currently in front. */ notebook = OBJECT_GET_DATA(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 = OBJECT_GET_DATA(notebook_pg, E_PAGE_ACTION); func(notebook_pg); cf_redissect_packets(&cfile); } /* * This routine is called when the user clicks the "Close" button in * the "Decode As..." dialog window. This routine then destroys the * dialog box and performs other housekeeping functions. * * @param close_bt A pointer to the "Close" button. * * @param parent_w A pointer to the dialog window. */ static void decode_close_cb (GtkWidget *close_bt _U_, gpointer parent_w) { GtkWidget *notebook_pg = NULL; void *binding = NULL; notebook_pg = OBJECT_GET_DATA(parent_w, E_PAGE_DCERPC); if(notebook_pg) { binding = OBJECT_GET_DATA(notebook_pg, E_PAGE_BINDING); } if(binding) { decode_dcerpc_binding_free(binding); } window_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 * close routine as if the user had clicked the close 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 _U_) { decode_close_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 _U_, gpointer user_data _U_) { /* Note that we no longer have a "Decode As" dialog box. */ decode_w = NULL; } /* * This routine is called when the user clicks the "Clear" button in * the "Decode As..." dialog window. This routine resets all the * dissector values and performs other housekeeping functions. * * @param GtkWidget * A pointer to the "Clear" button. * @param gpointer A pointer to the dialog window. */ static void decode_clear_cb(GtkWidget *clear_bt _U_, gpointer parent_w _U_) { decode_clear_all(); } /**************************************************/ /* 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 _U_, 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); SIGNAL_CONNECT(radio_button, "clicked", 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)); SIGNAL_CONNECT(radio_button, "clicked", 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 pack an option menu into an aligment, so * that it doesn't expand vertically to fill up the space available to * it. * * @param optmenu A pointer to the option menu to be so packed. * * @return GtkWidget * A pointer to the newly created alignment. */ static GtkWidget * decode_add_pack_menu (GtkWidget *optmenu) { GtkWidget *alignment; alignment = gtk_alignment_new(0.0, 0.5, 0.0, 0.0); gtk_container_add(GTK_CONTAINER(alignment), optmenu); return(alignment); } /* * 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 alignment into * which we've packed the newly created option menu. */ static GtkWidget * decode_add_srcdst_menu (GtkWidget *page) { GtkWidget *optmenu, *menu, *menuitem, *alignment; gchar tmp[100]; optmenu = gtk_option_menu_new(); menu = gtk_menu_new(); g_snprintf(tmp, 100, "source (%u)", cfile.edt->pi.srcport); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", 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 */ g_snprintf(tmp, 100, "destination (%u)", cfile.edt->pi.destport); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", 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"); OBJECT_SET_DATA(menuitem, "user_data", 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 */ OBJECT_SET_DATA(page, E_MENU_SRCDST, menu); gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); OBJECT_SET_DATA(page, E_PAGE_SPORT, GINT_TO_POINTER(cfile.edt->pi.srcport)); OBJECT_SET_DATA(page, E_PAGE_DPORT, GINT_TO_POINTER(cfile.edt->pi.destport)); alignment = decode_add_pack_menu(optmenu); return(alignment); } static GtkWidget * decode_add_ppid_menu (GtkWidget *page) { GtkWidget *optmenu, *menu, *menuitem; gchar tmp[100]; guint number_of_ppid; optmenu = gtk_option_menu_new(); menu = gtk_menu_new(); g_snprintf(tmp, 100, "PPID (%u)", 0); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", GINT_TO_POINTER(E_DECODE_PPID)); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) if (cfile.edt->pi.ppid[number_of_ppid] != 0) { g_snprintf(tmp, 100, "PPID (%u)", cfile.edt->pi.ppid[number_of_ppid]); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", GINT_TO_POINTER(E_DECODE_PPID + 1 + number_of_ppid)); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ } else break; OBJECT_SET_DATA(page, E_MENU_SRCDST, menu); gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); return(optmenu); } /*************************************************/ /* Dialog setup - list based menus */ /*************************************************/ #if GTK_MAJOR_VERSION >= 2 struct handle_lookup_info { dissector_handle_t handle; gboolean found; }; static gboolean lookup_handle(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter, gpointer data) { dissector_handle_t handle; struct handle_lookup_info *hli = (struct handle_lookup_info *)data; gtk_tree_model_get(model, iter, E_LIST_S_TABLE+1, &handle, -1); if (hli->handle == handle) { hli->found = TRUE; return TRUE; } return FALSE; } #endif /* * This routine creates one entry in the list of protocol dissector * that can be used. It is called by the dissector_table_foreach_handle * routine once for each entry in a dissector table's list of handles * for dissectors that could be used in that 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 table currently * being walked. * * @param value The dissector handle for this entry. 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_list (const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data) { const gchar *text[E_LIST_S_COLUMNS]; #if GTK_MAJOR_VERSION < 2 GtkCList *list; gint row; #else GtkTreeView *list; GtkListStore *store; GtkTreeIter iter; struct handle_lookup_info hli; #endif g_assert(user_data); g_assert(value); list = user_data; #if GTK_MAJOR_VERSION < 2 row = gtk_clist_find_row_from_data(list, value); /* We already have an entry for this handle. * XXX - will this ever happen? */ if (row != -1) return; #else hli.handle = value; hli.found = FALSE; store = GTK_LIST_STORE(gtk_tree_view_get_model(list)); gtk_tree_model_foreach(GTK_TREE_MODEL(store), lookup_handle, &hli); /* We already have an entry for this handle. * XXX - will this ever happen? */ if (hli.found) return; #endif text[E_LIST_S_PROTO_NAME] = proto_name; text[E_LIST_S_TABLE] = table_name; #if GTK_MAJOR_VERSION < 2 row = gtk_clist_prepend(list, (gchar **) text); gtk_clist_set_row_data(list, row, value); #else gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, E_LIST_S_PROTO_NAME, text[E_LIST_S_PROTO_NAME], E_LIST_S_TABLE, text[E_LIST_S_TABLE], E_LIST_S_TABLE+1, value, -1); #endif } static void decode_proto_add_to_list (const gchar *table_name, gpointer value, gpointer user_data) { const gchar *proto_name; gint i; dissector_handle_t handle; handle = value; proto_name = dissector_handle_get_short_name(handle); i = dissector_handle_get_protocol_index(handle); if (i >= 0 && !proto_is_protocol_enabled(find_protocol_by_id(i))) return; decode_add_to_list (table_name, proto_name, value, user_data); } /* * This routine starts the creation of a List on a notebook page. It * creates both a scrolled window and a list, adds the list to the * window, and attaches the list as a data object on the page. * * @param page A pointer to the notebook page being created. * * @param list_p Will be filled in with the address of a newly * created List. * * @param scrolled_win_p Will be filled in with the address of a newly * created GtkScrolledWindow. */ void decode_list_menu_start(GtkWidget *page, GtkWidget **list_p, GtkWidget **scrolled_win_p) { #if GTK_MAJOR_VERSION < 2 gchar *titles[E_LIST_S_COLUMNS] = {"Short Name", "Table Name"}; GtkCList *list; gint column; #else GtkTreeView *list; GtkListStore *store; GtkCellRenderer *renderer; GtkTreeViewColumn *tc; GtkTreeSortable *sortable; #endif #if GTK_MAJOR_VERSION < 2 list = GTK_CLIST(gtk_clist_new_with_titles(E_LIST_S_COLUMNS, titles)); OBJECT_SET_DATA(decode_w, "sctp_list", list); gtk_clist_column_titles_passive(list); #ifndef DEBUG gtk_clist_column_titles_hide(list); for (column = 1; column < E_LIST_S_COLUMNS; column++) gtk_clist_set_column_visibility (list, column, FALSE); #endif for (column = 0; column < E_LIST_S_COLUMNS; column++) gtk_clist_set_column_auto_resize(list, column, TRUE); OBJECT_SET_DATA(page, E_PAGE_LIST, list); #else store = gtk_list_store_new(E_LIST_S_COLUMNS+1, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); OBJECT_SET_DATA(G_OBJECT(decode_w), "sctp_data", store); list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store))); sortable = GTK_TREE_SORTABLE(store); gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL); gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING); gtk_tree_view_set_headers_clickable(list, FALSE); #ifndef DEBUG gtk_tree_view_set_headers_visible(list, FALSE); #endif renderer = gtk_cell_renderer_text_new(); tc = gtk_tree_view_column_new_with_attributes("Short Name", renderer, "text", E_LIST_S_PROTO_NAME, NULL); gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column(list, tc); g_object_set_data(G_OBJECT(page), E_PAGE_LIST, list); #endif *scrolled_win_p = scrolled_window_new(NULL, NULL); /* this will result to set the width of the dialog to the required size */ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); #if GTK_MAJOR_VERSION >= 2 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_SHADOW_IN); #endif #if GTK_MAJOR_VERSION < 2 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_WIDGET(list)); #else gtk_container_add(GTK_CONTAINER(*scrolled_win_p), GTK_WIDGET(list)); #endif *list_p = GTK_WIDGET(list); } /* * This routine finishes the creation of a List on a notebook page. * It adds the default entry, sets the default entry as the * highlighted entry, and sorts the List. * * @param list A pointer the the List to finish. */ void decode_list_menu_finish(GtkWidget *list) { const gchar *text[E_LIST_S_COLUMNS]; #if GTK_MAJOR_VERSION < 2 gint row; #else GtkListStore *store; GtkTreeIter iter; #endif text[E_LIST_S_PROTO_NAME] = "(default)"; text[E_LIST_S_TABLE] = "(none)"; #if GTK_MAJOR_VERSION < 2 row = gtk_clist_prepend(GTK_CLIST(list), (gchar **) text); gtk_clist_set_row_data(GTK_CLIST(list), row, NULL); gtk_clist_select_row(GTK_CLIST(list), 0, -1); gtk_clist_sort(GTK_CLIST(list)); #else store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list))); gtk_list_store_prepend(store, &iter); gtk_list_store_set(store, &iter, E_LIST_S_PROTO_NAME, text[E_LIST_S_PROTO_NAME], E_LIST_S_TABLE, text[E_LIST_S_TABLE], E_LIST_S_TABLE+1, NULL, -1); gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), &iter); #endif } /* * 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 table to use to build * this (list) menu. * * @return GtkWidget * A pointer to the newly created list within a * scrolled window. */ static GtkWidget * decode_add_simple_menu (GtkWidget *page, const gchar *table_name) { GtkWidget *scrolled_window; GtkWidget *list; decode_list_menu_start(page, &list, &scrolled_window); dissector_table_foreach_handle(table_name, decode_proto_add_to_list, list); decode_list_menu_finish(list); return(scrolled_window); } /**************************************************/ /* Dialog setup */ /**************************************************/ /* * This routine creates a sample notebook page in the dialog box. * This notebook page provides a prompt specifying what is being * changed and its current value (e.g. "IP Protocol number (17)"), and * a list 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 title for this page to use when debugging. * * @param table_name The name of the dissector 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 (const gchar *prompt, const gchar *title, const gchar *table_name, guint value) { GtkWidget *page, *label, *scrolled_window; page = gtk_hbox_new(FALSE, 5); OBJECT_SET_DATA(page, E_PAGE_ACTION, decode_simple); OBJECT_SET_DATA(page, E_PAGE_TABLE, (gchar *) table_name); OBJECT_SET_DATA(page, E_PAGE_TITLE, (gchar *) title); OBJECT_SET_DATA(page, E_PAGE_VALUE, GUINT_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 or UDP notebook page in the dialog box. * All items created by this routine are packed into a single * horizontal box. First is a label indicating whether the port(s) for * which the user can set the dissection is a TCP port or a UDP port. * 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". * * @param prompt The prompt for this notebook page * * @param table_name The name of the dissector table to use to * build this page. * * @return GtkWidget * A pointer to the notebook page created by * this routine. */ static GtkWidget * decode_add_tcpudp_page (const gchar *prompt, const gchar *table_name) { GtkWidget *page, *label, *scrolled_window, *optmenu; page = gtk_hbox_new(FALSE, 5); OBJECT_SET_DATA(page, E_PAGE_ACTION, decode_transport); OBJECT_SET_DATA(page, E_PAGE_TABLE, (gchar *) table_name); OBJECT_SET_DATA(page, E_PAGE_TITLE, "Transport"); /* Always enabled */ label = gtk_label_new(prompt); gtk_box_pack_start(GTK_BOX(page), label, 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_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); } static void decode_sctp_list_menu_start(GtkWidget **list_p, GtkWidget **scrolled_win_p) { #if GTK_MAJOR_VERSION < 2 /* gchar *titles[E_LIST_S_COLUMNS] = {"Short Name", "Table Name"};*/ GtkCList *list; gint column; #else GtkTreeView *list; GtkListStore *sctp_store; GtkCellRenderer *renderer; GtkTreeViewColumn *tc; GtkTreeSortable *sortable; #endif #if GTK_MAJOR_VERSION < 2 list=OBJECT_GET_DATA(decode_w, "sctp_list"); gtk_clist_column_titles_passive(list); #ifndef DEBUG gtk_clist_column_titles_hide(list); for (column = 1; column < E_LIST_S_COLUMNS; column++) gtk_clist_set_column_visibility (list, column, FALSE); #endif for (column = 0; column < E_LIST_S_COLUMNS; column++) gtk_clist_set_column_auto_resize(list, column, TRUE); #else sctp_store = OBJECT_GET_DATA(decode_w, "sctp_data"); list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(sctp_store))); sortable = GTK_TREE_SORTABLE(sctp_store); gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL); gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING); gtk_tree_view_set_headers_clickable(list, FALSE); #ifndef DEBUG gtk_tree_view_set_headers_visible(list, FALSE); #endif renderer = gtk_cell_renderer_text_new(); tc = gtk_tree_view_column_new_with_attributes("Short Name", renderer, "text", E_LIST_S_PROTO_NAME, NULL); gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column(list, tc); #endif *scrolled_win_p = scrolled_window_new(NULL, NULL); /* this will result to set the width of the dialog to the required size */ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); #if GTK_MAJOR_VERSION >= 2 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_SHADOW_IN); gtk_container_add(GTK_CONTAINER(*scrolled_win_p), GTK_WIDGET(list)); #endif *list_p = GTK_WIDGET(list); } static void decode_sctp_update_ppid_menu(GtkWidget *w _U_, GtkWidget *page) { GtkWidget *menu, *menuitem, *list, *scrolled_window, *sctpmenu; gchar tmp[100]; guint number_of_ppid; #if GTK_MAJOR_VERSION < 2 GtkCList *sctp_list; #else GtkListStore *sctp_store; #endif menu = gtk_menu_new(); g_snprintf(tmp, 100, "PPID (%u)", 0); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", GINT_TO_POINTER(E_DECODE_PPID)); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++) if (cfile.edt->pi.ppid[number_of_ppid] != 0) { g_snprintf(tmp, 100, "PPID (%u)", cfile.edt->pi.ppid[number_of_ppid]); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", GINT_TO_POINTER(E_DECODE_PPID + 1 + number_of_ppid)); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); /* gtk_widget_show_all() doesn't show this */ } else break; OBJECT_SET_DATA(page, E_MENU_SRCDST, menu); OBJECT_SET_DATA(page, E_PAGE_TABLE, "sctp.ppi"); sctpmenu = OBJECT_GET_DATA(decode_w, "user_data"); gtk_option_menu_set_menu(GTK_OPTION_MENU(sctpmenu), menu); #if GTK_MAJOR_VERSION < 2 sctp_list = OBJECT_GET_DATA(decode_w, "sctp_list"); gtk_clist_clear(sctp_list); #else sctp_store = OBJECT_GET_DATA(G_OBJECT(decode_w), "sctp_data"); gtk_list_store_clear(sctp_store); #endif decode_sctp_list_menu_start(&list, &scrolled_window); dissector_table_foreach_handle("sctp.ppi", decode_proto_add_to_list, list); decode_list_menu_finish(list); } static void decode_sctp_update_srcdst_menu(GtkWidget *w _U_, GtkWidget *page) { GtkWidget *menu, *menuitem, *scrolled_window, *list, *sctpmenu; gchar tmp[100]; #if GTK_MAJOR_VERSION < 2 GtkCList *sctp_list; #else GtkListStore *sctp_store; #endif menu = gtk_menu_new(); g_snprintf(tmp, 100, "source (%u)", cfile.edt->pi.srcport); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", 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 */ g_snprintf(tmp, 100, "destination (%u)", cfile.edt->pi.destport); menuitem = gtk_menu_item_new_with_label(tmp); OBJECT_SET_DATA(menuitem, "user_data", 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"); OBJECT_SET_DATA(menuitem, "user_data", 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 */ OBJECT_SET_DATA(page, E_MENU_SRCDST, menu); OBJECT_SET_DATA(page, E_PAGE_TABLE, "sctp.port"); sctpmenu = OBJECT_GET_DATA(decode_w, "user_data"); gtk_option_menu_set_menu(GTK_OPTION_MENU(sctpmenu), menu); OBJECT_SET_DATA(page, E_PAGE_SPORT, GINT_TO_POINTER(cfile.edt->pi.srcport)); OBJECT_SET_DATA(page, E_PAGE_DPORT, GINT_TO_POINTER(cfile.edt->pi.destport)); #if GTK_MAJOR_VERSION < 2 sctp_list = OBJECT_GET_DATA(decode_w, "sctp_list"); gtk_clist_clear(sctp_list); #else sctp_store = OBJECT_GET_DATA(G_OBJECT(decode_w), "sctp_data"); gtk_list_store_clear(sctp_store); #endif decode_sctp_list_menu_start(&list, &scrolled_window); dissector_table_foreach_handle("sctp.port", decode_proto_add_to_list, list); decode_list_menu_finish(list); } static GtkWidget * decode_sctp_add_port_ppid (GtkWidget *page) { GtkWidget *format_vb, *radio_button; GSList *format_grp; format_vb = gtk_vbox_new(FALSE, 2); radio_button = gtk_radio_button_new_with_label(NULL, "PPID"); format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(radio_button)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE); SIGNAL_CONNECT(radio_button, "clicked", decode_sctp_update_ppid_menu, page); gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0); radio_button = gtk_radio_button_new_with_label(format_grp, "Port"); format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(radio_button)); SIGNAL_CONNECT(radio_button, "clicked", decode_sctp_update_srcdst_menu, page); gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0); return(format_vb); } static GtkWidget * decode_add_sctp_page (const gchar *prompt, const gchar *table_name) { GtkWidget *page, *label, *scrolled_window, *radio, *vbox, *alignment, *sctpbox, *sctpmenu; page = gtk_hbox_new(FALSE, 5); OBJECT_SET_DATA(page, E_PAGE_ACTION, decode_transport); OBJECT_SET_DATA(page, E_PAGE_TABLE, (gchar *) table_name); OBJECT_SET_DATA(page, E_PAGE_TITLE, "Transport"); vbox = gtk_vbox_new(FALSE, 5); radio = decode_sctp_add_port_ppid(page); gtk_box_pack_start(GTK_BOX(vbox), radio, TRUE, TRUE, 0); /* Always enabled */ sctpbox = gtk_hbox_new(FALSE, 5); label = gtk_label_new(prompt); gtk_box_pack_start(GTK_BOX(sctpbox), label, TRUE, TRUE, 0); sctpmenu = decode_add_ppid_menu(page); OBJECT_SET_DATA(decode_w, "user_data", sctpmenu); alignment = decode_add_pack_menu(sctpmenu); gtk_box_pack_start(GTK_BOX(sctpbox), alignment, TRUE, TRUE, 0); /* Conditionally enabled - only when decoding packets */ label = gtk_label_new("as"); gtk_box_pack_start(GTK_BOX(sctpbox), label, TRUE, TRUE, 0); decode_dimmable = g_slist_prepend(decode_dimmable, label); gtk_box_pack_start(GTK_BOX(vbox), sctpbox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(page), vbox, TRUE, TRUE, 0); 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 indicates whether we'd actually have any pages in the * notebook in a "Decode As" dialog box; if there wouldn't be, we * inactivate the menu item for "Decode As". */ gboolean decode_as_ok(void) { return cfile.edt->pi.ethertype || cfile.edt->pi.ipproto || cfile.edt->pi.ptype == PT_TCP || cfile.edt->pi.ptype == PT_UDP; } /* * 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. */ static 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); OBJECT_SET_DATA(decode_w, E_NOTEBOOK, notebook); /* Add link level selection page */ if (cfile.edt->pi.ethertype) { g_snprintf(buffer, 40, "Ethertype 0x%04x", cfile.edt->pi.ethertype); page = decode_add_simple_page(buffer, "Link", "ethertype", cfile.edt->pi.ethertype); label = gtk_label_new("Link"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); } /* Add network selection page */ if (cfile.edt->pi.ipproto) { /* * The network-layer protocol is IP. */ g_snprintf(buffer, 40, "IP protocol %u", cfile.edt->pi.ipproto); page = decode_add_simple_page(buffer, "Network", "ip.proto", cfile.edt->pi.ipproto); OBJECT_SET_DATA(page, E_PAGE_ACTION, decode_simple); label = gtk_label_new("Network"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); } /* Add transport selection page */ switch (cfile.edt->pi.ptype) { case PT_TCP: page = decode_add_tcpudp_page("TCP", "tcp.port"); break; case PT_UDP: page = decode_add_tcpudp_page("UDP", "udp.port"); break; case PT_SCTP: page = decode_add_sctp_page("SCTP", "sctp.ppi"); break; default: page = NULL; break; } if (page != NULL) { label = gtk_label_new("Transport"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); } if(cfile.edt->pi.dcetransporttype != -1) { page = decode_dcerpc_add_page(&cfile.edt->pi); label = gtk_label_new("DCE-RPC"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); OBJECT_SET_DATA(decode_w, E_PAGE_DCERPC, page); } /* 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 _U_, gpointer data _U_) { GtkWidget *main_vb, *format_hb, *bbox, *ok_bt, *close_bt, *help_bt, *button; GtkWidget *button_vb, *apply_bt; GtkTooltips *tooltips = gtk_tooltips_new(); 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"); /* Provide a minimum of a couple of rows worth of data */ gtk_window_set_default_size(GTK_WINDOW(decode_w), -1, E_DECODE_MIN_HEIGHT); /* 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); button = gtk_button_new_with_label("Show Current"); SIGNAL_CONNECT(button, "clicked", decode_show_cb, decode_w); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_box_pack_start(GTK_BOX(button_vb), button, FALSE, FALSE, 0); gtk_tooltips_set_tip(tooltips, button, "Open a dialog showing the current settings.", NULL); button = gtk_button_new_with_label("Clear"); SIGNAL_CONNECT(button, "clicked", decode_clear_cb, decode_w); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_box_pack_start(GTK_BOX(button_vb), button, FALSE, FALSE, 0); gtk_tooltips_set_tip(tooltips, button, "Clear ALL settings.", NULL); decode_add_notebook(format_hb); } /* Button row */ if(topic_available(HELP_DECODE_AS_DIALOG)) { bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL); } else { bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CLOSE, NULL); } gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0); gtk_widget_show(bbox); ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK); SIGNAL_CONNECT(ok_bt, "clicked", decode_ok_cb, decode_w); gtk_tooltips_set_tip(tooltips, ok_bt, "Apply current setting, close dialog and redissect packets.", NULL); apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY); SIGNAL_CONNECT(apply_bt, "clicked", decode_apply_cb, decode_w); gtk_tooltips_set_tip(tooltips, apply_bt, "Apply current setting, redissect packets and keep dialog open.", NULL); close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE); window_set_cancel_button(decode_w, close_bt, NULL); SIGNAL_CONNECT(close_bt, "clicked", decode_close_cb, decode_w); gtk_tooltips_set_tip(tooltips, close_bt, "Close the dialog, don't redissect packets.", NULL); if(topic_available(HELP_DECODE_AS_DIALOG)) { help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP); SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_DECODE_AS_DIALOG); } gtk_widget_grab_default(ok_bt); SIGNAL_CONNECT(decode_w, "delete_event", decode_delete_cb, NULL); SIGNAL_CONNECT(decode_w, "destroy", decode_destroy_cb, NULL); gtk_widget_show_all(decode_w); window_present(decode_w); }