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