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