c0879c8b2f008698b65161cc5c2508cf67862e69
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10  *                              needed by dissect routines
11  * Jeff Foster,    2001/03/12,  added support tabbed hex display windowss
12  *
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <gtk/gtk.h>
34 #include <gdk/gdkkeysyms.h>
35
36 #include <string.h>
37 #include <ctype.h>
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #ifdef NEED_STRERROR_H
44 #include "strerror.h"
45 #endif
46
47 #ifdef NEED_GETOPT_H
48 #include "getopt.h"
49 #endif
50
51 #ifdef _WIN32 /* Needed for console I/O */
52 #include <fcntl.h>
53 #include <conio.h>
54 #endif
55
56 #ifdef HAVE_LIBPORTAUDIO
57 #include <portaudio.h>
58 #endif /* HAVE_LIBPORTAUDIO */
59
60 #include <epan/epan.h>
61 #include <epan/filesystem.h>
62 #include <epan/privileges.h>
63 #include <epan/epan_dissect.h>
64 #include <epan/timestamp.h>
65 #include <epan/packet.h>
66 #include <epan/plugins.h>
67 #include <epan/dfilter/dfilter.h>
68 #include <epan/strutil.h>
69 #include <epan/addr_resolv.h>
70 #include <epan/emem.h>
71 #include <epan/ex-opt.h>
72 #include <epan/funnel.h>
73 #include <epan/expert.h>
74 #include <epan/frequency-utils.h>
75
76 /* general (not GTK specific) */
77 #include "file.h"
78 #include "summary.h"
79 #include "filters.h"
80 #include "disabled_protos.h"
81 #include <epan/prefs.h>
82 #include "filter_dlg.h"
83 #include "layout_prefs.h"
84 #include "color.h"
85 #include "color_filters.h"
86 #include "print.h"
87 #include "simple_dialog.h"
88 #include "register.h"
89 #include <epan/prefs-int.h>
90 #include "ringbuffer.h"
91 #include "../ui_util.h"
92 #include <epan/tap.h>
93 #include <epan/stat_cmd_args.h>
94 #include "util.h"
95 #include "clopts_common.h"
96 #include "cmdarg_err.h"
97 #include "version_info.h"
98 #include "merge.h"
99 #include "u3.h"
100 #include "uat_gui.h"
101 #include "epan/uat.h"
102
103
104 #ifdef HAVE_LIBPCAP
105 #include "capture-pcap-util.h"
106 #include "capture.h"
107 #include "capture_sync.h"
108 #endif
109
110 #ifdef _WIN32
111 #include "capture-wpcap.h"
112 #include "capture_wpcap_packet.h"
113 #include <tchar.h> /* Needed for Unicode */
114 #if GTK_MAJOR_VERSION >= 2
115 #include <commctrl.h>
116 #endif /* GTK_MAJOR_VERSION >= 2 */
117 #endif /* _WIN32 */
118
119 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
120 #include "ethclist.h"
121 #endif
122
123 /* GTK related */
124 #include "statusbar.h"
125 #include "alert_box.h"
126 #if 0
127 #include "dlg_utils.h"
128 #endif
129 #include "file_dlg.h"
130 #include "gtkglobals.h"
131 #include "colors.h"
132 #include "gui_utils.h"
133 #include "compat_macros.h"
134 #include "color_dlg.h"
135
136 #include "main.h"
137 #include "menu.h"
138 #include "../main_window.h"
139 #include "../menu.h"
140 #include "capture_file_dlg.h"
141 #include <epan/column.h>
142 #include "proto_draw.h"
143 #include "keys.h"
144 #include "packet_win.h"
145 #include "toolbar.h"
146 #include "find_dlg.h"
147 #include "packet_list.h"
148 #include "recent.h"
149 #include "follow_tcp.h"
150 #include "font_utils.h"
151 #include "about_dlg.h"
152 #include "help_dlg.h"
153 #include "decode_as_dlg.h"
154 #include "webbrowser.h"
155 #include "capture_dlg.h"
156 #include "capture_ui_utils.h"
157 #include "log.h"
158 #include "../epan/emem.h"
159 #include "file_util.h"
160 #if GTK_MAJOR_VERSION >= 2
161 #ifdef HAVE_LIBPCAP
162 #include "../image/wsicon16.xpm"
163 #include "../image/wsicon32.xpm"
164 #include "../image/wsicon48.xpm"
165 #include "../image/wsicon64.xpm"
166 #include "../image/wsiconcap16.xpm"
167 #include "../image/wsiconcap32.xpm"
168 #include "../image/wsiconcap48.xpm"
169 #endif
170 #endif
171 #ifdef SHOW_WELCOME_PAGE
172 #include "../image/wssplash.xpm"
173 #endif
174
175 #ifdef HAVE_AIRPCAP
176 #include <airpcap.h>
177 #include "airpcap_loader.h"
178 #include "airpcap_dlg.h"
179 #include "airpcap_gui_utils.h"
180
181 #include "./gtk/toolbar.h"
182
183 #include "./image/toolbar/wep_closed_24.xpm"
184 #endif
185
186 #ifdef  HAVE_AIRPDCAP
187 /*      Davide Schiera (2006-11-22): including AirPDcap project                                                 */
188 #include <epan/crypt/airpdcap_ws.h>
189 /* Davide Schiera (2006-11-22) ----------------------------------------------   */
190 #endif
191
192 #ifdef NEED_G_ASCII_STRCASECMP_H
193 #include "../epan/g_ascii_strcasecmp.h"
194 #endif
195
196 /*
197  * Files under personal and global preferences directories in which
198  * GTK settings for Wireshark are stored.
199  */
200 #define RC_FILE "gtkrc"
201
202 #ifdef HAVE_LIBPCAP
203 #define DEF_READY_MESSAGE " Ready to load or capture"
204 #else
205 #define DEF_READY_MESSAGE " Ready to load file"
206 #endif
207
208 capture_file cfile;
209 GtkWidget   *main_display_filter_widget=NULL;
210 GtkWidget   *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
211 GtkWidget   *pkt_scrollw;
212 static GtkWidget   *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
213 static GtkWidget   *main_first_pane, *main_second_pane;
214 static GtkWidget   *status_pane_left, *status_pane_right;
215 static GtkWidget   *menubar, *main_vbox, *main_tb, *stat_hbox, *filter_tb;
216 static GtkWidget   *priv_warning_dialog;
217
218 #ifdef HAVE_AIRPCAP
219 GtkWidget *airpcap_tb;
220 static GtkWidget *driver_warning_dialog;
221 static int    airpcap_dll_ret_val = -1;
222 #endif
223
224 /*
225  * The order below defines the priority of info bar contexts.
226  */
227 typedef enum {
228     STATUS_LEVEL_MAIN,
229     STATUS_LEVEL_FILE,
230     STATUS_LEVEL_FILTER,
231     STATUS_LEVEL_HELP,
232     NUM_STATUS_LEVELS
233 } status_level_e;
234
235 static GtkWidget    *info_bar;
236 static GtkWidget    *packets_bar = NULL;
237 static GtkWidget    *profile_bar = NULL;
238 static GtkWidget    *welcome_pane;
239 static guint        main_ctx, file_ctx, help_ctx, filter_ctx;
240 static guint        status_levels[NUM_STATUS_LEVELS];
241 static guint        packets_ctx;
242 static guint        profile_ctx;
243 static gchar        *packets_str = NULL;
244 static gchar        *profile_str = NULL;
245 GString *comp_info_str, *runtime_info_str;
246 gboolean have_capture_file = FALSE; /* XXX - is there an equivalent in cfile? */
247
248 #ifdef _WIN32
249 static gboolean has_console;    /* TRUE if app has console */
250 static void destroy_console(void);
251 #endif
252 static void console_log_handler(const char *log_domain,
253     GLogLevelFlags log_level, const char *message, gpointer user_data);
254
255 #ifdef HAVE_LIBPCAP
256 static gboolean list_link_layer_types;
257 capture_options global_capture_opts;
258 capture_options *capture_opts = &global_capture_opts;
259 #endif
260
261 gboolean block_toolbar_signals = FALSE;
262
263 static void create_main_window(gint, gint, gint, e_prefs*);
264 static void show_main_window(gboolean);
265 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
266 static void main_save_window_geometry(GtkWidget *widget);
267
268 #define E_DFILTER_CM_KEY          "display_filter_combo"
269 #define E_DFILTER_FL_KEY          "display_filter_list"
270
271 /* Match selected byte pattern */
272 static void
273 match_selected_cb_do(gpointer data, int action, gchar *text)
274 {
275     GtkWidget  *filter_te;
276     char       *cur_filter, *new_filter;
277
278     if ((!text) || (0 == strlen(text))) {
279         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not acquire information to build a filter!\nTry expanding or choosing another item.");
280         return;
281     }
282
283     g_assert(data);
284     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
285     g_assert(filter_te);
286
287     cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
288
289     switch (action&MATCH_SELECTED_MASK) {
290
291     case MATCH_SELECTED_REPLACE:
292         new_filter = g_strdup(text);
293         break;
294
295     case MATCH_SELECTED_AND:
296         if ((!cur_filter) || (0 == strlen(cur_filter)))
297             new_filter = g_strdup(text);
298         else
299             new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
300         break;
301
302     case MATCH_SELECTED_OR:
303         if ((!cur_filter) || (0 == strlen(cur_filter)))
304             new_filter = g_strdup(text);
305         else
306             new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
307         break;
308
309     case MATCH_SELECTED_NOT:
310         new_filter = g_strconcat("!(", text, ")", NULL);
311         break;
312
313     case MATCH_SELECTED_AND_NOT:
314         if ((!cur_filter) || (0 == strlen(cur_filter)))
315             new_filter = g_strconcat("!(", text, ")", NULL);
316         else
317             new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
318         break;
319
320     case MATCH_SELECTED_OR_NOT:
321         if ((!cur_filter) || (0 == strlen(cur_filter)))
322             new_filter = g_strconcat("!(", text, ")", NULL);
323         else
324             new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
325         break;
326
327     default:
328         g_assert_not_reached();
329         new_filter = NULL;
330         break;
331     }
332
333     /* Free up the copy we got of the old filter text. */
334     g_free(cur_filter);
335
336     /* Don't change the current display filter if we only want to copy the filter */
337     if (action&MATCH_SELECTED_COPY_ONLY) {
338         GString *gtk_text_str = g_string_new("");
339         g_string_sprintfa(gtk_text_str, "%s", new_filter);
340         copy_to_clipboard(gtk_text_str);
341         g_string_free(gtk_text_str, TRUE);
342     } else {
343         /* create a new one and set the display filter entry accordingly */
344         gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
345
346         /* Run the display filter so it goes in effect. */
347         if (action&MATCH_SELECTED_APPLY_NOW)
348             main_filter_packets(&cfile, new_filter, FALSE);
349     }
350
351     /* Free up the new filter text. */
352     g_free(new_filter);
353 }
354
355 void
356 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
357 {
358     char *filter = NULL;
359
360     if (cfile.finfo_selected) {
361         filter = proto_construct_match_selected_string(cfile.finfo_selected,
362                                                        cfile.edt);
363         match_selected_cb_do((data ? data : w), action, filter);
364     }
365 }
366
367 void
368 colorize_selected_ptree_cb(GtkWidget *w _U_, gpointer data _U_, guint8 filt_nr)
369 {
370     char *filter = NULL;
371
372     if (cfile.finfo_selected) {
373         filter = proto_construct_match_selected_string(cfile.finfo_selected,
374                                                        cfile.edt);
375         if ((!filter) || (0 == strlen(filter))) {
376             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
377                 "Could not acquire information to build a filter!\n"
378                 "Try expanding or choosing another item.");
379             return;
380         }
381
382         if (filt_nr==0) {
383             color_display_with_filter(filter);
384         } else {
385             if (filt_nr==255) {
386                 color_filters_reset_tmp();
387             } else {
388                 color_filters_set_tmp(filt_nr,filter, FALSE);
389             }
390             cf_colorize_packets(&cfile);
391         }
392     }
393 }
394
395
396 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
397 {
398     gchar *selected_proto_url;
399     gchar *proto_abbrev = data;
400
401
402     switch(btn) {
403     case(ESD_BTN_OK):
404         if (cfile.finfo_selected) {
405             /* open wiki page using the protocol abbreviation */
406             selected_proto_url = g_strdup_printf("http://wiki.wireshark.org/Protocols/%s", proto_abbrev);
407             browser_open_url(selected_proto_url);
408             g_free(selected_proto_url);
409         }
410         break;
411     case(ESD_BTN_CANCEL):
412         break;
413     default:
414         g_assert_not_reached();
415     }
416 }
417
418
419 void
420 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
421 {
422     int field_id;
423     const gchar *proto_abbrev;
424     gpointer  dialog;
425
426
427     if (cfile.finfo_selected) {
428         /* convert selected field to protocol abbreviation */
429         /* XXX - could this conversion be simplified? */
430         field_id = cfile.finfo_selected->hfinfo->id;
431         /* if the selected field isn't a protocol, get it's parent */
432         if(!proto_registrar_is_protocol(field_id)) {
433             field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
434         }
435
436         proto_abbrev = proto_registrar_get_abbrev(field_id);
437
438         /* ask the user if the wiki page really should be opened */
439         dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
440                     PRIMARY_TEXT_START "Open Wireshark Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
441                     "\n"
442                     "This will open the \"%s\" related Wireshark Wiki page in your Web browser.\n"
443                     "\n"
444                     "The Wireshark Wiki is a collaborative approach to provide information\n"
445                     "about Wireshark in several ways (not limited to protocol specifics).\n"
446                     "\n"
447                     "This Wiki is new, so the page of the selected protocol\n"
448                     "may not exist and/or may not contain valuable information.\n"
449                     "\n"
450                     "As everyone can edit the Wiki and add new content (or extend existing),\n"
451                     "you are encouraged to add information if you can.\n"
452                     "\n"
453                     "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
454                     "\n"
455                     "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
456                     "which will save you a lot of editing and will give a consistent look over the pages.",
457                     proto_abbrev, proto_abbrev);
458         simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, (gpointer) proto_abbrev);
459     }
460 }
461
462
463 void
464 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
465 {
466     int field_id;
467     const gchar *proto_abbrev;
468     gchar *selected_proto_url;
469
470
471     if (cfile.finfo_selected) {
472         /* convert selected field to protocol abbreviation */
473         /* XXX - could this conversion be simplified? */
474         field_id = cfile.finfo_selected->hfinfo->id;
475         /* if the selected field isn't a protocol, get it's parent */
476         if(!proto_registrar_is_protocol(field_id)) {
477             field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
478         }
479
480         proto_abbrev = proto_registrar_get_abbrev(field_id);
481
482         /* open reference page using the protocol abbreviation */
483         selected_proto_url = g_strdup_printf("http://www.wireshark.org/docs/dfref/%c/%s.html", proto_abbrev[0], proto_abbrev);
484         browser_open_url(selected_proto_url);
485         g_free(selected_proto_url);
486     }
487 }
488
489 static gchar *
490 get_text_from_packet_list(gpointer data)
491 {
492     gint        row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
493     gint        column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
494     frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
495
496     if(strlen(fdata->col_expr.col_expr[column]) != 0 &&
497        strlen(fdata->col_expr.col_expr_val[column]) != 0)
498             return ep_strdup_printf("%s == %s",
499                                     fdata->col_expr.col_expr[column],
500                                     fdata->col_expr.col_expr_val[column]);
501     else
502             return NULL;
503 }
504
505 void
506 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
507 {
508     match_selected_cb_do(data,
509         action,
510         get_text_from_packet_list(data));
511 }
512
513 /* This function allows users to right click in the details window and copy the text
514  * information to the operating systems clipboard.
515  *
516  * We first check to see if a string representation is setup in the tree and then
517  * read the string. If not available then we try to grab the value. If all else
518  * fails we display a message to the user to indicate the copy could not be completed.
519  */
520 void
521 copy_selected_plist_cb(GtkWidget *w _U_, gpointer data _U_)
522 {
523     GString *gtk_text_str = g_string_new("");
524     char labelstring[256];
525     char *stringpointer = labelstring;
526
527     if (cfile.finfo_selected->rep->representation != 0) {
528         g_string_sprintfa(gtk_text_str, "%s", cfile.finfo_selected->rep->representation);   /* Get the represented data */
529     }
530     if (gtk_text_str->len == 0) {                                                           /* If no representation then... */
531         proto_item_fill_label(cfile.finfo_selected, stringpointer);                         /* Try to read the value */
532         g_string_sprintfa(gtk_text_str, "%s", stringpointer);
533     }
534     if (gtk_text_str->len == 0) {                                                           /* Could not get item so display error msg */
535         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Could not acquire information to copy, try expanding or choosing another item");
536     }
537     else
538     {
539         copy_to_clipboard(gtk_text_str);                     /* Copy string to clipboard */
540     }
541     g_string_free(gtk_text_str, TRUE);                       /* Free the memory */
542 }
543
544
545 /* XXX: use a preference for this setting! */
546 static guint dfilter_combo_max_recent = 10;
547
548 /* add a display filter to the combo box */
549 /* Note: a new filter string will replace an old identical one */
550 static gboolean
551 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
552     GList     *li;
553     GList     *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
554
555
556     /* GtkCombos don't let us get at their list contents easily, so we maintain
557        our own filter list, and feed it to gtk_combo_set_popdown_strings when
558        a new filter is added. */
559     li = g_list_first(dfilter_list);
560     while (li) {
561         /* If the filter is already in the list, remove the old one and
562          * append the new one at the latest position (at g_list_append() below) */
563         if (li->data && strcmp(s, li->data) == 0) {
564             dfilter_list = g_list_remove(dfilter_list, li->data);
565             break;
566         }
567         li = li->next;
568     }
569
570     dfilter_list = g_list_append(dfilter_list, s);
571     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
572     gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), dfilter_list);
573     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(dfilter_list)->data);
574
575     return TRUE;
576 }
577
578
579 /* write all non empty display filters (until maximum count)
580  * of the combo box GList to the user's recent file */
581 void
582 dfilter_recent_combo_write_all(FILE *rf) {
583   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
584   GList     *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
585   GList     *li;
586   guint      max_count = 0;
587
588
589   /* write all non empty display filter strings to the recent file (until max count) */
590   li = g_list_first(dfilter_list);
591   while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
592     if (strlen(li->data)) {
593       fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
594     }
595     li = li->next;
596   }
597 }
598
599 /* empty the combobox entry field */
600 void
601 dfilter_combo_add_empty(void) {
602   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
603
604   gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
605 }
606
607
608 /* add a display filter coming from the user's recent file to the dfilter combo box */
609 gboolean
610 dfilter_combo_add_recent(gchar *s) {
611   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
612   char      *dup;
613
614   dup = g_strdup(s);
615   if (!dfilter_combo_add(filter_cm, dup)) {
616     g_free(dup);
617     return FALSE;
618   }
619
620   return TRUE;
621 }
622
623
624 /* call cf_filter_packets() and add this filter string to the recent filter list */
625 gboolean
626 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
627 {
628   GtkCombo  *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
629   GList     *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
630   GList     *li;
631   gboolean   add_filter = TRUE;
632   gboolean   free_filter = TRUE;
633   char      *s;
634   cf_status_t cf_status;
635
636   s = g_strdup(dftext);
637
638   cf_status = cf_filter_packets(cf, s, force);
639   if (!s)
640     return (cf_status == CF_OK);
641
642   /* GtkCombos don't let us get at their list contents easily, so we maintain
643      our own filter list, and feed it to gtk_combo_set_popdown_strings when
644      a new filter is added. */
645   if (cf_status == CF_OK) {
646     li = g_list_first(dfilter_list);
647     while (li) {
648       if (li->data && strcmp(s, li->data) == 0)
649         add_filter = FALSE;
650       li = li->next;
651     }
652
653     if (add_filter) {
654       /* trim list size first */
655       while (g_list_length(dfilter_list) >= dfilter_combo_max_recent) {
656         dfilter_list = g_list_remove(dfilter_list, g_list_first(dfilter_list)->data);
657       }
658
659       free_filter = FALSE;
660       dfilter_list = g_list_append(dfilter_list, s);
661       OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
662       gtk_combo_set_popdown_strings(filter_cm, dfilter_list);
663       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(dfilter_list)->data);
664     }
665   }
666   if (free_filter)
667     g_free(s);
668
669   return (cf_status == CF_OK);
670 }
671
672
673 /* Run the current display filter on the current packet set, and
674    redisplay. */
675 static void
676 filter_activate_cb(GtkWidget *w _U_, gpointer data)
677 {
678   const char *s;
679
680   s = gtk_entry_get_text(GTK_ENTRY(data));
681
682   main_filter_packets(&cfile, s, FALSE);
683 }
684
685 /* redisplay with no display filter */
686 static void
687 filter_reset_cb(GtkWidget *w, gpointer data _U_)
688 {
689   GtkWidget *filter_te = NULL;
690
691   if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
692     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
693   }
694   main_filter_packets(&cfile, NULL, FALSE);
695 }
696
697 /* mark as reference time frame */
698 static void
699 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
700   if (row == -1)
701     return;
702   if (set) {
703     frame->flags.ref_time=1;
704   } else {
705     frame->flags.ref_time=0;
706   }
707   cf_reftime_packets(&cfile);
708 }
709
710
711 GtkWidget *reftime_dialog = NULL;
712
713 static void reftime_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
714 {
715     switch(btn) {
716     case(ESD_BTN_YES):
717         timestamp_set_type(TS_RELATIVE);
718         recent.gui_time_format  = TS_RELATIVE;
719         cf_change_time_formats(&cfile);
720         break;
721     case(ESD_BTN_NO):
722         break;
723     default:
724         g_assert_not_reached();
725     }
726
727     if (cfile.current_frame) {
728       /* XXX hum, should better have a "cfile->current_row" here ... */
729       set_frame_reftime(!cfile.current_frame->flags.ref_time,
730                      cfile.current_frame,
731                      packet_list_find_row_from_data(cfile.current_frame));
732     }
733 }
734
735
736 void
737 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
738 {
739
740   switch(action){
741   case REFTIME_TOGGLE:
742     if (cfile.current_frame) {
743         if(recent.gui_time_format != TS_RELATIVE && cfile.current_frame->flags.ref_time==0) {
744             reftime_dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO,
745                 PRIMARY_TEXT_START "Switch to the appropriate Time Display Format?" PRIMARY_TEXT_END "\n\n"
746                 "Time References don't work well with the currently selected Time Display Format.\n\n"
747                 "Do you want to switch to \"Seconds Since Beginning of Capture\" now?");
748             simple_dialog_set_cb(reftime_dialog, reftime_answered_cb, NULL);
749         } else {
750             /* XXX hum, should better have a "cfile->current_row" here ... */
751             set_frame_reftime(!cfile.current_frame->flags.ref_time,
752                               cfile.current_frame,
753                               packet_list_find_row_from_data(cfile.current_frame));
754         }
755     }
756     break;
757   case REFTIME_FIND_NEXT:
758     find_previous_next_frame_with_filter("frame.ref_time", FALSE);
759     break;
760   case REFTIME_FIND_PREV:
761     find_previous_next_frame_with_filter("frame.ref_time", TRUE);
762     break;
763   }
764 }
765
766 void
767 find_next_mark_cb(GtkWidget *w _U_, gpointer data _U_, int action _U_)
768 {
769     find_previous_next_frame_with_filter("frame.marked == TRUE", FALSE);
770 }
771
772 void
773 find_prev_mark_cb(GtkWidget *w _U_, gpointer data _U_, int action _U_)
774 {
775     find_previous_next_frame_with_filter("frame.marked == TRUE", TRUE);
776 }
777
778 #if GTK_MAJOR_VERSION < 2
779 static void
780 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
781                         gpointer user_data _U_)
782 #else
783 static void
784 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
785 #endif
786 {
787     field_info   *finfo;
788     gchar        *help_str = NULL;
789     gchar         len_str[2+10+1+5+1]; /* ", {N} bytes\0",
790                                           N < 4294967296 */
791     gboolean      has_blurb = FALSE;
792     guint         length = 0, byte_len;
793     GtkWidget    *byte_view;
794     const guint8 *byte_data;
795     gint          finfo_length;
796 #if GTK_MAJOR_VERSION >= 2
797     GtkTreeModel *model;
798     GtkTreeIter   iter;
799 #endif
800
801 #if GTK_MAJOR_VERSION >= 2
802     /* if nothing is selected */
803     if (!gtk_tree_selection_get_selected(sel, &model, &iter))
804     {
805         /*
806          * Which byte view is displaying the current protocol tree
807          * row's data?
808          */
809         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
810         if (byte_view == NULL)
811             return;     /* none */
812
813         byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
814         if (byte_data == NULL)
815             return;     /* none */
816
817         cf_unselect_field(&cfile);
818         packet_hex_print(byte_view, byte_data,
819                          cfile.current_frame, NULL, byte_len);
820         return;
821     }
822     gtk_tree_model_get(model, &iter, 1, &finfo, -1);
823 #else
824     g_assert(node);
825     finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
826 #endif
827     if (!finfo) return;
828
829     set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
830
831     byte_view = get_notebook_bv_ptr(byte_nb_ptr);
832     byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
833     g_assert(byte_data != NULL);
834
835     cfile.finfo_selected = finfo;
836     set_menus_for_selected_tree_row(&cfile);
837
838     if (finfo->hfinfo) {
839         if (finfo->hfinfo->blurb != NULL &&
840             finfo->hfinfo->blurb[0] != '\0') {
841             has_blurb = TRUE;
842             length = strlen(finfo->hfinfo->blurb);
843         } else {
844             length = strlen(finfo->hfinfo->name);
845         }
846         finfo_length = finfo->length + finfo->appendix_length;
847         if (finfo_length == 0) {
848             len_str[0] = '\0';
849         } else if (finfo_length == 1) {
850             g_strlcpy (len_str, ", 1 byte", sizeof len_str);
851         } else {
852             g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo_length);
853         }
854         statusbar_pop_field_msg();      /* get rid of current help msg */
855         if (length) {
856             help_str = g_strdup_printf(" %s (%s)%s",
857                     (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
858                     finfo->hfinfo->abbrev, len_str);
859             statusbar_push_field_msg(help_str);
860             g_free(help_str);
861         } else {
862             /*
863              * Don't show anything if the field name is zero-length;
864              * the pseudo-field for "proto_tree_add_text()" is such
865              * a field, and we don't want "Text (text)" showing up
866              * on the status line if you've selected such a field.
867              *
868              * XXX - there are zero-length fields for which we *do*
869              * want to show the field name.
870              *
871              * XXX - perhaps the name and abbrev field should be null
872              * pointers rather than null strings for that pseudo-field,
873              * but we'd have to add checks for null pointers in some
874              * places if we did that.
875              *
876              * Or perhaps protocol tree items added with
877              * "proto_tree_add_text()" should have -1 as the field index,
878              * with no pseudo-field being used, but that might also
879              * require special checks for -1 to be added.
880              */
881             statusbar_push_field_msg("");
882         }
883     }
884
885     packet_hex_print(byte_view, byte_data, cfile.current_frame, finfo,
886                      byte_len);
887 }
888
889 #if GTK_MAJOR_VERSION < 2
890 static void
891 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
892                           gpointer user_data _U_)
893 {
894         GtkWidget       *byte_view;
895         const guint8    *data;
896         guint           len;
897
898         /*
899          * Which byte view is displaying the current protocol tree
900          * row's data?
901          */
902         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
903         if (byte_view == NULL)
904                 return; /* none */
905
906         data = get_byte_view_data_and_length(byte_view, &len);
907         if (data == NULL)
908                 return; /* none */
909
910         cf_unselect_field(&cfile);
911         packet_hex_print(byte_view, data, cfile.current_frame, NULL, len);
912 }
913 #endif
914
915 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
916   if (cfile.edt->tree)
917     collapse_all_tree(cfile.edt->tree, tree_view);
918 }
919
920 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
921   if (cfile.edt->tree)
922     expand_all_tree(cfile.edt->tree, tree_view);
923 }
924
925 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
926 #if GTK_MAJOR_VERSION < 2
927   GtkCTreeNode *node;
928 #else
929   GtkTreePath  *path;
930 #endif
931
932 #if GTK_MAJOR_VERSION < 2
933   node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
934   if(node) {
935     /* the mouse position is at an entry, expand that one */
936   gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
937   }
938 #else
939   path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
940   if(path) {
941     /* the mouse position is at an entry, expand that one */
942   gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
943   gtk_tree_path_free(path);
944   }
945 #endif
946 }
947
948 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
949   if (cfile.edt->tree) {
950     guint32 tmp = g_resolv_flags;
951     g_resolv_flags = RESOLV_ALL;
952     proto_tree_draw(cfile.edt->tree, tree_view);
953     g_resolv_flags = tmp;
954   }
955 }
956
957 /*
958  * Push a message referring to file access onto the statusbar.
959  */
960 void
961 statusbar_push_file_msg(const gchar *msg)
962 {
963     int i;
964
965     /*g_warning("statusbar_push: %s", msg);*/
966     for (i = STATUS_LEVEL_FILE + 1; i < NUM_STATUS_LEVELS; i++) {
967         if (status_levels[i])
968             return;
969     }
970     status_levels[STATUS_LEVEL_FILE]++;
971     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
972 }
973
974 /*
975  * Pop a message referring to file access off the statusbar.
976  */
977 void
978 statusbar_pop_file_msg(void)
979 {
980     /*g_warning("statusbar_pop");*/
981     if (status_levels[STATUS_LEVEL_FILE] > 0) {
982         status_levels[STATUS_LEVEL_FILE]--;
983     }
984     gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
985 }
986
987 /*
988  * XXX - do we need multiple statusbar contexts?
989  */
990
991 /*
992  * Push a message referring to the currently-selected field onto the statusbar.
993  */
994 void
995 statusbar_push_field_msg(const gchar *msg)
996 {
997     int i;
998
999     for (i = STATUS_LEVEL_HELP + 1; i < NUM_STATUS_LEVELS; i++) {
1000         if (status_levels[i])
1001             return;
1002     }
1003     status_levels[STATUS_LEVEL_HELP]++;
1004
1005     gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
1006 }
1007
1008 /*
1009  * Pop a message referring to the currently-selected field off the statusbar.
1010  */
1011 void
1012 statusbar_pop_field_msg(void)
1013 {
1014     if (status_levels[STATUS_LEVEL_HELP] > 0) {
1015         status_levels[STATUS_LEVEL_HELP]--;
1016     }
1017     gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
1018 }
1019
1020 /*
1021  * Push a message referring to the current filter onto the statusbar.
1022  */
1023 void
1024 statusbar_push_filter_msg(const gchar *msg)
1025 {
1026     int i;
1027
1028     for (i = STATUS_LEVEL_FILTER + 1; i < NUM_STATUS_LEVELS; i++) {
1029         if (status_levels[i])
1030             return;
1031     }
1032     status_levels[STATUS_LEVEL_FILTER]++;
1033
1034     gtk_statusbar_push(GTK_STATUSBAR(info_bar), filter_ctx, msg);
1035 }
1036
1037 /*
1038  * Pop a message referring to the current filter off the statusbar.
1039  */
1040 void
1041 statusbar_pop_filter_msg(void)
1042 {
1043     if (status_levels[STATUS_LEVEL_FILTER] > 0) {
1044         status_levels[STATUS_LEVEL_FILTER]--;
1045     }
1046     gtk_statusbar_pop(GTK_STATUSBAR(info_bar), filter_ctx);
1047 }
1048
1049 /*
1050  * update the packets statusbar to the current values
1051  */
1052 void packets_bar_update(void)
1053 {
1054
1055     if(packets_bar) {
1056         /* remove old status */
1057         if(packets_str) {
1058             g_free(packets_str);
1059             gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1060         }
1061
1062         /* do we have any packets? */
1063         if(cfile.count) {
1064             if(cfile.drops_known) {
1065                 packets_str = g_strdup_printf(" Packets: %u Displayed: %u Marked: %u Dropped: %u",
1066                     cfile.count, cfile.displayed_count, cfile.marked_count, cfile.drops);
1067             } else {
1068                 packets_str = g_strdup_printf(" Packets: %u Displayed: %u Marked: %u",
1069                     cfile.count, cfile.displayed_count, cfile.marked_count);
1070             }
1071         } else {
1072             packets_str = g_strdup(" No Packets");
1073         }
1074         gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
1075     }
1076 }
1077
1078 /*
1079  * update the packets statusbar to the current values
1080  */
1081 void profile_bar_update(void)
1082 {
1083     if (profile_bar) {
1084         /* remove old status */
1085         if(profile_str) {
1086             g_free(profile_str);
1087             gtk_statusbar_pop(GTK_STATUSBAR(profile_bar), profile_ctx);
1088         }
1089
1090         profile_str = g_strdup_printf (" Profile: %s", get_profile_name ());
1091
1092         gtk_statusbar_push(GTK_STATUSBAR(profile_bar), profile_ctx, profile_str);
1093     }
1094 }
1095
1096 void
1097 main_set_for_capture_file(gboolean have_capture_file_in)
1098 {
1099     have_capture_file = have_capture_file_in;
1100
1101     main_widgets_show_or_hide();
1102 }
1103
1104 gboolean
1105 main_do_quit(void)
1106 {
1107         /* get the current geometry, before writing it to disk */
1108         main_save_window_geometry(top_level);
1109
1110         /* write user's recent file to disk
1111          * It is no problem to write this file, even if we do not quit */
1112         write_recent();
1113
1114         /* XXX - should we check whether the capture file is an
1115            unsaved temporary file for a live capture and, if so,
1116            pop up a "do you want to exit without saving the capture
1117            file?" dialog, and then just return, leaving said dialog
1118            box to forcibly quit if the user clicks "OK"?
1119
1120            If so, note that this should be done in a subroutine that
1121            returns TRUE if we do so, and FALSE otherwise, and if it
1122            returns TRUE we should return TRUE without nuking anything.
1123
1124            Note that, if we do that, we might also want to check if
1125            an "Update list of packets in real time" capture is in
1126            progress and, if so, ask whether they want to terminate
1127            the capture and discard it, and return TRUE, before nuking
1128            any child capture, if they say they don't want to do so. */
1129
1130 #ifdef HAVE_LIBPCAP
1131         /* Nuke any child capture in progress. */
1132         capture_kill_child(capture_opts);
1133 #endif
1134
1135         /* Are we in the middle of reading a capture? */
1136         if (cfile.state == FILE_READ_IN_PROGRESS) {
1137                 /* Yes, so we can't just close the file and quit, as
1138                    that may yank the rug out from under the read in
1139                    progress; instead, just set the state to
1140                    "FILE_READ_ABORTED" and return - the code doing the read
1141                    will check for that and, if it sees that, will clean
1142                    up and quit. */
1143                 cfile.state = FILE_READ_ABORTED;
1144
1145                 /* Say that the window should *not* be deleted;
1146                    that'll be done by the code that cleans up. */
1147                 return TRUE;
1148         } else {
1149                 /* Close any capture file we have open; on some OSes, you
1150                    can't unlink a temporary capture file if you have it
1151                    open.
1152                    "cf_close()" will unlink it after closing it if
1153                    it's a temporary file.
1154
1155                    We do this here, rather than after the main loop returns,
1156                    as, after the main loop returns, the main window may have
1157                    been destroyed (if this is called due to a "destroy"
1158                    even on the main window rather than due to the user
1159                    selecting a menu item), and there may be a crash
1160                    or other problem when "cf_close()" tries to
1161                    clean up stuff in the main window.
1162
1163                    XXX - is there a better place to put this?
1164                    Or should we have a routine that *just* closes the
1165                    capture file, and doesn't do anything with the UI,
1166                    which we'd call here, and another routine that
1167                    calls that routine and also cleans up the UI, which
1168                    we'd call elsewhere? */
1169                 cf_close(&cfile);
1170
1171                 /* Exit by leaving the main loop, so that any quit functions
1172                    we registered get called. */
1173                 gtk_main_quit();
1174
1175                 /* Say that the window should be deleted. */
1176                 return FALSE;
1177         }
1178 }
1179
1180 static gboolean
1181 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1182 {
1183   gpointer dialog;
1184
1185   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1186 #if GTK_MAJOR_VERSION >= 2
1187     gtk_window_present(GTK_WINDOW(top_level));
1188 #endif
1189     /* user didn't saved his current file, ask him */
1190     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1191                 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1192                 "If you quit the program without saving, your capture data will be discarded.");
1193     simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1194     return TRUE;
1195   } else {
1196     /* unchanged file, just exit */
1197     /* "main_do_quit()" indicates whether the main window should be deleted. */
1198     return main_do_quit();
1199   }
1200 }
1201
1202
1203
1204 static void
1205 main_load_window_geometry(GtkWidget *widget)
1206 {
1207     window_geometry_t geom;
1208
1209     geom.set_pos        = prefs.gui_geometry_save_position;
1210     geom.x              = recent.gui_geometry_main_x;
1211     geom.y              = recent.gui_geometry_main_y;
1212     geom.set_size       = prefs.gui_geometry_save_size;
1213     if (recent.gui_geometry_main_width > 0 &&
1214         recent.gui_geometry_main_height > 0) {
1215         geom.width          = recent.gui_geometry_main_width;
1216         geom.height         = recent.gui_geometry_main_height;
1217         geom.set_maximized  = prefs.gui_geometry_save_maximized;
1218     } else {
1219         /* We assume this means the width and height weren't set in
1220            the "recent" file (or that there is no "recent" file),
1221            and weren't set to a default value, so we don't set the
1222            size.  (The "recent" file code rejects non-positive width
1223            and height values.) */
1224        geom.set_size = FALSE;
1225     }
1226     geom.maximized      = recent.gui_geometry_main_maximized;
1227
1228     window_set_geometry(widget, &geom);
1229
1230     if (recent.has_gui_geometry_main_upper_pane && recent.gui_geometry_main_upper_pane)
1231         gtk_paned_set_position(GTK_PANED(main_first_pane), recent.gui_geometry_main_upper_pane);
1232     if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_main_lower_pane)
1233         gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
1234     if (recent.has_gui_geometry_status_pane && recent.gui_geometry_status_pane_left)
1235         gtk_paned_set_position(GTK_PANED(status_pane_left), recent.gui_geometry_status_pane_left);
1236     if (recent.has_gui_geometry_status_pane && recent.gui_geometry_status_pane_right)
1237         gtk_paned_set_position(GTK_PANED(status_pane_right), recent.gui_geometry_status_pane_right);
1238 }
1239
1240
1241 static void
1242 main_save_window_geometry(GtkWidget *widget)
1243 {
1244     window_geometry_t geom;
1245
1246     window_get_geometry(widget, &geom);
1247
1248     if (prefs.gui_geometry_save_position) {
1249         recent.gui_geometry_main_x = geom.x;
1250         recent.gui_geometry_main_y = geom.y;
1251     }
1252
1253     if (prefs.gui_geometry_save_size) {
1254         recent.gui_geometry_main_width  = geom.width;
1255         recent.gui_geometry_main_height = geom.height;
1256     }
1257
1258 #if GTK_MAJOR_VERSION >= 2
1259     if(prefs.gui_geometry_save_maximized) {
1260         recent.gui_geometry_main_maximized = geom.maximized;
1261     }
1262
1263     recent.gui_geometry_main_upper_pane     = gtk_paned_get_position(GTK_PANED(main_first_pane));
1264     recent.gui_geometry_main_lower_pane     = gtk_paned_get_position(GTK_PANED(main_second_pane));
1265     recent.gui_geometry_status_pane_left    = gtk_paned_get_position(GTK_PANED(status_pane_left));
1266     recent.gui_geometry_status_pane_right   = gtk_paned_get_position(GTK_PANED(status_pane_right));
1267 #endif
1268 }
1269
1270 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1271 {
1272     switch(btn) {
1273     case(ESD_BTN_SAVE):
1274         /* save file first */
1275         file_save_as_cmd(after_save_exit, NULL);
1276         break;
1277     case(ESD_BTN_DONT_SAVE):
1278         main_do_quit();
1279         break;
1280     case(ESD_BTN_CANCEL):
1281         break;
1282     default:
1283         g_assert_not_reached();
1284     }
1285 }
1286
1287 void
1288 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1289 {
1290   gpointer dialog;
1291
1292   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1293     /* user didn't saved his current file, ask him */
1294     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1295                 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1296                 "If you quit the program without saving, your capture data will be discarded.");
1297     simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1298   } else {
1299     /* unchanged file, just exit */
1300     main_do_quit();
1301   }
1302 }
1303
1304 static void
1305 print_usage(gboolean print_ver) {
1306
1307   FILE *output;
1308
1309 #ifdef _WIN32
1310   create_console();
1311 #endif
1312
1313   if (print_ver) {
1314     output = stdout;
1315     fprintf(output, "Wireshark " VERSION "%s\n"
1316         "Interactively dump and analyze network traffic.\n"
1317         "See http://www.wireshark.org for more information.\n"
1318         "\n"
1319         "%s",
1320         wireshark_svnversion, get_copyright_info());
1321   } else {
1322     output = stderr;
1323   }
1324   fprintf(output, "\n");
1325   fprintf(output, "Usage: wireshark [options] ... [ <infile> ]\n");
1326   fprintf(output, "\n");
1327
1328 #ifdef HAVE_LIBPCAP
1329   fprintf(output, "Capture interface:\n");
1330   fprintf(output, "  -i <interface>           name or idx of interface (def: first non-loopback)\n");
1331   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
1332   fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
1333   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
1334   fprintf(output, "  -k                       start capturing immediately (def: do nothing)\n");
1335   fprintf(output, "  -Q                       quit Wireshark after capturing\n");
1336   fprintf(output, "  -S                       update packet display when new packets are captured\n");
1337   fprintf(output, "  -l                       turn on automatic scrolling while -S is in use\n");
1338 #ifdef _WIN32
1339   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
1340 #endif
1341   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
1342   fprintf(output, "  -D                       print list of interfaces and exit\n");
1343   fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
1344   fprintf(output, "\n");
1345   fprintf(output, "Capture stop conditions:\n");
1346   fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
1347   fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
1348   fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
1349   fprintf(output, "                              files:NUM - stop after NUM files\n");
1350   /*fprintf(output, "\n");*/
1351   fprintf(output, "Capture output:\n");
1352   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
1353   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
1354   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
1355 #endif  /* HAVE_LIBPCAP */
1356
1357   /*fprintf(output, "\n");*/
1358   fprintf(output, "Input file:\n");
1359   fprintf(output, "  -r <infile>              set the filename to read from (no pipes or stdin!)\n");
1360
1361   fprintf(output, "\n");
1362   fprintf(output, "Processing:\n");
1363   fprintf(output, "  -R <read filter>         packet filter in Wireshark display filter syntax\n");
1364   fprintf(output, "  -n                       disable all name resolutions (def: all enabled)\n");
1365   fprintf(output, "  -N <name resolve flags>  enable specific name resolution(s): \"mntC\"\n");
1366
1367   fprintf(output, "\n");
1368   fprintf(output, "User interface:\n");
1369   fprintf(output, "  -C <config profile>      start with specified configuration profile\n");
1370   fprintf(output, "  -g <packet number>       go to specified packet number after \"-r\"\n");
1371   fprintf(output, "  -m <font>                set the font name used for most text\n");
1372   fprintf(output, "  -t ad|a|r|d|dd|e         output format of time stamps (def: r: rel. to first)\n");
1373   fprintf(output, "  -X <key>:<value>         eXtension options, see man page for details\n");
1374   fprintf(output, "  -z <statistics>          show various statistics, see man page for details\n");
1375
1376   fprintf(output, "\n");
1377   fprintf(output, "Output:\n");
1378   fprintf(output, "  -w <outfile|->           set the output filename (or '-' for stdout)\n");
1379
1380   fprintf(output, "\n");
1381   fprintf(output, "Miscellaneous:\n");
1382   fprintf(output, "  -h                       display this help and exit\n");
1383   fprintf(output, "  -v                       display version info and exit\n");
1384   fprintf(output, "  -P <key>:<path>          persconf:path - personal configuration files\n");
1385   fprintf(output, "                           persdata:path - personal data files\n");
1386   fprintf(output, "  -o <name>:<value> ...    override preference or recent setting\n");
1387 #ifndef _WIN32
1388   fprintf(output, "  --display=DISPLAY        X display to use\n");
1389 #endif
1390
1391 #ifdef _WIN32
1392   destroy_console();
1393 #endif
1394 }
1395
1396 static void
1397 show_version(void)
1398 {
1399 #ifdef _WIN32
1400   create_console();
1401 #endif
1402
1403   printf(PACKAGE " " VERSION "%s\n"
1404          "\n"
1405          "%s"
1406          "\n"
1407          "%s"
1408          "\n"
1409          "%s",
1410       wireshark_svnversion, get_copyright_info(), comp_info_str->str,
1411       runtime_info_str->str);
1412
1413 #ifdef _WIN32
1414   destroy_console();
1415 #endif
1416 }
1417
1418 /*
1419  * Report an error in command-line arguments.
1420  * Creates a console on Windows.
1421  * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
1422  * terminal isn't the standard error?
1423  */
1424 void
1425 cmdarg_err(const char *fmt, ...)
1426 {
1427   va_list ap;
1428
1429 #ifdef _WIN32
1430   create_console();
1431 #endif
1432   va_start(ap, fmt);
1433   fprintf(stderr, "wireshark: ");
1434   vfprintf(stderr, fmt, ap);
1435   fprintf(stderr, "\n");
1436   va_end(ap);
1437 }
1438
1439 /*
1440  * Report additional information for an error in command-line arguments.
1441  * Creates a console on Windows.
1442  * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
1443  * terminal isn't the standard error?
1444  */
1445 void
1446 cmdarg_err_cont(const char *fmt, ...)
1447 {
1448   va_list ap;
1449
1450 #ifdef _WIN32
1451   create_console();
1452 #endif
1453   va_start(ap, fmt);
1454   vfprintf(stderr, fmt, ap);
1455   fprintf(stderr, "\n");
1456   va_end(ap);
1457 }
1458
1459 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1460 /*
1461    Once every 3 seconds we get a callback here which we use to update
1462    the tap extensions. Since Gtk1 is single threaded we dont have to
1463    worry about any locking or critical regions.
1464  */
1465 static gint
1466 update_cb(gpointer data _U_)
1467 {
1468         draw_tap_listeners(FALSE);
1469         return 1;
1470 }
1471 #else
1472
1473 /* if these three functions are copied to gtk1 Wireshark, since gtk1 does not
1474    use threads all updte_thread_mutex can be dropped and protect/unprotect
1475    would just be empty functions.
1476
1477    This allows gtk2-rpcstat.c and friends to be copied unmodified to
1478    gtk1-wireshark and it will just work.
1479  */
1480 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1481 gpointer
1482 update_thread(gpointer data _U_)
1483 {
1484     while(1){
1485         GTimeVal tv1, tv2;
1486         g_get_current_time(&tv1);
1487         g_static_mutex_lock(&update_thread_mutex);
1488         gdk_threads_enter();
1489         draw_tap_listeners(FALSE);
1490         gdk_threads_leave();
1491         g_static_mutex_unlock(&update_thread_mutex);
1492         g_thread_yield();
1493         g_get_current_time(&tv2);
1494         if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1495             (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1496             g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1497                      (tv2.tv_sec * 1000000 + tv2.tv_usec));
1498         }
1499     }
1500     return NULL;
1501 }
1502 #endif
1503 void
1504 protect_thread_critical_region(void)
1505 {
1506 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1507     g_static_mutex_lock(&update_thread_mutex);
1508 #endif
1509 }
1510 void
1511 unprotect_thread_critical_region(void)
1512 {
1513 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1514     g_static_mutex_unlock(&update_thread_mutex);
1515 #endif
1516 }
1517
1518 /* Set the file name in the status line, in the name for the main window,
1519    and in the name for the main window's icon. */
1520 static void
1521 set_display_filename(capture_file *cf)
1522 {
1523   const gchar *name_ptr;
1524   gchar       *status_msg;
1525   gchar       *size_str;
1526   gchar       *win_name;
1527
1528   name_ptr = cf_get_display_name(cf);
1529
1530   if (!cf->is_tempfile && cf->filename) {
1531     /* Add this filename to the list of recent files in the "Recent Files" submenu */
1532     add_menu_recent_capture_file(cf->filename);
1533   }
1534
1535   /* convert file size */
1536   if (cf->f_datalen/1024/1024 > 10) {
1537     size_str = g_strdup_printf("%" G_GINT64_MODIFIER "d MB", cf->f_datalen/1024/1024);
1538   } else if (cf->f_datalen/1024 > 10) {
1539     size_str = g_strdup_printf("%" G_GINT64_MODIFIER "d KB", cf->f_datalen/1024);
1540   } else {
1541     size_str = g_strdup_printf("%" G_GINT64_MODIFIER "d Bytes", cf->f_datalen);
1542   }
1543
1544   /* statusbar */
1545 #if 0
1546   /* XXX - don't show the highest expert level unless the TCP checksum offloading is "solved" */
1547   status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu [Expert: %s]",
1548     (cf->filename) ? cf->filename : "", size_str,
1549     (long)cf->elapsed_time.secs/3600,
1550     (long)cf->elapsed_time.secs%3600/60,
1551     (long)cf->elapsed_time.secs%60,
1552     val_to_str(expert_get_highest_severity(), expert_severity_vals, "Unknown (%u)"));
1553 #endif
1554   status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu",
1555     (cf->filename) ? cf->filename : "", size_str,
1556     (long)cf->elapsed_time.secs/3600,
1557     (long)cf->elapsed_time.secs%3600/60,
1558     (long)cf->elapsed_time.secs%60);
1559   g_free(size_str);
1560   statusbar_push_file_msg(status_msg);
1561   g_free(status_msg);
1562
1563   /* window title */
1564   win_name = g_strdup_printf("%s - Wireshark", name_ptr);
1565   set_main_window_name(win_name);
1566   g_free(win_name);
1567 }
1568
1569 GtkWidget           *close_dlg = NULL;
1570
1571 static void
1572 priv_warning_dialog_cb(gpointer dialog, gint btn _U_, gpointer data _U_)
1573 {
1574     recent.privs_warn_if_elevated = !simple_dialog_check_get(dialog);
1575 }
1576
1577 #ifdef _WIN32
1578 static void
1579 npf_warning_dialog_cb(gpointer dialog, gint btn _U_, gpointer data _U_)
1580 {
1581     recent.privs_warn_if_no_npf = !simple_dialog_check_get(dialog);
1582 }
1583 #endif
1584
1585 static void
1586 main_cf_cb_file_closing(capture_file *cf)
1587 {
1588
1589     /* if we have more than 10000 packets, show a splash screen while closing */
1590     /* XXX - don't know a better way to decide wether to show or not,
1591      * as most of the time is spend in a single eth_clist_clear function,
1592      * so we can't use a progress bar here! */
1593     if(cf->count > 10000) {
1594         close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE,
1595                                   "%sClosing file!%s\n\nPlease wait ...",
1596                                   simple_dialog_primary_start(),
1597                                   simple_dialog_primary_end());
1598 #if GTK_MAJOR_VERSION >= 2
1599         gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1600 #else
1601         gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
1602 #endif
1603     }
1604
1605     /* Destroy all windows, which refer to the
1606        capture file we're closing. */
1607     destroy_packet_wins();
1608     file_save_as_destroy();
1609
1610     /* Clear any file-related status bar messages.
1611        XXX - should be "clear *ALL* file-related status bar messages;
1612        will there ever be more than one on the stack? */
1613     statusbar_pop_file_msg();
1614
1615     /* Restore the standard title bar message. */
1616     set_main_window_name("The Wireshark Network Analyzer");
1617
1618     /* Disable all menu items that make sense only if you have a capture. */
1619     set_menus_for_capture_file(NULL);
1620     set_menus_for_captured_packets(FALSE);
1621     set_menus_for_selected_packet(cf);
1622     set_menus_for_capture_in_progress(FALSE);
1623     set_menus_for_selected_tree_row(cf);
1624
1625     /* Set up main window for no capture file. */
1626     main_set_for_capture_file(FALSE);
1627
1628     main_window_update();
1629 }
1630
1631 static void
1632 main_cf_cb_file_closed(capture_file *cf _U_)
1633 {
1634   if(close_dlg != NULL) {
1635     splash_destroy(close_dlg);
1636     close_dlg = NULL;
1637   }
1638
1639   /* go back to "No packets" */
1640   packets_bar_update();
1641 }
1642
1643 static void
1644 main_cf_cb_file_read_start(capture_file *cf)
1645 {
1646   const gchar *name_ptr;
1647   gchar       *load_msg;
1648
1649   /* Ensure we pop any previous loaded filename */
1650   statusbar_pop_file_msg();
1651
1652   name_ptr = get_basename(cf->filename);
1653
1654   load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1655   statusbar_push_file_msg(load_msg);
1656   g_free(load_msg);
1657
1658   /* Set up main window for a capture file. */
1659   main_set_for_capture_file(TRUE);
1660 }
1661
1662 static void
1663 main_cf_cb_file_read_finished(capture_file *cf)
1664 {
1665     statusbar_pop_file_msg();
1666     set_display_filename(cf);
1667
1668     /* Enable menu items that make sense if you have a capture file you've
1669        finished reading. */
1670     set_menus_for_capture_file(cf);
1671
1672     /* Enable menu items that make sense if you have some captured packets. */
1673     set_menus_for_captured_packets(TRUE);
1674 }
1675
1676 #if GTK_MAJOR_VERSION >= 2
1677 GList *icon_list_create(
1678     const char **icon16_xpm,
1679     const char **icon32_xpm,
1680     const char **icon48_xpm,
1681     const char **icon64_xpm)
1682 {
1683   GList *icon_list = NULL;
1684   GdkPixbuf * pixbuf16;
1685   GdkPixbuf * pixbuf32;
1686   GdkPixbuf * pixbuf48;
1687   GdkPixbuf * pixbuf64;
1688
1689
1690   if(icon16_xpm != NULL) {
1691       pixbuf16 = gdk_pixbuf_new_from_xpm_data(icon16_xpm);
1692       g_assert(pixbuf16);
1693       icon_list = g_list_append(icon_list, pixbuf16);
1694   }
1695
1696   if(icon32_xpm != NULL) {
1697       pixbuf32 = gdk_pixbuf_new_from_xpm_data(icon32_xpm);
1698       g_assert(pixbuf32);
1699       icon_list = g_list_append(icon_list, pixbuf32);
1700   }
1701
1702   if(icon48_xpm != NULL) {
1703       pixbuf48 = gdk_pixbuf_new_from_xpm_data(icon48_xpm);
1704       g_assert(pixbuf48);
1705       icon_list = g_list_append(icon_list, pixbuf48);
1706   }
1707
1708   if(icon64_xpm != NULL) {
1709       pixbuf64 = gdk_pixbuf_new_from_xpm_data(icon64_xpm);
1710       g_assert(pixbuf64);
1711       icon_list = g_list_append(icon_list, pixbuf64);
1712   }
1713
1714   return icon_list;
1715 }
1716 #endif
1717
1718 #ifdef HAVE_LIBPCAP
1719 static void
1720 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1721 {
1722     gchar *title;
1723 #if GTK_MAJOR_VERSION >= 2
1724     static GList *icon_list = NULL;
1725 #endif
1726
1727
1728     if(capture_opts->iface) {
1729         title = g_strdup_printf("%s: Capturing - Wireshark",
1730                                 get_iface_description(capture_opts));
1731     } else {
1732         title = g_strdup_printf("Capturing - Wireshark");
1733     }
1734     set_main_window_name(title);
1735     g_free(title);
1736
1737 #if GTK_MAJOR_VERSION >= 2
1738     if(icon_list == NULL) {
1739         icon_list = icon_list_create(wsiconcap16_xpm, wsiconcap32_xpm, wsiconcap48_xpm, NULL);
1740     }
1741     gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1742 #endif
1743
1744     /* Disable menu items that make no sense if you're currently running
1745        a capture. */
1746     set_menus_for_capture_in_progress(TRUE);
1747
1748     /* update statusbar */
1749     statusbar_push_file_msg(" Waiting for capture input data ...");
1750
1751     /* Don't set up main window for a capture file. */
1752     main_set_for_capture_file(FALSE);
1753 }
1754
1755 static void
1756 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1757 {
1758     gchar *capture_msg;
1759     gchar *title;
1760
1761     /* We've done this in "prepared" above, but it will be cleared while
1762        switching to the next multiple file. */
1763     if(capture_opts->iface) {
1764         title = g_strdup_printf("%s: Capturing - Wireshark",
1765                                 get_iface_description(capture_opts));
1766     } else {
1767         title = g_strdup_printf("Capturing - Wireshark");
1768     }
1769     set_main_window_name(title);
1770     g_free(title);
1771
1772     set_menus_for_capture_in_progress(TRUE);
1773
1774     /* Enable menu items that make sense if you have some captured
1775        packets (yes, I know, we don't have any *yet*). */
1776     set_menus_for_captured_packets(TRUE);
1777
1778     statusbar_pop_file_msg();
1779
1780     if(capture_opts->iface) {
1781         capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1782                                       get_iface_description(capture_opts),
1783                                       (capture_opts->save_file) ? capture_opts->save_file : "");
1784     } else {
1785         capture_msg = g_strdup_printf(" <live capture in progress> to file: %s",
1786             (capture_opts->save_file) ? capture_opts->save_file : "");
1787     }
1788
1789     statusbar_push_file_msg(capture_msg);
1790
1791     g_free(capture_msg);
1792
1793     /* Set up main window for a capture file. */
1794     main_set_for_capture_file(TRUE);
1795 }
1796
1797 static void
1798 main_cf_cb_live_capture_update_continue(capture_file *cf)
1799 {
1800     gchar *capture_msg;
1801
1802
1803     statusbar_pop_file_msg();
1804
1805 #if 0
1806     /* XXX - don't show the highest expert level unless the TCP checksum offloading is "solved" */
1807     if (cf->f_datalen/1024/1024 > 10) {
1808         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %" G_GINT64_MODIFIER "d MB [Expert: %s]",
1809                                       get_iface_description(capture_opts),
1810                                       capture_opts->save_file,
1811                                       cf->f_datalen/1024/1024,
1812                                       val_to_str(expert_get_highest_severity(),
1813                                                  expert_severity_vals,
1814                                                  "Unknown (%u)"));
1815     } else if (cf->f_datalen/1024 > 10) {
1816         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %" G_GINT64_MODIFIER "d KB [Expert: %s]",
1817                                       get_iface_description(capture_opts),
1818                                       capture_opts->save_file,
1819                                       cf->f_datalen/1024,
1820                                       val_to_str(expert_get_highest_severity(),
1821                                                  expert_severity_vals,
1822                                                  "Unknown (%u)"));
1823     } else {
1824         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %" G_GINT64_MODIFIER "d Bytes [Expert: %s]",
1825                                       get_iface_description(capture_opts),
1826                                       capture_opts->save_file,
1827                                       cf->f_datalen,
1828                                       val_to_str(expert_get_highest_severity(),
1829                                                  expert_severity_vals,
1830                                                  "Unknown (%u)"));
1831     }
1832 #endif
1833     if (cf->f_datalen/1024/1024 > 10) {
1834         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %" G_GINT64_MODIFIER "d MB",
1835                                       get_iface_description(capture_opts),
1836                                       capture_opts->save_file,
1837                                       cf->f_datalen/1024/1024);
1838     } else if (cf->f_datalen/1024 > 10) {
1839         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %" G_GINT64_MODIFIER "d KB",
1840                                       get_iface_description(capture_opts),
1841                                       capture_opts->save_file,
1842                                       cf->f_datalen/1024);
1843     } else {
1844         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %" G_GINT64_MODIFIER "d Bytes",
1845                                       get_iface_description(capture_opts),
1846                                       capture_opts->save_file,
1847                                       cf->f_datalen);
1848     }
1849
1850     statusbar_push_file_msg(capture_msg);
1851 }
1852
1853 GtkWidget * stop_dlg = NULL;
1854
1855 static void
1856 main_cf_cb_live_capture_update_finished(capture_file *cf)
1857 {
1858 #if GTK_MAJOR_VERSION >= 2
1859     static GList *icon_list = NULL;
1860 #endif
1861
1862     if(stop_dlg != NULL) {
1863         simple_dialog_close(stop_dlg);
1864         stop_dlg = NULL;
1865     }
1866
1867     /* Pop the "<live capture in progress>" message off the status bar. */
1868     statusbar_pop_file_msg();
1869
1870     set_display_filename(cf);
1871
1872     /* Enable menu items that make sense if you're not currently running
1873      a capture. */
1874     set_menus_for_capture_in_progress(FALSE);
1875
1876     /* Enable menu items that make sense if you have a capture file
1877        you've finished reading. */
1878     set_menus_for_capture_file(cf);
1879
1880     /* Set up main window for a capture file. */
1881     main_set_for_capture_file(TRUE);
1882
1883 #if GTK_MAJOR_VERSION >= 2
1884     if(icon_list == NULL) {
1885         icon_list = icon_list_create(wsicon16_xpm, wsicon32_xpm, wsicon48_xpm, wsicon64_xpm);
1886     }
1887     gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1888 #endif
1889
1890     if(capture_opts->quit_after_cap) {
1891         /* command line asked us to quit after the capture */
1892         /* don't pop up a dialog to ask for unsaved files etc. */
1893         main_do_quit();
1894     }
1895 }
1896
1897 static void
1898 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1899 {
1900     gchar *capture_msg;
1901
1902
1903     /* Enable menu items that make sense if you have some captured
1904        packets (yes, I know, we don't have any *yet*). */
1905     /*set_menus_for_captured_packets(TRUE);*/
1906
1907     statusbar_pop_file_msg();
1908
1909     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s",
1910                                   get_iface_description(capture_opts),
1911                                   (capture_opts->save_file) ? capture_opts->save_file : "");
1912
1913     statusbar_push_file_msg(capture_msg);
1914     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " Packets: 0");
1915
1916     g_free(capture_msg);
1917
1918     /* Don't set up main window for a capture file. */
1919     main_set_for_capture_file(FALSE);
1920 }
1921
1922 static void
1923 main_cf_cb_live_capture_fixed_continue(capture_file *cf)
1924 {
1925     gchar *capture_msg;
1926
1927
1928     gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1929
1930     capture_msg = g_strdup_printf(" Packets: %u", cf_get_packet_count(cf));
1931
1932     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, capture_msg);
1933
1934     g_free(capture_msg);
1935 }
1936
1937 static void
1938 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1939 {
1940 #if GTK_MAJOR_VERSION >= 2
1941     static GList *icon_list = NULL;
1942 #endif
1943
1944     if(stop_dlg != NULL) {
1945         simple_dialog_close(stop_dlg);
1946         stop_dlg = NULL;
1947     }
1948
1949     /* Pop the "<live capture in progress>" message off the status bar. */
1950     statusbar_pop_file_msg();
1951
1952     /* Pop the "<capturing>" message off the status bar */
1953     gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1954
1955     /*set_display_filename(cf);*/
1956
1957     /* Enable menu items that make sense if you're not currently running
1958      a capture. */
1959     set_menus_for_capture_in_progress(FALSE);
1960
1961     /* Restore the standard title bar message */
1962     /* (just in case we have trouble opening the capture file). */
1963     set_main_window_name("The Wireshark Network Analyzer");
1964
1965 #if GTK_MAJOR_VERSION >= 2
1966     if(icon_list == NULL) {
1967         icon_list = icon_list_create(wsicon16_xpm, wsicon32_xpm, wsicon48_xpm, wsicon64_xpm);
1968     }
1969     gtk_window_set_icon_list(GTK_WINDOW(top_level), icon_list);
1970 #endif
1971
1972     /* We don't have loaded the capture file, this will be done later.
1973      * For now we still have simply a blank screen. */
1974
1975     if(capture_opts->quit_after_cap) {
1976         /* command line asked us to quit after the capture */
1977         /* don't pop up a dialog to ask for unsaved files etc. */
1978         main_do_quit();
1979     }
1980 }
1981
1982 static void
1983 main_cf_cb_live_capture_stopping(capture_file *cf _U_)
1984 {
1985     /* Beware: this state won't be called, if the capture child
1986      * closes the capturing on it's own! */
1987 #if 0
1988     /* XXX - the time to stop the capture has been reduced (this was only a
1989      * problem on Win32 because of the capture piping), so showing a splash
1990      * isn't really necessary any longer. Unfortunately, the GTKClist packet
1991      * list seems to have problems updating after the dialog is closed, so
1992      * this was disabled here. */
1993     stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...",
1994                 simple_dialog_primary_start(), simple_dialog_primary_end());
1995 #if GTK_MAJOR_VERSION >= 2
1996     gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1997 #else
1998     gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1999 #endif
2000 #endif
2001 }
2002
2003 #endif
2004
2005 static void
2006 main_cf_cb_packet_selected(gpointer data)
2007 {
2008     capture_file *cf = data;
2009
2010     /* Display the GUI protocol tree and hex dump.
2011       XXX - why do we dump core if we call "proto_tree_draw()"
2012       before calling "add_byte_views()"? */
2013     add_main_byte_views(cf->edt);
2014     main_proto_tree_draw(cf->edt->tree);
2015
2016     /* The user is searching for a string in the data or a hex value,
2017      * highlight the field that is found in the tree and hex displays. */
2018     if((cfile.string || cfile.hex) && cfile.search_pos != 0) {
2019 #if GTK_MAJOR_VERSION < 2
2020         highlight_field(cf->edt->tvb, cfile.search_pos,
2021                         (GtkCTree *)tree_view, cf->edt->tree);
2022 #else
2023         highlight_field(cf->edt->tvb, cfile.search_pos,
2024                         (GtkTreeView *)tree_view, cf->edt->tree);
2025 #endif
2026         cfile.search_pos = 0; /* Reset the position */
2027     }
2028
2029     /* A packet is selected. */
2030     set_menus_for_selected_packet(cf);
2031 }
2032
2033 static void
2034 main_cf_cb_packet_unselected(capture_file *cf)
2035 {
2036     /* Clear out the display of that packet. */
2037     clear_tree_and_hex_views();
2038
2039     /* No packet is selected. */
2040     set_menus_for_selected_packet(cf);
2041 }
2042
2043 static void
2044 main_cf_cb_field_unselected(capture_file *cf)
2045 {
2046     statusbar_pop_field_msg();
2047     set_menus_for_selected_tree_row(cf);
2048 }
2049
2050 static void
2051 main_cf_cb_file_safe_started(gchar * filename)
2052 {
2053     const gchar  *name_ptr;
2054     gchar        *save_msg;
2055
2056     name_ptr = get_basename(filename);
2057
2058     save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
2059
2060     statusbar_push_file_msg(save_msg);
2061     g_free(save_msg);
2062 }
2063
2064 static void
2065 main_cf_cb_file_safe_finished(gpointer data _U_)
2066 {
2067     /* Pop the "Saving:" message off the status bar. */
2068     statusbar_pop_file_msg();
2069 }
2070
2071 static void
2072 main_cf_cb_file_safe_failed(gpointer data _U_)
2073 {
2074     /* Pop the "Saving:" message off the status bar. */
2075     statusbar_pop_file_msg();
2076 }
2077
2078 static void
2079 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
2080 {
2081     set_menus_for_capture_file(&cfile);
2082 }
2083
2084 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
2085 {
2086     switch(event) {
2087     case(cf_cb_file_closing):
2088         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
2089         main_cf_cb_file_closing(data);
2090         break;
2091     case(cf_cb_file_closed):
2092         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
2093         main_cf_cb_file_closed(data);
2094         break;
2095     case(cf_cb_file_read_start):
2096         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read start");
2097         main_cf_cb_file_read_start(data);
2098         break;
2099     case(cf_cb_file_read_finished):
2100         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
2101         main_cf_cb_file_read_finished(data);
2102         break;
2103 #ifdef HAVE_LIBPCAP
2104     case(cf_cb_live_capture_prepared):
2105         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
2106         main_cf_cb_live_capture_prepared(data);
2107         break;
2108     case(cf_cb_live_capture_update_started):
2109         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
2110         main_cf_cb_live_capture_update_started(data);
2111         break;
2112     case(cf_cb_live_capture_update_continue):
2113         /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
2114         main_cf_cb_live_capture_update_continue(data);
2115         break;
2116     case(cf_cb_live_capture_update_finished):
2117         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
2118         main_cf_cb_live_capture_update_finished(data);
2119         break;
2120     case(cf_cb_live_capture_fixed_started):
2121         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
2122         main_cf_cb_live_capture_fixed_started(data);
2123         break;
2124     case(cf_cb_live_capture_fixed_continue):
2125         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed continue");
2126         main_cf_cb_live_capture_fixed_continue(data);
2127         break;
2128     case(cf_cb_live_capture_fixed_finished):
2129         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
2130         main_cf_cb_live_capture_fixed_finished(data);
2131         break;
2132     case(cf_cb_live_capture_stopping):
2133         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
2134         main_cf_cb_live_capture_stopping(data);
2135         break;
2136 #endif
2137     case(cf_cb_packet_selected):
2138         main_cf_cb_packet_selected(data);
2139         break;
2140     case(cf_cb_packet_unselected):
2141         main_cf_cb_packet_unselected(data);
2142         break;
2143     case(cf_cb_field_unselected):
2144         main_cf_cb_field_unselected(data);
2145         break;
2146     case(cf_cb_file_safe_started):
2147         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe started");
2148         main_cf_cb_file_safe_started(data);
2149         break;
2150     case(cf_cb_file_safe_finished):
2151         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe finished");
2152         main_cf_cb_file_safe_finished(data);
2153         break;
2154     case(cf_cb_file_safe_reload_finished):
2155         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: reload finished");
2156         main_cf_cb_file_safe_reload_finished(data);
2157         break;
2158     case(cf_cb_file_safe_failed):
2159         g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe failed");
2160         main_cf_cb_file_safe_failed(data);
2161         break;
2162     default:
2163         g_warning("main_cf_callback: event %u unknown", event);
2164         g_assert_not_reached();
2165     }
2166 }
2167
2168 static void
2169 get_gui_compiled_info(GString *str)
2170 {
2171   get_epan_compiled_version_info(str);
2172
2173   g_string_append(str, ", ");
2174 #ifdef HAVE_LIBPORTAUDIO
2175 #ifdef PORTAUDIO_API_1
2176   g_string_append(str, "with PortAudio <= V18");
2177 #else /* PORTAUDIO_API_1 */
2178   g_string_append(str, "with ");
2179   g_string_append(str, Pa_GetVersionText());
2180 #endif /* PORTAUDIO_API_1 */
2181 #else /* HAVE_LIBPORTAUDIO */
2182   g_string_append(str, "without PortAudio");
2183 #endif /* HAVE_LIBPORTAUDIO */
2184
2185   g_string_append(str, ", ");
2186 #ifdef HAVE_AIRPCAP
2187   get_compiled_airpcap_version(str);
2188 #else
2189   g_string_append(str, "without AirPcap");
2190 #endif
2191 }
2192
2193 static void
2194 get_gui_runtime_info(GString *str
2195 #ifndef HAVE_AIRPCAP
2196         _U_
2197 #endif
2198 )
2199 {
2200 #ifdef HAVE_AIRPCAP
2201   g_string_append(str, ", ");
2202   get_runtime_airpcap_version(str);
2203 #endif
2204
2205   if(u3_active()) {
2206     g_string_append(str, ", ");
2207     u3_runtime_info(str);
2208   }
2209
2210 }
2211
2212 static e_prefs *
2213 read_configuration_files(char **gdp_path, char **dp_path)
2214 {
2215   int                  gpf_open_errno, gpf_read_errno;
2216   int                  cf_open_errno, df_open_errno;
2217   int                  gdp_open_errno, gdp_read_errno;
2218   int                  dp_open_errno, dp_read_errno;
2219   char                *gpf_path, *pf_path;
2220   char                *cf_path, *df_path;
2221   int                  pf_open_errno, pf_read_errno;
2222   e_prefs             *prefs;
2223
2224   /* Read the preference files. */
2225   prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
2226                      &pf_open_errno, &pf_read_errno, &pf_path);
2227
2228   if (gpf_path != NULL) {
2229     if (gpf_open_errno != 0) {
2230       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2231         "Could not open global preferences file\n\"%s\": %s.", gpf_path,
2232         strerror(gpf_open_errno));
2233     }
2234     if (gpf_read_errno != 0) {
2235       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2236         "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
2237         strerror(gpf_read_errno));
2238     }
2239   }
2240   if (pf_path != NULL) {
2241     if (pf_open_errno != 0) {
2242       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2243         "Could not open your preferences file\n\"%s\": %s.", pf_path,
2244         strerror(pf_open_errno));
2245     }
2246     if (pf_read_errno != 0) {
2247       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2248         "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
2249         strerror(pf_read_errno));
2250     }
2251     g_free(pf_path);
2252     pf_path = NULL;
2253   }
2254
2255 #ifdef _WIN32
2256   /* if the user wants a console to be always there, well, we should open one for him */
2257   if (prefs->gui_console_open == console_open_always) {
2258     create_console();
2259   }
2260 #endif
2261
2262   /* Read the capture filter file. */
2263   read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
2264   if (cf_path != NULL) {
2265       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2266         "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2267         strerror(cf_open_errno));
2268       g_free(cf_path);
2269   }
2270
2271   /* Read the display filter file. */
2272   read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
2273   if (df_path != NULL) {
2274       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2275         "Could not open your display filter file\n\"%s\": %s.", df_path,
2276         strerror(df_open_errno));
2277       g_free(df_path);
2278   }
2279
2280   /* Read the disabled protocols file. */
2281   read_disabled_protos_list(gdp_path, &gdp_open_errno, &gdp_read_errno,
2282                             dp_path, &dp_open_errno, &dp_read_errno);
2283   if (*gdp_path != NULL) {
2284     if (gdp_open_errno != 0) {
2285       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2286         "Could not open global disabled protocols file\n\"%s\": %s.",
2287         *gdp_path, strerror(gdp_open_errno));
2288     }
2289     if (gdp_read_errno != 0) {
2290       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2291         "I/O error reading global disabled protocols file\n\"%s\": %s.",
2292         *gdp_path, strerror(gdp_read_errno));
2293     }
2294     g_free(*gdp_path);
2295     *gdp_path = NULL;
2296   }
2297   if (*dp_path != NULL) {
2298     if (dp_open_errno != 0) {
2299       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2300         "Could not open your disabled protocols file\n\"%s\": %s.", *dp_path,
2301         strerror(dp_open_errno));
2302     }
2303     if (dp_read_errno != 0) {
2304       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2305         "I/O error reading your disabled protocols file\n\"%s\": %s.", *dp_path,
2306         strerror(dp_read_errno));
2307     }
2308     g_free(*dp_path);
2309     *dp_path = NULL;
2310   }
2311
2312   return prefs;
2313 }
2314
2315 /* And now our feature presentation... [ fade to music ] */
2316 int
2317 main(int argc, char *argv[])
2318 {
2319   char                *init_progfile_dir_error;
2320   char                *s;
2321   int                  opt;
2322   extern char         *optarg;
2323   gboolean             arg_error = FALSE;
2324
2325 #ifdef _WIN32
2326   WSADATA              wsaData;
2327 #endif  /* _WIN32 */
2328
2329   char                *rf_path;
2330   int                  rf_open_errno;
2331   char                *gdp_path, *dp_path;
2332   int                  err;
2333 #ifdef HAVE_LIBPCAP
2334   gboolean             start_capture = FALSE;
2335 #else
2336   gboolean             capture_option_specified = FALSE;
2337 #endif
2338   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
2339   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
2340   dfilter_t           *rfcode = NULL;
2341   gboolean             rfilter_parse_failed = FALSE;
2342   e_prefs             *prefs;
2343   char                 badopt;
2344   GtkWidget           *splash_win = NULL;
2345   GLogLevelFlags       log_flags;
2346   guint                go_to_packet = 0;
2347   int                  optind_initial;
2348   int                  status;
2349   gchar               *cur_user, *cur_group;
2350
2351 #ifdef HAVE_AIRPCAP
2352   char                  *err_str;
2353   /*gchar                       *cant_get_if_list_errstr;*/
2354 #endif
2355
2356 #define OPTSTRING_INIT "a:b:c:C:Df:g:Hhi:klLm:nN:o:P:pQr:R:Ss:t:vw:X:y:z:"
2357
2358 #if defined HAVE_LIBPCAP && defined _WIN32
2359 #define OPTSTRING_WIN32 "B:"
2360 #else
2361 #define OPTSTRING_WIN32 ""
2362 #endif
2363
2364   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
2365     OPTSTRING_INIT OPTSTRING_WIN32;
2366
2367   /*
2368    * Get credential information for later use, and drop privileges
2369    * before doing anything else.
2370    * Let the user know if anything happened.
2371    */
2372   get_credential_info();
2373   relinquish_special_privs_perm();
2374
2375   /*
2376    * Attempt to get the pathname of the executable file.
2377    */
2378   init_progfile_dir_error = init_progfile_dir(argv[0]);
2379
2380   /* initialize the funnel mini-api */
2381   initialize_funnel_ops();
2382
2383 #ifdef  HAVE_AIRPDCAP
2384   /*    Davide Schiera (2006-11-18): init AirPDcap context                                                              */
2385   AirPDcapInitContext(&airpdcap_ctx);
2386   /* Davide Schiera (2006-11-18) -------------------------------------------    */
2387 #endif
2388
2389 #ifdef _WIN32
2390   /* Load wpcap if possible. Do this before collecting the run-time version information */
2391   load_wpcap();
2392
2393   /* ... and also load the packet.dll from wpcap */
2394   wpcap_packet_load();
2395
2396 #ifdef HAVE_AIRPCAP
2397   /* Load the airpcap.dll.  This must also be done before collecting
2398    * run-time version information. */
2399   airpcap_dll_ret_val = load_airpcap();
2400
2401   switch (airpcap_dll_ret_val) {
2402   case AIRPCAP_DLL_OK:
2403     /* load the airpcap interfaces */
2404     airpcap_if_list = get_airpcap_interface_list(&err, &err_str);
2405
2406     if (airpcap_if_list == NULL || g_list_length(airpcap_if_list) == 0){
2407       if (err == CANT_GET_AIRPCAP_INTERFACE_LIST && err_str != NULL) {
2408         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", "Failed to open Airpcap Adapters!");
2409         g_free(err_str);
2410       }
2411       airpcap_if_active = NULL;
2412
2413     } else {
2414
2415       /* select the first ad default (THIS SHOULD BE CHANGED) */
2416       airpcap_if_active = airpcap_get_default_if(airpcap_if_list);
2417           }
2418     break;
2419 #if 0
2420     /*
2421      * XXX - Maybe we need to warn the user if one of the following happens???
2422      */
2423     case AIRPCAP_DLL_OLD:
2424       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_OLD\n");
2425       break;
2426
2427     case AIRPCAP_DLL_ERROR:
2428       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DLL_ERROR\n");
2429       break;
2430
2431     case AIRPCAP_DLL_NOT_FOUND:
2432       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s","AIRPCAP_DDL_NOT_FOUND\n");
2433       break;
2434 #endif
2435   }
2436 #endif /* HAVE_AIRPCAP */
2437
2438   /* Start windows sockets */
2439   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
2440 #endif  /* _WIN32 */
2441
2442   /* Assemble the compile-time version information string */
2443   comp_info_str = g_string_new("Compiled ");
2444
2445   g_string_append(comp_info_str, "with ");
2446   g_string_sprintfa(comp_info_str,
2447 #ifdef GTK_MAJOR_VERSION
2448                     "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
2449                     GTK_MICRO_VERSION);
2450 #else
2451                     "GTK+ (version unknown)");
2452 #endif
2453   g_string_append(comp_info_str, ", ");
2454
2455   get_compiled_version_info(comp_info_str, get_gui_compiled_info);
2456
2457   /* Assemble the run-time version information string */
2458   runtime_info_str = g_string_new("Running ");
2459   get_runtime_version_info(runtime_info_str, get_gui_runtime_info);
2460
2461
2462   /* "pre-scan" the command line parameters, if we have "console only"
2463      parameters.  We do this so we don't start GTK+ if we're only showing
2464      command-line help or version information.
2465
2466      XXX - this pre-scan is doen before we start GTK+, so we haven't
2467      run gtk_init() on the arguments.  That means that GTK+ arguments
2468      have not been removed from the argument list; those arguments
2469      begin with "--", and will be treated as an error by getopt().
2470
2471      We thus ignore errors - *and* set "opterr" to 0 to suppress the
2472      error messages. */
2473   opterr = 0;
2474   optind_initial = optind;
2475   while ((opt = getopt(argc, argv, optstring)) != -1) {
2476     switch (opt) {
2477       case 'C':        /* Configuration Profile */
2478         if (profile_exists (optarg)) {
2479           set_profile_name (optarg);
2480         } else {
2481           cmdarg_err("Configuration Profile \"%s\" does not exist", optarg);
2482           exit(1);
2483         }
2484         break;
2485       case 'h':        /* Print help and exit */
2486         print_usage(TRUE);
2487         exit(0);
2488         break;
2489       case 'P':        /* Path settings - change these before the Preferences and alike are processed */
2490         status = filesystem_opt(opt, optarg);
2491         if(status != 0) {
2492             cmdarg_err("-P flag \"%s\" failed (hint: is it quoted and existing?)", optarg);
2493             exit(status);
2494         }
2495         break;
2496       case 'v':        /* Show version and exit */
2497         show_version();
2498         exit(0);
2499         break;
2500       case 'X':
2501         /*
2502          *  Extension command line options have to be processed before
2503          *  we call epan_init() as they are supposed to be used by dissectors
2504          *  or taps very early in the registration process.
2505          */
2506         ex_opt_add(optarg);
2507         break;
2508       case '?':        /* Ignore errors - the "real" scan will catch them. */
2509         break;
2510     }
2511   }
2512
2513   /* Init the "Open file" dialog directory */
2514   /* (do this after the path settings are processed) */
2515   set_last_open_dir(get_persdatafile_dir());
2516
2517   /* Set getopt index back to initial value, so it will start with the
2518      first command line parameter again.  Also reset opterr to 1, so that
2519      error messages are printed by getopt().
2520
2521      XXX - this seems to work on most platforms, but time will tell.
2522      The Single UNIX Specification says "The getopt() function need
2523      not be reentrant", so this isn't guaranteed to work.  The Mac
2524      OS X 10.4[.x] getopt() man page says
2525
2526        In order to use getopt() to evaluate multiple sets of arguments, or to
2527        evaluate a single set of arguments multiple times, the variable optreset
2528        must be set to 1 before the second and each additional set of calls to
2529        getopt(), and the variable optind must be reinitialized.
2530
2531            ...
2532
2533        The optreset variable was added to make it possible to call the getopt()
2534        function multiple times.  This is an extension to the IEEE Std 1003.2
2535        (``POSIX.2'') specification.
2536
2537      which I think comes from one of the other BSDs.
2538
2539      XXX - if we want to control all the command-line option errors, so
2540      that we can display them where we choose (e.g., in a window), we'd
2541      want to leave opterr as 0, and produce our own messages using optopt.
2542      We'd have to check the value of optopt to see if it's a valid option
2543      letter, in which case *presumably* the error is "this option requires
2544      an argument but none was specified", or not a valid option letter,
2545      in which case *presumably* the error is "this option isn't valid".
2546      Some versions of getopt() let you supply a option string beginning
2547      with ':', which means that getopt() will return ':' rather than '?'
2548      for "this option requires an argument but none was specified", but
2549      not all do. */
2550   optind = optind_initial;
2551   opterr = 1;
2552
2553   /* Set the current locale according to the program environment.
2554    * We haven't localized anything, but some GTK widgets are localized
2555    * (the file selection dialogue, for example).
2556    * This also sets the C-language locale to the native environment. */
2557   gtk_set_locale();
2558
2559   /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
2560   gtk_init (&argc, &argv);
2561
2562   cf_callback_add(main_cf_callback, NULL);
2563
2564 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
2565   /* initialize our GTK eth_clist_type */
2566   init_eth_clist_type();
2567 #endif
2568
2569   /* Arrange that if we have no console window, and a GLib message logging
2570      routine is called to log a message, we pop up a console window.
2571
2572      We do that by inserting our own handler for all messages logged
2573      to the default domain; that handler pops up a console if necessary,
2574      and then calls the default handler. */
2575
2576   /* We might want to have component specific log levels later ... */
2577
2578   log_flags =
2579                     G_LOG_LEVEL_ERROR|
2580                     G_LOG_LEVEL_CRITICAL|
2581                     G_LOG_LEVEL_WARNING|
2582                     G_LOG_LEVEL_MESSAGE|
2583                     G_LOG_LEVEL_INFO|
2584                     G_LOG_LEVEL_DEBUG|
2585                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
2586
2587   g_log_set_handler(NULL,
2588                     log_flags,
2589                     console_log_handler, NULL /* user_data */);
2590   g_log_set_handler(LOG_DOMAIN_MAIN,
2591                     log_flags,
2592                     console_log_handler, NULL /* user_data */);
2593
2594 #ifdef HAVE_LIBPCAP
2595   g_log_set_handler(LOG_DOMAIN_CAPTURE,
2596                     log_flags,
2597                     console_log_handler, NULL /* user_data */);
2598   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
2599                     log_flags,
2600                     console_log_handler, NULL /* user_data */);
2601
2602   /* Set the initial values in the capture_opts. This might be overwritten
2603      by preference settings and then again by the command line parameters. */
2604   capture_opts_init(capture_opts, &cfile);
2605
2606   capture_opts->snaplen             = MIN_PACKET_SIZE;
2607   capture_opts->has_ring_num_files  = TRUE;
2608 #endif
2609
2610   /* We won't come till here, if we had a "console only" command line parameter. */
2611   splash_win = splash_new("Loading Wireshark ...");
2612   if (init_progfile_dir_error != NULL) {
2613     simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2614         "Can't get pathname of Wireshark: %s.\n"
2615         "It won't be possible to capture traffic.\n"
2616         "Report this to the Wireshark developers.",
2617         init_progfile_dir_error);
2618     g_free(init_progfile_dir_error);
2619   }
2620
2621   splash_update(RA_DISSECTORS, NULL, (gpointer)splash_win);
2622
2623   /* Register all dissectors; we must do this before checking for the
2624      "-G" flag, as the "-G" flag dumps information registered by the
2625      dissectors, and we must do it before we read the preferences, in
2626      case any dissectors register preferences. */
2627   epan_init(register_all_protocols,register_all_protocol_handoffs,
2628             splash_update, (gpointer) splash_win,
2629             failure_alert_box,open_failure_alert_box,read_failure_alert_box);
2630
2631   splash_update(RA_LISTENERS, NULL, (gpointer)splash_win);
2632
2633   /* Register all tap listeners; we do this before we parse the arguments,
2634      as the "-z" argument can specify a registered tap. */
2635
2636   /* we register the plugin taps before the other taps because
2637           stats_tree taps plugins will be registered as tap listeners
2638           by stats_tree_stat.c and need to registered before that */
2639
2640 #ifdef HAVE_PLUGINS
2641   register_all_plugin_tap_listeners();
2642 #endif
2643
2644   register_all_tap_listeners();
2645
2646   splash_update(RA_PREFERENCES, NULL, (gpointer)splash_win);
2647
2648   /* Now register the preferences for any non-dissector modules.
2649      We must do that before we read the preferences as well. */
2650   prefs_register_modules();
2651
2652   /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
2653 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
2654   {
2655       GThread *ut;
2656       g_thread_init(NULL);
2657       gdk_threads_init();
2658       ut=g_thread_create(update_thread, NULL, FALSE, NULL);
2659       g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
2660   }
2661 #else  /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
2662   /* this is to keep tap extensions updating once every 3 seconds */
2663   gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
2664 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
2665
2666 #if HAVE_GNU_ADNS
2667   gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
2668 #endif
2669
2670   splash_update(RA_CONFIGURATION, NULL, (gpointer)splash_win);
2671
2672   prefs = read_configuration_files (&gdp_path, &dp_path);
2673
2674   /* Read the (static part) of the recent file. Only the static part of it will be read, */
2675   /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2676   /* We have to do this already here, so command line parameters can overwrite these values. */
2677   recent_read_static(&rf_path, &rf_open_errno);
2678
2679   init_cap_file(&cfile);
2680
2681   /* Now get our args */
2682   while ((opt = getopt(argc, argv, optstring)) != -1) {
2683     switch (opt) {
2684       /*** capture option specific ***/
2685       case 'a':        /* autostop criteria */
2686       case 'b':        /* Ringbuffer option */
2687       case 'c':        /* Capture xxx packets */
2688       case 'f':        /* capture filter */
2689       case 'k':        /* Start capture immediately */
2690       case 'H':        /* Hide capture info dialog box */
2691       case 'i':        /* Use interface xxx */
2692       case 'p':        /* Don't capture in promiscuous mode */
2693       case 'Q':        /* Quit after capture (just capture to file) */
2694       case 's':        /* Set the snapshot (capture) length */
2695       case 'S':        /* "Sync" mode: used for following file ala tail -f */
2696       case 'w':        /* Write to capture file xxx */
2697       case 'y':        /* Set the pcap data link type */
2698 #ifdef _WIN32
2699       case 'B':        /* Buffer size */
2700 #endif /* _WIN32 */
2701 #ifdef HAVE_LIBPCAP
2702         status = capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
2703         if(status != 0) {
2704             exit(status);
2705         }
2706 #else
2707         capture_option_specified = TRUE;
2708         arg_error = TRUE;
2709 #endif
2710         break;
2711
2712       /*** all non capture option specific ***/
2713       case 'C':
2714         /* Configuration profile settings were already processed just ignore them this time*/
2715         break;
2716       case 'D':        /* Print a list of capture devices and exit */
2717 #ifdef HAVE_LIBPCAP
2718         capture_opts_list_interfaces(FALSE);
2719         exit(0);
2720 #else
2721         capture_option_specified = TRUE;
2722         arg_error = TRUE;
2723 #endif
2724         break;
2725       case 'g':        /* Go to packet */
2726         go_to_packet = get_positive_int(optarg, "go to packet");
2727         break;
2728       case 'l':        /* Automatic scrolling in live capture mode */
2729 #ifdef HAVE_LIBPCAP
2730         auto_scroll_live = TRUE;
2731 #else
2732         capture_option_specified = TRUE;
2733         arg_error = TRUE;
2734 #endif
2735         break;
2736       case 'L':        /* Print list of link-layer types and exit */
2737 #ifdef HAVE_LIBPCAP
2738         list_link_layer_types = TRUE;
2739 #else
2740         capture_option_specified = TRUE;
2741         arg_error = TRUE;
2742 #endif
2743         break;
2744       case 'm':        /* Fixed-width font for the display */
2745         if (prefs->PREFS_GUI_FONT_NAME != NULL)
2746           g_free(prefs->PREFS_GUI_FONT_NAME);
2747         prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2748         break;
2749       case 'n':        /* No name resolution */
2750         g_resolv_flags = RESOLV_NONE;
2751         break;
2752       case 'N':        /* Select what types of addresses/port #s to resolve */
2753         if (g_resolv_flags == RESOLV_ALL)
2754           g_resolv_flags = RESOLV_NONE;
2755         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2756         if (badopt != '\0') {
2757           cmdarg_err("-N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2758                         badopt);
2759           exit(1);
2760         }
2761         break;
2762       case 'o':        /* Override preference from command line */
2763         switch (prefs_set_pref(optarg)) {
2764         case PREFS_SET_OK:
2765           break;
2766         case PREFS_SET_SYNTAX_ERR:
2767           cmdarg_err("Invalid -o flag \"%s\"", optarg);
2768           exit(1);
2769           break;
2770         case PREFS_SET_NO_SUCH_PREF:
2771           /* not a preference, might be a recent setting */
2772           switch (recent_set_arg(optarg)) {
2773             case PREFS_SET_OK:
2774               break;
2775             case PREFS_SET_SYNTAX_ERR:
2776               /* shouldn't happen, checked already above */
2777               cmdarg_err("Invalid -o flag \"%s\"", optarg);
2778               exit(1);
2779               break;
2780             case PREFS_SET_NO_SUCH_PREF:
2781             case PREFS_SET_OBSOLETE:
2782               cmdarg_err("-o flag \"%s\" specifies unknown preference/recent value",
2783                     optarg);
2784               exit(1);
2785               break;
2786             default:
2787               g_assert_not_reached();
2788             }
2789           break;
2790         case PREFS_SET_OBSOLETE:
2791           cmdarg_err("-o flag \"%s\" specifies obsolete preference",
2792                         optarg);
2793           exit(1);
2794           break;
2795         default:
2796           g_assert_not_reached();
2797         }
2798         break;
2799       case 'P':
2800         /* Path settings were already processed just ignore them this time*/
2801         break;
2802       case 'r':        /* Read capture file xxx */
2803         /* We may set "last_open_dir" to "cf_name", and if we change
2804            "last_open_dir" later, we free the old value, so we have to
2805            set "cf_name" to something that's been allocated. */
2806 #if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
2807         /* since GLib 2.6, we need to convert filenames to utf8 for Win32 */
2808         cf_name = g_locale_to_utf8(optarg, -1, NULL, NULL, NULL);
2809 #else
2810         cf_name = g_strdup(optarg);
2811 #endif
2812         break;
2813       case 'R':        /* Read file filter */
2814         rfilter = optarg;
2815         break;
2816       case 't':        /* Time stamp type */
2817         if (strcmp(optarg, "r") == 0)
2818           timestamp_set_type(TS_RELATIVE);
2819         else if (strcmp(optarg, "a") == 0)
2820           timestamp_set_type(TS_ABSOLUTE);
2821         else if (strcmp(optarg, "ad") == 0)
2822           timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2823         else if (strcmp(optarg, "d") == 0)
2824           timestamp_set_type(TS_DELTA);
2825         else if (strcmp(optarg, "dd") == 0)
2826           timestamp_set_type(TS_DELTA_DIS);
2827         else if (strcmp(optarg, "e") == 0)
2828           timestamp_set_type(TS_EPOCH);
2829         else {
2830           cmdarg_err("Invalid time stamp type \"%s\"", optarg);
2831           cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
2832           cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
2833           exit(1);
2834         }
2835         break;
2836       case 'X':
2837           /* ext ops were already processed just ignore them this time*/
2838           break;
2839       case 'z':
2840         /* We won't call the init function for the stat this soon
2841            as it would disallow MATE's fields (which are registered
2842            by the preferences set callback) from being used as
2843            part of a tap filter.  Instead, we just add the argument
2844            to a list of stat arguments. */
2845         if (!process_stat_cmd_arg(optarg)) {
2846           cmdarg_err("Invalid -z argument.");
2847           cmdarg_err_cont("  -z argument must be one of :");
2848           list_stat_cmd_args();
2849           exit(1);
2850         }
2851         break;
2852       default:
2853       case '?':        /* Bad flag - print usage message */
2854         arg_error = TRUE;
2855         break;
2856     }
2857   }
2858   argc -= optind;
2859   argv += optind;
2860   if (argc >= 1) {
2861     if (cf_name != NULL) {
2862       /*
2863        * Input file name specified with "-r" *and* specified as a regular
2864        * command-line argument.
2865        */
2866       cmdarg_err("File name specified both with -r and regular argument");
2867       arg_error = TRUE;
2868     } else {
2869       /*
2870        * Input file name not specified with "-r", and a command-line argument
2871        * was specified; treat it as the input file name.
2872        *
2873        * Yes, this is different from tshark, where non-flag command-line
2874        * arguments are a filter, but this works better on GUI desktops
2875        * where a command can be specified to be run to open a particular
2876        * file - yes, you could have "-r" as the last part of the command,
2877        * but that's a bit ugly.
2878        */
2879 #if defined _WIN32 && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
2880       /* since GLib 2.6, we need to convert filenames to utf8 for Win32 */
2881       cf_name = g_locale_to_utf8(argv[0], -1, NULL, NULL, NULL);
2882 #else
2883       cf_name = g_strdup(argv[0]);
2884 #endif
2885     }
2886     argc--;
2887     argv++;
2888   }
2889
2890
2891
2892   if (argc != 0) {
2893     /*
2894      * Extra command line arguments were specified; complain.
2895      */
2896     cmdarg_err("Invalid argument: %s", argv[0]);
2897     arg_error = TRUE;
2898   }
2899
2900   if (arg_error) {
2901 #ifndef HAVE_LIBPCAP
2902     if (capture_option_specified) {
2903       cmdarg_err("This version of Wireshark was not built with support for capturing packets.");
2904     }
2905 #endif
2906     print_usage(FALSE);
2907     exit(1);
2908   }
2909
2910 #ifdef HAVE_LIBPCAP
2911   if (start_capture && list_link_layer_types) {
2912     /* Specifying *both* is bogus. */
2913     cmdarg_err("You can't specify both -L and a live capture.");
2914     exit(1);
2915   }
2916
2917   if (list_link_layer_types) {
2918     /* We're supposed to list the link-layer types for an interface;
2919        did the user also specify a capture file to be read? */
2920     if (cf_name) {
2921       /* Yes - that's bogus. */
2922       cmdarg_err("You can't specify -L and a capture file to be read.");
2923       exit(1);
2924     }
2925     /* No - did they specify a ring buffer option? */
2926     if (capture_opts->multi_files_on) {
2927       cmdarg_err("Ring buffer requested, but a capture isn't being done.");
2928       exit(1);
2929     }
2930   } else {
2931     /* We're supposed to do a live capture; did the user also specify
2932        a capture file to be read? */
2933     if (start_capture && cf_name) {
2934       /* Yes - that's bogus. */
2935       cmdarg_err("You can't specify both a live capture and a capture file to be read.");
2936       exit(1);
2937     }
2938
2939     /* No - was the ring buffer option specified and, if so, does it make
2940        sense? */
2941     if (capture_opts->multi_files_on) {
2942       /* Ring buffer works only under certain conditions:
2943          a) ring buffer does not work with temporary files;
2944          b) real_time_mode and multi_files_on are mutually exclusive -
2945             real_time_mode takes precedence;
2946          c) it makes no sense to enable the ring buffer if the maximum
2947             file size is set to "infinite". */
2948       if (capture_opts->save_file == NULL) {
2949         cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
2950         capture_opts->multi_files_on = FALSE;
2951       }
2952 /*      if (capture_opts->real_time_mode) {
2953         cmdarg_err("Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2954         capture_opts->multi_files_on = FALSE;
2955       }*/
2956       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2957         cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
2958 /* XXX - this must be redesigned as the conditions changed */
2959 /*      capture_opts->multi_files_on = FALSE;*/
2960       }
2961     }
2962   }
2963
2964   if (start_capture || list_link_layer_types) {
2965     /* Did the user specify an interface to use? */
2966     if (!capture_opts_trim_iface(capture_opts,
2967         (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) {
2968         exit(2);
2969     }
2970   }
2971
2972   if (list_link_layer_types) {
2973     status = capture_opts_list_link_layer_types(capture_opts, FALSE);
2974     exit(status);
2975   }
2976
2977   /* Fill in capture options with values from the preferences */
2978   prefs_to_capture_opts();
2979
2980   capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
2981   capture_opts_trim_ring_num_files(capture_opts);
2982 #endif /* HAVE_LIBPCAP */
2983
2984   /* Notify all registered modules that have had any of their preferences
2985      changed either from one of the preferences file or from the command
2986      line that their preferences have changed. */
2987   prefs_apply_all();
2988
2989   /* disabled protocols as per configuration file */
2990   if (gdp_path == NULL && dp_path == NULL) {
2991     set_disabled_protos_list();
2992   }
2993
2994   build_column_format_array(&cfile, TRUE);
2995
2996   /* read in rc file from global and personal configuration paths. */
2997   rc_file = get_datafile_path(RC_FILE);
2998   gtk_rc_parse(rc_file);
2999   g_free(rc_file);
3000   rc_file = get_persconffile_path(RC_FILE, FALSE, FALSE);
3001   gtk_rc_parse(rc_file);
3002   g_free(rc_file);
3003
3004   font_init();
3005
3006   /* close the splash screen, as we are going to open the main window now */
3007   splash_destroy(splash_win);
3008
3009   /************************************************************************/
3010   /* Everything is prepared now, preferences and command line was read in */
3011
3012   /* Pop up the main window. */
3013   create_main_window(pl_size, tv_size, bv_size, prefs);
3014
3015   /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
3016   recent_read_dynamic(&rf_path, &rf_open_errno);
3017   color_filters_enable(recent.packet_list_colorize);
3018
3019   /* rearrange all the widgets as we now have all recent settings ready for this */
3020   main_widgets_rearrange();
3021
3022   /* Fill in column titles.  This must be done after the top level window
3023      is displayed.
3024
3025      XXX - is that still true, with fixed-width columns? */
3026   packet_list_set_column_titles();
3027
3028   menu_recent_read_finished();
3029 #ifdef HAVE_LIBPCAP
3030   menu_auto_scroll_live_changed(auto_scroll_live);
3031 #endif
3032
3033   switch (user_font_apply()) {
3034   case FA_SUCCESS:
3035       break;
3036   case FA_FONT_NOT_RESIZEABLE:
3037       /* "user_font_apply()" popped up an alert box. */
3038       /* turn off zooming - font can't be resized */
3039   case FA_FONT_NOT_AVAILABLE:
3040       /* XXX - did we successfully load the un-zoomed version earlier?
3041       If so, this *probably* means the font is available, but not at
3042       this particular zoom level, but perhaps some other failure
3043       occurred; I'm not sure you can determine which is the case,
3044       however. */
3045       /* turn off zooming - zoom level is unavailable */
3046   default:
3047       /* in any other case than FA_SUCCESS, turn off zooming */
3048       recent.gui_zoom_level = 0;
3049       /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
3050   }
3051
3052   dnd_init(top_level);
3053
3054   colors_init();
3055   color_filters_init();
3056   decode_as_init();
3057
3058   /* the window can be sized only, if it's not already shown, so do it now! */
3059   main_load_window_geometry(top_level);
3060
3061   /* Tell the user not to run as root. */
3062   if (running_with_special_privs() && recent.privs_warn_if_elevated) {
3063     cur_user = get_cur_username();
3064     cur_group = get_cur_groupname();
3065     priv_warning_dialog = simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3066       "Running as user \"%s\" and group \"%s\".\n"
3067       "This could be dangerous.", cur_user, cur_group);
3068     g_free(cur_user);
3069     g_free(cur_group);
3070     simple_dialog_check_set(priv_warning_dialog, "Don't show this message again.");
3071     simple_dialog_set_cb(priv_warning_dialog, priv_warning_dialog_cb, NULL);
3072   }
3073
3074 #ifdef _WIN32
3075   /* Warn the user if npf.sys isn't loaded. */
3076   if (!npf_sys_is_running() && recent.privs_warn_if_no_npf && get_os_major_version() >= 6) {
3077     priv_warning_dialog = simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
3078       "The NPF driver isn't running.  You may have trouble\n"
3079       "capturing or listing interfaces.");
3080     simple_dialog_check_set(priv_warning_dialog, "Don't show this message again.");
3081     simple_dialog_set_cb(priv_warning_dialog, npf_warning_dialog_cb, NULL);
3082   }
3083 #endif
3084
3085   /* If we were given the name of a capture file, read it in now;
3086      we defer it until now, so that, if we can't open it, and pop
3087      up an alert box, the alert box is more likely to come up on
3088      top of the main window - but before the preference-file-error
3089      alert box, so, if we get one of those, it's more likely to come
3090      up on top of us. */
3091   if (cf_name) {
3092     show_main_window(TRUE);
3093     if (rfilter != NULL) {
3094       if (!dfilter_compile(rfilter, &rfcode)) {
3095         bad_dfilter_alert_box(rfilter);
3096         rfilter_parse_failed = TRUE;
3097       }
3098     }
3099     if (!rfilter_parse_failed) {
3100       if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
3101         /* "cf_open()" succeeded, so it closed the previous
3102            capture file, and thus destroyed any previous read filter
3103            attached to "cf". */
3104
3105         cfile.rfcode = rfcode;
3106         /* Open stat windows; we do so after creating the main window,
3107            to avoid GTK warnings, and after successfully opening the
3108            capture file, so we know we have something to compute stats
3109            on, and after registering all dissectors, so that MATE will
3110            have registered its field array and we can have a tap filter
3111            with one of MATE's late-registered fields as part of the
3112            filter. */
3113         start_requested_stats();
3114
3115         /* Read the capture file. */
3116         switch (cf_read(&cfile)) {
3117
3118         case CF_READ_OK:
3119         case CF_READ_ERROR:
3120           /* Just because we got an error, that doesn't mean we were unable
3121              to read any of the file; we handle what we could get from the
3122              file. */
3123           /* if the user told us to jump to a specific packet, do it now */
3124           if(go_to_packet != 0) {
3125             cf_goto_frame(&cfile, go_to_packet);
3126           }
3127           break;
3128
3129         case CF_READ_ABORTED:
3130           /* Exit now. */
3131           gtk_exit(0);
3132           break;
3133         }
3134         /* Save the name of the containing directory specified in the
3135            path name, if any; we can write over cf_name, which is a
3136            good thing, given that "get_dirname()" does write over its
3137            argument. */
3138         s = get_dirname(cf_name);
3139         set_last_open_dir(s);
3140         g_free(cf_name);
3141         cf_name = NULL;
3142       } else {
3143         if (rfcode != NULL)
3144           dfilter_free(rfcode);
3145         cfile.rfcode = NULL;
3146         show_main_window(FALSE);
3147         set_menus_for_capture_in_progress(FALSE);
3148       }
3149     }
3150   } else {
3151 #ifdef HAVE_LIBPCAP
3152     if (start_capture) {
3153       if (capture_opts->save_file != NULL) {
3154         /* Save the directory name for future file dialogs. */
3155         /* (get_dirname overwrites filename) */
3156         s = get_dirname(g_strdup(capture_opts->save_file));
3157         set_last_open_dir(s);
3158         g_free(s);
3159       }
3160       /* "-k" was specified; start a capture. */
3161       show_main_window(TRUE);
3162       if (capture_start(capture_opts)) {
3163         /* The capture started.  Open stat windows; we do so after creating
3164            the main window, to avoid GTK warnings, and after successfully
3165            opening the capture file, so we know we have something to compute
3166            stats on, and after registering all dissectors, so that MATE will
3167            have registered its field array and we can have a tap filter with
3168            one of MATE's late-registered fields as part of the filter. */
3169         start_requested_stats();
3170       }
3171     }
3172     else {
3173       show_main_window(FALSE);
3174       set_menus_for_capture_in_progress(FALSE);
3175     }
3176
3177     /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
3178     if (!start_capture && strlen(capture_opts->cfilter) == 0) {
3179       g_free(capture_opts->cfilter);
3180       capture_opts->cfilter = g_strdup(get_conn_cfilter());
3181     }
3182 #else /* HAVE_LIBPCAP */
3183     show_main_window(FALSE);
3184     set_menus_for_capture_in_progress(FALSE);
3185 #endif /* HAVE_LIBPCAP */
3186   }
3187
3188   /* register our pid if we are being run from a U3 device */
3189   u3_register_pid();
3190
3191   g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "Wireshark is up and ready to go");
3192
3193   /* we'll enter the GTK loop now and hand the control over to GTK ... */
3194   gtk_main();
3195   /* ... back from GTK, we're going down now! */
3196
3197   /* deregister our pid */
3198   u3_deregister_pid();
3199
3200   epan_cleanup();
3201
3202 #ifdef  HAVE_AIRPDCAP
3203         /*      Davide Schiera (2006-11-18): destroy AirPDcap context                                                   */
3204         AirPDcapDestroyContext(&airpdcap_ctx);
3205         /* Davide Schiera (2006-11-18) -------------------------------------------      */
3206 #endif
3207
3208 #ifdef _WIN32
3209   /* hide the (unresponsive) main window, while asking the user to close the console window */
3210   gtk_widget_hide(top_level);
3211
3212   /* Shutdown windows sockets */
3213   WSACleanup();
3214
3215   /* For some unknown reason, the "atexit()" call in "create_console()"
3216      doesn't arrange that "destroy_console()" be called when we exit,
3217      so we call it here if a console was created. */
3218   destroy_console();
3219 #endif
3220
3221   gtk_exit(0);
3222
3223   /* This isn't reached, but we need it to keep GCC from complaining
3224      that "main()" returns without returning a value - it knows that
3225      "exit()" never returns, but it doesn't know that "gtk_exit()"
3226      doesn't, as GTK+ doesn't declare it with the attribute
3227      "noreturn". */
3228   return 0;     /* not reached */
3229 }
3230
3231 #ifdef _WIN32
3232
3233 /* We build this as a GUI subsystem application on Win32, so
3234    "WinMain()", not "main()", gets called.
3235
3236    Hack shamelessly stolen from the Win32 port of the GIMP. */
3237 #ifdef __GNUC__
3238 #define _stdcall  __attribute__((stdcall))
3239 #endif
3240
3241 int _stdcall
3242 WinMain (struct HINSTANCE__ *hInstance,
3243          struct HINSTANCE__ *hPrevInstance,
3244          char               *lpszCmdLine,
3245          int                 nCmdShow)
3246 {
3247 #if GTK_MAJOR_VERSION >= 2
3248   INITCOMMONCONTROLSEX comm_ctrl;
3249
3250   /* Initialize our controls. Required for native Windows file dialogs. */
3251   memset (&comm_ctrl, 0, sizeof(comm_ctrl));
3252   comm_ctrl.dwSize = sizeof(comm_ctrl);
3253   /* Includes the animate, header, hot key, list view, progress bar,
3254    * status bar, tab, tooltip, toolbar, trackbar, tree view, and
3255    * up-down controls
3256    */
3257   comm_ctrl.dwICC = ICC_WIN95_CLASSES;
3258   InitCommonControlsEx(&comm_ctrl);
3259
3260   /* RichEd20.DLL is needed for filter entries. */
3261   LoadLibrary(_T("riched20.dll"));
3262 #endif /* GTK_MAJOR_VERSION >= 2 */
3263
3264   has_console = FALSE;
3265   return main (__argc, __argv);
3266 }
3267
3268 /*
3269  * If this application has no console window to which its standard output
3270  * would go, create one.
3271  */
3272 void
3273 create_console(void)
3274 {
3275   if (!has_console) {
3276     /* We have no console to which to print the version string, so
3277        create one and make it the standard input, output, and error. */
3278     if (!AllocConsole())
3279       return;   /* couldn't create console */
3280     eth_freopen("CONIN$", "r", stdin);
3281     eth_freopen("CONOUT$", "w", stdout);
3282     eth_freopen("CONOUT$", "w", stderr);
3283
3284     /* Well, we have a console now. */
3285     has_console = TRUE;
3286
3287     /* Now register "destroy_console()" as a routine to be called just
3288        before the application exits, so that we can destroy the console
3289        after the user has typed a key (so that the console doesn't just
3290        disappear out from under them, giving the user no chance to see
3291        the message(s) we put in there). */
3292     atexit(destroy_console);
3293
3294     SetConsoleTitle(_T("Wireshark Debug Console"));
3295   }
3296 }
3297
3298 static void
3299 destroy_console(void)
3300 {
3301   if (has_console) {
3302     printf("\n\nPress any key to exit\n");
3303     _getch();
3304     FreeConsole();
3305   }
3306 }
3307 #endif /* _WIN32 */
3308
3309
3310 /* This routine should not be necessary, at least as I read the GLib
3311    source code, as it looks as if GLib is, on Win32, *supposed* to
3312    create a console window into which to display its output.
3313
3314    That doesn't happen, however.  I suspect there's something completely
3315    broken about that code in GLib-for-Win32, and that it may be related
3316    to the breakage that forces us to just call "printf()" on the message
3317    rather than passing the message on to "g_log_default_handler()"
3318    (which is the routine that does the aforementioned non-functional
3319    console window creation). */
3320 static void
3321 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
3322                     const char *message, gpointer user_data _U_)
3323 {
3324   time_t curr;
3325   struct tm *today;
3326   const char *level;
3327
3328
3329   /* ignore log message, if log_level isn't interesting.
3330      If preferences aren't loaded yet, display message anyway */
3331   if((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 &&
3332      prefs.console_log_level != 0) {
3333     return;
3334   }
3335
3336   /* create a "timestamp" */
3337   time(&curr);
3338   today = localtime(&curr);
3339
3340 #ifdef _WIN32
3341   if (prefs.gui_console_open != console_open_never || log_level & G_LOG_LEVEL_ERROR) {
3342     /* the user wants a console or the application will terminate immediately */
3343     create_console();
3344   }
3345   if (has_console) {
3346     /* For some unknown reason, the above doesn't appear to actually cause
3347        anything to be sent to the standard output, so we'll just splat the
3348        message out directly, just to make sure it gets out. */
3349 #endif
3350     switch(log_level & G_LOG_LEVEL_MASK) {
3351     case G_LOG_LEVEL_ERROR:
3352         level = "Err ";
3353         break;
3354     case G_LOG_LEVEL_CRITICAL:
3355         level = "Crit";
3356         break;
3357     case G_LOG_LEVEL_WARNING:
3358         level = "Warn";
3359         break;
3360     case G_LOG_LEVEL_MESSAGE:
3361         level = "Msg ";
3362         break;
3363     case G_LOG_LEVEL_INFO:
3364         level = "Info";
3365         break;
3366     case G_LOG_LEVEL_DEBUG:
3367         level = "Dbg ";
3368         break;
3369     default:
3370         fprintf(stderr, "unknown log_level %u\n", log_level);
3371         level = NULL;
3372         g_assert_not_reached();
3373     }
3374
3375     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
3376             today->tm_hour, today->tm_min, today->tm_sec,
3377             log_domain != NULL ? log_domain : "",
3378             level, message);
3379 #ifdef _WIN32
3380     if(log_level & G_LOG_LEVEL_ERROR) {
3381         /* wait for a key press before the following error handler will terminate the program
3382            this way the user at least can read the error message */
3383         printf("\n\nPress any key to exit\n");
3384         _getch();
3385     }
3386   } else {
3387     g_log_default_handler(log_domain, log_level, message, user_data);
3388   }
3389 #endif
3390 }
3391
3392
3393 static GtkWidget *info_bar_new(void)
3394 {
3395     int i;
3396
3397     /* tip: tooltips don't work on statusbars! */
3398     info_bar = gtk_statusbar_new();
3399     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
3400     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
3401     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
3402     filter_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "filter");
3403 #if GTK_MAJOR_VERSION >= 2
3404     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
3405 #endif
3406     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
3407
3408     for (i = 0; i < NUM_STATUS_LEVELS; i++) {
3409         status_levels[i] = 0;
3410     }
3411
3412     return info_bar;
3413 }
3414
3415 static GtkWidget *packets_bar_new(void)
3416 {
3417     /* tip: tooltips don't work on statusbars! */
3418     packets_bar = gtk_statusbar_new();
3419     packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
3420     packets_bar_update();
3421 #if GTK_MAJOR_VERSION >= 2
3422     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(packets_bar), FALSE);
3423 #endif
3424
3425     return packets_bar;
3426 }
3427
3428 static GtkWidget *profile_bar_new(void)
3429 {
3430     /* tip: tooltips don't work on statusbars! */
3431     profile_bar = gtk_statusbar_new();
3432     profile_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(profile_bar), "profile");
3433     profile_bar_update();
3434
3435     return profile_bar;
3436 }
3437
3438
3439 /*
3440  * Helper for main_widgets_rearrange()
3441  */
3442 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
3443     gtk_container_remove(GTK_CONTAINER(data), widget);
3444 }
3445
3446 static GtkWidget *main_widget_layout(gint layout_content)
3447 {
3448     switch(layout_content) {
3449     case(layout_pane_content_none):
3450         return NULL;
3451     case(layout_pane_content_plist):
3452         return pkt_scrollw;
3453     case(layout_pane_content_pdetails):
3454         return tv_scrollw;
3455     case(layout_pane_content_pbytes):
3456         return byte_nb_ptr;
3457     default:
3458         g_assert_not_reached();
3459         return NULL;
3460     }
3461 }
3462
3463
3464 /*
3465  * Rearrange the main window widgets
3466  */
3467 void main_widgets_rearrange(void) {
3468     GtkWidget *first_pane_widget1, *first_pane_widget2;
3469     GtkWidget *second_pane_widget1, *second_pane_widget2;
3470     gboolean split_top_left;
3471
3472     /* be a bit faster */
3473     gtk_widget_hide(main_vbox);
3474
3475     /* be sure, we don't loose a widget while rearranging */
3476     gtk_widget_ref(menubar);
3477     gtk_widget_ref(main_tb);
3478     gtk_widget_ref(filter_tb);
3479
3480 #ifdef HAVE_AIRPCAP
3481     gtk_widget_ref(airpcap_tb);
3482 #endif
3483
3484     gtk_widget_ref(pkt_scrollw);
3485     gtk_widget_ref(tv_scrollw);
3486     gtk_widget_ref(byte_nb_ptr);
3487     gtk_widget_ref(stat_hbox);
3488     gtk_widget_ref(info_bar);
3489     gtk_widget_ref(packets_bar);
3490     gtk_widget_ref(profile_bar);
3491     gtk_widget_ref(status_pane_left);
3492     gtk_widget_ref(status_pane_right);
3493     gtk_widget_ref(main_pane_v1);
3494     gtk_widget_ref(main_pane_v2);
3495     gtk_widget_ref(main_pane_h1);
3496     gtk_widget_ref(main_pane_h2);
3497     gtk_widget_ref(welcome_pane);
3498
3499     /* empty all containers participating */
3500     gtk_container_foreach(GTK_CONTAINER(main_vbox),     foreach_remove_a_child, main_vbox);
3501     gtk_container_foreach(GTK_CONTAINER(stat_hbox),     foreach_remove_a_child, stat_hbox);
3502     gtk_container_foreach(GTK_CONTAINER(status_pane_left),   foreach_remove_a_child, status_pane_left);
3503     gtk_container_foreach(GTK_CONTAINER(status_pane_right),   foreach_remove_a_child, status_pane_right);
3504     gtk_container_foreach(GTK_CONTAINER(main_pane_v1),  foreach_remove_a_child, main_pane_v1);
3505     gtk_container_foreach(GTK_CONTAINER(main_pane_v2),  foreach_remove_a_child, main_pane_v2);
3506     gtk_container_foreach(GTK_CONTAINER(main_pane_h1),  foreach_remove_a_child, main_pane_h1);
3507     gtk_container_foreach(GTK_CONTAINER(main_pane_h2),  foreach_remove_a_child, main_pane_h2);
3508
3509     /* add the menubar always at the top */
3510     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
3511
3512     /* main toolbar */
3513     gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
3514
3515     /* filter toolbar in toolbar area */
3516     if (!prefs.filter_toolbar_show_in_statusbar) {
3517         gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
3518     }
3519
3520 #ifdef HAVE_AIRPCAP
3521     /* airpcap toolbar */
3522     gtk_box_pack_start(GTK_BOX(main_vbox), airpcap_tb, FALSE, TRUE, 1);
3523 #endif
3524
3525     /* fill the main layout panes */
3526     switch(prefs.gui_layout_type) {
3527     case(layout_type_5):
3528         main_first_pane  = main_pane_v1;
3529         main_second_pane = main_pane_v2;
3530         split_top_left = FALSE;
3531         break;
3532     case(layout_type_2):
3533         main_first_pane  = main_pane_v1;
3534         main_second_pane = main_pane_h1;
3535         split_top_left = FALSE;
3536         break;
3537     case(layout_type_1):
3538         main_first_pane  = main_pane_v1;
3539         main_second_pane = main_pane_h1;
3540         split_top_left = TRUE;
3541         break;
3542     case(layout_type_4):
3543         main_first_pane  = main_pane_h1;
3544         main_second_pane = main_pane_v1;
3545         split_top_left = FALSE;
3546         break;
3547     case(layout_type_3):
3548         main_first_pane  = main_pane_h1;
3549         main_second_pane = main_pane_v1;
3550         split_top_left = TRUE;
3551         break;
3552     case(layout_type_6):
3553         main_first_pane  = main_pane_h1;
3554         main_second_pane = main_pane_h2;
3555         split_top_left = FALSE;
3556         break;
3557     default:
3558         main_first_pane = NULL;
3559         main_second_pane = NULL;
3560         split_top_left = FALSE;
3561         g_assert_not_reached();
3562     }
3563     if (split_top_left) {
3564         first_pane_widget1 = main_second_pane;
3565         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
3566         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
3567         first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
3568     } else {
3569         first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
3570         first_pane_widget2 = main_second_pane;
3571         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
3572         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
3573     }
3574     if (first_pane_widget1 != NULL)
3575         gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
3576     if (first_pane_widget2 != NULL)
3577         gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
3578     if (second_pane_widget1 != NULL)
3579         gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
3580     if (second_pane_widget2 != NULL)
3581         gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
3582
3583     gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
3584
3585     /* welcome pane */
3586     gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
3587
3588     /* statusbar hbox */
3589     gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
3590
3591     /* filter toolbar in statusbar hbox */
3592     if (prefs.filter_toolbar_show_in_statusbar) {
3593         gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
3594     }
3595
3596 #ifdef HAVE_AIRPCAP
3597     /* airpcap toolbar */
3598     gtk_box_pack_start(GTK_BOX(main_vbox), airpcap_tb, FALSE, TRUE, 1);
3599 #endif
3600
3601     /* statusbar */
3602     gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane_left, TRUE, TRUE, 0);
3603     gtk_paned_pack1(GTK_PANED(status_pane_left), info_bar, FALSE, FALSE);
3604     gtk_paned_pack2(GTK_PANED(status_pane_left), status_pane_right, TRUE, FALSE);
3605     gtk_paned_pack1(GTK_PANED(status_pane_right), packets_bar, TRUE, FALSE);
3606     gtk_paned_pack2(GTK_PANED(status_pane_right), profile_bar, FALSE, FALSE);
3607
3608     /* hide widgets on users recent settings */
3609     main_widgets_show_or_hide();
3610
3611     gtk_widget_show(main_vbox);
3612 }
3613
3614 static void
3615 is_widget_visible(GtkWidget *widget, gpointer data)
3616 {
3617     gboolean *is_visible = data;
3618
3619     if (!*is_visible) {
3620         if (GTK_WIDGET_VISIBLE(widget))
3621             *is_visible = TRUE;
3622     }
3623 }
3624
3625 /*#define SHOW_WELCOME_PAGE*/
3626 #ifdef SHOW_WELCOME_PAGE
3627 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
3628    As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
3629 GtkWidget *
3630 welcome_item(const gchar *stock_item, const gchar * label, const gchar * message, const gchar * tooltip,
3631                          GtkSignalFunc callback, void *callback_data)
3632 {
3633     GtkWidget *w, *item_hb;
3634 #if GTK_MAJOR_VERSION >= 2
3635     gchar *formatted_message;
3636     GtkTooltips *tooltips;
3637
3638     tooltips = gtk_tooltips_new();
3639 #endif
3640
3641     item_hb = gtk_hbox_new(FALSE, 1);
3642
3643     w = BUTTON_NEW_FROM_STOCK(stock_item);
3644     WIDGET_SET_SIZE(w, 80, 40);
3645 #if GTK_MAJOR_VERSION >= 2
3646     gtk_button_set_label(GTK_BUTTON(w), label);
3647     gtk_tooltips_set_tip(tooltips, w, tooltip, NULL);
3648 #endif
3649     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
3650     SIGNAL_CONNECT(w, "clicked", callback, callback_data);
3651
3652     w = gtk_label_new(message);
3653     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3654 #if GTK_MAJOR_VERSION >= 2
3655     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
3656     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
3657     g_free(formatted_message);
3658 #endif
3659
3660     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
3661
3662     return item_hb;
3663 }
3664
3665
3666 GtkWidget *
3667 welcome_header_new(void)
3668 {
3669     GtkWidget *item_vb;
3670     GtkWidget *item_hb;
3671     GtkWidget *eb;
3672     GdkColor bg;
3673     GtkWidget *icon;
3674     gchar *message;
3675     GtkWidget *w;
3676
3677
3678     /* background color of the header bar */
3679     bg.pixel = 0;
3680     bg.red = 154 * 255;
3681     bg.green = 210 * 255;
3682     bg.blue = 229 * 255;
3683
3684     item_vb = gtk_vbox_new(FALSE, 0);
3685
3686     /* colorize vbox */
3687     get_color(&bg);
3688     eb = gtk_event_box_new();
3689     gtk_container_add(GTK_CONTAINER(eb), item_vb);
3690 #if GTK_MAJOR_VERSION >= 2
3691     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &bg);
3692 #endif
3693
3694     item_hb = gtk_hbox_new(FALSE, 0);
3695     gtk_box_pack_start(GTK_BOX(item_vb), item_hb, FALSE, FALSE, 10);
3696
3697     icon = xpm_to_widget_from_parent(top_level, wssplash_xpm);
3698     /*icon = xpm_to_widget_from_parent(top_level, wsicon64_xpm);*/
3699     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 10);
3700
3701 #if GTK_MAJOR_VERSION < 2
3702     message = "The World's Most Popular Network Protocol Analyzer";
3703 #else
3704     message = "<span weight=\"bold\" size=\"x-large\">" "The World's Most Popular Network Protocol Analyzer" "</span>";
3705 #endif
3706     w = gtk_label_new(message);
3707 #if GTK_MAJOR_VERSION >= 2
3708     gtk_label_set_markup(GTK_LABEL(w), message);
3709 #endif
3710     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3711     gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3712
3713     gtk_widget_show_all(eb);
3714
3715     return eb;
3716 }
3717
3718 GtkWidget *
3719 welcome_topic_header_new(const char *header)
3720 {
3721     GtkWidget *w;
3722     GdkColor bg;
3723     GtkWidget *eb;
3724 #if GTK_MAJOR_VERSION >= 2
3725     gchar *formatted_message;
3726 #endif
3727
3728
3729     w = gtk_label_new(header);
3730 #if GTK_MAJOR_VERSION >= 2
3731     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", header);
3732     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
3733     g_free(formatted_message);
3734 #endif
3735
3736     /* topic header background color */
3737     bg.pixel = 0;
3738     bg.red = 24 * 255;
3739     bg.green = 151 * 255;
3740     bg.blue = 192 * 255;
3741
3742     /* colorize vbox */
3743     get_color(&bg);
3744     eb = gtk_event_box_new();
3745     gtk_container_add(GTK_CONTAINER(eb), w);
3746 #if GTK_MAJOR_VERSION >= 2
3747     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &bg);
3748 #endif
3749
3750     return eb;
3751 }
3752
3753
3754 GtkWidget *
3755 welcome_topic_new(const char *header, GtkWidget **to_fill)
3756 {
3757     GtkWidget *topic_vb;
3758     GtkWidget *layout_vb;
3759     GtkWidget *topic_eb;
3760     GtkWidget *topic_header;
3761     GdkColor bg;
3762
3763     topic_vb = gtk_vbox_new(FALSE, 0);
3764
3765         /* topic content background color */
3766     bg.pixel = 0;
3767     bg.red = 221 * 255;
3768     bg.green = 226 * 255;
3769     bg.blue = 228 * 255;
3770
3771     topic_header = welcome_topic_header_new(header);
3772     gtk_box_pack_start(GTK_BOX(topic_vb), topic_header, FALSE, FALSE, 0);
3773
3774     layout_vb = gtk_vbox_new(FALSE, 5);
3775     gtk_container_border_width(GTK_CONTAINER(layout_vb), 10);
3776     gtk_box_pack_start(GTK_BOX(topic_vb), layout_vb, FALSE, FALSE, 0);
3777
3778     /* colorize vbox (we need an event box for this!) */
3779     get_color(&bg);
3780     topic_eb = gtk_event_box_new();
3781     gtk_container_add(GTK_CONTAINER(topic_eb), topic_vb);
3782 #if GTK_MAJOR_VERSION >= 2
3783     gtk_widget_modify_bg(topic_eb, GTK_STATE_NORMAL, &bg);
3784 #endif
3785     *to_fill = layout_vb;
3786
3787     return topic_eb;
3788 }
3789
3790
3791 #if GTK_MAJOR_VERSION >= 2
3792 static gboolean
3793 welcome_link_enter_cb(GtkWidget *widget _U_, GdkEventCrossing *event _U_, gpointer user_data)
3794 {
3795     gchar *message;
3796     GtkWidget *w = user_data;
3797
3798     message = g_strdup_printf("<span foreground='blue' underline='single'>%s</span>", OBJECT_GET_DATA(w,"TEXT"));
3799 #if GTK_MAJOR_VERSION >= 2
3800     gtk_label_set_markup(GTK_LABEL(w), message);
3801 #endif
3802     g_free(message);
3803
3804     return FALSE;
3805 }
3806
3807 static gboolean
3808 welcome_link_leave_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer user_data)
3809 {
3810     gchar *message;
3811     GtkWidget *w = user_data;
3812
3813     message = g_strdup_printf("<span foreground='blue'>%s</span>", OBJECT_GET_DATA(w,"TEXT"));
3814 #if GTK_MAJOR_VERSION >= 2
3815     gtk_label_set_markup(GTK_LABEL(w), message);
3816 #endif
3817     g_free(message);
3818
3819     return FALSE;
3820 }
3821 #endif
3822
3823
3824 static gboolean
3825 welcome_link_press_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_) {
3826
3827     g_warning("TBD: link pressed");
3828
3829     return FALSE;
3830 }
3831
3832 GtkWidget *
3833 welcome_link_new(const gchar *text, GtkWidget **label /*, void *callback, void *private_data */)
3834 {
3835     gchar *message;
3836     GtkWidget *w;
3837     GtkWidget *eb;
3838
3839 #if GTK_MAJOR_VERSION < 2
3840     message = g_strdup(text);
3841 #else
3842     message = g_strdup_printf("<span foreground='blue'>%s</span>", text);
3843 #endif
3844     w = gtk_label_new(message);
3845     *label = w;
3846 #if GTK_MAJOR_VERSION >= 2
3847     gtk_label_set_markup(GTK_LABEL(w), message);
3848 #endif
3849     g_free(message);
3850
3851         /* event box */
3852     eb = gtk_event_box_new();
3853     gtk_container_add(GTK_CONTAINER(eb), w);
3854
3855 #if GTK_MAJOR_VERSION >= 2
3856     SIGNAL_CONNECT(eb, "enter-notify-event", welcome_link_enter_cb, w);
3857     SIGNAL_CONNECT(eb, "leave-notify-event", welcome_link_leave_cb, w);
3858 #endif
3859     SIGNAL_CONNECT(eb, "button-press-event", welcome_link_press_cb, w);
3860
3861     /* XXX - memleak */
3862     OBJECT_SET_DATA(w, "TEXT", g_strdup(text));
3863
3864     return eb;
3865 }
3866
3867 GtkWidget *
3868 welcome_filename_link_new(const char *filename, GtkWidget **label)
3869 {
3870     GString             *str;
3871     GtkWidget   *w;
3872     const unsigned int max = 60;
3873
3874
3875     str = g_string_new(filename);
3876
3877     if(str->len > max) {
3878         g_string_erase(str, 0, str->len-max /*cut*/);
3879         g_string_prepend(str, "... ");
3880     }
3881
3882     w = welcome_link_new(str->str, label);
3883
3884     g_string_free(str, TRUE);
3885
3886     return w;
3887 }
3888
3889
3890 GtkWidget *
3891 welcome_if_new(const char *if_name, GdkColor *topic_bg, gboolean active)
3892 {
3893     GtkWidget *interface_hb;
3894     GtkWidget *w;
3895     GtkWidget *label;
3896     GtkTooltips *tooltips;
3897     GString   *message;
3898
3899
3900     tooltips = gtk_tooltips_new();
3901
3902     interface_hb = gtk_hbox_new(FALSE, 5);
3903
3904     w = welcome_link_new("START", &label);
3905     gtk_tooltips_set_tip(tooltips, w, "Immediately start a capture on this interface", NULL);
3906 #if GTK_MAJOR_VERSION >= 2
3907     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, topic_bg);
3908 #endif
3909     gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
3910     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
3911
3912     w = welcome_link_new("OPTIONS", &label);
3913     gtk_tooltips_set_tip(tooltips, w, "Show the capture options of this interface", NULL);
3914 #if GTK_MAJOR_VERSION >= 2
3915     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, topic_bg);
3916 #endif
3917     gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
3918     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
3919
3920     w = welcome_link_new("DETAILS", &label);
3921     gtk_tooltips_set_tip(tooltips, w, "Show detailed information about this interface", NULL);
3922 #if GTK_MAJOR_VERSION >= 2
3923     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, topic_bg);
3924 #endif
3925     gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
3926     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
3927
3928     message = g_string_new(if_name);
3929
3930     /* truncate string if it's too long */
3931     if(message->len > 38) {
3932         g_string_truncate(message, 35);
3933         g_string_append  (message, " ...");
3934     }
3935 #if GTK_MAJOR_VERSION >= 2
3936     /* if this is the "active" interface, display it bold */
3937     if(active) {
3938         g_string_prepend(message, "<span weight=\"bold\">");
3939         g_string_append (message, "</span>");
3940         }
3941 #endif
3942     w = gtk_label_new(message->str);
3943 #if GTK_MAJOR_VERSION >= 2
3944     gtk_label_set_markup(GTK_LABEL(w), message->str);
3945 #endif
3946     g_string_free(message, TRUE);
3947
3948     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3949     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
3950
3951     return interface_hb;
3952 }
3953
3954 /* XXX - the layout has to be improved */
3955 GtkWidget *
3956 welcome_new(void)
3957 {
3958     GtkWidget *welcome_scrollw;
3959     GtkWidget *welcome_vb;
3960     GtkWidget *welcome_hb;
3961     GtkWidget *column_vb;
3962     GtkWidget *item_hb;
3963     GtkWidget *w;
3964     GtkWidget *label;
3965     GtkWidget *header;
3966     GtkWidget *topic_vb;
3967     GtkWidget *topic_to_fill;
3968     GtkWidget *interface_hb;
3969     GdkColor  topic_bg;
3970
3971
3972     /* topic content background color */
3973     topic_bg.pixel = 0;
3974     topic_bg.red = 221 * 255;
3975     topic_bg.green = 226 * 255;
3976     topic_bg.blue = 228 * 255;
3977
3978     welcome_scrollw = scrolled_window_new(NULL, NULL);
3979
3980     welcome_vb = gtk_vbox_new(FALSE, 0);
3981
3982     /* header */
3983     header = welcome_header_new();
3984     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
3985
3986     /* content */
3987     welcome_hb = gtk_hbox_new(FALSE, 10);
3988     gtk_container_border_width(GTK_CONTAINER(welcome_hb), 10);
3989     gtk_box_pack_start(GTK_BOX(welcome_vb), welcome_hb, TRUE, TRUE, 0);
3990
3991     /* column capture */
3992     column_vb = gtk_vbox_new(FALSE, 10);
3993     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
3994
3995     /* capture topic */
3996     topic_vb = welcome_topic_new("Capture", &topic_to_fill);
3997     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
3998
3999 #ifdef HAVE_LIBPCAP
4000     item_hb = welcome_item(WIRESHARK_STOCK_CAPTURE_INTERFACES,
4001         "Interfaces...",
4002         "Interface Life List",
4003                 "Show a life list of the available capture interfaces",
4004         GTK_SIGNAL_FUNC(capture_if_cb), NULL);
4005     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4006 #endif
4007
4008     w = gtk_label_new("Available Interfaces:");
4009     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
4010     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
4011
4012     interface_hb = welcome_if_new("Generic dialup adapter", &topic_bg, FALSE);
4013     gtk_box_pack_start(GTK_BOX(topic_to_fill), interface_hb, FALSE, FALSE, 0);
4014
4015     /* Marvell interface (currently "active") */
4016     interface_hb = welcome_if_new("Marvell Gigabit Ethernet Controller", &topic_bg, TRUE);
4017     gtk_box_pack_start(GTK_BOX(topic_to_fill), interface_hb, FALSE, FALSE, 0);
4018
4019     /* Wireless interface */
4020     interface_hb = welcome_if_new("Intel(R) PRO/Wireless 3945ABG Network Connection", &topic_bg, FALSE);
4021     gtk_box_pack_start(GTK_BOX(topic_to_fill), interface_hb, FALSE, FALSE, 0);
4022
4023
4024     /* capture help topic */
4025     topic_vb = welcome_topic_new("Capture Help", &topic_to_fill);
4026     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
4027
4028 #ifdef HAVE_LIBPCAP
4029     item_hb = welcome_item(WIRESHARK_STOCK_CAPTURE_START,
4030         "Setup",
4031                 "How To: Setup a Capture",
4032                 "How To: Setup a Capture (online from the Wiki)",
4033         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
4034     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4035
4036     item_hb = welcome_item(WIRESHARK_STOCK_CAPTURE_START,
4037         "Examples",
4038                 "Capture Filter Examples",
4039                 "Capture Filter Examples (online from the Wiki)",
4040         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
4041     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4042 #endif
4043
4044     /* fill bottom space */
4045     w = gtk_label_new("");
4046     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
4047
4048
4049     /* column files */
4050     topic_vb = welcome_topic_new("Files", &topic_to_fill);
4051     gtk_box_pack_start(GTK_BOX(welcome_hb), topic_vb, TRUE, TRUE, 0);
4052
4053     item_hb = welcome_item(GTK_STOCK_OPEN,
4054         "Open...",
4055         "Open a Capture File",
4056                 "Open a previously captured file",
4057         GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
4058     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4059
4060     item_hb = welcome_item(GTK_STOCK_OPEN,
4061         "Examples",
4062         "Download Examples",
4063                 "Download Example Capture Files (from the Wiki)",
4064         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
4065     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4066
4067     w = gtk_label_new("Recent Files:");
4068     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
4069     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
4070
4071     w = welcome_link_new("C:\\Testfiles\\hello.pcap", &label);
4072 #if GTK_MAJOR_VERSION >= 2
4073     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &topic_bg);
4074 #endif
4075     gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
4076     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 0);
4077
4078     w = welcome_filename_link_new("C:\\Testfiles\\hello2.pcap", &label);
4079 #if GTK_MAJOR_VERSION >= 2
4080     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &topic_bg);
4081 #endif
4082     gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
4083     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 0);
4084
4085     w = welcome_filename_link_new(
4086                 "C:\\Testfiles\\to avoid screen garbage\\Unfortunately this is a very long filename which had to be truncated.pcap",
4087                 &label);
4088 #if GTK_MAJOR_VERSION >= 2
4089     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &topic_bg);
4090 #endif
4091     gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
4092     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 0);
4093
4094     w = gtk_label_new("");
4095     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
4096
4097
4098     /* column online */
4099     column_vb = gtk_vbox_new(FALSE, 10);
4100     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
4101
4102     /* topic online */
4103     topic_vb = welcome_topic_new("Online", &topic_to_fill);
4104     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
4105
4106 #if (GLIB_MAJOR_VERSION >= 2)
4107     item_hb = welcome_item(WIRESHARK_STOCK_WEB_SUPPORT,
4108         "Help",
4109         "Show the User's Guide",
4110                 "Show the User's Guide (local version, if available)",
4111         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
4112     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4113
4114     item_hb = welcome_item(GTK_STOCK_HOME,
4115         "Home",
4116         "Projects Home Page",
4117                 "Visit www.wireshark.org, the project's home page",
4118         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
4119     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
4120 #endif
4121
4122     /* topic updates */
4123     topic_vb = welcome_topic_new("Updates", &topic_to_fill);
4124     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
4125
4126     w = gtk_label_new("No updates available!");
4127     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
4128
4129
4130     /* the end */
4131     gtk_widget_show_all(welcome_vb);
4132
4133     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
4134                                           welcome_vb);
4135     gtk_widget_show_all(welcome_scrollw);
4136
4137     return welcome_scrollw;
4138 }
4139 #else
4140 static GtkWidget *
4141 welcome_new(void)
4142 {
4143     /* this is just a dummy to fill up window space, simply showing nothing */
4144     return scrolled_window_new(NULL, NULL);
4145 }
4146 #endif
4147
4148
4149
4150 /*
4151  * XXX - this doesn't appear to work with the paned widgets in
4152  * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
4153  * and the other pane doesn't grow to take up the rest of the pane.
4154  * It does appear to work with GTK+ 2.x.
4155  */
4156 void
4157 main_widgets_show_or_hide(void)
4158 {
4159     gboolean main_second_pane_show;
4160
4161     if (recent.main_toolbar_show) {
4162         gtk_widget_show(main_tb);
4163     } else {
4164         gtk_widget_hide(main_tb);
4165     }
4166
4167     /*
4168      * Show the status hbox if either:
4169      *
4170      *    1) we're showing the filter toolbar and we want it in the status
4171      *       line
4172      *
4173      * or
4174      *
4175      *    2) we're showing the status bar.
4176      */
4177     if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
4178          recent.statusbar_show) {
4179         gtk_widget_show(stat_hbox);
4180     } else {
4181         gtk_widget_hide(stat_hbox);
4182     }
4183
4184     if (recent.statusbar_show) {
4185         gtk_widget_show(status_pane_left);
4186     } else {
4187         gtk_widget_hide(status_pane_left);
4188     }
4189
4190     if (recent.filter_toolbar_show) {
4191         gtk_widget_show(filter_tb);
4192     } else {
4193         gtk_widget_hide(filter_tb);
4194     }
4195
4196 #ifdef HAVE_AIRPCAP
4197     if (recent.airpcap_toolbar_show) {
4198         gtk_widget_show(airpcap_tb);
4199     } else {
4200         gtk_widget_hide(airpcap_tb);
4201     }
4202 #endif
4203
4204     if (recent.packet_list_show && have_capture_file) {
4205         gtk_widget_show(pkt_scrollw);
4206     } else {
4207         gtk_widget_hide(pkt_scrollw);
4208     }
4209
4210     if (recent.tree_view_show && have_capture_file) {
4211         gtk_widget_show(tv_scrollw);
4212     } else {
4213         gtk_widget_hide(tv_scrollw);
4214     }
4215
4216     if (recent.byte_view_show && have_capture_file) {
4217         gtk_widget_show(byte_nb_ptr);
4218     } else {
4219         gtk_widget_hide(byte_nb_ptr);
4220     }
4221
4222     if (have_capture_file) {
4223         gtk_widget_show(main_first_pane);
4224     } else {
4225         gtk_widget_hide(main_first_pane);
4226     }
4227
4228     /*
4229      * Is anything in "main_second_pane" visible?
4230      * If so, show it, otherwise hide it.
4231      */
4232     main_second_pane_show = FALSE;
4233     gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
4234                           &main_second_pane_show);
4235     if (main_second_pane_show) {
4236         gtk_widget_show(main_second_pane);
4237     } else {
4238         gtk_widget_hide(main_second_pane);
4239     }
4240
4241     if (!have_capture_file) {
4242         if(welcome_pane) {
4243             gtk_widget_show(welcome_pane);
4244         }
4245     } else {
4246         gtk_widget_hide(welcome_pane);
4247     }
4248
4249     /* workaround for bug in GtkCList to ensure packet list scrollbar is updated */
4250     packet_list_freeze ();
4251     packet_list_thaw ();
4252 }
4253
4254
4255 #if GTK_MAJOR_VERSION >= 2
4256 /* called, when the window state changes (minimized, maximized, ...) */
4257 static int
4258 window_state_event_cb (GtkWidget *widget _U_,
4259                        GdkEvent *event,
4260                        gpointer  data _U_)
4261 {
4262     GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
4263
4264     if( (event->type) == (GDK_WINDOW_STATE)) {
4265         if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
4266             /* we might have dialogs popped up while we where iconified,
4267                show em now */
4268             display_queued_messages();
4269         }
4270     }
4271     return FALSE;
4272 }
4273 #endif
4274
4275 #ifdef HAVE_AIRPCAP