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