Remove trailing whitespace
[metze/wireshark/wip.git] / ui / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 #include "config.h"
25
26 #include <gtk/gtk.h>
27 #include <gdk/gdkkeysyms.h>
28 #if GTK_CHECK_VERSION(3,0,0)
29 # include <gdk/gdkkeysyms-compat.h>
30 #endif
31
32 #include <epan/packet.h>
33 #include <epan/epan_dissect.h>
34 #include <epan/decode_as.h>
35 #include <epan/dissectors/packet-dcerpc.h>
36
37 #include "ui/decode_as_utils.h"
38 #include "ui/simple_dialog.h"
39 #include "ui/utf8_entities.h"
40
41 #include "ui/gtk/main.h"
42 #include "ui/gtk/decode_as_dlg.h"
43 #include "ui/gtk/dlg_utils.h"
44 #include "ui/gtk/gui_utils.h"
45 #include "ui/gtk/help_dlg.h"
46 #include "ui/gtk/old-gtk-compat.h"
47 #include "ui/gtk/packet_win.h"
48
49 #undef DEBUG
50
51 /**************************************************/
52 /*                Typedefs & Enums                */
53 /**************************************************/
54
55 #define E_DECODE_MIN_HEIGHT 300
56 #define E_NOTEBOOK "notebook"
57
58 #define E_COMBO_BOX_MULTIVALUE "combo_box_multivalue"
59
60 #define E_PAGE_DECODE_AS_DATA  "decode_as_data"
61
62 /*
63  * Columns for a "Display" list
64  */
65 #define E_LIST_D_TABLE      0
66 #define E_LIST_D_SELECTOR   1
67 #define E_LIST_D_INITIAL    2
68 #define E_LIST_D_CURRENT    3
69 #define E_LIST_D_MAX        E_LIST_D_CURRENT
70 #define E_LIST_D_COLUMNS   (E_LIST_D_MAX + 1)
71
72 /*
73  * Columns for a "Select" list.
74  * Note that most of these columns aren't displayed; they're attached
75  * to the row of the table as additional information.
76  */
77 #define E_LIST_S_PROTO_NAME 0
78 #define E_LIST_S_TABLE      1
79 /* The following is for debugging in decode_add_to_list */
80 #define E_LIST_S_MAX        E_LIST_S_TABLE
81 #define E_LIST_S_COLUMNS   (E_LIST_S_MAX + 1)
82
83 #define E_PAGE_LIST   "notebook_page_list"
84 #define E_PAGE_TABLE  "notebook_page_table_name"
85 #define E_PAGE_TITLE  "notebook_page_title"
86 #define E_PAGE_VALUE  "notebook_page_value"
87
88 #define E_PAGE_ACTION "notebook_page_action"
89
90 /**************************************************/
91 /*             File Global Variables              */
92 /**************************************************/
93
94 /*
95  * Keep a static pointer to the current "Decode As" window.  This is
96  * kept so that if somebody tries to do "Tools:Decode As" while
97  * there's already a "Decode As" window up, we just pop up the
98  * existing one, rather than creating a new one.
99  */
100 static GtkWidget *decode_w = NULL;
101
102 /*
103  * A static pointer to the current "Decode As:Show" window.  This is
104  * kept so that if somebody tries to do clock the "Show Current"
105  * button or select the "Display:User Specified Decodes" menu item
106  * while there's already a "Decode As:Show" window up, we just pop up
107  * the existing one, rather than creating a new one.
108  */
109 static GtkWidget *decode_show_w = NULL;
110
111 /*
112  * A list of the dialog items that only have meaning when the user has
113  * selected the "Decode" radio button.  When the "Do not decode"
114  * button is selected these items should be dimmed.
115  */
116 GSList *decode_dimmable = NULL;
117
118 /*
119  * Remember the "action" radio button that is currently selected in
120  * the dialog.  This value is initialized when the dialog is created,
121  * modified in a callback routine, and read in the routine that
122  * handles a click in the "OK" button for the dialog.
123  */
124 enum action_type  requested_action = (enum action_type)-1;
125
126
127 /**************************************************/
128 /*            Global Functions                    */
129 /**************************************************/
130
131 /**************************************************/
132 /*             Saving "Decode As"                 */
133 /**************************************************/
134
135 /*
136  * Data structure to hold information of the "Decode As" entry.
137  */
138 struct da_entry {
139   gchar *table;
140   guint selector;
141   gchar *initial;
142   gchar *current;
143 };
144
145 /*
146  * A typedef for the "Decode As" entry.
147  */
148 typedef struct da_entry da_entry_t;
149
150 /*
151  * Container that holds the entries of the "Decode As"
152  */
153 GSList *da_entries = NULL;
154
155 /*
156  * Save entries into preferences.
157  */
158 static void
159 write_da_entry(gpointer item, gpointer user_data)
160 {
161   da_entry_t *entry = (da_entry_t *)item;
162   FILE *daf = (FILE *)user_data;
163   gchar *selector_str = g_strdup_printf("%d", entry->selector);
164
165   decode_as_write_entry(daf, entry->table, selector_str, entry->initial, entry->current);
166   g_free(selector_str);
167 }
168
169 /*
170  * Free memory used by the da_entry
171  */
172 static void
173 free_da_entry(gpointer item, gpointer user_data _U_)
174 {
175   da_entry_t *entry = (da_entry_t *)item;
176   g_free(entry->table);
177   g_free(entry->initial);
178   g_free(entry->current);
179 }
180
181
182 /**************************************************/
183 /*             Show Changed Dissectors            */
184 /**************************************************/
185
186 #define SORT_ALPHABETICAL 0
187
188 static gint
189 sort_iter_compare_func (GtkTreeModel *model,
190                         GtkTreeIter *a,
191                         GtkTreeIter *b,
192                         gpointer user_data)
193 {
194     gint sortcol = GPOINTER_TO_INT(user_data);
195     gint ret = 0;
196     switch (sortcol)
197     {
198         case SORT_ALPHABETICAL:
199         {
200         gchar *name1, *name2;
201         gtk_tree_model_get(model, a, 0, &name1, -1);
202         gtk_tree_model_get(model, b, 0, &name2, -1);
203         if (name1 == NULL || name2 == NULL)
204         {
205             if (name1 == NULL && name2 == NULL)
206                 break; /* both equal => ret = 0 */
207             ret = (name1 == NULL) ? -1 : 1;
208         }
209         else
210         {
211             ret = g_ascii_strcasecmp(name1,name2);
212         }
213         g_free(name1);
214         g_free(name2);
215         }
216         break;
217         default:
218         g_return_val_if_reached(0);
219     }
220     return ret;
221 }
222
223
224 static void
225 decode_add_to_show_list (gpointer list_data,
226                          const gchar *table_name,
227                          gchar *selector_name,
228                          const gchar *initial_proto_name,
229                          const gchar *current_proto_name)
230 {
231     const gchar     *text[E_LIST_D_COLUMNS];
232     GtkListStore *store;
233     GtkTreeIter   iter;
234
235     store = (GtkListStore *)list_data;
236
237     text[E_LIST_D_TABLE] = table_name;
238     text[E_LIST_D_SELECTOR] = selector_name;
239     text[E_LIST_D_INITIAL] = initial_proto_name;
240     text[E_LIST_D_CURRENT] = current_proto_name;
241     gtk_list_store_append(store, &iter);
242     gtk_list_store_set(store, &iter, E_LIST_D_TABLE, text[E_LIST_D_TABLE],
243                        E_LIST_D_SELECTOR, text[E_LIST_D_SELECTOR],
244                        E_LIST_D_INITIAL, text[E_LIST_D_INITIAL],
245                        E_LIST_D_CURRENT, text[E_LIST_D_CURRENT], -1);
246 }
247
248
249 /*
250  * This routine creates one entry in the list of protocol dissector
251  * that have been changed.  It is called by the g_hash_foreach routine
252  * once for each changed entry in a dissector table.
253  *
254  * @param table_name The table name in which this dissector is found.
255  *
256  * @param key A pointer to the key for this entry in the dissector
257  * hash table.  This is generally the numeric selector of the
258  * protocol, i.e. the ethernet type code, IP port number, TCP port
259  * number, etc.
260  *
261  * @param value A pointer to the value for this entry in the dissector
262  * hash table.  This is an opaque pointer that can only be handed back
263  * to routine in the file packet.c
264  *
265  * @param user_data A pointer to the list in which this information
266  * should be stored.
267  */
268 static void
269 decode_build_show_list (const gchar *table_name, ftenum_t selector_type,
270                         gpointer key, gpointer value, gpointer user_data)
271 {
272     dissector_handle_t current, initial;
273     const gchar *current_proto_name, *initial_proto_name;
274     gchar       *selector_name;
275     gchar        string1[20];
276     da_entry_t *entry;
277
278     entry = g_new(da_entry_t,1);
279
280     g_assert(user_data);
281     g_assert(value);
282
283     current = dtbl_entry_get_handle((dtbl_entry_t *)value);
284     if (current == NULL)
285         current_proto_name = DECODE_AS_NONE;
286     else
287         current_proto_name = dissector_handle_get_short_name(current);
288     initial = dtbl_entry_get_initial_handle((dtbl_entry_t *)value);
289     if (initial == NULL)
290         initial_proto_name = DECODE_AS_NONE;
291     else
292         initial_proto_name = dissector_handle_get_short_name(initial);
293
294     switch (selector_type) {
295
296     case FT_UINT8:
297     case FT_UINT16:
298     case FT_UINT24:
299     case FT_UINT32:
300         switch (get_dissector_table_base(table_name)) {
301
302         case BASE_DEC:
303             g_snprintf(string1, sizeof(string1), "%u", GPOINTER_TO_UINT(key));
304             break;
305
306         case BASE_HEX:
307             switch (get_dissector_table_selector_type(table_name)) {
308
309             case FT_UINT8:
310                 g_snprintf(string1, sizeof(string1), "0x%02x", GPOINTER_TO_UINT(key));
311                 break;
312
313             case FT_UINT16:
314                 g_snprintf(string1, sizeof(string1), "0x%04x", GPOINTER_TO_UINT(key));
315                 break;
316
317             case FT_UINT24:
318                 g_snprintf(string1, sizeof(string1), "0x%06x", GPOINTER_TO_UINT(key));
319                 break;
320
321             case FT_UINT32:
322                 g_snprintf(string1, sizeof(string1), "0x%08x", GPOINTER_TO_UINT(key));
323                 break;
324
325             default:
326                 g_assert_not_reached();
327                 break;
328             }
329             break;
330
331         case BASE_OCT:
332             g_snprintf(string1, sizeof(string1), "%#o", GPOINTER_TO_UINT(key));
333             break;
334         }
335         selector_name = string1;
336         break;
337
338     case FT_STRING:
339     case FT_STRINGZ:
340         selector_name = (gchar *)key;
341         break;
342
343     default:
344         g_assert_not_reached();
345         selector_name = NULL;
346         break;
347     }
348
349     decode_add_to_show_list (
350         user_data,
351         get_dissector_table_ui_name(table_name),
352         selector_name,
353         initial_proto_name,
354         current_proto_name);
355
356     entry->table    = g_strdup(table_name);
357     entry->selector = GPOINTER_TO_UINT(key);
358     entry->initial  = g_strdup(initial_proto_name);
359     entry->current  = g_strdup(current_proto_name);
360     da_entries = g_slist_append(da_entries, entry);
361 }
362
363
364 /*
365  * This routine is called when the user clicks the "OK" button in
366  * the "Decode As:Show..." dialog window.  This routine destroys the
367  * dialog box and performs other housekeeping functions.
368  *
369  * @param ok_bt A pointer to the "OK" button.
370  *
371  * @param parent_w A pointer to the dialog window.
372  */
373 static void
374 decode_show_ok_cb (GtkWidget *ok_bt _U_, gpointer parent_w)
375 {
376     window_destroy(GTK_WIDGET(parent_w));
377 }
378
379
380 /*
381  * This routine is called when the user clicks the "Clear" button in
382  * the "Decode As:Show..." dialog window.  This routine resets all the
383  * dissector values and then destroys the dialog box and performs
384  * other housekeeping functions.
385  *
386  * @param clear_bt A pointer to the "Clear" button.
387  *
388  * @param parent_w A pointer to the dialog window.
389  */
390 static void
391 decode_show_clear_cb (GtkWidget *clear_bt _U_, gpointer parent_w)
392 {
393     decode_clear_all();
394     redissect_packets();
395     redissect_all_packet_windows();
396
397     window_destroy(GTK_WIDGET(parent_w));
398
399     decode_show_cb(NULL, NULL);
400 }
401
402
403 /*
404  * This routine is called when the user clicks the X at the top right end in
405  * the "Decode As:Show..." dialog window.  This routine simply calls the
406  * ok routine as if the user had clicked the ok button.
407  *
408  * @param win       A pointer to the dialog box.
409  *
410  * @param event     A pointer to the event struct
411  *
412  * @param user_data Unused
413  */
414 static gboolean
415 decode_show_delete_cb (GtkWidget *win _U_, GdkEvent *event _U_, gpointer user_data _U_)
416 {
417     decode_show_ok_cb(NULL, decode_show_w);
418     return FALSE;
419 }
420
421
422 /*
423  * This routine is called at the destruction of the "Decode As:Show"
424  * dialog box.  It clears the pointer maintained by this file, so that
425  * the next time the user clicks the "Decode As:Show" button a new
426  * dialog box will be created.
427  *
428  * @param win A pointer to the dialog box.
429  *
430  * @param user_data Unused
431  */
432 static void
433 decode_show_destroy_cb (GtkWidget *win _U_, gpointer user_data _U_)
434 {
435     /* Note that we no longer have a "Decode As:Show" dialog box. */
436     decode_show_w = NULL;
437
438     /* Clear saved "Decode As" entries. */
439     g_slist_foreach(da_entries, free_da_entry, NULL);
440     g_slist_free(da_entries);
441     da_entries = NULL;
442 }
443
444
445 /*
446  * This routine saves the current "Decode As"-entries into the
447  * preferences file
448  *
449  * @param win Unused
450  *
451  * @param user_data Unused
452  */
453 static void
454 decode_show_save_cb (GtkWidget *win _U_, gpointer user_data _U_)
455 {
456   FILE        *daf = decode_as_open();
457
458   if (!daf) return;
459
460   g_slist_foreach(da_entries, write_da_entry, daf);
461
462   fclose(daf);
463 }
464
465 /* add a single binding to the Show list */
466 static void
467 decode_dcerpc_add_show_list_single(gpointer data, gpointer user_data)
468 {
469     gchar      string1[20];
470
471
472     decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)data;
473
474     g_snprintf(string1, sizeof(string1), "ctx_id: %u", binding->ctx_id);
475
476     decode_add_to_show_list (
477         user_data,
478         "DCE-RPC",
479         string1,
480         "-",
481         binding->ifname->str);
482 }
483
484 /*
485  * This routine creates the "Decode As:Show" dialog box. This dialog box
486  * shows the user which protocols have had their dissectors changed.
487  *
488  * @param w Unused
489  *
490  * @param user_data Unused
491  */
492 void
493 decode_show_cb (GtkWidget *w _U_, gpointer user_data _U_)
494 {
495     GtkWidget         *main_vb, *bbox, *ok_bt, *clear_bt, *save_bt, *help_bt, *scrolled_window;
496     const gchar       *titles[E_LIST_D_COLUMNS] = {
497         "Table", "Value", "Initial", "Current"
498     };
499     gint               column;
500     GtkListStore      *store;
501     GtkTreeView       *list;
502     GtkCellRenderer   *renderer;
503     GtkTreeViewColumn *tc;
504     GtkTreeIter        iter;
505
506     if (decode_show_w != NULL) {
507         /* There's already a "Decode As" dialog box; reactivate it. */
508         reactivate_window(decode_show_w);
509         return;
510     }
511
512     decode_show_w = dlg_window_new("Wireshark: Decode As: Show");
513     /* Provide a minimum of a couple of rows worth of data */
514     gtk_window_set_default_size(GTK_WINDOW(decode_show_w), -1, E_DECODE_MIN_HEIGHT);
515
516     /* Container for each row of widgets */
517     main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 2, FALSE);
518     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
519     gtk_container_add(GTK_CONTAINER(decode_show_w), main_vb);
520
521     /* Initialize list */
522     store = gtk_list_store_new(E_LIST_D_COLUMNS, G_TYPE_STRING,
523                                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
524     list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
525     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
526     gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(list), FALSE);
527     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(list),
528                                 GTK_SELECTION_NONE);
529
530     for (column = 0; column < E_LIST_D_COLUMNS; column++) {
531         renderer = gtk_cell_renderer_text_new();
532         tc = gtk_tree_view_column_new_with_attributes(titles[column],
533                                                       renderer, "text",
534                                                       column, NULL);
535         gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
536         gtk_tree_view_column_set_resizable(tc, TRUE);
537         gtk_tree_view_append_column(list, tc);
538     }
539
540     /* Add data */
541     dissector_all_tables_foreach_changed(decode_build_show_list, store);
542     g_object_unref(G_OBJECT(store));
543     decode_dcerpc_add_show_list(decode_dcerpc_add_show_list_single, store);
544
545     /* Put list into a scrolled window */
546     scrolled_window = scrolled_window_new(NULL, NULL);
547     /* this will result to set the width of the dialog to the required size */
548     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
549                                    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
550     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
551                                         GTK_SHADOW_IN);
552     gtk_container_add(GTK_CONTAINER(scrolled_window),
553                       GTK_WIDGET(list));
554     gtk_box_pack_start(GTK_BOX(main_vb), scrolled_window, TRUE, TRUE, 0);
555
556     /* Button row */
557     bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CLEAR, GTK_STOCK_SAVE, GTK_STOCK_HELP, NULL);
558     gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
559     gtk_widget_show(bbox);
560
561     ok_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
562     g_signal_connect(ok_bt, "clicked", G_CALLBACK(decode_show_ok_cb), decode_show_w);
563
564     clear_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLEAR);
565     g_signal_connect(clear_bt, "clicked", G_CALLBACK(decode_show_clear_cb), decode_show_w);
566
567     save_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_SAVE);
568     g_signal_connect(save_bt, "clicked", G_CALLBACK(decode_show_save_cb), decode_show_w);
569
570     help_bt =(GtkWidget *) g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
571     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_DECODE_AS_SHOW_DIALOG);
572
573     /* set ok as default, this button won't change anything */
574     window_set_cancel_button(decode_show_w, ok_bt, NULL);
575
576     g_signal_connect(decode_show_w, "delete_event", G_CALLBACK(decode_show_delete_cb), NULL);
577     g_signal_connect(decode_show_w, "destroy", G_CALLBACK(decode_show_destroy_cb), NULL);
578
579     gtk_widget_set_sensitive(clear_bt,
580                              gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter));
581
582     gtk_widget_show_all(decode_show_w);
583     window_present(decode_show_w);
584 }
585
586
587 /**************************************************/
588 /*         Modify the dissector routines          */
589 /**************************************************/
590
591
592 /**************************************************/
593 /* Action routines for the "Decode As..." dialog  */
594 /*   - called when the OK button pressed          */
595 /*   - one per notebook page                      */
596 /**************************************************/
597
598
599 #ifdef DEBUG
600 /*
601  * Print debugging information about tree view selection.  Extract all
602  * information from the tree view entry that was selected and print it to
603  * a dialog window.
604  *
605  * @param tree_view The tree view to dump.
606  *
607  * @param leadin A string to print at the start of each line.
608  */
609 static void
610 decode_debug (GtkTreeView *tree_view, gchar *leadin)
611 {
612     GtkListStore *store;
613     GtkTreeSelection *selection;
614     GtkTreeIter iter;
615     char *string, *text[E_LIST_S_COLUMNS];
616     dissector_handle_t handle;
617
618     selection = gtk_tree_view_get_selection(tree_view);
619
620     if (gtk_tree_selection_get_selected(selection, NULL, &iter)){
621         store = GTK_LIST_STORE(gtk_tree_view_get_model(tree_view));
622         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
623                            E_LIST_S_PROTO_NAME, &text[E_LIST_S_PROTO_NAME],
624                            E_LIST_S_TABLE, &text[E_LIST_S_TABLE],
625                            E_LIST_S_TABLE+1, &handle,
626                            -1);
627         string = g_strdup_printf("%s list: <put handle here>, name %s, table %s",
628                                  leadin, text[E_LIST_S_PROTO_NAME],
629                                  text[E_LIST_S_TABLE]);
630     } else {
631         string = g_strdup_printf("%s list row (none), aka do not decode", leadin);
632     }
633     simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, string);
634     g_free(string);
635 }
636 #endif
637
638
639 /*
640  * This routine is called when the user clicks the "OK" button in the
641  * "Decode As..." dialog window and a 'simple' page is foremost.
642  * This routine takes care of making any changes requested to the
643  * dissector tables.  This routine is currently used for IP and
644  * Ethertypes.  Any 'single change' notebook page can use this
645  * routine.
646  *
647  * @param notebook_pg A pointer to the "network" notebook page.
648  */
649 static void
650 decode_simple (GtkWidget *notebook_pg)
651 {
652     GtkWidget *list, *combo_box;
653     GtkTreeSelection  *selection;
654     GtkTreeModel      *model;
655     GtkTreeIter        iter;
656     decode_as_t *entry;
657     gchar *table_name, *abbrev;
658     dissector_handle_t handle;
659     guint value_loop, *selector_type;
660     gpointer ptr, value_ptr;
661     gint requested_index = 0;
662     gboolean add_reset_list = FALSE;
663
664     list = (GtkWidget *)g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_LIST);
665     if (requested_action == E_DECODE_NO)
666         gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)));
667
668     entry = (decode_as_t *)g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_DECODE_AS_DATA);
669     table_name = (gchar *)g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_TABLE);
670
671     /* (sub)dissector selection */
672     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
673     if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
674     {
675         abbrev = NULL;
676         handle = NULL;
677     } else {
678         gtk_tree_model_get(model, &iter, E_LIST_S_PROTO_NAME, &abbrev,
679                            E_LIST_S_TABLE+1, &handle, -1);
680     }
681
682     if (entry->num_items > 1)
683     {
684         combo_box = (GtkWidget *)g_object_get_data(G_OBJECT(notebook_pg), E_COMBO_BOX_MULTIVALUE);
685         if (!ws_combo_box_get_active_pointer(GTK_COMBO_BOX(combo_box), &ptr))
686             g_assert_not_reached();  /* Programming error if no active item in combo_box */
687         requested_index = GPOINTER_TO_INT(ptr);
688     }
689
690     /* Apply values to dissector table (stored in entry) */
691     for (value_loop = 0; value_loop < entry->values[requested_index].num_values; value_loop++)
692     {
693         value_ptr = entry->values[requested_index].build_values[value_loop](&cfile.edt->pi);
694         if (abbrev != NULL && strcmp(abbrev, "(default)") == 0) {
695             add_reset_list = entry->reset_value(table_name, value_ptr);
696         } else {
697             add_reset_list = entry->change_value(table_name, value_ptr, &handle, abbrev);
698         }
699
700         if (add_reset_list) {
701             selector_type = g_new(guint,1);
702             *selector_type = GPOINTER_TO_UINT(value_ptr);
703             decode_build_reset_list(g_strdup(table_name), FT_UINT32, selector_type, NULL, NULL);
704         }
705     }
706
707     g_free(abbrev);
708 }
709
710
711 /**************************************************/
712 /*      Signals from the "Decode As..." dialog    */
713 /**************************************************/
714
715 /*
716  * This routine is called when the user clicks the "OK" button in the
717  * "Decode As..." dialog window.  This routine calls various helper
718  * routines to set/clear dissector values as requested by the user.
719  * These routines accumulate information on what actions they have
720  * taken, and this summary information is printed by this routine.
721  * This routine then destroys the dialog box and performs other
722  * housekeeping functions.
723  *
724  * @param ok_bt A pointer to the "OK" button.
725  *
726  * @param parent_w A pointer to the dialog window.
727  */
728 static void
729 decode_ok_cb (GtkWidget *ok_bt _U_, gpointer parent_w)
730 {
731     GtkWidget *notebook, *notebook_pg;
732     void (* func)(GtkWidget *);
733     gint page_num;
734     decode_as_t *entry;
735
736     /* Call the right routine for the page that was currently in front. */
737     notebook =  (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_NOTEBOOK);
738     page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
739     notebook_pg = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num);
740
741     func = (void (*)(GtkWidget *))g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_ACTION);
742     func(notebook_pg);
743
744     /* Free any values that used dynamic memory */
745     entry = (decode_as_t *)g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_DECODE_AS_DATA);
746     if ((entry->num_items == 1) && (entry->free_func != NULL))
747         entry->free_func(g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_VALUE));
748
749     window_destroy(GTK_WIDGET(parent_w));
750     g_slist_free(decode_dimmable);
751     decode_dimmable = NULL;
752
753     redissect_packets();
754     redissect_all_packet_windows();
755 }
756
757 /*
758  * This routine is called when the user clicks the "Apply" button in the
759  * "Decode As..." dialog window.  This routine calls various helper
760  * routines to set/clear dissector values as requested by the user.
761  * These routines accumulate information on what actions they have
762  * taken, and this summary information is printed by this routine.
763  *
764  * @param apply_bt A pointer to the "Apply" button.
765  *
766  * @param parent_w A pointer to the dialog window.
767  */
768 static void
769 decode_apply_cb (GtkWidget *apply_bt _U_, gpointer parent_w)
770 {
771     GtkWidget *notebook, *notebook_pg;
772     void (* func)(GtkWidget *);
773     gint page_num;
774
775     /* Call the right routine for the page that was currently in front. */
776     notebook =  (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_NOTEBOOK);
777     page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
778     notebook_pg = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num);
779
780     func = (void (*)(GtkWidget *))g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_ACTION);
781     func(notebook_pg);
782
783     redissect_packets();
784     redissect_all_packet_windows();
785 }
786
787 /*
788  * This routine is called when the user clicks the "Close" button in
789  * the "Decode As..." dialog window.  This routine then destroys the
790  * dialog box and performs other housekeeping functions.
791  *
792  * @param close_bt A pointer to the "Close" button.
793  *
794  * @param parent_w A pointer to the dialog window.
795  */
796 static void
797 decode_close_cb (GtkWidget *close_bt _U_, gpointer parent_w)
798 {
799     GtkWidget *notebook, *notebook_pg;
800     gint page_num;
801     decode_as_t *entry;
802
803     /* Call the right routine for the page that was currently in front. */
804     notebook =  (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_NOTEBOOK);
805     page_num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
806     notebook_pg = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page_num);
807
808     /* Free any values that used dynamic memory */
809     entry = (decode_as_t *)g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_DECODE_AS_DATA);
810     if ((entry->num_items == 1) && (entry->free_func != NULL))
811         entry->free_func(g_object_get_data(G_OBJECT(notebook_pg), E_PAGE_VALUE));
812
813     window_destroy(GTK_WIDGET(parent_w));
814     g_slist_free(decode_dimmable);
815     decode_dimmable = NULL;
816 }
817
818
819 /*
820  * This routine is called when the user clicks the "Close" button in
821  * the "Decode As..." dialog window.  This routine simply calls the
822  * close routine as if the user had clicked the close button instead
823  * of the close button.
824  *
825  * @param decode_w_lcl A pointer to the dialog box.
826  *
827  * @param event    A pointer to the GdkEvent struct
828  *
829  * @param user_data Unused
830  */
831 static gboolean
832 decode_delete_cb (GtkWidget *decode_w_lcl, GdkEvent *event _U_, gpointer user_data _U_)
833 {
834     decode_close_cb(NULL, decode_w_lcl);
835     return FALSE;
836 }
837
838
839 /*
840  * This routine is called at the destruction of the "Decode As..."
841  * dialog box.  It clears the pointer maintained by this file, so that
842  * the next time the user selects the "Decode As..." menu item a new
843  * dialog box will be created.
844  *
845  * @param win A pointer to the dialog box.
846  *
847  * @param user_data Unused
848  *
849  * @return void
850  */
851 static void
852 decode_destroy_cb (GtkWidget *win _U_, gpointer user_data _U_)
853 {
854     /* Note that we no longer have a "Decode As" dialog box. */
855     decode_w = NULL;
856 }
857
858
859 /*
860  * This routine is called when the user clicks the "Clear" button in
861  * the "Decode As..." dialog window.  This routine resets all the
862  * dissector values and performs other housekeeping functions.
863  *
864  * @param clear_bt A pointer to the "Clear" button.
865  *
866  * @param user_data Unused
867  */
868 static void
869 decode_clear_cb(GtkWidget *clear_bt _U_, gpointer user_data _U_)
870 {
871     decode_clear_all();
872     redissect_packets();
873     redissect_all_packet_windows();
874 }
875
876
877
878 /**************************************************/
879 /*          Dialog setup - radio buttons          */
880 /**************************************************/
881
882 /*
883  * Update the requested action field of the dialog.  This routine is
884  * called by GTK when either of the two radio buttons in the dialog is
885  * clicked.
886  *
887  * @param w The radio button that was clicked.
888  *
889  * @param user_data The enum value assigned to this radio button.  This
890  * will be either E_DECODE_YES or E_DECODE_NO
891  */
892 static void
893 decode_update_action (GtkWidget *w _U_, gpointer user_data)
894 {
895     GSList *tmp;
896     gboolean enable;
897
898     requested_action = (enum action_type)GPOINTER_TO_INT(user_data);
899     enable = (requested_action == E_DECODE_YES);
900     for (tmp = decode_dimmable; tmp; tmp = g_slist_next(tmp)) {
901         gtk_widget_set_sensitive((GtkWidget *)tmp->data, enable);
902     }
903 }
904
905 /*
906  * This routine is called to create the "Decode" and "Do not decode"
907  * radio buttons.  These buttons are installed into a vbox, and set up
908  * as a format group.
909  *
910  * @return GtkWidget * A pointer to the vbox containing the buttons
911  */
912 static GtkWidget *
913 decode_add_yes_no (void)
914 {
915     GtkWidget   *format_vb, *radio_button;
916     GSList      *format_grp;
917
918     format_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 2, FALSE);
919
920     radio_button = gtk_radio_button_new_with_label(NULL, "Decode");
921     format_grp = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button));
922     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE);
923     g_signal_connect(radio_button, "clicked", G_CALLBACK(decode_update_action),
924                    GINT_TO_POINTER(E_DECODE_YES));
925     gtk_box_pack_start(GTK_BOX(format_vb), radio_button, FALSE, FALSE, 0);
926
927     radio_button = gtk_radio_button_new_with_label(format_grp, "Do not decode");
928     g_signal_connect(radio_button, "clicked", G_CALLBACK(decode_update_action),
929                    GINT_TO_POINTER(E_DECODE_NO));
930     gtk_box_pack_start(GTK_BOX(format_vb), radio_button, FALSE, FALSE, 0);
931
932     return(format_vb);
933 }
934
935 /**************************************************/
936 /*          Dialog setup - simple combo_boxes     */
937 /**************************************************/
938
939 /*
940  * This routine is called to pack an combo_box into an aligment, so
941  * that it doesn't expand vertically to fill up the space available to
942  * it.
943  *
944  * @param combo_box A pointer to the option menu to be so packed.
945  *
946  * @return GtkWidget * A pointer to the newly created alignment.
947  */
948 static GtkWidget *
949 decode_add_pack_combo_box (GtkWidget *combo_box)
950 {
951     GtkWidget *alignment;
952
953     alignment = gtk_alignment_new(0.0f, 0.5f, 0.0f, 0.0f);
954     gtk_container_add(GTK_CONTAINER(alignment), combo_box);
955
956     return(alignment);
957 }
958
959
960 /*
961  * This routine is called to add a selection combo_box to
962  * the dialog box.  The combo_box choices are determined by the dissector.
963  * The default choice for the combo_box is also determined by the dissector.
964  *
965  * @param page A pointer notebook page that will contain all
966  * widgets created by this routine.
967  * @param entry Decode As structure used to setup combo_box
968  *
969  * @return GtkWidget * A pointer to the newly created alignment into
970  * which we've packed the newly created combo_box.
971  */
972 static GtkWidget *
973 decode_add_multivalue_combo_box (GtkWidget *page, decode_as_t *entry)
974 {
975     GtkWidget *combo_box, *alignment;
976     guint value;
977     gchar prompt[MAX_DECODE_AS_PROMPT_LEN];
978
979     combo_box = ws_combo_box_new_text_and_pointer();
980
981     for (value = 0; value < entry->num_items; value++)
982     {
983         entry->values[value].label_func(&cfile.edt->pi, prompt);
984         ws_combo_box_append_text_and_pointer(GTK_COMBO_BOX(combo_box), prompt, GINT_TO_POINTER(value));
985     }
986
987     ws_combo_box_set_active(GTK_COMBO_BOX(combo_box), entry->default_index_value);
988     g_object_set_data(G_OBJECT(page), E_COMBO_BOX_MULTIVALUE, combo_box);
989
990     alignment = decode_add_pack_combo_box(combo_box);
991     return(alignment);
992 }
993
994 /*************************************************/
995 /*        Dialog setup - list based menus        */
996 /*************************************************/
997
998 struct handle_lookup_info {
999     dissector_handle_t handle;
1000     gboolean           found;
1001 };
1002
1003 static gboolean
1004 lookup_handle(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
1005               gpointer user_data)
1006 {
1007     dissector_handle_t handle;
1008     struct handle_lookup_info *hli = (struct handle_lookup_info *)user_data;
1009
1010     gtk_tree_model_get(model, iter, E_LIST_S_TABLE+1, &handle, -1);
1011     if (hli->handle == handle) {
1012         hli->found = TRUE;
1013         return TRUE;
1014     }
1015     return FALSE;
1016 }
1017
1018 /*
1019  * This routine creates one entry in the list of protocol dissector
1020  * that can be used.  It is called by the dissector_table_foreach_handle
1021  * routine once for each entry in a dissector table's list of handles
1022  * for dissectors that could be used in that table.  It guarantees unique
1023  * entries by iterating over the list of entries build up to this point,
1024  * looking for a duplicate name.  If there is no duplicate, then this
1025  * entry is added to the list of possible dissectors.
1026  *
1027  * @param table_name The name of the dissector table currently
1028  * being walked.
1029  *
1030  * @param proto_name The protocol name
1031  *
1032  * @param value The dissector handle for this entry.  This is an opaque
1033  * pointer that can only be handed back to routines in the file packet.c
1034  *
1035  * @param user_data A data block passed into each instance of this
1036  * routine.  It contains information from the caller of the foreach
1037  * routine, specifying information about the dissector table and where
1038  * to store any information generated by this routine.
1039  */
1040 static void
1041 decode_add_to_list (const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data)
1042 {
1043     const gchar     *text[E_LIST_S_COLUMNS];
1044     GtkTreeView  *list;
1045     GtkListStore *store;
1046     GtkTreeIter   iter;
1047     struct handle_lookup_info hli;
1048
1049     g_assert(user_data);
1050     g_assert(value);
1051
1052     list = (GtkTreeView *)user_data;
1053
1054     hli.handle = (dissector_handle_t)value;
1055     hli.found = FALSE;
1056     store = GTK_LIST_STORE(gtk_tree_view_get_model(list));
1057     gtk_tree_model_foreach(GTK_TREE_MODEL(store), lookup_handle, &hli);
1058     /* We already have an entry for this handle.
1059      * XXX - will this ever happen? */
1060     if (hli.found) return;
1061
1062     text[E_LIST_S_PROTO_NAME] = proto_name;
1063     text[E_LIST_S_TABLE] = table_name;
1064     gtk_list_store_append(store, &iter);
1065     gtk_list_store_set(store, &iter,
1066                        E_LIST_S_PROTO_NAME, text[E_LIST_S_PROTO_NAME],
1067                        E_LIST_S_TABLE, text[E_LIST_S_TABLE],
1068                        E_LIST_S_TABLE+1, value, -1);
1069 }
1070
1071 static gboolean
1072 decode_list_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer user_data _U_)
1073 {
1074   if (event->type == GDK_2BUTTON_PRESS) {
1075     GtkWidget *main_w = gtk_widget_get_toplevel(list);
1076
1077     decode_ok_cb (NULL, main_w);
1078   }
1079
1080   return FALSE;
1081 }
1082
1083 static gboolean
1084 decode_list_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer user_data _U_)
1085 {
1086   if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
1087     GtkWidget    *main_w = gtk_widget_get_toplevel(list);
1088
1089     decode_ok_cb (NULL, main_w);
1090   }
1091
1092   return FALSE;
1093 }
1094
1095 /*
1096  * This routine starts the creation of a List on a notebook page.  It
1097  * creates both a scrolled window and a list, adds the list to the
1098  * window, and attaches the list as a data object on the page.
1099  *
1100  * @param page A pointer to the notebook page being created.
1101  *
1102  * @param list_p Will be filled in with the address of a newly
1103  * created List.
1104  *
1105  * @param scrolled_win_p Will be filled in with the address of a newly
1106  * created GtkScrolledWindow.
1107  */
1108 static void
1109 decode_list_menu_start(GtkWidget *page, GtkWidget **list_p,
1110                        GtkWidget **scrolled_win_p)
1111 {
1112     GtkTreeView       *list;
1113     GtkListStore      *store;
1114     GtkCellRenderer   *renderer;
1115     GtkTreeViewColumn *tc;
1116     GtkTreeSortable   *sortable;
1117
1118     store = gtk_list_store_new(E_LIST_S_COLUMNS+1, G_TYPE_STRING,
1119                                G_TYPE_STRING, G_TYPE_POINTER);
1120     g_object_set_data(G_OBJECT(decode_w), "sctp_data", store);
1121     list = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
1122     g_object_unref(G_OBJECT(store));
1123     sortable = GTK_TREE_SORTABLE(store);
1124     gtk_tree_sortable_set_sort_func(sortable, SORT_ALPHABETICAL, sort_iter_compare_func, GINT_TO_POINTER(SORT_ALPHABETICAL), NULL);
1125     gtk_tree_sortable_set_sort_column_id(sortable, SORT_ALPHABETICAL, GTK_SORT_ASCENDING);
1126     gtk_tree_view_set_headers_clickable(list, FALSE);
1127 #ifndef DEBUG
1128     gtk_tree_view_set_headers_visible(list, FALSE);
1129 #endif
1130     renderer = gtk_cell_renderer_text_new();
1131     tc = gtk_tree_view_column_new_with_attributes("Short Name", renderer,
1132                                                   "text", E_LIST_S_PROTO_NAME,
1133                                                   NULL);
1134     gtk_tree_view_column_set_sizing(tc, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1135     gtk_tree_view_append_column(list, tc);
1136     g_object_set_data(G_OBJECT(page), E_PAGE_LIST, list);
1137
1138     *scrolled_win_p = scrolled_window_new(NULL, NULL);
1139     /* this will result to set the width of the dialog to the required size */
1140     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(*scrolled_win_p),
1141                                    GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1142     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(*scrolled_win_p),
1143                                    GTK_SHADOW_IN);
1144     gtk_container_add(GTK_CONTAINER(*scrolled_win_p), GTK_WIDGET(list));
1145
1146     *list_p = GTK_WIDGET(list);
1147 }
1148
1149 /*
1150  * This routine finishes the creation of a List on a notebook page.
1151  * It adds the default entry, sets the default entry as the
1152  * highlighted entry, and sorts the List.
1153  *
1154  * @param list A pointer the the List to finish.
1155  */
1156 static void
1157 decode_list_menu_finish(GtkWidget *list)
1158 {
1159     const gchar *text[E_LIST_S_COLUMNS];
1160     GtkListStore *store;
1161     GtkTreeIter   iter;
1162
1163     text[E_LIST_S_PROTO_NAME] = "(default)";
1164     text[E_LIST_S_TABLE] = DECODE_AS_NONE;
1165     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
1166     gtk_list_store_prepend(store, &iter);
1167     gtk_list_store_set(store, &iter,
1168                        E_LIST_S_PROTO_NAME, text[E_LIST_S_PROTO_NAME],
1169                        E_LIST_S_TABLE, text[E_LIST_S_TABLE],
1170                        E_LIST_S_TABLE+1, NULL, -1);
1171
1172     gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), &iter);
1173     g_signal_connect(list, "button_press_event", G_CALLBACK(decode_list_button_press_cb), NULL);
1174     g_signal_connect(list, "key_release_event", G_CALLBACK(decode_list_key_release_cb), NULL);
1175 }
1176
1177 /*
1178  * This routine is called to add the dissector selection list to a
1179  * notebook page.  This scrolled list contains an entry labeled
1180  * "default", and an entry for each protocol that has had a dissector
1181  * registered.  The default choice for the list is set to the
1182  * "default" choice, which will return the protocol/port selections to
1183  * their original dissector(s).
1184  *
1185  * @param page A pointer to the notebook page currently being created.
1186  *
1187  * @param entry Decode As structure used to build this (list) menu.
1188  *
1189  * @return GtkWidget * A pointer to the newly created list within a
1190  * scrolled window.
1191  */
1192 static GtkWidget *
1193 decode_add_simple_menu (GtkWidget *page, decode_as_t *entry)
1194 {
1195     GtkWidget *scrolled_window;
1196     GtkWidget *list;
1197
1198     decode_list_menu_start(page, &list, &scrolled_window);
1199     entry->populate_list(entry->table_name, decode_add_to_list, list);
1200     decode_list_menu_finish(list);
1201     return(scrolled_window);
1202 }
1203
1204
1205 /**************************************************/
1206 /*                  Dialog setup                  */
1207 /**************************************************/
1208
1209 /*
1210  * This routine creates a sample notebook page in the dialog box.
1211  * This notebook page provides a prompt specifying what is being
1212  * changed and its current value (e.g. "IP Protocol number (17)"), and
1213  * a list specifying all the available choices.  The list of choices
1214  * is conditionally enabled, based upon the setting of the
1215  * "decode"/"do not decode" radio buttons.
1216  *
1217  * @param entry Decode As structure used to build this page
1218  *
1219  * @return GtkWidget * A pointer to the notebook page created by this
1220  * routine.
1221  */
1222 static GtkWidget *
1223 decode_add_simple_page (decode_as_t *entry)
1224 {
1225     GtkWidget  *page, *label, *scrolled_window, *combo_box;
1226     gchar prompt[MAX_DECODE_AS_PROMPT_LEN];
1227
1228     page = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5, FALSE);
1229     g_object_set_data(G_OBJECT(page), E_PAGE_ACTION, decode_simple);
1230     g_object_set_data(G_OBJECT(page), E_PAGE_TABLE, (gchar *) entry->table_name);
1231     g_object_set_data(G_OBJECT(page), E_PAGE_DECODE_AS_DATA, (gchar *)entry);
1232
1233     if (entry->num_items == 1)
1234     {
1235         g_object_set_data(G_OBJECT(page), E_PAGE_VALUE, entry->values[0].build_values[0](&cfile.edt->pi));
1236
1237         /* Always enabled */
1238         entry->values->label_func(&cfile.edt->pi, prompt);
1239         label = gtk_label_new(prompt);
1240         gtk_box_pack_start(GTK_BOX(page), label, FALSE, FALSE, 0);
1241     }
1242     else
1243     {
1244         /* Always enabled */
1245         if (entry->pre_value_str)
1246         {
1247             label = gtk_label_new(entry->pre_value_str);
1248             gtk_box_pack_start(GTK_BOX(page), label, FALSE, FALSE, 0);
1249         }
1250         combo_box = decode_add_multivalue_combo_box(page, entry);
1251         gtk_box_pack_start(GTK_BOX(page), combo_box, FALSE, FALSE, 0);
1252
1253         if (entry->post_value_str)
1254         {
1255             label = gtk_label_new(entry->post_value_str);
1256             gtk_box_pack_start(GTK_BOX(page), label, FALSE, FALSE, 0);
1257         }
1258     }
1259
1260     /* Conditionally enabled - only when decoding packets */
1261     scrolled_window = decode_add_simple_menu(page, entry);
1262     gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
1263     decode_dimmable = g_slist_prepend(decode_dimmable, scrolled_window);
1264
1265     return(page);
1266 }
1267
1268 /*
1269  * This routine indicates whether we'd actually have any pages in the
1270  * notebook in a "Decode As" dialog box; if there wouldn't be, we
1271  * inactivate the menu item for "Decode As".
1272  */
1273 gboolean
1274 decode_as_ok(void)
1275 {
1276     wmem_list_frame_t * protos = wmem_list_head(cfile.edt->pi.layers);
1277     int proto_id;
1278     const char* proto_name;
1279     GList *list_entry;
1280     decode_as_t *entry;
1281     dissector_table_t sub_dissectors;
1282
1283     while (protos != NULL)
1284     {
1285         proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
1286         proto_name = proto_get_protocol_filter_name(proto_id);
1287
1288         list_entry = decode_as_list;
1289         while (list_entry != NULL) {
1290             entry = (decode_as_t *)list_entry->data;
1291             if (!strcmp(proto_name, entry->name))
1292             {
1293                 sub_dissectors = find_dissector_table(entry->table_name);
1294                 if (sub_dissectors != NULL)
1295                     return TRUE;
1296             }
1297
1298             list_entry = g_list_next(list_entry);
1299         }
1300
1301         protos = wmem_list_frame_next(protos);
1302     }
1303
1304     return FALSE;
1305 }
1306
1307
1308 /*
1309  * This routine creates the bulk of the "Decode As" dialog box.  All
1310  * items created by this routine are packed as pages into a notebook.
1311  * There will be a page for each protocol layer that can be changed.
1312  *
1313  * @param format_hb A pointer to the widget in which the notebook
1314  * should be installed.
1315  */
1316 static void
1317 decode_add_notebook (GtkWidget *format_hb)
1318 {
1319     GtkWidget *notebook, *page, *label;
1320     wmem_list_frame_t * protos = wmem_list_head(cfile.edt->pi.layers);
1321     int proto_id;
1322     const char* proto_name;
1323     GList *list_entry;
1324     decode_as_t *entry;
1325     dissector_table_t sub_dissectors;
1326
1327     /* Start a nootbook for flipping between sets of changes */
1328     notebook = gtk_notebook_new();
1329     gtk_box_pack_start(GTK_BOX(format_hb), notebook, TRUE, TRUE, 0);
1330     g_object_set_data(G_OBJECT(decode_w), E_NOTEBOOK, notebook);
1331
1332     while (protos != NULL)
1333     {
1334         proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos));
1335         proto_name = proto_get_protocol_filter_name(proto_id);
1336
1337         list_entry = decode_as_list;
1338         while (list_entry != NULL) {
1339             entry = (decode_as_t *)list_entry->data;
1340             if (!strcmp(proto_name, entry->name))
1341             {
1342                 sub_dissectors = find_dissector_table(entry->table_name);
1343                 if (sub_dissectors != NULL)
1344                 {
1345                     page = decode_add_simple_page(entry);
1346                     label = gtk_label_new(entry->title);
1347                     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1348                 }
1349             }
1350
1351             list_entry = g_list_next(list_entry);
1352         }
1353
1354         protos = wmem_list_frame_next(protos);
1355     }
1356
1357     /* Select the last added page (selects first by default) */
1358     /* Notebook must be visible for set_page to work. */
1359     gtk_widget_show_all(notebook);
1360     gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), -1);
1361 }
1362
1363
1364 /*
1365  * This routine creates the "Decode As" dialog box. This dialog box
1366  * asks the user which protocol to use for decoding the currently
1367  * selected packet.  This will affect the last packet that we called a
1368  * dissection routine on belongs (this might be the most recently
1369  * selected packet, or it might be the last packet in the file).
1370  *
1371  * This routine uses an auxiliary function to create the bulk of the
1372  * dialog box, and then hand crafts the button box at the bottom of
1373  * the dialog.
1374  *
1375  * @param w Unused
1376  *
1377  * @param user_data Unused
1378  */
1379 void
1380 decode_as_cb (GtkWidget * w _U_, gpointer user_data _U_)
1381 {
1382     GtkWidget   *main_vb, *format_hb, *bbox, *ok_bt, *close_bt, *help_bt, *button;
1383     GtkWidget   *button_vb, *apply_bt;
1384
1385     if (decode_w != NULL) {
1386         /* There's already a "Decode As" dialog box; reactivate it. */
1387         reactivate_window(decode_w);
1388         return;
1389     }
1390
1391     requested_action = E_DECODE_YES;
1392     decode_w = dlg_window_new("Wireshark: Decode As");
1393     /* Provide a minimum of a couple of rows worth of data */
1394     gtk_window_set_default_size(GTK_WINDOW(decode_w), -1, E_DECODE_MIN_HEIGHT);
1395
1396     /* Container for each row of widgets */
1397     main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 2, FALSE);
1398     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
1399     gtk_container_add(GTK_CONTAINER(decode_w), main_vb);
1400
1401     /* First row - Buttons and Notebook */
1402     format_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5, FALSE);
1403     gtk_box_pack_start(GTK_BOX(main_vb), format_hb, TRUE, TRUE, 10);
1404
1405     button_vb = decode_add_yes_no();
1406     gtk_box_pack_start(GTK_BOX(format_hb), button_vb, FALSE, FALSE, 10);
1407
1408     button = gtk_button_new_with_label("Show Current");
1409     g_signal_connect(button, "clicked", G_CALLBACK(decode_show_cb), NULL);
1410     gtk_widget_set_can_default(button, TRUE);
1411     gtk_box_pack_end(GTK_BOX(button_vb), button, FALSE, FALSE, 0);
1412         gtk_widget_set_tooltip_text(button, "Open a dialog showing the current settings.\n"
1413                 "Note you need to select and press apply first to be able to save the current setting");
1414
1415     button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
1416     g_signal_connect(button, "clicked", G_CALLBACK(decode_clear_cb), NULL);
1417     gtk_widget_set_can_default(button, TRUE);
1418     gtk_box_pack_end(GTK_BOX(button_vb), button, FALSE, FALSE, 0);
1419         gtk_widget_set_tooltip_text(button, "Clear ALL settings.");
1420
1421     decode_add_notebook(format_hb);
1422
1423     /* Button row */
1424     bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
1425     gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
1426     gtk_widget_show(bbox);
1427
1428     ok_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
1429     g_signal_connect(ok_bt, "clicked", G_CALLBACK(decode_ok_cb), decode_w);
1430         gtk_widget_set_tooltip_text(ok_bt, "Apply current setting, close dialog and redissect packets.");
1431
1432     apply_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
1433     g_signal_connect(apply_bt, "clicked", G_CALLBACK(decode_apply_cb), decode_w);
1434         gtk_widget_set_tooltip_text(apply_bt, "Apply current setting, redissect packets and keep dialog open.");
1435
1436     close_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1437     window_set_cancel_button(decode_w, close_bt, NULL);
1438     g_signal_connect(close_bt, "clicked", G_CALLBACK(decode_close_cb), decode_w);
1439         gtk_widget_set_tooltip_text(close_bt, "Close the dialog, don't redissect packets.");
1440
1441     help_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1442     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_DECODE_AS_DIALOG);
1443
1444     gtk_widget_grab_default(ok_bt);
1445
1446     g_signal_connect(decode_w, "delete_event", G_CALLBACK(decode_delete_cb), NULL);
1447     g_signal_connect(decode_w, "destroy", G_CALLBACK(decode_destroy_cb), NULL);
1448
1449     gtk_widget_show_all(decode_w);
1450     window_present(decode_w);
1451 }