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