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