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