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