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