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