Check on every iteration of a loop whether to pop up a dialog box,
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id$
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@ethereal.com>
7  * Copyright 1998 Gerald Combs
8  *
9  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10  *                              needed by dissect routines
11  * Jeff Foster,    2001/03/12,  added support tabbed hex display windowss
12  *
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 #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 #include <epan/emem.h>
69
70 /* general (not GTK specific) */
71 #include "file.h"
72 #include "summary.h"
73 #include "filters.h"
74 #include "disabled_protos.h"
75 #include <epan/prefs.h>
76 #include "filter_dlg.h"
77 #include "layout_prefs.h"
78 #include "color.h"
79 #include "color_filters.h"
80 #include "print.h"
81 #include "simple_dialog.h"
82 #include "register.h"
83 #include <epan/prefs-int.h>
84 #include "ringbuffer.h"
85 #include "../ui_util.h"
86 #include <epan/tap.h>
87 #include <epan/stat_cmd_args.h>
88 #include "util.h"
89 #include "clopts_common.h"
90 #include "version_info.h"
91 #include "merge.h"
92
93 #ifdef HAVE_LIBPCAP
94 #include <pcap.h>
95 #include "pcap-util.h"
96 #include "capture.h"
97 #endif
98
99 #ifdef _WIN32
100 #include "capture-wpcap.h"
101 #include "capture_wpcap_packet.h"
102 #endif
103
104 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
105 #include "ethclist.h"
106 #endif
107
108 /* GTK related */
109 #include "statusbar.h"
110 #include "alert_box.h"
111 #include "dlg_utils.h"
112 #include "gtkglobals.h"
113 #include "colors.h"
114 #include "gui_utils.h"
115 #include "compat_macros.h"
116
117 #include "main.h"
118 #include "menu.h"
119 #include "../main_window.h"
120 #include "../menu.h"
121 #include "file_dlg.h"
122 #include <epan/column.h>
123 #include "proto_draw.h"
124 #include "keys.h"
125 #include "packet_win.h"
126 #include "toolbar.h"
127 #include "find_dlg.h"
128 #include "packet_list.h"
129 #include "recent.h"
130 #include "follow_dlg.h"
131 #include "font_utils.h"
132 #include "about_dlg.h"
133 #include "help_dlg.h"
134 #include "decode_as_dlg.h"
135 #include "webbrowser.h"
136 #include "capture_dlg.h"
137 #if 0
138 #include "../image/eicon3d64.xpm"
139 #endif
140 #include "capture_ui_utils.h"
141 #include "log.h"
142 #include "../epan/emem.h"
143
144
145
146 /*
147  * Files under personal and global preferences directories in which
148  * GTK settings for Ethereal are stored.
149  */
150 #define RC_FILE "gtkrc"
151
152 #ifdef HAVE_LIBPCAP
153 #define DEF_READY_MESSAGE " Ready to load or capture"
154 #else
155 #define DEF_READY_MESSAGE " Ready to load file"
156 #endif
157
158 capture_file cfile;
159 GtkWidget   *main_display_filter_widget=NULL;
160 GtkWidget   *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
161 static GtkWidget   *main_pane_v1, *main_pane_v2, *main_pane_h1, *main_pane_h2;
162 static GtkWidget   *main_first_pane, *main_second_pane;
163 static GtkWidget   *status_pane;
164 static GtkWidget   *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
165 static GtkWidget        *info_bar;
166 static GtkWidget    *packets_bar = NULL;
167 static GtkWidget    *welcome_pane;
168 static guint    main_ctx, file_ctx, help_ctx;
169 static guint        packets_ctx;
170 static gchar        *packets_str = NULL;
171 GString *comp_info_str, *runtime_info_str;
172 gchar       *ethereal_path = NULL;
173 gboolean have_capture_file = FALSE; /* XXX - is there an aquivalent in cfile? */
174
175 gboolean             capture_child; /* True if this is the child for "-S" */
176 #ifdef _WIN32
177 static gboolean has_console;    /* TRUE if app has console */
178 static void destroy_console(void);
179 #endif
180 static void console_log_handler(const char *log_domain,
181     GLogLevelFlags log_level, const char *message, gpointer user_data);
182
183 #ifdef HAVE_LIBPCAP
184 static gboolean list_link_layer_types;
185 capture_options global_capture_opts;
186 capture_options *capture_opts = &global_capture_opts;
187 #endif
188
189
190 static void create_main_window(gint, gint, gint, e_prefs*);
191 static void show_main_window(gboolean);
192 static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
193 static void main_save_window_geometry(GtkWidget *widget);
194
195 #define E_DFILTER_CM_KEY          "display_filter_combo"
196 #define E_DFILTER_FL_KEY          "display_filter_list"
197
198
199
200 /* Match selected byte pattern */
201 static void
202 match_selected_cb_do(gpointer data, int action, gchar *text)
203 {
204     GtkWidget           *filter_te;
205     char                *cur_filter, *new_filter;
206
207     if (!text)
208         return;
209     g_assert(data);
210     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
211     g_assert(filter_te);
212
213     cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
214
215     switch (action&MATCH_SELECTED_MASK) {
216
217     case MATCH_SELECTED_REPLACE:
218         new_filter = g_strdup(text);
219         break;
220
221     case MATCH_SELECTED_AND:
222         if ((!cur_filter) || (0 == strlen(cur_filter)))
223             new_filter = g_strdup(text);
224         else
225             new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
226         break;
227
228     case MATCH_SELECTED_OR:
229         if ((!cur_filter) || (0 == strlen(cur_filter)))
230             new_filter = g_strdup(text);
231         else
232             new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
233         break;
234
235     case MATCH_SELECTED_NOT:
236         new_filter = g_strconcat("!(", text, ")", NULL);
237         break;
238
239     case MATCH_SELECTED_AND_NOT:
240         if ((!cur_filter) || (0 == strlen(cur_filter)))
241             new_filter = g_strconcat("!(", text, ")", NULL);
242         else
243             new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
244         break;
245
246     case MATCH_SELECTED_OR_NOT:
247         if ((!cur_filter) || (0 == strlen(cur_filter)))
248             new_filter = g_strconcat("!(", text, ")", NULL);
249         else
250             new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
251         break;
252
253     default:
254         g_assert_not_reached();
255         new_filter = NULL;
256         break;
257     }
258
259     /* Free up the copy we got of the old filter text. */
260     g_free(cur_filter);
261
262     /* create a new one and set the display filter entry accordingly */
263     gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
264
265     /* Run the display filter so it goes in effect. */
266     if (action&MATCH_SELECTED_APPLY_NOW)
267         main_filter_packets(&cfile, new_filter, FALSE);
268
269     /* Free up the new filter text. */
270     g_free(new_filter);
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 = ep_alloc0(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 "%s\n\n%s\n\n%s\n",
1124       svnversion, comp_info_str->str, runtime_info_str->str);
1125
1126 #ifdef _WIN32
1127   destroy_console();
1128 #endif
1129 }
1130
1131 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1132 /* 
1133    Once every 3 seconds we get a callback here which we use to update
1134    the tap extensions. Since Gtk1 is single threaded we dont have to
1135    worry about any locking or critical regions.
1136  */
1137 static gint
1138 update_cb(gpointer data _U_)
1139 {
1140         draw_tap_listeners(FALSE);
1141         return 1;
1142 }
1143 #else
1144
1145 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1146    use threads all updte_thread_mutex can be dropped and protect/unprotect 
1147    would just be empty functions.
1148
1149    This allows gtk2-rpcstat.c and friends to be copied unmodified to 
1150    gtk1-ethereal and it will just work.
1151  */
1152 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1153 gpointer
1154 update_thread(gpointer data _U_)
1155 {
1156     while(1){
1157         GTimeVal tv1, tv2;
1158         g_get_current_time(&tv1);
1159         g_static_mutex_lock(&update_thread_mutex);
1160         gdk_threads_enter();
1161         draw_tap_listeners(FALSE);
1162         gdk_threads_leave();
1163         g_static_mutex_unlock(&update_thread_mutex);
1164         g_thread_yield();
1165         g_get_current_time(&tv2);
1166         if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1167             (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1168             g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1169                      (tv2.tv_sec * 1000000 + tv2.tv_usec));
1170         }
1171     }
1172     return NULL;
1173 }
1174 #endif
1175 void
1176 protect_thread_critical_region(void)
1177 {
1178 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1179     g_static_mutex_lock(&update_thread_mutex);
1180 #endif
1181 }
1182 void
1183 unprotect_thread_critical_region(void)
1184 {
1185 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1186     g_static_mutex_unlock(&update_thread_mutex);
1187 #endif
1188 }
1189
1190 /* Set the file name in the status line, in the name for the main window,
1191    and in the name for the main window's icon. */
1192 static void
1193 set_display_filename(capture_file *cf)
1194 {
1195   const gchar *name_ptr;
1196   gchar       *status_msg;
1197   gchar       *size_str;
1198   gchar       *win_name;
1199
1200   name_ptr = cf_get_display_name(cf);
1201         
1202   if (!cf->is_tempfile && cf->filename) {
1203     /* Add this filename to the list of recent files in the "Recent Files" submenu */
1204     add_menu_recent_capture_file(cf->filename);
1205   }
1206
1207   /* convert file size */
1208   if (cf->f_datalen/1024/1024 > 10) {
1209     size_str = g_strdup_printf("%ld MB", cf->f_datalen/1024/1024);
1210   } else if (cf->f_datalen/1024 > 10) {
1211     size_str = g_strdup_printf("%ld KB", cf->f_datalen/1024);
1212   } else {
1213     size_str = g_strdup_printf("%ld Bytes", cf->f_datalen);
1214   }
1215
1216   /* statusbar */
1217   status_msg = g_strdup_printf(" File: \"%s\" %s %02lu:%02lu:%02lu", 
1218     (cf->filename) ? cf->filename : "", size_str,
1219     (long)cf->elapsed_time.secs/3600,
1220     (long)cf->elapsed_time.secs%3600/60,
1221     (long)cf->elapsed_time.secs%60);
1222   g_free(size_str);
1223   statusbar_push_file_msg(status_msg);
1224   g_free(status_msg);
1225
1226   /* window title */
1227   win_name = g_strdup_printf("%s - Ethereal", name_ptr);
1228   set_main_window_name(win_name);
1229   g_free(win_name);
1230 }
1231
1232 GtkWidget           *close_dlg = NULL;
1233
1234 static void
1235 main_cf_cb_file_closing(capture_file *cf)
1236 {
1237
1238         /* if we have more than 10000 packets, show a splash screen while closing */
1239         /* XXX - don't know a better way to decide wether to show or not,
1240          * as most of the time is spend in a single eth_clist_clear function, 
1241          * so we can't use a progress bar here! */
1242         if(cf->count > 10000) {
1243                 close_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sClosing file!%s\n\nPlease wait ...", 
1244                         simple_dialog_primary_start(), simple_dialog_primary_end());
1245 #if GTK_MAJOR_VERSION >= 2
1246                 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1247 #else
1248                 gtk_window_set_position(GTK_WINDOW(close_dlg), GTK_WIN_POS_CENTER);
1249 #endif
1250         }
1251
1252     /* Destroy all windows, which refer to the
1253        capture file we're closing. */
1254     destroy_cfile_wins();
1255
1256     /* Clear any file-related status bar messages.
1257        XXX - should be "clear *ALL* file-related status bar messages;
1258        will there ever be more than one on the stack? */
1259     statusbar_pop_file_msg();
1260
1261     /* Restore the standard title bar message. */
1262     set_main_window_name("The Ethereal Network Analyzer");
1263
1264     /* Disable all menu items that make sense only if you have a capture. */
1265     set_menus_for_capture_file(FALSE);
1266     set_menus_for_unsaved_capture_file(FALSE);
1267     set_menus_for_captured_packets(FALSE);
1268     set_menus_for_selected_packet(cf);
1269     set_menus_for_capture_in_progress(FALSE);
1270     set_menus_for_selected_tree_row(cf);
1271
1272     /* Set up main window for no capture file. */
1273     main_set_for_capture_file(FALSE);
1274
1275     main_window_update();
1276 }
1277
1278 static void
1279 main_cf_cb_file_closed(capture_file *cf _U_)
1280 {
1281   if(close_dlg != NULL) {
1282     splash_destroy(close_dlg);
1283     close_dlg = NULL;
1284   }
1285
1286   /* go back to "No packets" */
1287   packets_bar_update();
1288 }
1289
1290 static void
1291 main_cf_cb_file_read_start(capture_file *cf)
1292 {
1293   const gchar *name_ptr;
1294   gchar       *load_msg;
1295
1296   name_ptr = get_basename(cf->filename);
1297
1298   load_msg = g_strdup_printf(" Loading: %s", name_ptr);
1299   statusbar_push_file_msg(load_msg);
1300   g_free(load_msg);
1301 }
1302
1303 static void
1304 main_cf_cb_file_read_finished(capture_file *cf)
1305 {
1306     statusbar_pop_file_msg();
1307     set_display_filename(cf);
1308
1309     /* Enable menu items that make sense if you have a capture file you've
1310      finished reading. */
1311     set_menus_for_capture_file(TRUE);
1312     set_menus_for_unsaved_capture_file(!cf->user_saved);
1313
1314     /* Enable menu items that make sense if you have some captured packets. */
1315     set_menus_for_captured_packets(TRUE);
1316
1317     /* Set up main window for a capture file. */
1318     main_set_for_capture_file(TRUE);
1319 }
1320
1321 #ifdef HAVE_LIBPCAP
1322 static void
1323 main_cf_cb_live_capture_prepared(capture_options *capture_opts)
1324 {
1325     gchar *title;
1326
1327
1328     if(capture_opts->iface) {
1329         title = g_strdup_printf("%s: Capturing - Ethereal",
1330                             get_interface_descriptive_name(capture_opts->iface));
1331     } else {
1332         title = g_strdup_printf("Capturing - Ethereal");
1333     }
1334     set_main_window_name(title);
1335     g_free(title);
1336
1337     /* Disable menu items that make no sense if you're currently running
1338        a capture. */
1339     set_menus_for_capture_in_progress(TRUE);
1340
1341     /* update statusbar */
1342     statusbar_push_file_msg("Waiting for capture input data ...");
1343
1344     /* Don't set up main window for a capture file. */
1345     main_set_for_capture_file(FALSE);
1346 }
1347
1348 static void
1349 main_cf_cb_live_capture_update_started(capture_options *capture_opts)
1350 {
1351     gchar *capture_msg;
1352     gchar *title;
1353
1354
1355     /* We've done this in "prepared" above, but it will be cleared while
1356        switching to the next multiple file. */
1357     if(capture_opts->iface) {
1358         title = g_strdup_printf("%s: Capturing - Ethereal",
1359                             get_interface_descriptive_name(capture_opts->iface));
1360     } else {
1361         title = g_strdup_printf("Capturing - Ethereal");
1362     }
1363     set_main_window_name(title);
1364     g_free(title);
1365
1366     set_menus_for_capture_in_progress(TRUE);
1367
1368     /* Enable menu items that make sense if you have some captured
1369        packets (yes, I know, we don't have any *yet*). */
1370     set_menus_for_captured_packets(TRUE);
1371
1372     statusbar_pop_file_msg();
1373
1374     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s", 
1375         get_interface_descriptive_name(capture_opts->iface), 
1376         (capture_opts->save_file) ? capture_opts->save_file : "");
1377
1378     statusbar_push_file_msg(capture_msg);
1379
1380     g_free(capture_msg);
1381
1382     /* Set up main window for a capture file. */
1383     main_set_for_capture_file(TRUE);
1384 }
1385
1386 static void
1387 main_cf_cb_live_capture_update_continue(capture_file *cf)
1388 {
1389     gchar *capture_msg;
1390
1391
1392     statusbar_pop_file_msg();
1393
1394     if (cf->f_datalen/1024/1024 > 10) {
1395         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld MB", 
1396             get_interface_descriptive_name(capture_opts->iface), 
1397             capture_opts->save_file,
1398             cf->f_datalen/1024/1024);
1399     } else if (cf->f_datalen/1024 > 10) {
1400         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld KB", 
1401             get_interface_descriptive_name(capture_opts->iface), 
1402             capture_opts->save_file,
1403             cf->f_datalen/1024);
1404     } else {
1405         capture_msg = g_strdup_printf(" %s: <live capture in progress> File: %s %ld Bytes", 
1406             get_interface_descriptive_name(capture_opts->iface), 
1407             capture_opts->save_file,
1408             cf->f_datalen);
1409     }
1410
1411     statusbar_push_file_msg(capture_msg);
1412 }
1413
1414 GtkWidget * stop_dlg = NULL;
1415
1416 static void
1417 main_cf_cb_live_capture_update_finished(capture_file *cf)
1418 {
1419         if(stop_dlg != NULL) {
1420                 simple_dialog_close(stop_dlg);
1421                 stop_dlg = NULL;
1422         }
1423
1424     /* Pop the "<live capture in progress>" message off the status bar. */
1425     statusbar_pop_file_msg();
1426
1427     set_display_filename(cf);
1428
1429     /* Enable menu items that make sense if you're not currently running
1430      a capture. */
1431     set_menus_for_capture_in_progress(FALSE);
1432
1433     /* Enable menu items that make sense if you have a capture file
1434      you've finished reading. */
1435     set_menus_for_capture_file(TRUE);
1436     set_menus_for_unsaved_capture_file(!cf->user_saved);
1437
1438     /* Set up main window for a capture file. */
1439     main_set_for_capture_file(TRUE);
1440 }
1441
1442 static void
1443 main_cf_cb_live_capture_fixed_started(capture_options *capture_opts)
1444 {
1445     gchar *capture_msg;
1446
1447
1448     /* Enable menu items that make sense if you have some captured
1449        packets (yes, I know, we don't have any *yet*). */
1450     /*set_menus_for_captured_packets(TRUE);*/
1451
1452     statusbar_pop_file_msg();
1453
1454     capture_msg = g_strdup_printf(" %s: <live capture in progress> to file: %s", 
1455         get_interface_descriptive_name(capture_opts->iface), 
1456         (capture_opts->save_file) ? capture_opts->save_file : "");
1457
1458     statusbar_push_file_msg(capture_msg);
1459     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " <capturing>");
1460
1461     g_free(capture_msg);
1462
1463     /* Don't set up main window for a capture file. */
1464     main_set_for_capture_file(FALSE);
1465 }
1466
1467 static void
1468 main_cf_cb_live_capture_fixed_finished(capture_file *cf _U_)
1469 {
1470         if(stop_dlg != NULL) {
1471                 simple_dialog_close(stop_dlg);
1472                 stop_dlg = NULL;
1473         }
1474
1475     /* Pop the "<live capture in progress>" message off the status bar. */
1476     statusbar_pop_file_msg();
1477
1478     /* Pop the "<capturing>" message off the status bar */
1479         gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1480
1481     /*set_display_filename(cf);*/
1482
1483     /* Enable menu items that make sense if you're not currently running
1484      a capture. */
1485     set_menus_for_capture_in_progress(FALSE);
1486
1487     /* We don't have loaded the capture file, this will be done later.
1488      * For now we still have simply a blank screen. */
1489 }
1490
1491 static void
1492 main_cf_cb_live_capture_stopping(capture_file *cf _U_)
1493 {
1494 #if 0
1495         /* XXX - the time to stop the capture has been reduced (this was only a 
1496          * problem on Win32 because of the capture piping), so showing a splash 
1497          * isn't really necessary any longer. Unfortunately, the GTKClist packet 
1498          * list seems to have problems updating after the dialog is closed, so 
1499          * this was disabled here. */
1500     stop_dlg = simple_dialog(ESD_TYPE_STOP, ESD_BTN_NONE, "%sCapture stop!%s\n\nPlease wait ...", 
1501                 simple_dialog_primary_start(), simple_dialog_primary_end());
1502 #if GTK_MAJOR_VERSION >= 2
1503         gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER_ON_PARENT);
1504 #else
1505         gtk_window_set_position(GTK_WINDOW(stop_dlg), GTK_WIN_POS_CENTER);
1506 #endif
1507 #endif
1508 }
1509
1510 #endif
1511
1512 static void
1513 main_cf_cb_packet_selected(gpointer data)
1514 {
1515     capture_file *cf = data;
1516
1517     /* Display the GUI protocol tree and hex dump.
1518       XXX - why do we dump core if we call "proto_tree_draw()"
1519       before calling "add_byte_views()"? */
1520     add_main_byte_views(cf->edt);
1521     main_proto_tree_draw(cf->edt->tree);
1522
1523     /* A packet is selected. */
1524     set_menus_for_selected_packet(cf);
1525 }
1526
1527 static void
1528 main_cf_cb_packet_unselected(capture_file *cf)
1529 {
1530     /* Clear out the display of that packet. */
1531     clear_tree_and_hex_views();
1532
1533     /* No packet is selected. */
1534     set_menus_for_selected_packet(cf);
1535 }
1536
1537 static void
1538 main_cf_cb_field_unselected(capture_file *cf)
1539 {
1540     statusbar_pop_field_msg();
1541     set_menus_for_selected_tree_row(cf);
1542 }
1543
1544 static void
1545 main_cf_cb_file_safe_started(gchar * filename)
1546 {
1547     const gchar  *name_ptr;
1548     gchar        *save_msg;
1549
1550     name_ptr = get_basename(filename);
1551
1552     save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
1553
1554     statusbar_push_file_msg(save_msg);
1555     g_free(save_msg);
1556 }
1557
1558 static void
1559 main_cf_cb_file_safe_finished(gpointer data _U_)
1560 {
1561     /* Pop the "Saving:" message off the status bar. */
1562     statusbar_pop_file_msg();
1563 }
1564
1565 static void
1566 main_cf_cb_file_safe_failed(gpointer data _U_)
1567 {
1568     /* Pop the "Saving:" message off the status bar. */
1569     statusbar_pop_file_msg();
1570 }
1571
1572 static void
1573 main_cf_cb_file_safe_reload_finished(gpointer data _U_)
1574 {
1575     set_menus_for_unsaved_capture_file(FALSE);
1576 }
1577
1578 static void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
1579 {
1580     switch(event) {
1581     case(cf_cb_file_closing):
1582                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closing");
1583         main_cf_cb_file_closing(data);
1584         break;
1585     case(cf_cb_file_closed):
1586                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Closed");
1587         main_cf_cb_file_closed(data);
1588         break;
1589     case(cf_cb_file_read_start):
1590                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read start");
1591         main_cf_cb_file_read_start(data);
1592         break;
1593     case(cf_cb_file_read_finished):
1594                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: Read finished");
1595         main_cf_cb_file_read_finished(data);
1596         break;
1597 #ifdef HAVE_LIBPCAP
1598     case(cf_cb_live_capture_prepared):
1599                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
1600         main_cf_cb_live_capture_prepared(data);
1601         break;
1602     case(cf_cb_live_capture_update_started):
1603                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
1604         main_cf_cb_live_capture_update_started(data);
1605         break;
1606     case(cf_cb_live_capture_update_continue):
1607                 /*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
1608         main_cf_cb_live_capture_update_continue(data);
1609         break;
1610     case(cf_cb_live_capture_fixed_started):
1611                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
1612         main_cf_cb_live_capture_fixed_started(data);
1613         break;
1614     case(cf_cb_live_capture_update_finished):
1615                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
1616         main_cf_cb_live_capture_update_finished(data);
1617         break;
1618     case(cf_cb_live_capture_fixed_finished):
1619                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
1620         main_cf_cb_live_capture_fixed_finished(data);
1621         break;
1622     case(cf_cb_live_capture_stopping):
1623                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
1624         main_cf_cb_live_capture_stopping(data);
1625         break;
1626 #endif
1627     case(cf_cb_packet_selected):
1628         main_cf_cb_packet_selected(data);
1629         break;
1630     case(cf_cb_packet_unselected):
1631         main_cf_cb_packet_unselected(data);
1632         break;
1633     case(cf_cb_field_unselected):
1634         main_cf_cb_field_unselected(data);
1635         break;
1636     case(cf_cb_file_safe_started):
1637                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe started");
1638         main_cf_cb_file_safe_started(data);
1639         break;
1640     case(cf_cb_file_safe_finished):
1641                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe finished");
1642         main_cf_cb_file_safe_finished(data);
1643         break;
1644     case(cf_cb_file_safe_reload_finished):
1645                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: reload finished");
1646         main_cf_cb_file_safe_reload_finished(data);
1647         break;
1648     case(cf_cb_file_safe_failed):
1649                 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: safe failed");
1650         main_cf_cb_file_safe_failed(data);
1651         break;
1652     default:
1653         g_warning("main_cf_callback: event %u unknown", event);
1654         g_assert_not_reached();
1655     }
1656 }
1657
1658 /* And now our feature presentation... [ fade to music ] */
1659 int
1660 main(int argc, char *argv[])
1661 {
1662 #ifdef HAVE_LIBPCAP
1663   const char          *command_name;
1664 #endif
1665   char                *s;
1666   int                  i;
1667   int                  opt;
1668   extern char         *optarg;
1669   gboolean             arg_error = FALSE;
1670
1671 #ifdef _WIN32
1672   WSADATA              wsaData;
1673 #endif  /* _WIN32 */
1674
1675   char                *rf_path;
1676   int                  rf_open_errno;
1677   char                *gpf_path, *pf_path;
1678   char                *cf_path, *df_path;
1679   char                *gdp_path, *dp_path;
1680   int                  gpf_open_errno, gpf_read_errno;
1681   int                  pf_open_errno, pf_read_errno;
1682   int                  cf_open_errno, df_open_errno;
1683   int                  gdp_open_errno, gdp_read_errno;
1684   int                  dp_open_errno, dp_read_errno;
1685   int                  err;
1686 #ifdef HAVE_LIBPCAP
1687   gboolean             start_capture = FALSE;
1688   GList               *if_list;
1689   if_info_t           *if_info;
1690   GList               *lt_list, *lt_entry;
1691   data_link_info_t    *data_link_info;
1692   gchar                err_str[PCAP_ERRBUF_SIZE];
1693   gchar               *cant_get_if_list_errstr;
1694   gboolean             stats_known;
1695   struct pcap_stat     stats;
1696 #else
1697   gboolean             capture_option_specified = FALSE;
1698 #endif
1699   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1700   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1701   dfilter_t           *rfcode = NULL;
1702   gboolean             rfilter_parse_failed = FALSE;
1703   e_prefs             *prefs;
1704   char                 badopt;
1705   GtkWidget           *splash_win = NULL;
1706   GLogLevelFlags       log_flags;
1707   guint                go_to_packet = 0;
1708   int                  optind_initial;
1709
1710 #define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:w:vy:z:"
1711
1712 #ifdef HAVE_LIBPCAP
1713 #ifdef _WIN32
1714 #define OPTSTRING_CHILD "W:Z:"
1715 #define OPTSTRING_WIN32 "B:"
1716 #else
1717 #define OPTSTRING_CHILD "W:"
1718 #define OPTSTRING_WIN32 ""
1719 #endif  /* _WIN32 */
1720 #else
1721 #define OPTSTRING_CHILD ""
1722 #define OPTSTRING_WIN32 ""
1723 #endif  /* HAVE_LIBPCAP */
1724
1725   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) + sizeof(OPTSTRING_WIN32) - 2] =
1726     OPTSTRING_INIT OPTSTRING_WIN32;
1727
1728   /* initialize memory allocation subsystem */
1729   ep_init_chunk();
1730   se_init_chunk();
1731
1732   /*** create the compile and runtime version strings ***/
1733 #ifdef _WIN32
1734   /* Load wpcap if possible. Do this before collecting the run-time version information */
1735   load_wpcap();
1736
1737   /* ... and also load the packet.dll from wpcap */
1738   wpcap_packet_load();
1739
1740   /* Start windows sockets */
1741   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1742 #endif  /* _WIN32 */
1743
1744   /* Assemble the compile-time version information string */
1745   comp_info_str = g_string_new("Compiled ");
1746   g_string_append(comp_info_str, "with ");
1747   g_string_sprintfa(comp_info_str,
1748 #ifdef GTK_MAJOR_VERSION
1749                     "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1750                     GTK_MICRO_VERSION);
1751 #else
1752                     "GTK+ (version unknown)");
1753 #endif
1754
1755   g_string_append(comp_info_str, ", ");
1756   get_compiled_version_info(comp_info_str);
1757
1758   /* Assemble the run-time version information string */
1759   runtime_info_str = g_string_new("Running ");
1760   get_runtime_version_info(runtime_info_str);
1761
1762
1763   /*** "pre-scan" the command line parameters, if we have "console only" parameters ***/
1764   /* (e.g. don't start GTK+, if we only have to show the command line help) */
1765   optind_initial = optind;
1766   while ((opt = getopt(argc, argv, optstring)) != -1) {
1767     switch (opt) {
1768       case 'h':        /* Print help and exit */
1769         print_usage(TRUE);
1770         exit(0);
1771         break;
1772       case 'v':        /* Show version and exit */
1773         show_version();
1774         exit(0);
1775         break;
1776       case 'G':        /* dump various field or other infos, see handle_dashG_option() */
1777   /* If invoked with the "-G" flag, we dump out information based on
1778      the argument to the "-G" flag; if no argument is specified,
1779      for backwards compatibility we dump out a glossary of display
1780      filter symbols.
1781
1782      We must do this before calling "gtk_init()", because "gtk_init()"
1783      tries to open an X display, and we don't want to have to do any X
1784      stuff just to do a build.
1785
1786      Given that we call "gtk_init()" before doing the regular argument
1787      list processing, so that it can handle X and GTK+ arguments and
1788      remove them from the list at which we look, this means we must do
1789      this before doing the regular argument list processing, as well.
1790
1791      This means that:
1792
1793         you must give the "-G" flag as the first flag on the command line;
1794
1795         you must give it as "-G", nothing more, nothing less;
1796
1797         the first argument after the "-G" flag, if present, will be used
1798         to specify the information to dump;
1799
1800         arguments after that will not be used. */        
1801         handle_dashG_option(argc, argv, "ethereal");
1802         /* will never return! */
1803         exit(0);
1804         break;
1805     }
1806   }
1807
1808   /* set getopt index back to initial value, so it will start with the first command line parameter again */
1809   /* (XXX - this seems to be portable, but time will tell) */
1810   optind = optind_initial;
1811
1812
1813   /* Set the current locale according to the program environment.
1814    * We haven't localized anything, but some GTK widgets are localized
1815    * (the file selection dialogue, for example).
1816    * This also sets the C-language locale to the native environment. */
1817   gtk_set_locale();
1818
1819   /* Let GTK get its args (will need an X server, so do this after command line only commands handled) */
1820   gtk_init (&argc, &argv);
1821
1822   cf_callback_add(main_cf_callback, NULL);
1823
1824 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
1825   /* initialize our GTK eth_clist_type */
1826   init_eth_clist_type();
1827 #endif
1828
1829   ethereal_path = argv[0];
1830
1831   /* Arrange that if we have no console window, and a GLib message logging
1832      routine is called to log a message, we pop up a console window.
1833
1834      We do that by inserting our own handler for all messages logged
1835      to the default domain; that handler pops up a console if necessary,
1836      and then calls the default handler. */
1837
1838   /* We might want to have component specific log levels later ... */
1839
1840   /* the default_log_handler will use stdout, which makes trouble with the */
1841   /* capture child, as it uses stdout for it's sync_pipe */
1842   /* so do the filtering in the console_log_handler and not here */
1843   log_flags = 
1844                     G_LOG_LEVEL_ERROR|
1845                     G_LOG_LEVEL_CRITICAL|
1846                     G_LOG_LEVEL_WARNING|
1847                     G_LOG_LEVEL_MESSAGE|
1848                     G_LOG_LEVEL_INFO|
1849                     G_LOG_LEVEL_DEBUG|
1850                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
1851
1852   g_log_set_handler(NULL,
1853                     log_flags,
1854                     console_log_handler, NULL /* user_data */);
1855   g_log_set_handler(LOG_DOMAIN_MAIN,
1856                     log_flags,
1857                     console_log_handler, NULL /* user_data */);
1858
1859 #ifdef HAVE_LIBPCAP
1860   g_log_set_handler(LOG_DOMAIN_CAPTURE,
1861                     log_flags,
1862             console_log_handler, NULL /* user_data */);
1863   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
1864                     log_flags,
1865             console_log_handler, NULL /* user_data */);
1866
1867   /* Set the initial values in the capture_opts. This might be overwritten 
1868      by preference settings and then again by the command line parameters. */
1869   capture_opts_init(capture_opts, &cfile);
1870
1871   capture_opts->snaplen             = MIN_PACKET_SIZE;
1872   capture_opts->has_ring_num_files  = TRUE;
1873
1874   command_name = get_basename(ethereal_path);
1875   /* Set "capture_child" to indicate whether this is going to be a child
1876      process for a "-S" capture. */
1877   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1878   if (capture_child) {
1879     strcat(optstring, OPTSTRING_CHILD);
1880   }
1881 #endif
1882
1883   /* We want a splash screen only if we're not a child process.
1884      We won't come till here, if we had a "console only" command line parameter. */
1885 #ifdef HAVE_LIBPCAP
1886   if (!capture_child)
1887 #endif
1888     splash_win = splash_new("Loading Ethereal ...");
1889
1890   splash_update(splash_win, "Registering dissectors ...");
1891
1892   /* Register all dissectors; we must do this before checking for the
1893      "-G" flag, as the "-G" flag dumps information registered by the
1894      dissectors, and we must do it before we read the preferences, in
1895      case any dissectors register preferences. */
1896   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs,
1897             failure_alert_box,open_failure_alert_box,read_failure_alert_box);
1898
1899   splash_update(splash_win, "Registering tap listeners ...");
1900
1901   /* Register all tap listeners; we do this before we parse the arguments,
1902      as the "-z" argument can specify a registered tap. */
1903
1904   /* we register the plugin taps before the other taps because
1905           stats_tree taps plugins will be registered as tap listeners
1906           by stats_tree_stat.c and need to registered before that */
1907
1908 #ifdef HAVE_PLUGINS
1909   register_all_plugin_tap_listeners();
1910 #endif
1911
1912   register_all_tap_listeners();
1913   
1914   splash_update(splash_win, "Loading module preferences ...");
1915
1916   /* Now register the preferences for any non-dissector modules.
1917      We must do that before we read the preferences as well. */
1918   prefs_register_modules();
1919
1920   /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1921 #if !defined(_WIN32) && GTK_MAJOR_VERSION >= 2 && defined(G_THREADS_ENABLED) && defined USE_THREADS
1922   {
1923       GThread *ut;
1924       g_thread_init(NULL);
1925       gdk_threads_init();
1926       ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1927       g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1928   }
1929 #else  /* _WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1930   /* this is to keep tap extensions updating once every 3 seconds */
1931   gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1932 #endif /* !_WIN32 && GTK2 && G_THREADS_ENABLED */
1933
1934 #if HAVE_GNU_ADNS
1935   gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
1936 #endif
1937
1938   splash_update(splash_win, "Loading configuration files ...");
1939
1940   /* Read the preference files. */
1941   prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
1942                      &pf_open_errno, &pf_read_errno, &pf_path);
1943   if (gpf_path != NULL) {
1944     if (gpf_open_errno != 0) {
1945       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1946         "Could not open global preferences file\n\"%s\": %s.", gpf_path,
1947         strerror(gpf_open_errno));
1948     }
1949     if (gpf_read_errno != 0) {
1950       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1951         "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
1952         strerror(gpf_read_errno));
1953     }
1954   }
1955   if (pf_path != NULL) {
1956     if (pf_open_errno != 0) {
1957       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1958         "Could not open your preferences file\n\"%s\": %s.", pf_path,
1959         strerror(pf_open_errno));
1960     }
1961     if (pf_read_errno != 0) {
1962       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1963         "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
1964         strerror(pf_read_errno));
1965     }
1966     g_free(pf_path);
1967     pf_path = NULL;
1968   }
1969
1970 #ifdef _WIN32
1971   /* if the user wants a console to be always there, well, we should open one for him */
1972   if (prefs->gui_console_open == console_open_always) {
1973     create_console();
1974   }
1975 #endif
1976
1977 #ifdef HAVE_LIBPCAP
1978   /* If this is a capture child process, it should pay no attention
1979      to the "prefs.capture_prom_mode" setting in the preferences file;
1980      it should do what the parent process tells it to do, and if
1981      the parent process wants it not to run in promiscuous mode, it'll
1982      tell it so with a "-p" flag.
1983
1984      Otherwise, set promiscuous mode from the preferences setting. */
1985   /* the same applies to other preferences settings as well. */
1986   if (capture_child) {
1987     auto_scroll_live             = FALSE;
1988   } else {
1989     capture_opts->promisc_mode   = prefs->capture_prom_mode;
1990     capture_opts->show_info      = prefs->capture_show_info;
1991     capture_opts->real_time_mode = prefs->capture_real_time;
1992     auto_scroll_live             = prefs->capture_auto_scroll;
1993   }
1994
1995 #endif /* HAVE_LIBPCAP */
1996
1997   /* Set the name resolution code's flags from the preferences. */
1998   g_resolv_flags = prefs->name_resolve;
1999
2000   /* Read the capture filter file. */
2001   read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
2002   if (cf_path != NULL) {
2003       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2004         "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2005         strerror(cf_open_errno));
2006       g_free(cf_path);
2007   }
2008
2009   /* Read the display filter file. */
2010   read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
2011   if (df_path != NULL) {
2012       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2013         "Could not open your display filter file\n\"%s\": %s.", df_path,
2014         strerror(df_open_errno));
2015       g_free(df_path);
2016   }
2017
2018   /* Read the disabled protocols file. */
2019   read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
2020                             &dp_path, &dp_open_errno, &dp_read_errno);
2021   if (gdp_path != NULL) {
2022     if (gdp_open_errno != 0) {
2023       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2024         "Could not open global disabled protocols file\n\"%s\": %s.",
2025         gdp_path, strerror(gdp_open_errno));
2026     }
2027     if (gdp_read_errno != 0) {
2028       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2029         "I/O error reading global disabled protocols file\n\"%s\": %s.",
2030         gdp_path, strerror(gdp_read_errno));
2031     }
2032     g_free(gdp_path);
2033   }
2034   if (dp_path != NULL) {
2035     if (dp_open_errno != 0) {
2036       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2037         "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
2038         strerror(dp_open_errno));
2039     }
2040     if (dp_read_errno != 0) {
2041       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2042         "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2043         strerror(dp_read_errno));
2044     }
2045     g_free(dp_path);
2046   }
2047
2048   /* Read the (static part) of the recent file. Only the static part of it will be read, */
2049   /* as we don't have the gui now to fill the recent lists which is done in the dynamic part. */
2050   /* We have to do this already here, so command line parameters can overwrite these values. */
2051   recent_read_static(&rf_path, &rf_open_errno);
2052
2053   init_cap_file(&cfile);
2054
2055   /* Now get our args */
2056   while ((opt = getopt(argc, argv, optstring)) != -1) {
2057     switch (opt) {
2058       /*** capture option specific ***/
2059       case 'a':        /* autostop criteria */
2060       case 'b':        /* Ringbuffer option */
2061       case 'c':        /* Capture xxx packets */
2062       case 'f':        /* capture filter */
2063       case 'k':        /* Start capture immediately */
2064       case 'H':        /* Hide capture info dialog box */
2065       case 'i':        /* Use interface xxx */
2066       case 'p':        /* Don't capture in promiscuous mode */
2067       case 'Q':        /* Quit after capture (just capture to file) */
2068       case 's':        /* Set the snapshot (capture) length */
2069       case 'S':        /* "Sync" mode: used for following file ala tail -f */
2070       case 'w':        /* Write to capture file xxx */
2071       case 'y':        /* Set the pcap data link type */
2072 #ifdef _WIN32
2073       case 'B':        /* Buffer size */
2074       /* Hidden option supporting Sync mode */
2075       case 'Z':        /* Write to pipe FD XXX */
2076 #endif /* _WIN32 */
2077 #ifdef HAVE_LIBPCAP
2078         capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2079 #else
2080         capture_option_specified = TRUE;
2081         arg_error = TRUE;
2082 #endif
2083         break;
2084 #ifdef HAVE_LIBPCAP
2085       /* This is a hidden option supporting Sync mode, so we don't set
2086        * the error flags for the user in the non-libpcap case.
2087        */
2088       case 'W':        /* Write to capture file FD xxx */
2089         capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
2090         break;
2091 #endif
2092
2093       /*** all non capture option specific ***/
2094       case 'g':        /* Go to packet */
2095         go_to_packet = get_positive_int("Ethereal", optarg, "go to packet");
2096         break;
2097       case 'l':        /* Automatic scrolling in live capture mode */
2098 #ifdef HAVE_LIBPCAP
2099         auto_scroll_live = TRUE;
2100 #else
2101         capture_option_specified = TRUE;
2102         arg_error = TRUE;
2103 #endif
2104         break;
2105       case 'L':        /* Print list of link-layer types and exit */
2106 #ifdef HAVE_LIBPCAP
2107         list_link_layer_types = TRUE;
2108 #else
2109         capture_option_specified = TRUE;
2110         arg_error = TRUE;
2111 #endif
2112         break;
2113       case 'm':        /* Fixed-width font for the display */
2114         if (prefs->PREFS_GUI_FONT_NAME != NULL)
2115           g_free(prefs->PREFS_GUI_FONT_NAME);
2116         prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2117         break;
2118       case 'n':        /* No name resolution */
2119         g_resolv_flags = RESOLV_NONE;
2120         break;
2121       case 'N':        /* Select what types of addresses/port #s to resolve */
2122         if (g_resolv_flags == RESOLV_ALL)
2123           g_resolv_flags = RESOLV_NONE;
2124         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2125         if (badopt != '\0') {
2126           g_warning("ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'",
2127                         badopt);
2128           exit(1);
2129         }
2130         break;
2131       case 'o':        /* Override preference from command line */
2132         switch (prefs_set_pref(optarg)) {
2133         case PREFS_SET_OK:
2134           break;
2135         case PREFS_SET_SYNTAX_ERR:
2136           g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2137           exit(1);
2138           break;
2139         case PREFS_SET_NO_SUCH_PREF:
2140           /* not a preference, might be a recent setting */
2141           switch (recent_set_arg(optarg)) {
2142             case PREFS_SET_OK:
2143               break;
2144             case PREFS_SET_SYNTAX_ERR:
2145               /* shouldn't happen, checked already above */
2146               g_warning("ethereal: Invalid -o flag \"%s\"", optarg);
2147               exit(1);
2148               break;
2149             case PREFS_SET_NO_SUCH_PREF:
2150             case PREFS_SET_OBSOLETE:
2151               g_warning("ethereal: -o flag \"%s\" specifies unknown preference/recent value",
2152                     optarg);
2153               exit(1);
2154               break;
2155             default:
2156               g_assert_not_reached();
2157             }
2158           break;
2159         case PREFS_SET_OBSOLETE:
2160           g_warning("ethereal: -o flag \"%s\" specifies obsolete preference",
2161                         optarg);
2162           exit(1);
2163           break;
2164         default:
2165           g_assert_not_reached();
2166         }
2167         break;
2168       case 'r':        /* Read capture file xxx */
2169         /* We may set "last_open_dir" to "cf_name", and if we change
2170            "last_open_dir" later, we free the old value, so we have to
2171            set "cf_name" to something that's been allocated. */
2172         cf_name = g_strdup(optarg);
2173         break;
2174       case 'R':        /* Read file filter */
2175         rfilter = optarg;
2176         break;
2177       case 't':        /* Time stamp type */
2178         if (strcmp(optarg, "r") == 0)
2179           timestamp_set_type(TS_RELATIVE);
2180         else if (strcmp(optarg, "a") == 0)
2181           timestamp_set_type(TS_ABSOLUTE);
2182         else if (strcmp(optarg, "ad") == 0)
2183           timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
2184         else if (strcmp(optarg, "d") == 0)
2185           timestamp_set_type(TS_DELTA);
2186         else {
2187           g_warning("ethereal: Invalid time stamp type \"%s\"",
2188             optarg);
2189           g_warning("It must be \"r\" for relative, \"a\" for absolute,");
2190           g_warning("\"ad\" for absolute with date, or \"d\" for delta.");
2191           exit(1);
2192         }
2193         break;
2194       case 'z':
2195         /* We won't call the init function for the stat this soon
2196            as it would disallow MATE's fields (which are registered
2197            by the preferences set callback) from being used as
2198            part of a tap filter.  Instead, we just add the argument
2199            to a list of stat arguments. */
2200         if (!process_stat_cmd_arg(optarg)) {
2201           g_warning("ethereal: invalid -z argument.");
2202           g_warning("  -z argument must be one of :");
2203           list_stat_cmd_args();
2204           exit(1);
2205         }
2206         break;
2207       default:
2208       case '?':        /* Bad flag - print usage message */
2209             g_warning("Bad flag");
2210         arg_error = TRUE;
2211         break;
2212     }
2213   }
2214   argc -= optind;
2215   argv += optind;
2216   if (argc >= 1) {
2217     if (cf_name != NULL) {
2218       /*
2219        * Input file name specified with "-r" *and* specified as a regular
2220        * command-line argument.
2221        */
2222           g_warning("File name specified both with -r and regular argument");
2223       arg_error = TRUE;
2224     } else {
2225       /*
2226        * Input file name not specified with "-r", and a command-line argument
2227        * was specified; treat it as the input file name.
2228        *
2229        * Yes, this is different from tethereal, where non-flag command-line
2230        * arguments are a filter, but this works better on GUI desktops
2231        * where a command can be specified to be run to open a particular
2232        * file - yes, you could have "-r" as the last part of the command,
2233        * but that's a bit ugly.
2234        */
2235       cf_name = g_strdup(argv[0]);
2236     }
2237     argc--;
2238     argv++;
2239   }
2240
2241
2242
2243   if (argc != 0) {
2244     /*
2245      * Extra command line arguments were specified; complain.
2246      */
2247     g_warning("Invalid argument: %s", argv[0]);
2248     arg_error = TRUE;
2249   }
2250
2251   if (arg_error) {
2252 #ifndef HAVE_LIBPCAP
2253     if (capture_option_specified) {
2254       g_warning("This version of Ethereal was not built with support for capturing packets.");
2255     }
2256 #endif
2257     print_usage(FALSE);
2258     exit(1);
2259   }
2260
2261 #ifdef HAVE_LIBPCAP
2262   if (start_capture && list_link_layer_types) {
2263     /* Specifying *both* is bogus. */
2264     g_warning("ethereal: You can't specify both -L and a live capture.");
2265     exit(1);
2266   }
2267
2268   if (list_link_layer_types) {
2269     /* We're supposed to list the link-layer types for an interface;
2270        did the user also specify a capture file to be read? */
2271     if (cf_name) {
2272       /* Yes - that's bogus. */
2273       g_warning("ethereal: You can't specify -L and a capture file to be read.");
2274       exit(1);
2275     }
2276     /* No - did they specify a ring buffer option? */
2277     if (capture_opts->multi_files_on) {
2278       g_warning("ethereal: Ring buffer requested, but a capture isn't being done.");
2279       exit(1);
2280     }
2281   } else {
2282     /* We're supposed to do a live capture; did the user also specify
2283        a capture file to be read? */
2284     if (start_capture && cf_name) {
2285       /* Yes - that's bogus. */
2286       g_warning("ethereal: You can't specify both a live capture and a capture file to be read.");
2287       exit(1);
2288     }
2289
2290     /* No - was the ring buffer option specified and, if so, does it make
2291        sense? */
2292     if (capture_opts->multi_files_on) {
2293       /* Ring buffer works only under certain conditions:
2294          a) ring buffer does not work with temporary files;
2295          b) real_time_mode and multi_files_on are mutually exclusive -
2296             real_time_mode takes precedence;
2297          c) it makes no sense to enable the ring buffer if the maximum
2298             file size is set to "infinite". */
2299       if (capture_opts->save_file == NULL) {
2300         g_warning("ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.");
2301         capture_opts->multi_files_on = FALSE;
2302       }
2303 /*      if (capture_opts->real_time_mode) {
2304         g_warning("ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.");
2305         capture_opts->multi_files_on = FALSE;
2306       }*/
2307       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
2308         g_warning("ethereal: Ring buffer requested, but no maximum capture file size or duration were specified.");
2309 /* XXX - this must be redesigned as the conditions changed */
2310 /*      capture_opts->multi_files_on = FALSE;*/
2311       }
2312     }
2313   }
2314
2315   if (start_capture || list_link_layer_types) {
2316     /* Did the user specify an interface to use? */
2317     if (capture_opts->iface == NULL) {
2318       /* No - is a default specified in the preferences file? */
2319       if (prefs->capture_device != NULL) {
2320           /* Yes - use it. */
2321           capture_opts->iface = g_strdup(get_if_name(prefs->capture_device));
2322       } else {
2323         /* No - pick the first one from the list of interfaces. */
2324         if_list = get_interface_list(&err, err_str);
2325         if (if_list == NULL) {
2326           switch (err) {
2327
2328           case CANT_GET_INTERFACE_LIST:
2329               cant_get_if_list_errstr = cant_get_if_list_error_message(err_str);
2330               g_warning("%s", cant_get_if_list_errstr);
2331               g_free(cant_get_if_list_errstr);
2332               break;
2333
2334           case NO_INTERFACES_FOUND:
2335               g_warning("ethereal: There are no interfaces on which a capture can be done");
2336               break;
2337           }
2338           exit(2);
2339         }
2340         if_info = if_list->data;        /* first interface */
2341         capture_opts->iface = g_strdup(if_info->name);
2342         free_interface_list(if_list);
2343       }
2344     }
2345   }
2346
2347   if (list_link_layer_types) {
2348     /* Get the list of link-layer types for the capture device. */
2349     lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
2350     if (lt_list == NULL) {
2351       if (err_str[0] != '\0') {
2352         g_warning("ethereal: The list of data link types for the capture device could not be obtained (%s)."
2353           "Please check to make sure you have sufficient permissions, and that\n"
2354           "you have the proper interface or pipe specified.\n", err_str);
2355       } else
2356         g_warning("ethereal: The capture device has no data link types.");
2357       exit(2);
2358     }
2359     g_warning("Data link types (use option -y to set):");
2360     for (lt_entry = lt_list; lt_entry != NULL;
2361          lt_entry = g_list_next(lt_entry)) {
2362       data_link_info = lt_entry->data;
2363       g_warning("  %s", data_link_info->name);
2364       if (data_link_info->description != NULL)
2365         g_warning(" (%s)", data_link_info->description);
2366       else
2367         g_warning(" (not supported)");
2368       putchar('\n');
2369     }
2370     free_pcap_linktype_list(lt_list);
2371     exit(0);
2372   }
2373
2374   if (capture_opts->has_snaplen) {
2375     if (capture_opts->snaplen < 1)
2376       capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
2377     else if (capture_opts->snaplen < MIN_PACKET_SIZE)
2378       capture_opts->snaplen = MIN_PACKET_SIZE;
2379   }
2380
2381   /* Check the value range of the ringbuffer_num_files parameter */
2382   if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
2383     capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
2384 #if RINGBUFFER_MIN_NUM_FILES > 0
2385   else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
2386     capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
2387 #endif
2388 #endif /* HAVE_LIBPCAP */
2389
2390   /* Notify all registered modules that have had any of their preferences
2391      changed either from one of the preferences file or from the command
2392      line that their preferences have changed. */
2393   prefs_apply_all();
2394
2395   /* disabled protocols as per configuration file */
2396   if (gdp_path == NULL && dp_path == NULL) {
2397     set_disabled_protos_list();
2398   }
2399
2400   /* Build the column format array */
2401   col_setup(&cfile.cinfo, prefs->num_cols);
2402   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2403     cfile.cinfo.col_fmt[i] = get_column_format(i);
2404     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2405     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2406       NUM_COL_FMTS);
2407     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2408     cfile.cinfo.col_data[i] = NULL;
2409     if (cfile.cinfo.col_fmt[i] == COL_INFO)
2410       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2411     else
2412       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2413     cfile.cinfo.col_fence[i] = 0;
2414     cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2415     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2416   }
2417
2418   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2419       int j;
2420
2421       for (j = 0; j < NUM_COL_FMTS; j++) {
2422          if (!cfile.cinfo.fmt_matx[i][j])
2423              continue;
2424          
2425          if (cfile.cinfo.col_first[j] == -1)
2426              cfile.cinfo.col_first[j] = i;
2427          cfile.cinfo.col_last[j] = i;
2428       }
2429   }
2430
2431   /* read in rc file from global and personal configuration paths. */
2432   rc_file = get_datafile_path(RC_FILE);
2433   gtk_rc_parse(rc_file);
2434   rc_file = get_persconffile_path(RC_FILE, FALSE);
2435   gtk_rc_parse(rc_file);
2436
2437 #ifdef HAVE_LIBPCAP
2438   font_init(capture_child);
2439 #else
2440   font_init(FALSE);
2441 #endif
2442
2443   /* close the splash screen, as we are going to open the main window now */
2444   splash_destroy(splash_win);
2445
2446
2447 #ifdef HAVE_LIBPCAP
2448   /* Is this a "child" ethereal, which is only supposed to pop up a
2449      capture box to let us stop the capture, and run a capture
2450      to a file that our parent will read? */
2451   if (capture_child) {
2452     /* This is the child process of a capture session,
2453        so just do the low-level work of a capture - don't create
2454        a temporary file and fork off *another* child process (so don't
2455        call "capture_start()"). */
2456
2457     /* Pop up any queued-up alert boxes. */
2458     display_queued_messages();
2459
2460     /* Now start the capture. 
2461        After the capture is done; there's nothing more for us to do. */
2462
2463     /* XXX - hand these stats to the parent process */
2464     if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
2465         /* capture ok */
2466         gtk_exit(0);
2467     } else {
2468         /* capture failed */
2469         gtk_exit(1);
2470     }
2471   }
2472 #endif
2473
2474   /***********************************************************************/
2475   /* Everything is prepared now, preferences and command line was read in,
2476        we are NOT a child window for a synced capture. */
2477
2478   /* Pop up the main window. */
2479   create_main_window(pl_size, tv_size, bv_size, prefs);
2480
2481   /* Read the dynamic part of the recent file, as we have the gui now ready for it. */
2482   recent_read_dynamic(&rf_path, &rf_open_errno);
2483   color_filters_enable(recent.packet_list_colorize);
2484
2485   /* rearrange all the widgets as we now have all recent settings ready for this */
2486   main_widgets_rearrange();
2487
2488   /* Fill in column titles.  This must be done after the top level window
2489      is displayed.
2490
2491      XXX - is that still true, with fixed-width columns? */
2492   packet_list_set_column_titles();
2493
2494   menu_recent_read_finished();
2495
2496   switch (user_font_apply()) {
2497   case FA_SUCCESS:
2498       break;
2499   case FA_FONT_NOT_RESIZEABLE:
2500       /* "user_font_apply()" popped up an alert box. */
2501       /* turn off zooming - font can't be resized */
2502   case FA_FONT_NOT_AVAILABLE:
2503       /* XXX - did we successfully load the un-zoomed version earlier?
2504       If so, this *probably* means the font is available, but not at
2505       this particular zoom level, but perhaps some other failure
2506       occurred; I'm not sure you can determine which is the case,
2507       however. */
2508       /* turn off zooming - zoom level is unavailable */
2509   default:
2510       /* in any other case than FA_SUCCESS, turn off zooming */
2511       recent.gui_zoom_level = 0;        
2512       /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2513   }
2514
2515   dnd_init(top_level);
2516
2517   colors_init();
2518   color_filters_init();
2519   decode_as_init();
2520
2521   /* the window can be sized only, if it's not already shown, so do it now! */
2522   main_load_window_geometry(top_level);
2523
2524   /* If we were given the name of a capture file, read it in now;
2525      we defer it until now, so that, if we can't open it, and pop
2526      up an alert box, the alert box is more likely to come up on
2527      top of the main window - but before the preference-file-error
2528      alert box, so, if we get one of those, it's more likely to come
2529      up on top of us. */
2530   if (cf_name) {
2531     show_main_window(TRUE);
2532     if (rfilter != NULL) {
2533       if (!dfilter_compile(rfilter, &rfcode)) {
2534         bad_dfilter_alert_box(rfilter);
2535         rfilter_parse_failed = TRUE;
2536       }
2537     }
2538     if (!rfilter_parse_failed) {
2539       if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
2540         /* "cf_open()" succeeded, so it closed the previous
2541            capture file, and thus destroyed any previous read filter
2542            attached to "cf". */
2543
2544         cfile.rfcode = rfcode;
2545         /* Open stat windows; we do so after creating the main window,
2546            to avoid GTK warnings, and after successfully opening the
2547            capture file, so we know we have something to compute stats
2548            on, and after registering all dissectors, so that MATE will
2549            have registered its field array and we can have a tap filter
2550            with one of MATE's late-registered fields as part of the
2551            filter. */
2552         start_requested_stats();
2553
2554         /* Read the capture file. */
2555         switch (cf_read(&cfile)) {
2556
2557         case CF_READ_OK:
2558         case CF_READ_ERROR:
2559           /* Just because we got an error, that doesn't mean we were unable
2560              to read any of the file; we handle what we could get from the
2561              file. */
2562           /* if the user told us to jump to a specific packet, do it now */
2563           if(go_to_packet != 0) {
2564             cf_goto_frame(&cfile, go_to_packet);
2565           }
2566           break;
2567
2568         case CF_READ_ABORTED:
2569           /* Exit now. */
2570           gtk_exit(0);
2571           break;
2572         }
2573         /* Save the name of the containing directory specified in the
2574            path name, if any; we can write over cf_name, which is a
2575            good thing, given that "get_dirname()" does write over its
2576            argument. */
2577         s = get_dirname(cf_name);
2578         /* we might already set this from the recent file, don't overwrite this */
2579         if(get_last_open_dir() == NULL) 
2580           set_last_open_dir(s);
2581         g_free(cf_name);
2582         cf_name = NULL;
2583       } else {
2584         if (rfcode != NULL)
2585           dfilter_free(rfcode);
2586         cfile.rfcode = NULL;
2587     show_main_window(FALSE);
2588         set_menus_for_capture_in_progress(FALSE);
2589       }
2590     }
2591   } else {
2592 #ifdef HAVE_LIBPCAP
2593     if (start_capture) {
2594       if (capture_opts->save_file != NULL) {
2595         /* Save the directory name for future file dialogs. */
2596         /* (get_dirname overwrites filename) */
2597         s = get_dirname(g_strdup(capture_opts->save_file));  
2598         set_last_open_dir(s);
2599         g_free(s);
2600       }
2601       /* "-k" was specified; start a capture. */
2602       show_main_window(TRUE);
2603       if (capture_start(capture_opts)) {
2604         /* The capture started.  Open stat windows; we do so after creating
2605            the main window, to avoid GTK warnings, and after successfully
2606            opening the capture file, so we know we have something to compute
2607            stats on, and after registering all dissectors, so that MATE will
2608            have registered its field array and we can have a tap filter with
2609            one of MATE's late-registered fields as part of the filter. */
2610         start_requested_stats();
2611       }
2612     }
2613     else {
2614       show_main_window(FALSE);
2615       set_menus_for_capture_in_progress(FALSE);
2616     }
2617
2618     /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
2619     if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
2620       if (capture_opts->cfilter) {
2621         g_free(capture_opts->cfilter);
2622       }
2623       capture_opts->cfilter = g_strdup(get_conn_cfilter());
2624     }
2625 #else /* HAVE_LIBPCAP */
2626     show_main_window(FALSE);
2627     set_menus_for_capture_in_progress(FALSE);
2628 #endif /* HAVE_LIBPCAP */
2629   }
2630
2631   /* we'll enter the GTK loop now and hand the control over to GTK ... */
2632   gtk_main();
2633   /* ... back from GTK, we're going down now! */
2634
2635   epan_cleanup();
2636   g_free(rc_file);
2637
2638 #ifdef _WIN32
2639   /* hide the (unresponsive) main window, while asking the user to close the console window */
2640   gtk_widget_hide(top_level);
2641
2642   /* Shutdown windows sockets */
2643   WSACleanup();
2644
2645   /* For some unknown reason, the "atexit()" call in "create_console()"
2646      doesn't arrange that "destroy_console()" be called when we exit,
2647      so we call it here if a console was created. */
2648   destroy_console();
2649 #endif
2650
2651   gtk_exit(0);
2652
2653   /* This isn't reached, but we need it to keep GCC from complaining
2654      that "main()" returns without returning a value - it knows that
2655      "exit()" never returns, but it doesn't know that "gtk_exit()"
2656      doesn't, as GTK+ doesn't declare it with the attribute
2657      "noreturn". */
2658   return 0;     /* not reached */
2659 }
2660
2661 #ifdef _WIN32
2662
2663 /* We build this as a GUI subsystem application on Win32, so
2664    "WinMain()", not "main()", gets called.
2665
2666    Hack shamelessly stolen from the Win32 port of the GIMP. */
2667 #ifdef __GNUC__
2668 #define _stdcall  __attribute__((stdcall))
2669 #endif
2670
2671 int _stdcall
2672 WinMain (struct HINSTANCE__ *hInstance,
2673          struct HINSTANCE__ *hPrevInstance,
2674          char               *lpszCmdLine,
2675          int                 nCmdShow)
2676 {
2677   has_console = FALSE;
2678   return main (__argc, __argv);
2679 }
2680
2681 /*
2682  * If this application has no console window to which its standard output
2683  * would go, create one.
2684  */
2685 void
2686 create_console(void)
2687 {
2688   if (!has_console) {
2689     /* We have no console to which to print the version string, so
2690        create one and make it the standard input, output, and error. */
2691     if (!AllocConsole())
2692       return;   /* couldn't create console */
2693     freopen("CONIN$", "r", stdin);
2694     freopen("CONOUT$", "w", stdout);
2695     freopen("CONOUT$", "w", stderr);
2696
2697     /* Well, we have a console now. */
2698     has_console = TRUE;
2699
2700     /* Now register "destroy_console()" as a routine to be called just
2701        before the application exits, so that we can destroy the console
2702        after the user has typed a key (so that the console doesn't just
2703        disappear out from under them, giving the user no chance to see
2704        the message(s) we put in there). */
2705     atexit(destroy_console);
2706
2707         if(capture_child) {
2708                 SetConsoleTitle("Ethereal Capture Child Debug Console");
2709         } else {
2710                 SetConsoleTitle("Ethereal Debug Console");
2711         }
2712   }
2713 }
2714
2715 static void
2716 destroy_console(void)
2717 {
2718   if (has_console && !capture_child) {
2719     printf("\n\nPress any key to exit\n");
2720     _getch();
2721     FreeConsole();
2722   }
2723 }
2724 #endif /* _WIN32 */
2725
2726
2727 /* This routine should not be necessary, at least as I read the GLib
2728    source code, as it looks as if GLib is, on Win32, *supposed* to
2729    create a console window into which to display its output.
2730
2731    That doesn't happen, however.  I suspect there's something completely
2732    broken about that code in GLib-for-Win32, and that it may be related
2733    to the breakage that forces us to just call "printf()" on the message
2734    rather than passing the message on to "g_log_default_handler()"
2735    (which is the routine that does the aforementioned non-functional
2736    console window creation). */
2737 static void
2738 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2739                     const char *message, gpointer user_data _U_)
2740 {
2741   time_t curr;
2742   struct tm *today;
2743   const char *level;
2744
2745
2746   /* ignore log message, if log_level isn't interesting */
2747   if( !(log_level & G_LOG_LEVEL_MASK & prefs.console_log_level)) {
2748     return;
2749   }
2750
2751   /* create a "timestamp" */
2752   time(&curr);
2753   today = localtime(&curr);    
2754
2755 #ifdef _WIN32
2756   if (prefs.gui_console_open != console_open_never) {
2757     create_console();
2758   }
2759   if (has_console) {
2760     /* For some unknown reason, the above doesn't appear to actually cause
2761        anything to be sent to the standard output, so we'll just splat the
2762        message out directly, just to make sure it gets out. */
2763 #endif
2764     switch(log_level & G_LOG_LEVEL_MASK) {
2765     case G_LOG_LEVEL_ERROR:
2766         level = "Err ";
2767         break;
2768     case G_LOG_LEVEL_CRITICAL:
2769         level = "Crit";
2770         break;
2771     case G_LOG_LEVEL_WARNING:
2772         level = "Warn";
2773         break;
2774     case G_LOG_LEVEL_MESSAGE:
2775         level = "Msg ";
2776         break;
2777     case G_LOG_LEVEL_INFO:
2778         level = "Info";
2779         break;
2780     case G_LOG_LEVEL_DEBUG:
2781         level = "Dbg ";
2782         break;
2783     default:
2784         fprintf(stderr, "unknown log_level %u\n", log_level);
2785         level = NULL;
2786         g_assert_not_reached();
2787     }
2788
2789     /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
2790     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
2791             today->tm_hour, today->tm_min, today->tm_sec,
2792             log_domain != NULL ? log_domain : "",
2793             level, message);
2794 #ifdef _WIN32
2795   } else {
2796     g_log_default_handler(log_domain, log_level, message, user_data);
2797   }
2798 #endif
2799 }
2800
2801
2802 static GtkWidget *info_bar_new(void)
2803 {
2804     /* tip: tooltips don't work on statusbars! */
2805     info_bar = gtk_statusbar_new();
2806     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2807     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2808     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2809 #if GTK_MAJOR_VERSION >= 2
2810     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
2811 #endif
2812     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2813
2814     return info_bar;
2815 }
2816
2817 static GtkWidget *packets_bar_new(void)
2818 {
2819     /* tip: tooltips don't work on statusbars! */
2820     packets_bar = gtk_statusbar_new();
2821     packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
2822     packets_bar_update();
2823
2824     return packets_bar;
2825 }
2826
2827
2828 /*
2829  * Helper for main_widgets_rearrange()
2830  */
2831 static void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
2832     gtk_container_remove(GTK_CONTAINER(data), widget);
2833 }
2834
2835 static GtkWidget *main_widget_layout(gint layout_content)
2836 {
2837     switch(layout_content) {
2838     case(layout_pane_content_none):
2839         return NULL;
2840         break;
2841     case(layout_pane_content_plist):
2842         return pkt_scrollw;
2843         break;
2844     case(layout_pane_content_pdetails):
2845         return tv_scrollw;
2846         break;
2847     case(layout_pane_content_pbytes):
2848         return byte_nb_ptr;
2849         break;
2850     default:
2851         g_assert_not_reached();
2852         return NULL;
2853     }
2854 }
2855
2856
2857 /*
2858  * Rearrange the main window widgets
2859  */
2860 void main_widgets_rearrange(void) {
2861     GtkWidget *first_pane_widget1, *first_pane_widget2;
2862     GtkWidget *second_pane_widget1, *second_pane_widget2;
2863     gboolean split_top_left;
2864
2865     /* be a bit faster */
2866     gtk_widget_hide(main_vbox);
2867
2868     /* be sure, we don't loose a widget while rearranging */
2869     gtk_widget_ref(menubar);
2870     gtk_widget_ref(main_tb);
2871     gtk_widget_ref(filter_tb);
2872     gtk_widget_ref(pkt_scrollw);
2873     gtk_widget_ref(tv_scrollw);
2874     gtk_widget_ref(byte_nb_ptr);
2875     gtk_widget_ref(stat_hbox);
2876     gtk_widget_ref(info_bar);
2877     gtk_widget_ref(packets_bar);
2878     gtk_widget_ref(status_pane);
2879     gtk_widget_ref(main_pane_v1);
2880     gtk_widget_ref(main_pane_v2);
2881     gtk_widget_ref(main_pane_h1);
2882     gtk_widget_ref(main_pane_h2);
2883     gtk_widget_ref(welcome_pane);
2884
2885     /* empty all containers participating */
2886     gtk_container_foreach(GTK_CONTAINER(main_vbox),     foreach_remove_a_child, main_vbox);
2887     gtk_container_foreach(GTK_CONTAINER(stat_hbox),     foreach_remove_a_child, stat_hbox);
2888     gtk_container_foreach(GTK_CONTAINER(status_pane),   foreach_remove_a_child, status_pane);
2889     gtk_container_foreach(GTK_CONTAINER(main_pane_v1),  foreach_remove_a_child, main_pane_v1);
2890     gtk_container_foreach(GTK_CONTAINER(main_pane_v2),  foreach_remove_a_child, main_pane_v2);
2891     gtk_container_foreach(GTK_CONTAINER(main_pane_h1),  foreach_remove_a_child, main_pane_h1);
2892     gtk_container_foreach(GTK_CONTAINER(main_pane_h2),  foreach_remove_a_child, main_pane_h2);
2893
2894     /* add the menubar always at the top */
2895     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2896
2897     /* main toolbar */
2898     gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
2899
2900     /* filter toolbar in toolbar area */
2901     if (!prefs.filter_toolbar_show_in_statusbar) {
2902         gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
2903     }
2904
2905     /* fill the main layout panes */
2906     switch(prefs.gui_layout_type) {
2907     case(layout_type_5):
2908         main_first_pane  = main_pane_v1;
2909         main_second_pane = main_pane_v2;
2910         split_top_left = FALSE;
2911         break;
2912     case(layout_type_2):
2913         main_first_pane  = main_pane_v1;
2914         main_second_pane = main_pane_h1;
2915         split_top_left = FALSE;
2916         break;
2917     case(layout_type_1):
2918         main_first_pane  = main_pane_v1;
2919         main_second_pane = main_pane_h1;
2920         split_top_left = TRUE;
2921         break;
2922     case(layout_type_4):
2923         main_first_pane  = main_pane_h1;
2924         main_second_pane = main_pane_v1;
2925         split_top_left = FALSE;
2926         break;
2927     case(layout_type_3):
2928         main_first_pane  = main_pane_h1;
2929         main_second_pane = main_pane_v1;
2930         split_top_left = TRUE;
2931         break;
2932     case(layout_type_6):
2933         main_first_pane  = main_pane_h1;
2934         main_second_pane = main_pane_h2;
2935         split_top_left = FALSE;
2936         break;
2937     default:
2938         main_first_pane = NULL;
2939         main_second_pane = NULL;
2940         split_top_left = FALSE;
2941         g_assert_not_reached();
2942     }
2943     if (split_top_left) {
2944         first_pane_widget1 = main_second_pane;
2945         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2946         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_2);
2947         first_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2948     } else {
2949         first_pane_widget1 = main_widget_layout(prefs.gui_layout_content_1);
2950         first_pane_widget2 = main_second_pane;
2951         second_pane_widget1 = main_widget_layout(prefs.gui_layout_content_2);
2952         second_pane_widget2 = main_widget_layout(prefs.gui_layout_content_3);
2953     }
2954     if (first_pane_widget1 != NULL)
2955         gtk_paned_add1(GTK_PANED(main_first_pane), first_pane_widget1);
2956     if (first_pane_widget2 != NULL)
2957         gtk_paned_add2(GTK_PANED(main_first_pane), first_pane_widget2);
2958     if (second_pane_widget1 != NULL)
2959         gtk_paned_pack1(GTK_PANED(main_second_pane), second_pane_widget1, TRUE, TRUE);
2960     if (second_pane_widget2 != NULL)
2961         gtk_paned_pack2(GTK_PANED(main_second_pane), second_pane_widget2, FALSE, FALSE);
2962
2963     gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
2964
2965     /* welcome pane */
2966     gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
2967
2968     /* statusbar hbox */
2969     gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2970
2971     /* filter toolbar in statusbar hbox */
2972     if (prefs.filter_toolbar_show_in_statusbar) {
2973         gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
2974     }
2975
2976     /* statusbar */
2977     gtk_box_pack_start(GTK_BOX(stat_hbox), status_pane, TRUE, TRUE, 0);
2978     gtk_paned_pack1(GTK_PANED(status_pane), info_bar, FALSE, FALSE);
2979     gtk_paned_pack2(GTK_PANED(status_pane), packets_bar, FALSE, FALSE);
2980
2981     /* hide widgets on users recent settings */
2982     main_widgets_show_or_hide();
2983
2984     gtk_widget_show(main_vbox);
2985 }
2986
2987 static void
2988 is_widget_visible(GtkWidget *widget, gpointer data)
2989 {
2990     gboolean *is_visible = data;
2991
2992     if (!*is_visible) {
2993         if (GTK_WIDGET_VISIBLE(widget))
2994             *is_visible = TRUE;
2995     }
2996 }
2997
2998
2999 #if 0
3000 /* XXX - There seems to be some disagreement about if and how this feature should be implemented.
3001    As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
3002 GtkWidget *
3003 welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
3004 {
3005     GtkWidget *w, *item_hb;
3006 #if GTK_MAJOR_VERSION >= 2
3007     gchar *formatted_message;
3008 #endif
3009
3010
3011     item_hb = gtk_hbox_new(FALSE, 1);
3012
3013     w = BUTTON_NEW_FROM_STOCK(stock_item);
3014     WIDGET_SET_SIZE(w, 60, 60);
3015 #if GTK_MAJOR_VERSION >= 2
3016     gtk_button_set_label(GTK_BUTTON(w), label);
3017 #endif
3018     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
3019     SIGNAL_CONNECT(w, "clicked", callback, callback_data);
3020
3021     w = gtk_label_new(message);
3022         gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3023 #if GTK_MAJOR_VERSION >= 2
3024     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
3025     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
3026     g_free(formatted_message);
3027 #endif
3028
3029     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
3030
3031     return item_hb;
3032 }
3033
3034
3035 /* XXX - the layout has to be improved */
3036 GtkWidget *
3037 welcome_new(void)
3038 {
3039     GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
3040     GtkWidget *w, *icon;
3041     gchar * message;
3042
3043
3044     welcome_scrollw = scrolled_window_new(NULL, NULL);
3045
3046     welcome_hb = gtk_hbox_new(FALSE, 1);
3047         /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
3048
3049     welcome_vb = gtk_vbox_new(FALSE, 1);
3050
3051     item_hb = gtk_hbox_new(FALSE, 1);
3052
3053     icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
3054     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
3055
3056 #if GTK_MAJOR_VERSION < 2
3057     message = "Welcome to Ethereal!";
3058 #else
3059     message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
3060 #endif
3061     w = gtk_label_new(message);
3062 #if GTK_MAJOR_VERSION >= 2
3063     gtk_label_set_markup(GTK_LABEL(w), message);
3064 #endif
3065     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
3066     gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
3067
3068     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3069
3070     w = gtk_label_new("What would you like to do?");
3071     gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
3072     gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
3073
3074 #ifdef HAVE_LIBPCAP
3075     item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START, 
3076         "Capture",
3077         "Capture live data from your network", 
3078         GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
3079     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3080 #endif
3081
3082     item_hb = welcome_item(GTK_STOCK_OPEN, 
3083         "Open",
3084         "Open a previously captured file",
3085         GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
3086     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3087
3088 #if (GLIB_MAJOR_VERSION >= 2)
3089     item_hb = welcome_item(GTK_STOCK_HOME, 
3090         "Home",
3091         "Visit the Ethereal homepage",
3092         GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
3093     gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
3094 #endif
3095
3096     /* the end */
3097     w = gtk_label_new("");
3098     gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
3099
3100     w = gtk_label_new("");
3101     gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3102
3103     gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
3104
3105     w = gtk_label_new("");
3106     gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
3107
3108     gtk_widget_show_all(welcome_hb);
3109
3110     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
3111                                           welcome_hb);
3112     gtk_widget_show_all(welcome_scrollw);
3113
3114     return welcome_scrollw;
3115 }
3116 #endif /* 0 */
3117
3118 static GtkWidget *
3119 welcome_new(void)
3120 {
3121     /* this is just a dummy to fill up window space, simply showing nothing */
3122     return scrolled_window_new(NULL, NULL);
3123 }
3124
3125
3126
3127 /*
3128  * XXX - this doesn't appear to work with the paned widgets in
3129  * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
3130  * and the other pane doesn't grow to take up the rest of the pane.
3131  * It does appear to work with GTK+ 2.x.
3132  */
3133 void
3134 main_widgets_show_or_hide(void)
3135 {
3136     gboolean main_second_pane_show;
3137
3138     if (recent.main_toolbar_show) {
3139         gtk_widget_show(main_tb);
3140     } else {
3141         gtk_widget_hide(main_tb);
3142     }
3143
3144     /*
3145      * Show the status hbox if either:
3146      *
3147      *    1) we're showing the filter toolbar and we want it in the status
3148      *       line
3149      *
3150      * or
3151      *
3152      *    2) we're showing the status bar.
3153      */
3154     if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
3155          recent.statusbar_show) {
3156         gtk_widget_show(stat_hbox);
3157     } else {
3158         gtk_widget_hide(stat_hbox);
3159     }
3160
3161     if (recent.statusbar_show) {
3162         gtk_widget_show(status_pane);
3163     } else {
3164         gtk_widget_hide(status_pane);
3165     }
3166
3167     if (recent.filter_toolbar_show) {
3168         gtk_widget_show(filter_tb);
3169     } else {
3170         gtk_widget_hide(filter_tb);
3171     }
3172
3173     if (recent.packet_list_show && have_capture_file) {
3174         gtk_widget_show(pkt_scrollw);
3175     } else {
3176         gtk_widget_hide(pkt_scrollw);
3177     }
3178
3179     if (recent.tree_view_show && have_capture_file) {
3180         gtk_widget_show(tv_scrollw);
3181     } else {
3182         gtk_widget_hide(tv_scrollw);
3183     }
3184
3185     if (recent.byte_view_show && have_capture_file) {
3186         gtk_widget_show(byte_nb_ptr);
3187     } else {
3188         gtk_widget_hide(byte_nb_ptr);
3189     }
3190
3191     if (have_capture_file) {
3192         gtk_widget_show(main_first_pane);
3193     } else {
3194         gtk_widget_hide(main_first_pane);
3195     }
3196
3197     /*
3198      * Is anything in "main_second_pane" visible?
3199      * If so, show it, otherwise hide it.
3200      */
3201     main_second_pane_show = FALSE;
3202     gtk_container_foreach(GTK_CONTAINER(main_second_pane), is_widget_visible,
3203                           &main_second_pane_show);
3204     if (main_second_pane_show) {
3205         gtk_widget_show(main_second_pane);
3206     } else {
3207         gtk_widget_hide(main_second_pane);
3208     }
3209
3210     if (!have_capture_file) {
3211         if(welcome_pane) {
3212             gtk_widget_show(welcome_pane);
3213         }
3214     } else {
3215         gtk_widget_hide(welcome_pane);
3216     }
3217 }
3218
3219
3220 #if GTK_MAJOR_VERSION >= 2
3221 /* called, when the window state changes (minimized, maximized, ...) */
3222 static int
3223 window_state_event_cb (GtkWidget *widget _U_,
3224                        GdkEvent *event,
3225                        gpointer  data _U_)
3226 {
3227     GdkWindowState new_window_state = ((GdkEventWindowState*)event)->new_window_state;
3228
3229     if( (event->type) == (GDK_WINDOW_STATE)) {
3230         if(!(new_window_state & GDK_WINDOW_STATE_ICONIFIED)) {
3231             /* we might have dialogs popped up while we where iconified,
3232                show em now */
3233             display_queued_messages();
3234         }
3235     }
3236     return FALSE;
3237 }
3238 #endif
3239
3240
3241 static void
3242 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
3243 {
3244     GtkWidget     
3245                   *filter_bt, *filter_cm, *filter_te,
3246                   *filter_add_expr_bt,
3247                   *filter_apply,
3248                   *filter_reset;
3249     GList         *dfilter_list = NULL;
3250     GtkTooltips   *tooltips;
3251     GtkAccelGroup *accel;
3252         gchar         *title;
3253     /* Display filter construct dialog has an Apply button, and "OK" not
3254        only sets our text widget, it activates it (i.e., it causes us to
3255        filter the capture). */
3256     static construct_args_t args = {
3257         "Ethereal: Display Filter",
3258         TRUE,
3259         TRUE
3260     };
3261
3262     /* use user-defined title if preference is set */
3263     title = create_user_window_title("The Ethereal Network Analyzer");
3264
3265     /* Main window */
3266     top_level = window_new(GTK_WINDOW_TOPLEVEL, title);
3267     g_free(title);
3268
3269     tooltips = gtk_tooltips_new();
3270
3271 #ifdef _WIN32 
3272 #if GTK_MAJOR_VERSION < 2
3273     /* has to be done, after top_level window is created */
3274     app_font_gtk1_init(top_level);
3275 #endif
3276 #endif
3277     
3278     gtk_widget_set_name(top_level, "main window");
3279     SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
3280                    NULL);
3281 #if GTK_MAJOR_VERSION >= 2
3282     SIGNAL_CONNECT(GTK_OBJECT(top_level), "window_state_event",
3283                          G_CALLBACK (window_state_event_cb), NULL);
3284 #endif
3285
3286     gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
3287
3288     /* Container for menu bar, toolbar(s), paned windows and progress/info box */
3289     main_vbox = gtk_vbox_new(FALSE, 1);
3290     gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
3291     gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
3292     gtk_widget_show(main_vbox);
3293
3294     /* Menu bar */
3295     menubar = main_menu_new(&accel);
3296     gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
3297     gtk_widget_show(menubar);
3298
3299     /* Main Toolbar */
3300     main_tb = toolbar_new();
3301     gtk_widget_show (main_tb);
3302
3303     /* Packet list */
3304     pkt_scrollw = packet_list_new(prefs);
3305     WIDGET_SET_SIZE(packet_list, -1, pl_size);
3306     gtk_widget_show(pkt_scrollw);
3307
3308     /* Tree view */
3309     tv_scrollw = main_tree_view_new(prefs, &tree_view);
3310     WIDGET_SET_SIZE(tv_scrollw, -1, tv_size);
3311     gtk_widget_show(tv_scrollw);
3312
3313 #if GTK_MAJOR_VERSION < 2
3314     SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
3315     SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
3316                    NULL);
3317 #else
3318     SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
3319                    "changed", tree_view_selection_changed_cb, NULL);
3320 #endif
3321     SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
3322                    OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
3323     gtk_widget_show(tree_view);
3324
3325     /* Byte view. */
3326     byte_nb_ptr = byte_view_new();
3327     WIDGET_SET_SIZE(byte_nb_ptr, -1, bv_size);
3328     gtk_widget_show(byte_nb_ptr);
3329
3330     SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
3331                    OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
3332
3333
3334     /* Panes for the packet list, tree, and byte view */
3335     main_pane_v1 = gtk_vpaned_new();
3336     gtk_widget_show(main_pane_v1);
3337     main_pane_v2 = gtk_vpaned_new();
3338     gtk_widget_show(main_pane_v2);
3339     main_pane_h1 = gtk_hpaned_new();
3340     gtk_widget_show(main_pane_h1);
3341     main_pane_h2 = gtk_hpaned_new();
3342     gtk_widget_show(main_pane_h2);
3343
3344     /* filter toolbar */
3345 #if GTK_MAJOR_VERSION < 2
3346     filter_tb = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,
3347                                GTK_TOOLBAR_BOTH);
3348 #else
3349     filter_tb = gtk_toolbar_new();
3350     gtk_toolbar_set_orientation(GTK_TOOLBAR(filter_tb),
3351                                 GTK_ORIENTATION_HORIZONTAL);
3352 #endif /* GTK_MAJOR_VERSION */
3353     gtk_widget_show(filter_tb);
3354
3355     /* Create the "Filter:" button */
3356     filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
3357     SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
3358     gtk_widget_show(filter_bt);
3359     OBJECT_SET_DATA(top_level, E_FILT_BT_PTR_KEY, filter_bt);
3360
3361     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_bt, 
3362         "Open the \"Display Filter\" dialog, to edit/apply filters", "Private");
3363
3364     /* Create the filter combobox */
3365     filter_cm = gtk_combo_new();
3366     dfilter_list = NULL;
3367     gtk_combo_disable_activate(GTK_COMBO(filter_cm));
3368     gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
3369     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, dfilter_list);
3370     filter_te = GTK_COMBO(filter_cm)->entry;
3371     main_display_filter_widget=filter_te;
3372     OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
3373     OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
3374     OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm);
3375     SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
3376     SIGNAL_CONNECT(filter_te, "changed", filter_te_syntax_check_cb, NULL);
3377     WIDGET_SET_SIZE(filter_cm, 400, -1);
3378     gtk_widget_show(filter_cm);
3379     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_cm, 
3380         NULL, NULL);
3381     /* setting a tooltip for a combobox will do nothing, so add it to the corresponding text entry */
3382     gtk_tooltips_set_tip(tooltips, filter_te, 
3383         "Enter a display filter, or choose one of your recently used filters. "
3384         "The background color of this field is changed by a continuous syntax check (green is valid, red is invalid).", 
3385         NULL);
3386
3387     /* Create the "Add Expression..." button, to pop up a dialog
3388        for constructing filter comparison expressions. */
3389     filter_add_expr_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_ADD_EXPRESSION);
3390     OBJECT_SET_DATA(filter_tb, E_FILT_FILTER_TE_KEY, filter_te);
3391     SIGNAL_CONNECT(filter_add_expr_bt, "clicked", filter_add_expr_bt_cb, filter_tb);
3392     gtk_widget_show(filter_add_expr_bt);
3393     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_add_expr_bt, 
3394         "Add an expression to this filter string", "Private");
3395
3396     /* Create the "Clear" button */
3397     filter_reset = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLEAR);
3398     OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
3399     SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
3400     gtk_widget_show(filter_reset);
3401     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_reset, 
3402         "Clear this filter string and update the display", "Private");
3403
3404     /* Create the "Apply" button */
3405     filter_apply = BUTTON_NEW_FROM_STOCK(GTK_STOCK_APPLY);
3406     OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
3407     SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
3408     gtk_widget_show(filter_apply);
3409     gtk_toolbar_append_widget(GTK_TOOLBAR(filter_tb), filter_apply, 
3410         "Apply this filter string to the display", "Private");
3411
3412     /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
3413      * of any widget that ends up calling a callback which needs
3414      * that text entry pointer */
3415     set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
3416     set_menu_object_data("/Analyze/Display Filters...", E_FILT_TE_PTR_KEY,
3417                          filter_te);
3418     set_menu_object_data("/Analyze/Follow TCP Stream", E_DFILTER_TE_KEY,
3419                          filter_te);
3420     set_menu_object_data("/Analyze/Apply as Filter/Selected", E_DFILTER_TE_KEY,
3421                          filter_te);
3422     set_menu_object_data("/Analyze/Apply as Filter/Not Selected", E_DFILTER_TE_KEY,
3423                          filter_te);
3424     set_menu_object_data("/Analyze/Apply as Filter/... and Selected", E_DFILTER_TE_KEY,
3425                          filter_te);
3426     set_menu_object_data("/Analyze/Apply as Filter/... or Selected", E_DFILTER_TE_KEY,
3427                          filter_te);
3428     set_menu_object_data("/Analyze/Apply as Filter/... and not Selected", E_DFILTER_TE_KEY,
3429                          filter_te);
3430     set_menu_object_data("/Analyze/Apply as Filter/... or not Selected", E_DFILTER_TE_KEY,
3431                          filter_te);
3432     set_menu_object_data("/Analyze/Prepare a Filter/Selected", E_DFILTER_TE_KEY,
3433                          filter_te);
3434     set_menu_object_data("/Analyze/Prepare a Filter/Not Selected", E_DFILTER_TE_KEY,
3435                          filter_te);
3436     set_menu_object_data("/Analyze/Prepare a Filter/... and Selected", E_DFILTER_TE_KEY,
3437                          filter_te);
3438     set_menu_object_data("/Analyze/Prepare a Filter/... or Selected", E_DFILTER_TE_KEY,
3439                          filter_te);
3440     set_menu_object_data("/Analyze/Prepare a Filter/... and not Selected", E_DFILTER_TE_KEY,
3441                          filter_te);
3442     set_menu_object_data("/Analyze/Prepare a Filter/... or not Selected", E_DFILTER_TE_KEY,
3443                          filter_te);
3444     set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
3445     OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
3446     OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
3447
3448     /* info (main) statusbar */
3449     info_bar = info_bar_new();
3450     gtk_widget_show(info_bar);
3451
3452     /* packets statusbar */
3453     packets_bar = packets_bar_new();
3454     gtk_widget_show(packets_bar);
3455
3456     /* Filter/status hbox */
3457     stat_hbox = gtk_hbox_new(FALSE, 1);
3458     gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
3459     gtk_widget_show(stat_hbox);
3460
3461     /* Pane for the statusbar */
3462     status_pane = gtk_hpaned_new();
3463     gtk_widget_show(status_pane);
3464
3465     /* Pane for the welcome screen */
3466     welcome_pane = welcome_new();
3467     gtk_widget_show(welcome_pane);
3468 }
3469
3470 static void
3471 show_main_window(gboolean doing_work)
3472 {
3473   main_set_for_capture_file(doing_work);
3474
3475   /*** we have finished all init things, show the main window ***/
3476   gtk_widget_show(top_level);
3477
3478   /* the window can be maximized only, if it's visible, so do it after show! */
3479   main_load_window_geometry(top_level);
3480
3481   /* process all pending GUI events before continue */
3482   while (gtk_events_pending()) gtk_main_iteration();
3483
3484   /* Pop up any queued-up alert boxes. */
3485   display_queued_messages();
3486 }