"Field Information" context menu item that will bring up a web page reference to...
[obnox/wireshark/wip.git] / gtk / menu.c
1 /* menu.c
2  * Menu routines
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30
31 #include <string.h>
32
33 #include "main.h"
34 #include "menu.h"
35 #include "../stat_menu.h"
36 #include "gui_stat_menu.h"
37 #include <epan/packet.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/prefs.h>
40 #include <epan/tap.h>
41 #include <epan/timestamp.h>
42 #include <epan/ipproto.h>
43
44 #include "about_dlg.h"
45 #include "capture_dlg.h"
46 #include "color_dlg.h"
47 #include "filter_dlg.h"
48 #include "dlg_utils.h"
49 #include "capture_file_dlg.h"
50 #include "fileset_dlg.h"
51 #include "find_dlg.h"
52 #include "goto_dlg.h"
53 #include "summary_dlg.h"
54 #include "prefs_dlg.h"
55 #include "packet_win.h"
56 #include "print.h"
57 #include "follow_dlg.h"
58 #include "decode_as_dlg.h"
59 #include "help_dlg.h"
60 #include "supported_protos_dlg.h"
61 #include "proto_dlg.h"
62 #include "proto_hier_stats_dlg.h"
63 #include "keys.h"
64 #include <epan/plugins.h>
65 #include <epan/epan_dissect.h>
66 #include "compat_macros.h"
67 #include "toolbar.h"
68 #include "gtkglobals.h"
69 #include "register.h"
70 #include "../menu.h"
71 #include "packet_list.h"
72 #include "ethclist.h"
73 #include "recent.h"
74 #include "../ui_util.h"
75 #include "proto_draw.h"
76 #include "conversations_table.h"
77 #include "hostlist_table.h"
78 #include "simple_dialog.h"
79 #include "packet_history.h"
80 #include "color_filters.h"
81 #include "ssl-dlg.h"
82
83 GtkWidget *popup_menu_object;
84
85 static void
86 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w, gpointer unused _U_);
87
88 typedef struct _menu_item {
89     char    *name;
90     gint    group;
91     gboolean enabled;
92     GtkItemFactoryCallback callback;
93     gpointer callback_data;
94     gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *);
95     gboolean (*selected_tree_row_enabled)(field_info *);
96     GList *children;
97 } menu_item_t;
98
99 static GList *tap_menu_tree_root = NULL;
100
101 static void 
102 merge_all_tap_menus(GList *node);
103
104 #define GTK_MENU_FUNC(a) ((GtkItemFactoryCallback)(a))
105
106 static void menus_init(void);
107 static void set_menu_sensitivity (GtkItemFactory *, const gchar *, gint);
108 static void main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
109 static void filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
110 static void packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_);
111 static void tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_);
112 static void byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_);
113 static void statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_);
114 static void timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_);
115 static void timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_);
116 static void timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_);
117 static void timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_);
118 static void timestamp_auto_cb(GtkWidget *w _U_, gpointer d _U_);
119 static void timestamp_sec_cb(GtkWidget *w _U_, gpointer d _U_);
120 static void timestamp_dsec_cb(GtkWidget *w _U_, gpointer d _U_);
121 static void timestamp_csec_cb(GtkWidget *w _U_, gpointer d _U_);
122 static void timestamp_msec_cb(GtkWidget *w _U_, gpointer d _U_);
123 static void timestamp_usec_cb(GtkWidget *w _U_, gpointer d _U_);
124 static void timestamp_nsec_cb(GtkWidget *w _U_, gpointer d _U_);
125 static void name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_);
126 static void name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_);
127 static void name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_);
128 #ifdef HAVE_LIBPCAP
129 static void auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_);
130 #endif
131 static void colorize_cb(GtkWidget *w _U_, gpointer d _U_);
132
133 /* This is the GtkItemFactoryEntry structure used to generate new menus.
134        Item 1: The menu path. The letter after the underscore indicates an
135                accelerator key once the menu is open.
136        Item 2: The accelerator key for the entry
137        Item 3: The callback function.
138        Item 4: The callback action.  This changes the parameters with
139                which the function is called.  The default is 0.
140        Item 5: The item type, used to define what kind of an item it is.
141                Here are the possible values:
142
143                NULL               -> "<Item>"
144                ""                 -> "<Item>"
145                "<Title>"          -> create a title item
146                "<Item>"           -> create a simple item
147                "<ImageItem>"      -> create an item holding an image (gtk2)
148                "<StockItem>"      -> create an item holding a stock image (gtk2)
149                "<CheckItem>"      -> create a check item
150                "<ToggleItem>"     -> create a toggle item
151                "<RadioItem>"      -> create a radio item
152                <path>             -> path of a radio item to link against
153                "<Separator>"      -> create a separator
154                "<Tearoff>"        -> create a tearoff separator (gtk2)
155                "<Branch>"         -> create an item to hold sub items (optional)
156                "<LastBranch>"     -> create a right justified branch
157        Item 6: extra data needed for ImageItem and StockItem (gtk2)
158     */
159
160 /*  As a general GUI guideline, we try to follow the Gnome Human Interface Guidelines, which can be found at:
161     http://developer.gnome.org/projects/gup/hig/1.0/index.html
162     
163 Please note: there are some differences between the Gnome HIG menu suggestions and our implementation:
164
165 File/Open Recent:   the Gnome HIG suggests putting the list of recently used files as elements into the File menuitem.
166                     As this is ok for only a few items, this will become unhandy for 10 or even more list entries.
167                     For this reason, we use a submenu for this.
168
169 File/Close:         the Gnome HIG suggests putting this item just above the Quit item.
170                     This results in unintuitive behaviour as both Close and Quit items are very near together.
171                     By putting the Close item near the open item(s), it better suggests that it will close the 
172                     currently opened/captured file only.
173 */
174
175 /* main menu */
176 static GtkItemFactoryEntry menu_items[] =
177 {
178     ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL),
179     ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb,
180                              0, GTK_STOCK_OPEN),
181     ITEM_FACTORY_ENTRY("/File/Open _Recent", NULL, NULL, 0, "<Branch>", NULL),
182     ITEM_FACTORY_ENTRY("/File/_Merge...", NULL, file_merge_cmd_cb, 0, NULL, NULL),
183     ITEM_FACTORY_STOCK_ENTRY("/File/_Close", "<control>W", file_close_cmd_cb,
184                              0, GTK_STOCK_CLOSE),
185     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
186     ITEM_FACTORY_STOCK_ENTRY("/File/_Save", "<control>S", file_save_cmd_cb,
187                              0, GTK_STOCK_SAVE),
188     ITEM_FACTORY_STOCK_ENTRY("/File/Save _As...", "<shift><control>S", file_save_as_cmd_cb,
189                              0, GTK_STOCK_SAVE_AS),
190     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
191     ITEM_FACTORY_ENTRY("/File/File Set", NULL, NULL, 0, "<Branch>", NULL),
192     ITEM_FACTORY_STOCK_ENTRY("/File/File Set/List Files", NULL, fileset_cb, 0, ETHEREAL_STOCK_FILE_SET_LIST),
193     ITEM_FACTORY_STOCK_ENTRY("/File/File Set/Next File", NULL, fileset_next_cb, 0, ETHEREAL_STOCK_FILE_SET_NEXT),
194     ITEM_FACTORY_STOCK_ENTRY("/File/File Set/Previous File", NULL, fileset_previous_cb, 0, ETHEREAL_STOCK_FILE_SET_PREVIOUS),
195     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
196     ITEM_FACTORY_ENTRY("/File/_Export", NULL, NULL, 0, "<Branch>", NULL),
197     ITEM_FACTORY_ENTRY("/File/Export/as \"Plain _Text\" file...", NULL, export_text_cmd_cb,
198                              0, NULL, NULL),
199     ITEM_FACTORY_ENTRY("/File/Export/as \"_PostScript\" file...", NULL, export_ps_cmd_cb,
200                              0, NULL, NULL),
201     ITEM_FACTORY_ENTRY("/File/Export/as \"_CSV\" (Comma Separated Values packet summary) file...",
202                              NULL, export_csv_cmd_cb, 0, NULL, NULL),
203     ITEM_FACTORY_ENTRY("/File/Export/<separator>", NULL, NULL, 0, "<Separator>", NULL),
204     ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_SML\" (packet summary) file...", NULL, export_psml_cmd_cb,
205                              0, NULL, NULL),
206     ITEM_FACTORY_ENTRY("/File/Export/as XML - \"P_DML\" (packet details) file...", NULL, export_pdml_cmd_cb,
207                              0, NULL, NULL),
208     ITEM_FACTORY_ENTRY("/File/Export/<separator>", NULL, NULL, 0, "<Separator>", NULL),
209     ITEM_FACTORY_ENTRY("/File/Export/Selected Packet _Bytes...", "<control>H", savehex_cb,
210                              0, NULL, NULL),
211     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
212     ITEM_FACTORY_STOCK_ENTRY("/File/_Print...", "<control>P", file_print_cmd_cb,
213                              0, GTK_STOCK_PRINT),
214     ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL),
215     ITEM_FACTORY_STOCK_ENTRY("/File/_Quit", "<control>Q", file_quit_cmd_cb,
216                              0, GTK_STOCK_QUIT),
217     ITEM_FACTORY_ENTRY("/_Edit", NULL, NULL, 0, "<Branch>", NULL),
218 #if 0
219     /* Un-#if this when we actually implement Cut/Copy/Paste. */
220     ITEM_FACTORY_STOCK_ENTRY("/Edit/Cut", "<control>X", NULL,
221                              0, GTK_STOCK_CUT),
222     ITEM_FACTORY_STOCK_ENTRY("/Edit/Copy", "<control>C", NULL,
223                              0, GTK_STOCK_COPY),
224     ITEM_FACTORY_STOCK_ENTRY("/Edit/Paste", "<control>V", NULL,
225                              0, GTK_STOCK_PASTE),
226     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>"),
227 #endif
228     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Find Packet...", "<control>F",
229                              find_frame_cb, 0, GTK_STOCK_FIND),
230     ITEM_FACTORY_ENTRY("/Edit/Find Ne_xt", "<control>N", find_next_cb, 0, NULL, NULL),
231     ITEM_FACTORY_ENTRY("/Edit/Find Pre_vious", "<control>B", find_previous_cb, 0, NULL, NULL),
232     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
233     ITEM_FACTORY_ENTRY("/Edit/_Time Reference", NULL, NULL, 0, "<Branch>", NULL),
234     ITEM_FACTORY_STOCK_ENTRY("/Edit/Time Reference/Set Time Reference (toggle)", "<control>T", reftime_frame_cb, 
235                         REFTIME_TOGGLE, ETHEREAL_STOCK_TIME),
236     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Next", NULL, reftime_frame_cb, REFTIME_FIND_NEXT, NULL, NULL),
237     ITEM_FACTORY_ENTRY("/Edit/Time Reference/Find Previous", NULL, reftime_frame_cb, REFTIME_FIND_PREV, NULL, NULL),
238     ITEM_FACTORY_ENTRY("/Edit/_Mark Packet (toggle)", "<control>M", packet_list_mark_frame_cb,
239                        0, NULL, NULL),
240     ITEM_FACTORY_ENTRY("/Edit/Mark _All Packets", NULL, packet_list_mark_all_frames_cb,
241                        0, NULL, NULL),
242     ITEM_FACTORY_ENTRY("/Edit/_Unmark All Packets", NULL, packet_list_unmark_all_frames_cb,
243                        0, NULL, NULL),
244     ITEM_FACTORY_ENTRY("/Edit/<separator>", NULL, NULL, 0, "<Separator>", NULL),
245     ITEM_FACTORY_STOCK_ENTRY("/Edit/_Preferences...", "<shift><control>P", prefs_cb,
246                              0, GTK_STOCK_PREFERENCES),
247     ITEM_FACTORY_ENTRY("/_View", NULL, NULL, 0, "<Branch>", NULL),
248     ITEM_FACTORY_ENTRY("/View/_Main Toolbar", NULL, main_toolbar_show_cb, 0, "<CheckItem>", NULL),
249     ITEM_FACTORY_ENTRY("/View/_Filter Toolbar", NULL, filter_toolbar_show_cb, 0, "<CheckItem>", NULL),
250     ITEM_FACTORY_ENTRY("/View/_Statusbar", NULL, statusbar_show_cb, 0, "<CheckItem>", NULL),
251     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
252     ITEM_FACTORY_ENTRY("/View/Packet _List", NULL, packet_list_show_cb, 0, "<CheckItem>", NULL),
253     ITEM_FACTORY_ENTRY("/View/Packet _Details", NULL, tree_view_show_cb, 0, "<CheckItem>", NULL),
254     ITEM_FACTORY_ENTRY("/View/Packet _Bytes", NULL, byte_view_show_cb, 0, "<CheckItem>", NULL),
255     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
256     ITEM_FACTORY_ENTRY("/View/_Time Display Format", NULL, NULL, 0, "<Branch>", NULL),
257     ITEM_FACTORY_ENTRY("/View/Time Display Format/Date and Time of Day:   1970-01-01 01:02:03.123456", NULL, timestamp_absolute_date_cb, 
258                         0, "<RadioItem>", NULL),
259     ITEM_FACTORY_ENTRY("/View/Time Display Format/Time of Day:   01:02:03.123456", NULL, timestamp_absolute_cb, 
260                         0, "/View/Time Display Format/Date and Time of Day:   1970-01-01 01:02:03.123456", NULL),
261     ITEM_FACTORY_ENTRY("/View/Time Display Format/Seconds Since Beginning of Capture:   123.123456", NULL, timestamp_relative_cb, 
262                         0, "/View/Time Display Format/Date and Time of Day:   1970-01-01 01:02:03.123456", NULL),
263     ITEM_FACTORY_ENTRY("/View/Time Display Format/Seconds Since Previous Packet:   1.123456", NULL, timestamp_delta_cb, 
264                         0, "/View/Time Display Format/Date and Time of Day:   1970-01-01 01:02:03.123456", NULL),
265     ITEM_FACTORY_ENTRY("/View/Time Display Format/<separator>", NULL, NULL, 0, "<Separator>", NULL),
266     ITEM_FACTORY_ENTRY("/View/Time Display Format/Automatic (File Format Precision)", NULL, timestamp_auto_cb, 
267                         0, "<RadioItem>", NULL),
268     ITEM_FACTORY_ENTRY("/View/Time Display Format/Seconds:   0", NULL, timestamp_sec_cb, 
269                         0, "/View/Time Display Format/Automatic (File Format Precision)", NULL),
270     ITEM_FACTORY_ENTRY("/View/Time Display Format/Deciseconds:   0.1", NULL, timestamp_dsec_cb, 
271                         0, "/View/Time Display Format/Automatic (File Format Precision)", NULL),
272     ITEM_FACTORY_ENTRY("/View/Time Display Format/Centiseconds:   0.12", NULL, timestamp_csec_cb, 
273                         0, "/View/Time Display Format/Automatic (File Format Precision)", NULL),
274     ITEM_FACTORY_ENTRY("/View/Time Display Format/Milliseconds:   0.123", NULL, timestamp_msec_cb, 
275                         0, "/View/Time Display Format/Automatic (File Format Precision)", NULL),
276     ITEM_FACTORY_ENTRY("/View/Time Display Format/Microseconds:   0.123456", NULL, timestamp_usec_cb, 
277                         0, "/View/Time Display Format/Automatic (File Format Precision)", NULL),
278     ITEM_FACTORY_ENTRY("/View/Time Display Format/Nanoseconds:   0.123456789", NULL, timestamp_nsec_cb, 
279                         0, "/View/Time Display Format/Automatic (File Format Precision)", NULL),
280     ITEM_FACTORY_ENTRY("/View/Name Resol_ution", NULL, NULL, 0, "<Branch>", NULL),
281     ITEM_FACTORY_ENTRY("/View/Name Resolution/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
282     ITEM_FACTORY_ENTRY("/View/Name Resolution/<separator>", NULL, NULL, 0, "<Separator>", NULL),
283     ITEM_FACTORY_ENTRY("/View/Name Resolution/Enable for _MAC Layer", NULL, name_resolution_mac_cb, 0, "<CheckItem>", NULL),
284     ITEM_FACTORY_ENTRY("/View/Name Resolution/Enable for _Network Layer", NULL, name_resolution_network_cb, 0, "<CheckItem>", NULL),
285     ITEM_FACTORY_ENTRY("/View/Name Resolution/Enable for _Transport Layer", NULL, name_resolution_transport_cb, 0, "<CheckItem>", NULL),
286     ITEM_FACTORY_ENTRY("/View/Colorize Packet List", NULL, colorize_cb, 0, "<CheckItem>", NULL),
287 #ifdef HAVE_LIBPCAP
288     ITEM_FACTORY_ENTRY("/View/Auto Scroll in Li_ve Capture", NULL, auto_scroll_live_cb, 0, "<CheckItem>", NULL),
289 #endif
290     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
291     ITEM_FACTORY_STOCK_ENTRY("/View/_Zoom In", "<control>plus", view_zoom_in_cb,
292                              0, GTK_STOCK_ZOOM_IN),
293     ITEM_FACTORY_STOCK_ENTRY("/View/Zoom _Out", "<control>minus", view_zoom_out_cb,
294                              0, GTK_STOCK_ZOOM_OUT),
295     ITEM_FACTORY_STOCK_ENTRY("/View/_Normal Size", "<control>equal", view_zoom_100_cb,
296                              0, GTK_STOCK_ZOOM_100),
297     ITEM_FACTORY_STOCK_ENTRY("/View/Resize All Columns", NULL, packet_list_resize_columns_cb,
298                        0, ETHEREAL_STOCK_RESIZE_COLUMNS),
299     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
300     ITEM_FACTORY_ENTRY("/View/E_xpand Subtrees", NULL, expand_tree_cb, 0, NULL, NULL),
301     ITEM_FACTORY_ENTRY("/View/_Expand All", NULL, expand_all_cb,
302                        0, NULL, NULL),
303     ITEM_FACTORY_ENTRY("/View/Collapse _All", NULL, collapse_all_cb,
304                        0, NULL, NULL),
305     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
306     ITEM_FACTORY_STOCK_ENTRY("/View/_Coloring Rules...", NULL, color_display_cb,
307                        0, GTK_STOCK_SELECT_COLOR),
308     ITEM_FACTORY_ENTRY("/View/<separator>", NULL, NULL, 0, "<Separator>", NULL),
309     ITEM_FACTORY_ENTRY("/View/Show Packet in New _Window", NULL,
310                        new_window_cb, 0, NULL, NULL),
311     ITEM_FACTORY_STOCK_ENTRY("/View/_Reload", "<control>R", file_reload_cmd_cb,
312                              0, GTK_STOCK_REFRESH),
313     ITEM_FACTORY_ENTRY("/_Go", NULL, NULL, 0, "<Branch>", NULL),
314     ITEM_FACTORY_STOCK_ENTRY("/Go/_Back", "<alt>Left",
315                              history_back_cb, 0, GTK_STOCK_GO_BACK),
316     ITEM_FACTORY_STOCK_ENTRY("/Go/_Forward", "<alt>Right",
317                              history_forward_cb, 0, GTK_STOCK_GO_FORWARD),
318     ITEM_FACTORY_STOCK_ENTRY("/Go/_Go to Packet...", "<control>G",
319                              goto_frame_cb, 0, GTK_STOCK_JUMP_TO),
320     ITEM_FACTORY_ENTRY("/Go/Go to _Corresponding Packet", NULL, goto_framenum_cb,
321                        0, NULL, NULL),
322     ITEM_FACTORY_ENTRY("/Go/<separator>", NULL, NULL, 0, "<Separator>", NULL),
323     ITEM_FACTORY_STOCK_ENTRY("/Go/F_irst Packet", NULL,
324                              goto_top_frame_cb, 0, GTK_STOCK_GOTO_TOP),
325     ITEM_FACTORY_STOCK_ENTRY("/Go/_Last Packet", NULL,
326                              goto_bottom_frame_cb, 0, GTK_STOCK_GOTO_BOTTOM),
327 #ifdef HAVE_LIBPCAP
328     ITEM_FACTORY_ENTRY("/_Capture", NULL, NULL, 0, "<Branch>", NULL),
329     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Interfaces...", NULL,
330                              capture_if_cb, 0, ETHEREAL_STOCK_CAPTURE_INTERFACES),
331     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Options...", "<control>K",
332                              capture_prep_cb, 0, ETHEREAL_STOCK_CAPTURE_OPTIONS),
333     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Start", NULL,
334                              capture_start_cb, 0, ETHEREAL_STOCK_CAPTURE_START),
335     ITEM_FACTORY_STOCK_ENTRY("/Capture/S_top", "<control>E", capture_stop_cb,
336                              0, ETHEREAL_STOCK_CAPTURE_STOP),
337     ITEM_FACTORY_STOCK_ENTRY("/Capture/_Restart", NULL, capture_restart_cb,
338                              0, ETHEREAL_STOCK_CAPTURE_RESTART),
339     ITEM_FACTORY_STOCK_ENTRY("/Capture/Capture _Filters...", NULL, cfilter_dialog_cb,
340                        0, ETHEREAL_STOCK_CAPTURE_FILTER),
341 #endif /* HAVE_LIBPCAP */
342     ITEM_FACTORY_ENTRY("/_Analyze", NULL, NULL, 0, "<Branch>", NULL),
343     ITEM_FACTORY_STOCK_ENTRY("/Analyze/_Display Filters...", NULL, dfilter_dialog_cb,
344                        0, ETHEREAL_STOCK_DISPLAY_FILTER),
345     ITEM_FACTORY_ENTRY("/Analyze/Appl_y as Filter", NULL, NULL, 0, "<Branch>", NULL),
346     ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/_Selected", NULL, match_selected_ptree_cb, 
347                        MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
348     ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/_Not Selected", NULL, match_selected_ptree_cb, 
349                        MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
350     ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... _and Selected", NULL, match_selected_ptree_cb,
351                        MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
352     ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... _or Selected", NULL, match_selected_ptree_cb,
353                        MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
354     ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... a_nd not Selected", NULL, match_selected_ptree_cb, 
355                        MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
356     ITEM_FACTORY_ENTRY("/Analyze/Apply as Filter/... o_r not Selected", NULL, match_selected_ptree_cb, 
357                        MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
358     ITEM_FACTORY_ENTRY("/Analyze/_Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
359     ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/_Selected", NULL, match_selected_ptree_cb, 
360                        MATCH_SELECTED_REPLACE, NULL, NULL),
361     ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/_Not Selected", NULL, match_selected_ptree_cb, 
362                        MATCH_SELECTED_NOT, NULL, NULL),
363     ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... _and Selected", NULL, match_selected_ptree_cb,
364                        MATCH_SELECTED_AND, NULL, NULL),
365     ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... _or Selected", NULL, match_selected_ptree_cb,
366                        MATCH_SELECTED_OR, NULL, NULL),
367     ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... a_nd not Selected", NULL, match_selected_ptree_cb, 
368                        MATCH_SELECTED_AND_NOT, NULL, NULL),
369     ITEM_FACTORY_ENTRY("/Analyze/Prepare a Filter/... o_r not Selected", NULL, match_selected_ptree_cb, 
370                        MATCH_SELECTED_OR_NOT, NULL, NULL),
371     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
372     ITEM_FACTORY_STOCK_ENTRY("/Analyze/_Enabled Protocols...", "<shift><control>R", proto_cb, 0, ETHEREAL_STOCK_CHECKBOX),
373     ITEM_FACTORY_STOCK_ENTRY("/Analyze/Decode _As...", NULL, decode_as_cb,
374                        0, ETHEREAL_STOCK_DECODE_AS),
375     ITEM_FACTORY_STOCK_ENTRY("/Analyze/_User Specified Decodes...", NULL,
376                        decode_show_cb, 0, ETHEREAL_STOCK_DECODE_AS),
377     ITEM_FACTORY_ENTRY("/Analyze/<separator>", NULL, NULL, 0, "<Separator>", NULL),
378     ITEM_FACTORY_ENTRY("/Analyze/_Follow TCP Stream", NULL,
379                        follow_stream_cb, 0, NULL, NULL),    
380     ITEM_FACTORY_ENTRY("/Analyze/_Follow SSL Stream", NULL,
381                        ssl_stream_cb, 0, NULL, NULL),    
382     ITEM_FACTORY_ENTRY("/_Statistics", NULL, NULL, 0, "<Branch>", NULL),
383     ITEM_FACTORY_STOCK_ENTRY("/Statistics/_Summary", NULL, summary_open_cb, 0, GTK_STOCK_PROPERTIES),
384     ITEM_FACTORY_ENTRY("/Statistics/_Protocol Hierarchy", NULL,
385                        proto_hier_stats_cb, 0, NULL, NULL),
386     ITEM_FACTORY_STOCK_ENTRY("/Statistics/Conversations", NULL,
387                        init_conversation_notebook_cb, 0, ETHEREAL_STOCK_CONVERSATIONS),
388     ITEM_FACTORY_STOCK_ENTRY("/Statistics/Endpoints", NULL,
389                        init_hostlist_notebook_cb, 0, ETHEREAL_STOCK_ENDPOINTS),
390     ITEM_FACTORY_ENTRY("/_Help", NULL, NULL, 0, "<Branch>", NULL),
391     ITEM_FACTORY_STOCK_ENTRY("/Help/_Contents", "F1", topic_menu_cb, HELP_CONTENT, GTK_STOCK_HELP),
392     ITEM_FACTORY_ENTRY("/Help/_Supported Protocols", NULL, supported_cb, 0, NULL, NULL),
393 #if (GLIB_MAJOR_VERSION >= 2)
394 #ifdef ETHEREAL_EUG_DIR
395     ITEM_FACTORY_ENTRY("/Help/User's Guide", NULL, topic_menu_cb, HELP_CONTENT, NULL, NULL),
396 #endif
397     ITEM_FACTORY_ENTRY("/Help/Manual Pages", NULL, NULL, 0, "<Branch>", NULL),
398     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Ethereal", NULL, topic_menu_cb, LOCALPAGE_MAN_ETHEREAL, NULL, NULL),
399     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Ethereal Filter", NULL, topic_menu_cb, LOCALPAGE_MAN_ETHEREAL_FILTER, NULL, NULL),
400     ITEM_FACTORY_ENTRY("/Help/Manual Pages/<separator>", NULL, NULL, 0, "<Separator>", NULL),
401     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Tethereal", NULL, topic_menu_cb, LOCALPAGE_MAN_TETHEREAL, NULL, NULL),
402     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Dumpcap", NULL, topic_menu_cb, LOCALPAGE_MAN_DUMPCAP, NULL, NULL),
403     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Mergecap", NULL, topic_menu_cb, LOCALPAGE_MAN_MERGECAP, NULL, NULL),
404     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Editcap", NULL, topic_menu_cb, LOCALPAGE_MAN_EDITCAP, NULL, NULL),
405     ITEM_FACTORY_ENTRY("/Help/Manual Pages/Text2pcap", NULL, topic_menu_cb, LOCALPAGE_MAN_TEXT2PCAP, NULL, NULL),
406     ITEM_FACTORY_ENTRY("/Help/Ethereal Online", NULL, NULL, 0, "<Branch>", NULL),
407     ITEM_FACTORY_STOCK_ENTRY("/Help/Ethereal Online/Home Page", NULL, topic_menu_cb, ONLINEPAGE_HOME, GTK_STOCK_HOME),
408     ITEM_FACTORY_STOCK_ENTRY("/Help/Ethereal Online/Wiki", NULL, topic_menu_cb, ONLINEPAGE_WIKI, ETHEREAL_STOCK_WIKI),
409     ITEM_FACTORY_STOCK_ENTRY("/Help/Ethereal Online/User's Guide", NULL, topic_menu_cb, ONLINEPAGE_USERGUIDE, ETHEREAL_STOCK_WEB_SUPPORT),
410     ITEM_FACTORY_ENTRY("/Help/Ethereal Online/FAQ's", NULL, topic_menu_cb, ONLINEPAGE_FAQ, NULL, NULL),
411     ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Downloads", NULL, topic_menu_cb, ONLINEPAGE_DOWNLOAD, NULL, NULL),
412     ITEM_FACTORY_ENTRY("/Help/Ethereal Online/Example Files", NULL, topic_menu_cb, ONLINEPAGE_SAMPLE_FILES, NULL, NULL),
413 #endif
414     ITEM_FACTORY_ENTRY("/Help/<separator>", NULL, NULL, 0, "<Separator>", NULL),
415     ITEM_FACTORY_STOCK_ENTRY("/Help/_About Ethereal", NULL, about_ethereal_cb,
416                        0, ETHEREAL_STOCK_ABOUT)
417 };
418
419
420 /* calculate the number of menu_items */
421 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
422
423 /* packet list popup */
424 static GtkItemFactoryEntry packet_list_menu_items[] =
425 {
426     ITEM_FACTORY_ENTRY("/Mark Packet (toggle)", NULL, packet_list_mark_frame_cb, 0, NULL, NULL),
427     ITEM_FACTORY_ENTRY("/Time Reference", NULL, NULL, 0, "<Branch>", NULL),
428     ITEM_FACTORY_STOCK_ENTRY("/Time Reference/Set Time Reference (toggle)", NULL, reftime_frame_cb, REFTIME_TOGGLE, ETHEREAL_STOCK_TIME),
429     ITEM_FACTORY_ENTRY("/Time Reference/Find Next", NULL, reftime_frame_cb, REFTIME_FIND_NEXT, NULL, NULL),
430     ITEM_FACTORY_ENTRY("/Time Reference/Find Previous", NULL, reftime_frame_cb, REFTIME_FIND_PREV, NULL, NULL),
431
432     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
433
434     ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
435     ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_plist_cb, 
436                        MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
437     ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_plist_cb, 
438                        MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
439     ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_plist_cb, 
440                        MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
441     ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_plist_cb, 
442                        MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
443     ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_plist_cb, 
444                        MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
445     ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_plist_cb,
446                        MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
447
448     ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
449     ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_plist_cb,
450                        MATCH_SELECTED_REPLACE, NULL, NULL),
451     ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_plist_cb,
452                        MATCH_SELECTED_NOT, NULL, NULL),
453     ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_plist_cb,
454                        MATCH_SELECTED_AND, NULL, NULL),
455     ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_plist_cb,
456                        MATCH_SELECTED_OR, NULL, NULL),
457     ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_plist_cb,
458                        MATCH_SELECTED_AND_NOT, NULL, NULL),
459     ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_plist_cb,
460                        MATCH_SELECTED_OR_NOT, NULL, NULL),
461
462     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
463                        0, NULL, NULL),
464     ITEM_FACTORY_ENTRY("/Follow SSL Stream", NULL, ssl_stream_cb,
465                        0, NULL, NULL),
466
467     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
468
469     ITEM_FACTORY_STOCK_ENTRY("/Decode As...", NULL, decode_as_cb, 0, ETHEREAL_STOCK_DECODE_AS),
470     ITEM_FACTORY_STOCK_ENTRY("/Print...", NULL, file_print_selected_cmd_cb, 0, GTK_STOCK_PRINT),
471     ITEM_FACTORY_ENTRY("/Show Packet in New Window", NULL, new_window_cb,
472                        0, NULL, NULL)
473 };
474
475 static GtkItemFactoryEntry tree_view_menu_items[] =
476 {
477     ITEM_FACTORY_ENTRY("/Expand Subtrees", NULL, expand_tree_cb, 0, NULL, NULL),
478     ITEM_FACTORY_ENTRY("/Expand All", NULL, expand_all_cb, 0, NULL, NULL),
479     ITEM_FACTORY_ENTRY("/Collapse All", NULL, collapse_all_cb, 0, NULL, NULL),
480
481     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
482
483     ITEM_FACTORY_ENTRY("/Apply as Filter", NULL, NULL, 0, "<Branch>", NULL),
484     ITEM_FACTORY_ENTRY("/Apply as Filter/_Selected", NULL, match_selected_ptree_cb, 
485                        MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
486     ITEM_FACTORY_ENTRY("/Apply as Filter/_Not Selected", NULL, match_selected_ptree_cb,
487                        MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
488     ITEM_FACTORY_ENTRY("/Apply as Filter/... _and Selected", NULL, match_selected_ptree_cb,
489                        MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
490     ITEM_FACTORY_ENTRY("/Apply as Filter/... _or Selected", NULL, match_selected_ptree_cb,
491                        MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
492     ITEM_FACTORY_ENTRY("/Apply as Filter/... a_nd not Selected", NULL, match_selected_ptree_cb, 
493                        MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
494     ITEM_FACTORY_ENTRY("/Apply as Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
495                        MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW, NULL, NULL),
496
497     ITEM_FACTORY_ENTRY("/Prepare a Filter", NULL, NULL, 0, "<Branch>", NULL),
498     ITEM_FACTORY_ENTRY("/Prepare a Filter/_Selected", NULL, match_selected_ptree_cb, 
499                        MATCH_SELECTED_REPLACE, NULL, NULL),
500     ITEM_FACTORY_ENTRY("/Prepare a Filter/_Not Selected", NULL, match_selected_ptree_cb,
501                        MATCH_SELECTED_NOT, NULL, NULL),
502     ITEM_FACTORY_ENTRY("/Prepare a Filter/... _and Selected", NULL, match_selected_ptree_cb,
503                        MATCH_SELECTED_AND, NULL, NULL),
504     ITEM_FACTORY_ENTRY("/Prepare a Filter/... _or Selected", NULL, match_selected_ptree_cb,
505                        MATCH_SELECTED_OR, NULL, NULL),
506     ITEM_FACTORY_ENTRY("/Prepare a Filter/... a_nd not Selected", NULL, match_selected_ptree_cb, 
507                        MATCH_SELECTED_AND_NOT, NULL, NULL),
508     ITEM_FACTORY_ENTRY("/Prepare a Filter/... o_r not Selected", NULL, match_selected_ptree_cb,
509                        MATCH_SELECTED_OR_NOT, NULL, NULL),
510
511     ITEM_FACTORY_ENTRY("/Follow TCP Stream", NULL, follow_stream_cb,
512                        0, NULL, NULL),
513     ITEM_FACTORY_ENTRY("/Follow SSL Stream", NULL, ssl_stream_cb,
514                        0, NULL, NULL),
515
516     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
517
518     ITEM_FACTORY_STOCK_ENTRY("/Wiki Protocol Page", NULL, selected_ptree_info_cb,
519                        0, ETHEREAL_STOCK_WIKI),
520     ITEM_FACTORY_STOCK_ENTRY("/Filter Field Reference", NULL, selected_ptree_ref_cb,
521                        0, ETHEREAL_STOCK_INTERNET),
522     ITEM_FACTORY_STOCK_ENTRY("/Field Information", NULL, selected_ptree_field_url_cb,
523                        0, ETHEREAL_STOCK_INTERNET),
524     ITEM_FACTORY_ENTRY("/Protocol Preferences...", NULL, properties_cb,
525                        0, NULL, NULL),
526     ITEM_FACTORY_ENTRY("/<separator>", NULL, NULL, 0, "<Separator>", NULL),
527     ITEM_FACTORY_STOCK_ENTRY("/Decode As...", NULL, decode_as_cb, 0, ETHEREAL_STOCK_DECODE_AS),
528     ITEM_FACTORY_ENTRY("/_Resolve Name", NULL, resolve_name_cb, 0, NULL, NULL),
529     ITEM_FACTORY_ENTRY("/_Go to Corresponding Packet", NULL, goto_framenum_cb, 0, NULL, NULL),
530 };
531
532 static GtkItemFactoryEntry hexdump_menu_items[] =
533 {
534     ITEM_FACTORY_ENTRY("/Copy", NULL, copy_hex_cb,
535                        0, NULL, NULL),
536     ITEM_FACTORY_ENTRY("/Export Selected Packet Bytes...", NULL, savehex_cb,
537                        0, NULL, NULL),
538 };
539
540 static int initialize = TRUE;
541 static GtkItemFactory *main_menu_factory = NULL;
542 static GtkItemFactory *packet_list_menu_factory = NULL;
543 static GtkItemFactory *tree_view_menu_factory = NULL;
544 static GtkItemFactory *hexdump_menu_factory = NULL;
545
546 static GSList *popup_menu_list = NULL;
547
548 static GtkAccelGroup *grp;
549
550 GtkWidget *
551 main_menu_new(GtkAccelGroup ** table) {
552   GtkWidget *menubar;
553
554   grp = gtk_accel_group_new();
555
556   if (initialize)
557     menus_init();
558
559   menubar = main_menu_factory->widget;
560
561   if (table)
562     *table = grp;
563
564   return menubar;
565 }
566
567 static void
568 menus_init(void) {
569   if (initialize) {
570     initialize = FALSE;
571
572     /* popup */
573     packet_list_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
574     popup_menu_object = gtk_menu_new();
575     gtk_item_factory_create_items_ac(packet_list_menu_factory, sizeof(packet_list_menu_items)/sizeof(packet_list_menu_items[0]), packet_list_menu_items, popup_menu_object, 2);
576     OBJECT_SET_DATA(popup_menu_object, PM_PACKET_LIST_KEY,
577                     packet_list_menu_factory->widget);
578     popup_menu_list = g_slist_append((GSList *)popup_menu_list, packet_list_menu_factory);
579
580     tree_view_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
581     gtk_item_factory_create_items_ac(tree_view_menu_factory, sizeof(tree_view_menu_items)/sizeof(tree_view_menu_items[0]), tree_view_menu_items, popup_menu_object, 2);
582     OBJECT_SET_DATA(popup_menu_object, PM_TREE_VIEW_KEY,
583                     tree_view_menu_factory->widget);
584     popup_menu_list = g_slist_append((GSList *)popup_menu_list, tree_view_menu_factory);
585
586     hexdump_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<main>", NULL);
587     gtk_item_factory_create_items_ac(hexdump_menu_factory, sizeof(hexdump_menu_items)/sizeof(hexdump_menu_items[0]), hexdump_menu_items, popup_menu_object, 2);
588     OBJECT_SET_DATA(popup_menu_object, PM_HEXDUMP_KEY,
589                     hexdump_menu_factory->widget);
590     popup_menu_list = g_slist_append((GSList *)popup_menu_list, hexdump_menu_factory);
591
592     /* main */
593     main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
594     gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
595
596     merge_all_tap_menus(tap_menu_tree_root);
597
598     /* Initialize enabled/disabled state of menu items */
599     set_menus_for_unsaved_capture_file(FALSE);
600     set_menus_for_capture_file(FALSE);
601 #if 0
602     /* Un-#if this when we actually implement Cut/Copy/Paste.
603        Then make sure you enable them when they can be done. */
604     set_menu_sensitivity(main_menu_factory, "/Edit/Cut", FALSE);
605     set_menu_sensitivity(main_menu_factory, "/Edit/Copy", FALSE);
606     set_menu_sensitivity(main_menu_factory, "/Edit/Paste", FALSE);
607 #endif
608
609     set_menus_for_captured_packets(FALSE);
610     set_menus_for_selected_packet(&cfile);
611     set_menus_for_selected_tree_row(&cfile);
612     set_menus_for_capture_in_progress(FALSE);
613         set_menus_for_file_set(/* dialog */TRUE, /* previous file */ FALSE, /* next_file */ FALSE);
614
615     /* init with an empty recent files list */
616     clear_menu_recent_capture_file_cmd_cb(NULL, NULL);
617   }
618 }
619
620
621 static gint tap_menu_item_add_compare(gconstpointer a, gconstpointer b)
622 {
623     return strcmp(
624         ((const menu_item_t *) a)->name, 
625         ((const menu_item_t *) b)->name);
626 }
627
628
629 /* add a menuitem below the current node */
630 static GList * tap_menu_item_add(
631     char *name, 
632     gint group, 
633     GtkItemFactoryCallback callback,
634     gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
635     gboolean (*selected_tree_row_enabled)(field_info *),
636     gpointer callback_data,
637         GList *curnode)
638 {
639     menu_item_t *curr;
640     menu_item_t *child;
641
642
643     child = g_malloc(sizeof (menu_item_t));
644     child->group            = group;
645     child->name             = name;
646     child->callback         = callback;
647     child->selected_packet_enabled = selected_packet_enabled;
648     child->selected_tree_row_enabled = selected_tree_row_enabled;
649     child->callback_data    = callback_data;
650     child->enabled          = FALSE;
651     child->children         = NULL;
652
653     /* insert the new child node into the parent */
654     curr = curnode->data;
655     curr->children = g_list_insert_sorted(curr->children, child, tap_menu_item_add_compare);
656
657     /* return the new node */
658     /* XXX: improve this */
659     return g_list_find(curr->children, child);
660 }
661
662 /*
663  * Add a new menu item for a tap.
664  * This must be called after we've created the main menu, so it can't
665  * be called from the routine that registers taps - we have to introduce
666  * another per-tap registration routine.
667  *
668  * "callback" gets called when the menu item is selected; it should do
669  * the work of creating the tap window.
670  *
671  * "selected_packet_enabled" gets called by "set_menus_for_selected_packet()";
672  * it's passed a Boolean that's TRUE if a packet is selected and FALSE
673  * otherwise, and should return TRUE if the tap will work now (which
674  * might depend on whether a packet is selected and, if one is, on the
675  * packet) and FALSE if not.
676  *
677  * "selected_tree_row_enabled" gets called by
678  * "set_menus_for_selected_tree_row()"; it's passed a Boolean that's TRUE if
679  * a protocol tree row is selected and FALSE otherwise, and should return
680  * TRUE if the tap will work now (which might depend on whether a tree row
681  * is selected and, if one is, on the tree row) and FALSE if not.
682  */
683 void
684 register_stat_menu_item(
685     const char *name, 
686     REGISTER_STAT_GROUP_E group,
687     GtkItemFactoryCallback callback,
688     gboolean (*selected_packet_enabled)(frame_data *, epan_dissect_t *),
689     gboolean (*selected_tree_row_enabled)(field_info *),
690     gpointer callback_data)
691 {
692     /*static const char toolspath[] = "/Statistics/";*/
693     const char *toolspath;
694     const char *p;
695     char *menupath;
696     size_t menupathlen;
697     menu_item_t *child;
698     GList *curnode;
699     GList *childnode;
700
701     /*
702      * The menu path must be relative.
703      */
704     g_assert(*name != '/');
705
706     switch(group) {
707     case(REGISTER_STAT_GROUP_GENERIC): toolspath = "/Statistics/"; break;
708     case(REGISTER_STAT_GROUP_CONVERSATION_LIST): toolspath = "/Statistics/_Conversation List/"; break;
709     case(REGISTER_STAT_GROUP_ENDPOINT_LIST): toolspath = "/Statistics/_Endpoint List/"; break;
710     case(REGISTER_STAT_GROUP_RESPONSE_TIME): toolspath = "/Statistics/Service _Response Time/"; break;
711     case(REGISTER_STAT_GROUP_TELEPHONY): toolspath = "/Statistics/"; break;
712     case(REGISTER_STAT_GROUP_NONE): toolspath = "/Statistics/"; break;
713     case(REGISTER_ANALYZE_GROUP_NONE): toolspath = "/Analyze/"; break;
714     default:
715         g_assert(0);
716         toolspath = NULL;
717     }
718
719     /* add the (empty) root node, if not already done */
720     if(tap_menu_tree_root == NULL) {
721         child = g_malloc0(sizeof (menu_item_t));
722         tap_menu_tree_root = g_list_append(NULL, child);
723     }
724
725     /*
726      * Create any submenus required.
727      */
728     curnode = tap_menu_tree_root;
729     p = name;
730     while ((p = strchr(p, '/')) != NULL) {
731         /*
732          * OK, everything between "name" and "p" is
733          * a menu relative subtree into which the menu item
734          * will be placed.
735          *
736          * Construct the absolute path name of that subtree.
737          */
738         menupathlen = strlen(toolspath) + 1 + (p - name);
739         menupath = g_malloc(menupathlen);
740         strcpy(menupath, toolspath);
741         strncat(menupath, name, p - name);
742
743         /*
744          * Does there exist an entry with that path at this
745          * level of the Analyze menu tree?
746          */
747         child = curnode->data;
748         for (childnode = child->children; childnode != NULL; childnode = childnode->next) {
749             child = childnode->data;
750             if (strcmp(child->name, menupath) == 0)
751                 break;
752         }
753         if (childnode == NULL) {
754             /*
755              * No.  Create such an item as a subtree, and
756              * add it to the Tools menu tree.
757              */
758             childnode = tap_menu_item_add(
759                 menupath, group, NULL, NULL ,NULL, NULL, curnode);
760         } else {
761             /*
762              * Yes.  We don't need this "menupath" any longer.
763              */
764             g_free(menupath);
765         }
766         curnode = childnode;
767
768         /*
769          * Skip over the '/' we found.
770          */
771         p++;
772     }
773
774     /*
775      * Construct the main menu path for the menu item.
776      */
777     menupathlen = strlen(toolspath) + 1 + strlen(name);
778     menupath = g_malloc(menupathlen);
779     strcpy(menupath, toolspath);
780     strcat(menupath, name);
781
782     /*
783      * Construct an item factory entry for the item, and add it to
784      * the main menu.
785      */
786     tap_menu_item_add(
787         menupath, group, callback, 
788         selected_packet_enabled, selected_tree_row_enabled, 
789         callback_data, curnode);
790 }
791
792
793 static guint merge_tap_menus_layered(GList *node, gint group) {
794     GtkItemFactoryEntry *entry;
795     GList       *child;
796     guint       added = 0;
797     menu_item_t *node_data = node->data;
798
799     /*
800      * Is this a leaf node or an interior node?
801      */
802     if (node_data->children == NULL) {
803         /*
804          * It's a leaf node.
805          */
806
807         /*
808          * The root node doesn't correspond to a menu tree item; it
809          * has a null name pointer.
810          */
811         if (node_data->name != NULL && group == node_data->group) {
812             entry = g_malloc0(sizeof (GtkItemFactoryEntry));
813             entry->path = node_data->name;
814             entry->callback = node_data->callback;
815 #if GTK_MAJOR_VERSION >= 2
816             switch(group) {
817             case(REGISTER_STAT_GROUP_NONE):
818                 break;
819             case(REGISTER_STAT_GROUP_GENERIC):
820                 break;
821             case(REGISTER_STAT_GROUP_CONVERSATION_LIST):
822                 entry->item_type = "<StockItem>";
823                 entry->extra_data = ETHEREAL_STOCK_CONVERSATIONS;
824                 break;
825             case(REGISTER_STAT_GROUP_ENDPOINT_LIST):
826                 entry->item_type = "<StockItem>";
827                 entry->extra_data = ETHEREAL_STOCK_ENDPOINTS;
828                 break;
829             case(REGISTER_STAT_GROUP_RESPONSE_TIME):
830                 entry->item_type = "<StockItem>";
831                 entry->extra_data = ETHEREAL_STOCK_TIME;
832                 break;
833             case(REGISTER_STAT_GROUP_TELEPHONY):
834                 entry->item_type = "<StockItem>";
835                 entry->extra_data = ETHEREAL_STOCK_TELEPHONY;
836                 break;
837             case(REGISTER_ANALYZE_GROUP_NONE):
838                 break;
839             default:
840                 g_assert_not_reached();
841             }
842 #endif
843             gtk_item_factory_create_item(main_menu_factory, entry, node_data->callback_data, 2);
844             set_menu_sensitivity(main_menu_factory, node_data->name, FALSE); /* no capture file yet */
845             added++;
846         }
847     } else {
848         /*
849          * It's an interior node; call
850          * "merge_tap_menus_layered()" on all its children 
851          */
852
853         /*
854          * The root node doesn't correspond to a menu tree item; it
855          * has a null name pointer.
856          */
857         if (node_data->name != NULL && group == node_data->group) {
858             entry = g_malloc0(sizeof (GtkItemFactoryEntry));
859             entry->path = node_data->name;
860             entry->item_type = "<Branch>";
861             gtk_item_factory_create_item(main_menu_factory, entry,
862                 NULL, 2);
863             set_menu_sensitivity(main_menu_factory, node_data->name,
864                 FALSE);    /* no children yet */
865             added++;
866         }
867
868         for (child = node_data->children; child != NULL; child =
869             child->next) {
870             added += merge_tap_menus_layered(child, group);
871         }
872     }
873
874     return added;
875 }
876
877
878 void merge_all_tap_menus(GList *node) {
879     GtkItemFactoryEntry *entry;
880
881     entry = g_malloc0(sizeof (GtkItemFactoryEntry));
882     entry->item_type = "<Separator>";
883     entry->path = "/Statistics/";
884
885     /* 
886      * merge only the menu items of the specific group,
887      * and then append a seperator
888      */
889     if (merge_tap_menus_layered(node, REGISTER_STAT_GROUP_GENERIC)) {
890         gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
891     }
892     if (merge_tap_menus_layered(node, REGISTER_STAT_GROUP_CONVERSATION_LIST)) {
893         /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
894     }
895     if (merge_tap_menus_layered(node, REGISTER_STAT_GROUP_ENDPOINT_LIST)) {
896         /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
897     }
898     if (merge_tap_menus_layered(node, REGISTER_STAT_GROUP_RESPONSE_TIME)) {
899         gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
900     }
901     if (merge_tap_menus_layered(node, REGISTER_STAT_GROUP_TELEPHONY)) {
902         gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);
903     }
904     if (merge_tap_menus_layered(node, REGISTER_STAT_GROUP_NONE)) {
905         /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
906     }
907     if (merge_tap_menus_layered(node, REGISTER_ANALYZE_GROUP_NONE)) {
908                 entry->path = "/Analyze/";
909         /*gtk_item_factory_create_item(main_menu_factory, entry, NULL, 2);*/
910     }
911 }
912
913
914
915 /*
916  * Enable/disable menu sensitivity.
917  */
918 static void
919 set_menu_sensitivity(GtkItemFactory *ifactory, const gchar *path, gint val)
920 {
921   GSList *menu_list;
922   GtkWidget *menu_item;
923   gchar *dup;
924   gchar *dest;
925
926
927   /* the underscore character regularly confuses things, as it will prevent finding 
928    * the menu_item, so it has to be removed first */
929   dup = g_strdup(path);
930   dest = dup;
931   while(*path) {
932       if (*path != '_') {
933         *dest = *path;
934         dest++;
935       }
936       path++;
937   }
938   *dest = '\0';
939
940   if (ifactory == NULL) {
941     /*
942      * Do it for all pop-up menus.
943      */
944     for (menu_list = popup_menu_list; menu_list != NULL;
945          menu_list = g_slist_next(menu_list))
946       set_menu_sensitivity(menu_list->data, dup, val);
947   } else {
948     /*
949      * Do it for that particular menu.
950      */
951     if ((menu_item = gtk_item_factory_get_widget(ifactory, dup)) != NULL) {
952       if (GTK_IS_MENU(menu_item)) {
953         /*
954          * "dup" refers to a submenu; "gtk_item_factory_get_widget()"
955          * gets the menu, not the item that, when selected, pops up
956          * the submenu.
957          *
958          * We have to change the latter item's sensitivity, so that
959          * it shows up normally if sensitive and grayed-out if
960          * insensitive.
961          */
962         menu_item = gtk_menu_get_attach_widget(GTK_MENU(menu_item));
963       }
964       gtk_widget_set_sensitive(menu_item, val);
965     } else{
966       /* be sure this menu item *is* existing */
967       g_assert_not_reached();
968     }
969   }
970
971   g_free(dup);
972 }
973
974 static void
975 set_menu_object_data_meat(GtkItemFactory *ifactory, const gchar *path, const gchar *key, gpointer data)
976 {
977         GtkWidget *menu = NULL;
978
979         if ((menu = gtk_item_factory_get_widget(ifactory, path)) != NULL)
980                 OBJECT_SET_DATA(menu, key, data);
981 }
982
983 void
984 set_menu_object_data (const gchar *path, const gchar *key, gpointer data) {
985   GSList *menu_list = popup_menu_list;
986   gchar *shortpath = strrchr(path, '/');
987
988   set_menu_object_data_meat(main_menu_factory, path, key, data);
989   while (menu_list != NULL) {
990         set_menu_object_data_meat(menu_list->data, shortpath, key, data);
991         menu_list = g_slist_next(menu_list);
992   }
993 }
994
995
996 /* Recently used capture files submenu: 
997  * Submenu containing the recently used capture files.
998  * The capture filenames are always kept with the absolute path, to be independant
999  * of the current path. 
1000  * They are only stored inside the labels of the submenu (no separate list). */
1001
1002 #define MENU_RECENT_FILES_PATH "/File/Open Recent"
1003 #define MENU_RECENT_FILES_KEY "Recent File Name"
1004
1005 static void
1006 update_menu_recent_capture_file1(GtkWidget *widget, gpointer cnt) {
1007     gchar *widget_cf_name;
1008
1009     widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
1010
1011     /* if this menu item is a file, count it */
1012     if (widget_cf_name) {
1013         (*(guint *)cnt)++;
1014     }
1015 }
1016
1017
1018 /* update the menu */
1019 static void
1020 update_menu_recent_capture_file(GtkWidget *submenu_recent_files) {
1021     guint cnt = 0;
1022
1023     gtk_container_foreach(GTK_CONTAINER(submenu_recent_files), 
1024                 update_menu_recent_capture_file1, &cnt);
1025
1026     /* make parent menu item sensitive only, if we have any valid files in the list */
1027     set_menu_sensitivity(main_menu_factory, MENU_RECENT_FILES_PATH, cnt);
1028 }
1029
1030
1031 /* remove the capture filename from the "Recent Files" menu */
1032 static void
1033 remove_menu_recent_capture_file(GtkWidget *widget, gpointer unused _U_) {
1034     GtkWidget *submenu_recent_files;
1035     gchar *widget_cf_name;
1036
1037
1038     widget_cf_name = OBJECT_GET_DATA(widget, MENU_RECENT_FILES_KEY);
1039     g_free(widget_cf_name);
1040
1041     /* get the submenu container item */
1042     submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1043
1044     /* XXX: is this all we need to do, to free the menu item and its label?
1045        The reference count of widget will go to 0, so it'll be freed;
1046        will that free the label? */
1047     gtk_container_remove(GTK_CONTAINER(submenu_recent_files), widget);
1048 }
1049
1050
1051 /* callback, if the user pushed the <Clear File List> item */
1052 static void
1053 clear_menu_recent_capture_file_cmd_cb(GtkWidget *w _U_, gpointer unused _U_) {
1054     GtkWidget *submenu_recent_files;
1055
1056
1057     submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1058
1059     gtk_container_foreach(GTK_CONTAINER(submenu_recent_files), 
1060                 remove_menu_recent_capture_file, NULL);
1061
1062     update_menu_recent_capture_file(submenu_recent_files);
1063 }
1064
1065
1066 /* callback, if the user pushed a recent file submenu item */
1067 void
1068 menu_open_recent_file_cmd(GtkWidget *w)
1069 {
1070         GtkWidget *submenu_recent_files;
1071         GtkWidget *menu_item_child;
1072         gchar     *cf_name;
1073         int       err;
1074
1075         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1076
1077         /* get capture filename from the menu item label */
1078         menu_item_child = (GTK_BIN(w))->child;
1079         gtk_label_get(GTK_LABEL(menu_item_child), &cf_name);
1080
1081         /* open and read the capture file (this will close an existing file) */
1082         if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
1083                 cf_read(&cfile);
1084         } else {
1085                 /* the capture file isn't existing any longer, remove menu item */
1086                 /* XXX: ask user to remove item, it's maybe only a temporary problem */
1087                 remove_menu_recent_capture_file(w, NULL);
1088         }
1089
1090         update_menu_recent_capture_file(submenu_recent_files);
1091 }
1092
1093 static void menu_open_recent_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1094 {
1095     switch(btn) {
1096     case(ESD_BTN_YES):
1097         /* save file first */
1098         file_save_as_cmd(after_save_open_recent_file, data);
1099         break;
1100     case(ESD_BTN_NO):
1101         cf_close(&cfile);
1102         menu_open_recent_file_cmd(data);
1103         break;
1104     case(ESD_BTN_CANCEL):
1105         break;
1106     default:
1107         g_assert_not_reached();
1108     }
1109 }
1110
1111 static void
1112 menu_open_recent_file_cmd_cb(GtkWidget *widget, gpointer data _U_) {
1113   gpointer  dialog;
1114
1115
1116   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1117     /* user didn't saved his current file, ask him */
1118     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
1119                 PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1120                 "If you open a new capture file without saving, your current capture data will be discarded.");
1121     simple_dialog_set_cb(dialog, menu_open_recent_file_answered_cb, widget);
1122   } else {
1123     /* unchanged file */
1124     menu_open_recent_file_cmd(widget);
1125   }
1126 }
1127
1128 /* add the capture filename (with an absolute path) to the "Recent Files" menu */
1129 static void
1130 add_menu_recent_capture_file_absolute(gchar *cf_name) {
1131         GtkWidget *submenu_recent_files;
1132         GList *menu_item_list;
1133         GList *li;
1134         gchar *widget_cf_name;
1135         gchar *normalized_cf_name;
1136         GtkWidget *menu_item;
1137         guint cnt;
1138
1139
1140
1141         normalized_cf_name = g_strdup(cf_name);
1142 #ifdef _WIN32
1143         /* replace all slashes by backslashes */
1144         g_strdelimit(normalized_cf_name, "/", '\\');
1145 #endif
1146
1147         /* get the submenu container item */
1148         submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1149
1150         /* convert container to a GList */
1151         menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1152
1153         /* iterate through list items of menu_item_list, 
1154          * removing special items, a maybe duplicate entry and every item above count_max */
1155         cnt = 1;
1156         for (li = g_list_first(menu_item_list); li; li = li->next, cnt++) {
1157                 /* get capture filename */
1158                 menu_item = GTK_WIDGET(li->data);
1159                 widget_cf_name = OBJECT_GET_DATA(menu_item, MENU_RECENT_FILES_KEY);
1160
1161                 /* if this element string is one of our special items (seperator, ...) or
1162                  * already in the list or 
1163                  * this element is above maximum count (too old), remove it */
1164                 if (!widget_cf_name ||
1165 #ifdef _WIN32
1166                     /* do a case insensitive compare on win32 */
1167 #if GLIB_MAJOR_VERSION < 2
1168                     g_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1169 #else
1170                     g_ascii_strncasecmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1171 #endif
1172 #else   /* _WIN32 */
1173                     /* do a case sensitive compare on unix */
1174                     strncmp(widget_cf_name, normalized_cf_name, 1000) == 0 ||
1175 #endif
1176                     cnt >= prefs.gui_recent_files_count_max) {
1177                         remove_menu_recent_capture_file(li->data, NULL);
1178                         cnt--;
1179                 }
1180         }
1181
1182         g_list_free(menu_item_list);
1183
1184         /* add new item at latest position */
1185         menu_item = gtk_menu_item_new_with_label(normalized_cf_name);
1186         OBJECT_SET_DATA(menu_item, MENU_RECENT_FILES_KEY, normalized_cf_name);
1187         gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item);
1188         SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate", 
1189                 menu_open_recent_file_cmd_cb, (GtkObject *) menu_item);
1190         gtk_widget_show (menu_item);
1191
1192         /* add seperator at last position */
1193         menu_item = gtk_menu_item_new();
1194         gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1195         gtk_widget_show (menu_item);
1196
1197         /* add new "clear list" item at last position */
1198 #if GTK_MAJOR_VERSION < 2
1199         menu_item = gtk_menu_item_new_with_label("<Clear File List>");
1200 #else
1201         menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
1202 #endif
1203         gtk_menu_append (GTK_MENU(submenu_recent_files), menu_item);
1204         SIGNAL_CONNECT_OBJECT(GTK_OBJECT(menu_item), "activate", 
1205                 clear_menu_recent_capture_file_cmd_cb, (GtkObject *) menu_item);
1206         gtk_widget_show (menu_item);
1207
1208         update_menu_recent_capture_file(submenu_recent_files);
1209 }
1210
1211
1212 /* add the capture filename to the "Recent Files" menu */
1213 /* (will change nothing, if this filename is already in the menu) */
1214 void
1215 add_menu_recent_capture_file(gchar *cf_name) {
1216         gchar *curr;
1217         gchar *absolute;
1218         
1219         
1220         /* if this filename is an absolute path, we can use it directly */
1221         if (g_path_is_absolute(cf_name)) {
1222                 add_menu_recent_capture_file_absolute(cf_name);
1223                 return;
1224         }
1225
1226         /* this filename is not an absolute path, prepend the current dir */
1227         curr = g_get_current_dir();
1228         absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name);
1229         add_menu_recent_capture_file_absolute(absolute);
1230         g_free(curr);
1231         g_free(absolute);
1232 }
1233
1234
1235 /* write all capture filenames of the menu to the user's recent file */
1236 void
1237 menu_recent_file_write_all(FILE *rf) {
1238     GtkWidget   *submenu_recent_files;
1239     GList       *children;
1240     GList       *child;
1241     gchar       *cf_name;
1242
1243
1244     submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH);
1245
1246     /* we have to iterate backwards through the children's list,
1247      * so we get the latest item last in the file.
1248      * (don't use gtk_container_foreach() here, it will return the wrong iteration order) */
1249     children = gtk_container_children(GTK_CONTAINER(submenu_recent_files));
1250     child = g_list_last(children);
1251     while(child != NULL) {
1252         /* get capture filename from the menu item label */
1253         cf_name = OBJECT_GET_DATA(child->data, MENU_RECENT_FILES_KEY);
1254         if (cf_name) {
1255             fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name);
1256         }
1257
1258         child = g_list_previous(child);
1259     }
1260
1261     g_list_free(children);
1262 }
1263
1264
1265 static void
1266 main_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1267 {
1268
1269     /* save current setting in recent */
1270     recent.main_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1271
1272     main_widgets_show_or_hide();
1273 }
1274
1275
1276 static void
1277 filter_toolbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1278 {
1279
1280     /* save current setting in recent */
1281     recent.filter_toolbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1282
1283     main_widgets_show_or_hide();
1284 }
1285
1286
1287 static void
1288 packet_list_show_cb(GtkWidget *w _U_, gpointer d _U_)
1289 {
1290
1291     /* save current setting in recent */
1292     recent.packet_list_show = GTK_CHECK_MENU_ITEM(w)->active;
1293
1294     main_widgets_show_or_hide();
1295 }
1296
1297
1298 static void
1299 tree_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1300 {
1301
1302     /* save current setting in recent */
1303     recent.tree_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1304
1305     main_widgets_show_or_hide();
1306 }
1307
1308
1309 static void
1310 byte_view_show_cb(GtkWidget *w _U_, gpointer d _U_)
1311 {
1312
1313     /* save current setting in recent */
1314     recent.byte_view_show = GTK_CHECK_MENU_ITEM(w)->active;
1315
1316     main_widgets_show_or_hide();
1317 }
1318
1319
1320 static void
1321 statusbar_show_cb(GtkWidget *w _U_, gpointer d _U_)
1322 {
1323
1324     /* save current setting in recent */
1325     recent.statusbar_show = GTK_CHECK_MENU_ITEM(w)->active;
1326
1327     main_widgets_show_or_hide();
1328 }
1329
1330
1331 static void 
1332 timestamp_absolute_cb(GtkWidget *w _U_, gpointer d _U_)
1333 {
1334     if (recent.gui_time_format != TS_ABSOLUTE) {
1335         timestamp_set_type(TS_ABSOLUTE);
1336         recent.gui_time_format  = TS_ABSOLUTE;
1337         cf_change_time_formats(&cfile);
1338     }
1339 }
1340
1341 static void 
1342 timestamp_absolute_date_cb(GtkWidget *w _U_, gpointer d _U_)
1343 {
1344     if (recent.gui_time_format != TS_ABSOLUTE_WITH_DATE) {
1345         timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
1346         recent.gui_time_format  = TS_ABSOLUTE_WITH_DATE;
1347         cf_change_time_formats(&cfile);
1348     }
1349 }
1350
1351 static void 
1352 timestamp_relative_cb(GtkWidget *w _U_, gpointer d _U_)
1353 {
1354     if (recent.gui_time_format != TS_RELATIVE) {
1355         timestamp_set_type(TS_RELATIVE);
1356         recent.gui_time_format  = TS_RELATIVE;
1357         cf_change_time_formats(&cfile);
1358     }
1359 }
1360
1361 static void 
1362 timestamp_delta_cb(GtkWidget *w _U_, gpointer d _U_)
1363 {
1364     if (recent.gui_time_format != TS_DELTA) {
1365         timestamp_set_type(TS_DELTA);
1366         recent.gui_time_format  = TS_DELTA;
1367         cf_change_time_formats(&cfile);
1368     }
1369 }
1370
1371 static void 
1372 timestamp_auto_cb(GtkWidget *w _U_, gpointer d _U_)
1373 {
1374     if (recent.gui_time_precision != TS_PREC_AUTO) {
1375                 /* the actual precision will be set in cf_change_time_formats() below */
1376         timestamp_set_precision(TS_PREC_AUTO_SEC);
1377         recent.gui_time_precision  = TS_PREC_AUTO;
1378         cf_change_time_formats(&cfile);
1379     }
1380 }
1381
1382 static void 
1383 timestamp_sec_cb(GtkWidget *w _U_, gpointer d _U_)
1384 {
1385     if (recent.gui_time_precision != TS_PREC_FIXED_SEC) {
1386         timestamp_set_precision(TS_PREC_FIXED_SEC);
1387         recent.gui_time_precision  = TS_PREC_FIXED_SEC;
1388         cf_change_time_formats(&cfile);
1389     }
1390 }
1391
1392 static void 
1393 timestamp_dsec_cb(GtkWidget *w _U_, gpointer d _U_)
1394 {
1395     if (recent.gui_time_precision != TS_PREC_FIXED_DSEC) {
1396         timestamp_set_precision(TS_PREC_FIXED_DSEC);
1397         recent.gui_time_precision  = TS_PREC_FIXED_DSEC;
1398         cf_change_time_formats(&cfile);
1399     }
1400 }
1401
1402 static void 
1403 timestamp_csec_cb(GtkWidget *w _U_, gpointer d _U_)
1404 {
1405     if (recent.gui_time_precision != TS_PREC_FIXED_CSEC) {
1406         timestamp_set_precision(TS_PREC_FIXED_CSEC);
1407         recent.gui_time_precision  = TS_PREC_FIXED_CSEC;
1408         cf_change_time_formats(&cfile);
1409     }
1410 }
1411
1412 static void 
1413 timestamp_msec_cb(GtkWidget *w _U_, gpointer d _U_)
1414 {
1415     if (recent.gui_time_precision != TS_PREC_FIXED_MSEC) {
1416         timestamp_set_precision(TS_PREC_FIXED_MSEC);
1417         recent.gui_time_precision  = TS_PREC_FIXED_MSEC;
1418         cf_change_time_formats(&cfile);
1419     }
1420 }
1421
1422 static void 
1423 timestamp_usec_cb(GtkWidget *w _U_, gpointer d _U_)
1424 {
1425     if (recent.gui_time_precision != TS_PREC_FIXED_USEC) {
1426         timestamp_set_precision(TS_PREC_FIXED_USEC);
1427         recent.gui_time_precision  = TS_PREC_FIXED_USEC;
1428         cf_change_time_formats(&cfile);
1429     }
1430 }
1431
1432 static void 
1433 timestamp_nsec_cb(GtkWidget *w _U_, gpointer d _U_)
1434 {
1435     if (recent.gui_time_precision != TS_PREC_FIXED_NSEC) {
1436         timestamp_set_precision(TS_PREC_FIXED_NSEC);
1437         recent.gui_time_precision  = TS_PREC_FIXED_NSEC;
1438         cf_change_time_formats(&cfile);
1439     }
1440 }
1441
1442
1443 void
1444 menu_name_resolution_changed(void)
1445 {
1446     GtkWidget *menu = NULL;
1447
1448     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for MAC Layer");
1449     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_MAC);
1450
1451     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Network Layer");
1452     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_NETWORK);
1453
1454     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Name Resolution/Enable for Transport Layer");
1455     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), g_resolv_flags & RESOLV_TRANSPORT);
1456 }
1457
1458 static void 
1459 name_resolution_mac_cb(GtkWidget *w _U_, gpointer d _U_)
1460 {
1461     if (GTK_CHECK_MENU_ITEM(w)->active) {
1462         g_resolv_flags |= RESOLV_MAC;
1463     } else {
1464         g_resolv_flags &= ~RESOLV_MAC;
1465     }
1466 }
1467
1468 static void 
1469 name_resolution_network_cb(GtkWidget *w _U_, gpointer d _U_)
1470 {
1471     if (GTK_CHECK_MENU_ITEM(w)->active) {
1472         g_resolv_flags |= RESOLV_NETWORK;
1473     } else {
1474         g_resolv_flags &= ~RESOLV_NETWORK;
1475     }
1476 }
1477
1478 static void 
1479 name_resolution_transport_cb(GtkWidget *w _U_, gpointer d _U_)
1480 {
1481     if (GTK_CHECK_MENU_ITEM(w)->active) {
1482         g_resolv_flags |= RESOLV_TRANSPORT;
1483     } else {
1484         g_resolv_flags &= ~RESOLV_TRANSPORT;
1485     }
1486 }
1487
1488 #ifdef HAVE_LIBPCAP
1489 void
1490 menu_auto_scroll_live_changed(gboolean auto_scroll_live_in) {
1491     GtkWidget *menu;
1492
1493
1494     /* tell menu about it */
1495     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Auto Scroll in Live Capture");
1496     if( ((gboolean) GTK_CHECK_MENU_ITEM(menu)->active) != auto_scroll_live_in) {
1497         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), auto_scroll_live_in);
1498     }
1499
1500     /* tell toolbar about it */
1501     toolbar_auto_scroll_live_changed(auto_scroll_live_in);
1502
1503     /* change auto scroll */
1504     if(auto_scroll_live_in != auto_scroll_live) {
1505         auto_scroll_live  = auto_scroll_live_in;
1506     }
1507 }
1508
1509 static void 
1510 auto_scroll_live_cb(GtkWidget *w _U_, gpointer d _U_)
1511 {
1512     menu_auto_scroll_live_changed(GTK_CHECK_MENU_ITEM(w)->active);
1513 }
1514 #endif
1515
1516
1517 void
1518 menu_colorize_changed(gboolean packet_list_colorize) {
1519     GtkWidget *menu;
1520
1521
1522     /* tell menu about it */
1523     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Colorize Packet List");
1524     if( ((gboolean) GTK_CHECK_MENU_ITEM(menu)->active) != packet_list_colorize) {
1525         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), packet_list_colorize);
1526     }
1527
1528     /* tell toolbar about it */
1529     toolbar_colorize_changed(packet_list_colorize);
1530
1531     /* change colorization */
1532     if(packet_list_colorize != recent.packet_list_colorize) {
1533         recent.packet_list_colorize = packet_list_colorize;
1534         color_filters_enable(packet_list_colorize);
1535         cf_colorize_packets(&cfile);
1536     }
1537 }
1538
1539 static void 
1540 colorize_cb(GtkWidget *w, gpointer d _U_)
1541 {
1542     menu_colorize_changed(GTK_CHECK_MENU_ITEM(w)->active);
1543 }
1544
1545
1546 /* the recent file read has finished, update the menu corresponding */
1547 void
1548 menu_recent_read_finished(void) {
1549     GtkWidget *menu = NULL;
1550
1551     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Main Toolbar");
1552     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.main_toolbar_show);
1553
1554     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Filter Toolbar");
1555     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.filter_toolbar_show);
1556
1557     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Statusbar");
1558     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.statusbar_show);
1559
1560     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet List");
1561     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.packet_list_show);
1562
1563     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Details");
1564     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.tree_view_show);
1565
1566     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Packet Bytes");
1567     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.byte_view_show);
1568
1569     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Colorize Packet List");
1570     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), recent.packet_list_colorize);
1571
1572     menu_name_resolution_changed();
1573
1574 #ifdef HAVE_LIBPCAP
1575     menu = gtk_item_factory_get_widget(main_menu_factory, "/View/Auto Scroll in Live Capture");
1576     gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), auto_scroll_live);
1577 #endif
1578
1579     main_widgets_rearrange();
1580
1581     /* don't change the time format, if we had a command line value */
1582     if (timestamp_get_type() != TS_NOT_SET) {
1583         recent.gui_time_format = timestamp_get_type();
1584     }
1585
1586     switch(recent.gui_time_format) {
1587     case(TS_ABSOLUTE_WITH_DATE):
1588         menu = gtk_item_factory_get_widget(main_menu_factory, 
1589             "/View/Time Display Format/Date and Time of Day:   1970-01-01 01:02:03.123456");
1590         /* set_active will not trigger the callback when activating an active item! */
1591         recent.gui_time_format = -1;
1592         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE);
1593         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1594         break;
1595     case(TS_ABSOLUTE):
1596         menu = gtk_item_factory_get_widget(main_menu_factory, 
1597             "/View/Time Display Format/Time of Day:   01:02:03.123456");
1598         /* set_active will not trigger the callback when activating an active item! */
1599         recent.gui_time_format = -1;
1600         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1601         break;
1602     case(TS_RELATIVE):
1603         menu = gtk_item_factory_get_widget(main_menu_factory, 
1604             "/View/Time Display Format/Seconds Since Beginning of Capture:   123.123456");
1605         recent.gui_time_format = -1;
1606         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1607         break;
1608     case(TS_DELTA):
1609         menu = gtk_item_factory_get_widget(main_menu_factory, 
1610             "/View/Time Display Format/Seconds Since Previous Packet:   1.123456");
1611         recent.gui_time_format = -1;
1612         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1613         break;
1614     default:
1615         g_assert_not_reached();
1616     }
1617
1618     switch(recent.gui_time_precision) {
1619     case(TS_PREC_AUTO):
1620         menu = gtk_item_factory_get_widget(main_menu_factory, 
1621             "/View/Time Display Format/Automatic (File Format Precision)");
1622         /* set_active will not trigger the callback when activating an active item! */
1623         recent.gui_time_precision = -1;
1624         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), FALSE);
1625         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1626         break;
1627     case(TS_PREC_FIXED_SEC):
1628         menu = gtk_item_factory_get_widget(main_menu_factory, 
1629             "/View/Time Display Format/Seconds:   0");
1630         recent.gui_time_precision = -1;
1631         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1632         break;
1633     case(TS_PREC_FIXED_DSEC):
1634         menu = gtk_item_factory_get_widget(main_menu_factory, 
1635             "/View/Time Display Format/Deciseconds:   0.1");
1636         recent.gui_time_precision = -1;
1637         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1638         break;
1639     case(TS_PREC_FIXED_CSEC):
1640         menu = gtk_item_factory_get_widget(main_menu_factory, 
1641             "/View/Time Display Format/Centiseconds:   0.12");
1642         recent.gui_time_precision = -1;
1643         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1644         break;
1645     case(TS_PREC_FIXED_MSEC):
1646         menu = gtk_item_factory_get_widget(main_menu_factory, 
1647             "/View/Time Display Format/Milliseconds:   0.123");
1648         recent.gui_time_precision = -1;
1649         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1650         break;
1651     case(TS_PREC_FIXED_USEC):
1652         menu = gtk_item_factory_get_widget(main_menu_factory, 
1653             "/View/Time Display Format/Microseconds:   0.123456");
1654         recent.gui_time_precision = -1;
1655         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1656         break;
1657     case(TS_PREC_FIXED_NSEC):
1658         menu = gtk_item_factory_get_widget(main_menu_factory, 
1659             "/View/Time Display Format/Nanoseconds:   0.123456789");
1660         recent.gui_time_precision = -1;
1661         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu), TRUE);
1662         break;
1663     default:
1664         g_assert_not_reached();
1665     }
1666
1667     menu_colorize_changed(recent.packet_list_colorize);
1668 }
1669
1670
1671 gint
1672 popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
1673 {
1674     GtkWidget *menu = (GtkWidget *)data;
1675     GdkEventButton *event_button = NULL;
1676     gint row, column;
1677
1678     if(widget == NULL || event == NULL || data == NULL) {
1679         return FALSE;
1680     }
1681
1682     /*
1683      * If we ever want to make the menu differ based on what row
1684      * and/or column we're above, we'd use "eth_clist_get_selection_info()"
1685      * to find the row and column number for the coordinates; a CTree is,
1686      * I guess, like a CList with one column(?) and the expander widget
1687      * as a pixmap.
1688      */
1689     /* Check if we are on packet_list object */
1690     if (widget == OBJECT_GET_DATA(popup_menu_object, E_MPACKET_LIST_KEY)) {
1691         if (packet_list_get_event_row_column(widget, (GdkEventButton *)event,
1692                                              &row, &column)) {
1693             OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_ROW_KEY,
1694                             GINT_TO_POINTER(row));
1695             OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_COL_KEY,
1696                             GINT_TO_POINTER(column));
1697             packet_list_set_selected_row(row);
1698         }
1699     }
1700
1701     /* Check if we are on tree_view object */
1702     if (widget == tree_view) {
1703         tree_view_select(widget, (GdkEventButton *) event);
1704     }
1705
1706     /* Check if we are on byte_view object */
1707     if(widget == get_notebook_bv_ptr(byte_nb_ptr)) {
1708         byte_view_select(widget, (GdkEventButton *) event);
1709     }
1710
1711     /* context menu handler (but the byte view notebook pages have their own handler) */
1712     if(event->type == GDK_BUTTON_PRESS && widget != byte_nb_ptr) {
1713         event_button = (GdkEventButton *) event;
1714
1715         /* To qoute the "Gdk Event Structures" doc:
1716          * "Normally button 1 is the left mouse button, 2 is the middle button, and 3 is the right button" */
1717         if(event_button->button == 3) {
1718             gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1719                            event_button->button,
1720                            event_button->time);
1721             SIGNAL_EMIT_STOP_BY_NAME(widget, "button_press_event");
1722             return TRUE;
1723         }
1724     }
1725 #if GTK_MAJOR_VERSION >= 2
1726     /* GDK_2BUTTON_PRESS is a doubleclick -> expand/collapse tree row */
1727     /* GTK version 1 seems to be doing this automatically */
1728     if (widget == tree_view && event->type == GDK_2BUTTON_PRESS) {
1729         GtkTreePath      *path;
1730
1731         if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget),
1732                                           (gint) (((GdkEventButton *)event)->x),
1733                                           (gint) (((GdkEventButton *)event)->y),
1734                                           &path, NULL, NULL, NULL))
1735         {
1736             if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
1737                 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
1738             else
1739                 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget), path,
1740                                          FALSE);
1741             gtk_tree_path_free(path);
1742         }
1743     }
1744 #endif
1745     return FALSE;
1746 }
1747
1748 /* Enable or disable menu items based on whether you have a capture file
1749    you've finished reading. */
1750 void
1751 set_menus_for_capture_file(gboolean have_capture_file)
1752 {
1753   set_menu_sensitivity(main_menu_factory, "/File/Open...", have_capture_file);
1754   set_menu_sensitivity(main_menu_factory, "/File/Open Recent", have_capture_file);
1755   set_menu_sensitivity(main_menu_factory, "/File/Merge...", have_capture_file);
1756   set_menu_sensitivity(main_menu_factory, "/File/Close", have_capture_file);
1757   set_menu_sensitivity(main_menu_factory, "/File/Save As...",
1758       have_capture_file);
1759   set_menu_sensitivity(main_menu_factory, "/File/Export", have_capture_file);
1760   set_menu_sensitivity(main_menu_factory, "/View/Reload", have_capture_file);
1761   set_toolbar_for_capture_file(have_capture_file);
1762   packets_bar_update();
1763 }
1764
1765 /* Enable or disable menu items based on whether you have an unsaved
1766    capture file you've finished reading. */
1767 void
1768 set_menus_for_unsaved_capture_file(gboolean have_unsaved_capture_file)
1769 {
1770   set_menu_sensitivity(main_menu_factory, "/File/Save",
1771       have_unsaved_capture_file);
1772   set_toolbar_for_unsaved_capture_file(have_unsaved_capture_file);
1773 }
1774
1775 /* Enable or disable menu items based on whether there's a capture in
1776    progress. */
1777 void
1778 set_menus_for_capture_in_progress(gboolean capture_in_progress)
1779 {
1780   set_menu_sensitivity(main_menu_factory, "/File/Open...",
1781       !capture_in_progress);
1782   set_menu_sensitivity(main_menu_factory, "/File/Open Recent", 
1783       !capture_in_progress);
1784 #ifdef HAVE_LIBPCAP
1785   set_menu_sensitivity(main_menu_factory, "/Capture/Options...",
1786       !capture_in_progress);
1787   set_menu_sensitivity(main_menu_factory, "/Capture/Start",
1788       !capture_in_progress);
1789   set_menu_sensitivity(main_menu_factory, "/Capture/Stop",
1790       capture_in_progress);
1791   set_menu_sensitivity(main_menu_factory, "/Capture/Restart",
1792       capture_in_progress);
1793   set_toolbar_for_capture_in_progress(capture_in_progress);
1794
1795   set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
1796 #endif /* HAVE_LIBPCAP */
1797 }
1798
1799 /* Enable or disable menu items based on whether you have some captured
1800    packets. */
1801 static gboolean
1802 walk_menu_tree_for_captured_packets(GList *node,
1803     gboolean have_captured_packets)
1804 {
1805         gboolean    is_enabled;
1806         GList       *child;
1807         menu_item_t *node_data = node->data;
1808
1809         /*
1810          * Is this a leaf node or an interior node?
1811          */
1812         if (node_data->children == NULL) {
1813                 /*
1814                  * It's a leaf node.
1815                  *
1816                  * If it has no "selected_packet_enabled()" or
1817                  * "selected_tree_row_enabled()" routines, we enable
1818                  * it.  This allows tap windows to be popped up even
1819                  * if you have no capture file; this is done to let
1820                  * the user pop up multiple tap windows before reading
1821                  * in a capture file, so that they can be processed in
1822                  * parallel while the capture file is being read rather
1823                  * than one at at time as you pop up the windows, and to
1824                  * let the user pop up tap windows before starting an
1825                  * "Update list of packets in real time" capture, so that
1826                  * the statistics can be displayed while the capture is
1827                  * in progress.
1828                  *
1829                  * If it has either of those routines, we disable it for
1830                  * now - as long as, when a capture is first available,
1831                  * we don't get called after a packet or tree row is
1832                  * selected, that's OK.
1833                  * XXX - that should be done better.
1834                  */
1835                 if (node_data->selected_packet_enabled == NULL &&
1836                     node_data->selected_tree_row_enabled == NULL)
1837                         node_data->enabled = TRUE;
1838                 else
1839                         node_data->enabled = FALSE;
1840         } else {
1841                 /*
1842                  * It's an interior node; call
1843                  * "walk_menu_tree_for_captured_packets()" on all its
1844                  * children and, if any of them are enabled, enable
1845                  * this node, otherwise disable it.
1846                  *
1847                  * XXX - should we just leave all interior nodes enabled?
1848                  * Which is a better UI choice?
1849                  */
1850                 is_enabled = FALSE;
1851                 for (child = node_data->children; child != NULL; child =
1852                     child->next) {
1853                         if (walk_menu_tree_for_captured_packets(child,
1854                             have_captured_packets))
1855                                 is_enabled = TRUE;
1856                 }
1857                 node_data->enabled = is_enabled;
1858         }
1859
1860         /*
1861          * The root node doesn't correspond to a menu tree item; it
1862          * has a null name pointer.
1863          */
1864         if (node_data->name != NULL) {
1865                 set_menu_sensitivity(main_menu_factory, node_data->name,
1866                     node_data->enabled);
1867         }
1868         return node_data->enabled;
1869 }
1870
1871 void
1872 set_menus_for_captured_packets(gboolean have_captured_packets)
1873 {
1874   set_menu_sensitivity(main_menu_factory, "/File/Print...",
1875       have_captured_packets);
1876   set_menu_sensitivity(packet_list_menu_factory, "/Print...",
1877       have_captured_packets);
1878   set_menu_sensitivity(main_menu_factory, "/Edit/Find Packet...",
1879       have_captured_packets);
1880   set_menu_sensitivity(main_menu_factory, "/Edit/Find Next",
1881       have_captured_packets);
1882   set_menu_sensitivity(main_menu_factory, "/Edit/Find Previous",
1883       have_captured_packets);
1884   set_menu_sensitivity(main_menu_factory, "/View/Zoom In",
1885       have_captured_packets);
1886   set_menu_sensitivity(main_menu_factory, "/View/Zoom Out",
1887       have_captured_packets);
1888   set_menu_sensitivity(main_menu_factory, "/View/Normal Size",
1889       have_captured_packets);
1890   set_menu_sensitivity(main_menu_factory, "/Go/Go to Packet...",
1891       have_captured_packets);
1892   set_menu_sensitivity(main_menu_factory, "/Go/First Packet",
1893       have_captured_packets);
1894   set_menu_sensitivity(main_menu_factory, "/Go/Last Packet",
1895       have_captured_packets);
1896   set_menu_sensitivity(main_menu_factory, "/Statistics/Summary",
1897       have_captured_packets);
1898   set_menu_sensitivity(main_menu_factory, "/Statistics/Protocol Hierarchy", 
1899       have_captured_packets);
1900       
1901   walk_menu_tree_for_captured_packets(tap_menu_tree_root,
1902       have_captured_packets);
1903   set_toolbar_for_captured_packets(have_captured_packets);
1904   packets_bar_update();
1905 }
1906
1907 /* Enable or disable menu items based on whether a packet is selected and,
1908    if so, on the properties of the packet. */
1909 static gboolean
1910 walk_menu_tree_for_selected_packet(GList *node, frame_data *fd,
1911     epan_dissect_t *edt)
1912 {
1913         gboolean is_enabled;
1914         GList *child;
1915         menu_item_t *node_data = node->data;
1916
1917         /*
1918          * Is this a leaf node or an interior node?
1919          */
1920         if (node_data->children == NULL) {
1921                 /*
1922                  * It's a leaf node.
1923                  *
1924                  * If it has no "selected_packet_enabled()" routine,
1925                  * leave its enabled/disabled status alone - it
1926                  * doesn't depend on whether we have a packet selected
1927                  * or not or on the selected packet.
1928                  *
1929                  * If it has a "selected_packet_enabled()" routine,
1930                  * call it and set the item's enabled/disabled status
1931                  * based on its return value.
1932                  */
1933                 if (node_data->selected_packet_enabled != NULL)
1934                         node_data->enabled = node_data->selected_packet_enabled(fd, edt);
1935         } else {
1936                 /*
1937                  * It's an interior node; call
1938                  * "walk_menu_tree_for_selected_packet()" on all its
1939                  * children and, if any of them are enabled, enable
1940                  * this node, otherwise disable it.
1941                  *
1942                  * XXX - should we just leave all interior nodes enabled?
1943                  * Which is a better UI choice?
1944                  */
1945                 is_enabled = FALSE;
1946                 for (child = node_data->children; child != NULL; child =
1947                     child->next) {
1948                         if (walk_menu_tree_for_selected_packet(child, fd, edt))
1949                                 is_enabled = TRUE;
1950                 }
1951                 node_data->enabled = is_enabled;
1952         }
1953
1954         /*
1955          * The root node doesn't correspond to a menu tree item; it
1956          * has a null name pointer.
1957          */
1958         if (node_data->name != NULL) {
1959                 set_menu_sensitivity(main_menu_factory, node_data->name,
1960                     node_data->enabled);
1961         }
1962         return node_data->enabled;
1963 }
1964
1965 int 
1966 packet_is_ssl(epan_dissect_t* edt)
1967 {
1968   GPtrArray* array;
1969   int ssl_id, is_ssl;
1970   if (!edt || !edt->tree)
1971       return 0;
1972   ssl_id = proto_get_id_by_filter_name("ssl");
1973   if (ssl_id < 0)
1974       return 0;
1975   array = proto_find_finfo(edt->tree, ssl_id);
1976   is_ssl = array->len > 0;
1977   g_ptr_array_free(array, FALSE);
1978   return is_ssl;
1979 }
1980
1981 void
1982 set_menus_for_selected_packet(capture_file *cf)
1983 {
1984   int is_ssl = packet_is_ssl(cf->edt);
1985   set_menu_sensitivity(main_menu_factory, "/Edit/Mark Packet (toggle)",
1986       cf->current_frame != NULL);
1987   set_menu_sensitivity(packet_list_menu_factory, "/Mark Packet (toggle)",
1988       cf->current_frame != NULL);
1989   set_menu_sensitivity(main_menu_factory, "/Edit/Time Reference",
1990       cf->current_frame != NULL);
1991   set_menu_sensitivity(packet_list_menu_factory, "/Time Reference",
1992       cf->current_frame != NULL);
1993   set_menu_sensitivity(main_menu_factory, "/Edit/Mark All Packets",
1994       cf->current_frame != NULL);
1995   set_menu_sensitivity(main_menu_factory, "/Edit/Unmark All Packets",
1996       cf->current_frame != NULL);
1997   set_menu_sensitivity(main_menu_factory, "/View/Resize All Columns",
1998       cf->current_frame != NULL);
1999   set_menu_sensitivity(main_menu_factory, "/View/Collapse All",
2000       cf->current_frame != NULL);
2001   set_menu_sensitivity(tree_view_menu_factory, "/Collapse All",
2002       cf->current_frame != NULL);
2003   set_menu_sensitivity(main_menu_factory, "/View/Expand All",
2004       cf->current_frame != NULL);
2005   set_menu_sensitivity(tree_view_menu_factory, "/Expand All",
2006       cf->current_frame != NULL);
2007   set_menu_sensitivity(main_menu_factory, "/View/Show Packet in New Window",
2008       cf->current_frame != NULL);
2009   set_menu_sensitivity(packet_list_menu_factory, "/Show Packet in New Window",
2010       cf->current_frame != NULL);
2011   set_menu_sensitivity(main_menu_factory, "/Analyze/Follow TCP Stream",
2012       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
2013   set_menu_sensitivity(packet_list_menu_factory, "/Follow TCP Stream",
2014       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
2015   set_menu_sensitivity(tree_view_menu_factory, "/Follow TCP Stream",
2016       cf->current_frame != NULL ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
2017   set_menu_sensitivity(main_menu_factory, "/Analyze/Follow SSL Stream",
2018       cf->current_frame != NULL ? is_ssl : FALSE);
2019   set_menu_sensitivity(packet_list_menu_factory, "/Follow SSL Stream",
2020       cf->current_frame != NULL ? is_ssl : FALSE);
2021   set_menu_sensitivity(tree_view_menu_factory, "/Follow SSL Stream",
2022       cf->current_frame != NULL ? is_ssl : FALSE);
2023   set_menu_sensitivity(main_menu_factory, "/Analyze/Decode As...",
2024       cf->current_frame != NULL && decode_as_ok());
2025   set_menu_sensitivity(packet_list_menu_factory, "/Decode As...",
2026       cf->current_frame != NULL && decode_as_ok());
2027   set_menu_sensitivity(tree_view_menu_factory, "/Decode As...",
2028       cf->current_frame != NULL && decode_as_ok());
2029   set_menu_sensitivity(main_menu_factory, "/View/Name Resolution/Resolve Name",
2030       cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
2031   set_menu_sensitivity(tree_view_menu_factory, "/Resolve Name",
2032       cf->current_frame != NULL && (g_resolv_flags & RESOLV_ALL_ADDRS) != RESOLV_ALL_ADDRS);
2033   set_menu_sensitivity(packet_list_menu_factory, "/Apply as Filter",
2034       cf->current_frame != NULL);
2035   set_menu_sensitivity(packet_list_menu_factory, "/Prepare a Filter",
2036       cf->current_frame != NULL);
2037
2038   walk_menu_tree_for_selected_packet(tap_menu_tree_root, cf->current_frame,
2039       cf->edt);
2040   packets_bar_update();
2041 }
2042
2043 /* Enable or disable menu items based on whether a tree row is selected
2044    and, if so, on the properties of the tree row. */
2045 static gboolean
2046 walk_menu_tree_for_selected_tree_row(GList *node, field_info *fi)
2047 {
2048         gboolean is_enabled;
2049         GList *child;
2050         menu_item_t *node_data = node->data;
2051
2052         /*
2053          * Is this a leaf node or an interior node?
2054          */
2055         if (node_data->children == NULL) {
2056                 /*
2057                  * It's a leaf node.
2058                  *
2059                  * If it has no "selected_tree_row_enabled()" routine,
2060                  * leave its enabled/disabled status alone - it
2061                  * doesn't depend on whether we have a tree row selected
2062                  * or not or on the selected tree row.
2063                  *
2064                  * If it has a "selected_tree_row_enabled()" routine,
2065                  * call it and set the item's enabled/disabled status
2066                  * based on its return value.
2067                  */
2068                 if (node_data->selected_tree_row_enabled != NULL)
2069                         node_data->enabled = node_data->selected_tree_row_enabled(fi);
2070         } else {
2071                 /*
2072                  * It's an interior node; call
2073                  * "walk_menu_tree_for_selected_tree_row()" on all its
2074                  * children and, if any of them are enabled, enable
2075                  * this node, otherwise disable it.
2076                  *
2077                  * XXX - should we just leave all interior nodes enabled?
2078                  * Which is a better UI choice?
2079                  */
2080                 is_enabled = FALSE;
2081                 for (child = node_data->children; child != NULL; child =
2082                     child->next) {
2083                         if (walk_menu_tree_for_selected_tree_row(child, fi))
2084                                 is_enabled = TRUE;
2085                 }
2086                 node_data->enabled = is_enabled;
2087         }
2088
2089         /*
2090          * The root node doesn't correspond to a menu tree item; it
2091          * has a null name pointer.
2092          */
2093         if (node_data->name != NULL) {
2094                 set_menu_sensitivity(main_menu_factory, node_data->name,
2095                     node_data->enabled);
2096         }
2097         return node_data->enabled;
2098 }
2099
2100 void
2101 set_menus_for_selected_tree_row(capture_file *cf)
2102 {
2103   gboolean properties;
2104
2105
2106   set_menu_sensitivity(main_menu_factory, "/File/Export/Selected Packet Bytes...", 
2107       cf->finfo_selected != NULL);  
2108   set_menu_sensitivity(hexdump_menu_factory, "/Copy", 
2109       cf->finfo_selected != NULL);
2110   set_menu_sensitivity(hexdump_menu_factory, "/Export Selected Packet Bytes...", 
2111       cf->finfo_selected != NULL);
2112   
2113   if (cf->finfo_selected != NULL) {
2114         header_field_info *hfinfo = cf->finfo_selected->hfinfo;
2115         if (hfinfo->parent == -1) {
2116           properties = prefs_is_registered_protocol(hfinfo->abbrev);
2117         } else {
2118           properties = prefs_is_registered_protocol(proto_registrar_get_abbrev(hfinfo->parent));
2119         }
2120         set_menu_sensitivity(main_menu_factory,
2121           "/Go/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
2122         set_menu_sensitivity(tree_view_menu_factory,
2123           "/Go to Corresponding Packet", hfinfo->type == FT_FRAMENUM);
2124         set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter",
2125           proto_can_match_selected(cf->finfo_selected, cf->edt));
2126         set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter",
2127           proto_can_match_selected(cf->finfo_selected, cf->edt));
2128         set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter",
2129           proto_can_match_selected(cf->finfo_selected, cf->edt));
2130         set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter",
2131           proto_can_match_selected(cf->finfo_selected, cf->edt));
2132         set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
2133           properties);
2134         set_menu_sensitivity(main_menu_factory, "/View/Expand Subtrees", cf->finfo_selected->tree_type != -1);
2135         set_menu_sensitivity(tree_view_menu_factory, "/Expand Subtrees", cf->finfo_selected->tree_type != -1);
2136         set_menu_sensitivity(tree_view_menu_factory, "/Wiki Protocol Page",
2137           TRUE);
2138         set_menu_sensitivity(tree_view_menu_factory, "/Filter Field Reference",
2139           TRUE);
2140         set_menu_sensitivity(tree_view_menu_factory, "/Field Information",
2141                              selected_ptree_has_field_url());
2142   } else {
2143         set_menu_sensitivity(main_menu_factory,
2144             "/Go/Go to Corresponding Packet", FALSE);
2145         set_menu_sensitivity(tree_view_menu_factory,
2146             "/Go to Corresponding Packet", FALSE);
2147         set_menu_sensitivity(main_menu_factory, "/Analyze/Apply as Filter", FALSE);
2148         set_menu_sensitivity(tree_view_menu_factory, "/Apply as Filter", FALSE);
2149         set_menu_sensitivity(main_menu_factory, "/Analyze/Prepare a Filter", FALSE);
2150         set_menu_sensitivity(tree_view_menu_factory, "/Prepare a Filter", FALSE);
2151         set_menu_sensitivity(tree_view_menu_factory, "/Protocol Preferences...",
2152           FALSE);
2153         set_menu_sensitivity(main_menu_factory, "/View/Expand Subtrees", FALSE);
2154         set_menu_sensitivity(tree_view_menu_factory, "/Expand Subtrees", FALSE);
2155         set_menu_sensitivity(tree_view_menu_factory, "/Wiki Protocol Page",
2156           FALSE);
2157         set_menu_sensitivity(tree_view_menu_factory, "/Filter Field Reference",
2158           FALSE);
2159         set_menu_sensitivity(tree_view_menu_factory, "/Field Information",
2160           FALSE);
2161   }
2162
2163   walk_menu_tree_for_selected_tree_row(tap_menu_tree_root, cf->finfo_selected);
2164 }
2165
2166 void set_menus_for_packet_history(gboolean back_history, gboolean forward_history) {
2167
2168   set_menu_sensitivity(main_menu_factory, "/Go/Back", back_history);
2169   set_menu_sensitivity(main_menu_factory, "/Go/Forward", forward_history);
2170
2171   set_toolbar_for_packet_history(back_history, forward_history);
2172 }
2173
2174
2175 void set_menus_for_file_set(gboolean file_set, gboolean previous_file, gboolean next_file) {
2176
2177   set_menu_sensitivity(main_menu_factory, "/File/File Set/List Files", file_set);
2178   set_menu_sensitivity(main_menu_factory, "/File/File Set/Previous File", previous_file);
2179   set_menu_sensitivity(main_menu_factory, "/File/File Set/Next File", next_file);
2180 }