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