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