fix 467: when using -k command line option, convert interface name display string...
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id$
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@ethereal.com>
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
35 #include <string.h>
36 #include <ctype.h>
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #ifdef HAVE_IO_H
43 #include <io.h> /* open/close on win32 */
44 #endif
45
46 #ifdef NEED_STRERROR_H
47 #include "strerror.h"
48 #endif
49
50 #ifdef NEED_GETOPT_H
51 #include "getopt.h"
52 #endif
53
54 #ifdef _WIN32 /* Needed for console I/O */
55 #include <fcntl.h>
56 #include <conio.h>
57 #endif
58
59 #include <epan/epan.h>
60 #include <epan/filesystem.h>
61 #include <epan/epan_dissect.h>
62 #include <epan/timestamp.h>
63 #include <epan/packet.h>
64 #include <epan/plugins.h>
65 #include <epan/dfilter/dfilter.h>
66 #include <epan/strutil.h>
67 #include <epan/addr_resolv.h>
68 #include <epan/emem.h>
69
70 /* general (not GTK specific) */
71 #include "file.h"
72 #include "summary.h"
73 #include "filters.h"
74 #include "disabled_protos.h"
75 #include <epan/prefs.h>
76 #include "filter_dlg.h"
77 #include "layout_prefs.h"
78 #include "color.h"
79 #include "color_filters.h"
80 #include "print.h"
81 #include "simple_dialog.h"
82 #include "register.h"
83 #include <epan/prefs-int.h>
84 #include "ringbuffer.h"
85 #include "../ui_util.h"
86 #include <epan/tap.h>
87 #include <epan/stat_cmd_args.h>
88 #include "util.h"
89 #include "clopts_common.h"
90 #include "version_info.h"
91 #include "merge.h"
92
93 #ifdef HAVE_LIBPCAP
94 #include <pcap.h>
95 #include "pcap-util.h"
96 #include "capture.h"
97 #endif
98
99 #ifdef _WIN32
100 #include "capture-wpcap.h"
101 #include "capture_wpcap_packet.h"
102 #endif
103
104 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
105 #include "ethclist.h"
106 #endif
107
108 /* GTK related */
109 #include "statusbar.h"
110 #include "alert_box.h"
111 #include "dlg_utils.h"
112 #include "gtkglobals.h"
113 #include "colors.h"
114 #include "gui_utils.h"
115 #include "compat_macros.h"
116
117 #include "main.h"
118 #include "menu.h"
119 #include "../main_window.h"
120 #include "../menu.h"
121 #include "file_dlg.h"
122 #include <epan/column.h>
123 #include "proto_draw.h"
124 #include "keys.h"
125 #include "packet_win.h"
126 #include "toolbar.h"
127 #include "find_dlg.h"
128 #include "packet_list.h"
129 #include "recent.h"
130 #include "follow_dlg.h"
131 #include "font_utils.h"
132 #include "about_dlg.h"
133 #include "help_dlg.h"
134 #include "decode_as_dlg.h"
135 #include "webbrowser.h"
136 #include "capture_dlg.h"
137 #if 0
138 #include "../image/eicon3d64.xpm"
139 #endif
140 #include "capture_ui_utils.h"
141 #include "log.h"
142 #include "../epan/emem.h"
143
144
145
146 /*
147  * Files under personal and global preferences directories in which
148  * GTK settings for Ethereal are stored.
149  */
150 #define RC_FILE "gtkrc"
151
152 #ifdef HAVE_LIBPCAP
153 #define DEF_READY_MESSAGE " Ready to load or capture"
154 #else
155 #define DEF_READY_MESSAGE " Ready to load file"
156 #endif
157
158 capture_file cfile;
159 GtkWidget   *main_display_filter_widget=NULL;
160 GtkWidget   *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
161 static GtkWidget   *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
162 static GtkWidget   *main_first_pane, *main_second_pane;
163 static GtkWidget   *status_pane;
164 static GtkWidget   *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
165 static GtkWidget        *info_bar;
166 static GtkWidget    *packets_bar = NULL;
167 static GtkWidget    *welcome_pane;
168 static guint    main_ctx, file_ctx, help_ctx;
169 static guint        packets_ctx;
170 static gchar        *packets_str = NULL;
171 GString *comp_info_str, *runtime_info_str;
172 gchar       *ethereal_path = NULL;
173 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
174
175 gboolean             capture_child; /* True if this is the child for "-S" */
176 #ifdef _WIN32
177 static gboolean has_console;    /* TRUE if app has console */
178 static void destroy_console(void);
179 #endif
180 static void console_log_handler(const char *log_domain,
181     GLogLevelFlags log_level, const char *message, gpointer user_data);
182
183 #ifdef HAVE_LIBPCAP
184 static gboolean list_link_layer_types;
185 capture_options global_capture_opts;
186 capture_options *capture_opts = &global_capture_opts;
187 #endif
188
189
190 static void create_main_window(gint, gint, gint, e_prefs*);
191 static void show_main_window(gboolean);
192 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
193 static void main_save_window_geometry(GtkWidget *widget);
194
195 #define E_DFILTER_CM_KEY          "display_filter_combo"
196 #define E_DFILTER_FL_KEY          "display_filter_list"
197
198
199
200 /* Match selected byte pattern */
201 static void
202 match_selected_cb_do(gpointer data, int action, gchar *text)
203 {
204     GtkWidget           *filter_te;
205     char                *cur_filter, *new_filter;
206
207     if (!text)
208         return;
209     g_assert(data);
210     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
211     g_assert(filter_te);
212
213     cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
214
215     switch (action&MATCH_SELECTED_MASK) {
216
217     case MATCH_SELECTED_REPLACE:
218         new_filter = g_strdup(text);
219         break;
220
221     case MATCH_SELECTED_AND:
222         if ((!cur_filter) || (0 == strlen(cur_filter)))
223             new_filter = g_strdup(text);
224         else
225             new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
226         break;
227
228     case MATCH_SELECTED_OR:
229         if ((!cur_filter) || (0 == strlen(cur_filter)))
230             new_filter = g_strdup(text);
231         else
232             new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
233         break;
234
235     case MATCH_SELECTED_NOT:
236         new_filter = g_strconcat("!(", text, ")", NULL);
237         break;
238
239     case MATCH_SELECTED_AND_NOT:
240         if ((!cur_filter) || (0 == strlen(cur_filter)))
241             new_filter = g_strconcat("!(", text, ")", NULL);
242         else
243             new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
244         break;
245
246     case MATCH_SELECTED_OR_NOT:
247         if ((!cur_filter) || (0 == strlen(cur_filter)))
248             new_filter = g_strconcat("!(", text, ")", NULL);
249         else
250             new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
251         break;
252
253     default:
254         g_assert_not_reached();
255         new_filter = NULL;
256         break;
257     }
258
259     /* Free up the copy we got of the old filter text. */
260     g_free(cur_filter);
261
262     /* create a new one and set the display filter entry accordingly */
263     gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
264
265     /* Run the display filter so it goes in effect. */
266     if (action&MATCH_SELECTED_APPLY_NOW)
267         main_filter_packets(&cfile, new_filter, FALSE);
268
269     /* Free up the new filter text. */
270     g_free(new_filter);
271 }
272
273 void
274 match_selected_ptree_cb(GtkWidget *w, gpointer data, MATCH_SELECTED_E action)
275 {
276     if (cfile.finfo_selected)
277         match_selected_cb_do((data ? data : w),
278             action,
279             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
280 }
281
282
283 static void selected_ptree_info_answered_cb(gpointer dialog _U_, gint btn, gpointer data)
284 {
285     gchar *selected_proto_url;
286     gchar *proto_abbrev = data;
287
288
289     switch(btn) {
290     case(ESD_BTN_OK):
291         if (cfile.finfo_selected) {
292             /* open wiki page using the protocol abbreviation */
293             selected_proto_url = g_strdup_printf("http://wiki.ethereal.com/Protocols/%s", proto_abbrev);
294             browser_open_url(selected_proto_url);
295             g_free(selected_proto_url);
296         }
297         break;
298     case(ESD_BTN_CANCEL):
299         break;
300     default:
301         g_assert_not_reached();
302     }
303 }
304
305
306 void 
307 selected_ptree_info_cb(GtkWidget *widget _U_, gpointer data _U_)
308 {
309     int field_id;
310     const gchar *proto_abbrev;
311     gpointer  dialog;
312
313
314     if (cfile.finfo_selected) {
315         /* convert selected field to protocol abbreviation */
316         /* XXX - could this conversion be simplified? */
317         field_id = cfile.finfo_selected->hfinfo->id;
318         /* if the selected field isn't a protocol, get it's parent */
319         if(!proto_registrar_is_protocol(field_id)) {
320             field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
321         }
322
323         proto_abbrev = proto_registrar_get_abbrev(field_id);
324
325         /* ask the user if the wiki page really should be opened */
326         dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_OK_CANCEL,
327                     PRIMARY_TEXT_START "Open Ethereal Wiki page of protocol \"%s\"?" PRIMARY_TEXT_END "\n"
328                     "\n"
329                     "This will open the \"%s\" related Ethereal Wiki page in your Web browser.\n"
330                     "\n"
331                     "The Ethereal Wiki is a collaborative approach to provide information\n"
332                     "about Ethereal in several ways (not limited to protocol specifics).\n"
333                     "\n"
334                     "This Wiki is new, so the page of the selected protocol\n"
335                     "may not exist and/or may not contain valuable information.\n"
336                     "\n"
337                     "As everyone can edit the Wiki and add new content (or extend existing),\n"
338                     "you are encouraged to add information if you can.\n"
339                     "\n"
340                     "Hint 1: If you are new to wiki editing, try out editing the Sandbox first!\n"
341                     "\n"
342                     "Hint 2: If you want to add a new protocol page, you should use the ProtocolTemplate,\n"
343                     "which will save you a lot of editing and will give a consistent look over the pages.",
344                     proto_abbrev, proto_abbrev);
345         simple_dialog_set_cb(dialog, selected_ptree_info_answered_cb, (gpointer) proto_abbrev);
346     }
347 }
348
349
350 void 
351 selected_ptree_ref_cb(GtkWidget *widget _U_, gpointer data _U_)
352 {
353     int field_id;
354     const gchar *proto_abbrev;
355     gchar *selected_proto_url;
356
357
358     if (cfile.finfo_selected) {
359         /* convert selected field to protocol abbreviation */
360         /* XXX - could this conversion be simplified? */
361         field_id = cfile.finfo_selected->hfinfo->id;
362         /* if the selected field isn't a protocol, get it's parent */
363         if(!proto_registrar_is_protocol(field_id)) {
364             field_id = proto_registrar_get_parent(cfile.finfo_selected->hfinfo->id);
365         }
366
367         proto_abbrev = proto_registrar_get_abbrev(field_id);
368
369         /* open reference page using the protocol abbreviation */
370         selected_proto_url = g_strdup_printf("http://www.ethereal.com/docs/dfref/%c/%s", proto_abbrev[0], proto_abbrev);
371         browser_open_url(selected_proto_url);
372         g_free(selected_proto_url);
373     }
374 }
375
376
377 static gchar *
378 get_text_from_packet_list(gpointer data)
379 {
380     gint        row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
381     gint        column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
382     frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
383     epan_dissect_t *edt;
384     gchar      *buf=NULL;
385     int         len;
386     int         err;
387     gchar       *err_info;
388
389     if (fdata != NULL) {
390         if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
391                        cfile.pd, fdata->cap_len, &err, &err_info)) {
392             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
393                           cf_read_error_message(err, err_info), cfile.filename);
394             return NULL;
395         }
396
397         edt = epan_dissect_new(FALSE, FALSE);
398         epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
399                          &cfile.cinfo);
400         epan_dissect_fill_in_columns(edt);
401
402         if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
403             strlen(cfile.cinfo.col_expr_val[column]) != 0) {
404             len = strlen(cfile.cinfo.col_expr[column]) +
405                   strlen(cfile.cinfo.col_expr_val[column]) + 5;
406             buf = ep_alloc0(len);
407             g_snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
408                      cfile.cinfo.col_expr_val[column]);
409         }
410
411         epan_dissect_free(edt);
412     }
413
414     return buf;
415 }
416
417 void
418 match_selected_plist_cb(GtkWidget *w _U_, gpointer data, MATCH_SELECTED_E action)
419 {
420     match_selected_cb_do(data,
421         action,
422         get_text_from_packet_list(data));
423 }
424
425
426
427 /* XXX: use a preference for this setting! */
428 static guint dfilter_combo_max_recent = 10;
429
430 /* add a display filter to the combo box */
431 /* Note: a new filter string will replace an old identical one */
432 static gboolean
433 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
434   GList     *li;
435   GList     *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
436
437
438   /* GtkCombos don't let us get at their list contents easily, so we maintain
439      our own filter list, and feed it to gtk_combo_set_popdown_strings when
440      a new filter is added. */
441     li = g_list_first(dfilter_list);
442     while (li) {
443         /* If the filter is already in the list, remove the old one and 
444                  * append the new one at the latest position (at g_list_append() below) */
445                 if (li->data && strcmp(s, li->data) == 0) {
446           dfilter_list = g_list_remove(dfilter_list, li->data);
447                   break;
448                 }
449       li = li->next;
450     }
451
452     dfilter_list = g_list_append(dfilter_list, s);
453     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
454     gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), dfilter_list);
455     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(dfilter_list)->data);
456
457     return TRUE;
458 }
459
460
461 /* write all non empty display filters (until maximum count) 
462  * of the combo box GList to the user's recent file */
463 void
464 dfilter_recent_combo_write_all(FILE *rf) {
465   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
466   GList     *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
467   GList     *li;
468   guint      max_count = 0;
469
470
471   /* write all non empty display filter strings to the recent file (until max count) */
472   li = g_list_first(dfilter_list);
473   while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
474     if (strlen(li->data)) {
475       fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
476     }
477     li = li->next;
478   }
479 }
480
481 /* empty the combobox entry field */
482 void
483 dfilter_combo_add_empty(void) {
484   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
485
486   gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
487 }
488
489
490 /* add a display filter coming from the user's recent file to the dfilter combo box */
491 gboolean
492 dfilter_combo_add_recent(gchar *s) {
493   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
494   char      *dup;
495
496   dup = g_strdup(s);
497   if (!dfilter_combo_add(filter_cm, dup)) {
498     g_free(dup);
499     return FALSE;
500   }
501
502   return TRUE;
503 }
504
505
506 /* call cf_filter_packets() and add this filter string to the recent filter list */
507 gboolean
508 main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force)
509 {
510   GtkCombo  *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
511   GList     *dfilter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
512   GList     *li;
513   gboolean   add_filter = TRUE;
514   gboolean   free_filter = TRUE;
515   char      *s;
516   cf_status_t cf_status;
517
518   /* we'll crash later on if dftext is NULL */
519   g_assert(dftext != NULL);
520   
521   s = g_strdup(dftext);
522
523   /* GtkCombos don't let us get at their list contents easily, so we maintain
524      our own filter list, and feed it to gtk_combo_set_popdown_strings when
525      a new filter is added. */
526   cf_status = cf_filter_packets(cf, s, force);
527   if (cf_status == CF_OK) {
528     li = g_list_first(dfilter_list);
529     while (li) {
530       if (li->data && strcmp(s, li->data) == 0)
531         add_filter = FALSE;
532       li = li->next;
533     }
534
535     if (add_filter) {
536       /* trim list size first */
537       while (g_list_length(dfilter_list) >= dfilter_combo_max_recent) {
538         dfilter_list = g_list_remove(dfilter_list, g_list_first(dfilter_list)->data);
539       }
540
541       free_filter = FALSE;
542       dfilter_list = g_list_append(dfilter_list, s);
543       OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
544       gtk_combo_set_popdown_strings(filter_cm, dfilter_list);
545       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(dfilter_list)->data);
546     }
547   }
548   if (free_filter)
549     g_free(s);
550
551   return (cf_status == CF_OK);
552 }
553
554
555 /* Run the current display filter on the current packet set, and
556    redisplay. */
557 static void
558 filter_activate_cb(GtkWidget *w _U_, gpointer data)
559 {
560   const char *s;
561
562   s = gtk_entry_get_text(GTK_ENTRY(data));
563
564   main_filter_packets(&cfile, s, FALSE);
565 }
566
567 /* redisplay with no display filter */
568 static void
569 filter_reset_cb(GtkWidget *w, gpointer data _U_)
570 {
571   GtkWidget *filter_te = NULL;
572
573   if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
574     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
575   }
576   main_filter_packets(&cfile, "", FALSE);
577 }
578
579 /* mark as reference time frame */
580 static void
581 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
582   if (row == -1)
583     return;
584   if (set) {
585     frame->flags.ref_time=1;
586   } else {
587     frame->flags.ref_time=0;
588   }
589   cf_reftime_packets(&cfile);
590 }
591
592 void 
593 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, REFTIME_ACTION_E action)
594 {
595
596   switch(action){
597   case REFTIME_TOGGLE:
598     if (cfile.current_frame) {
599       /* XXX hum, should better have a "cfile->current_row" here ... */
600       set_frame_reftime(!cfile.current_frame->flags.ref_time,
601                      cfile.current_frame,
602                      packet_list_find_row_from_data(cfile.current_frame));
603     }
604     break;
605   case REFTIME_FIND_NEXT:
606     find_previous_next_frame_with_filter("frame.ref_time", FALSE);
607     break;
608   case REFTIME_FIND_PREV:
609     find_previous_next_frame_with_filter("frame.ref_time", TRUE);
610     break;
611   }
612 }
613
614 #if GTK_MAJOR_VERSION < 2
615 static void
616 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
617                         gpointer user_data _U_)
618 #else
619 static void
620 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
621 #endif
622 {
623     field_info   *finfo;
624     gchar        *help_str = NULL;
625     gchar         len_str[2+10+1+5+1]; /* ", {N} bytes\0",
626                                           N < 4294967296 */
627     gboolean      has_blurb = FALSE;
628     guint         length = 0, byte_len;
629     GtkWidget    *byte_view;
630     const guint8 *byte_data;
631 #if GTK_MAJOR_VERSION >= 2
632     GtkTreeModel *model;
633     GtkTreeIter   iter;
634 #endif
635
636 #if GTK_MAJOR_VERSION >= 2
637     /* if nothing is selected */
638     if (!gtk_tree_selection_get_selected(sel, &model, &iter))
639     {
640         /*
641          * Which byte view is displaying the current protocol tree
642          * row's data?
643          */
644         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
645         if (byte_view == NULL)
646             return;     /* none */
647
648         byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
649         if (byte_data == NULL)
650             return;     /* none */
651
652         cf_unselect_field(&cfile);
653         packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
654                          cfile.current_frame, NULL, byte_len);
655         return;
656     }
657     gtk_tree_model_get(model, &iter, 1, &finfo, -1);
658 #else
659     g_assert(node);
660     finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
661 #endif
662     if (!finfo) return;
663
664     set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
665
666     byte_view = get_notebook_bv_ptr(byte_nb_ptr);
667     byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
668     g_assert(byte_data != NULL);
669
670     cfile.finfo_selected = finfo;
671     set_menus_for_selected_tree_row(&cfile);
672
673     if (finfo->hfinfo) {
674         if (finfo->hfinfo->blurb != NULL &&
675             finfo->hfinfo->blurb[0] != '\0') {
676             has_blurb = TRUE;
677             length = strlen(finfo->hfinfo->blurb);
678         } else {
679             length = strlen(finfo->hfinfo->name);
680         }
681         if (finfo->length == 0) {
682             len_str[0] = '\0';
683         } else if (finfo->length == 1) {
684             strcpy (len_str, ", 1 byte");
685         } else {
686             g_snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
687         }
688         statusbar_pop_field_msg();      /* get rid of current help msg */
689         if (length) {
690             help_str = g_strdup_printf("%s (%s)%s",
691                     (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
692                     finfo->hfinfo->abbrev, len_str);
693             statusbar_push_field_msg(help_str);
694             g_free(help_str);
695         } else {
696             /*
697              * Don't show anything if the field name is zero-length;
698              * the pseudo-field for "proto_tree_add_text()" is such
699              * a field, and we don't want "Text (text)" showing up
700              * on the status line if you've selected such a field.
701              *
702              * XXX - there are zero-length fields for which we *do*
703              * want to show the field name.
704              *
705              * XXX - perhaps the name and abbrev field should be null
706              * pointers rather than null strings for that pseudo-field,
707              * but we'd have to add checks for null pointers in some
708              * places if we did that.
709              *
710              * Or perhaps protocol tree items added with
711              * "proto_tree_add_text()" should have -1 as the field index,
712              * with no pseudo-field being used, but that might also
713              * require special checks for -1 to be added.
714              */
715             statusbar_push_field_msg("");
716         }
717     }
718
719 #if GTK_MAJOR_VERSION < 2
720     packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
721                      finfo, byte_len);
722 #else
723     packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
724                      finfo, byte_len);
725 #endif
726 }
727
728 #if GTK_MAJOR_VERSION < 2
729 static void
730 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
731                           gpointer user_data _U_)
732 {
733         GtkWidget       *byte_view;
734         const guint8    *data;
735         guint           len;
736
737         /*
738          * Which byte view is displaying the current protocol tree
739          * row's data?
740          */
741         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
742         if (byte_view == NULL)
743                 return; /* none */
744
745         data = get_byte_view_data_and_length(byte_view, &len);
746         if (data == NULL)
747                 return; /* none */
748
749         cf_unselect_field(&cfile);
750         packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
751                 NULL, len);
752 }
753 #endif
754
755 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
756   if (cfile.edt->tree)
757     collapse_all_tree(cfile.edt->tree, tree_view);
758 }
759
760 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
761   if (cfile.edt->tree)
762     expand_all_tree(cfile.edt->tree, tree_view);
763 }
764
765 void expand_tree_cb(GtkWidget *widget _U_, gpointer data _U_) {
766 #if GTK_MAJOR_VERSION < 2    
767   GtkCTreeNode *node;
768 #else
769   GtkTreePath  *path;
770 #endif
771
772 #if GTK_MAJOR_VERSION < 2
773   node = gtk_ctree_find_by_row_data(GTK_CTREE(tree_view), NULL, cfile.finfo_selected);
774   if(node) {
775     /* the mouse position is at an entry, expand that one */
776   gtk_ctree_expand_recursive(GTK_CTREE(tree_view), node);
777   }
778 #else
779   path = tree_find_by_field_info(GTK_TREE_VIEW(tree_view), cfile.finfo_selected);
780   if(path) {
781     /* the mouse position is at an entry, expand that one */
782   gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, TRUE);
783   gtk_tree_path_free(path);
784   }
785 #endif
786 }
787
788 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
789   if (cfile.edt->tree) {
790     guint32 tmp = g_resolv_flags;
791     g_resolv_flags = RESOLV_ALL;
792     proto_tree_draw(cfile.edt->tree, tree_view);
793     g_resolv_flags = tmp;
794   }
795 }
796
797 /*
798  * Push a message referring to file access onto the statusbar.
799  */
800 void
801 statusbar_push_file_msg(gchar *msg)
802 {
803     /*g_warning("statusbar_push: %s", msg);*/
804         gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
805 }
806
807 /*
808  * Pop a message referring to file access off the statusbar.
809  */
810 void
811 statusbar_pop_file_msg(void)
812 {
813     /*g_warning("statusbar_pop");*/
814         gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
815 }
816
817 /*
818  * XXX - do we need multiple statusbar contexts?
819  */
820
821 /*
822  * Push a message referring to the currently-selected field onto the statusbar.
823  */
824 void
825 statusbar_push_field_msg(gchar *msg)
826 {
827         gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
828 }
829
830 /*
831  * Pop a message referring to the currently-selected field off the statusbar.
832  */
833 void
834 statusbar_pop_field_msg(void)
835 {
836         gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
837 }
838
839 /*
840  * update the packets statusbar to the current values
841  */
842 void packets_bar_update(void)
843 {
844
845     if(packets_bar) {
846         /* remove old status */
847         if(packets_str) {
848             g_free(packets_str);
849                 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
850         }
851
852         /* do we have any packets? */
853         if(cfile.count) {
854             if(cfile.drops_known) {
855                 packets_str = g_strdup_printf(" P: %u D: %u M: %u Drops: %u", 
856                     cfile.count, cfile.displayed_count, cfile.marked_count, cfile.drops);
857             } else {
858                 packets_str = g_strdup_printf(" P: %u D: %u M: %u", 
859                     cfile.count, cfile.displayed_count, cfile.marked_count);
860             }
861         } else {
862             packets_str = g_strdup(" No Packets");
863         }
864             gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
865     }
866 }
867
868 void
869 main_set_for_capture_file(gboolean have_capture_file_in)
870 {
871     have_capture_file = have_capture_file_in;
872
873     main_widgets_show_or_hide();
874 }
875
876 gboolean
877 main_do_quit(void)
878 {
879         /* get the current geometry, before writing it to disk */
880         main_save_window_geometry(top_level);
881
882         /* write user's recent file to disk
883          * It is no problem to write this file, even if we do not quit */
884         write_recent();
885
886         /* XXX - should we check whether the capture file is an
887            unsaved temporary file for a live capture and, if so,
888            pop up a "do you want to exit without saving the capture
889            file?" dialog, and then just return, leaving said dialog
890            box to forcibly quit if the user clicks "OK"?
891
892            If so, note that this should be done in a subroutine that
893            returns TRUE if we do so, and FALSE otherwise, and if it
894            returns TRUE we should return TRUE without nuking anything.
895
896            Note that, if we do that, we might also want to check if
897            an "Update list of packets in real time" capture is in
898            progress and, if so, ask whether they want to terminate
899            the capture and discard it, and return TRUE, before nuking
900            any child capture, if they say they don't want to do so. */
901
902 #ifdef HAVE_LIBPCAP
903         /* Nuke any child capture in progress. */
904         capture_kill_child(capture_opts);
905 #endif
906
907         /* Are we in the middle of reading a capture? */
908         if (cfile.state == FILE_READ_IN_PROGRESS) {
909                 /* Yes, so we can't just close the file and quit, as
910                    that may yank the rug out from under the read in
911                    progress; instead, just set the state to
912                    "FILE_READ_ABORTED" and return - the code doing the read
913                    will check for that and, if it sees that, will clean
914                    up and quit. */
915                 cfile.state = FILE_READ_ABORTED;
916
917                 /* Say that the window should *not* be deleted;
918                    that'll be done by the code that cleans up. */
919                 return TRUE;
920         } else {
921                 /* Close any capture file we have open; on some OSes, you
922                    can't unlink a temporary capture file if you have it
923                    open.
924                    "cf_close()" will unlink it after closing it if
925                    it's a temporary file.
926
927                    We do this here, rather than after the main loop returns,
928                    as, after the main loop returns, the main window may have
929                    been destroyed (if this is called due to a "destroy"
930                    even on the main window rather than due to the user
931                    selecting a menu item), and there may be a crash
932                    or other problem when "cf_close()" tries to
933                    clean up stuff in the main window.
934
935                    XXX - is there a better place to put this?
936                    Or should we have a routine that *just* closes the
937                    capture file, and doesn't do anything with the UI,
938                    which we'd call here, and another routine that
939                    calls that routine and also cleans up the UI, which
940                    we'd call elsewhere? */
941                 cf_close(&cfile);
942
943                 /* Exit by leaving the main loop, so that any quit functions
944                    we registered get called. */
945                 gtk_main_quit();
946
947                 /* Say that the window should be deleted. */
948                 return FALSE;
949         }
950 }
951
952 static gboolean
953 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
954 {
955   gpointer dialog;
956
957   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
958 #if GTK_MAJOR_VERSION >= 2
959     gtk_window_present(GTK_WINDOW(top_level));
960 #endif
961     /* user didn't saved his current file, ask him */
962     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
963                 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
964                 "If you quit the program without saving, your capture data will be discarded.");
965     simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
966     return TRUE;
967   } else {
968     /* unchanged file, just exit */
969     /* "main_do_quit()" indicates whether the main window should be deleted. */
970     return main_do_quit();
971   }
972 }
973
974
975
976 static void
977 main_load_window_geometry(GtkWidget *widget)
978 {
979     window_geometry_t geom;
980
981     geom.set_pos        = prefs.gui_geometry_save_position;
982     geom.x              = recent.gui_geometry_main_x;
983     geom.y              = recent.gui_geometry_main_y;
984     geom.set_size       = prefs.gui_geometry_save_size;
985     if (recent.gui_geometry_main_width > 0 &&
986         recent.gui_geometry_main_height > 0) {
987         geom.width          = recent.gui_geometry_main_width;
988         geom.height         = recent.gui_geometry_main_height;
989         geom.set_maximized  = prefs.gui_geometry_save_maximized;
990     } else {
991         /* We assume this means the width and height weren't set in
992            the "recent" file (or that there is no "recent" file),
993            and weren't set to a default value, so we don't set the
994            size.  (The "recent" file code rejects non-positive width
995            and height values.) */
996        geom.set_size = FALSE;
997     }
998     geom.maximized      = recent.gui_geometry_main_maximized;
999
1000     window_set_geometry(widget, &geom);
1001
1002     if (recent.has_gui_geometry_main_upper_pane && recent.gui_geometry_main_upper_pane)
1003         gtk_paned_set_position(GTK_PANED(main_first_pane),  recent.gui_geometry_main_upper_pane);
1004     if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_main_lower_pane)
1005         gtk_paned_set_position(GTK_PANED(main_second_pane), recent.gui_geometry_main_lower_pane);
1006     if (recent.has_gui_geometry_main_lower_pane && recent.gui_geometry_status_pane)
1007         gtk_paned_set_position(GTK_PANED(status_pane),      recent.gui_geometry_status_pane);
1008 }
1009
1010
1011 static void
1012 main_save_window_geometry(GtkWidget *widget)
1013 {
1014     window_geometry_t geom;
1015
1016     window_get_geometry(widget, &geom);
1017
1018     if (prefs.gui_geometry_save_position) {
1019         recent.gui_geometry_main_x = geom.x;
1020             recent.gui_geometry_main_y = geom.y;
1021     }
1022
1023     if (prefs.gui_geometry_save_size) {
1024         recent.gui_geometry_main_width  = geom.width, 
1025         recent.gui_geometry_main_height = geom.height;
1026     }
1027
1028 #if GTK_MAJOR_VERSION >= 2
1029     if(prefs.gui_geometry_save_maximized) {
1030         recent.gui_geometry_main_maximized = geom.maximized;
1031     }
1032
1033     recent.gui_geometry_main_upper_pane     = gtk_paned_get_position(GTK_PANED(main_first_pane));
1034     recent.gui_geometry_main_lower_pane     = gtk_paned_get_position(GTK_PANED(main_second_pane));
1035     recent.gui_geometry_status_pane         = gtk_paned_get_position(GTK_PANED(status_pane));
1036 #endif
1037 }
1038
1039 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1040 {
1041     switch(btn) {
1042     case(ESD_BTN_SAVE):
1043         /* save file first */
1044         file_save_as_cmd(after_save_exit, NULL);
1045         break;
1046     case(ESD_BTN_DONT_SAVE):
1047         main_do_quit();
1048         break;
1049     case(ESD_BTN_CANCEL):
1050         break;
1051     default:
1052         g_assert_not_reached();
1053     }
1054 }
1055
1056 void
1057 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1058 {
1059   gpointer dialog;
1060
1061   if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
1062     /* user didn't saved his current file, ask him */
1063     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_SAVE_DONTSAVE_CANCEL,
1064                 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1065                 "If you quit the program without saving, your capture data will be discarded.");
1066     simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1067   } else {
1068     /* unchanged file, just exit */
1069     main_do_quit();
1070   }
1071 }
1072
1073 static void
1074 print_usage(gboolean print_ver) {
1075
1076   FILE *output;
1077
1078 #ifdef _WIN32
1079   create_console();
1080 #endif
1081
1082   if (print_ver) {
1083     output = stdout;
1084     fprintf(output, "This is "PACKAGE " " VERSION "%s"
1085         "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
1086         "\n\n%s\n\n%s\n",
1087         svnversion, comp_info_str->str, runtime_info_str->str);
1088   } else {
1089     output = stderr;
1090   }
1091 #ifdef HAVE_LIBPCAP
1092   fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);        
1093   fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
1094   fprintf(output, "\t[ -B capture buffer size (Win32 only) ]\n"); 
1095   fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
1096   fprintf(output, "\t[ -g <packet number> ]\n");
1097   fprintf(output, "\t[ -i <capture interface> ] [ -m <font> ] [ -N <name resolving flags> ]\n");
1098   fprintf(output, "\t[ -o <preference/recent setting> ] ...\n");
1099   fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
1100   fprintf(output, "\t[ -t <time stamp format> ]\n");
1101   fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
1102   fprintf(output, "\t[ <infile> ]\n");
1103 #else
1104   fprintf(output, "\n%s [ -vh ] [ -n ] [ -g <packet number> ] [ -m <font> ]\n", PACKAGE);
1105   fprintf(output, "\t[ -N <resolving flags> ] [ -o <preference/recent setting> ...\n");
1106   fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ]\n");
1107   fprintf(output, "\t[ -t <time stamp format> ]\n");
1108   fprintf(output, "\t[ -z <statistics ] [ <infile> ]\n");
1109 #endif
1110
1111 #ifdef _WIN32
1112   destroy_console();
1113 #endif
1114 }
1115
1116 static void
1117 show_version(void)
1118 {
1119 #ifdef _WIN32
1120   create_console();
1121 #endif
1122
1123   printf(PACKAGE " " VERSION "%s\n\n%s\n\n%s\n",
1124       svnversion, comp_info_str->str, runtime_info_str->str);
1125
1126 #ifdef _WIN32
1127   destroy_console();
1128 #endif
1129 }
1130
1131 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1132 /* 
1133    Once every 3 seconds we get a callback here which we use to update
1134    the tap extensions. Since Gtk1 is single threaded we dont have to
1135    worry about any locking or critical regions.
1136  */
1137 static gint
1138 update_cb(gpointer data _U_)
1139 {
1140         draw_tap_listeners(FALSE);
1141         return 1;
1142 }
1143 #else
1144
1145 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1146    use threads all updte_thread_mutex can be dropped and protect/unprotect 
1147    would just be empty functions.
1148
1149    This allows gtk2-rpcstat.c and friends to be copied unmodified to 
1150    gtk1-ethereal and it will just work.
1151  */
1152 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1153 gpointer
1154 update_thread(gpointer data _U_)
1155 {
1156     while(1){
1157         GTimeVal tv1, tv2;
1158         g_get_current_time(&tv1);
1159         g_static_mutex_lock(&update_thread_mutex);
1160         gdk_threads_enter();
1161         draw_tap_listeners(FALSE);
1162         gdk_threads_leave();
1163         g_static_mutex_unlock(&update_thread_mutex);
1164         g_thread_yield();
1165         g_get_current_time(&tv2);
1166         if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1167             (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1168             g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1169                      (tv2.tv_sec * 1000000 + tv2.tv_usec));
1170         }
1171     }
1172     return NULL;
1173 }
1174 #endif
1175 void
1176 protect_thread_critical_region(void)
1177 {
1178 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1179     g_static_mutex_lock(&update_thread_mutex);
1180 #endif
1181 }
1182 void
1183 unprotect_thread_critical_region(void)
1184 {
1185 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1186     g_static_mutex_unlock(&update_thread_mutex);
1187 #endif
1188 }
1189
1190 /* Set the file name in the status line, in the name for the main window,
1191    and in the name for the main window's icon. */
1192 static void
1193 set_display_filename(capture_file *cf)
1194 {
1195   const gchar *name_ptr;
1196   gchar       *status_msg;
1197   gchar       *size_str;
1198   gchar       *win_name;
1199
1200   name_ptr = cf_get_display_name(cf);
1201         
1202   if (!cf->is_tempfile && cf->filename) {
1203     /* Add this filename to the list of recent files in the "Recent Files" submenu */
1204     add_menu_recent_capture_file(cf->filename);
1205   }
1206
1207   /* convert file size */
1208   if (cf->f_datalen/1024/1024 > 10) {
1209     size_str = g_strdup_printf("%ld MB", cf->f_datalen/1024/1024);
1210   } else if (cf->f_datalen/1024 > 10) {
1211     size_str = g_strdup_printf("%ld KB", cf->f_datalen/1024);
1212   } else {
1213     size_str = g_strdup_printf("%ld Bytes", cf->f_datalen);
1214   }
1215
1216   /* statusbar */
1217   status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu", 
1218     (cf->filename) ? cf->filename : "", size_str,
1219     (long)cf->elapsed_time.secs/3600,
1220     (long)cf->elapsed_time.secs%3600/60,
1221     (long)cf->elapsed_time.secs%60);
1222   g_free(size_str);
1223   statusbar_push_file_msg(status_msg);
1224   g_free(status_msg);
1225
1226   /* window title */
1227   win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1228   set_main_window_name(win_name);
1229   g_free(win_name);
1230 }
1231
1232 GtkWidget           *close_dlg = NULL;
1233
1234 static void
1235 main_cf_cb_file_closing(capture_file *cf)
1236 {
1237
1238         /* if we have more than 10000 packets, show a splash screen while closing */
1239         /* XXX - don't know a better way to decide wether to show or not,
1240          * as most of the time is spend in a single eth_clist_clear function, 
1241          * so we can't use a progress bar here! */
1242         if(cf->count > 10000) {
1243                 close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sClosing file!%s\n\nPlease wait ...", 
1244                         simple_dialog_primary_start(), simple_dialog_primary_end());
1245 #if GTK_MAJOR_VERSION >= 2
1246                 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1247 #else
1248                 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
1249 #endif
1250         }
1251
1252     /* Destroy all windows, which refer to the
1253        capture file we're closing. */
1254     destroy_cfile_wins();
1255
1256     /* Clear any file-related status bar messages.
1257        XXX - should be "clear *ALL* file-related status bar messages;
1258        will there ever be more than one on the stack? */
1259     statusbar_pop_file_msg();
1260
1261     /* go back to "No packets" */
1262     packets_bar_update();
1263
1264     /* Restore the standard title bar message. */
1265     set_main_window_name("The Ethereal Network Analyzer");
1266
1267     /* Disable all menu items that make sense only if you have a capture. */
1268     set_menus_for_capture_file(FALSE);
1269     set_menus_for_unsaved_capture_file(FALSE);
1270     set_menus_for_captured_packets(FALSE);
1271     set_menus_for_selected_packet(cf);
1272     set_menus_for_capture_in_progress(FALSE);
1273     set_menus_for_selected_tree_row(cf);
1274
1275     /* Set up main window for no capture file. */
1276     main_set_for_capture_file(FALSE);
1277
1278     main_window_update();
1279 }
1280
1281 static void
1282 main_cf_cb_file_closed(capture_file *cf _U_)
1283 {
1284   if(close_dlg != NULL) {
1285     splash_destroy(close_dlg);
1286     close_dlg = NULL;
1287   }
1288 }
1289
1290 static void
1291 main_cf_cb_file_read_start(capture_file *cf)
1292 {
1293   const gchar *name_ptr;
1294   gchar       *load_msg;
1295
1296   name_ptr = get_basename(cf->filename);
1297
1298   load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1299   statusbar_push_file_msg(load_msg);
1300   g_free(load_msg);
1301 }
1302
1303 static void
1304 main_cf_cb_file_read_finished(capture_file *cf)
1305 {
1306     statusbar_pop_file_msg();
1307     set_display_filename(cf);
1308
1309     /* Enable menu items that make sense if you have a capture file you've
1310      finished reading. */
1311     set_menus_for_capture_file(TRUE);
1312     set_menus_for_unsaved_capture_file(!cf->user_saved);
1313
1314     /* Enable menu items that make sense if you have some captured packets. */
1315     set_menus_for_captured_packets(TRUE);
1316
1317     /* Set up main window for a capture file. */
1318     main_set_for_capture_file(TRUE);
1319 }
1320
1321 #ifdef HAVE_LIBPCAP
1322 static void
1323 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1324 {
1325     gchar *title;
1326
1327
1328     if(capture_opts->iface) {
1329         title = g_strdup_printf("%s: Capturing - Ethereal",
1330                             get_interface_descriptive_name(capture_opts->iface));
1331     } else {
1332         title = g_strdup_printf("Capturing - Ethereal");
1333     }
1334     set_main_window_name(title);
1335     g_free(title);
1336
1337     /* Disable menu items that make no sense if you're currently running
1338        a capture. */
1339     set_menus_for_capture_in_progress(TRUE);
1340
1341     /* update statusbar */
1342     statusbar_push_file_msg("Waiting for capture input data ...");
1343
1344     /* Don't set up main window for a capture file. */
1345     main_set_for_capture_file(FALSE);
1346 }
1347
1348 static void
1349 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1350 {
1351     gchar *capture_msg;
1352
1353
1354     /* Enable menu items that make sense if you have some captured
1355        packets (yes, I know, we don't have any *yet*). */
1356     set_menus_for_captured_packets(TRUE);
1357
1358     statusbar_pop_file_msg();
1359
1360     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s", 
1361         get_interface_descriptive_name(capture_opts->iface), 
1362         (capture_opts->save_file) ? capture_opts->save_file : "");
1363
1364     statusbar_push_file_msg(capture_msg);
1365
1366     g_free(capture_msg);
1367
1368     /* Set up main window for a capture file. */
1369     main_set_for_capture_file(TRUE);
1370 }
1371
1372 static void
1373 main_cf_cb_live_capture_update_continue(capture_file *cf)
1374 {
1375     gchar *capture_msg;
1376
1377
1378     statusbar_pop_file_msg();
1379
1380     if (cf->f_datalen/1024/1024 > 10) {
1381         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB", 
1382             get_interface_descriptive_name(capture_opts->iface), 
1383             capture_opts->save_file,
1384             cf->f_datalen/1024/1024);
1385     } else if (cf->f_datalen/1024 > 10) {
1386         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB", 
1387             get_interface_descriptive_name(capture_opts->iface), 
1388             capture_opts->save_file,
1389             cf->f_datalen/1024);
1390     } else {
1391         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes", 
1392             get_interface_descriptive_name(capture_opts->iface), 
1393             capture_opts->save_file,
1394             cf->f_datalen);
1395     }
1396
1397     statusbar_push_file_msg(capture_msg);
1398 }
1399
1400 GtkWidget * stop_dlg = NULL;
1401
1402 static void
1403 main_cf_cb_live_capture_update_finished(capture_file *cf)
1404 {
1405         if(stop_dlg != NULL) {
1406                 simple_dialog_close(stop_dlg);
1407                 stop_dlg = NULL;
1408         }
1409
1410     /* Pop the "<live capture in progress>" message off the status bar. */
1411     statusbar_pop_file_msg();
1412
1413     set_display_filename(cf);
1414
1415     /* Enable menu items that make sense if you're not currently running
1416      a capture. */
1417     set_menus_for_capture_in_progress(FALSE);
1418
1419     /* Enable menu items that make sense if you have a capture file
1420      you've finished reading. */
1421     set_menus_for_capture_file(TRUE);
1422     set_menus_for_unsaved_capture_file(!cf->user_saved);
1423
1424     /* Set up main window for a capture file. */
1425     main_set_for_capture_file(TRUE);
1426 }
1427
1428 static void
1429 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1430 {
1431     gchar *capture_msg;
1432
1433
1434     /* Enable menu items that make sense if you have some captured
1435        packets (yes, I know, we don't have any *yet*). */
1436     /*set_menus_for_captured_packets(TRUE);*/
1437
1438     statusbar_pop_file_msg();
1439
1440     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s", 
1441         get_interface_descriptive_name(capture_opts->iface), 
1442         (capture_opts->save_file) ? capture_opts->save_file : "");
1443
1444     statusbar_push_file_msg(capture_msg);
1445     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " <capturing>");
1446
1447     g_free(capture_msg);
1448
1449     /* Don't set up main window for a capture file. */
1450     main_set_for_capture_file(FALSE);
1451 }
1452
1453 static void
1454 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1455 {
1456         if(stop_dlg != NULL) {
1457                 simple_dialog_close(stop_dlg);
1458                 stop_dlg = NULL;
1459         }
1460
1461     /* Pop the "<live capture in progress>" message off the status bar. */
1462     statusbar_pop_file_msg();
1463
1464     /* Pop the "<capturing>" message off the status bar */
1465         gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1466
1467     /*set_display_filename(cf);*/
1468
1469     /* Enable menu items that make sense if you're not currently running
1470      a capture. */
1471     set_menus_for_capture_in_progress(FALSE);
1472
1473     /* We don't have loaded the capture file, this will be done later.
1474      * For now we still have simply a blank screen. */
1475 }
1476
1477 static void
1478 main_cf_cb_live_capture_stopping(capture_file *cf _U_)
1479 {
1480     stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...", 
1481                 simple_dialog_primary_start(), simple_dialog_primary_end());
1482 #if GTK_MAJOR_VERSION >= 2
1483         gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1484 #else
1485         gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1486 #endif
1487 }
1488
1489 #endif
1490
1491 static void
1492 main_cf_cb_packet_selected(gpointer data)
1493 {
1494     capture_file *cf = data;
1495
1496     /* Display the GUI protocol tree and hex dump.
1497       XXX - why do we dump core if we call "proto_tree_draw()"
1498       before calling "add_byte_views()"? */
1499     add_main_byte_views(cf->edt);
1500     main_proto_tree_draw(cf->edt->tree);
1501
1502     /* A packet is selected. */
1503     set_menus_for_selected_packet(cf);
1504 }
1505
1506 static void
1507 main_cf_cb_packet_unselected(capture_file *cf)
1508 {
1509     /* Clear out the display of that packet. */
1510     clear_tree_and_hex_views();
1511
1512     /* No packet is selected. */
1513     set_menus_for_selected_packet(cf);
1514 }
1515
1516 static void
1517 main_cf_cb_field_unselected(capture_file *cf)
1518 {
1519     statusbar_pop_field_msg();
1520     set_menus_for_selected_tree_row(cf);
1521 }
1522
1523 static void
1524 main_cf_cb_file_safe_started(gchar * filename)
1525 {
1526     const gchar  *name_ptr;
1527     gchar        *save_msg;
1528
1529     name_ptr = get_basename(filename);
1530
1531     save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1532
1533     statusbar_push_file_msg(save_msg);
1534     g_free(save_msg);
1535 }
1536
1537 static void
1538 main_cf_cb_file_safe_finished(gpointer data _U_)
1539 {
1540     /* Pop the "Saving:" message off the status bar. */
1541     statusbar_pop_file_msg();
1542 }
1543
1544 static void
1545 main_cf_cb_file_safe_failed(gpointer data _U_)
1546 {
1547     /* Pop the "Saving:" message off the status bar. */
1548     statusbar_pop_file_msg();
1549 }
1550
1551 static void
1552 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1553 {
1554     set_menus_for_unsaved_capture_file(FALSE);
1555 }
1556
1557 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1558 {
1559     switch(event) {
1560     case(cf_cb_file_closing):
1561         main_cf_cb_file_closing(data);
1562         break;
1563     case(cf_cb_file_closed):
1564         main_cf_cb_file_closed(data);
1565         break;
1566     case(cf_cb_file_read_start):
1567         main_cf_cb_file_read_start(data);
1568         break;
1569     case(cf_cb_file_read_finished):
1570         main_cf_cb_file_read_finished(data);
1571         break;
1572 #ifdef HAVE_LIBPCAP
1573     case(cf_cb_live_capture_prepared):
1574         main_cf_cb_live_capture_prepared(data);
1575         break;
1576     case(cf_cb_live_capture_update_started):
1577         main_cf_cb_live_capture_update_started(data);
1578         break;
1579     case(cf_cb_live_capture_update_continue):
1580         main_cf_cb_live_capture_update_continue(data);
1581         break;
1582     case(cf_cb_live_capture_fixed_started):
1583         main_cf_cb_live_capture_fixed_started(data);
1584         break;
1585     case(cf_cb_live_capture_update_finished):
1586         main_cf_cb_live_capture_update_finished(data);
1587         break;
1588     case(cf_cb_live_capture_fixed_finished):
1589         main_cf_cb_live_capture_fixed_finished(data);
1590         break;
1591     case(cf_cb_live_capture_stopping):
1592         main_cf_cb_live_capture_stopping(data);
1593         break;
1594 #endif
1595     case(cf_cb_packet_selected):
1596         main_cf_cb_packet_selected(data);
1597         break;
1598     case(cf_cb_packet_unselected):
1599         main_cf_cb_packet_unselected(data);
1600         break;
1601     case(cf_cb_field_unselected):
1602         main_cf_cb_field_unselected(data);
1603         break;
1604     case(cf_cb_file_safe_started):
1605         main_cf_cb_file_safe_started(data);
1606         break;
1607     case(cf_cb_file_safe_finished):
1608         main_cf_cb_file_safe_finished(data);
1609         break;
1610     case(cf_cb_file_safe_reload_finished):
1611         main_cf_cb_file_safe_reload_finished(data);
1612         break;
1613     case(cf_cb_file_safe_failed):
1614         main_cf_cb_file_safe_failed(data);
1615         break;
1616     default:
1617         g_warning("main_cf_callback: event %u unknown", event);
1618         g_assert_not_reached();
1619     }
1620 }
1621
1622 /* And now our feature presentation... [ fade to music ] */
1623 int
1624 main(int argc, char *argv[])
1625 {
1626 #ifdef HAVE_LIBPCAP
1627   const char          *command_name;
1628 #endif
1629   char                *s;
1630   int                  i;
1631   int                  opt;
1632   extern char         *optarg;
1633   gboolean             arg_error = FALSE;
1634
1635 #ifdef _WIN32
1636   WSADATA              wsaData;
1637 #endif  /* _WIN32 */
1638
1639   char                *rf_path;
1640   int                  rf_open_errno;
1641   char                *gpf_path, *pf_path;
1642   char                *cf_path, *df_path;
1643   char                *gdp_path, *dp_path;
1644   int                  gpf_open_errno, gpf_read_errno;
1645   int                  pf_open_errno, pf_read_errno;
1646   int                  cf_open_errno, df_open_errno;
1647   int                  gdp_open_errno, gdp_read_errno;
1648   int                  dp_open_errno, dp_read_errno;
1649   int                  err;
1650 #ifdef HAVE_LIBPCAP
1651   gboolean             start_capture = FALSE;
1652   GList               *if_list;
1653   if_info_t           *if_info;
1654   GList               *lt_list, *lt_entry;
1655   data_link_info_t    *data_link_info;
1656   gchar                err_str[PCAP_ERRBUF_SIZE];
1657   gchar               *cant_get_if_list_errstr;
1658   gboolean             stats_known;
1659   struct pcap_stat     stats;
1660 #else
1661   gboolean             capture_option_specified = FALSE;
1662 #endif
1663   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1664   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1665   dfilter_t           *rfcode = NULL;
1666   gboolean             rfilter_parse_failed = FALSE;
1667   e_prefs             *prefs;
1668   char                 badopt;
1669   GtkWidget           *splash_win = NULL;
1670   GLogLevelFlags       log_flags;
1671   guint                go_to_packet = 0;
1672   int                  optind_initial;
1673
1674 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1675
1676 #ifdef HAVE_LIBPCAP
1677 #ifdef _WIN32
1678 #define OPTSTRING_CHILD "W:Z:"
1679 #define OPTSTRING_WIN32 "B:"
1680 #else
1681 #define OPTSTRING_CHILD "W:"
1682 #define OPTSTRING_WIN32 ""
1683 #endif  /* _WIN32 */
1684 #else
1685 #define OPTSTRING_CHILD ""
1686 #define OPTSTRING_WIN32 ""
1687 #endif  /* HAVE_LIBPCAP */
1688
1689   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1690     OPTSTRING_INIT OPTSTRING_WIN32;
1691
1692   /* initialize memory allocation subsystem */
1693   ep_init_chunk();
1694   se_init_chunk();
1695
1696   /*** create the compile and runtime version strings ***/
1697 #ifdef _WIN32
1698   /* Load wpcap if possible. Do this before collecting the run-time version information */
1699   load_wpcap();
1700
1701   /* ... and also load the packet.dll from wpcap */
1702   wpcap_packet_load();
1703
1704   /* Start windows sockets */
1705   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1706 #endif  /* _WIN32 */
1707
1708   /* Assemble the compile-time version information string */
1709   comp_info_str = g_string_new("Compiled ");
1710   g_string_append(comp_info_str, "with ");
1711   g_string_sprintfa(comp_info_str,
1712 #ifdef GTK_MAJOR_VERSION
1713                     "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1714                     GTK_MICRO_VERSION);
1715 #else
1716                     "GTK+ (version unknown)");
1717 #endif
1718
1719   g_string_append(comp_info_str, ", ");
1720   get_compiled_version_info(comp_info_str);
1721
1722   /* Assemble the run-time version information string */
1723   runtime_info_str = g_string_new("Running ");
1724   get_runtime_version_info(runtime_info_str);
1725
1726
1727   /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1728   /* (e.g. don't start GTK+, if we only have to show the command line help) */
1729   optind_initial = optind;
1730   while ((opt = getopt(argc, argv, optstring)) != -1) {
1731     switch (opt) {
1732       case 'h':        /* Print help and exit */
1733         print_usage(TRUE);
1734         exit(0);
1735         break;
1736       case 'v':        /* Show version and exit */
1737         show_version();
1738         exit(0);
1739         break;
1740       case 'G':        /* dump various field or other infos, see handle_dashG_option() */
1741   /* If invoked with the "-G" flag, we dump out information based on
1742      the argument to the "-G" flag; if no argument is specified,
1743      for backwards compatibility we dump out a glossary of display
1744      filter symbols.
1745
1746      We must do this before calling "gtk_init()", because "gtk_init()"
1747      tries to open an X display, and we don't want to have to do any X
1748      stuff just to do a build.
1749
1750      Given that we call "gtk_init()" before doing the regular argument
1751      list processing, so that it can handle X and GTK+ arguments and
1752      remove them from the list at which we look, this means we must do
1753      this before doing the regular argument list processing, as well.
1754
1755      This means that:
1756
1757         you must give the "-G" flag as the first flag on the command line;
1758
1759         you must give it as "-G", nothing more, nothing less;
1760
1761         the first argument after the "-G" flag, if present, will be used
1762         to specify the information to dump;
1763
1764         arguments after that will not be used. */        
1765         handle_dashG_option(argc, argv, "ethereal");
1766         /* will never return! */
1767         exit(0);
1768         break;
1769     }
1770   }
1771
1772   /* set getopt index back to initial value, so it will start with the first command line parameter again */
1773   /* (XXX - this seems to be portable, but time will tell) */
1774   optind = optind_initial;
1775
1776
1777   /* Set the current locale according to the program environment.
1778    * We haven't localized anything, but some GTK widgets are localized
1779    * (the file selection dialogue, for example).
1780    * This also sets the C-language locale to the native environment. */
1781   gtk_set_locale();
1782
1783   /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1784   gtk_init (&argc, &argv);
1785
1786   cf_callback_add(main_cf_callback, NULL);
1787
1788 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1789   /* initialize our GTK eth_clist_type */
1790   init_eth_clist_type();
1791 #endif
1792
1793   ethereal_path = argv[0];
1794
1795   /* Arrange that if we have no console window, and a GLib message logging
1796      routine is called to log a message, we pop up a console window.
1797
1798      We do that by inserting our own handler for all messages logged
1799      to the default domain; that handler pops up a console if necessary,
1800      and then calls the default handler. */
1801
1802   /* We might want to have component specific log levels later ... */
1803
1804   /* the default_log_handler will use stdout, which makes trouble with the */
1805   /* capture child, as it uses stdout for it's sync_pipe */
1806   /* so do the filtering in the console_log_handler and not here */
1807   log_flags = 
1808                     G_LOG_LEVEL_ERROR|
1809                     G_LOG_LEVEL_CRITICAL|
1810                     G_LOG_LEVEL_WARNING|
1811                     G_LOG_LEVEL_MESSAGE|
1812                     G_LOG_LEVEL_INFO|
1813                     G_LOG_LEVEL_DEBUG|
1814                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1815
1816   g_log_set_handler(NULL,
1817                     log_flags,
1818                     console_log_handler, NULL /* user_data */);
1819
1820 #ifdef HAVE_LIBPCAP
1821   g_log_set_handler(LOG_DOMAIN_CAPTURE,
1822                     log_flags,
1823             console_log_handler, NULL /* user_data */);
1824   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1825                     log_flags,
1826             console_log_handler, NULL /* user_data */);
1827
1828   /* Set the initial values in the capture_opts. This might be overwritten 
1829      by preference settings and then again by the command line parameters. */
1830   capture_opts_init(capture_opts, &cfile);
1831
1832   capture_opts->snaplen             = MIN_PACKET_SIZE;
1833   capture_opts->has_ring_num_files  = TRUE;
1834
1835   command_name = get_basename(ethereal_path);
1836   /* Set "capture_child" to indicate whether this is going to be a child
1837      process for a "-S" capture. */
1838   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1839   if (capture_child) {
1840     strcat(optstring, OPTSTRING_CHILD);
1841   }
1842 #endif
1843
1844   /* We want a splash screen only if we're not a child process.
1845      We won't come till here, if we had a "console only" command line parameter. */
1846 #ifdef HAVE_LIBPCAP
1847   if (!capture_child)
1848 #endif
1849     splash_win = splash_new("Loading Ethereal ...");
1850
1851   splash_update(splash_win, "Registering dissectors ...");
1852
1853   /* Register all dissectors; we must do this before checking for the
1854      "-G" flag, as the "-G" flag dumps information registered by the
1855      dissectors, and we must do it before we read the preferences, in
1856      case any dissectors register preferences. */
1857   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1858             failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1859
1860   splash_update(splash_win, "Registering tap listeners ...");
1861
1862   /* Register all tap listeners; we do this before we parse the arguments,
1863      as the "-z" argument can specify a registered tap. */
1864
1865   /* we register the plugin taps before the other taps because
1866           stats_tree taps plugins will be registered as tap listeners
1867           by stats_tree_stat.c and need to registered before that */
1868
1869 #ifdef HAVE_PLUGINS
1870   register_all_plugin_tap_listeners();
1871 #endif
1872
1873   register_all_tap_listeners();
1874   
1875   splash_update(splash_win, "Loading module preferences ...");
1876
1877   /* Now register the preferences for any non-dissector modules.
1878      We must do that before we read the preferences as well. */
1879   prefs_register_modules();
1880
1881   /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1882 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1883   {
1884       GThread *ut;
1885       g_thread_init(NULL);
1886       gdk_threads_init();
1887       ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1888       g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1889   }
1890 #else  /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1891   /* this is to keep tap extensions updating once every 3 seconds */
1892   gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1893 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1894
1895 #if HAVE_GNU_ADNS
1896   gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1897 #endif
1898
1899   splash_update(splash_win, "Loading configuration files ...");
1900
1901   /* Read the preference files. */
1902   prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1903                      &pf_open_errno, &pf_read_errno, &pf_path);
1904   if (gpf_path != NULL) {
1905     if (gpf_open_errno != 0) {
1906       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1907         "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1908         strerror(gpf_open_errno));
1909     }
1910     if (gpf_read_errno != 0) {
1911       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1912         "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1913         strerror(gpf_read_errno));
1914     }
1915   }
1916   if (pf_path != NULL) {
1917     if (pf_open_errno != 0) {
1918       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1919         "Could not open your preferences file\n\"%s\": %s.", pf_path,
1920         strerror(pf_open_errno));
1921     }
1922     if (pf_read_errno != 0) {
1923       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1924         "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1925         strerror(pf_read_errno));
1926     }
1927     g_free(pf_path);
1928     pf_path = NULL;
1929   }
1930
1931 #ifdef _WIN32
1932   /* if the user wants a console to be always there, well, we should open one for him */
1933   if (prefs->gui_console_open == console_open_always) {
1934     create_console();
1935   }
1936 #endif
1937
1938 #ifdef HAVE_LIBPCAP
1939   /* If this is a capture child process, it should pay no attention
1940      to the "prefs.capture_prom_mode" setting in the preferences file;
1941      it should do what the parent process tells it to do, and if
1942      the parent process wants it not to run in promiscuous mode, it'll
1943      tell it so with a "-p" flag.
1944
1945      Otherwise, set promiscuous mode from the preferences setting. */
1946   /* the same applies to other preferences settings as well. */
1947   if (capture_child) {
1948     auto_scroll_live             = FALSE;
1949   } else {
1950     capture_opts->promisc_mode   = prefs->capture_prom_mode;
1951     capture_opts->show_info      = prefs->capture_show_info;
1952     capture_opts->real_time_mode = prefs->capture_real_time;
1953     auto_scroll_live             = prefs->capture_auto_scroll;
1954   }
1955
1956 #endif /* HAVE_LIBPCAP */
1957
1958   /* Set the name resolution code's flags from the preferences. */
1959   g_resolv_flags = prefs->name_resolve;
1960
1961   /* Read the capture filter file. */
1962   read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1963   if (cf_path != NULL) {
1964       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1965         "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1966         strerror(cf_open_errno));
1967       g_free(cf_path);
1968   }
1969
1970   /* Read the display filter file. */
1971   read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1972   if (df_path != NULL) {
1973       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1974         "Could not open your display filter file\n\"%s\": %s.", df_path,
1975         strerror(df_open_errno));
1976       g_free(df_path);
1977   }
1978
1979   /* Read the disabled protocols file. */
1980   read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1981                             &dp_path, &dp_open_errno, &dp_read_errno);
1982   if (gdp_path != NULL) {
1983     if (gdp_open_errno != 0) {
1984       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1985         "Could not open global disabled protocols file\n\"%s\": %s.",
1986         gdp_path, strerror(gdp_open_errno));
1987     }
1988     if (gdp_read_errno != 0) {
1989       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1990         "I/O error reading global disabled protocols file\n\"%s\": %s.",
1991         gdp_path, strerror(gdp_read_errno));
1992     }
1993     g_free(gdp_path);
1994   }
1995   if (dp_path != NULL) {
1996     if (dp_open_errno != 0) {
1997       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1998         "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1999         strerror(dp_open_errno));
2000     }
2001     if (dp_read_errno != 0) {
2002       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2003         "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2004         strerror(dp_read_errno));
2005     }
2006     g_free(dp_path);
2007   }
2008
2009   /* Read the (static part) of the recent file. Only the static part of it will be read, */
2010   /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2011   /* We have to do this already here, so command line parameters can overwrite these values. */
2012   recent_read_static(&rf_path, &rf_open_errno);
2013
2014   init_cap_file(&cfile);
2015
2016   /* Now get our args */
2017   while ((opt = getopt(argc, argv, optstring)) != -1) {
2018     switch (opt) {
2019       /*** capture option specific ***/
2020       case 'a':        /* autostop criteria */
2021       case 'b':        /* Ringbuffer option */
2022       case 'c':        /* Capture xxx packets */
2023       case 'f':        /* capture filter */
2024       case 'k':        /* Start capture immediately */
2025       case 'H':        /* Hide capture info dialog box */
2026       case 'i':        /* Use interface xxx */
2027       case 'p':        /* Don't capture in promiscuous mode */
2028       case 'Q':        /* Quit after capture (just capture to file) */
2029       case 's':        /* Set the snapshot (capture) length */
2030       case 'S':        /* "Sync" mode: used for following file ala tail -f */
2031       case 'w':        /* Write to capture file xxx */
2032       case 'y':        /* Set the pcap data link type */
2033 #ifdef _WIN32
2034       case 'B':        /* Buffer size */
2035       /* Hidden option supporting Sync mode */
2036       case 'Z':        /* Write to pipe FD XXX */
2037 #endif /* _WIN32 */
2038 #ifdef HAVE_LIBPCAP
2039         capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2040 #else
2041         capture_option_specified = TRUE;
2042         arg_error = TRUE;
2043 #endif
2044         break;
2045 #ifdef HAVE_LIBPCAP
2046       /* This is a hidden option supporting Sync mode, so we don't set
2047        * the error flags for the user in the non-libpcap case.
2048        */
2049       case 'W':        /* Write to capture file FD xxx */
2050         capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2051         break;
2052 #endif
2053
2054       /*** all non capture option specific ***/
2055       case 'g':        /* Go to packet */
2056         go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2057         break;
2058       case 'l':        /* Automatic scrolling in live capture mode */
2059 #ifdef HAVE_LIBPCAP
2060         auto_scroll_live = TRUE;
2061 #else
2062         capture_option_specified = TRUE;
2063         arg_error = TRUE;
2064 #endif
2065         break;
2066       case 'L':        /* Print list of link-layer types and exit */
2067 #ifdef HAVE_LIBPCAP
2068         list_link_layer_types = TRUE;
2069 #else
2070         capture_option_specified = TRUE;
2071         arg_error = TRUE;
2072 #endif
2073         break;
2074       case 'm':        /* Fixed-width font for the display */
2075         if (prefs->PREFS_GUI_FONT_NAME != NULL)
2076           g_free(prefs->PREFS_GUI_FONT_NAME);
2077         prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2078         break;
2079       case 'n':        /* No name resolution */
2080         g_resolv_flags = RESOLV_NONE;
2081         break;
2082       case 'N':        /* Select what types of addresses/port #s to resolve */
2083         if (g_resolv_flags == RESOLV_ALL)
2084           g_resolv_flags = RESOLV_NONE;
2085         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2086         if (badopt != '\0') {
2087           g_warning("ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2088                         badopt);
2089           exit(1);
2090         }
2091         break;
2092       case 'o':        /* Override preference from command line */
2093         switch (prefs_set_pref(optarg)) {
2094         case PREFS_SET_OK:
2095           break;
2096         case PREFS_SET_SYNTAX_ERR:
2097           g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2098           exit(1);
2099           break;
2100         case PREFS_SET_NO_SUCH_PREF:
2101           /* not a preference, might be a recent setting */
2102           switch (recent_set_arg(optarg)) {
2103             case PREFS_SET_OK:
2104               break;
2105             case PREFS_SET_SYNTAX_ERR:
2106               /* shouldn't happen, checked already above */
2107               g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2108               exit(1);
2109               break;
2110             case PREFS_SET_NO_SUCH_PREF:
2111             case PREFS_SET_OBSOLETE:
2112               g_warning("ethereal: -o flag \"%s\" specifies unknown preference/recent value",
2113                     optarg);
2114               exit(1);
2115               break;
2116             default:
2117               g_assert_not_reached();
2118             }
2119           break;
2120         case PREFS_SET_OBSOLETE:
2121           g_warning("ethereal: -o flag \"%s\" specifies obsolete preference",
2122                         optarg);
2123           exit(1);
2124           break;
2125         default:
2126           g_assert_not_reached();
2127         }
2128         break;
2129       case 'r':        /* Read capture file xxx */
2130         /* We may set "last_open_dir" to "cf_name", and if we change
2131            "last_open_dir" later, we free the old value, so we have to
2132            set "cf_name" to something that's been allocated. */
2133         cf_name = g_strdup(optarg);
2134         break;
2135       case 'R':        /* Read file filter */
2136         rfilter = optarg;
2137         break;
2138       case 't':        /* Time stamp type */
2139         if (strcmp(optarg, "r") == 0)
2140           timestamp_set_type(TS_RELATIVE);
2141         else if (strcmp(optarg, "a") == 0)
2142           timestamp_set_type(TS_ABSOLUTE);
2143         else if (strcmp(optarg, "ad") == 0)
2144           timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2145         else if (strcmp(optarg, "d") == 0)
2146           timestamp_set_type(TS_DELTA);
2147         else {
2148           g_warning("ethereal: Invalid time stamp type \"%s\"",
2149             optarg);
2150           g_warning("It must be \"r\" for relative, \"a\" for absolute,");
2151           g_warning("\"ad\" for absolute with date, or \"d\" for delta.");
2152           exit(1);
2153         }
2154         break;
2155       case 'z':
2156         /* We won't call the init function for the stat this soon
2157            as it would disallow MATE's fields (which are registered
2158            by the preferences set callback) from being used as
2159            part of a tap filter.  Instead, we just add the argument
2160            to a list of stat arguments. */
2161         if (!process_stat_cmd_arg(optarg)) {
2162           g_warning("ethereal: invalid -z argument.");
2163           g_warning("  -z argument must be one of :");
2164           list_stat_cmd_args();
2165           exit(1);
2166         }
2167         break;
2168       default:
2169       case '?':        /* Bad flag - print usage message */
2170             g_warning("Bad flag");
2171         arg_error = TRUE;
2172         break;
2173     }
2174   }
2175   argc -= optind;
2176   argv += optind;
2177   if (argc >= 1) {
2178     if (cf_name != NULL) {
2179       /*
2180        * Input file name specified with "-r" *and* specified as a regular
2181        * command-line argument.
2182        */
2183           g_warning("File name specified both with -r and regular argument");
2184       arg_error = TRUE;
2185     } else {
2186       /*
2187        * Input file name not specified with "-r", and a command-line argument
2188        * was specified; treat it as the input file name.
2189        *
2190        * Yes, this is different from tethereal, where non-flag command-line
2191        * arguments are a filter, but this works better on GUI desktops
2192        * where a command can be specified to be run to open a particular
2193        * file - yes, you could have "-r" as the last part of the command,
2194        * but that's a bit ugly.
2195        */
2196       cf_name = g_strdup(argv[0]);
2197     }
2198     argc--;
2199     argv++;
2200   }
2201
2202
2203
2204   if (argc != 0) {
2205     /*
2206      * Extra command line arguments were specified; complain.
2207      */
2208     g_warning("Invalid argument: %s", argv[0]);
2209     arg_error = TRUE;
2210   }
2211
2212   if (arg_error) {
2213 #ifndef HAVE_LIBPCAP
2214     if (capture_option_specified) {
2215       g_warning("This version of Ethereal was not built with support for capturing packets.");
2216     }
2217 #endif
2218     print_usage(FALSE);
2219     exit(1);
2220   }
2221
2222 #ifdef HAVE_LIBPCAP
2223   if (start_capture && list_link_layer_types) {
2224     /* Specifying *both* is bogus. */
2225     g_warning("ethereal: You can't specify both -L and a live capture.");
2226     exit(1);
2227   }
2228
2229   if (list_link_layer_types) {
2230     /* We're supposed to list the link-layer types for an interface;
2231        did the user also specify a capture file to be read? */
2232     if (cf_name) {
2233       /* Yes - that's bogus. */
2234       g_warning("ethereal: You can't specify -L and a capture file to be read.");
2235       exit(1);
2236     }
2237     /* No - did they specify a ring buffer option? */
2238     if (capture_opts->multi_files_on) {
2239       g_warning("ethereal: Ring buffer requested, but a capture isn't being done.");
2240       exit(1);
2241     }
2242   } else {
2243     /* We're supposed to do a live capture; did the user also specify
2244        a capture file to be read? */
2245     if (start_capture && cf_name) {
2246       /* Yes - that's bogus. */
2247       g_warning("ethereal: You can't specify both a live capture and a capture file to be read.");
2248       exit(1);
2249     }
2250
2251     /* No - was the ring buffer option specified and, if so, does it make
2252        sense? */
2253     if (capture_opts->multi_files_on) {
2254       /* Ring buffer works only under certain conditions:
2255          a) ring buffer does not work with temporary files;
2256          b) real_time_mode and multi_files_on are mutually exclusive -
2257             real_time_mode takes precedence;
2258          c) it makes no sense to enable the ring buffer if the maximum
2259             file size is set to "infinite". */
2260       if (capture_opts->save_file == NULL) {
2261         g_warning("ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.");
2262         capture_opts->multi_files_on = FALSE;
2263       }
2264 /*      if (capture_opts->real_time_mode) {
2265         g_warning("ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2266         capture_opts->multi_files_on = FALSE;
2267       }*/
2268       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2269         g_warning("ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.");
2270 /* XXX - this must be redesigned as the conditions changed */
2271 /*      capture_opts->multi_files_on = FALSE;*/
2272       }
2273     }
2274   }
2275
2276   if (start_capture || list_link_layer_types) {
2277     /* Did the user specify an interface to use? */
2278     if (capture_opts->iface == NULL) {
2279       /* No - is a default specified in the preferences file? */
2280       if (prefs->capture_device != NULL) {
2281           /* Yes - use it. */
2282           capture_opts->iface = g_strdup(get_if_name(prefs->capture_device));
2283       } else {
2284         /* No - pick the first one from the list of interfaces. */
2285         if_list = get_interface_list(&err, err_str);
2286         if (if_list == NULL) {
2287           switch (err) {
2288
2289           case CANT_GET_INTERFACE_LIST:
2290               cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2291               g_warning("%s", cant_get_if_list_errstr);
2292               g_free(cant_get_if_list_errstr);
2293               break;
2294
2295           case NO_INTERFACES_FOUND:
2296               g_warning("ethereal: There are no interfaces on which a capture can be done");
2297               break;
2298           }
2299           exit(2);
2300         }
2301         if_info = if_list->data;        /* first interface */
2302         capture_opts->iface = g_strdup(if_info->name);
2303         free_interface_list(if_list);
2304       }
2305     }
2306   }
2307
2308   if (list_link_layer_types) {
2309     /* Get the list of link-layer types for the capture device. */
2310     lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2311     if (lt_list == NULL) {
2312       if (err_str[0] != '\0') {
2313         g_warning("ethereal: The list of data link types for the capture device could not be obtained (%s)."
2314           "Please check to make sure you have sufficient permissions, and that\n"
2315           "you have the proper interface or pipe specified.\n", err_str);
2316       } else
2317         g_warning("ethereal: The capture device has no data link types.");
2318       exit(2);
2319     }
2320     g_warning("Data link types (use option -y to set):");
2321     for (lt_entry = lt_list; lt_entry != NULL;
2322          lt_entry = g_list_next(lt_entry)) {
2323       data_link_info = lt_entry->data;
2324       g_warning("  %s", data_link_info->name);
2325       if (data_link_info->description != NULL)
2326         g_warning(" (%s)", data_link_info->description);
2327       else
2328         g_warning(" (not supported)");
2329       putchar('\n');
2330     }
2331     free_pcap_linktype_list(lt_list);
2332     exit(0);
2333   }
2334
2335   if (capture_opts->has_snaplen) {
2336     if (capture_opts->snaplen < 1)
2337       capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2338     else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2339       capture_opts->snaplen = MIN_PACKET_SIZE;
2340   }
2341
2342   /* Check the value range of the ringbuffer_num_files parameter */
2343   if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2344     capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2345 #if RINGBUFFER_MIN_NUM_FILES > 0
2346   else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2347     capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2348 #endif
2349 #endif /* HAVE_LIBPCAP */
2350
2351   /* Notify all registered modules that have had any of their preferences
2352      changed either from one of the preferences file or from the command
2353      line that their preferences have changed. */
2354   prefs_apply_all();
2355
2356   /* disabled protocols as per configuration file */
2357   if (gdp_path == NULL && dp_path == NULL) {
2358     set_disabled_protos_list();
2359   }
2360
2361   /* Build the column format array */
2362   col_setup(&cfile.cinfo, prefs->num_cols);
2363   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2364     cfile.cinfo.col_fmt[i] = get_column_format(i);
2365     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2366     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2367       NUM_COL_FMTS);
2368     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2369     cfile.cinfo.col_data[i] = NULL;
2370     if (cfile.cinfo.col_fmt[i] == COL_INFO)
2371       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2372     else
2373       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2374     cfile.cinfo.col_fence[i] = 0;
2375     cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2376     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2377   }
2378
2379   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2380       int j;
2381
2382       for (j = 0; j < NUM_COL_FMTS; j++) {
2383          if (!cfile.cinfo.fmt_matx[i][j])
2384              continue;
2385          
2386          if (cfile.cinfo.col_first[j] == -1)
2387              cfile.cinfo.col_first[j] = i;
2388          cfile.cinfo.col_last[j] = i;
2389       }
2390   }
2391
2392   /* read in rc file from global and personal configuration paths. */
2393   rc_file = get_datafile_path(RC_FILE);
2394   gtk_rc_parse(rc_file);
2395   rc_file = get_persconffile_path(RC_FILE, FALSE);
2396   gtk_rc_parse(rc_file);
2397
2398 #ifdef HAVE_LIBPCAP
2399   font_init(capture_child);
2400 #else
2401   font_init(FALSE);
2402 #endif
2403
2404   /* close the splash screen, as we are going to open the main window now */
2405   splash_destroy(splash_win);
2406
2407
2408 #ifdef HAVE_LIBPCAP
2409   /* Is this a "child" ethereal, which is only supposed to pop up a
2410      capture box to let us stop the capture, and run a capture
2411      to a file that our parent will read? */
2412   if (capture_child) {
2413     /* This is the child process of a capture session,
2414        so just do the low-level work of a capture - don't create
2415        a temporary file and fork off *another* child process (so don't
2416        call "capture_start()"). */
2417
2418     /* Pop up any queued-up alert boxes. */
2419     display_queued_messages();
2420
2421     /* Now start the capture. 
2422        After the capture is done; there's nothing more for us to do. */
2423
2424     /* XXX - hand these stats to the parent process */
2425     if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2426         /* capture ok */
2427         gtk_exit(0);
2428     } else {
2429         /* capture failed */
2430         gtk_exit(1);
2431     }
2432   }
2433 #endif
2434
2435   /***********************************************************************/
2436   /* Everything is prepared now, preferences and command line was read in,
2437        we are NOT a child window for a synced capture. */
2438
2439   /* Pop up the main window. */
2440   create_main_window(pl_size, tv_size, bv_size, prefs);
2441
2442   /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2443   recent_read_dynamic(&rf_path, &rf_open_errno);
2444   color_filters_enable(recent.packet_list_colorize);
2445
2446   /* rearrange all the widgets as we now have all recent settings ready for this */
2447   main_widgets_rearrange();
2448
2449   /* Fill in column titles.  This must be done after the top level window
2450      is displayed.
2451
2452      XXX - is that still true, with fixed-width columns? */
2453   packet_list_set_column_titles();
2454
2455   menu_recent_read_finished();
2456
2457   switch (user_font_apply()) {
2458   case FA_SUCCESS:
2459       break;
2460   case FA_FONT_NOT_RESIZEABLE:
2461       /* "user_font_apply()" popped up an alert box. */
2462       /* turn off zooming - font can't be resized */
2463   case FA_FONT_NOT_AVAILABLE:
2464       /* XXX - did we successfully load the un-zoomed version earlier?
2465       If so, this *probably* means the font is available, but not at
2466       this particular zoom level, but perhaps some other failure
2467       occurred; I'm not sure you can determine which is the case,
2468       however. */
2469       /* turn off zooming - zoom level is unavailable */
2470   default:
2471       /* in any other case than FA_SUCCESS, turn off zooming */
2472       recent.gui_zoom_level = 0;        
2473       /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2474   }
2475
2476   dnd_init(top_level);
2477
2478   colors_init();
2479   color_filters_init();
2480   decode_as_init();
2481
2482   /* the window can be sized only, if it's not already shown, so do it now! */
2483   main_load_window_geometry(top_level);
2484
2485   /* If we were given the name of a capture file, read it in now;
2486      we defer it until now, so that, if we can't open it, and pop
2487      up an alert box, the alert box is more likely to come up on
2488      top of the main window - but before the preference-file-error
2489      alert box, so, if we get one of those, it's more likely to come
2490      up on top of us. */
2491   if (cf_name) {
2492     show_main_window(TRUE);
2493     if (rfilter != NULL) {
2494       if (!dfilter_compile(rfilter, &rfcode)) {
2495         bad_dfilter_alert_box(rfilter);
2496         rfilter_parse_failed = TRUE;
2497       }
2498     }
2499     if (!rfilter_parse_failed) {
2500       if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2501         /* "cf_open()" succeeded, so it closed the previous
2502            capture file, and thus destroyed any previous read filter
2503            attached to "cf". */
2504
2505         cfile.rfcode = rfcode;
2506         /* Open stat windows; we do so after creating the main window,
2507            to avoid GTK warnings, and after successfully opening the
2508            capture file, so we know we have something to compute stats
2509            on, and after registering all dissectors, so that MATE will
2510            have registered its field array and we can have a tap filter
2511            with one of MATE's late-registered fields as part of the
2512            filter. */
2513         start_requested_stats();
2514
2515         /* Read the capture file. */
2516         switch (cf_read(&cfile)) {
2517
2518         case CF_READ_OK:
2519         case CF_READ_ERROR:
2520           /* Just because we got an error, that doesn't mean we were unable
2521              to read any of the file; we handle what we could get from the
2522              file. */
2523           /* if the user told us to jump to a specific packet, do it now */
2524           if(go_to_packet != 0) {
2525             cf_goto_frame(&cfile, go_to_packet);
2526           }
2527           break;
2528
2529         case CF_READ_ABORTED:
2530           /* Exit now. */
2531           gtk_exit(0);
2532           break;
2533         }
2534         /* Save the name of the containing directory specified in the
2535            path name, if any; we can write over cf_name, which is a
2536            good thing, given that "get_dirname()" does write over its
2537            argument. */
2538         s = get_dirname(cf_name);
2539         /* we might already set this from the recent file, don't overwrite this */
2540         if(get_last_open_dir() == NULL) 
2541           set_last_open_dir(s);
2542         g_free(cf_name);
2543         cf_name = NULL;
2544       } else {
2545         if (rfcode != NULL)
2546           dfilter_free(rfcode);
2547         cfile.rfcode = NULL;
2548         set_menus_for_capture_in_progress(FALSE);
2549       }
2550     }
2551   } else {
2552 #ifdef HAVE_LIBPCAP
2553     if (start_capture) {
2554       if (capture_opts->save_file != NULL) {
2555         /* Save the directory name for future file dialogs. */
2556         /* (get_dirname overwrites filename) */
2557         s = get_dirname(g_strdup(capture_opts->save_file));  
2558         set_last_open_dir(s);
2559         g_free(s);
2560       }
2561       /* "-k" was specified; start a capture. */
2562       show_main_window(TRUE);
2563       if (capture_start(capture_opts)) {
2564         /* The capture started.  Open stat windows; we do so after creating
2565            the main window, to avoid GTK warnings, and after successfully
2566            opening the capture file, so we know we have something to compute
2567            stats on, and after registering all dissectors, so that MATE will
2568            have registered its field array and we can have a tap filter with
2569            one of MATE's late-registered fields as part of the filter. */
2570         start_requested_stats();
2571       }
2572     }
2573     else {
2574       show_main_window(FALSE);
2575       set_menus_for_capture_in_progress(FALSE);
2576     }
2577
2578     /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2579     if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2580       if (capture_opts->cfilter) {
2581         g_free(capture_opts->cfilter);
2582       }
2583       capture_opts->cfilter = g_strdup(get_conn_cfilter());
2584     }
2585 #else /* HAVE_LIBPCAP */
2586     show_main_window(FALSE);
2587     set_menus_for_capture_in_progress(FALSE);
2588 #endif /* HAVE_LIBPCAP */
2589   }
2590
2591   /* we'll enter the GTK loop now and hand the control over to GTK ... */
2592   gtk_main();
2593   /* ... back from GTK, we're going down now! */
2594
2595   epan_cleanup();
2596   g_free(rc_file);
2597
2598 #ifdef _WIN32
2599   /* hide the (unresponsive) main window, while asking the user to close the console window */
2600   gtk_widget_hide(top_level);
2601
2602   /* Shutdown windows sockets */
2603   WSACleanup();
2604
2605   /* For some unknown reason, the "atexit()" call in "create_console()"
2606      doesn't arrange that "destroy_console()" be called when we exit,
2607      so we call it here if a console was created. */
2608   destroy_console();
2609 #endif
2610
2611   gtk_exit(0);
2612
2613   /* This isn't reached, but we need it to keep GCC from complaining
2614      that "main()" returns without returning a value - it knows that
2615      "exit()" never returns, but it doesn't know that "gtk_exit()"
2616      doesn't, as GTK+ doesn't declare it with the attribute
2617      "noreturn". */
2618   return 0;     /* not reached */
2619 }
2620
2621 #ifdef _WIN32
2622
2623 /* We build this as a GUI subsystem application on Win32, so
2624    "WinMain()", not "main()", gets called.
2625
2626    Hack shamelessly stolen from the Win32 port of the GIMP. */
2627 #ifdef __GNUC__
2628 #define _stdcall  __attribute__((stdcall))
2629 #endif
2630
2631 int _stdcall
2632 WinMain (struct HINSTANCE__ *hInstance,
2633          struct HINSTANCE__ *hPrevInstance,
2634          char               *lpszCmdLine,
2635          int                 nCmdShow)
2636 {
2637   has_console = FALSE;
2638   return main (__argc, __argv);
2639 }
2640
2641 /*
2642  * If this application has no console window to which its standard output
2643  * would go, create one.
2644  */
2645 void
2646 create_console(void)
2647 {
2648   if (!has_console) {
2649     /* We have no console to which to print the version string, so
2650        create one and make it the standard input, output, and error. */
2651     if (!AllocConsole())
2652       return;   /* couldn't create console */
2653     freopen("CONIN$", "r", stdin);
2654     freopen("CONOUT$", "w", stdout);
2655     freopen("CONOUT$", "w", stderr);
2656
2657     /* Well, we have a console now. */
2658     has_console = TRUE;
2659
2660     /* Now register "destroy_console()" as a routine to be called just
2661        before the application exits, so that we can destroy the console
2662        after the user has typed a key (so that the console doesn't just
2663        disappear out from under them, giving the user no chance to see
2664        the message(s) we put in there). */
2665     atexit(destroy_console);
2666
2667         if(capture_child) {
2668                 SetConsoleTitle("Ethereal Capture Child Debug Console");
2669         } else {
2670                 SetConsoleTitle("Ethereal Debug Console");
2671         }
2672   }
2673 }
2674
2675 static void
2676 destroy_console(void)
2677 {
2678   if (has_console && !capture_child) {
2679     printf("\n\nPress any key to exit\n");
2680     _getch();
2681     FreeConsole();
2682   }
2683 }
2684 #endif /* _WIN32 */
2685
2686
2687 /* This routine should not be necessary, at least as I read the GLib
2688    source code, as it looks as if GLib is, on Win32, *supposed* to
2689    create a console window into which to display its output.
2690
2691    That doesn't happen, however.  I suspect there's something completely
2692    broken about that code in GLib-for-Win32, and that it may be related
2693    to the breakage that forces us to just call "printf()" on the message
2694    rather than passing the message on to "g_log_default_handler()"
2695    (which is the routine that does the aforementioned non-functional
2696    console window creation). */
2697 static void
2698 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2699                     const char *message, gpointer user_data _U_)
2700 {
2701   time_t curr;
2702   struct tm *today;
2703   const char *level;
2704
2705
2706   /* change this, if you want to see more verbose log output */
2707   /* XXX - make this a pref value */
2708   if( (log_level & G_LOG_LEVEL_MASK) > G_LOG_LEVEL_WARNING) {
2709     return;
2710   }
2711
2712   /* create a "timestamp" */
2713   time(&curr);
2714   today = localtime(&curr);    
2715
2716 #ifdef _WIN32
2717   if (prefs.gui_console_open != console_open_never) {
2718     create_console();
2719   }
2720   if (has_console) {
2721     /* For some unknown reason, the above doesn't appear to actually cause
2722        anything to be sent to the standard output, so we'll just splat the
2723        message out directly, just to make sure it gets out. */
2724 #endif
2725     switch(log_level & G_LOG_LEVEL_MASK) {
2726     case G_LOG_LEVEL_ERROR:
2727         level = "Err ";
2728         break;
2729     case G_LOG_LEVEL_CRITICAL:
2730         level = "Crit";
2731         break;
2732     case G_LOG_LEVEL_WARNING:
2733         level = "Warn";
2734         break;
2735     case G_LOG_LEVEL_MESSAGE:
2736         level = "Msg ";
2737         break;
2738     case G_LOG_LEVEL_INFO:
2739         level = "Info";
2740         break;
2741     case G_LOG_LEVEL_DEBUG:
2742         level = "Dbg ";
2743         break;
2744     default:
2745         fprintf(stderr, "unknown log_level %u\n", log_level);
2746         level = NULL;
2747         g_assert_not_reached();
2748     }
2749
2750     /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2751     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2752             today->tm_hour, today->tm_min, today->tm_sec,
2753             log_domain != NULL ? log_domain : "",
2754             level, message);
2755 #ifdef _WIN32
2756   } else {
2757     g_log_default_handler(log_domain, log_level, message, user_data);
2758   }
2759 #endif
2760 }
2761
2762
2763 static GtkWidget *info_bar_new(void)
2764 {
2765     /* tip: tooltips don't work on statusbars! */
2766     info_bar = gtk_statusbar_new();
2767     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2768     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2769     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2770 #if GTK_MAJOR_VERSION >= 2
2771     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2772 #endif
2773     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2774
2775     return info_bar;
2776 }
2777
2778 static GtkWidget *packets_bar_new(void)
2779 {
2780     /* tip: tooltips don't work on statusbars! */
2781     packets_bar = gtk_statusbar_new();
2782     packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2783     packets_bar_update();
2784
2785     return packets_bar;
2786 }
2787
2788
2789 /*
2790  * Helper for main_widgets_rearrange()
2791  */
2792 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2793     gtk_container_remove(GTK_CONTAINER(data), widget);
2794 }
2795
2796 static GtkWidget *main_widget_layout(gint layout_content)
2797 {
2798     switch(layout_content) {
2799     case(layout_pane_content_none):
2800         return NULL;
2801         break;
2802     case(layout_pane_content_plist):
2803         return pkt_scrollw;
2804         break;
2805     case(layout_pane_content_pdetails):
2806         return tv_scrollw;
2807         break;
2808     case(layout_pane_content_pbytes):
2809         return byte_nb_ptr;
2810         break;
2811     default:
2812         g_assert_not_reached();
2813         return NULL;
2814     }
2815 }
2816
2817
2818 /*
2819  * Rearrange the main window widgets
2820  */
2821 void main_widgets_rearrange(void) {
2822     GtkWidget *first_pane_widget1, *first_pane_widget2;
2823     GtkWidget *second_pane_widget1, *second_pane_widget2;
2824     gboolean split_top_left;
2825
2826     /* be a bit faster */
2827     gtk_widget_hide(main_vbox);
2828
2829     /* be sure, we don't loose a widget while rearranging */
2830     gtk_widget_ref(menubar);
2831     gtk_widget_ref(main_tb);
2832     gtk_widget_ref(filter_tb);
2833     gtk_widget_ref(pkt_scrollw);
2834     gtk_widget_ref(tv_scrollw);
2835     gtk_widget_ref(byte_nb_ptr);
2836     gtk_widget_ref(stat_hbox);
2837     gtk_widget_ref(info_bar);
2838     gtk_widget_ref(packets_bar);
2839     gtk_widget_ref(status_pane);
2840     gtk_widget_ref(main_pane_v1);
2841     gtk_widget_ref(main_pane_v2);
2842     gtk_widget_ref(main_pane_h1);
2843     gtk_widget_ref(main_pane_h2);
2844     gtk_widget_ref(welcome_pane);
2845
2846     /* empty all containers participating */
2847     gtk_container_foreach(GTK_CONTAINER(main_vbox),     foreach_remove_a_child, main_vbox);
2848     gtk_container_foreach(GTK_CONTAINER(stat_hbox),     foreach_remove_a_child, stat_hbox);
2849     gtk_container_foreach(GTK_CONTAINER(status_pane),   foreach_remove_a_child, status_pane);
2850     gtk_container_foreach(GTK_CONTAINER(main_pane_v1),  foreach_remove_a_child, main_pane_v1);
2851     gtk_container_foreach(GTK_CONTAINER(main_pane_v2),  foreach_remove_a_child, main_pane_v2);
2852     gtk_container_foreach(GTK_CONTAINER(main_pane_h1),  foreach_remove_a_child, main_pane_h1);
2853     gtk_container_foreach(GTK_CONTAINER(main_pane_h2),  foreach_remove_a_child, main_pane_h2);
2854
2855     /* add the menubar always at the top */
2856     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2857
2858     /* main toolbar */
2859     gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2860
2861     /* filter toolbar in toolbar area */
2862     if (!prefs.filter_toolbar_show_in_statusbar) {
2863         gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2864     }
2865
2866     /* fill the main layout panes */
2867     switch(prefs.gui_layout_type) {
2868     case(layout_type_5):
2869         main_first_pane  = main_pane_v1;
2870         main_second_pane = main_pane_v2;
2871         split_top_left = FALSE;
2872         break;
2873     case(layout_type_2):
2874         main_first_pane  = main_pane_v1;
2875         main_second_pane = main_pane_h1;
2876         split_top_left = FALSE;
2877         break;
2878     case(layout_type_1):
2879         main_first_pane  = main_pane_v1;
2880         main_second_pane = main_pane_h1;
2881         split_top_left = TRUE;
2882         break;
2883     case(layout_type_4):
2884         main_first_pane  = main_pane_h1;
2885         main_second_pane = main_pane_v1;
2886         split_top_left = FALSE;
2887         break;
2888     case(layout_type_3):
2889         main_first_pane  = main_pane_h1;
2890         main_second_pane = main_pane_v1;
2891         split_top_left = TRUE;
2892         break;
2893     case(layout_type_6):
2894         main_first_pane  = main_pane_h1;
2895         main_second_pane = main_pane_h2;
2896         split_top_left = FALSE;
2897         break;
2898     default:
2899         main_first_pane = NULL;
2900         main_second_pane = NULL;
2901         split_top_left = FALSE;
2902         g_assert_not_reached();
2903     }
2904     if (split_top_left) {
2905         first_pane_widget1 = main_second_pane;
2906         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2907         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2908         first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2909     } else {
2910         first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2911         first_pane_widget2 = main_second_pane;
2912         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2913         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2914     }
2915     if (first_pane_widget1 != NULL)
2916         gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2917     if (first_pane_widget2 != NULL)
2918         gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2919     if (second_pane_widget1 != NULL)
2920         gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2921     if (second_pane_widget2 != NULL)
2922         gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2923
2924     gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2925
2926     /* welcome pane */
2927     gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2928
2929     /* statusbar hbox */
2930     gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2931
2932     /* filter toolbar in statusbar hbox */
2933     if (prefs.filter_toolbar_show_in_statusbar) {
2934         gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2935     }
2936
2937     /* statusbar */
2938     gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2939     gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2940     gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2941
2942     /* hide widgets on users recent settings */
2943     main_widgets_show_or_hide();
2944
2945     gtk_widget_show(main_vbox);
2946 }
2947
2948 static void
2949 is_widget_visible(GtkWidget *widget, gpointer data)
2950 {
2951     gboolean *is_visible = data;
2952
2953     if (!*is_visible) {
2954         if (GTK_WIDGET_VISIBLE(widget))
2955             *is_visible = TRUE;
2956     }
2957 }
2958
2959
2960 #if 0
2961 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2962    As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2963 GtkWidget *
2964 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2965 {
2966     GtkWidget *w, *item_hb;
2967 #if GTK_MAJOR_VERSION >= 2
2968     gchar *formatted_message;
2969 #endif
2970
2971
2972     item_hb = gtk_hbox_new(FALSE, 1);
2973
2974     w = BUTTON_NEW_FROM_STOCK(stock_item);
2975     WIDGET_SET_SIZE(w, 60, 60);
2976 #if GTK_MAJOR_VERSION >= 2
2977     gtk_button_set_label(GTK_BUTTON(w), label);
2978 #endif
2979     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
2980     SIGNAL_CONNECT(w, "clicked", callback, callback_data);
2981
2982     w = gtk_label_new(message);
2983         gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2984 #if GTK_MAJOR_VERSION >= 2
2985     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
2986     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
2987     g_free(formatted_message);
2988 #endif
2989
2990     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
2991
2992     return item_hb;
2993 }
2994
2995
2996 /* XXX - the layout has to be improved */
2997 GtkWidget *
2998 welcome_new(void)
2999 {
3000     GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
3001     GtkWidget *w, *icon;
3002     gchar * message;
3003
3004
3005     welcome_scrollw = scrolled_window_new(NULL, NULL);
3006
3007     welcome_hb = gtk_hbox_new(FALSE, 1);
3008         /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
3009
3010     welcome_vb = gtk_vbox_new(FALSE, 1);
3011
3012     item_hb = gtk_hbox_new(FALSE, 1);
3013
3014     icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
3015     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
3016
3017 #if GTK_MAJOR_VERSION < 2
3018     message = "Welcome to Ethereal!";
3019 #else
3020     message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
3021 #endif
3022     w = gtk_label_new(message);
3023 #if GTK_MAJOR_VERSION >= 2
3024     gtk_label_set_markup(GTK_LABEL(w), message);
3025 #endif
3026     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3027     gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3028
3029     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3030
3031     w = gtk_label_new("What would you like to do?");
3032     gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
3033     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3034
3035 #ifdef HAVE_LIBPCAP
3036     item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START, 
3037         "Capture",
3038         "Capture live data from your network", 
3039         GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
3040     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3041 #endif
3042
3043     item_hb = welcome_item(GTK_STOCK_OPEN, 
3044         "Open",
3045         "Open a previously captured file",
3046         GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
3047     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3048
3049 #if (GLIB_MAJOR_VERSION >= 2)
3050     item_hb = welcome_item(GTK_STOCK_HOME, 
3051         "Home",
3052         "Visit the Ethereal homepage",
3053         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
3054     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3055 #endif
3056
3057     /* the end */
3058     w = gtk_label_new("");
3059     gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
3060
3061     w = gtk_label_new("");
3062     gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3063
3064     gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3065
3066     w = gtk_label_new("");
3067     gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3068
3069     gtk_widget_show_all(welcome_hb);
3070
3071     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3072                                           welcome_hb);
3073     gtk_widget_show_all(welcome_scrollw);
3074
3075     return welcome_scrollw;
3076 }
3077 #endif /* 0 */
3078
3079 static GtkWidget *
3080 welcome_new(void)
3081 {
3082     /* this is just a dummy to fill up window space, simply showing nothing */
3083     return scrolled_window_new(NULL, NULL);
3084 }
3085
3086
3087
3088 /*
3089  * XXX - this doesn't appear to work with the paned widgets in
3090  * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3091  * and the other pane doesn't grow to take up the rest of the pane.
3092  * It does appear to work with GTK+ 2.x.
3093  */
3094 void
3095 main_widgets_show_or_hide(void)
3096 {
3097     gboolean main_second_pane_show;
3098
3099     if (recent.main_toolbar_show) {
3100         gtk_widget_show(main_tb);
3101     } else {
3102         gtk_widget_hide(main_tb);
3103     }
3104
3105     /*
3106      * Show the status hbox if either:
3107      *
3108      *    1) we're showing the filter toolbar and we want it in the status
3109      *       line
3110      *
3111      * or
3112      *
3113      *    2) we're showing the status bar.
3114      */
3115     if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3116          recent.statusbar_show) {
3117         gtk_widget_show(stat_hbox);
3118     } else {
3119         gtk_widget_hide(stat_hbox);
3120     }
3121
3122     if (recent.statusbar_show) {
3123         gtk_widget_show(status_pane);
3124     } else {
3125         gtk_widget_hide(status_pane);
3126     }
3127
3128     if (recent.filter_toolbar_show) {
3129         gtk_widget_show(filter_tb);
3130     } else {
3131         gtk_widget_hide(filter_tb);
3132     }
3133
3134     if (recent.packet_list_show && have_capture_file) {
3135         gtk_widget_show(pkt_scrollw);
3136     } else {
3137         gtk_widget_hide(pkt_scrollw);
3138     }
3139
3140     if (recent.tree_view_show && have_capture_file) {
3141         gtk_widget_show(tv_scrollw);
3142     } else {
3143         gtk_widget_hide(tv_scrollw);
3144     }
3145
3146     if (recent.byte_view_show && have_capture_file) {
3147         gtk_widget_show(byte_nb_ptr);
3148     } else {
3149         gtk_widget_hide(byte_nb_ptr);
3150     }
3151
3152     if (have_capture_file) {
3153         gtk_widget_show(main_first_pane);
3154     } else {
3155         gtk_widget_hide(main_first_pane);
3156     }
3157
3158     /*
3159      * Is anything in "main_second_pane" visible?
3160      * If so, show it, otherwise hide it.
3161      */
3162     main_second_pane_show = FALSE;
3163     gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3164                           &main_second_pane_show);
3165     if (main_second_pane_show) {
3166         gtk_widget_show(main_second_pane);
3167     } else {
3168         gtk_widget_hide(main_second_pane);
3169     }
3170
3171     if (!have_capture_file) {
3172         if(welcome_pane) {
3173             gtk_widget_show(welcome_pane);
3174         }
3175     } else {
3176         gtk_widget_hide(welcome_pane);
3177     }
3178 }
3179
3180
3181 #if GTK_MAJOR_VERSION >= 2
3182 /* called, when the window state changes (minimized, maximized, ...) */
3183 static int
3184 window_state_event_cb (GtkWidget *widget _U_,
3185                        GdkEvent *event,
3186                        gpointer  data _U_)
3187 {
3188     GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3189
3190     if( (event->type) == (GDK_WINDOW_STATE)) {
3191         if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3192             /* we might have dialogs popped up while we where iconified,
3193                show em now */
3194             display_queued_messages();
3195         }
3196     }
3197     return FALSE;
3198 }
3199 #endif
3200
3201
3202 static void
3203 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3204 {
3205     GtkWidget     
3206                   *filter_bt, *filter_cm, *filter_te,
3207                   *filter_add_expr_bt,
3208                   *filter_apply,
3209                   *filter_reset;
3210     GList         *dfilter_list = NULL;
3211     GtkTooltips   *tooltips;
3212     GtkAccelGroup *accel;
3213         gchar         *title;
3214     /* Display filter construct dialog has an Apply button, and "OK" not
3215        only sets our text widget, it activates it (i.e., it causes us to
3216        filter the capture). */
3217     static construct_args_t args = {
3218         "Ethereal: Display Filter",
3219         TRUE,
3220         TRUE
3221     };
3222
3223     /* use user-defined title if preference is set */
3224     title = create_user_window_title("The Ethereal Network Analyzer");
3225
3226     /* Main window */
3227     top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3228     g_free(title);
3229
3230     tooltips = gtk_tooltips_new();
3231
3232 #ifdef _WIN32 
3233 #if GTK_MAJOR_VERSION < 2
3234     /* has to be done, after top_level window is created */
3235     app_font_gtk1_init(top_level);
3236 #endif
3237 #endif
3238     
3239     gtk_widget_set_name(top_level, "main window");
3240     SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3241                    NULL);
3242 #if GTK_MAJOR_VERSION >= 2
3243     SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3244                          G_CALLBACK (window_state_event_cb), NULL);
3245 #endif
3246
3247     gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3248
3249     /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3250     main_vbox = gtk_vbox_new(FALSE, 1);
3251     gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3252     gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3253     gtk_widget_show(main_vbox);
3254
3255     /* Menu bar */
3256     menubar = main_menu_new(&accel);
3257     gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3258     gtk_widget_show(menubar);
3259
3260     /* Main Toolbar */
3261     main_tb = toolbar_new();
3262     gtk_widget_show (main_tb);
3263
3264     /* Packet list */
3265     pkt_scrollw = packet_list_new(prefs);
3266     WIDGET_SET_SIZE(packet_list, -1, pl_size);
3267     gtk_widget_show(pkt_scrollw);
3268
3269     /* Tree view */
3270     tv_scrollw = main_tree_view_new(prefs, &tree_view);
3271     WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3272     gtk_widget_show(tv_scrollw);
3273
3274 #if GTK_MAJOR_VERSION < 2
3275     SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3276     SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3277                    NULL);
3278 #else
3279     SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3280                    "changed", tree_view_selection_changed_cb, NULL);
3281 #endif
3282     SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3283                    OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3284     gtk_widget_show(tree_view);
3285
3286     /* Byte view. */
3287     byte_nb_ptr = byte_view_new();
3288     WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3289     gtk_widget_show(byte_nb_ptr);
3290
3291     SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3292                    OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3293
3294
3295     /* Panes for the packet list, tree, and byte view */
3296     main_pane_v1 = gtk_vpaned_new();
3297     gtk_widget_show(main_pane_v1);
3298     main_pane_v2 = gtk_vpaned_new();
3299     gtk_widget_show(main_pane_v2);
3300     main_pane_h1 = gtk_hpaned_new();
3301     gtk_widget_show(main_pane_h1);
3302     main_pane_h2 = gtk_hpaned_new();
3303     gtk_widget_show(main_pane_h2);
3304
3305     /* filter toolbar */
3306 #if GTK_MAJOR_VERSION < 2
3307     filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3308                                GTK_TOOLBAR_BOTH);
3309 #else
3310     filter_tb = gtk_toolbar_new();
3311     gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3312                                 GTK_ORIENTATION_HORIZONTAL);
3313 #endif /* GTK_MAJOR_VERSION */
3314     gtk_widget_show(filter_tb);
3315
3316     /* Create the "Filter:" button */
3317     filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3318     SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3319     gtk_widget_show(filter_bt);
3320     OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3321
3322     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt, 
3323         "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3324
3325     /* Create the filter combobox */
3326     filter_cm = gtk_combo_new();
3327     dfilter_list = NULL;
3328     gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3329     gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3330     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3331     filter_te = GTK_COMBO(filter_cm)->entry;
3332     main_display_filter_widget=filter_te;
3333     OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3334     OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3335     OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3336     SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3337     SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3338     WIDGET_SET_SIZE(filter_cm, 400, -1);
3339     gtk_widget_show(filter_cm);
3340     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm, 
3341         NULL, NULL);
3342     /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3343     gtk_tooltips_set_tip(tooltips, filter_te, 
3344         "Enter a display filter, or choose one of your recently used filters. "
3345         "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).", 
3346         NULL);
3347
3348     /* Create the "Add Expression..." button, to pop up a dialog
3349        for constructing filter comparison expressions. */
3350     filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3351     OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3352     SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3353     gtk_widget_show(filter_add_expr_bt);
3354     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt, 
3355         "Add an expression to this filter string", "Private");
3356
3357     /* Create the "Clear" button */
3358     filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3359     OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3360     SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3361     gtk_widget_show(filter_reset);
3362     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset, 
3363         "Clear this filter string and update the display", "Private");
3364
3365     /* Create the "Apply" button */
3366     filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3367     OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3368     SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3369     gtk_widget_show(filter_apply);
3370     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply, 
3371         "Apply this filter string to the display", "Private");
3372
3373     /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3374      * of any widget that ends up calling a callback which needs
3375      * that text entry pointer */
3376     set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3377     set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3378                          filter_te);
3379     set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3380                          filter_te);
3381     set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3382                          filter_te);
3383     set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3384                          filter_te);
3385     set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3386                          filter_te);
3387     set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3388                          filter_te);
3389     set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3390                          filter_te);
3391     set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3392                          filter_te);
3393     set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3394                          filter_te);
3395     set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3396                          filter_te);
3397     set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3398                          filter_te);
3399     set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3400                          filter_te);
3401     set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3402                          filter_te);
3403     set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3404                          filter_te);
3405     set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3406     OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3407     OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3408
3409     /* info (main) statusbar */
3410     info_bar = info_bar_new();
3411     gtk_widget_show(info_bar);
3412
3413     /* packets statusbar */
3414     packets_bar = packets_bar_new();
3415     gtk_widget_show(packets_bar);
3416
3417     /* Filter/status hbox */
3418     stat_hbox = gtk_hbox_new(FALSE, 1);
3419     gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3420     gtk_widget_show(stat_hbox);
3421
3422     /* Pane for the statusbar */
3423     status_pane = gtk_hpaned_new();
3424     gtk_widget_show(status_pane);
3425
3426     /* Pane for the welcome screen */
3427     welcome_pane = welcome_new();
3428     gtk_widget_show(welcome_pane);
3429 }
3430
3431 static void
3432 show_main_window(gboolean doing_work)
3433 {
3434   main_set_for_capture_file(doing_work);
3435
3436   /*** we have finished all init things, show the main window ***/
3437   gtk_widget_show(top_level);
3438
3439   /* the window can be maximized only, if it's visible, so do it after show! */
3440   main_load_window_geometry(top_level);
3441
3442   /* process all pending GUI events before continue */
3443   while (gtk_events_pending()) gtk_main_iteration();
3444
3445   /* Pop up any queued-up alert boxes. */
3446   display_queued_messages();
3447 }