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