from Graeme Hewson: "Fixes for ethereal config files"
[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
69 /* general (not GTK specific) */
70 #include "svnversion.h"
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"     /* beware: ui_util.h exists twice! */
86 #include <epan/tap.h>
87 #include "util.h"
88 #include "clopts_common.h"
89 #include "version_info.h"
90 #include "merge.h"
91
92 #ifdef HAVE_LIBPCAP
93 #include <pcap.h>
94 #include "pcap-util.h"
95 #include "capture.h"
96 #endif
97
98 #ifdef _WIN32
99 #include "capture-wpcap.h"
100 #include "capture_wpcap_packet.h"
101 #endif
102
103 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
104 #include "ethclist.h"
105 #endif
106
107 /* GTK related */
108 #include "statusbar.h"
109 #include "alert_box.h"
110 #include "dlg_utils.h"
111 #include "gtkglobals.h"
112 #include "colors.h"
113 #include "ui_util.h"        /* beware: ui_util.h exists twice! */
114 #include "compat_macros.h"
115
116 #include "main.h"
117 #include "menu.h"
118 #include "../main_window.h"
119 #include "../menu.h"
120 #include "file_dlg.h"
121 #include <epan/column.h>
122 #include "proto_draw.h"
123 #include "keys.h"
124 #include "packet_win.h"
125 #include "toolbar.h"
126 #include "find_dlg.h"
127 #include "packet_list.h"
128 #include "recent.h"
129 #include "follow_dlg.h"
130 #include "font_utils.h"
131 #include "about_dlg.h"
132 #include "help_dlg.h"
133 #include "decode_as_dlg.h"
134 #include "webbrowser.h"
135 #include "capture_dlg.h"
136 #if 0
137 #include "../image/eicon3d64.xpm"
138 #endif
139 #include "capture_ui_utils.h"
140 #include "log.h"
141
142
143
144 /*
145  * Files under personal and global preferences directories in which
146  * GTK settings for Ethereal are stored.
147  */
148 #define RC_FILE "gtkrc"
149
150 #ifdef HAVE_LIBPCAP
151 #define DEF_READY_MESSAGE " Ready to load or capture"
152 #else
153 #define DEF_READY_MESSAGE " Ready to load file"
154 #endif
155
156 capture_file cfile;
157 GtkWidget   *main_display_filter_widget=NULL;
158 GtkWidget   *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
159 static GtkWidget   *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
160 static GtkWidget   *main_first_pane, *main_second_pane;
161 static GtkWidget   *status_pane;
162 static GtkWidget   *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
163 static GtkWidget        *info_bar;
164 static GtkWidget    *packets_bar = NULL;
165 static GtkWidget    *welcome_pane;
166 static guint    main_ctx, file_ctx, help_ctx;
167 static guint        packets_ctx;
168 static gchar        *packets_str = NULL;
169 GString *comp_info_str, *runtime_info_str;
170 gchar       *ethereal_path = NULL;
171 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
172
173 #ifdef _WIN32
174 static gboolean has_console;    /* TRUE if app has console */
175 static void destroy_console(void);
176 #endif
177 static void console_log_handler(const char *log_domain,
178     GLogLevelFlags log_level, const char *message, gpointer user_data);
179
180 #ifdef HAVE_LIBPCAP
181 static gboolean list_link_layer_types;
182 capture_options global_capture_opts;
183 capture_options *capture_opts = &global_capture_opts;
184 #endif
185
186
187 static void create_main_window(gint, gint, gint, e_prefs*);
188 static void show_main_window(gboolean);
189 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
190 static void main_save_window_geometry(GtkWidget *widget);
191
192 #define E_DFILTER_CM_KEY          "display_filter_combo"
193 #define E_DFILTER_FL_KEY          "display_filter_list"
194
195
196
197 /* Match selected byte pattern */
198 static void
199 match_selected_cb_do(gpointer data, int action, gchar *text)
200 {
201     GtkWidget           *filter_te;
202     char                *cur_filter, *new_filter;
203
204     if (!text)
205         return;
206     g_assert(data);
207     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
208     g_assert(filter_te);
209
210     cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
211
212     switch (action&MATCH_SELECTED_MASK) {
213
214     case MATCH_SELECTED_REPLACE:
215         new_filter = g_strdup(text);
216         break;
217
218     case MATCH_SELECTED_AND:
219         if ((!cur_filter) || (0 == strlen(cur_filter)))
220             new_filter = g_strdup(text);
221         else
222             new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
223         break;
224
225     case MATCH_SELECTED_OR:
226         if ((!cur_filter) || (0 == strlen(cur_filter)))
227             new_filter = g_strdup(text);
228         else
229             new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
230         break;
231
232     case MATCH_SELECTED_NOT:
233         new_filter = g_strconcat("!(", text, ")", NULL);
234         break;
235
236     case MATCH_SELECTED_AND_NOT:
237         if ((!cur_filter) || (0 == strlen(cur_filter)))
238             new_filter = g_strconcat("!(", text, ")", NULL);
239         else
240             new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
241         break;
242
243     case MATCH_SELECTED_OR_NOT:
244         if ((!cur_filter) || (0 == strlen(cur_filter)))
245             new_filter = g_strconcat("!(", text, ")", NULL);
246         else
247             new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
248         break;
249
250     default:
251         g_assert_not_reached();
252         new_filter = NULL;
253         break;
254     }
255
256     /* Free up the copy we got of the old filter text. */
257     g_free(cur_filter);
258
259     /* create a new one and set the display filter entry accordingly */
260     gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
261
262     /* Run the display filter so it goes in effect. */
263     if (action&MATCH_SELECTED_APPLY_NOW)
264         main_filter_packets(&cfile, new_filter, FALSE);
265
266     /* Free up the new filter text. */
267     g_free(new_filter);
268
269     /* Free up the generated text we were handed. */
270     g_free(text);
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 = g_malloc0(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
1085 #ifdef SVNVERSION
1086         " (" SVNVERSION ")"
1087 #endif
1088         "\n (C) 1998-2005 Gerald Combs <gerald@ethereal.com>"
1089         "\n\n%s\n\n%s\n",
1090         comp_info_str->str, runtime_info_str->str);
1091   } else {
1092     output = stderr;
1093   }
1094 #ifdef HAVE_LIBPCAP
1095   fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n", PACKAGE);        
1096   fprintf(output, "\t[ -b <capture ring buffer option> ] ...\n");
1097   fprintf(output, "\t[ -B capture buffer size (Win32 only) ]\n"); 
1098   fprintf(output, "\t[ -c <capture packet count> ] [ -f <capture filter> ]\n");
1099   fprintf(output, "\t[ -g <packet number> ]\n");
1100   fprintf(output, "\t[ -i <capture interface> ] [ -m <font> ] [ -N <name resolving flags> ]\n");
1101   fprintf(output, "\t[ -o <preference/recent setting> ] ...\n");
1102   fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ] [ -s <capture snaplen> ]\n");
1103   fprintf(output, "\t[ -t <time stamp format> ]\n");
1104   fprintf(output, "\t[ -w <savefile> ] [ -y <capture link type> ] [ -z <statistics> ]\n");
1105   fprintf(output, "\t[ <infile> ]\n");
1106 #else
1107   fprintf(output, "\n%s [ -vh ] [ -n ] [ -g <packet number> ] [ -m <font> ]\n", PACKAGE);
1108   fprintf(output, "\t[ -N <resolving flags> ] [ -o <preference/recent setting> ...\n");
1109   fprintf(output, "\t[ -r <infile> ] [ -R <read (display) filter> ]\n");
1110   fprintf(output, "\t[ -t <time stamp format> ]\n");
1111   fprintf(output, "\t[ -z <statistics ] [ <infile> ]\n");
1112 #endif
1113
1114 #ifdef _WIN32
1115   destroy_console();
1116 #endif
1117 }
1118
1119 static void
1120 show_version(void)
1121 {
1122 #ifdef _WIN32
1123   create_console();
1124 #endif
1125
1126   printf(PACKAGE " " VERSION
1127 #ifdef SVNVERSION
1128       " (" SVNVERSION ")"
1129 #endif
1130       "\n\n%s\n\n%s\n",
1131       comp_info_str->str, runtime_info_str->str);
1132
1133 #ifdef _WIN32
1134   destroy_console();
1135 #endif
1136 }
1137
1138 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1139 /* 
1140    Once every 3 seconds we get a callback here which we use to update
1141    the tap extensions. Since Gtk1 is single threaded we dont have to
1142    worry about any locking or critical regions.
1143  */
1144 static gint
1145 update_cb(gpointer data _U_)
1146 {
1147         draw_tap_listeners(FALSE);
1148         return 1;
1149 }
1150 #else
1151
1152 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1153    use threads all updte_thread_mutex can be dropped and protect/unprotect 
1154    would just be empty functions.
1155
1156    This allows gtk2-rpcstat.c and friends to be copied unmodified to 
1157    gtk1-ethereal and it will just work.
1158  */
1159 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1160 gpointer
1161 update_thread(gpointer data _U_)
1162 {
1163     while(1){
1164         GTimeVal tv1, tv2;
1165         g_get_current_time(&tv1);
1166         g_static_mutex_lock(&update_thread_mutex);
1167         gdk_threads_enter();
1168         draw_tap_listeners(FALSE);
1169         gdk_threads_leave();
1170         g_static_mutex_unlock(&update_thread_mutex);
1171         g_thread_yield();
1172         g_get_current_time(&tv2);
1173         if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1174             (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1175             g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1176                      (tv2.tv_sec * 1000000 + tv2.tv_usec));
1177         }
1178     }
1179     return NULL;
1180 }
1181 #endif
1182 void
1183 protect_thread_critical_region(void)
1184 {
1185 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1186     g_static_mutex_lock(&update_thread_mutex);
1187 #endif
1188 }
1189 void
1190 unprotect_thread_critical_region(void)
1191 {
1192 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1193     g_static_mutex_unlock(&update_thread_mutex);
1194 #endif
1195 }
1196
1197 /* Set the file name in the status line, in the name for the main window,
1198    and in the name for the main window's icon. */
1199 static void
1200 set_display_filename(capture_file *cf)
1201 {
1202   const gchar *name_ptr;
1203   gchar       *status_msg;
1204   gchar       *size_str;
1205   gchar       *win_name;
1206
1207   name_ptr = cf_get_display_name(cf);
1208         
1209   if (!cf->is_tempfile && cf->filename) {
1210     /* Add this filename to the list of recent files in the "Recent Files" submenu */
1211     add_menu_recent_capture_file(cf->filename);
1212   }
1213
1214   /* convert file size */
1215   if (cf->f_len/1024/1024 > 10) {
1216     size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
1217   } else if (cf->f_len/1024 > 10) {
1218     size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
1219   } else {
1220     size_str = g_strdup_printf("%ld Bytes", cf->f_len);
1221   }
1222
1223   /* statusbar */
1224   status_msg = g_strdup_printf(" File: \"%s\" %s %02u:%02u:%02u", 
1225     (cf->filename) ? cf->filename : "", size_str,
1226     cf->esec/3600, cf->esec%3600/60, cf->esec%60);
1227   g_free(size_str);
1228   statusbar_push_file_msg(status_msg);
1229   g_free(status_msg);
1230
1231   /* window title */
1232   win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1233   set_main_window_name(win_name);
1234   g_free(win_name);
1235 }
1236
1237
1238 static void
1239 main_cf_cb_file_closed(capture_file *cf)
1240 {
1241     /* Destroy all windows, which refer to the
1242        capture file we're closing. */
1243     destroy_cfile_wins();
1244
1245     /* Clear any file-related status bar messages.
1246        XXX - should be "clear *ALL* file-related status bar messages;
1247        will there ever be more than one on the stack? */
1248     statusbar_pop_file_msg();
1249
1250     /* go back to "No packets" */
1251     packets_bar_update();
1252
1253     /* Restore the standard title bar message. */
1254     set_main_window_name("The Ethereal Network Analyzer");
1255
1256     /* Disable all menu items that make sense only if you have a capture. */
1257     set_menus_for_capture_file(FALSE);
1258     set_menus_for_unsaved_capture_file(FALSE);
1259     set_menus_for_captured_packets(FALSE);
1260     set_menus_for_selected_packet(cf);
1261     set_menus_for_capture_in_progress(FALSE);
1262     set_menus_for_selected_tree_row(cf);
1263
1264     /* Set up main window for no capture file. */
1265     main_set_for_capture_file(FALSE);
1266 }
1267
1268 static void
1269 main_cf_cb_file_read_start(capture_file *cf)
1270 {
1271   const gchar *name_ptr;
1272   gchar       *load_msg;
1273
1274   name_ptr = get_basename(cf->filename);
1275
1276   load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1277   statusbar_push_file_msg(load_msg);
1278   g_free(load_msg);
1279 }
1280
1281 static void
1282 main_cf_cb_file_read_finished(capture_file *cf)
1283 {
1284     statusbar_pop_file_msg();
1285     set_display_filename(cf);
1286
1287     /* Enable menu items that make sense if you have a capture file you've
1288      finished reading. */
1289     set_menus_for_capture_file(TRUE);
1290     set_menus_for_unsaved_capture_file(!cf->user_saved);
1291
1292     /* Enable menu items that make sense if you have some captured packets. */
1293     set_menus_for_captured_packets(TRUE);
1294
1295     /* Set up main window for a capture file. */
1296     main_set_for_capture_file(TRUE);
1297 }
1298
1299 #ifdef HAVE_LIBPCAP
1300 static void
1301 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1302 {
1303     gchar *title;
1304
1305
1306     if(capture_opts->iface) {
1307         title = g_strdup_printf("%s: Capturing - Ethereal",
1308                             get_interface_descriptive_name(capture_opts->iface));
1309     } else {
1310         title = g_strdup_printf("Capturing - Ethereal");
1311     }
1312     set_main_window_name(title);
1313     g_free(title);
1314
1315     /* Disable menu items that make no sense if you're currently running
1316        a capture. */
1317     set_menus_for_capture_in_progress(TRUE);
1318
1319     /* update statusbar */
1320     statusbar_push_file_msg("Waiting for capture input data ...");
1321
1322     /* Don't set up main window for a capture file. */
1323     main_set_for_capture_file(FALSE);
1324 }
1325
1326 static void
1327 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1328 {
1329     gchar *capture_msg;
1330
1331
1332     /* Enable menu items that make sense if you have some captured
1333        packets (yes, I know, we don't have any *yet*). */
1334     set_menus_for_captured_packets(TRUE);
1335
1336     statusbar_pop_file_msg();
1337
1338     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s", 
1339         get_interface_descriptive_name(capture_opts->iface), 
1340         (capture_opts->save_file) ? capture_opts->save_file : "");
1341
1342     statusbar_push_file_msg(capture_msg);
1343
1344     g_free(capture_msg);
1345
1346     /* Set up main window for a capture file. */
1347     main_set_for_capture_file(TRUE);
1348 }
1349
1350 static void
1351 main_cf_cb_live_capture_update_continue(capture_file *cf)
1352 {
1353     gchar *capture_msg;
1354
1355
1356     statusbar_pop_file_msg();
1357
1358     if (cf->f_len/1024/1024 > 10) {
1359         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB", 
1360             get_interface_descriptive_name(capture_opts->iface), 
1361             capture_opts->save_file,
1362             cf->f_len/1024/1024);
1363     } else if (cf->f_len/1024 > 10) {
1364         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB", 
1365             get_interface_descriptive_name(capture_opts->iface), 
1366             capture_opts->save_file,
1367             cf->f_len/1024);
1368     } else {
1369         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes", 
1370             get_interface_descriptive_name(capture_opts->iface), 
1371             capture_opts->save_file,
1372             cf->f_len);
1373     }
1374
1375     statusbar_push_file_msg(capture_msg);
1376 }
1377
1378 static void
1379 main_cf_cb_live_capture_update_finished(capture_file *cf)
1380 {
1381     /* Pop the "<live capture in progress>" message off the status bar. */
1382     statusbar_pop_file_msg();
1383
1384     set_display_filename(cf);
1385
1386     /* Enable menu items that make sense if you're not currently running
1387      a capture. */
1388     set_menus_for_capture_in_progress(FALSE);
1389
1390     /* Enable menu items that make sense if you have a capture file
1391      you've finished reading. */
1392     set_menus_for_capture_file(TRUE);
1393     set_menus_for_unsaved_capture_file(!cf->user_saved);
1394
1395     /* Set up main window for a capture file. */
1396     main_set_for_capture_file(TRUE);
1397 }
1398
1399 static void
1400 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1401 {
1402     gchar *capture_msg;
1403
1404
1405     /* Enable menu items that make sense if you have some captured
1406        packets (yes, I know, we don't have any *yet*). */
1407     /*set_menus_for_captured_packets(TRUE);*/
1408
1409     statusbar_pop_file_msg();
1410
1411     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s", 
1412         get_interface_descriptive_name(capture_opts->iface), 
1413         (capture_opts->save_file) ? capture_opts->save_file : "");
1414
1415     statusbar_push_file_msg(capture_msg);
1416     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " <capturing>");
1417
1418     g_free(capture_msg);
1419
1420     /* Don't set up main window for a capture file. */
1421     main_set_for_capture_file(FALSE);
1422 }
1423
1424 static void
1425 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1426 {
1427     /* Pop the "<live capture in progress>" message off the status bar. */
1428     statusbar_pop_file_msg();
1429
1430     /* Pop the "<capturing>" message off the status bar */
1431         gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1432
1433     /*set_display_filename(cf);*/
1434
1435     /* Enable menu items that make sense if you're not currently running
1436      a capture. */
1437     set_menus_for_capture_in_progress(FALSE);
1438
1439     /* We don't have loaded the capture file, this will be done later.
1440      * For now we still have simply a blank screen. */
1441 }
1442 #endif
1443
1444 static void
1445 main_cf_cb_packet_selected(gpointer data)
1446 {
1447     capture_file *cf = data;
1448
1449     /* Display the GUI protocol tree and hex dump.
1450       XXX - why do we dump core if we call "proto_tree_draw()"
1451       before calling "add_byte_views()"? */
1452     add_main_byte_views(cf->edt);
1453     main_proto_tree_draw(cf->edt->tree);
1454
1455     /* A packet is selected. */
1456     set_menus_for_selected_packet(cf);
1457 }
1458
1459 static void
1460 main_cf_cb_packet_unselected(capture_file *cf)
1461 {
1462     /* Clear out the display of that packet. */
1463     clear_tree_and_hex_views();
1464
1465     /* No packet is selected. */
1466     set_menus_for_selected_packet(cf);
1467 }
1468
1469 static void
1470 main_cf_cb_field_unselected(capture_file *cf)
1471 {
1472     statusbar_pop_field_msg();
1473     set_menus_for_selected_tree_row(cf);
1474 }
1475
1476 static void
1477 main_cf_cb_file_safe_started(gchar * filename)
1478 {
1479     const gchar  *name_ptr;
1480     gchar        *save_msg;
1481
1482     name_ptr = get_basename(filename);
1483
1484     save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1485
1486     statusbar_push_file_msg(save_msg);
1487     g_free(save_msg);
1488 }
1489
1490 static void
1491 main_cf_cb_file_safe_finished(gpointer data _U_)
1492 {
1493     /* Pop the "Saving:" message off the status bar. */
1494     statusbar_pop_file_msg();
1495 }
1496
1497 static void
1498 main_cf_cb_file_safe_failed(gpointer data _U_)
1499 {
1500     /* Pop the "Saving:" message off the status bar. */
1501     statusbar_pop_file_msg();
1502 }
1503
1504 static void
1505 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1506 {
1507     set_menus_for_unsaved_capture_file(FALSE);
1508 }
1509
1510 void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1511 {
1512     switch(event) {
1513     case(cf_cb_file_closed):
1514         main_cf_cb_file_closed(data);
1515         break;
1516     case(cf_cb_file_read_start):
1517         main_cf_cb_file_read_start(data);
1518         break;
1519     case(cf_cb_file_read_finished):
1520         main_cf_cb_file_read_finished(data);
1521         break;
1522 #ifdef HAVE_LIBPCAP
1523     case(cf_cb_live_capture_prepared):
1524         main_cf_cb_live_capture_prepared(data);
1525         break;
1526     case(cf_cb_live_capture_update_started):
1527         main_cf_cb_live_capture_update_started(data);
1528         break;
1529     case(cf_cb_live_capture_update_continue):
1530         main_cf_cb_live_capture_update_continue(data);
1531         break;
1532     case(cf_cb_live_capture_fixed_started):
1533         main_cf_cb_live_capture_fixed_started(data);
1534         break;
1535     case(cf_cb_live_capture_update_finished):
1536         main_cf_cb_live_capture_update_finished(data);
1537         break;
1538     case(cf_cb_live_capture_fixed_finished):
1539         main_cf_cb_live_capture_fixed_finished(data);
1540         break;
1541 #endif
1542     case(cf_cb_packet_selected):
1543         main_cf_cb_packet_selected(data);
1544         break;
1545     case(cf_cb_packet_unselected):
1546         main_cf_cb_packet_unselected(data);
1547         break;
1548     case(cf_cb_field_unselected):
1549         main_cf_cb_field_unselected(data);
1550         break;
1551     case(cf_cb_file_safe_started):
1552         main_cf_cb_file_safe_started(data);
1553         break;
1554     case(cf_cb_file_safe_finished):
1555         main_cf_cb_file_safe_finished(data);
1556         break;
1557     case(cf_cb_file_safe_reload_finished):
1558         main_cf_cb_file_safe_reload_finished(data);
1559         break;
1560     case(cf_cb_file_safe_failed):
1561         main_cf_cb_file_safe_failed(data);
1562         break;
1563     default:
1564         g_warning("main_cf_callback: event %u unknown", event);
1565         g_assert_not_reached();
1566     }
1567 }
1568
1569 /* And now our feature presentation... [ fade to music ] */
1570 int
1571 main(int argc, char *argv[])
1572 {
1573 #ifdef HAVE_LIBPCAP
1574   const char          *command_name;
1575 #endif
1576   char                *s;
1577   int                  i;
1578   int                  opt;
1579   extern char         *optarg;
1580   gboolean             arg_error = FALSE;
1581
1582 #ifdef _WIN32
1583   WSADATA              wsaData;
1584 #endif  /* _WIN32 */
1585
1586   char                *rf_path;
1587   int                  rf_open_errno;
1588   char                *gpf_path, *pf_path;
1589   char                *cf_path, *df_path;
1590   char                *gdp_path, *dp_path;
1591   int                  gpf_open_errno, gpf_read_errno;
1592   int                  pf_open_errno, pf_read_errno;
1593   int                  cf_open_errno, df_open_errno;
1594   int                  gdp_open_errno, gdp_read_errno;
1595   int                  dp_open_errno, dp_read_errno;
1596   int                  err;
1597 #ifdef HAVE_LIBPCAP
1598   gboolean             start_capture = FALSE;
1599   GList               *if_list;
1600   if_info_t           *if_info;
1601   GList               *lt_list, *lt_entry;
1602   data_link_info_t    *data_link_info;
1603   gchar                err_str[PCAP_ERRBUF_SIZE];
1604   gchar               *cant_get_if_list_errstr;
1605   gboolean             stats_known;
1606   struct pcap_stat     stats;
1607 #else
1608   gboolean             capture_option_specified = FALSE;
1609 #endif
1610   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1611   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1612   dfilter_t           *rfcode = NULL;
1613   gboolean             rfilter_parse_failed = FALSE;
1614   e_prefs             *prefs;
1615   char                 badopt;
1616   GtkWidget           *splash_win = NULL;
1617   gboolean             capture_child; /* True if this is the child for "-S" */
1618   GLogLevelFlags       log_flags;
1619   guint                go_to_packet = 0;
1620   int                  optind_initial;
1621
1622 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1623
1624 #ifdef HAVE_LIBPCAP
1625 #ifdef _WIN32
1626 #define OPTSTRING_CHILD "W:Z:"
1627 #define OPTSTRING_WIN32 "B:"
1628 #else
1629 #define OPTSTRING_CHILD "W:"
1630 #define OPTSTRING_WIN32 ""
1631 #endif  /* _WIN32 */
1632 #else
1633 #define OPTSTRING_CHILD ""
1634 #define OPTSTRING_WIN32 ""
1635 #endif  /* HAVE_LIBPCAP */
1636
1637   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1638     OPTSTRING_INIT OPTSTRING_WIN32;
1639
1640
1641   /*** create the compile and runtime version strings ***/
1642 #ifdef _WIN32
1643   /* Load wpcap if possible. Do this before collecting the run-time version information */
1644   load_wpcap();
1645
1646   /* ... and also load the packet.dll from wpcap */
1647   wpcap_packet_load();
1648
1649   /* Start windows sockets */
1650   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1651 #endif  /* _WIN32 */
1652
1653   /* Assemble the compile-time version information string */
1654   comp_info_str = g_string_new("Compiled ");
1655   g_string_append(comp_info_str, "with ");
1656   g_string_sprintfa(comp_info_str,
1657 #ifdef GTK_MAJOR_VERSION
1658                     "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1659                     GTK_MICRO_VERSION);
1660 #else
1661                     "GTK+ (version unknown)");
1662 #endif
1663
1664   g_string_append(comp_info_str, ", ");
1665   get_compiled_version_info(comp_info_str);
1666
1667   /* Assemble the run-time version information string */
1668   runtime_info_str = g_string_new("Running ");
1669   get_runtime_version_info(runtime_info_str);
1670
1671
1672   /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1673   /* (e.g. don't start GTK+, if we only have to show the command line help) */
1674   optind_initial = optind;
1675   while ((opt = getopt(argc, argv, optstring)) != -1) {
1676     switch (opt) {
1677       case 'h':        /* Print help and exit */
1678         print_usage(TRUE);
1679         exit(0);
1680         break;
1681       case 'v':        /* Show version and exit */
1682         show_version();
1683         exit(0);
1684         break;
1685       case 'G':        /* dump various field or other infos, see handle_dashG_option() */
1686   /* If invoked with the "-G" flag, we dump out information based on
1687      the argument to the "-G" flag; if no argument is specified,
1688      for backwards compatibility we dump out a glossary of display
1689      filter symbols.
1690
1691      We must do this before calling "gtk_init()", because "gtk_init()"
1692      tries to open an X display, and we don't want to have to do any X
1693      stuff just to do a build.
1694
1695      Given that we call "gtk_init()" before doing the regular argument
1696      list processing, so that it can handle X and GTK+ arguments and
1697      remove them from the list at which we look, this means we must do
1698      this before doing the regular argument list processing, as well.
1699
1700      This means that:
1701
1702         you must give the "-G" flag as the first flag on the command line;
1703
1704         you must give it as "-G", nothing more, nothing less;
1705
1706         the first argument after the "-G" flag, if present, will be used
1707         to specify the information to dump;
1708
1709         arguments after that will not be used. */        
1710         handle_dashG_option(argc, argv, "ethereal");
1711         /* will never return! */
1712         exit(0);
1713         break;
1714     }
1715   }
1716
1717   /* set getopt index back to initial value, so it will start with the first command line parameter again */
1718   /* (XXX - this seems to be portable, but time will tell) */
1719   optind = optind_initial;
1720
1721
1722   /* Set the current locale according to the program environment.
1723    * We haven't localized anything, but some GTK widgets are localized
1724    * (the file selection dialogue, for example).
1725    * This also sets the C-language locale to the native environment. */
1726   gtk_set_locale();
1727
1728   /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1729   gtk_init (&argc, &argv);
1730
1731   cf_callback_add(main_cf_callback, NULL);
1732
1733 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1734   /* initialize our GTK eth_clist_type */
1735   init_eth_clist_type();
1736 #endif
1737
1738   ethereal_path = argv[0];
1739
1740   /* Arrange that if we have no console window, and a GLib message logging
1741      routine is called to log a message, we pop up a console window.
1742
1743      We do that by inserting our own handler for all messages logged
1744      to the default domain; that handler pops up a console if necessary,
1745      and then calls the default handler. */
1746
1747   /* We might want to have component specific log levels later ... */
1748
1749   /* the default_log_handler will use stdout, which makes trouble with the */
1750   /* capture child, as it uses stdout for it's sync_pipe */
1751   /* so do the filtering in the console_log_handler and not here */
1752   log_flags = 
1753                     G_LOG_LEVEL_ERROR|
1754                     G_LOG_LEVEL_CRITICAL|
1755                     G_LOG_LEVEL_WARNING|
1756                     G_LOG_LEVEL_MESSAGE|
1757                     G_LOG_LEVEL_INFO|
1758                     G_LOG_LEVEL_DEBUG|
1759                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1760
1761   g_log_set_handler(NULL,
1762                     log_flags,
1763                     console_log_handler, NULL /* user_data */);
1764
1765 #ifdef HAVE_LIBPCAP
1766   g_log_set_handler(LOG_DOMAIN_CAPTURE,
1767                     log_flags,
1768             console_log_handler, NULL /* user_data */);
1769   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1770                     log_flags,
1771             console_log_handler, NULL /* user_data */);
1772
1773   /* Set the initial values in the capture_opts. This might be overwritten 
1774      by preference settings and then again by the command line parameters. */
1775   capture_opts_init(capture_opts, &cfile);
1776
1777   capture_opts->snaplen             = MIN_PACKET_SIZE;
1778   capture_opts->has_ring_num_files  = TRUE;
1779
1780   command_name = get_basename(ethereal_path);
1781   /* Set "capture_child" to indicate whether this is going to be a child
1782      process for a "-S" capture. */
1783   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1784   if (capture_child) {
1785     strcat(optstring, OPTSTRING_CHILD);
1786   }
1787 #endif
1788
1789   /* We want a splash screen only if we're not a child process.
1790      We won't come till here, if we had a "console only" command line parameter. */
1791 #ifdef HAVE_LIBPCAP
1792   if (!capture_child)
1793 #endif
1794     splash_win = splash_new("Loading Ethereal ...");
1795
1796   splash_update(splash_win, "Registering dissectors ...");
1797
1798   /* Register all dissectors; we must do this before checking for the
1799      "-G" flag, as the "-G" flag dumps information registered by the
1800      dissectors, and we must do it before we read the preferences, in
1801      case any dissectors register preferences. */
1802   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1803             failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1804
1805   splash_update(splash_win, "Registering tap listeners ...");
1806
1807   /* Register all tap listeners; we do this before we parse the arguments,
1808      as the "-z" argument can specify a registered tap. */
1809
1810   /* we register the plugin taps before the other taps because
1811           stats_tree taps plugins will be registered as tap listeners
1812           by stats_tree_stat.c and need to registered before that */
1813
1814 #ifdef HAVE_PLUGINS
1815   register_all_plugin_tap_listeners();
1816 #endif
1817
1818   register_all_tap_listeners();
1819   
1820   splash_update(splash_win, "Loading module preferences ...");
1821
1822   /* Now register the preferences for any non-dissector modules.
1823      We must do that before we read the preferences as well. */
1824   prefs_register_modules();
1825
1826   /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1827 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1828   {
1829       GThread *ut;
1830       g_thread_init(NULL);
1831       gdk_threads_init();
1832       ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1833       g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1834   }
1835 #else  /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1836   /* this is to keep tap extensions updating once every 3 seconds */
1837   gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1838 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1839
1840 #if HAVE_GNU_ADNS
1841   gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1842 #endif
1843
1844   splash_update(splash_win, "Loading configuration files ...");
1845
1846   /* Read the preference files. */
1847   prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1848                      &pf_open_errno, &pf_read_errno, &pf_path);
1849   if (gpf_path != NULL) {
1850     if (gpf_open_errno != 0) {
1851       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1852         "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1853         strerror(gpf_open_errno));
1854     }
1855     if (gpf_read_errno != 0) {
1856       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1857         "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1858         strerror(gpf_read_errno));
1859     }
1860   }
1861   if (pf_path != NULL) {
1862     if (pf_open_errno != 0) {
1863       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1864         "Could not open your preferences file\n\"%s\": %s.", pf_path,
1865         strerror(pf_open_errno));
1866     }
1867     if (pf_read_errno != 0) {
1868       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1869         "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1870         strerror(pf_read_errno));
1871     }
1872     g_free(pf_path);
1873     pf_path = NULL;
1874   }
1875
1876 #ifdef _WIN32
1877   /* if the user wants a console to be always there, well, we should open one for him */
1878   if (prefs->gui_console_open == console_open_always) {
1879     create_console();
1880   }
1881 #endif
1882
1883 #ifdef HAVE_LIBPCAP
1884   /* If this is a capture child process, it should pay no attention
1885      to the "prefs.capture_prom_mode" setting in the preferences file;
1886      it should do what the parent process tells it to do, and if
1887      the parent process wants it not to run in promiscuous mode, it'll
1888      tell it so with a "-p" flag.
1889
1890      Otherwise, set promiscuous mode from the preferences setting. */
1891   /* the same applies to other preferences settings as well. */
1892   if (capture_child) {
1893     auto_scroll_live             = FALSE;
1894   } else {
1895     capture_opts->promisc_mode   = prefs->capture_prom_mode;
1896     capture_opts->show_info      = prefs->capture_show_info;
1897     capture_opts->real_time_mode = prefs->capture_real_time;
1898     auto_scroll_live             = prefs->capture_auto_scroll;
1899   }
1900
1901 #endif /* HAVE_LIBPCAP */
1902
1903   /* Set the name resolution code's flags from the preferences. */
1904   g_resolv_flags = prefs->name_resolve;
1905
1906   /* Read the capture filter file. */
1907   read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1908   if (cf_path != NULL) {
1909       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1910         "Could not open your capture filter file\n\"%s\": %s.", cf_path,
1911         strerror(cf_open_errno));
1912       g_free(cf_path);
1913   }
1914
1915   /* Read the display filter file. */
1916   read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1917   if (df_path != NULL) {
1918       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1919         "Could not open your display filter file\n\"%s\": %s.", df_path,
1920         strerror(df_open_errno));
1921       g_free(df_path);
1922   }
1923
1924   /* Read the disabled protocols file. */
1925   read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
1926                             &dp_path, &dp_open_errno, &dp_read_errno);
1927   if (gdp_path != NULL) {
1928     if (gdp_open_errno != 0) {
1929       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1930         "Could not open global disabled protocols file\n\"%s\": %s.",
1931         gdp_path, strerror(gdp_open_errno));
1932     }
1933     if (gdp_read_errno != 0) {
1934       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1935         "I/O error reading global disabled protocols file\n\"%s\": %s.",
1936         gdp_path, strerror(gdp_read_errno));
1937     }
1938     g_free(gdp_path);
1939   }
1940   if (dp_path != NULL) {
1941     if (dp_open_errno != 0) {
1942       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1943         "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
1944         strerror(dp_open_errno));
1945     }
1946     if (dp_read_errno != 0) {
1947       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1948         "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
1949         strerror(dp_read_errno));
1950     }
1951     g_free(dp_path);
1952   }
1953
1954   /* Read the (static part) of the recent file. Only the static part of it will be read, */
1955   /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
1956   /* We have to do this already here, so command line parameters can overwrite these values. */
1957   recent_read_static(&rf_path, &rf_open_errno);
1958
1959   init_cap_file(&cfile);
1960
1961   /* Now get our args */
1962   while ((opt = getopt(argc, argv, optstring)) != -1) {
1963     switch (opt) {
1964       /*** capture option specific ***/
1965       case 'a':        /* autostop criteria */
1966       case 'b':        /* Ringbuffer option */
1967       case 'c':        /* Capture xxx packets */
1968       case 'f':        /* capture filter */
1969       case 'k':        /* Start capture immediately */
1970       case 'H':        /* Hide capture info dialog box */
1971       case 'i':        /* Use interface xxx */
1972       case 'p':        /* Don't capture in promiscuous mode */
1973       case 'Q':        /* Quit after capture (just capture to file) */
1974       case 's':        /* Set the snapshot (capture) length */
1975       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1976       case 'w':        /* Write to capture file xxx */
1977       case 'y':        /* Set the pcap data link type */
1978 #ifdef _WIN32
1979       case 'B':        /* Buffer size */
1980       /* Hidden option supporting Sync mode */
1981       case 'Z':        /* Write to pipe FD XXX */
1982 #endif /* _WIN32 */
1983 #ifdef HAVE_LIBPCAP
1984         capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
1985 #else
1986         capture_option_specified = TRUE;
1987         arg_error = TRUE;
1988 #endif
1989         break;
1990 #ifdef HAVE_LIBPCAP
1991       /* This is a hidden option supporting Sync mode, so we don't set
1992        * the error flags for the user in the non-libpcap case.
1993        */
1994       case 'W':        /* Write to capture file FD xxx */
1995         capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
1996         break;
1997 #endif
1998
1999       /*** all non capture option specific ***/
2000       case 'g':        /* Go to packet */
2001         go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2002         break;
2003       case 'l':        /* Automatic scrolling in live capture mode */
2004 #ifdef HAVE_LIBPCAP
2005         auto_scroll_live = TRUE;
2006 #else
2007         capture_option_specified = TRUE;
2008         arg_error = TRUE;
2009 #endif
2010         break;
2011       case 'L':        /* Print list of link-layer types and exit */
2012 #ifdef HAVE_LIBPCAP
2013         list_link_layer_types = TRUE;
2014 #else
2015         capture_option_specified = TRUE;
2016         arg_error = TRUE;
2017 #endif
2018         break;
2019       case 'm':        /* Fixed-width font for the display */
2020         if (prefs->PREFS_GUI_FONT_NAME != NULL)
2021           g_free(prefs->PREFS_GUI_FONT_NAME);
2022         prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2023         break;
2024       case 'n':        /* No name resolution */
2025         g_resolv_flags = RESOLV_NONE;
2026         break;
2027       case 'N':        /* Select what types of addresses/port #s to resolve */
2028         if (g_resolv_flags == RESOLV_ALL)
2029           g_resolv_flags = RESOLV_NONE;
2030         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2031         if (badopt != '\0') {
2032           fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
2033                         badopt);
2034           exit(1);
2035         }
2036         break;
2037       case 'o':        /* Override preference from command line */
2038         switch (prefs_set_pref(optarg)) {
2039         case PREFS_SET_OK:
2040           break;
2041         case PREFS_SET_SYNTAX_ERR:
2042           fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
2043           exit(1);
2044           break;
2045         case PREFS_SET_NO_SUCH_PREF:
2046           /* not a preference, might be a recent setting */
2047           switch (recent_set_arg(optarg)) {
2048             case PREFS_SET_OK:
2049               break;
2050             case PREFS_SET_SYNTAX_ERR:
2051               /* shouldn't happen, checked already above */
2052               fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
2053               exit(1);
2054               break;
2055             case PREFS_SET_NO_SUCH_PREF:
2056             case PREFS_SET_OBSOLETE:
2057               fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference/recent value\n",
2058                     optarg);
2059               exit(1);
2060               break;
2061             default:
2062               g_assert_not_reached();
2063             }
2064           break;
2065         case PREFS_SET_OBSOLETE:
2066           fprintf(stderr, "ethereal: -o flag \"%s\" specifies obsolete preference\n",
2067                         optarg);
2068           exit(1);
2069           break;
2070         default:
2071           g_assert_not_reached();
2072         }
2073         break;
2074       case 'r':        /* Read capture file xxx */
2075         /* We may set "last_open_dir" to "cf_name", and if we change
2076            "last_open_dir" later, we free the old value, so we have to
2077            set "cf_name" to something that's been allocated. */
2078         cf_name = g_strdup(optarg);
2079         break;
2080       case 'R':        /* Read file filter */
2081         rfilter = optarg;
2082         break;
2083       case 't':        /* Time stamp type */
2084         if (strcmp(optarg, "r") == 0)
2085           set_timestamp_setting(TS_RELATIVE);
2086         else if (strcmp(optarg, "a") == 0)
2087           set_timestamp_setting(TS_ABSOLUTE);
2088         else if (strcmp(optarg, "ad") == 0)
2089           set_timestamp_setting(TS_ABSOLUTE_WITH_DATE);
2090         else if (strcmp(optarg, "d") == 0)
2091           set_timestamp_setting(TS_DELTA);
2092         else {
2093           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
2094             optarg);
2095           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
2096           fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
2097           exit(1);
2098         }
2099         break;
2100       case 'z':
2101         /* We won't call the init function for the tap this soon
2102            as it would disallow MATE's fields (which are registered
2103            by the preferences set callback) from being used as
2104            part of a tap filter.  Instead, we just add the argument
2105            to a list of tap arguments. */
2106         if (!process_tap_cmd_arg(optarg)) {
2107           fprintf(stderr,"ethereal: invalid -z argument.\n");
2108           fprintf(stderr,"  -z argument must be one of :\n");
2109           list_tap_cmd_args();
2110           exit(1);
2111         }
2112         break;
2113       default:
2114       case '?':        /* Bad flag - print usage message */
2115         arg_error = TRUE;
2116         break;
2117     }
2118   }
2119   argc -= optind;
2120   argv += optind;
2121   if (argc >= 1) {
2122     if (cf_name != NULL) {
2123       /*
2124        * Input file name specified with "-r" *and* specified as a regular
2125        * command-line argument.
2126        */
2127       arg_error = TRUE;
2128     } else {
2129       /*
2130        * Input file name not specified with "-r", and a command-line argument
2131        * was specified; treat it as the input file name.
2132        *
2133        * Yes, this is different from tethereal, where non-flag command-line
2134        * arguments are a filter, but this works better on GUI desktops
2135        * where a command can be specified to be run to open a particular
2136        * file - yes, you could have "-r" as the last part of the command,
2137        * but that's a bit ugly.
2138        */
2139       cf_name = g_strdup(argv[0]);
2140     }
2141     argc--;
2142     argv++;
2143   }
2144
2145
2146
2147   if (argc != 0) {
2148     /*
2149      * Extra command line arguments were specified; complain.
2150      */
2151     fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2152     arg_error = TRUE;
2153   }
2154
2155   if (arg_error) {
2156 #ifndef HAVE_LIBPCAP
2157     if (capture_option_specified) {
2158       fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2159     }
2160 #endif
2161     print_usage(FALSE);
2162     exit(1);
2163   }
2164
2165 #ifdef HAVE_LIBPCAP
2166   if (start_capture && list_link_layer_types) {
2167     /* Specifying *both* is bogus. */
2168     fprintf(stderr, "ethereal: You can't specify both -L and a live capture.\n");
2169     exit(1);
2170   }
2171
2172   if (list_link_layer_types) {
2173     /* We're supposed to list the link-layer types for an interface;
2174        did the user also specify a capture file to be read? */
2175     if (cf_name) {
2176       /* Yes - that's bogus. */
2177       fprintf(stderr, "ethereal: You can't specify -L and a capture file to be read.\n");
2178       exit(1);
2179     }
2180     /* No - did they specify a ring buffer option? */
2181     if (capture_opts->multi_files_on) {
2182       fprintf(stderr, "ethereal: Ring buffer requested, but a capture isn't being done.\n");
2183       exit(1);
2184     }
2185   } else {
2186     /* We're supposed to do a live capture; did the user also specify
2187        a capture file to be read? */
2188     if (start_capture && cf_name) {
2189       /* Yes - that's bogus. */
2190       fprintf(stderr, "ethereal: You can't specify both a live capture and a capture file to be read.\n");
2191       exit(1);
2192     }
2193
2194     /* No - was the ring buffer option specified and, if so, does it make
2195        sense? */
2196     if (capture_opts->multi_files_on) {
2197       /* Ring buffer works only under certain conditions:
2198          a) ring buffer does not work with temporary files;
2199          b) real_time_mode and multi_files_on are mutually exclusive -
2200             real_time_mode takes precedence;
2201          c) it makes no sense to enable the ring buffer if the maximum
2202             file size is set to "infinite". */
2203       if (capture_opts->save_file == NULL) {
2204         fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2205         capture_opts->multi_files_on = FALSE;
2206       }
2207 /*      if (capture_opts->real_time_mode) {
2208         fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2209         capture_opts->multi_files_on = FALSE;
2210       }*/
2211       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2212         fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.\n");
2213 /* XXX - this must be redesigned as the conditions changed */
2214 /*      capture_opts->multi_files_on = FALSE;*/
2215       }
2216     }
2217   }
2218
2219   if (start_capture || list_link_layer_types) {
2220     /* Did the user specify an interface to use? */
2221     if (capture_opts->iface == NULL) {
2222       /* No - is a default specified in the preferences file? */
2223       if (prefs->capture_device != NULL) {
2224           /* Yes - use it. */
2225           capture_opts->iface = g_strdup(prefs->capture_device);
2226       } else {
2227         /* No - pick the first one from the list of interfaces. */
2228         if_list = get_interface_list(&err, err_str);
2229         if (if_list == NULL) {
2230           switch (err) {
2231
2232           case CANT_GET_INTERFACE_LIST:
2233               cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2234               fprintf(stderr, "%s\n", cant_get_if_list_errstr);
2235               g_free(cant_get_if_list_errstr);
2236               break;
2237
2238           case NO_INTERFACES_FOUND:
2239               fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2240               break;
2241           }
2242           exit(2);
2243         }
2244         if_info = if_list->data;        /* first interface */
2245         capture_opts->iface = g_strdup(if_info->name);
2246         free_interface_list(if_list);
2247       }
2248     }
2249   }
2250
2251   if (list_link_layer_types) {
2252     /* Get the list of link-layer types for the capture device. */
2253     lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2254     if (lt_list == NULL) {
2255       if (err_str[0] != '\0') {
2256         fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2257           "Please check to make sure you have sufficient permissions, and that\n"
2258           "you have the proper interface or pipe specified.\n", err_str);
2259       } else
2260         fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2261       exit(2);
2262     }
2263     fprintf(stderr, "Data link types (use option -y to set):\n");
2264     for (lt_entry = lt_list; lt_entry != NULL;
2265          lt_entry = g_list_next(lt_entry)) {
2266       data_link_info = lt_entry->data;
2267       fprintf(stderr, "  %s", data_link_info->name);
2268       if (data_link_info->description != NULL)
2269         fprintf(stderr, " (%s)", data_link_info->description);
2270       else
2271         fprintf(stderr, " (not supported)");
2272       putchar('\n');
2273     }
2274     free_pcap_linktype_list(lt_list);
2275     exit(0);
2276   }
2277
2278   if (capture_opts->has_snaplen) {
2279     if (capture_opts->snaplen < 1)
2280       capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2281     else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2282       capture_opts->snaplen = MIN_PACKET_SIZE;
2283   }
2284
2285   /* Check the value range of the ringbuffer_num_files parameter */
2286   if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2287     capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2288 #if RINGBUFFER_MIN_NUM_FILES > 0
2289   else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2290     capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2291 #endif
2292 #endif /* HAVE_LIBPCAP */
2293
2294   /* Notify all registered modules that have had any of their preferences
2295      changed either from one of the preferences file or from the command
2296      line that their preferences have changed. */
2297   prefs_apply_all();
2298
2299   /* disabled protocols as per configuration file */
2300   if (gdp_path == NULL && dp_path == NULL) {
2301     set_disabled_protos_list();
2302   }
2303
2304   /* Build the column format array */
2305   col_setup(&cfile.cinfo, prefs->num_cols);
2306   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2307     cfile.cinfo.col_fmt[i] = get_column_format(i);
2308     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2309     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2310       NUM_COL_FMTS);
2311     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2312     cfile.cinfo.col_data[i] = NULL;
2313     if (cfile.cinfo.col_fmt[i] == COL_INFO)
2314       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2315     else
2316       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2317     cfile.cinfo.col_fence[i] = 0;
2318     cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2319     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2320   }
2321
2322   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2323       int j;
2324
2325       for (j = 0; j < NUM_COL_FMTS; j++) {
2326          if (!cfile.cinfo.fmt_matx[i][j])
2327              continue;
2328          
2329          if (cfile.cinfo.col_first[j] == -1)
2330              cfile.cinfo.col_first[j] = i;
2331          cfile.cinfo.col_last[j] = i;
2332       }
2333   }
2334
2335   /* read in rc file from global and personal configuration paths. */
2336   rc_file = get_datafile_path(RC_FILE);
2337   gtk_rc_parse(rc_file);
2338   rc_file = get_persconffile_path(RC_FILE, FALSE);
2339   gtk_rc_parse(rc_file);
2340
2341 #ifdef HAVE_LIBPCAP
2342   font_init(capture_child);
2343 #else
2344   font_init(FALSE);
2345 #endif
2346
2347   /* close the splash screen, as we are going to open the main window now */
2348   splash_destroy(splash_win);
2349
2350
2351 #ifdef HAVE_LIBPCAP
2352   /* Is this a "child" ethereal, which is only supposed to pop up a
2353      capture box to let us stop the capture, and run a capture
2354      to a file that our parent will read? */
2355   if (capture_child) {
2356     /* This is the child process of a capture session,
2357        so just do the low-level work of a capture - don't create
2358        a temporary file and fork off *another* child process (so don't
2359        call "capture_start()"). */
2360
2361     /* Pop up any queued-up alert boxes. */
2362     display_queued_messages();
2363
2364     /* Now start the capture. 
2365        After the capture is done; there's nothing more for us to do. */
2366
2367     /* XXX - hand these stats to the parent process */
2368     if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2369         /* capture ok */
2370         gtk_exit(0);
2371     } else {
2372         /* capture failed */
2373         gtk_exit(1);
2374     }
2375   }
2376 #endif
2377
2378   /***********************************************************************/
2379   /* Everything is prepared now, preferences and command line was read in,
2380        we are NOT a child window for a synced capture. */
2381
2382   /* Pop up the main window. */
2383   create_main_window(pl_size, tv_size, bv_size, prefs);
2384
2385   /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2386   recent_read_dynamic(&rf_path, &rf_open_errno);
2387   color_filters_enable(recent.packet_list_colorize);
2388
2389   /* rearrange all the widgets as we now have all recent settings ready for this */
2390   main_widgets_rearrange();
2391
2392   /* Fill in column titles.  This must be done after the top level window
2393      is displayed.
2394
2395      XXX - is that still true, with fixed-width columns? */
2396   packet_list_set_column_titles();
2397
2398   menu_recent_read_finished();
2399
2400   switch (user_font_apply()) {
2401   case FA_SUCCESS:
2402       break;
2403   case FA_FONT_NOT_RESIZEABLE:
2404       /* "user_font_apply()" popped up an alert box. */
2405       /* turn off zooming - font can't be resized */
2406   case FA_FONT_NOT_AVAILABLE:
2407       /* XXX - did we successfully load the un-zoomed version earlier?
2408       If so, this *probably* means the font is available, but not at
2409       this particular zoom level, but perhaps some other failure
2410       occurred; I'm not sure you can determine which is the case,
2411       however. */
2412       /* turn off zooming - zoom level is unavailable */
2413   default:
2414       /* in any other case than FA_SUCCESS, turn off zooming */
2415       recent.gui_zoom_level = 0;        
2416       /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2417   }
2418
2419   dnd_init(top_level);
2420
2421   colors_init();
2422   color_filters_init();
2423   decode_as_init();
2424
2425   /* the window can be sized only, if it's not already shown, so do it now! */
2426   main_load_window_geometry(top_level);
2427
2428   /* If we were given the name of a capture file, read it in now;
2429      we defer it until now, so that, if we can't open it, and pop
2430      up an alert box, the alert box is more likely to come up on
2431      top of the main window - but before the preference-file-error
2432      alert box, so, if we get one of those, it's more likely to come
2433      up on top of us. */
2434   if (cf_name) {
2435     show_main_window(TRUE);
2436     if (rfilter != NULL) {
2437       if (!dfilter_compile(rfilter, &rfcode)) {
2438         bad_dfilter_alert_box(rfilter);
2439         rfilter_parse_failed = TRUE;
2440       }
2441     }
2442     if (!rfilter_parse_failed) {
2443       if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2444         /* "cf_open()" succeeded, so it closed the previous
2445            capture file, and thus destroyed any previous read filter
2446            attached to "cf". */
2447
2448         cfile.rfcode = rfcode;
2449         /* Open tap windows; we do so after creating the main window,
2450            to avoid GTK warnings, and after successfully opening the
2451            capture file, so we know we have something to tap, and
2452            after registering all dissectors, so that MATE will have
2453            registered its field array and we can have a filter with
2454            one of MATE's late-registered fields as part of the tap's
2455            filter. */
2456         start_requested_taps();
2457
2458         /* Read the capture file. */
2459         switch (cf_read(&cfile)) {
2460
2461         case CF_READ_OK:
2462         case CF_READ_ERROR:
2463           /* Just because we got an error, that doesn't mean we were unable
2464              to read any of the file; we handle what we could get from the
2465              file. */
2466           /* if the user told us to jump to a specific packet, do it now */
2467           if(go_to_packet != 0) {
2468             cf_goto_frame(&cfile, go_to_packet);
2469           }
2470           break;
2471
2472         case CF_READ_ABORTED:
2473           /* Exit now. */
2474           gtk_exit(0);
2475           break;
2476         }
2477         /* Save the name of the containing directory specified in the
2478            path name, if any; we can write over cf_name, which is a
2479            good thing, given that "get_dirname()" does write over its
2480            argument. */
2481         s = get_dirname(cf_name);
2482         /* we might already set this from the recent file, don't overwrite this */
2483         if(get_last_open_dir() == NULL) 
2484           set_last_open_dir(s);
2485         g_free(cf_name);
2486         cf_name = NULL;
2487       } else {
2488         if (rfcode != NULL)
2489           dfilter_free(rfcode);
2490         cfile.rfcode = NULL;
2491         set_menus_for_capture_in_progress(FALSE);
2492       }
2493     }
2494   } else {
2495 #ifdef HAVE_LIBPCAP
2496     if (start_capture) {
2497       if (capture_opts->save_file != NULL) {
2498         /* Save the directory name for future file dialogs. */
2499         /* (get_dirname overwrites filename) */
2500         s = get_dirname(g_strdup(capture_opts->save_file));  
2501         set_last_open_dir(s);
2502         g_free(s);
2503       }
2504       /* "-k" was specified; start a capture. */
2505       show_main_window(TRUE);
2506       if (capture_start(capture_opts)) {
2507         /* The capture started.  Open tap windows; we do so after creating
2508            the main window, to avoid GTK warnings, and after successfully
2509            opening the capture file, so we know we have something to tap,
2510            and after registering all dissectors, so that MATE will have
2511            registered its field array and we can have a filter with
2512            one of MATE's late-registered fields as part of the tap's
2513            filter. */
2514         start_requested_taps();
2515       }
2516     }
2517     else {
2518       show_main_window(FALSE);
2519       set_menus_for_capture_in_progress(FALSE);
2520     }
2521
2522     /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2523     if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2524       if (capture_opts->cfilter) {
2525         g_free(capture_opts->cfilter);
2526       }
2527       capture_opts->cfilter = g_strdup(get_conn_cfilter());
2528     }
2529 #else /* HAVE_LIBPCAP */
2530     show_main_window(FALSE);
2531     set_menus_for_capture_in_progress(FALSE);
2532 #endif /* HAVE_LIBPCAP */
2533   }
2534
2535   gtk_main();
2536
2537   epan_cleanup();
2538   g_free(rc_file);
2539
2540 #ifdef _WIN32
2541   /* hide the (unresponsive) main window, while asking the user to close the console window */
2542   gtk_widget_hide(top_level);
2543
2544   /* Shutdown windows sockets */
2545   WSACleanup();
2546
2547   /* For some unknown reason, the "atexit()" call in "create_console()"
2548      doesn't arrange that "destroy_console()" be called when we exit,
2549      so we call it here if a console was created. */
2550   destroy_console();
2551 #endif
2552
2553   gtk_exit(0);
2554
2555   /* This isn't reached, but we need it to keep GCC from complaining
2556      that "main()" returns without returning a value - it knows that
2557      "exit()" never returns, but it doesn't know that "gtk_exit()"
2558      doesn't, as GTK+ doesn't declare it with the attribute
2559      "noreturn". */
2560   return 0;     /* not reached */
2561 }
2562
2563 #ifdef _WIN32
2564
2565 /* We build this as a GUI subsystem application on Win32, so
2566    "WinMain()", not "main()", gets called.
2567
2568    Hack shamelessly stolen from the Win32 port of the GIMP. */
2569 #ifdef __GNUC__
2570 #define _stdcall  __attribute__((stdcall))
2571 #endif
2572
2573 int _stdcall
2574 WinMain (struct HINSTANCE__ *hInstance,
2575          struct HINSTANCE__ *hPrevInstance,
2576          char               *lpszCmdLine,
2577          int                 nCmdShow)
2578 {
2579   has_console = FALSE;
2580   return main (__argc, __argv);
2581 }
2582
2583 /*
2584  * If this application has no console window to which its standard output
2585  * would go, create one.
2586  */
2587 void
2588 create_console(void)
2589 {
2590   if (!has_console) {
2591     /* We have no console to which to print the version string, so
2592        create one and make it the standard input, output, and error. */
2593     if (!AllocConsole())
2594       return;   /* couldn't create console */
2595     freopen("CONIN$", "r", stdin);
2596     freopen("CONOUT$", "w", stdout);
2597     freopen("CONOUT$", "w", stderr);
2598
2599     /* Well, we have a console now. */
2600     has_console = TRUE;
2601
2602     /* Now register "destroy_console()" as a routine to be called just
2603        before the application exits, so that we can destroy the console
2604        after the user has typed a key (so that the console doesn't just
2605        disappear out from under them, giving the user no chance to see
2606        the message(s) we put in there). */
2607     atexit(destroy_console);
2608   }
2609 }
2610
2611 static void
2612 destroy_console(void)
2613 {
2614   if (has_console) {
2615     printf("\n\nPress any key to exit\n");
2616     _getch();
2617     FreeConsole();
2618   }
2619 }
2620 #endif /* _WIN32 */
2621
2622
2623 /* This routine should not be necessary, at least as I read the GLib
2624    source code, as it looks as if GLib is, on Win32, *supposed* to
2625    create a console window into which to display its output.
2626
2627    That doesn't happen, however.  I suspect there's something completely
2628    broken about that code in GLib-for-Win32, and that it may be related
2629    to the breakage that forces us to just call "printf()" on the message
2630    rather than passing the message on to "g_log_default_handler()"
2631    (which is the routine that does the aforementioned non-functional
2632    console window creation). */
2633 static void
2634 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2635                     const char *message, gpointer user_data _U_)
2636 {
2637   time_t curr;
2638   struct tm *today;
2639   const char *level;
2640
2641
2642   /* change this, if you want to see more verbose log output */
2643   /* XXX - make this a pref value */
2644   if( (log_level & G_LOG_LEVEL_MASK) > G_LOG_LEVEL_WARNING) {
2645     return;
2646   }
2647
2648   /* create a "timestamp" */
2649   time(&curr);
2650   today = localtime(&curr);    
2651
2652 #ifdef _WIN32
2653   if (prefs.gui_console_open != console_open_never) {
2654     create_console();
2655   }
2656   if (has_console) {
2657     /* For some unknown reason, the above doesn't appear to actually cause
2658        anything to be sent to the standard output, so we'll just splat the
2659        message out directly, just to make sure it gets out. */
2660 #endif
2661     switch(log_level & G_LOG_LEVEL_MASK) {
2662     case G_LOG_LEVEL_ERROR:
2663         level = "Err ";
2664         break;
2665     case G_LOG_LEVEL_CRITICAL:
2666         level = "Crit";
2667         break;
2668     case G_LOG_LEVEL_WARNING:
2669         level = "Warn";
2670         break;
2671     case G_LOG_LEVEL_MESSAGE:
2672         level = "Msg ";
2673         break;
2674     case G_LOG_LEVEL_INFO:
2675         level = "Info";
2676         break;
2677     case G_LOG_LEVEL_DEBUG:
2678         level = "Dbg ";
2679         break;
2680     default:
2681         fprintf(stderr, "unknown log_level %u\n", log_level);
2682         level = NULL;
2683         g_assert_not_reached();
2684     }
2685
2686     /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2687     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2688             today->tm_hour, today->tm_min, today->tm_sec,
2689             log_domain != NULL ? log_domain : "",
2690             level, message);
2691 #ifdef _WIN32
2692   } else {
2693     g_log_default_handler(log_domain, log_level, message, user_data);
2694   }
2695 #endif
2696 }
2697
2698
2699 GtkWidget *info_bar_new(void)
2700 {
2701     /* tip: tooltips don't work on statusbars! */
2702     info_bar = gtk_statusbar_new();
2703     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2704     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2705     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2706 #if GTK_MAJOR_VERSION >= 2
2707     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2708 #endif
2709     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2710
2711     return info_bar;
2712 }
2713
2714 GtkWidget *packets_bar_new(void)
2715 {
2716     /* tip: tooltips don't work on statusbars! */
2717     packets_bar = gtk_statusbar_new();
2718     packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2719     packets_bar_update();
2720
2721     return packets_bar;
2722 }
2723
2724
2725 /*
2726  * Helper for main_widgets_rearrange()
2727  */
2728 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2729     gtk_container_remove(GTK_CONTAINER(data), widget);
2730 }
2731
2732 GtkWidget *main_widget_layout(gint layout_content)
2733 {
2734     switch(layout_content) {
2735     case(layout_pane_content_none):
2736         return NULL;
2737         break;
2738     case(layout_pane_content_plist):
2739         return pkt_scrollw;
2740         break;
2741     case(layout_pane_content_pdetails):
2742         return tv_scrollw;
2743         break;
2744     case(layout_pane_content_pbytes):
2745         return byte_nb_ptr;
2746         break;
2747     default:
2748         g_assert_not_reached();
2749         return NULL;
2750     }
2751 }
2752
2753
2754 /*
2755  * Rearrange the main window widgets
2756  */
2757 void main_widgets_rearrange(void) {
2758     GtkWidget *first_pane_widget1, *first_pane_widget2;
2759     GtkWidget *second_pane_widget1, *second_pane_widget2;
2760     gboolean split_top_left;
2761
2762     /* be a bit faster */
2763     gtk_widget_hide(main_vbox);
2764
2765     /* be sure, we don't loose a widget while rearranging */
2766     gtk_widget_ref(menubar);
2767     gtk_widget_ref(main_tb);
2768     gtk_widget_ref(filter_tb);
2769     gtk_widget_ref(pkt_scrollw);
2770     gtk_widget_ref(tv_scrollw);
2771     gtk_widget_ref(byte_nb_ptr);
2772     gtk_widget_ref(stat_hbox);
2773     gtk_widget_ref(info_bar);
2774     gtk_widget_ref(packets_bar);
2775     gtk_widget_ref(status_pane);
2776     gtk_widget_ref(main_pane_v1);
2777     gtk_widget_ref(main_pane_v2);
2778     gtk_widget_ref(main_pane_h1);
2779     gtk_widget_ref(main_pane_h2);
2780     gtk_widget_ref(welcome_pane);
2781
2782     /* empty all containers participating */
2783     gtk_container_foreach(GTK_CONTAINER(main_vbox),     foreach_remove_a_child, main_vbox);
2784     gtk_container_foreach(GTK_CONTAINER(stat_hbox),     foreach_remove_a_child, stat_hbox);
2785     gtk_container_foreach(GTK_CONTAINER(status_pane),   foreach_remove_a_child, status_pane);
2786     gtk_container_foreach(GTK_CONTAINER(main_pane_v1),  foreach_remove_a_child, main_pane_v1);
2787     gtk_container_foreach(GTK_CONTAINER(main_pane_v2),  foreach_remove_a_child, main_pane_v2);
2788     gtk_container_foreach(GTK_CONTAINER(main_pane_h1),  foreach_remove_a_child, main_pane_h1);
2789     gtk_container_foreach(GTK_CONTAINER(main_pane_h2),  foreach_remove_a_child, main_pane_h2);
2790
2791     /* add the menubar always at the top */
2792     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2793
2794     /* main toolbar */
2795     gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2796
2797     /* filter toolbar in toolbar area */
2798     if (!prefs.filter_toolbar_show_in_statusbar) {
2799         gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2800     }
2801
2802     /* fill the main layout panes */
2803     switch(prefs.gui_layout_type) {
2804     case(layout_type_5):
2805         main_first_pane  = main_pane_v1;
2806         main_second_pane = main_pane_v2;
2807         split_top_left = FALSE;
2808         break;
2809     case(layout_type_2):
2810         main_first_pane  = main_pane_v1;
2811         main_second_pane = main_pane_h1;
2812         split_top_left = FALSE;
2813         break;
2814     case(layout_type_1):
2815         main_first_pane  = main_pane_v1;
2816         main_second_pane = main_pane_h1;
2817         split_top_left = TRUE;
2818         break;
2819     case(layout_type_4):
2820         main_first_pane  = main_pane_h1;
2821         main_second_pane = main_pane_v1;
2822         split_top_left = FALSE;
2823         break;
2824     case(layout_type_3):
2825         main_first_pane  = main_pane_h1;
2826         main_second_pane = main_pane_v1;
2827         split_top_left = TRUE;
2828         break;
2829     case(layout_type_6):
2830         main_first_pane  = main_pane_h1;
2831         main_second_pane = main_pane_h2;
2832         split_top_left = FALSE;
2833         break;
2834     default:
2835         main_first_pane = NULL;
2836         main_second_pane = NULL;
2837         split_top_left = FALSE;
2838         g_assert_not_reached();
2839     }
2840     if (split_top_left) {
2841         first_pane_widget1 = main_second_pane;
2842         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2843         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2844         first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2845     } else {
2846         first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2847         first_pane_widget2 = main_second_pane;
2848         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2849         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2850     }
2851     if (first_pane_widget1 != NULL)
2852         gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2853     if (first_pane_widget2 != NULL)
2854         gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2855     if (second_pane_widget1 != NULL)
2856         gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2857     if (second_pane_widget2 != NULL)
2858         gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2859
2860     gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2861
2862     /* welcome pane */
2863     gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2864
2865     /* statusbar hbox */
2866     gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2867
2868     /* filter toolbar in statusbar hbox */
2869     if (prefs.filter_toolbar_show_in_statusbar) {
2870         gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2871     }
2872
2873     /* statusbar */
2874     gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2875     gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2876     gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2877
2878     /* hide widgets on users recent settings */
2879     main_widgets_show_or_hide();
2880
2881     gtk_widget_show(main_vbox);
2882 }
2883
2884 static void
2885 is_widget_visible(GtkWidget *widget, gpointer data)
2886 {
2887     gboolean *is_visible = data;
2888
2889     if (!*is_visible) {
2890         if (GTK_WIDGET_VISIBLE(widget))
2891             *is_visible = TRUE;
2892     }
2893 }
2894
2895
2896 #if 0
2897 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
2898    As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
2899 GtkWidget *
2900 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
2901 {
2902     GtkWidget *w, *item_hb;
2903 #if GTK_MAJOR_VERSION >= 2
2904     gchar *formatted_message;
2905 #endif
2906
2907
2908     item_hb = gtk_hbox_new(FALSE, 1);
2909
2910     w = BUTTON_NEW_FROM_STOCK(stock_item);
2911     WIDGET_SET_SIZE(w, 60, 60);
2912 #if GTK_MAJOR_VERSION >= 2
2913     gtk_button_set_label(GTK_BUTTON(w), label);
2914 #endif
2915     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
2916     SIGNAL_CONNECT(w, "clicked", callback, callback_data);
2917
2918     w = gtk_label_new(message);
2919         gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2920 #if GTK_MAJOR_VERSION >= 2
2921     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
2922     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
2923     g_free(formatted_message);
2924 #endif
2925
2926     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
2927
2928     return item_hb;
2929 }
2930
2931
2932 /* XXX - the layout has to be improved */
2933 GtkWidget *
2934 welcome_new(void)
2935 {
2936     GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
2937     GtkWidget *w, *icon;
2938     gchar * message;
2939
2940
2941     welcome_scrollw = scrolled_window_new(NULL, NULL);
2942
2943     welcome_hb = gtk_hbox_new(FALSE, 1);
2944         /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
2945
2946     welcome_vb = gtk_vbox_new(FALSE, 1);
2947
2948     item_hb = gtk_hbox_new(FALSE, 1);
2949
2950     icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
2951     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
2952
2953 #if GTK_MAJOR_VERSION < 2
2954     message = "Welcome to Ethereal!";
2955 #else
2956     message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
2957 #endif
2958     w = gtk_label_new(message);
2959 #if GTK_MAJOR_VERSION >= 2
2960     gtk_label_set_markup(GTK_LABEL(w), message);
2961 #endif
2962     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
2963     gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
2964
2965     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2966
2967     w = gtk_label_new("What would you like to do?");
2968     gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
2969     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
2970
2971 #ifdef HAVE_LIBPCAP
2972     item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START, 
2973         "Capture",
2974         "Capture live data from your network", 
2975         GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
2976     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2977 #endif
2978
2979     item_hb = welcome_item(GTK_STOCK_OPEN, 
2980         "Open",
2981         "Open a previously captured file",
2982         GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
2983     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2984
2985 #if (GLIB_MAJOR_VERSION >= 2)
2986     item_hb = welcome_item(GTK_STOCK_HOME, 
2987         "Home",
2988         "Visit the Ethereal homepage",
2989         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
2990     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
2991 #endif
2992
2993     /* the end */
2994     w = gtk_label_new("");
2995     gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
2996
2997     w = gtk_label_new("");
2998     gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
2999
3000     gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3001
3002     w = gtk_label_new("");
3003     gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3004
3005     gtk_widget_show_all(welcome_hb);
3006
3007     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3008                                           welcome_hb);
3009     gtk_widget_show_all(welcome_scrollw);
3010
3011     return welcome_scrollw;
3012 }
3013 #endif /* 0 */
3014
3015 GtkWidget *
3016 welcome_new(void)
3017 {
3018     /* this is just a dummy to fill up window space, simply showing nothing */
3019     return scrolled_window_new(NULL, NULL);
3020 }
3021
3022
3023
3024 /*
3025  * XXX - this doesn't appear to work with the paned widgets in
3026  * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3027  * and the other pane doesn't grow to take up the rest of the pane.
3028  * It does appear to work with GTK+ 2.x.
3029  */
3030 void
3031 main_widgets_show_or_hide(void)
3032 {
3033     gboolean main_second_pane_show;
3034
3035     if (recent.main_toolbar_show) {
3036         gtk_widget_show(main_tb);
3037     } else {
3038         gtk_widget_hide(main_tb);
3039     }
3040
3041     /*
3042      * Show the status hbox if either:
3043      *
3044      *    1) we're showing the filter toolbar and we want it in the status
3045      *       line
3046      *
3047      * or
3048      *
3049      *    2) we're showing the status bar.
3050      */
3051     if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3052          recent.statusbar_show) {
3053         gtk_widget_show(stat_hbox);
3054     } else {
3055         gtk_widget_hide(stat_hbox);
3056     }
3057
3058     if (recent.statusbar_show) {
3059         gtk_widget_show(status_pane);
3060     } else {
3061         gtk_widget_hide(status_pane);
3062     }
3063
3064     if (recent.filter_toolbar_show) {
3065         gtk_widget_show(filter_tb);
3066     } else {
3067         gtk_widget_hide(filter_tb);
3068     }
3069
3070     if (recent.packet_list_show && have_capture_file) {
3071         gtk_widget_show(pkt_scrollw);
3072     } else {
3073         gtk_widget_hide(pkt_scrollw);
3074     }
3075
3076     if (recent.tree_view_show && have_capture_file) {
3077         gtk_widget_show(tv_scrollw);
3078     } else {
3079         gtk_widget_hide(tv_scrollw);
3080     }
3081
3082     if (recent.byte_view_show && have_capture_file) {
3083         gtk_widget_show(byte_nb_ptr);
3084     } else {
3085         gtk_widget_hide(byte_nb_ptr);
3086     }
3087
3088     if (have_capture_file) {
3089         gtk_widget_show(main_first_pane);
3090     } else {
3091         gtk_widget_hide(main_first_pane);
3092     }
3093
3094     /*
3095      * Is anything in "main_second_pane" visible?
3096      * If so, show it, otherwise hide it.
3097      */
3098     main_second_pane_show = FALSE;
3099     gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3100                           &main_second_pane_show);
3101     if (main_second_pane_show) {
3102         gtk_widget_show(main_second_pane);
3103     } else {
3104         gtk_widget_hide(main_second_pane);
3105     }
3106
3107     if (!have_capture_file) {
3108         if(welcome_pane) {
3109             gtk_widget_show(welcome_pane);
3110         }
3111     } else {
3112         gtk_widget_hide(welcome_pane);
3113     }
3114 }
3115
3116
3117 #if GTK_MAJOR_VERSION >= 2
3118 /* called, when the window state changes (minimized, maximized, ...) */
3119 static int
3120 window_state_event_cb (GtkWidget *widget _U_,
3121                        GdkEvent *event,
3122                        gpointer  data _U_)
3123 {
3124     GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3125
3126     if( (event->type) == (GDK_WINDOW_STATE)) {
3127         if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3128             /* we might have dialogs popped up while we where iconified,
3129                show em now */
3130             display_queued_messages();
3131         }
3132     }
3133     return FALSE;
3134 }
3135 #endif
3136
3137
3138 static void
3139 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3140 {
3141     GtkWidget     
3142                   *filter_bt, *filter_cm, *filter_te,
3143                   *filter_add_expr_bt,
3144                   *filter_apply,
3145                   *filter_reset;
3146     GList         *dfilter_list = NULL;
3147     GtkTooltips   *tooltips;
3148     GtkAccelGroup *accel;
3149         gchar         *title;
3150     /* Display filter construct dialog has an Apply button, and "OK" not
3151        only sets our text widget, it activates it (i.e., it causes us to
3152        filter the capture). */
3153     static construct_args_t args = {
3154         "Ethereal: Display Filter",
3155         TRUE,
3156         TRUE
3157     };
3158
3159     /* use user-defined title if preference is set */
3160     title = create_user_window_title("The Ethereal Network Analyzer");
3161
3162     /* Main window */
3163     top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3164     g_free(title);
3165
3166     tooltips = gtk_tooltips_new();
3167
3168 #ifdef _WIN32 
3169 #if GTK_MAJOR_VERSION < 2
3170     /* has to be done, after top_level window is created */
3171     app_font_gtk1_init(top_level);
3172 #endif
3173 #endif
3174     
3175     gtk_widget_set_name(top_level, "main window");
3176     SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3177                    NULL);
3178 #if GTK_MAJOR_VERSION >= 2
3179     SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3180                          G_CALLBACK (window_state_event_cb), NULL);
3181 #endif
3182
3183     gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3184
3185     /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3186     main_vbox = gtk_vbox_new(FALSE, 1);
3187     gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3188     gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3189     gtk_widget_show(main_vbox);
3190
3191     /* Menu bar */
3192     menubar = main_menu_new(&accel);
3193     gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3194     gtk_widget_show(menubar);
3195
3196     /* Main Toolbar */
3197     main_tb = toolbar_new();
3198     gtk_widget_show (main_tb);
3199
3200     /* Packet list */
3201     pkt_scrollw = packet_list_new(prefs);
3202     WIDGET_SET_SIZE(packet_list, -1, pl_size);
3203     gtk_widget_show(pkt_scrollw);
3204
3205     /* Tree view */
3206     tv_scrollw = main_tree_view_new(prefs, &tree_view);
3207     WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3208     gtk_widget_show(tv_scrollw);
3209
3210 #if GTK_MAJOR_VERSION < 2
3211     SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3212     SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3213                    NULL);
3214 #else
3215     SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3216                    "changed", tree_view_selection_changed_cb, NULL);
3217 #endif
3218     SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3219                    OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3220     gtk_widget_show(tree_view);
3221
3222     /* Byte view. */
3223     byte_nb_ptr = byte_view_new();
3224     WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3225     gtk_widget_show(byte_nb_ptr);
3226
3227     SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3228                    OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3229
3230
3231     /* Panes for the packet list, tree, and byte view */
3232     main_pane_v1 = gtk_vpaned_new();
3233     gtk_widget_show(main_pane_v1);
3234     main_pane_v2 = gtk_vpaned_new();
3235     gtk_widget_show(main_pane_v2);
3236     main_pane_h1 = gtk_hpaned_new();
3237     gtk_widget_show(main_pane_h1);
3238     main_pane_h2 = gtk_hpaned_new();
3239     gtk_widget_show(main_pane_h2);
3240
3241     /* filter toolbar */
3242 #if GTK_MAJOR_VERSION < 2
3243     filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3244                                GTK_TOOLBAR_BOTH);
3245 #else
3246     filter_tb = gtk_toolbar_new();
3247     gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3248                                 GTK_ORIENTATION_HORIZONTAL);
3249 #endif /* GTK_MAJOR_VERSION */
3250     gtk_widget_show(filter_tb);
3251
3252     /* Create the "Filter:" button */
3253     filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3254     SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3255     gtk_widget_show(filter_bt);
3256     OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3257
3258     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt, 
3259         "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3260
3261     /* Create the filter combobox */
3262     filter_cm = gtk_combo_new();
3263     dfilter_list = NULL;
3264     gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3265     gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3266     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3267     filter_te = GTK_COMBO(filter_cm)->entry;
3268     main_display_filter_widget=filter_te;
3269     OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3270     OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3271     OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3272     SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3273     SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3274     WIDGET_SET_SIZE(filter_cm, 400, -1);
3275     gtk_widget_show(filter_cm);
3276     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm, 
3277         NULL, NULL);
3278     /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3279     gtk_tooltips_set_tip(tooltips, filter_te, 
3280         "Enter a display filter, or choose one of your recently used filters. "
3281         "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).", 
3282         NULL);
3283
3284     /* Create the "Add Expression..." button, to pop up a dialog
3285        for constructing filter comparison expressions. */
3286     filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3287     OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3288     SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3289     gtk_widget_show(filter_add_expr_bt);
3290     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt, 
3291         "Add an expression to this filter string", "Private");
3292
3293     /* Create the "Clear" button */
3294     filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3295     OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3296     SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3297     gtk_widget_show(filter_reset);
3298     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset, 
3299         "Clear this filter string and update the display", "Private");
3300
3301     /* Create the "Apply" button */
3302     filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3303     OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3304     SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3305     gtk_widget_show(filter_apply);
3306     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply, 
3307         "Apply this filter string to the display", "Private");
3308
3309     /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3310      * of any widget that ends up calling a callback which needs
3311      * that text entry pointer */
3312     set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3313     set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3314                          filter_te);
3315     set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3316                          filter_te);
3317     set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3318                          filter_te);
3319     set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3320                          filter_te);
3321     set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3322                          filter_te);
3323     set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3324                          filter_te);
3325     set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3326                          filter_te);
3327     set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3328                          filter_te);
3329     set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3330                          filter_te);
3331     set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3332                          filter_te);
3333     set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3334                          filter_te);
3335     set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3336                          filter_te);
3337     set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3338                          filter_te);
3339     set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3340                          filter_te);
3341     set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3342     OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3343     OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3344
3345     /* info (main) statusbar */
3346     info_bar = info_bar_new();
3347     gtk_widget_show(info_bar);
3348
3349     /* packets statusbar */
3350     packets_bar = packets_bar_new();
3351     gtk_widget_show(packets_bar);
3352
3353     /* Filter/status hbox */
3354     stat_hbox = gtk_hbox_new(FALSE, 1);
3355     gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3356     gtk_widget_show(stat_hbox);
3357
3358     /* Pane for the statusbar */
3359     status_pane = gtk_hpaned_new();
3360     gtk_widget_show(status_pane);
3361
3362     /* Pane for the welcome screen */
3363     welcome_pane = welcome_new();
3364     gtk_widget_show(welcome_pane);
3365 }
3366
3367 static void
3368 show_main_window(gboolean doing_work)
3369 {
3370   main_set_for_capture_file(doing_work);
3371
3372   /*** we have finished all init things, show the main window ***/
3373   gtk_widget_show(top_level);
3374
3375   /* the window can be maximized only, if it's visible, so do it after show! */
3376   main_load_window_geometry(top_level);
3377
3378   /* process all pending GUI events before continue */
3379   while (gtk_events_pending()) gtk_main_iteration();
3380
3381   /* Pop up any queued-up alert boxes. */
3382   display_queued_messages();
3383 }