From Didier Gautheron (bug 3126):
[obnox/wireshark/wip.git] / gtk / decode_as_dlg.c
1 /* decode_as_dlg.c
2  *
3  * $Id$
4  *
5  * Routines to modify dissector tables on the fly.
6  *
7  * By David Hampton <dhampton@mac.com>
8  * Copyright 2001 David Hampton
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 #include <string.h>
29
30 #include <gtk/gtk.h>
31 #include <gdk/gdkkeysyms.h>
32
33 #include <epan/packet.h>
34 #include <epan/ipproto.h>
35 #include <epan/epan_dissect.h>
36
37 #include "../globals.h"
38 #include "../simple_dialog.h"
39
40 #include "gtk/main.h"
41 #include "gtk/decode_as_dlg.h"
42 #include "gtk/dlg_utils.h"
43 #include "gtk/gui_utils.h"
44 #include "gtk/decode_as_dcerpc.h"
45 #include "gtk/decode_as_ber.h"
46 #include "gtk/help_dlg.h"
47
48 #undef DEBUG
49
50 /**************************************************/
51 /*                Typedefs & Enums                */
52 /**************************************************/
53
54 /*
55  * Enum used to track which transport layer port menu item is
56  * currently selected in the dialog.  These items are labeled "source",
57  * "destination", and "source/destination".
58  */
59 enum srcdst_type {
60     /* The "source port" menu item is currently selected. */
61     E_DECODE_SPORT,
62     /* The "destination port" menu item is currently selected. */
63     E_DECODE_DPORT,
64     /* The "source/destination port" menu item is currently selected. */
65     E_DECODE_BPORT,
66     /* For SCTP only. This MUST be the last entry! */
67     E_DECODE_PPID
68 };
69
70 #define E_DECODE_MIN_HEIGHT 300
71 #define E_NOTEBOOK "notebook"
72
73 #define E_MENU_SRCDST "menu_src_dst"
74
75 #define E_PAGE_DPORT "dport"
76 #define E_PAGE_SPORT "sport"
77 #define E_PAGE_PPID  "ppid"
78 #define E_PAGE_ASN1  "asn1"
79
80
81 /*
82  * Columns for a "Display" list
83  */
84 #define E_LIST_D_TABLE      0
85 #define E_LIST_D_SELECTOR   1
86 #define E_LIST_D_INITIAL    2
87 #define E_LIST_D_CURRENT    3
88 #define E_LIST_D_MAX        E_LIST_D_CURRENT
89 #define E_LIST_D_COLUMNS   (E_LIST_D_MAX + 1)
90
91 /**************************************************/
92 /*             File Global Variables              */
93 /**************************************************/
94
95 /*
96  * Keep a static pointer to the current "Decode As" window.  This is
97  * kept so that if somebody tries to do "Tools:Decode As" while
98  * there's already a "Decode As" window up, we just pop up the
99  * existing one, rather than creating a new one.
100  */
101 static GtkWidget *decode_w = NULL;
102
103 /*
104  * A static pointer to the current "Decode As:Show" window.  This is
105  * kept so that if somebody tries to do clock the "Show Current"
106  * button or select the "Display:User Specified Decodes" menu item
107  * while there's already a "Decode As:Show" window up, we just pop up
108  * the existing one, rather than creating a new one.
109  */
110 static GtkWidget *decode_show_w = NULL;
111
112 /*
113  * A list of the dialog items that only have meaning when the user has
114  * selected the "Decode" radio button.  When the "Do not decode"
115  * button is selected these items should be dimmed.
116  */
117 GSList *decode_dimmable = NULL;
118
119 /*
120  * Remember the "action" radio button that is currently selected in
121  * the dialog.  This value is initialized when the dialog is created,
122  * modified in a callback routine, and read in the routine that
123  * handles a click in the "OK" button for the dialog.
124  */
125 enum action_type        requested_action = -1;
126
127
128 /**************************************************/
129 /*            Global Functions                    */
130 /**************************************************/
131
132 /* init this module */
133 void decode_as_init(void) {
134
135     decode_dcerpc_init();
136 }
137
138 /**************************************************/
139 /*            Reset Changed Dissectors            */
140 /**************************************************/
141
142 /*
143  * Data structure for tracking which dissector need to be reset.  This
144  * structure is necessary as a hash table entry cannot be removed
145  * while a g_hash_table_foreach walk is in progress.
146  */
147 struct dissector_delete_item {
148     /* The name of the dissector table */
149     const gchar *ddi_table_name;
150     /* The type of the selector in that dissector table */
151     ftenum_t ddi_selector_type;
152     /* The selector in the dissector table */
153     union {
154         guint   sel_uint;
155         char    *sel_string;
156     } ddi_selector;
157 };
158
159 /*
160  * A typedef for the data structure to track the original dissector
161  * used for any given port on any given protocol.
162  */
163 typedef struct dissector_delete_item dissector_delete_item_t;
164
165 /*
166  * A list of dissectors that need to be reset.
167  */
168 GSList *dissector_reset_list = NULL;
169
170 /*
171  * This routine creates one entry in the list of protocol dissector
172  * that need to be reset. It is called by the g_hash_table_foreach
173  * routine once for each changed entry in a dissector table.
174  * Unfortunately it cannot delete the entry immediately as this screws
175  * up the foreach function, so it builds a list of dissectors to be
176  * reset once the foreach routine finishes.
177  *
178  * @param table_name The table name in which this dissector is found.
179  *
180  * @param key A pointer to the key for this entry in the dissector
181  * hash table.  This is generally the numeric selector of the
182  * protocol, i.e. the ethernet type code, IP port number, TCP port
183  * number, etc.
184  *
185  * @param value A pointer to the value for this entry in the dissector
186  * hash table.  This is an opaque pointer that can only be handed back
187  * to routine in the file packet.c - but it's unused.
188  *
189  * @param user_data Unused.
190  */
191 static void
192 decode_build_reset_list (const gchar *table_name, ftenum_t selector_type,
193                          gpointer key, gpointer value _U_,
194                          gpointer user_data _U_)
195 {
196     dissector_delete_item_t *item;
197
198     item = g_malloc(sizeof(dissector_delete_item_t));
199     item->ddi_table_name = table_name;
200     item->ddi_selector_type = selector_type;
201     switch (selector_type) {
202
203     case FT_UINT8:
204     case FT_UINT16:
205     case FT_UINT24:
206     case FT_UINT32:
207         item->ddi_selector.sel_uint = GPOINTER_TO_UINT(key);
208         break;
209
210     case FT_STRING:
211     case FT_STRINGZ:
212         item->ddi_selector.sel_string = key;
213         break;
214
215     default:
216         g_assert_not_reached();
217     }
218     dissector_reset_list = g_slist_prepend(dissector_reset_list, item);
219 }
220
221
222 /**************************************************/
223 /*             Show Changed Dissectors            */
224 /**************************************************/
225
226 #define SORT_ALPHABETICAL 0
227
228 static gint
229 sort_iter_compare_func (GtkTreeModel *model,
230 GtkTreeIter *a,
231 GtkTreeIter *b,
232 gpointer userdata)
233 {
234     gint sortcol = GPOINTER_TO_INT(userdata);
235     gint ret = 0;
236     switch (sortcol)
237     {
238         case SORT_ALPHABETICAL:
239         {
240         gchar *name1, *name2;
241         gtk_tree_model_get(model, a, 0, &name1, -1);
242         gtk_tree_model_get(model, b, 0, &name2, -1);
243         if (name1 == NULL || name2 == NULL)
244         {
245             if (name1 == NULL && name2 == NULL)
246                 break; /* both equal => ret = 0 */
247             ret = (name1 == NULL) ? -1 : 1;
248         }
249         else
250         {
251             ret = g_ascii_strcasecmp(name1,name2);
252         }
253         g_free(name1);
254         g_free(name2);
255         }
256         break;
257         default:
258         g_return_val_if_reached(0);
259     }
260     return ret;
261 }
262
263
264 void
265 decode_add_to_show_list (
266 gpointer list_data, 
267 const gchar *table_name, 
268 gchar *selector_name, 
269 const gchar *initial_proto_name, 
270 const gchar *current_proto_name)
271 {
272     const gchar     *text[E_LIST_D_COLUMNS];
273     GtkListStore *store;
274     GtkTreeIter   iter;
275
276     store = (GtkListStore *)list_data;
277
278     text[E_LIST_D_TABLE] = table_name;
279     text[E_LIST_D_SELECTOR] = selector_name;
280     text[E_LIST_D_INITIAL] = initial_proto_name;
281     text[E_LIST_D_CURRENT] = current_proto_name;
282     gtk_list_store_append(store, &iter);
283     gtk_list_store_set(store, &iter, E_LIST_D_TABLE, text[E_LIST_D_TABLE],
284                        E_LIST_D_SELECTOR, text[E_LIST_D_SELECTOR],
285                        E_LIST_D_INITIAL, text[E_LIST_D_INITIAL],
286                        E_LIST_D_CURRENT, text[E_LIST_D_CURRENT], -1);
287 }
288
289
290 /*
291  * This routine creates one entry in the list of protocol dissector
292  * that have been changed.  It is called by the g_hash_foreach routine
293  * once for each changed entry in a dissector table.
294  *
295  * @param table_name The table name in which this dissector is found.
296  *
297  * @param key A pointer to the key for this entry in the dissector
298  * hash table.  This is generally the numeric selector of the
299  * protocol, i.e. the ethernet type code, IP port number, TCP port
300  * number, etc.
301  *
302  * @param value A pointer to the value for this entry in the dissector
303  * hash table.  This is an opaque pointer that can only be handed back
304  * to routine in the file packet.c
305  *
306  * @param user_data A pointer to the list in which this information
307  * should be stored.
308  */
309 static void
310 decode_build_show_list (const gchar *table_name, ftenum_t selector_type,
311                         gpointer key, gpointer value, gpointer user_data)
312 {
313     dissector_handle_t current, initial;
314     const gchar *current_proto_name, *initial_proto_name;
315     gchar       *selector_name;
316     gchar        string1[20];
317
318     g_assert(user_data);
319     g_assert(value);
320
321     current = dtbl_entry_get_handle(value);
322     if (current == NULL)
323         current_proto_name = "(none)";
324     else
325         current_proto_name = dissector_handle_get_short_name(current);
326     initial = dtbl_entry_get_initial_handle(value);
327     if (initial == NULL)
328         initial_proto_name = "(none)";
329     else
330         initial_proto_name = dissector_handle_get_short_name(initial);
331
332     switch (selector_type) {
333
334     case FT_UINT8:
335     case FT_UINT16:
336     case FT_UINT24:
337     case FT_UINT32:
338         switch (get_dissector_table_base(table_name)) {
339
340         case BASE_DEC:
341             g_snprintf(string1, sizeof(string1), "%u", GPOINTER_TO_UINT(key));
342             break;
343
344         case BASE_HEX:
345             switch (get_dissector_table_selector_type(table_name)) {
346
347             case FT_UINT8:
348                 g_snprintf(string1, sizeof(string1), "0x%02x", GPOINTER_TO_UINT(key));
349                 break;
350
351             case FT_UINT16:
352                 g_snprintf(string1, sizeof(string1), "0x%04x", GPOINTER_TO_UINT(key));
353                 break;
354
355             case FT_UINT24:
356                 g_snprintf(string1, sizeof(string1), "0x%06x", GPOINTER_TO_UINT(key));
357                 break;
358
359             case FT_UINT32:
360                 g_snprintf(string1, sizeof(string1), "0x%08x", GPOINTER_TO_UINT(key));
361                 break;
362
363             default:
364                 g_assert_not_reached();
365                 break;
366             }
367             break;
368
369         case BASE_OCT:
370             g_snprintf(string1, sizeof(string1), "%#o", GPOINTER_TO_UINT(key));
371             break;
372         }
373         selector_name = string1;
374         break;
375
376     case FT_STRING:
377     case FT_STRINGZ:
378         selector_name = key;
379         break;
380
381     default:
382         g_assert_not_reached();
383         selector_name = NULL;
384         break;
385     }
386
387     decode_add_to_show_list (
388         user_data, 
389         get_dissector_table_ui_name(table_name),
390         selector_name, 
391         initial_proto_name, 
392         current_proto_name);
393 }
394
395
396 /* clear all settings */
397 static void
398 decode_clear_all(void)
399 {
400     dissector_delete_item_t *item;
401     GSList *tmp;
402
403     dissector_all_tables_foreach_changed(decode_build_reset_list, NULL);
404
405     for (tmp = dissector_reset_list; tmp; tmp = g_slist_next(tmp)) {
406         item = tmp->data;
407         switch (item->ddi_selector_type) {
408
409         case FT_UINT8:
410         case FT_UINT16:
411         case FT_UINT24:
412         case FT_UINT32:
413             dissector_reset(item->ddi_table_name, item->ddi_selector.sel_uint);
414             break;
415
416         case FT_STRING:
417         case FT_STRINGZ:
418             dissector_reset_string(item->ddi_table_name,
419                                    item->ddi_selector.sel_string);
420             break;
421
422         default:
423             g_assert_not_reached();
424         }
425         g_free(item);
426     }
427     g_slist_free(dissector_reset_list);
428     dissector_reset_list = NULL;
429
430     decode_dcerpc_reset_all();
431
432     redissect_packets();
433 }
434
435
436 /*
437  * This routine is called when the user clicks the "OK" button in
438  * the "Decode As:Show..." dialog window.  This routine destroys the
439  * dialog box and performs other housekeeping functions.
440  *
441  * @param GtkWidget * A pointer to the "OK" button.
442  *
443  * @param gpointer A pointer to the dialog window.
444  */
445 static void
446 decode_show_ok_cb (GtkWidget *ok_bt _U_, gpointer parent_w)
447 {
448     window_destroy(GTK_WIDGET(parent_w));
449 }
450
451
452 /*
453  * This routine is called when the user clicks the "Clear" button in
454  * the "Decode As:Show..." dialog window.  This routine resets all the
455  * dissector values and then destroys the dialog box and performs
456  * other housekeeping functions.
457  *
458  * @param GtkWidget * A pointer to the "Clear" button.
459  *
460  * @param gpointer A pointer to the dialog window.
461  */
462 static void
463 decode_show_clear_cb (GtkWidget *clear_bt _U_, gpointer parent_w)
464 {
465     decode_clear_all();
466
467     window_destroy(GTK_WIDGET(parent_w));
468 }
469
470
471 /*
472  * This routine is called when the user clicks the X at the top right end in
473  * the "Decode As:Show..." dialog window.  This routine simply calls the
474  * ok routine as if the user had clicked the ok button.
475  *
476  * @param GtkWidget * A pointer to the dialog box.
477  *
478  * @param gpointer Unknown
479  */
480 static gboolean
481 decode_show_delete_cb (GtkWidget *decode_w _U_, gpointer dummy _U_)
482 {
483     decode_show_ok_cb(NULL, decode_show_w);
484     return FALSE;
485 }
486
487
488 /*
489  * This routine is called at the destruction of the "Decode As:Show"
490  * dialog box.  It clears the pointer maintained by this file, so that
491  * the next time the user clicks the "Decode As:Show" button a new
492  * dialog box will be created.
493  *
494  * @param GtkWidget * A pointer to the dialog box.
495  *
496  * @param gpointer Unknown
497  */
498 static void
499 decode_show_destroy_cb (GtkWidget *win _U_, gpointer user_data _U_)
500 {
501     /* Note that we no longer have a "Decode As:Show" dialog box. */
502     decode_show_w = NULL;
503 }
504
505
506 /*
507  * This routine creates the "Decode As:Show" dialog box. This dialog box
508  * shows the user which protocols have had their dissectors changed.
509  *
510  * @param w Unknown
511  * @param data Unknown
512  */
513 void
514 decode_show_cb (GtkWidget * w _U_, gpointer data _U_)
515 {
516     GtkWidget         *main_vb, *bbox, *ok_bt, *clear_bt, *help_bt, *scrolled_window;
517     const gchar       *titles[E_LIST_D_COLUMNS] = {
518         "Table", "Value", "Initial", "Current"
519     };
520     gint               column;
521     GtkListStore      *store;
522     GtkTreeView       *list;
523     GtkCellRenderer   *renderer;
524     GtkTreeViewColumn *tc;
525     GtkTreeIter        iter;
526
527     if (decode_show_w != NULL) {
528         /* There's already a "Decode As" dialog box; reactivate it. */
529         reactivate_window(decode_show_w);
530         return;
531     }
532
533     decode_show_w = dlg_window_new("Wireshark: Decode As: Show");
534         /* Provide a minimum of a couple of rows worth of data */
535     gtk_window_set_default_size(GTK_WINDOW(decode_show_w), -1, E_DECODE_MIN_HEIGHT);
536
537     /* Container for each row of widgets */
538     main_vb = gtk_vbox_new(FALSE, 2);
539     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
540     gtk_container_add(GTK_CONTAINER(decode_show_w), main_vb);
541
542     /* Initialize list */
543     store = gtk_list_store_new(E_LIST_D_COLUMNS, G_TYPE_STRING,
544                                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
545     list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
546     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
547     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(list), FALSE);
548     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(list),
549                                 GTK_SELECTION_NONE);
550
551     for (column = 0; column < E_LIST_D_COLUMNS; column++) {
552         renderer = gtk_cell_renderer_text_new();
553         tc = gtk_tree_view_column_new_with_attributes(titles[column],
554                                                       renderer, "text",
555                                                       column, NULL);
556         gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
557         gtk_tree_view_append_column(list, tc);
558     }
559
560     /* Add data */
561     dissector_all_tables_foreach_changed(decode_build_show_list, store);
562     g_object_unref(G_OBJECT(store));
563     decode_dcerpc_add_show_list(store);
564
565     /* Put clist into a scrolled window */
566     scrolled_window = scrolled_window_new(NULL, NULL);
567     /* this will result to set the width of the dialog to the required size */
568     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
569                                    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
570     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), 
571                                         GTK_SHADOW_IN);
572     gtk_container_add(GTK_CONTAINER(scrolled_window),
573                       GTK_WIDGET(list));
574     gtk_box_pack_start(GTK_BOX(main_vb), scrolled_window, TRUE, TRUE, 0);
575
576     /* Button row */
577     bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CLEAR, GTK_STOCK_HELP, NULL);
578     gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
579     gtk_widget_show(bbox);
580
581     ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
582     g_signal_connect(ok_bt, "clicked", G_CALLBACK(decode_show_ok_cb), decode_show_w);
583     
584     clear_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLEAR);
585     g_signal_connect(clear_bt, "clicked", G_CALLBACK(decode_show_clear_cb), decode_show_w);
586
587     help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
588     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_DECODE_AS_SHOW_DIALOG);
589
590     /* set ok as default, this button won't change anything */
591     window_set_cancel_button(decode_show_w, ok_bt, NULL);
592
593     g_signal_connect(decode_show_w, "delete_event", G_CALLBACK(decode_show_delete_cb), NULL);
594     g_signal_connect(decode_show_w, "destroy", G_CALLBACK(decode_show_destroy_cb), NULL);
595     
596     gtk_widget_set_sensitive(clear_bt,
597                              gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter));
598
599     gtk_widget_show_all(decode_show_w);
600     window_present(decode_show_w);
601 }
602
603
604 /**************************************************/
605 /*         Modify the dissector routines          */
606 /**************************************************/
607
608 /*
609  * Modify a single dissector.  This routine first takes care of
610  * updating the internal table of original protocol/port/dissector
611  * combinations by adding a new entry (or removing an existing entry
612  * if the value is being set back to its default).  This routine then
613  * performs the actual modification to the packet dissector tables.
614  *
615  * @param s Pointer to a string buffer.  This buffer is used to build
616  * up a message indicating which ports have had their dissector
617  * changed. This output will be displayed all at once after all
618  * dissectors have been modified.
619  *
620  * @param table_name The table name in which the dissector should be
621  * modified.
622  *
623  * @param selector An enum value indication which selector value
624  * (i.e. IP protocol number, TCP port number, etc.)is to be changed.
625  *
626  * @param list The List in which all the selection information can
627  * be found.
628  *
629  * @return gchar * Pointer to the next free location in the string
630  * buffer.
631  */
632 static void
633 decode_change_one_dissector(gchar *table_name, guint selector, GtkWidget *list)
634 {
635     dissector_handle_t handle;
636     gchar              *abbrev;
637     GtkTreeSelection  *selection;
638     GtkTreeModel      *model;
639     GtkTreeIter        iter;
640
641     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
642     if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
643     {
644         abbrev = NULL;
645         handle = NULL;
646     } else {
647         gtk_tree_model_get(model, &iter, E_LIST_S_PROTO_NAME, &abbrev,
648                            E_LIST_S_TABLE+1, &handle, -1);
649     }
650
651     if (abbrev != NULL && strcmp(abbrev, "(default)") == 0) {
652         dissector_reset(table_name, selector);
653     } else {
654         dissector_change(table_name, selector, handle);
655     }
656     g_free(abbrev);
657 }
658
659
660 /**************************************************/
661 /* Action routines for the "Decode As..." dialog  */
662 /*   - called when the OK button pressed          */
663 /*   - one per notebook page                      */
664 /**************************************************/
665
666
667 #ifdef DEBUG
668 /*
669  * Print debugging information about clist selection.  Extract all
670  * information from the clist entry that was selected and print it to
671  * a dialog window.
672  *
673  * @param clist The clist to dump.
674  *
675  * @param leadin A string to print at the start of each line.
676  */
677 static void
678 decode_debug (GtkCList *clist, gchar *leadin)
679 {
680     gchar *string, *text[E_LIST_S_COLUMNS];
681     dissector_handle_t handle;
682     gint row;
683
684     if (clist->selection) {
685         row = GPOINTER_TO_INT(clist->selection->data);
686         gtk_clist_get_text(clist, row, E_LIST_S_PROTO_NAME, &text[E_LIST_S_PROTO_NAME]);
687         gtk_clist_get_text(clist, row, E_LIST_S_TABLE, &text[E_LIST_S_TABLE]);
688         handle = gtk_clist_get_row_data(clist, row);
689         string = g_strdup_printf("%s clist row %d: <put handle here>, name %s, table %s",
690                 leadin, row, text[E_LIST_S_PROTO_NAME],
691                 text[E_LIST_S_TABLE]);
692     } else {
693         string = g_strdup_printf("%s clist row (none), aka do not decode", leadin);
694     }
695     simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, string);
696     g_free(string);
697 }
698 #endif
699
700
701 /*
702  * This routine is called when the user clicks the "OK" button in the
703  * "Decode As..." dialog window and a 'simple' page is foremost.
704  * This routine takes care of making any changes requested to the
705  * dissector tables.  This routine is currently used for IP and
706  * Ethertypes.  Any 'single change' notebook page can use this
707  * routine.
708  *
709  * @param notebook_pg A pointer to the "network" notebook page.
710  */
711 static void
712 decode_simple (GtkWidget *notebook_pg)
713 {
714     GtkWidget *list;
715 #ifdef DEBUG
716     gchar *string;
717 #endif
718     gchar *table_name;
719     guint value;
720
721     list = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_LIST);
722     if (requested_action == E_DECODE_NO)
723         gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)));
724
725 #ifdef DEBUG
726     string = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_TITLE);
727     decode_debug(GTK_CLIST(list), string);
728 #endif
729
730     table_name = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_TABLE);
731     value = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_VALUE));
732     decode_change_one_dissector(table_name, value, list);
733 }
734
735
736 /*
737  * This routine is called when the user clicks the "OK" button in the
738  * "Decode As..." dialog window and the transport page is foremost.
739  * This routine takes care of making any changes requested to the TCP
740  * or UDP dissector tables.
741  *
742  * @param notebook_pg A pointer to the "transport" notebook page.
743  */
744 static void
745 decode_transport(GtkWidget *notebook_pg)
746 {
747     GtkWidget *menu, *menuitem;
748     GtkWidget *list;
749     gchar *table_name;
750     gint requested_srcdst, requested_port, ppid;
751     gpointer portp;
752
753     list = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_LIST);
754     if (requested_action == E_DECODE_NO)
755         gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)));
756
757     menu = g_object_get_data(G_OBJECT(notebook_pg), E_MENU_SRCDST);
758
759     menuitem = gtk_menu_get_active(GTK_MENU(menu));
760     requested_srcdst = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "user_data"));
761
762 #ifdef DEBUG
763     string = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_TITLE);
764     decode_debug(GTK_CLIST(list), string);
765 #endif
766
767     table_name = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_TABLE);
768     if (requested_srcdst >= E_DECODE_PPID) {
769         if (requested_srcdst == E_DECODE_PPID)
770            ppid = 0;
771         else
772            if (requested_srcdst - E_DECODE_PPID - 1 < MAX_NUMBER_OF_PPIDS)
773              ppid = cfile.edt->pi.ppids[requested_srcdst - E_DECODE_PPID - 1];
774            else 
775              return;
776         decode_change_one_dissector(table_name, ppid, list);
777         return;
778     }
779     if (requested_srcdst != E_DECODE_DPORT) {
780         portp = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_SPORT);
781         if (portp != NULL) {
782             requested_port = GPOINTER_TO_INT(portp);
783             decode_change_one_dissector(table_name, requested_port, list);
784         }
785     }
786     if (requested_srcdst != E_DECODE_SPORT) {
787         portp = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_DPORT);
788         if (portp != NULL) {
789             requested_port = GPOINTER_TO_INT(portp);
790             decode_change_one_dissector(table_name, requested_port, list);
791         }
792     }
793 }
794
795
796 /**************************************************/
797 /*      Signals from the "Decode As..." dialog    */
798 /**************************************************/
799
800 /*
801  * This routine is called when the user clicks the "OK" button in the
802  * "Decode As..." dialog window.  This routine calls various helper
803  * routines to set/clear dissector values as requested by the user.
804  * These routines accumulate information on what actions they have
805  * taken, and this summary information is printed by this routine.
806  * This routine then destroys the dialog box and performs other
807  * housekeeping functions.
808  *
809  * @param ok_bt A pointer to the "OK" button.
810  *
811  * @param parent_w A pointer to the dialog window.
812  */
813 static void
814 decode_ok_cb (GtkWidget *ok_bt _U_, gpointer parent_w)
815 {
816     GtkWidget *notebook, *notebook_pg;
817     void (* func)(GtkWidget *);
818     gint page_num;
819     void *binding = NULL;
820
821     /* Call the right routine for the page that was currently in front. */
822     notebook =  g_object_get_data(G_OBJECT(parent_w), E_NOTEBOOK);
823     page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
824     notebook_pg = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num);
825
826     func = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_ACTION);
827     func(notebook_pg);
828
829     /* Now destroy the "Decode As" dialog. */
830     notebook_pg = g_object_get_data(G_OBJECT(parent_w), E_PAGE_DCERPC);
831     if(notebook_pg) {
832         binding = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_BINDING);
833     }
834     if(binding) {
835         decode_dcerpc_binding_free(binding);    
836     }
837     window_destroy(GTK_WIDGET(parent_w));
838     g_slist_free(decode_dimmable);
839     decode_dimmable = NULL;
840
841     redissect_packets();
842 }
843
844 /*
845  * This routine is called when the user clicks the "Apply" button in the
846  * "Decode As..." dialog window.  This routine calls various helper
847  * routines to set/clear dissector values as requested by the user.
848  * These routines accumulate information on what actions they have
849  * taken, and this summary information is printed by this routine.
850  *
851  * @param apply_bt A pointer to the "Apply" button.
852  *
853  * @param parent_w A pointer to the dialog window.
854  */
855 static void
856 decode_apply_cb (GtkWidget *apply_bt _U_, gpointer parent_w)
857 {
858     GtkWidget *notebook, *notebook_pg;
859     void (* func)(GtkWidget *);
860     gint page_num;
861
862     /* Call the right routine for the page that was currently in front. */
863     notebook =  g_object_get_data(G_OBJECT(parent_w), E_NOTEBOOK);
864     page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
865     notebook_pg = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num);
866
867     func = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_ACTION);
868     func(notebook_pg);
869
870     redissect_packets();
871 }
872
873 /*
874  * This routine is called when the user clicks the "Close" button in
875  * the "Decode As..." dialog window.  This routine then destroys the
876  * dialog box and performs other housekeeping functions.
877  *
878  * @param close_bt A pointer to the "Close" button.
879  *
880  * @param parent_w A pointer to the dialog window.
881  */
882 static void
883 decode_close_cb (GtkWidget *close_bt _U_, gpointer parent_w)
884 {
885     GtkWidget *notebook_pg = NULL;
886     void *binding = NULL;
887
888
889     notebook_pg = g_object_get_data(G_OBJECT(parent_w), E_PAGE_DCERPC);
890     if(notebook_pg) {
891         binding = g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_BINDING);
892     }
893     if(binding) {
894         decode_dcerpc_binding_free(binding);
895     }
896     window_destroy(GTK_WIDGET(parent_w));
897     g_slist_free(decode_dimmable);
898     decode_dimmable = NULL;
899 }
900
901
902 /*
903  * This routine is called when the user clicks the "Close" button in
904  * the "Decode As..." dialog window.  This routine simply calls the
905  * close routine as if the user had clicked the close button instead
906  * of the close button.
907  *
908  * @param decode_w A pointer to the dialog box.
909  *
910  * @param dummy Unknown
911  */
912 static gboolean
913 decode_delete_cb (GtkWidget *decode_w, gpointer dummy _U_)
914 {
915     decode_close_cb(NULL, decode_w);
916     return FALSE;
917 }
918
919
920 /*
921  * This routine is called at the destruction of the "Decode As..."
922  * dialog box.  It clears the pointer maintained by this file, so that
923  * the next time the user selects the "Decode As..." menu item a new
924  * dialog box will be created.
925  *
926  * @param decode_w A pointer to the dialog box.
927  *
928  * @param user_data Unknown
929  *
930  * @return void
931  */
932 static void
933 decode_destroy_cb (GtkWidget *win _U_, gpointer user_data _U_)
934 {
935     /* Note that we no longer have a "Decode As" dialog box. */
936     decode_w = NULL;
937 }
938
939
940 /*
941  * This routine is called when the user clicks the "Clear" button in
942  * the "Decode As..." dialog window.  This routine resets all the
943  * dissector values and performs other housekeeping functions.
944  *
945  * @param GtkWidget * A pointer to the "Clear" button.
946  * @param gpointer A pointer to the dialog window.
947  */
948 static void
949 decode_clear_cb(GtkWidget *clear_bt _U_, gpointer parent_w _U_)
950 {
951     decode_clear_all();
952 }
953
954
955
956 /**************************************************/
957 /*          Dialog setup - radio buttons          */
958 /**************************************************/
959
960 /*
961  * Update the requested action field of the dialog.  This routine is
962  * called by GTK when either of the two radio buttons in the dialog is
963  * clicked.
964  *
965  * @param w The radio button that was clicked.
966  *
967  * @param data The enum value assigned to this radio button.  This
968  * will be either E_DECODE_YES or E_DECODE_NO
969  */
970 static void
971 decode_update_action (GtkWidget *w _U_, gpointer data)
972 {
973     GSList *tmp;
974     gboolean enable;
975
976     requested_action = GPOINTER_TO_INT(data);
977     enable = (requested_action == E_DECODE_YES);
978     for (tmp = decode_dimmable; tmp; tmp = g_slist_next(tmp)) {
979         gtk_widget_set_sensitive(tmp->data, enable);
980     }
981 }
982
983 /*
984  * This routine is called to create the "Decode" and "Do not decode"
985  * radio buttons.  These buttons are installed into a vbox, and set up
986  * as a format group.
987  *
988  * @return GtkWidget * A pointer to the vbox containing the buttons
989  */
990 static GtkWidget *
991 decode_add_yes_no (void)
992 {
993     GtkWidget   *format_vb, *radio_button;
994     GSList      *format_grp;
995
996     format_vb = gtk_vbox_new(FALSE, 2);
997
998     radio_button = gtk_radio_button_new_with_label(NULL, "Decode");
999     format_grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button));
1000     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE);
1001     g_signal_connect(radio_button, "clicked", G_CALLBACK(decode_update_action),
1002                    GINT_TO_POINTER(E_DECODE_YES));
1003     gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0);
1004
1005     radio_button = gtk_radio_button_new_with_label(format_grp, "Do not decode");
1006     format_grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button));
1007     g_signal_connect(radio_button, "clicked", G_CALLBACK(decode_update_action),
1008                    GINT_TO_POINTER(E_DECODE_NO));
1009     gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0);
1010
1011     return(format_vb);
1012 }
1013
1014 /**************************************************/
1015 /*          Dialog setup - simple menus           */
1016 /**************************************************/
1017
1018 /*
1019  * This routine is called to pack an option menu into an aligment, so
1020  * that it doesn't expand vertically to fill up the space available to
1021  * it.
1022  *
1023  * @param optmenu A pointer to the option menu to be so packed.
1024  *
1025  * @return GtkWidget * A pointer to the newly created alignment.
1026  */
1027 static GtkWidget *
1028 decode_add_pack_menu (GtkWidget *optmenu)
1029 {
1030     GtkWidget *alignment;
1031
1032     alignment = gtk_alignment_new(0.0f, 0.5f, 0.0f, 0.0f);
1033     gtk_container_add(GTK_CONTAINER(alignment), optmenu);
1034
1035     return(alignment);
1036 }
1037
1038
1039 /*
1040  * This routine is called to add the transport port selection menu to
1041  * the dialog box.  This is a three choice menu: source, destination
1042  * and both.  The default choice for the menu is set to the source
1043  * port number of the currently selected packet.
1044  *
1045  * @param page A pointer notebook page that will contain all
1046  * widgets created by this routine.
1047  *
1048  * @return GtkWidget * A pointer to the newly created alignment into
1049  * which we've packed the newly created option menu.
1050  */
1051 static GtkWidget *
1052 decode_add_srcdst_menu (GtkWidget *page)
1053 {
1054     GtkWidget *optmenu, *menu, *menuitem, *alignment;
1055     gchar      tmp[100];
1056
1057     optmenu = gtk_option_menu_new();
1058     menu = gtk_menu_new();
1059     g_snprintf(tmp, sizeof(tmp), "source (%u)", cfile.edt->pi.srcport);
1060     menuitem = gtk_menu_item_new_with_label(tmp);
1061     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_SPORT));
1062     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1063     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1064
1065     g_snprintf(tmp, sizeof(tmp), "destination (%u)", cfile.edt->pi.destport);
1066     menuitem = gtk_menu_item_new_with_label(tmp);
1067     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_DPORT));
1068     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1069     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1070
1071     menuitem = gtk_menu_item_new_with_label("both");
1072     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_BPORT));
1073     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1074     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1075
1076     g_object_set_data(G_OBJECT(page), E_MENU_SRCDST, menu);
1077     gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
1078     g_object_set_data(G_OBJECT(page), E_PAGE_SPORT, GINT_TO_POINTER(cfile.edt->pi.srcport));
1079     g_object_set_data(G_OBJECT(page), E_PAGE_DPORT, GINT_TO_POINTER(cfile.edt->pi.destport));
1080
1081     alignment = decode_add_pack_menu(optmenu);
1082
1083     return(alignment);
1084 }
1085
1086 static GtkWidget *
1087 decode_add_ppid_menu (GtkWidget *page)
1088 {
1089     GtkWidget *optmenu, *menu, *menuitem;
1090     gchar      tmp[100];
1091     guint      number_of_ppid;
1092     
1093     optmenu = gtk_option_menu_new();
1094     menu = gtk_menu_new();
1095     
1096     g_snprintf(tmp, sizeof(tmp), "PPID (%u)", 0);
1097     menuitem = gtk_menu_item_new_with_label(tmp);
1098     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_PPID));
1099     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1100     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1101     
1102     for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++)
1103       if (cfile.edt->pi.ppids[number_of_ppid] != 0) {
1104           g_snprintf(tmp, sizeof(tmp), "PPID (%u)", cfile.edt->pi.ppids[number_of_ppid]);
1105           menuitem = gtk_menu_item_new_with_label(tmp);
1106           g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_PPID + 1 + number_of_ppid));
1107           gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1108           gtk_widget_show(menuitem);    /* gtk_widget_show_all() doesn't show this */
1109       } else
1110           break;
1111
1112     g_object_set_data(G_OBJECT(page), E_MENU_SRCDST, menu);
1113     gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
1114
1115     return(optmenu);
1116 }
1117
1118 /*************************************************/
1119 /*        Dialog setup - list based menus        */
1120 /*************************************************/
1121
1122 struct handle_lookup_info {
1123     dissector_handle_t handle;
1124     gboolean           found;
1125 };
1126
1127 static gboolean
1128 lookup_handle(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
1129               gpointer data)
1130 {
1131     dissector_handle_t handle;
1132     struct handle_lookup_info *hli = (struct handle_lookup_info *)data;
1133
1134     gtk_tree_model_get(model, iter, E_LIST_S_TABLE+1, &handle, -1);
1135     if (hli->handle == handle) {
1136         hli->found = TRUE;
1137         return TRUE;
1138     }
1139     return FALSE;
1140 }
1141
1142 /*
1143  * This routine creates one entry in the list of protocol dissector
1144  * that can be used.  It is called by the dissector_table_foreach_handle
1145  * routine once for each entry in a dissector table's list of handles
1146  * for dissectors that could be used in that table.  It guarantees unique
1147  * entries by iterating over the list of entries build up to this point,
1148  * looking for a duplicate name.  If there is no duplicate, then this
1149  * entry is added to the list of possible dissectors.
1150  *
1151  * @param table_name The name of the dissector table currently
1152  * being walked.
1153  *
1154  * @param value The dissector handle for this entry.  This is an opaque
1155  * pointer that can only be handed back to routines in the file packet.c
1156  *
1157  * @param user_data A data block passed into each instance of this
1158  * routine.  It contains information from the caller of the foreach
1159  * routine, specifying information about the dissector table and where
1160  * to store any information generated by this routine.
1161  */
1162 void
1163 decode_add_to_list (const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data)
1164 {
1165     const gchar     *text[E_LIST_S_COLUMNS];
1166     GtkTreeView  *list;
1167     GtkListStore *store;
1168     GtkTreeIter   iter;
1169     struct handle_lookup_info hli;
1170
1171     g_assert(user_data);
1172     g_assert(value);
1173
1174     list = user_data;
1175
1176     hli.handle = value;
1177     hli.found = FALSE;
1178     store = GTK_LIST_STORE(gtk_tree_view_get_model(list));
1179     gtk_tree_model_foreach(GTK_TREE_MODEL(store), lookup_handle, &hli);
1180     /* We already have an entry for this handle.
1181      * XXX - will this ever happen? */
1182     if (hli.found) return;
1183
1184     text[E_LIST_S_PROTO_NAME] = proto_name;
1185     text[E_LIST_S_TABLE] = table_name;
1186     gtk_list_store_append(store, &iter);
1187     gtk_list_store_set(store, &iter,
1188                        E_LIST_S_PROTO_NAME, text[E_LIST_S_PROTO_NAME],
1189                        E_LIST_S_TABLE, text[E_LIST_S_TABLE],
1190                        E_LIST_S_TABLE+1, value, -1);
1191 }
1192
1193 static void
1194 decode_proto_add_to_list (const gchar *table_name, gpointer value, gpointer user_data)
1195 {
1196     const gchar     *proto_name;
1197     gint       i;
1198     dissector_handle_t handle;
1199
1200
1201     handle = value;
1202     proto_name = dissector_handle_get_short_name(handle);
1203
1204     i = dissector_handle_get_protocol_index(handle);
1205     if (i >= 0 && !proto_is_protocol_enabled(find_protocol_by_id(i)))
1206         return;
1207   
1208     decode_add_to_list (table_name, proto_name, value, user_data);
1209 }
1210
1211
1212 static gint
1213 decode_list_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
1214 {
1215   if (event->type == GDK_2BUTTON_PRESS) {
1216     GtkWidget *main_w = gtk_widget_get_toplevel(list);
1217
1218     decode_ok_cb (NULL, main_w);
1219   }
1220
1221   return FALSE;
1222 }
1223
1224 static gint
1225 decode_list_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
1226 {
1227   if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
1228     GtkWidget    *main_w = gtk_widget_get_toplevel(list);
1229
1230     decode_ok_cb (NULL, main_w);
1231   }
1232
1233   return FALSE;
1234 }
1235
1236 /*
1237  * This routine starts the creation of a List on a notebook page.  It
1238  * creates both a scrolled window and a list, adds the list to the
1239  * window, and attaches the list as a data object on the page.
1240  *
1241  * @param page A pointer to the notebook page being created.
1242  *
1243  * @param list_p Will be filled in with the address of a newly
1244  * created List.
1245  *
1246  * @param scrolled_win_p Will be filled in with the address of a newly
1247  * created GtkScrolledWindow.
1248  */
1249 void
1250 decode_list_menu_start(GtkWidget *page, GtkWidget **list_p,
1251                        GtkWidget **scrolled_win_p)
1252 {
1253     GtkTreeView       *list;
1254     GtkListStore      *store;
1255     GtkCellRenderer   *renderer;
1256     GtkTreeViewColumn *tc;
1257     GtkTreeSortable   *sortable;
1258
1259     store = gtk_list_store_new(E_LIST_S_COLUMNS+1, G_TYPE_STRING,
1260                                G_TYPE_STRING, G_TYPE_POINTER);
1261     g_object_set_data(G_OBJECT(decode_w), "sctp_data", store);
1262     list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
1263     g_object_unref(G_OBJECT(store));
1264     sortable = GTK_TREE_SORTABLE(store);
1265     gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
1266     gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
1267     gtk_tree_view_set_headers_clickable(list, FALSE);
1268 #ifndef DEBUG
1269     gtk_tree_view_set_headers_visible(list, FALSE);
1270 #endif
1271     renderer = gtk_cell_renderer_text_new();
1272     tc = gtk_tree_view_column_new_with_attributes("Short Name", renderer,
1273                                                   "text", E_LIST_S_PROTO_NAME,
1274                                                   NULL);
1275     gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1276     gtk_tree_view_append_column(list, tc);
1277     g_object_set_data(G_OBJECT(page), E_PAGE_LIST, list);
1278
1279     *scrolled_win_p = scrolled_window_new(NULL, NULL);
1280     /* this will result to set the width of the dialog to the required size */
1281     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled_win_p),
1282                                    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1283     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(*scrolled_win_p), 
1284                                    GTK_SHADOW_IN);
1285     gtk_container_add(GTK_CONTAINER(*scrolled_win_p), GTK_WIDGET(list));
1286
1287     *list_p = GTK_WIDGET(list);
1288 }
1289
1290 /*
1291  * This routine finishes the creation of a List on a notebook page.
1292  * It adds the default entry, sets the default entry as the
1293  * highlighted entry, and sorts the List.
1294  *
1295  * @param list A pointer the the List to finish.
1296  */
1297 void
1298 decode_list_menu_finish(GtkWidget *list)
1299 {
1300     const gchar *text[E_LIST_S_COLUMNS];
1301     GtkListStore *store;
1302     GtkTreeIter   iter;
1303
1304     text[E_LIST_S_PROTO_NAME] = "(default)";
1305     text[E_LIST_S_TABLE] = "(none)";
1306     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
1307     gtk_list_store_prepend(store, &iter);
1308     gtk_list_store_set(store, &iter,
1309                        E_LIST_S_PROTO_NAME, text[E_LIST_S_PROTO_NAME],
1310                        E_LIST_S_TABLE, text[E_LIST_S_TABLE],
1311                        E_LIST_S_TABLE+1, NULL, -1);
1312
1313     gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), &iter);
1314     g_signal_connect(list, "button_press_event", G_CALLBACK(decode_list_button_press_cb), NULL);
1315     g_signal_connect(list, "key_release_event", G_CALLBACK(decode_list_key_release_cb), NULL);
1316 }
1317
1318 /*
1319  * This routine is called to add the dissector selection list to a
1320  * notebook page.  This scrolled list contains an entry labeled
1321  * "default", and an entry for each protocol that has had a dissector
1322  * registered.  The default choice for the list is set to the
1323  * "default" choice, which will return the protocol/port selections to
1324  * their original dissector(s).
1325  *
1326  * @param page A pointer to the notebook page currently being created.
1327  *
1328  * @param table_name The name of the dissector table to use to build
1329  * this (list) menu.
1330  *
1331  * @return GtkWidget * A pointer to the newly created list within a
1332  * scrolled window.
1333  */
1334 static GtkWidget *
1335 decode_add_simple_menu (GtkWidget *page, const gchar *table_name)
1336 {
1337     GtkWidget *scrolled_window;
1338     GtkWidget *list;
1339
1340     decode_list_menu_start(page, &list, &scrolled_window);
1341     dissector_table_foreach_handle(table_name, decode_proto_add_to_list, list);
1342     decode_list_menu_finish(list);
1343     return(scrolled_window);
1344 }
1345
1346
1347 /**************************************************/
1348 /*                  Dialog setup                  */
1349 /**************************************************/
1350
1351 /*
1352  * This routine creates a sample notebook page in the dialog box.
1353  * This notebook page provides a prompt specifying what is being
1354  * changed and its current value (e.g. "IP Protocol number (17)"), and
1355  * a list specifying all the available choices.  The list of choices
1356  * is conditionally enabled, based upon the setting of the
1357  * "decode"/"do not decode" radio buttons.
1358  *
1359  * @param prompt The prompt for this notebook page
1360  *
1361  * @param title A title for this page to use when debugging.
1362  *
1363  * @param table_name The name of the dissector table to use to
1364  * build this page.
1365  *
1366  * @param value The protocol/port value that is to be changed.
1367  *
1368  * @return GtkWidget * A pointer to the notebook page created by this
1369  * routine.
1370  */
1371 static GtkWidget *
1372 decode_add_simple_page (const gchar *prompt, const gchar *title, const gchar *table_name,
1373                         guint value)
1374 {
1375     GtkWidget   *page, *label, *scrolled_window;
1376
1377     page = gtk_hbox_new(FALSE, 5);
1378     g_object_set_data(G_OBJECT(page), E_PAGE_ACTION, decode_simple);
1379     g_object_set_data(G_OBJECT(page), E_PAGE_TABLE, (gchar *) table_name);
1380     g_object_set_data(G_OBJECT(page), E_PAGE_TITLE, (gchar *) title);
1381     g_object_set_data(G_OBJECT(page), E_PAGE_VALUE, GUINT_TO_POINTER(value));
1382
1383     /* Always enabled */
1384     label = gtk_label_new(prompt);
1385     gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0);
1386
1387     /* Conditionally enabled - only when decoding packets */
1388     label = gtk_label_new("as");
1389     gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0);
1390     decode_dimmable = g_slist_prepend(decode_dimmable, label);
1391     scrolled_window = decode_add_simple_menu(page, table_name);
1392     gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
1393     decode_dimmable = g_slist_prepend(decode_dimmable, scrolled_window);
1394
1395     return(page);
1396 }
1397
1398
1399 /*
1400  * This routine creates the TCP or UDP notebook page in the dialog box.
1401  * All items created by this routine are packed into a single
1402  * horizontal box.  First is a label indicating whether the port(s) for
1403  * which the user can set the dissection is a TCP port or a UDP port.
1404  * Second is a menu allowing the user to select whether the source port,
1405  * destination port, or both ports will have dissectors added for them.
1406  * Last is a (conditionally enabled) popup menu listing all possible
1407  * dissectors that can be used to decode the packets, and the choice
1408  * or returning to the default dissector for these ports.
1409  *
1410  * The defaults for these items are the transport layer protocol of
1411  * the currently selected packet, the source port of the currently
1412  * selected packet, and the "default dissector".
1413  *
1414  * @param prompt The prompt for this notebook page
1415  *
1416  * @param table_name The name of the dissector table to use to
1417  * build this page.
1418  *
1419  * @return GtkWidget * A pointer to the notebook page created by
1420  * this routine.
1421  */
1422 static GtkWidget *
1423 decode_add_tcpudp_page (const gchar *prompt, const gchar *table_name)
1424 {
1425     GtkWidget   *page, *label, *scrolled_window, *optmenu;
1426
1427     page = gtk_hbox_new(FALSE, 5);
1428     g_object_set_data(G_OBJECT(page), E_PAGE_ACTION, decode_transport);
1429     g_object_set_data(G_OBJECT(page), E_PAGE_TABLE, (gchar *) table_name);
1430     g_object_set_data(G_OBJECT(page), E_PAGE_TITLE, "Transport");
1431
1432     /* Always enabled */
1433     label = gtk_label_new(prompt);
1434     gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0);
1435     optmenu = decode_add_srcdst_menu(page);
1436     gtk_box_pack_start(GTK_BOX(page), optmenu, TRUE, TRUE, 0);
1437     label = gtk_label_new("port(s)");
1438     gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0);
1439
1440     /* Conditionally enabled - only when decoding packets */
1441     label = gtk_label_new("as");
1442     gtk_box_pack_start(GTK_BOX(page), label, TRUE, TRUE, 0);
1443     decode_dimmable = g_slist_prepend(decode_dimmable, label);
1444     scrolled_window = decode_add_simple_menu(page, table_name);
1445     gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
1446     decode_dimmable = g_slist_prepend(decode_dimmable, scrolled_window);
1447
1448     return(page);
1449 }
1450
1451 static void
1452 decode_sctp_list_menu_start(GtkWidget **list_p, GtkWidget **scrolled_win_p)
1453 {
1454     GtkTreeView       *list;
1455     GtkListStore      *sctp_store;
1456     GtkCellRenderer   *renderer;
1457     GtkTreeViewColumn *tc;
1458     GtkTreeSortable   *sortable;
1459
1460     sctp_store = g_object_get_data(G_OBJECT(decode_w), "sctp_data");
1461     list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(sctp_store)));
1462     g_object_unref(G_OBJECT(sctp_store));
1463     sortable = GTK_TREE_SORTABLE(sctp_store);
1464     gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
1465     gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
1466     gtk_tree_view_set_headers_clickable(list, FALSE);
1467 #ifndef DEBUG
1468     gtk_tree_view_set_headers_visible(list, FALSE);
1469 #endif
1470     renderer = gtk_cell_renderer_text_new();
1471     tc = gtk_tree_view_column_new_with_attributes("Short Name", renderer,
1472                                                   "text", E_LIST_S_PROTO_NAME,
1473                                                   NULL);
1474     gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1475     gtk_tree_view_append_column(list, tc);
1476
1477     *scrolled_win_p = scrolled_window_new(NULL, NULL);
1478     /* this will result to set the width of the dialog to the required size */
1479     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1480     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(*scrolled_win_p), GTK_SHADOW_IN);
1481     gtk_container_add(GTK_CONTAINER(*scrolled_win_p), GTK_WIDGET(list));
1482     *list_p = GTK_WIDGET(list);
1483 }
1484
1485 static void
1486 decode_sctp_update_ppid_menu(GtkWidget *w _U_, GtkWidget *page)
1487 {
1488     GtkWidget *menu, *menuitem, *list, *scrolled_window, *sctpmenu;
1489     gchar      tmp[100];
1490     guint      number_of_ppid;
1491     GtkListStore *sctp_store;
1492
1493     menu = gtk_menu_new();
1494
1495     g_snprintf(tmp, sizeof(tmp), "PPID (%u)", 0);
1496     menuitem = gtk_menu_item_new_with_label(tmp);
1497     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_PPID));
1498     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1499     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1500     for(number_of_ppid = 0; number_of_ppid < MAX_NUMBER_OF_PPIDS; number_of_ppid++)
1501       if (cfile.edt->pi.ppids[number_of_ppid] != 0) {
1502         g_snprintf(tmp, sizeof(tmp), "PPID (%u)", cfile.edt->pi.ppids[number_of_ppid]);
1503         menuitem = gtk_menu_item_new_with_label(tmp);
1504         g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_PPID + 1 + number_of_ppid));
1505         gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1506         gtk_widget_show(menuitem);      /* gtk_widget_show_all() doesn't show this */
1507       } else
1508         break;
1509
1510     g_object_set_data(G_OBJECT(page), E_MENU_SRCDST, menu);
1511     g_object_set_data(G_OBJECT(page), E_PAGE_TABLE, "sctp.ppi");
1512     sctpmenu = g_object_get_data(G_OBJECT(decode_w), "user_data");
1513     gtk_option_menu_set_menu(GTK_OPTION_MENU(sctpmenu), menu);
1514
1515     sctp_store = g_object_get_data(G_OBJECT(G_OBJECT(decode_w)), "sctp_data");
1516     gtk_list_store_clear(sctp_store);
1517     decode_sctp_list_menu_start(&list, &scrolled_window);
1518     dissector_table_foreach_handle("sctp.ppi", decode_proto_add_to_list, list);
1519     decode_list_menu_finish(list);
1520 }
1521
1522
1523 static void
1524 decode_sctp_update_srcdst_menu(GtkWidget *w _U_, GtkWidget *page)
1525 {
1526     GtkWidget  *menu, *menuitem, *scrolled_window, *list, *sctpmenu;
1527     gchar      tmp[100];
1528     GtkListStore *sctp_store;
1529
1530     menu = gtk_menu_new();
1531     g_snprintf(tmp, sizeof(tmp), "source (%u)", cfile.edt->pi.srcport);
1532     menuitem = gtk_menu_item_new_with_label(tmp);
1533     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_SPORT));
1534     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1535     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1536
1537     g_snprintf(tmp, sizeof(tmp), "destination (%u)", cfile.edt->pi.destport);
1538     menuitem = gtk_menu_item_new_with_label(tmp);
1539     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_DPORT));
1540     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1541     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1542
1543     menuitem = gtk_menu_item_new_with_label("both");
1544     g_object_set_data(G_OBJECT(menuitem), "user_data", GINT_TO_POINTER(E_DECODE_BPORT));
1545     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
1546     gtk_widget_show(menuitem);  /* gtk_widget_show_all() doesn't show this */
1547
1548     g_object_set_data(G_OBJECT(page), E_MENU_SRCDST, menu);
1549     g_object_set_data(G_OBJECT(page), E_PAGE_TABLE, "sctp.port");
1550     sctpmenu = g_object_get_data(G_OBJECT(decode_w), "user_data");
1551     gtk_option_menu_set_menu(GTK_OPTION_MENU(sctpmenu), menu);
1552     g_object_set_data(G_OBJECT(page), E_PAGE_SPORT, GINT_TO_POINTER(cfile.edt->pi.srcport));
1553     g_object_set_data(G_OBJECT(page), E_PAGE_DPORT, GINT_TO_POINTER(cfile.edt->pi.destport));  
1554     sctp_store = g_object_get_data(G_OBJECT(G_OBJECT(decode_w)), "sctp_data");
1555     gtk_list_store_clear(sctp_store);
1556     decode_sctp_list_menu_start(&list, &scrolled_window);
1557     dissector_table_foreach_handle("sctp.port", decode_proto_add_to_list, list);
1558     decode_list_menu_finish(list);
1559 }
1560
1561
1562
1563 static GtkWidget *
1564 decode_sctp_add_port_ppid (GtkWidget *page)
1565 {
1566     GtkWidget *format_vb, *radio_button;
1567     GSList *format_grp;
1568
1569     format_vb = gtk_vbox_new(FALSE, 2);
1570
1571     radio_button = gtk_radio_button_new_with_label(NULL, "PPID");
1572     format_grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button));
1573     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE);
1574     g_signal_connect(radio_button, "clicked", G_CALLBACK(decode_sctp_update_ppid_menu), page);
1575
1576     gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0);
1577
1578     radio_button = gtk_radio_button_new_with_label(format_grp, "Port");
1579     format_grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button));
1580     g_signal_connect(radio_button, "clicked", G_CALLBACK(decode_sctp_update_srcdst_menu), page);
1581
1582     gtk_box_pack_start(GTK_BOX(format_vb), radio_button, TRUE, TRUE, 0);
1583
1584     return(format_vb);
1585 }
1586
1587
1588 static GtkWidget *
1589 decode_add_sctp_page (const gchar *prompt, const gchar *table_name)
1590 {
1591     GtkWidget   *page, *label, *scrolled_window,  *radio, *vbox, *alignment, *sctpbox, *sctpmenu;
1592
1593     page = gtk_hbox_new(FALSE, 5);
1594     g_object_set_data(G_OBJECT(page), E_PAGE_ACTION, decode_transport);
1595     g_object_set_data(G_OBJECT(page), E_PAGE_TABLE, (gchar *) table_name);
1596     g_object_set_data(G_OBJECT(page), E_PAGE_TITLE, "Transport");
1597
1598     vbox = gtk_vbox_new(FALSE, 5);
1599     radio = decode_sctp_add_port_ppid(page);
1600     gtk_box_pack_start(GTK_BOX(vbox), radio, TRUE, TRUE, 0);
1601
1602     /* Always enabled */
1603     sctpbox = gtk_hbox_new(FALSE, 5);
1604     label = gtk_label_new(prompt);
1605     gtk_box_pack_start(GTK_BOX(sctpbox), label, TRUE, TRUE, 0);  
1606     sctpmenu = decode_add_ppid_menu(page);
1607     g_object_set_data(G_OBJECT(decode_w), "user_data", sctpmenu);
1608     alignment = decode_add_pack_menu(sctpmenu);
1609
1610     gtk_box_pack_start(GTK_BOX(sctpbox), alignment, TRUE, TRUE, 0);
1611
1612     /* Conditionally enabled - only when decoding packets */
1613     label = gtk_label_new("as");
1614     gtk_box_pack_start(GTK_BOX(sctpbox), label, TRUE, TRUE, 0);
1615     decode_dimmable = g_slist_prepend(decode_dimmable, label);
1616     gtk_box_pack_start(GTK_BOX(vbox), sctpbox, TRUE, TRUE, 0);
1617     gtk_box_pack_start(GTK_BOX(page), vbox, TRUE, TRUE, 0);
1618
1619     scrolled_window = decode_add_simple_menu(page, table_name);
1620     gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
1621     decode_dimmable = g_slist_prepend(decode_dimmable, scrolled_window);
1622
1623     return(page);
1624 }
1625
1626
1627 /*
1628  * This routine indicates whether we'd actually have any pages in the
1629  * notebook in a "Decode As" dialog box; if there wouldn't be, we
1630  * inactivate the menu item for "Decode As".
1631  */
1632 gboolean
1633 decode_as_ok(void)
1634 {
1635     return cfile.edt->pi.ethertype || cfile.edt->pi.ipproto ||
1636         cfile.edt->pi.ptype == PT_TCP || cfile.edt->pi.ptype == PT_UDP || 
1637         cfile.cd_t == WTAP_FILE_BER;
1638 }
1639
1640
1641 /*
1642  * This routine creates the bulk of the "Decode As" dialog box.  All
1643  * items created by this routine are packed as pages into a notebook.
1644  * There will be a page for each protocol layer that can be change.
1645  *
1646  * @param GtkWidget * A pointer to the widget in which the notebook
1647  * should be installed.
1648  */
1649 static void
1650 decode_add_notebook (GtkWidget *format_hb)
1651 {
1652     GtkWidget *notebook, *page, *label;
1653     gchar buffer[40];
1654
1655     /* Start a nootbook for flipping between sets of changes */
1656     notebook = gtk_notebook_new();
1657     gtk_container_add(GTK_CONTAINER(format_hb), notebook);
1658     g_object_set_data(G_OBJECT(decode_w), E_NOTEBOOK, notebook);
1659
1660     /* Add link level selection page */
1661     if (cfile.edt->pi.ethertype) {
1662         g_snprintf(buffer, sizeof(buffer), "Ethertype 0x%04x", cfile.edt->pi.ethertype);
1663         page = decode_add_simple_page(buffer, "Link", "ethertype", cfile.edt->pi.ethertype);
1664         label = gtk_label_new("Link");
1665         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1666     }
1667
1668     /* Add mpls selection page */
1669     if (cfile.edt->pi.mpls_label) {
1670         g_snprintf(buffer, sizeof(buffer), "Data after label %u", cfile.edt->pi.mpls_label);
1671         page = decode_add_simple_page(buffer, "MPLS", "mpls.label", cfile.edt->pi.mpls_label);
1672         label = gtk_label_new("MPLS");
1673         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1674     }
1675
1676     /* Add network selection page */
1677     if (cfile.edt->pi.ipproto) {
1678         /*
1679          * The network-layer protocol is IP.
1680          */
1681         g_snprintf(buffer, sizeof(buffer), "IP protocol %u", cfile.edt->pi.ipproto);
1682         page = decode_add_simple_page(buffer, "Network", "ip.proto", cfile.edt->pi.ipproto);
1683         g_object_set_data(G_OBJECT(page), E_PAGE_ACTION, decode_simple);
1684         label = gtk_label_new("Network");
1685         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1686     }
1687
1688     /* Add transport selection page */
1689     switch (cfile.edt->pi.ptype) {
1690
1691     case PT_TCP:
1692         page = decode_add_tcpudp_page("TCP", "tcp.port");
1693         break;
1694
1695     case PT_UDP:
1696         page = decode_add_tcpudp_page("UDP", "udp.port");
1697         break;
1698
1699     case PT_SCTP:
1700         page = decode_add_sctp_page("SCTP", "sctp.ppi");
1701         break;
1702
1703     default:
1704         page = NULL;
1705         break;
1706     }
1707     if (page != NULL) {
1708         label = gtk_label_new("Transport");
1709         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1710     }
1711
1712     if(cfile.edt->pi.dcetransporttype != -1) {
1713             page = decode_dcerpc_add_page(&cfile.edt->pi);
1714             label = gtk_label_new("DCE-RPC");
1715             gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1716             g_object_set_data(G_OBJECT(decode_w), E_PAGE_DCERPC, page);
1717     }
1718
1719     if(cfile.cd_t == WTAP_FILE_BER) {
1720             page = decode_ber_add_page(&cfile.edt->pi);
1721             label = gtk_label_new("ASN.1");
1722             gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1723             g_object_set_data(G_OBJECT(decode_w), E_PAGE_ASN1, page);
1724     }
1725
1726     /* Select the last added page (selects first by default) */
1727     /* Notebook must be visible for set_page to work. */
1728     gtk_widget_show_all(notebook);
1729     gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), -1);
1730
1731 }
1732
1733
1734 /*
1735  * This routine creates the "Decode As" dialog box. This dialog box
1736  * asks the user which protocol to use for decoding the currently
1737  * selected packet.  This will affect the last packet that we called a
1738  * dissection routine on belongs (this might be the most recently
1739  * selected packet, or it might be the last packet in the file).
1740  *
1741  * This routine uses an auxiliary function to create the bulk of the
1742  * dialog box, and then hand crafts the button box at the bottom of
1743  * the dialog.
1744  *
1745  * @param w Unknown
1746  * @param data Unknown
1747  */
1748 void
1749 decode_as_cb (GtkWidget * w _U_, gpointer data _U_)
1750 {
1751     GtkWidget   *main_vb, *format_hb, *bbox, *ok_bt, *close_bt, *help_bt, *button;
1752     GtkWidget   *button_vb, *apply_bt;
1753     GtkTooltips *tooltips = gtk_tooltips_new();
1754
1755     if (decode_w != NULL) {
1756         /* There's already a "Decode As" dialog box; reactivate it. */
1757         reactivate_window(decode_w);
1758         return;
1759     }
1760
1761     requested_action = E_DECODE_YES;
1762     decode_w = dlg_window_new("Wireshark: Decode As");
1763     /* Provide a minimum of a couple of rows worth of data */
1764     gtk_window_set_default_size(GTK_WINDOW(decode_w), -1, E_DECODE_MIN_HEIGHT);
1765
1766     /* Container for each row of widgets */
1767     main_vb = gtk_vbox_new(FALSE, 2);
1768     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1769     gtk_container_add(GTK_CONTAINER(decode_w), main_vb);
1770
1771     /* First row - Buttons and Notebook */
1772     format_hb = gtk_hbox_new(FALSE, 5);
1773     gtk_box_pack_start(GTK_BOX(main_vb), format_hb, TRUE, TRUE, 10);
1774
1775     button_vb = decode_add_yes_no();
1776     gtk_box_pack_start(GTK_BOX(format_hb), button_vb, TRUE, TRUE, 10);
1777
1778     button = gtk_button_new_with_label("Show Current");
1779     g_signal_connect(button, "clicked", G_CALLBACK(decode_show_cb), decode_w);
1780     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1781     gtk_box_pack_start(GTK_BOX(button_vb), button, FALSE, FALSE, 0);
1782     gtk_tooltips_set_tip(tooltips, button, 
1783         "Open a dialog showing the current settings.", NULL);
1784
1785     button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
1786     g_signal_connect(button, "clicked", G_CALLBACK(decode_clear_cb), decode_w);
1787     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1788     gtk_box_pack_start(GTK_BOX(button_vb), button, FALSE, FALSE, 0);
1789     gtk_tooltips_set_tip(tooltips, button, 
1790         "Clear ALL settings.", NULL);
1791
1792     decode_add_notebook(format_hb);
1793
1794     /* Button row */
1795     bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
1796     gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
1797     gtk_widget_show(bbox);
1798
1799     ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
1800     g_signal_connect(ok_bt, "clicked", G_CALLBACK(decode_ok_cb), decode_w);
1801     gtk_tooltips_set_tip(tooltips, ok_bt, 
1802         "Apply current setting, close dialog and redissect packets.", NULL);
1803
1804     apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
1805     g_signal_connect(apply_bt, "clicked", G_CALLBACK(decode_apply_cb), decode_w);
1806     gtk_tooltips_set_tip(tooltips, apply_bt, 
1807         "Apply current setting, redissect packets and keep dialog open.", NULL);
1808
1809     close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1810     window_set_cancel_button(decode_w, close_bt, NULL);
1811     g_signal_connect(close_bt, "clicked", G_CALLBACK(decode_close_cb), decode_w);
1812     gtk_tooltips_set_tip(tooltips, close_bt, 
1813         "Close the dialog, don't redissect packets.", NULL);
1814
1815     help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1816     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_DECODE_AS_DIALOG);
1817
1818     gtk_widget_grab_default(ok_bt);
1819
1820     g_signal_connect(decode_w, "delete_event", G_CALLBACK(decode_delete_cb), NULL);
1821     g_signal_connect(decode_w, "destroy", G_CALLBACK(decode_destroy_cb), NULL);
1822
1823     gtk_widget_show_all(decode_w);
1824     window_present(decode_w);
1825 }