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