Redesigned the menu structure of the former statistics stuff,
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.404 2004/02/22 18:44:02 ulfl Exp $
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@ethereal.com>
7  * Copyright 1998 Gerald Combs
8  *
9  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10  *                              needed by dissect routines
11  * Jeff Foster,    2001/03/12,  added support tabbed hex display windowss
12  *
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  *
28  *
29  * To do:
30  * - Graphs
31  * - Playback window
32  * - Multiple window support
33  * - Add cut/copy/paste
34  * - Create header parsing routines
35  * - Make byte view selections more fancy?
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #ifdef HAVE_LIBPCAP
43 #include <pcap.h>
44 #endif
45
46 #include <gtk/gtk.h>
47
48 #include <string.h>
49 #include <ctype.h>
50
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54
55 #ifdef HAVE_IO_H
56 #include <io.h> /* open/close on win32 */
57 #endif
58
59 #ifdef NEED_SNPRINTF_H
60 # include "snprintf.h"
61 #endif
62
63 #ifdef NEED_STRERROR_H
64 #include "strerror.h"
65 #endif
66
67 #ifdef NEED_GETOPT_H
68 #include "getopt.h"
69 #endif
70
71 #ifdef WIN32 /* Needed for console I/O */
72 #include <fcntl.h>
73 #include <conio.h>
74 #endif
75
76 #include <epan/epan.h>
77 #include <epan/filesystem.h>
78 #include <epan/epan_dissect.h>
79
80 #include "cvsversion.h"
81 #include "main.h"
82 #include <epan/timestamp.h>
83 #include <epan/packet.h>
84 #include "capture.h"
85 #include "summary.h"
86 #include "file.h"
87 #include "filters.h"
88 #include "disabled_protos.h"
89 #include "prefs.h"
90 #include "menu.h"
91 #include "../menu.h"
92 #include "color.h"
93 #include "color_filters.h"
94 #include "color_utils.h"
95 #include "filter_prefs.h"
96 #include "file_dlg.h"
97 #include "column.h"
98 #include "print.h"
99 #include <epan/resolv.h>
100 #ifdef HAVE_LIBPCAP
101 #include "pcap-util.h"
102 #endif
103 #include "statusbar.h"
104 #include "alert_box.h"
105 #include "simple_dialog.h"
106 #include "dlg_utils.h"
107 #include "proto_draw.h"
108 #include <epan/dfilter/dfilter.h>
109 #include "keys.h"
110 #include "packet_win.h"
111 #include "gtkglobals.h"
112 #include <epan/plugins.h>
113 #include "colors.h"
114 #include <epan/strutil.h>
115 #include "register.h"
116 #include <prefs-int.h>
117 #include "ringbuffer.h"
118 #include "../ui_util.h"
119 #include "ui_util.h"
120 #include "toolbar.h"
121 #include "../tap.h"
122 #include "../util.h"
123 #include "../version_info.h"
124 #include "compat_macros.h"
125 #include "find_dlg.h"
126 #include "packet_list.h"
127 #include "recent.h"
128 #include "follow_dlg.h"
129
130 #ifdef WIN32
131 #include "capture-wpcap.h"
132 #endif
133
134 capture_file cfile;
135 GtkWidget   *main_display_filter_widget=NULL;
136 GtkWidget   *top_level = NULL, *tree_view, *byte_nb_ptr, *tv_scrollw;
137 GtkWidget   *upper_pane, *lower_pane;
138 GtkWidget   *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
139 static GtkWidget        *info_bar;
140 static GtkWidget    *packets_bar = NULL;
141 #if GTK_MAJOR_VERSION < 2
142 GdkFont     *m_r_font, *m_b_font;
143 guint        m_font_height, m_font_width;
144 #else
145 PangoFontDescription *m_r_font, *m_b_font;
146 #endif
147 static guint    main_ctx, file_ctx, help_ctx;
148 static guint        packets_ctx;
149 static gchar        *packets_str = NULL;
150 static GString *comp_info_str, *runtime_info_str;
151 gchar       *ethereal_path = NULL;
152 gchar       *last_open_dir = NULL;
153 static gboolean updated_last_open_dir = FALSE;
154
155 /* init with an invalid value, so that "recent" can detect this and */
156 /* distinguish it from a command line value */
157 ts_type timestamp_type = TS_NOT_SET;
158
159 #if GTK_MAJOR_VERSION < 2
160 GtkStyle *item_style;
161 #endif
162
163 #ifdef WIN32
164 static gboolean has_no_console; /* TRUE if app has no console */
165 static gboolean console_was_created; /* TRUE if console was created */
166 static void create_console(void);
167 static void destroy_console(void);
168 static void console_log_handler(const char *log_domain,
169     GLogLevelFlags log_level, const char *message, gpointer user_data);
170 #endif
171
172 #ifdef HAVE_LIBPCAP
173 static gboolean list_link_layer_types;
174 #endif
175
176 static void about_ethereal_destroy_cb(GtkWidget *, gpointer);
177 static void create_main_window(gint, gint, gint, e_prefs*);
178 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_);
179 static void main_save_window_geometry(GtkWidget *widget);
180 #ifdef WIN32
181 #if GTK_MAJOR_VERSION >= 2
182 static void try_to_get_windows_font_gtk2 (void);
183 #endif
184 #endif
185
186 #define E_DFILTER_CM_KEY          "display_filter_combo"
187 #define E_DFILTER_FL_KEY          "display_filter_list"
188
189 /* About Ethereal window */
190 #define MAX_ABOUT_MSG_LEN 2048
191
192 /*
193  * Keep a static pointer to the current "About Ethereal" window, if any, so
194  * that if somebody tries to do "About Ethereal" while there's already an
195  * "About Ethereal" window up, we just pop up the existing one, rather than
196  * creating a new one.
197  */
198 static GtkWidget *about_ethereal_w;
199
200 void
201 about_ethereal( GtkWidget *w _U_, gpointer data _U_ )
202 {
203   GtkWidget   *main_vb, *top_hb, *msg_label, *bbox, *ok_btn;
204   gchar        message[MAX_ABOUT_MSG_LEN];
205
206   if (about_ethereal_w != NULL) {
207     /* There's already an "About Ethereal" dialog box; reactivate it. */
208     reactivate_window(about_ethereal_w);
209     return;
210   }
211
212   /*
213    * XXX - use GtkDialog?  The GNOME 2.x GnomeAbout widget does.
214    * Should we use GtkDialog for simple_dialog() as well?  Or
215    * is the GTK+ 2.x GtkDialog appropriate but the 1.2[.x] one
216    * not?  (The GNOME 1.x GnomeAbout widget uses GnomeDialog.)
217    */
218   about_ethereal_w = dlg_window_new("About Ethereal");
219   SIGNAL_CONNECT(about_ethereal_w, "destroy", about_ethereal_destroy_cb, NULL);
220   gtk_container_border_width(GTK_CONTAINER(about_ethereal_w), 7);
221
222   /* Container for our rows */
223   main_vb = gtk_vbox_new(FALSE, 5);
224   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
225   gtk_container_add(GTK_CONTAINER(about_ethereal_w), main_vb);
226   gtk_widget_show(main_vb);
227
228   /* Top row: Message text */
229   top_hb = gtk_hbox_new(FALSE, 10);
230   gtk_container_add(GTK_CONTAINER(main_vb), top_hb);
231   gtk_widget_show(top_hb);
232
233   /* Construct the message string */
234   snprintf(message, MAX_ABOUT_MSG_LEN,
235            "Ethereal - Network Protocol Analyzer\n\n"
236            
237            "Version " VERSION
238 #ifdef CVSVERSION
239            " (" CVSVERSION ")"
240 #endif
241            " (C) 1998-2004 Gerald Combs <gerald@ethereal.com>\n\n"
242
243        "%s\n"
244        "%s\n\n"
245
246        "Ethereal is Open Source software released under the GNU General Public License.\n\n"
247
248            "Check the man page for complete documentation and\n"
249            "for the list of contributors.\n\n"
250
251            "See http://www.ethereal.com for more information.",
252             comp_info_str->str, runtime_info_str->str);
253
254   msg_label = gtk_label_new(message);
255   gtk_label_set_justify(GTK_LABEL(msg_label), GTK_JUSTIFY_FILL);
256   gtk_container_add(GTK_CONTAINER(top_hb), msg_label);
257   gtk_widget_show(msg_label);
258
259   /* Button row */
260   bbox = dlg_button_row_new(GTK_STOCK_OK, NULL);
261   gtk_container_add(GTK_CONTAINER(main_vb), bbox);
262   gtk_widget_show(bbox);
263
264   ok_btn = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
265   SIGNAL_CONNECT_OBJECT(ok_btn, "clicked", gtk_widget_destroy,
266                         about_ethereal_w);
267   gtk_widget_grab_default(ok_btn);
268
269   /* Catch the "key_press_event" signal in the window, so that we can catch
270      the ESC key being pressed and act as if the "Cancel" button had
271      been selected. */
272   dlg_set_cancel(about_ethereal_w, ok_btn);
273
274   gtk_widget_show(about_ethereal_w);
275 }
276
277 static void
278 about_ethereal_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
279 {
280   /* Note that we no longer have an "About Ethereal" dialog box. */
281   about_ethereal_w = NULL;
282 }
283
284 #if GTK_MAJOR_VERSION < 2
285 void
286 set_fonts(GdkFont *regular, GdkFont *bold)
287 #else
288 void
289 set_fonts(PangoFontDescription *regular, PangoFontDescription *bold)
290 #endif
291 {
292         /* Yes, assert. The code that loads the font should check
293          * for NULL and provide its own error message. */
294         g_assert(m_r_font && m_b_font);
295         m_r_font = regular;
296         m_b_font = bold;
297
298 #if GTK_MAJOR_VERSION < 2
299         m_font_height = m_r_font->ascent + m_r_font->descent;
300         m_font_width = gdk_string_width(m_r_font, "0");
301 #endif
302 }
303
304 /*
305  * Go to frame specified by currently selected protocol tree item.
306  */
307 void
308 goto_framenum_cb(GtkWidget *w _U_, gpointer data _U_)
309 {
310     if (cfile.finfo_selected) {
311         header_field_info       *hfinfo;
312         guint32                 framenum;
313
314         hfinfo = cfile.finfo_selected->hfinfo;
315         g_assert(hfinfo);
316         if (hfinfo->type == FT_FRAMENUM) {
317             framenum = fvalue_get_integer(&cfile.finfo_selected->value);
318             if (framenum != 0)
319                 goto_frame(&cfile, framenum);
320         }
321     }
322 }
323
324 void
325 goto_top_frame_cb(GtkWidget *w _U_, gpointer d _U_)
326 {
327     goto_top_frame(&cfile);
328 }
329
330 void
331 goto_bottom_frame_cb(GtkWidget *w _U_, gpointer d _U_)
332 {
333     goto_bottom_frame(&cfile);
334 }
335
336
337 void
338 view_zoom_in_cb(GtkWidget *w _U_, gpointer d _U_)
339 {
340     gint save_gui_zoom_level;
341
342     save_gui_zoom_level = recent.gui_zoom_level;
343     recent.gui_zoom_level++;
344     switch (font_apply()) {
345
346     case FA_SUCCESS:
347         break;
348
349     case FA_FONT_NOT_RESIZEABLE:
350         /* "font_apply()" popped up an alert box. */
351         recent.gui_zoom_level = save_gui_zoom_level;    /* undo zoom */
352         break;
353
354     case FA_FONT_NOT_AVAILABLE:
355         /* We assume this means that the specified size isn't available. */
356         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
357             "Your current font isn't available in the next larger size.\n");
358         recent.gui_zoom_level = save_gui_zoom_level;    /* undo zoom */
359         break;
360     }
361 }
362
363 void
364 view_zoom_out_cb(GtkWidget *w _U_, gpointer d _U_)
365 {
366     gint save_gui_zoom_level;
367
368     save_gui_zoom_level = recent.gui_zoom_level;
369     recent.gui_zoom_level--;
370     switch (font_apply()) {
371
372     case FA_SUCCESS:
373         break;
374
375     case FA_FONT_NOT_RESIZEABLE:
376         /* "font_apply()" popped up an alert box. */
377         recent.gui_zoom_level = save_gui_zoom_level;    /* undo zoom */
378         break;
379
380     case FA_FONT_NOT_AVAILABLE:
381         /* We assume this means that the specified size isn't available. */
382         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
383             "Your current font isn't available in the next smaller size.\n");
384         recent.gui_zoom_level = save_gui_zoom_level;    /* undo zoom */
385         break;
386     }
387 }
388
389 void
390 view_zoom_100_cb(GtkWidget *w _U_, gpointer d _U_)
391 {
392     gint save_gui_zoom_level;
393
394     save_gui_zoom_level = recent.gui_zoom_level;
395     recent.gui_zoom_level = 0;
396     switch (font_apply()) {
397
398     case FA_SUCCESS:
399         break;
400
401     case FA_FONT_NOT_RESIZEABLE:
402         /* "font_apply()" popped up an alert box. */
403         recent.gui_zoom_level = save_gui_zoom_level;    /* undo zoom */
404         break;
405
406     case FA_FONT_NOT_AVAILABLE:
407         /* We assume this means that the specified size isn't available.
408            XXX - this "shouldn't happen". */
409         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
410             "Your current font couldn't be reloaded at the size you selected.\n");
411         recent.gui_zoom_level = save_gui_zoom_level;    /* undo zoom */
412         break;
413     }
414 }
415
416
417 /* Match selected byte pattern */
418 static void
419 match_selected_cb_do(gpointer data, int action, gchar *text)
420 {
421     GtkWidget           *filter_te;
422     char                *cur_filter, *new_filter;
423
424     if (!text)
425         return;
426     g_assert(data);
427     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
428     g_assert(filter_te);
429
430     cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
431
432     switch (action&MATCH_SELECTED_MASK) {
433
434     case MATCH_SELECTED_REPLACE:
435         new_filter = g_strdup(text);
436         break;
437
438     case MATCH_SELECTED_AND:
439         if ((!cur_filter) || (0 == strlen(cur_filter)))
440             new_filter = g_strdup(text);
441         else
442             new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
443         break;
444
445     case MATCH_SELECTED_OR:
446         if ((!cur_filter) || (0 == strlen(cur_filter)))
447             new_filter = g_strdup(text);
448         else
449             new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
450         break;
451
452     case MATCH_SELECTED_NOT:
453         new_filter = g_strconcat("!(", text, ")", NULL);
454         break;
455
456     case MATCH_SELECTED_AND_NOT:
457         if ((!cur_filter) || (0 == strlen(cur_filter)))
458             new_filter = g_strconcat("!(", text, ")", NULL);
459         else
460             new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
461         break;
462
463     case MATCH_SELECTED_OR_NOT:
464         if ((!cur_filter) || (0 == strlen(cur_filter)))
465             new_filter = g_strconcat("!(", text, ")", NULL);
466         else
467             new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
468         break;
469
470     default:
471         g_assert_not_reached();
472         new_filter = NULL;
473         break;
474     }
475
476     /* Free up the copy we got of the old filter text. */
477     g_free(cur_filter);
478
479     /* create a new one and set the display filter entry accordingly */
480     gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
481
482     /* Run the display filter so it goes in effect. */
483     if (action&MATCH_SELECTED_APPLY_NOW)
484         main_filter_packets(&cfile, new_filter);
485
486     /* Free up the new filter text. */
487     g_free(new_filter);
488
489     /* Free up the generated text we were handed. */
490     g_free(text);
491 }
492
493 void
494 match_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
495 {
496     if (cfile.finfo_selected)
497         match_selected_cb_do((data ? data : w),
498             MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
499             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
500 }
501
502 void
503 match_selected_cb_and_ptree(GtkWidget *w, gpointer data)
504 {
505     if (cfile.finfo_selected)
506         match_selected_cb_do((data ? data : w),
507             MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
508             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
509 }
510
511 void
512 match_selected_cb_or_ptree(GtkWidget *w, gpointer data)
513 {
514     if (cfile.finfo_selected)
515         match_selected_cb_do((data ? data : w),
516             MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
517             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
518 }
519
520 void
521 match_selected_cb_not_ptree(GtkWidget *w, gpointer data)
522 {
523     if (cfile.finfo_selected)
524         match_selected_cb_do((data ? data : w),
525             MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
526             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
527 }
528
529 void
530 match_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
531 {
532     if (cfile.finfo_selected)
533         match_selected_cb_do((data ? data : w),
534             MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
535             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
536 }
537
538 void
539 match_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
540 {
541     if (cfile.finfo_selected)
542         match_selected_cb_do((data ? data : w),
543             MATCH_SELECTED_OR_NOT,
544             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
545 }
546
547 void
548 prepare_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
549 {
550     if (cfile.finfo_selected)
551         match_selected_cb_do((data ? data : w),
552             MATCH_SELECTED_REPLACE,
553             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
554 }
555
556 void
557 prepare_selected_cb_and_ptree(GtkWidget *w, gpointer data)
558 {
559     if (cfile.finfo_selected)
560         match_selected_cb_do((data ? data : w),
561             MATCH_SELECTED_AND,
562             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
563 }
564
565 void
566 prepare_selected_cb_or_ptree(GtkWidget *w, gpointer data)
567 {
568     if (cfile.finfo_selected)
569         match_selected_cb_do((data ? data : w),
570             MATCH_SELECTED_OR,
571             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
572 }
573
574 void
575 prepare_selected_cb_not_ptree(GtkWidget *w, gpointer data)
576 {
577     if (cfile.finfo_selected)
578         match_selected_cb_do((data ? data : w),
579             MATCH_SELECTED_NOT,
580             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
581 }
582
583 void
584 prepare_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
585 {
586     if (cfile.finfo_selected)
587         match_selected_cb_do((data ? data : w),
588             MATCH_SELECTED_AND_NOT,
589             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
590 }
591
592 void
593 prepare_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
594 {
595     if (cfile.finfo_selected)
596         match_selected_cb_do((data ? data : w),
597             MATCH_SELECTED_OR_NOT,
598             proto_construct_dfilter_string(cfile.finfo_selected, cfile.edt));
599 }
600
601 static gchar *
602 get_text_from_packet_list(gpointer data)
603 {
604     gint        row = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY));
605     gint        column = GPOINTER_TO_INT(OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY));
606     frame_data *fdata = (frame_data *)packet_list_get_row_data(row);
607     epan_dissect_t *edt;
608     gchar      *buf=NULL;
609     int         len;
610     int         err;
611     gchar       *err_info;
612
613     if (fdata != NULL) {
614         if (!wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
615                        cfile.pd, fdata->cap_len, &err, &err_info)) {
616             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
617                           cf_read_error_message(err, err_info), cfile.filename);
618             return NULL;
619         }
620
621         edt = epan_dissect_new(FALSE, FALSE);
622         epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
623                          &cfile.cinfo);
624         epan_dissect_fill_in_columns(edt);
625
626         if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
627             strlen(cfile.cinfo.col_expr_val[column]) != 0) {
628             len = strlen(cfile.cinfo.col_expr[column]) +
629                   strlen(cfile.cinfo.col_expr_val[column]) + 5;
630             buf = g_malloc0(len);
631             snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
632                      cfile.cinfo.col_expr_val[column]);
633         }
634
635         epan_dissect_free(edt);
636     }
637
638     return buf;
639 }
640
641 void
642 match_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
643 {
644     match_selected_cb_do(data,
645         MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
646         get_text_from_packet_list(data));
647 }
648
649 void
650 match_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
651 {
652     match_selected_cb_do(data,
653         MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
654         get_text_from_packet_list(data));
655 }
656
657 void
658 match_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
659 {
660     match_selected_cb_do(data,
661         MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
662         get_text_from_packet_list(data));
663 }
664
665 void
666 match_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
667 {
668     match_selected_cb_do(data,
669         MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
670         get_text_from_packet_list(data));
671 }
672
673 void
674 match_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
675 {
676     match_selected_cb_do(data,
677         MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
678         get_text_from_packet_list(data));
679 }
680
681 void
682 match_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
683 {
684     match_selected_cb_do(data,
685         MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
686         get_text_from_packet_list(data));
687 }
688
689 void
690 prepare_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
691 {
692     match_selected_cb_do(data,
693         MATCH_SELECTED_REPLACE,
694         get_text_from_packet_list(data));
695 }
696
697 void
698 prepare_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
699 {
700     match_selected_cb_do(data,
701         MATCH_SELECTED_AND,
702         get_text_from_packet_list(data));
703 }
704
705 void
706 prepare_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
707 {
708     match_selected_cb_do(data,
709         MATCH_SELECTED_OR,
710         get_text_from_packet_list(data));
711 }
712
713 void
714 prepare_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
715 {
716     match_selected_cb_do(data,
717         MATCH_SELECTED_NOT,
718         get_text_from_packet_list(data));
719 }
720
721 void
722 prepare_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
723 {
724     match_selected_cb_do(data,
725         MATCH_SELECTED_AND_NOT,
726         get_text_from_packet_list(data));
727 }
728
729 void
730 prepare_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
731 {
732     match_selected_cb_do(data,
733         MATCH_SELECTED_OR_NOT,
734         get_text_from_packet_list(data));
735 }
736
737
738 /* XXX: use a preference for this setting! */
739 static guint dfilter_combo_max_recent = 10;
740
741 /* add a display filter to the combo box */
742 /* Note: a new filter string will replace an old identical one */
743 static gboolean
744 dfilter_combo_add(GtkWidget *filter_cm, char *s) {
745   GList     *li;
746   GList     *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
747
748
749   /* GtkCombos don't let us get at their list contents easily, so we maintain
750      our own filter list, and feed it to gtk_combo_set_popdown_strings when
751      a new filter is added. */
752     li = g_list_first(filter_list);
753     while (li) {
754         /* If the filter is already in the list, remove the old one and 
755                  * append the new one at the latest position (at g_list_append() below) */
756                 if (li->data && strcmp(s, li->data) == 0) {
757           filter_list = g_list_remove(filter_list, li->data);
758                   break;
759                 }
760       li = li->next;
761     }
762
763     filter_list = g_list_append(filter_list, s);
764     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
765     gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
766     gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data);
767
768     return TRUE;
769 }
770
771
772 /* write all non empty display filters (until maximum count) 
773  * of the combo box GList to the user's recent file */
774 void
775 dfilter_recent_combo_write_all(FILE *rf) {
776   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
777   GList     *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
778   GList     *li;
779   guint      max_count = 0;
780
781
782   /* write all non empty display filter strings to the recent file (until max count) */
783   li = g_list_first(filter_list);
784   while ( li && (max_count++ <= dfilter_combo_max_recent) ) {
785     if (strlen(li->data)) {
786       fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", (char *)li->data);
787     }
788     li = li->next;
789   }
790 }
791
792 /* empty the combobox entry field */
793 void
794 dfilter_combo_add_empty(void) {
795   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
796
797   gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), "");
798 }
799
800
801 /* add a display filter coming from the user's recent file to the dfilter combo box */
802 gboolean
803 dfilter_combo_add_recent(gchar *s) {
804   GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
805   char      *dup;
806
807   dup = g_strdup(s);
808   if (!dfilter_combo_add(filter_cm, dup)) {
809     g_free(dup);
810     return FALSE;
811   }
812
813   return TRUE;
814 }
815
816
817 /* call filter_packets() and add this filter string to the recent filter list */
818 int
819 main_filter_packets(capture_file *cf, const gchar *dftext)
820 {
821   GtkCombo  *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY);
822   GList     *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
823   GList     *li;
824   gboolean   add_filter = TRUE;
825   gboolean   free_filter = TRUE;
826   char      *s;
827   int       filter_packets_ret;
828
829
830   s = g_strdup(dftext);
831
832   /* GtkCombos don't let us get at their list contents easily, so we maintain
833      our own filter list, and feed it to gtk_combo_set_popdown_strings when
834      a new filter is added. */
835   if ((filter_packets_ret = filter_packets(cf, s))) {
836     li = g_list_first(filter_list);
837     while (li) {
838       if (li->data && strcmp(s, li->data) == 0)
839         add_filter = FALSE;
840       li = li->next;
841     }
842
843     if (add_filter) {
844       /* trim list size first */
845       while (g_list_length(filter_list) >= dfilter_combo_max_recent) {
846         filter_list = g_list_remove(filter_list, g_list_first(filter_list)->data);
847       }
848
849       free_filter = FALSE;
850       filter_list = g_list_append(filter_list, s);
851       OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
852       gtk_combo_set_popdown_strings(filter_cm, filter_list);
853       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
854     }
855   }
856   if (free_filter)
857     g_free(s);
858
859   return filter_packets_ret;
860 }
861
862
863 /* Run the current display filter on the current packet set, and
864    redisplay. */
865 static void
866 filter_activate_cb(GtkWidget *w _U_, gpointer data)
867 {
868   const char *s;
869
870   s = gtk_entry_get_text(GTK_ENTRY(data));
871
872   main_filter_packets(&cfile, s);
873 }
874
875 /* redisplay with no display filter */
876 static void
877 filter_reset_cb(GtkWidget *w, gpointer data _U_)
878 {
879   GtkWidget *filter_te = NULL;
880
881   if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
882     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
883   }
884   main_filter_packets(&cfile, "");
885 }
886
887 /* mark as reference time frame */
888 static void
889 set_frame_reftime(gboolean set, frame_data *frame, gint row) {
890   if (row == -1)
891     return;
892   if (set) {
893     frame->flags.ref_time=1;
894   } else {
895     frame->flags.ref_time=0;
896   }
897   reftime_packets(&cfile);
898 }
899
900 /* 0: toggle ref time status for the selected frame 
901  * 1: find next ref time frame
902  * 2: find previous reftime frame
903  */
904 void 
905 reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, guint action)
906 {
907
908   switch(action){
909   case 0: /* toggle ref frame */
910     if (cfile.current_frame) {
911       /* XXX hum, should better have a "cfile->current_row" here ... */
912       set_frame_reftime(!cfile.current_frame->flags.ref_time,
913                      cfile.current_frame,
914                      packet_list_find_row_from_data(cfile.current_frame));
915     }
916     break;
917   case 1: /* find next ref frame */
918     find_previous_next_frame_with_filter("frame.ref_time", FALSE);
919     break;
920   case 2: /* find previous ref frame */
921     find_previous_next_frame_with_filter("frame.ref_time", TRUE);
922     break;
923   }
924 }
925
926 #if GTK_MAJOR_VERSION < 2
927 static void
928 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
929                         gpointer user_data _U_)
930 #else
931 static void
932 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
933 #endif
934 {
935     field_info   *finfo;
936     gchar        *help_str = NULL;
937     gchar         len_str[2+10+1+5+1]; /* ", {N} bytes\0",
938                                           N < 4294967296 */
939     gboolean      has_blurb = FALSE;
940     guint         length = 0, byte_len;
941     GtkWidget    *byte_view;
942     const guint8 *byte_data;
943 #if GTK_MAJOR_VERSION >= 2
944     GtkTreeModel *model;
945     GtkTreeIter   iter;
946 #endif
947
948 #if GTK_MAJOR_VERSION >= 2
949     /* if nothing is selected */
950     if (!gtk_tree_selection_get_selected(sel, &model, &iter))
951     {
952         /*
953          * Which byte view is displaying the current protocol tree
954          * row's data?
955          */
956         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
957         if (byte_view == NULL)
958             return;     /* none */
959
960         byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
961         if (byte_data == NULL)
962             return;     /* none */
963
964         unselect_field(&cfile);
965         packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
966                          cfile.current_frame, NULL, byte_len);
967         return;
968     }
969     gtk_tree_model_get(model, &iter, 1, &finfo, -1);
970 #else
971     g_assert(node);
972     finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
973 #endif
974     if (!finfo) return;
975
976     set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
977
978     byte_view = get_notebook_bv_ptr(byte_nb_ptr);
979     byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
980     g_assert(byte_data != NULL);
981
982     cfile.finfo_selected = finfo;
983     set_menus_for_selected_tree_row(&cfile);
984
985     if (finfo->hfinfo) {
986         if (finfo->hfinfo->blurb != NULL &&
987             finfo->hfinfo->blurb[0] != '\0') {
988             has_blurb = TRUE;
989             length = strlen(finfo->hfinfo->blurb);
990         } else {
991             length = strlen(finfo->hfinfo->name);
992         }
993         if (finfo->length == 0) {
994             len_str[0] = '\0';
995         } else if (finfo->length == 1) {
996             strcpy (len_str, ", 1 byte");
997         } else {
998             snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
999         }
1000         statusbar_pop_field_msg();      /* get rid of current help msg */
1001         if (length) {
1002             length += strlen(finfo->hfinfo->abbrev) + strlen(len_str) + 10;
1003             help_str = g_malloc(sizeof(gchar) * length);
1004             sprintf(help_str, "%s (%s)%s",
1005                     (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
1006                     finfo->hfinfo->abbrev, len_str);
1007             statusbar_push_field_msg(help_str);
1008             g_free(help_str);
1009         } else {
1010             /*
1011              * Don't show anything if the field name is zero-length;
1012              * the pseudo-field for "proto_tree_add_text()" is such
1013              * a field, and we don't want "Text (text)" showing up
1014              * on the status line if you've selected such a field.
1015              *
1016              * XXX - there are zero-length fields for which we *do*
1017              * want to show the field name.
1018              *
1019              * XXX - perhaps the name and abbrev field should be null
1020              * pointers rather than null strings for that pseudo-field,
1021              * but we'd have to add checks for null pointers in some
1022              * places if we did that.
1023              *
1024              * Or perhaps protocol tree items added with
1025              * "proto_tree_add_text()" should have -1 as the field index,
1026              * with no pseudo-field being used, but that might also
1027              * require special checks for -1 to be added.
1028              */
1029             statusbar_push_field_msg("");
1030         }
1031     }
1032
1033 #if GTK_MAJOR_VERSION < 2
1034     packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
1035                      finfo, byte_len);
1036 #else
1037     packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
1038                      finfo, byte_len);
1039 #endif
1040 }
1041
1042 #if GTK_MAJOR_VERSION < 2
1043 static void
1044 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
1045                           gpointer user_data _U_)
1046 {
1047         GtkWidget       *byte_view;
1048         const guint8    *data;
1049         guint           len;
1050
1051         /*
1052          * Which byte view is displaying the current protocol tree
1053          * row's data?
1054          */
1055         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
1056         if (byte_view == NULL)
1057                 return; /* none */
1058
1059         data = get_byte_view_data_and_length(byte_view, &len);
1060         if (data == NULL)
1061                 return; /* none */
1062
1063         unselect_field(&cfile);
1064         packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
1065                 NULL, len);
1066 }
1067 #endif
1068
1069 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
1070   if (cfile.edt->tree)
1071     collapse_all_tree(cfile.edt->tree, tree_view);
1072 }
1073
1074 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
1075   if (cfile.edt->tree)
1076     expand_all_tree(cfile.edt->tree, tree_view);
1077 }
1078
1079 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
1080   if (cfile.edt->tree) {
1081     guint32 tmp = g_resolv_flags;
1082     g_resolv_flags = RESOLV_ALL;
1083     proto_tree_draw(cfile.edt->tree, tree_view);
1084     g_resolv_flags = tmp;
1085   }
1086 }
1087
1088 /*
1089  * Push a message referring to file access onto the statusbar.
1090  */
1091 void
1092 statusbar_push_file_msg(gchar *msg)
1093 {
1094         gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
1095 }
1096
1097 /*
1098  * Pop a message referring to file access off the statusbar.
1099  */
1100 void
1101 statusbar_pop_file_msg(void)
1102 {
1103         gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1104 }
1105
1106 /*
1107  * XXX - do we need multiple statusbar contexts?
1108  */
1109
1110 /*
1111  * Push a message referring to the currently-selected field onto the statusbar.
1112  */
1113 void
1114 statusbar_push_field_msg(gchar *msg)
1115 {
1116         gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
1117 }
1118
1119 /*
1120  * Pop a message referring to the currently-selected field off the statusbar.
1121  */
1122 void
1123 statusbar_pop_field_msg(void)
1124 {
1125         gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
1126 }
1127
1128 /*
1129  * update the packets statusbar to the current values
1130  */
1131 void packets_bar_update(void)
1132 {
1133
1134     if(packets_bar) {
1135         /* remove old status */
1136         if(packets_str) {
1137             g_free(packets_str);
1138                 gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
1139         }
1140
1141         /* do we have any packets? */
1142         if(cfile.count) {
1143             packets_str = g_strdup_printf(" P: %u D: %u M: %u", 
1144                 cfile.count, cfile.displayed_count, cfile.marked_count);
1145         } else {
1146             packets_str = g_strdup(" No Packets");
1147         }
1148             gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str);
1149     }
1150 }
1151
1152
1153 gboolean
1154 main_do_quit(void)
1155 {
1156         gchar *rec_path;
1157
1158
1159     /* get the current geometry, before writing it to disk */
1160     main_save_window_geometry(top_level);
1161
1162         /* write user's recent file to disk
1163          * It is no problem to write this file, even if we do not quit */
1164         write_recent(&rec_path);
1165
1166         /* XXX - should we check whether the capture file is an
1167            unsaved temporary file for a live capture and, if so,
1168            pop up a "do you want to exit without saving the capture
1169            file?" dialog, and then just return, leaving said dialog
1170            box to forcibly quit if the user clicks "OK"?
1171
1172            If so, note that this should be done in a subroutine that
1173            returns TRUE if we do so, and FALSE otherwise, and if it
1174            returns TRUE we should return TRUE without nuking anything.
1175
1176            Note that, if we do that, we might also want to check if
1177            an "Update list of packets in real time" capture is in
1178            progress and, if so, ask whether they want to terminate
1179            the capture and discard it, and return TRUE, before nuking
1180            any child capture, if they say they don't want to do so. */
1181
1182 #ifdef HAVE_LIBPCAP
1183         /* Nuke any child capture in progress. */
1184         kill_capture_child();
1185 #endif
1186
1187         /* Are we in the middle of reading a capture? */
1188         if (cfile.state == FILE_READ_IN_PROGRESS) {
1189                 /* Yes, so we can't just close the file and quit, as
1190                    that may yank the rug out from under the read in
1191                    progress; instead, just set the state to
1192                    "FILE_READ_ABORTED" and return - the code doing the read
1193                    will check for that and, if it sees that, will clean
1194                    up and quit. */
1195                 cfile.state = FILE_READ_ABORTED;
1196
1197                 /* Say that the window should *not* be deleted;
1198                    that'll be done by the code that cleans up. */
1199                 return TRUE;
1200         } else {
1201                 /* Close any capture file we have open; on some OSes, you
1202                    can't unlink a temporary capture file if you have it
1203                    open.
1204                    "cf_close()" will unlink it after closing it if
1205                    it's a temporary file.
1206
1207                    We do this here, rather than after the main loop returns,
1208                    as, after the main loop returns, the main window may have
1209                    been destroyed (if this is called due to a "destroy"
1210                    even on the main window rather than due to the user
1211                    selecting a menu item), and there may be a crash
1212                    or other problem when "cf_close()" tries to
1213                    clean up stuff in the main window.
1214
1215                    XXX - is there a better place to put this?
1216                    Or should we have a routine that *just* closes the
1217                    capture file, and doesn't do anything with the UI,
1218                    which we'd call here, and another routine that
1219                    calls that routine and also cleans up the UI, which
1220                    we'd call elsewhere? */
1221                 cf_close(&cfile);
1222
1223                 /* Exit by leaving the main loop, so that any quit functions
1224                    we registered get called. */
1225                 gtk_main_quit();
1226
1227                 /* Say that the window should be deleted. */
1228                 return FALSE;
1229         }
1230 }
1231
1232 static gboolean
1233 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1234 {
1235   gpointer dialog;
1236
1237   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
1238     /* user didn't saved his current file, ask him */
1239     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
1240                 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1241                 "If you quit the program without saving, your capture data will be discarded.");
1242     simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1243     return TRUE;
1244   } else {
1245     /* unchanged file, just exit */
1246         /* "main_do_quit()" indicates whether the main window should be deleted. */
1247         return main_do_quit();
1248   }
1249 }
1250
1251 static void
1252 main_load_window_geometry(GtkWidget *widget
1253 #if GTK_MAJOR_VERSION < 2
1254         _U_
1255 #endif
1256 )
1257 {
1258     /* as we now have the geometry from the recent file, set it */
1259     if (prefs.gui_geometry_save_position) {
1260         gtk_widget_set_uposition(GTK_WIDGET(top_level),
1261                                  recent.gui_geometry_main_x,
1262                                  recent.gui_geometry_main_y);
1263     }
1264     if (prefs.gui_geometry_save_size) {
1265         WIDGET_SET_SIZE(top_level, 
1266                                 recent.gui_geometry_main_width,
1267                                 recent.gui_geometry_main_height);
1268     } else {
1269         WIDGET_SET_SIZE(top_level, DEF_WIDTH, -1);
1270     }
1271 #if GTK_MAJOR_VERSION >= 2
1272     if(prefs.gui_geometry_save_maximized) {
1273         if (recent.gui_geometry_main_maximized) {
1274             gdk_window_maximize(widget->window);
1275         } else {
1276             gdk_window_unmaximize(widget->window);
1277         }
1278     }
1279 #endif
1280 }
1281
1282 static void
1283 main_save_window_geometry(GtkWidget *widget)
1284 {
1285         gint desk_x, desk_y;
1286 #if GTK_MAJOR_VERSION >= 2
1287     GdkWindowState state;
1288 #endif
1289
1290         /* Try to grab our geometry.
1291
1292            GTK+ provides two routines to get a window's position relative
1293            to the X root window.  If I understand the documentation correctly,
1294            gdk_window_get_deskrelative_origin applies mainly to Enlightenment
1295            and gdk_window_get_root_origin applies for all other WMs.
1296
1297            The code below tries both routines, and picks the one that returns
1298            the upper-left-most coordinates.
1299
1300            More info at:
1301
1302         http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
1303         http://www.gtk.org/faq/#AEN606
1304     */
1305
1306     if (prefs.gui_geometry_save_position) {
1307             gdk_window_get_root_origin(widget->window, 
1308             &recent.gui_geometry_main_x, 
1309             &recent.gui_geometry_main_y);
1310             if (gdk_window_get_deskrelative_origin(widget->window,
1311                                     &desk_x, &desk_y)) {
1312                     if (desk_x <= recent.gui_geometry_main_x && 
1313                 desk_y <= recent.gui_geometry_main_y)
1314             {
1315                             recent.gui_geometry_main_x = desk_x;
1316                             recent.gui_geometry_main_y = desk_y;
1317                     }
1318             }
1319     }
1320
1321     if (prefs.gui_geometry_save_size) {
1322             /* XXX - Is this the "approved" method? */
1323             gdk_window_get_size(widget->window, 
1324             &recent.gui_geometry_main_width, 
1325             &recent.gui_geometry_main_height);
1326     }
1327
1328 #if GTK_MAJOR_VERSION >= 2
1329     if(prefs.gui_geometry_save_maximized) {
1330         state = gdk_window_get_state(widget->window);
1331         recent.gui_geometry_main_maximized = (state == GDK_WINDOW_STATE_MAXIMIZED);
1332     }
1333 #endif
1334 }
1335
1336 static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1337 {
1338     switch(btn) {
1339     case(ESD_BTN_YES):
1340         /* save file first */
1341         file_save_as_cmd(after_save_exit, NULL);
1342         break;
1343     case(ESD_BTN_NO):
1344         main_do_quit();
1345         break;
1346     case(ESD_BTN_CANCEL):
1347         break;
1348     default:
1349         g_assert_not_reached();
1350     }
1351 }
1352
1353 void
1354 file_quit_cmd_cb(GtkWidget *widget _U_, gpointer data _U_)
1355 {
1356   gpointer dialog;
1357
1358   if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
1359     /* user didn't saved his current file, ask him */
1360     dialog = simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTNS_YES_NO_CANCEL,
1361                 PRIMARY_TEXT_START "Save capture file before program quit?" PRIMARY_TEXT_END "\n\n"
1362                 "If you quit the program without saving, your capture data will be discarded.");
1363     simple_dialog_set_cb(dialog, file_quit_answered_cb, NULL);
1364   } else {
1365     /* unchanged file, just exit */
1366         main_do_quit();
1367   }
1368 }
1369
1370 static void
1371 print_usage(gboolean print_ver) {
1372
1373   FILE *output;
1374
1375   if (print_ver) {
1376     output = stdout;
1377     fprintf(output, "This is GNU " PACKAGE " " VERSION
1378 #ifdef CVSVERSION
1379         " (cvs " CVSVERSION ")"
1380 #endif
1381         "\n%s\n%s\n",
1382         comp_info_str->str, runtime_info_str->str);
1383   } else {
1384     output = stderr;
1385   }
1386 #ifdef HAVE_LIBPCAP
1387   fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n",
1388           PACKAGE);
1389   fprintf(output, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
1390   fprintf(output, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
1391   fprintf(output, "\t[ -i <interface> ] [ -m <medium font> ] [ -N <resolving> ]\n");
1392   fprintf(output, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1393   fprintf(output, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1394   fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1395   fprintf(output, "\t[ -w <savefile> ] [ -y <link type> ] [ -z <statistics string> ]\n");
1396   fprintf(output, "\t[ <infile> ]\n");
1397 #else
1398   fprintf(output, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1399           PACKAGE);
1400   fprintf(output, "\t[ -N <resolving> ] [ -o <preference setting> ...\n");
1401   fprintf(output, "\t[ -P <packet list height> ] [ -r <infile> ] [ -R <read filter> ]\n");
1402   fprintf(output, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1403   fprintf(output, "\t[ -z <statistics string> ] [ <infile> ]\n");
1404 #endif
1405 }
1406
1407 static void
1408 show_version(void)
1409 {
1410 #ifdef WIN32
1411   create_console();
1412 #endif
1413
1414   printf(PACKAGE " " VERSION
1415 #ifdef CVSVERSION
1416       " (cvs " CVSVERSION ")"
1417 #endif
1418       "\n%s\n%s\n",
1419       comp_info_str->str, runtime_info_str->str);
1420 }
1421
1422 static int
1423 get_natural_int(const char *string, const char *name)
1424 {
1425   long number;
1426   char *p;
1427
1428   number = strtol(string, &p, 10);
1429   if (p == string || *p != '\0') {
1430     fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1431             name, string);
1432     exit(1);
1433   }
1434   if (number < 0) {
1435     fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1436             name, string);
1437     exit(1);
1438   }
1439   if (number > INT_MAX) {
1440     fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1441             name, string, INT_MAX);
1442     exit(1);
1443   }
1444   return number;
1445 }
1446
1447 static int
1448 get_positive_int(const char *string, const char *name)
1449 {
1450   long number;
1451
1452   number = get_natural_int(string, name);
1453
1454   if (number == 0) {
1455     fprintf(stderr, "ethereal: The specified %s is zero\n",
1456             name);
1457     exit(1);
1458   }
1459
1460   return number;
1461 }
1462
1463 #ifdef HAVE_LIBPCAP
1464 /*
1465  * Given a string of the form "<autostop criterion>:<value>", as might appear
1466  * as an argument to a "-a" option, parse it and set the criterion in
1467  * question.  Return an indication of whether it succeeded or failed
1468  * in some fashion.
1469  */
1470 static gboolean
1471 set_autostop_criterion(const char *autostoparg)
1472 {
1473   gchar *p, *colonp;
1474
1475   colonp = strchr(autostoparg, ':');
1476   if (colonp == NULL)
1477     return FALSE;
1478
1479   p = colonp;
1480   *p++ = '\0';
1481
1482   /*
1483    * Skip over any white space (there probably won't be any, but
1484    * as we allow it in the preferences file, we might as well
1485    * allow it here).
1486    */
1487   while (isspace((guchar)*p))
1488     p++;
1489   if (*p == '\0') {
1490     /*
1491      * Put the colon back, so if our caller uses, in an
1492      * error message, the string they passed us, the message
1493      * looks correct.
1494      */
1495     *colonp = ':';
1496     return FALSE;
1497   }
1498   if (strcmp(autostoparg,"duration") == 0) {
1499     capture_opts.has_autostop_duration = TRUE;
1500     capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1501   } else if (strcmp(autostoparg,"filesize") == 0) {
1502     capture_opts.has_autostop_filesize = TRUE;
1503     capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1504   } else {
1505     return FALSE;
1506   }
1507   *colonp = ':'; /* put the colon back */
1508   return TRUE;
1509 }
1510
1511 /*
1512  * Given a string of the form "<ring buffer file>:<duration>", as might appear
1513  * as an argument to a "-b" option, parse it and set the arguments in
1514  * question.  Return an indication of whether it succeeded or failed
1515  * in some fashion.
1516  */
1517 static gboolean
1518 get_ring_arguments(const char *arg)
1519 {
1520   gchar *p = NULL, *colonp;
1521
1522   colonp = strchr(arg, ':');
1523
1524   if (colonp != NULL) {
1525     p = colonp;
1526     *p++ = '\0';
1527   }
1528
1529   capture_opts.ringbuffer_num_files = 
1530     get_natural_int(arg, "number of ring buffer files");
1531
1532   if (colonp == NULL)
1533     return TRUE;
1534
1535   /*
1536    * Skip over any white space (there probably won't be any, but
1537    * as we allow it in the preferences file, we might as well
1538    * allow it here).
1539    */
1540   while (isspace(*p))
1541     p++;
1542   if (*p == '\0') {
1543     /*
1544      * Put the colon back, so if our caller uses, in an
1545      * error message, the string they passed us, the message
1546      * looks correct.
1547      */
1548     *colonp = ':';
1549     return FALSE;
1550   }
1551
1552   capture_opts.has_ring_duration = TRUE;
1553   capture_opts.ringbuffer_duration = get_positive_int(p,
1554                                                       "ring buffer duration");
1555
1556   *colonp = ':';        /* put the colon back */
1557   return TRUE;
1558 }
1559 #endif
1560
1561 #if defined WIN32 || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
1562 /* 
1563    Once every 3 seconds we get a callback here which we use to update
1564    the tap extensions. Since Gtk1 is single threaded we dont have to
1565    worry about any locking or critical regions.
1566  */
1567 static gint
1568 update_cb(gpointer data _U_)
1569 {
1570         draw_tap_listeners(FALSE);
1571         return 1;
1572 }
1573 #else
1574
1575 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1576    use threads all updte_thread_mutex can be dropped and protect/unprotect 
1577    would just be empty functions.
1578
1579    This allows gtk2-rpcstat.c and friends to be copied unmodified to 
1580    gtk1-ethereal and it will just work.
1581  */
1582 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1583 gpointer
1584 update_thread(gpointer data _U_)
1585 {
1586     while(1){
1587         GTimeVal tv1, tv2;
1588         g_get_current_time(&tv1);
1589         g_static_mutex_lock(&update_thread_mutex);
1590         gdk_threads_enter();
1591         draw_tap_listeners(FALSE);
1592         gdk_threads_leave();
1593         g_static_mutex_unlock(&update_thread_mutex);
1594         g_thread_yield();
1595         g_get_current_time(&tv2);
1596         if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1597             (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1598             g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1599                      (tv2.tv_sec * 1000000 + tv2.tv_usec));
1600         }
1601     }
1602     return NULL;
1603 }
1604 #endif
1605 void
1606 protect_thread_critical_region(void)
1607 {
1608 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1609     g_static_mutex_lock(&update_thread_mutex);
1610 #endif
1611 }
1612 void
1613 unprotect_thread_critical_region(void)
1614 {
1615 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined USE_THREADS
1616     g_static_mutex_unlock(&update_thread_mutex);
1617 #endif
1618 }
1619
1620 /* structure to keep track of what tap listeners have been registered.
1621  */
1622 typedef struct _ethereal_tap_list {
1623         struct _ethereal_tap_list *next;
1624         char *cmd;
1625         void (*func)(char *arg);
1626 } ethereal_tap_list;
1627 static ethereal_tap_list *tap_list=NULL;
1628
1629 void
1630 register_ethereal_tap(char *cmd, void (*func)(char *arg))
1631 {
1632         ethereal_tap_list *newtl;
1633
1634         newtl=malloc(sizeof(ethereal_tap_list));
1635         newtl->next=tap_list;
1636         tap_list=newtl;
1637         newtl->cmd=cmd;
1638         newtl->func=func;
1639
1640 }
1641
1642
1643 enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL };
1644
1645 void
1646 dnd_open_file_cmd(gpointer cf_name)
1647 {
1648         int       err;
1649
1650     
1651     /* open and read the capture file (this will close an existing file) */
1652         if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
1653                 cf_read(&cfile);
1654         add_menu_recent_capture_file(cf_name);
1655         } else {
1656                 /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */
1657         }
1658
1659     g_free(cf_name);
1660 }
1661
1662 static void 
1663 dnd_open_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
1664 {
1665     switch(btn) {
1666     case(ESD_BTN_YES):
1667         /* save file first */
1668         file_save_as_cmd(after_save_open_dnd_file, data);
1669         break;
1670     case(ESD_BTN_NO):
1671         cf_close(&cfile);
1672         dnd_open_file_cmd(data);
1673         break;
1674     case(ESD_BTN_CANCEL):
1675         g_free(data);
1676         break;
1677     default:
1678         g_assert_not_reached();
1679     }
1680 }
1681
1682 static gchar *
1683 dnd_uri2filename(gchar *cf_name)
1684 {
1685     gchar     *src, *dest;
1686     gint      ret;
1687     guint     i;
1688     gchar     esc[3];
1689
1690
1691     /*
1692      * Remove URI header.
1693      * On win32 (at least WinXP), this string looks like (UNC or local filename):
1694      * file:////servername/sharename/dir1/dir2/capture-file.cap
1695      * or
1696      * file:///d:/dir1/dir2/capture-file.cap
1697      * we have to remove the prefix to get a valid filename.
1698      *
1699      * On UNIX (at least KDE 3.0 Konqueror), this string looks like:
1700      * file:/dir1/dir2/capture-file.cap
1701      * we have to remove the file: to get a valid filename.
1702      */ 
1703     if (strncmp("file:////", cf_name, 9) == 0) {
1704         /* now becoming: //servername/sharename/dir1/dir2/capture-file.cap */
1705         cf_name += 7;
1706     } else if (strncmp("file:///", cf_name, 8) == 0) {
1707         /* now becoming: d:/dir1/dir2/capture-file.cap */
1708         cf_name += 8;
1709     } else if (strncmp("file:", cf_name, 5) == 0) {
1710         /* now becoming: /dir1/dir2/capture-file.cap */
1711         cf_name += 5;
1712     }
1713
1714     /* 
1715      * unescape the escaped URI characters (spaces, ...)
1716      *
1717      * we have to replace escaped chars to their equivalents, 
1718      * e.g. %20 (always a two digit hexstring) -> ' '
1719      * the percent character '%' is escaped be a double one "%%"
1720      *
1721      * we do this conversation "in place" as the result is always 
1722      * equal or smaller in size.
1723      */
1724     src = cf_name;
1725     dest = cf_name;
1726     while (*src) {
1727         if (*src == '%') {
1728             src++;
1729             if (*src == '%') {
1730                 /* this is an escaped '%' char (was: "%%") */
1731                 *dest = *src;
1732                 src++;
1733                 dest++;
1734             } else {
1735                 /* convert escaped hexnumber to unscaped character */
1736                 esc[0] = src[0];
1737                 esc[1] = src[1];
1738                 esc[2] = '\0';
1739                 ret = sscanf(esc, "%x", &i);
1740                 if (ret == 1) {
1741                     src+=2;
1742                     *dest = (gchar) i;
1743                     dest++;
1744                 } else {
1745                     /* somethings wrong, just jump over that char
1746                      * this will result in a wrong string, but we might get
1747                      * user feedback and can fix it later ;-) */
1748                     src++;
1749                 }
1750             }
1751         } else {
1752             *dest = *src;
1753             src++;
1754             dest++;
1755         }
1756     }
1757     *dest = '\0';
1758
1759     return cf_name;
1760 }
1761
1762 static void 
1763 dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_, 
1764 GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_)
1765 {
1766     gchar     *cf_name, *cf_name_ori;
1767     gpointer  dialog;
1768
1769     if (info == DND_TARGET_URL) {
1770         /* DND_TARGET_URL on Win32:
1771          * The selection_data->data is a single string, containing one or more URI's,
1772          * seperated by CR/NL chars. The length of the whole field can be found 
1773          * in the selection_data->length field. As we can't handle more than one 
1774          * capture file at a time, we only try to load the first one. */
1775
1776         /* XXX: how does this string look like on other platforms? */
1777
1778         /* XXX: if more than one file is in the string, we might want to have 
1779          * a dialog box asking to merge these files together? */
1780
1781         /* the name might not be zero terminated -> make a copy of it */
1782         cf_name_ori = g_strndup((gchar *)selection_data->data, selection_data->length);
1783         cf_name = cf_name_ori;
1784
1785         /* replace trailing CR NL simply with zeroes */
1786         g_strdelimit(cf_name, "\r\n", '\0');
1787
1788         /* convert the URI to a local filename */
1789         cf_name = dnd_uri2filename(cf_name);
1790
1791         /* we need a clean name for later call to g_free() */
1792         cf_name = strdup(cf_name);
1793         g_free(cf_name_ori);
1794
1795         /* ask the user to save it's current capture file first */
1796         if((cfile.state != FILE_CLOSED) && !cfile.user_saved) {
1797             /* user didn't saved his current file, ask him */
1798             dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
1799                         ESD_BTNS_YES_NO_CANCEL,
1800                         PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
1801                         "If you open a new capture file without saving, your current capture data will be discarded.");
1802             simple_dialog_set_cb(dialog, dnd_open_file_answered_cb, cf_name);
1803         } else {
1804             /* unchanged file */
1805             dnd_open_file_cmd(cf_name);
1806         }
1807     }
1808 }
1809
1810 static void 
1811 dnd_init(GtkWidget *w)
1812 {
1813     /* we are only interested in the URI list containing filenames */
1814     static GtkTargetEntry target_entry[] = {
1815          /*{"STRING", 0, DND_TARGET_STRING},*/
1816          /*{"text/plain", 0, DND_TARGET_STRING},*/
1817          {"text/uri-list", 0, DND_TARGET_URL}
1818     };
1819
1820     /* set this window as a dnd destination */
1821     gtk_drag_dest_set(
1822          w, GTK_DEST_DEFAULT_ALL, target_entry,
1823          sizeof(target_entry) / sizeof(GtkTargetEntry),
1824          (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) );
1825
1826     /* get notified, if some dnd coming in */
1827     gtk_signal_connect(GTK_OBJECT(w), "drag_data_received",
1828         GTK_SIGNAL_FUNC(dnd_data_received), NULL);
1829 }
1830
1831
1832 /* And now our feature presentation... [ fade to music ] */
1833 int
1834 main(int argc, char *argv[])
1835 {
1836 #ifdef HAVE_LIBPCAP
1837   char                *command_name;
1838 #endif
1839   char                *s;
1840   int                  i;
1841   int                  opt;
1842   extern char         *optarg;
1843   gboolean             arg_error = FALSE;
1844
1845 #ifdef WIN32
1846   WSADATA              wsaData;
1847 #endif  /* WIN32 */
1848
1849   char                *rf_path;
1850   int                  rf_open_errno;
1851   char                *gpf_path, *pf_path;
1852   char                *cf_path, *df_path;
1853   char                *gdp_path, *dp_path;
1854   int                  gpf_open_errno, gpf_read_errno;
1855   int                  pf_open_errno, pf_read_errno;
1856   int                  cf_open_errno, df_open_errno;
1857   int                  gdp_open_errno, gdp_read_errno;
1858   int                  dp_open_errno, dp_read_errno;
1859   int                  err;
1860 #ifdef HAVE_LIBPCAP
1861   gboolean             start_capture = FALSE;
1862   gchar               *save_file = NULL;
1863   GList               *if_list;
1864   if_info_t           *if_info;
1865   GList               *lt_list, *lt_entry;
1866   data_link_info_t    *data_link_info;
1867   gchar                err_str[PCAP_ERRBUF_SIZE];
1868   gboolean             stats_known;
1869   struct pcap_stat     stats;
1870 #else
1871   gboolean             capture_option_specified = FALSE;
1872 #endif
1873   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1874   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1875   dfilter_t           *rfcode = NULL;
1876   gboolean             rfilter_parse_failed = FALSE;
1877   e_prefs             *prefs;
1878   char                 badopt;
1879 #if GTK_MAJOR_VERSION < 2
1880   char                *bold_font_name;
1881 #endif
1882   ethereal_tap_list   *tli = NULL;
1883   gchar               *tap_opt = NULL;
1884
1885 #define OPTSTRING_INIT "a:b:B:c:f:hi:klLm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:"
1886
1887 #ifdef HAVE_LIBPCAP
1888 #ifdef WIN32
1889 #define OPTSTRING_CHILD "W:Z:"
1890 #else
1891 #define OPTSTRING_CHILD "W:"
1892 #endif  /* WIN32 */
1893 #else
1894 #define OPTSTRING_CHILD ""
1895 #endif  /* HAVE_LIBPCAP */
1896
1897   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1898     OPTSTRING_INIT;
1899
1900   ethereal_path = argv[0];
1901
1902 #ifdef WIN32
1903   /* Arrange that if we have no console window, and a GLib message logging
1904      routine is called to log a message, we pop up a console window.
1905
1906      We do that by inserting our own handler for all messages logged
1907      to the default domain; that handler pops up a console if necessary,
1908      and then calls the default handler. */
1909   g_log_set_handler(NULL,
1910                     G_LOG_LEVEL_ERROR|
1911                     G_LOG_LEVEL_CRITICAL|
1912                     G_LOG_LEVEL_WARNING|
1913                     G_LOG_LEVEL_MESSAGE|
1914                     G_LOG_LEVEL_INFO|
1915                     G_LOG_LEVEL_DEBUG|
1916                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1917                     console_log_handler, NULL);
1918 #endif
1919
1920 #ifdef HAVE_LIBPCAP
1921   command_name = get_basename(ethereal_path);
1922   /* Set "capture_child" to indicate whether this is going to be a child
1923      process for a "-S" capture. */
1924   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1925   if (capture_child)
1926     strcat(optstring, OPTSTRING_CHILD);
1927 #endif
1928
1929   /* Register all dissectors; we must do this before checking for the
1930      "-G" flag, as the "-G" flag dumps information registered by the
1931      dissectors, and we must do it before we read the preferences, in
1932      case any dissectors register preferences. */
1933   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
1934
1935   /* Register all tap listeners; we do this before we parse the arguments,
1936      as the "-z" argument can specify a registered tap. */
1937   register_all_tap_listeners();
1938
1939   /* Now register the preferences for any non-dissector modules.
1940      We must do that before we read the preferences as well. */
1941   prefs_register_modules();
1942
1943   /* If invoked with the "-G" flag, we dump out information based on
1944      the argument to the "-G" flag; if no argument is specified,
1945      for backwards compatibility we dump out a glossary of display
1946      filter symbols.
1947
1948      We must do this before calling "gtk_init()", because "gtk_init()"
1949      tries to open an X display, and we don't want to have to do any X
1950      stuff just to do a build.
1951
1952      Given that we call "gtk_init()" before doing the regular argument
1953      list processing, so that it can handle X and GTK+ arguments and
1954      remove them from the list at which we look, this means we must do
1955      this before doing the regular argument list processing, as well.
1956
1957      This means that:
1958
1959         you must give the "-G" flag as the first flag on the command line;
1960
1961         you must give it as "-G", nothing more, nothing less;
1962
1963         the first argument after the "-G" flag, if present, will be used
1964         to specify the information to dump;
1965
1966         arguments after that will not be used. */
1967   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1968     if (argc == 2)
1969       proto_registrar_dump_fields();
1970     else {
1971       if (strcmp(argv[2], "fields") == 0)
1972         proto_registrar_dump_fields();
1973       else if (strcmp(argv[2], "protocols") == 0)
1974         proto_registrar_dump_protocols();
1975       else {
1976         fprintf(stderr, "ethereal: Invalid \"%s\" option for -G flag\n",
1977                 argv[2]);
1978         exit(1);
1979       }
1980     }
1981     exit(0);
1982   }
1983
1984   /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1985 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined G_THREADS_ENABLED && defined USE_THREADS
1986   {
1987       GThread *ut;
1988       g_thread_init(NULL);
1989       gdk_threads_init();
1990       ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1991       g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1992   }
1993 #else  /* WIN32 || GTK1.2 || !G_THREADS_ENABLED || !USE_THREADS */
1994   /* this is to keep tap extensions updating once every 3 seconds */
1995   gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1996 #endif /* !WIN32 && GTK2 && G_THREADS_ENABLED */
1997
1998 #if HAVE_GNU_ADNS
1999   gtk_timeout_add(750, (GtkFunction) host_name_lookup_process, NULL);
2000 #endif
2001
2002
2003   /* Set the current locale according to the program environment.
2004    * We haven't localized anything, but some GTK widgets are localized
2005    * (the file selection dialogue, for example).
2006    * This also sets the C-language locale to the native environment. */
2007   gtk_set_locale();
2008
2009   /* Let GTK get its args */
2010   gtk_init (&argc, &argv);
2011
2012   /* Read the preference files. */
2013   prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
2014                      &pf_open_errno, &pf_read_errno, &pf_path);
2015
2016 #ifdef HAVE_LIBPCAP
2017   capture_opts.has_snaplen = FALSE;
2018   capture_opts.snaplen = MIN_PACKET_SIZE;
2019   capture_opts.has_autostop_count = FALSE;
2020   capture_opts.autostop_count = 1;
2021   capture_opts.has_autostop_duration = FALSE;
2022   capture_opts.autostop_duration = 1;
2023   capture_opts.has_autostop_filesize = FALSE;
2024   capture_opts.autostop_filesize = 1;
2025   capture_opts.ringbuffer_on = FALSE;
2026   capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
2027   capture_opts.has_ring_duration = FALSE;
2028   capture_opts.ringbuffer_duration = 1;
2029   capture_opts.linktype = -1;
2030
2031   /* If this is a capture child process, it should pay no attention
2032      to the "prefs.capture_prom_mode" setting in the preferences file;
2033      it should do what the parent process tells it to do, and if
2034      the parent process wants it not to run in promiscuous mode, it'll
2035      tell it so with a "-p" flag.
2036
2037      Otherwise, set promiscuous mode from the preferences setting. */
2038   if (capture_child)
2039     capture_opts.promisc_mode = TRUE;
2040   else
2041     capture_opts.promisc_mode = prefs->capture_prom_mode;
2042
2043   /* Set "Update list of packets in real time" mode from the preferences
2044      setting. */
2045   capture_opts.sync_mode = prefs->capture_real_time;
2046
2047   /* And do the same for "Automatic scrolling in live capture" mode. */
2048   auto_scroll_live = prefs->capture_auto_scroll;
2049 #endif
2050
2051   /* Set the name resolution code's flags from the preferences. */
2052   g_resolv_flags = prefs->name_resolve;
2053
2054   /* Read the capture filter file. */
2055   read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
2056
2057   /* Read the display filter file. */
2058   read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
2059
2060   /* Read the disabled protocols file. */
2061   read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
2062                             &dp_path, &dp_open_errno, &dp_read_errno);
2063
2064   init_cap_file(&cfile);
2065
2066 #ifdef WIN32
2067   /* Load wpcap if possible. Do this before collecting the run-time version information */
2068   load_wpcap();
2069
2070   /* Start windows sockets */
2071   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
2072 #endif  /* WIN32 */
2073
2074   /* Assemble the compile-time version information string */
2075   comp_info_str = g_string_new("Compiled ");
2076   g_string_append(comp_info_str, "with ");
2077   g_string_sprintfa(comp_info_str,
2078 #ifdef GTK_MAJOR_VERSION
2079                     "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
2080                     GTK_MICRO_VERSION);
2081 #else
2082                     "GTK+ (version unknown)");
2083 #endif
2084
2085   g_string_append(comp_info_str, ", ");
2086   get_compiled_version_info(comp_info_str);
2087
2088   /* Assemble the run-time version information string */
2089   runtime_info_str = g_string_new("Running ");
2090   get_runtime_version_info(runtime_info_str);
2091
2092   /* Now get our args */
2093   while ((opt = getopt(argc, argv, optstring)) != -1) {
2094     switch (opt) {
2095       case 'a':        /* autostop criteria */
2096 #ifdef HAVE_LIBPCAP
2097         if (set_autostop_criterion(optarg) == FALSE) {
2098           fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
2099           exit(1);
2100         }
2101 #else
2102         capture_option_specified = TRUE;
2103         arg_error = TRUE;
2104 #endif
2105         break;
2106       case 'b':        /* Ringbuffer option */
2107 #ifdef HAVE_LIBPCAP
2108         capture_opts.ringbuffer_on = TRUE;
2109         if (get_ring_arguments(optarg) == FALSE) {
2110           fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
2111           exit(1);
2112         }
2113 #else
2114         capture_option_specified = TRUE;
2115         arg_error = TRUE;
2116 #endif
2117         break;
2118       case 'B':        /* Byte view pane height */
2119         bv_size = get_positive_int(optarg, "byte view pane height");
2120         break;
2121       case 'c':        /* Capture xxx packets */
2122 #ifdef HAVE_LIBPCAP
2123         capture_opts.has_autostop_count = TRUE;
2124         capture_opts.autostop_count = get_positive_int(optarg, "packet count");
2125 #else
2126         capture_option_specified = TRUE;
2127         arg_error = TRUE;
2128 #endif
2129         break;
2130       case 'f':
2131 #ifdef HAVE_LIBPCAP
2132         if (cfile.cfilter)
2133                 g_free(cfile.cfilter);
2134         cfile.cfilter = g_strdup(optarg);
2135 #else
2136         capture_option_specified = TRUE;
2137         arg_error = TRUE;
2138 #endif
2139         break;
2140       case 'h':        /* Print help and exit */
2141         print_usage(TRUE);
2142         exit(0);
2143         break;
2144       case 'i':        /* Use interface xxx */
2145 #ifdef HAVE_LIBPCAP
2146         cfile.iface = g_strdup(optarg);
2147 #else
2148         capture_option_specified = TRUE;
2149         arg_error = TRUE;
2150 #endif
2151         break;
2152       case 'k':        /* Start capture immediately */
2153 #ifdef HAVE_LIBPCAP
2154         start_capture = TRUE;
2155 #else
2156         capture_option_specified = TRUE;
2157         arg_error = TRUE;
2158 #endif
2159         break;
2160       case 'l':        /* Automatic scrolling in live capture mode */
2161 #ifdef HAVE_LIBPCAP
2162         auto_scroll_live = TRUE;
2163 #else
2164         capture_option_specified = TRUE;
2165         arg_error = TRUE;
2166 #endif
2167         break;
2168       case 'L':        /* Print list of link-layer types and exit */
2169 #ifdef HAVE_LIBPCAP
2170         list_link_layer_types = TRUE;
2171         break;
2172 #else
2173         capture_option_specified = TRUE;
2174         arg_error = TRUE;
2175 #endif
2176         break;
2177       case 'm':        /* Fixed-width font for the display */
2178         if (prefs->PREFS_GUI_FONT_NAME != NULL)
2179           g_free(prefs->PREFS_GUI_FONT_NAME);
2180         prefs->PREFS_GUI_FONT_NAME = g_strdup(optarg);
2181         break;
2182       case 'n':        /* No name resolution */
2183         g_resolv_flags = RESOLV_NONE;
2184         break;
2185       case 'N':        /* Select what types of addresses/port #s to resolve */
2186         if (g_resolv_flags == RESOLV_ALL)
2187           g_resolv_flags = RESOLV_NONE;
2188         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
2189         if (badopt != '\0') {
2190           fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
2191                         badopt);
2192           exit(1);
2193         }
2194         break;
2195       case 'o':        /* Override preference from command line */
2196         switch (prefs_set_pref(optarg)) {
2197
2198         case PREFS_SET_SYNTAX_ERR:
2199           fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
2200           exit(1);
2201           break;
2202
2203         case PREFS_SET_NO_SUCH_PREF:
2204         case PREFS_SET_OBSOLETE:
2205           fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
2206                         optarg);
2207           exit(1);
2208           break;
2209         }
2210         break;
2211       case 'p':        /* Don't capture in promiscuous mode */
2212 #ifdef HAVE_LIBPCAP
2213         capture_opts.promisc_mode = FALSE;
2214 #else
2215         capture_option_specified = TRUE;
2216         arg_error = TRUE;
2217 #endif
2218         break;
2219       case 'P':        /* Packet list pane height */
2220         pl_size = get_positive_int(optarg, "packet list pane height");
2221         break;
2222       case 'Q':        /* Quit after capture (just capture to file) */
2223 #ifdef HAVE_LIBPCAP
2224         quit_after_cap  = TRUE;
2225         start_capture   = TRUE;  /*** -Q implies -k !! ***/
2226 #else
2227         capture_option_specified = TRUE;
2228         arg_error = TRUE;
2229 #endif
2230         break;
2231       case 'r':        /* Read capture file xxx */
2232         /* We may set "last_open_dir" to "cf_name", and if we change
2233            "last_open_dir" later, we free the old value, so we have to
2234            set "cf_name" to something that's been allocated. */
2235         cf_name = g_strdup(optarg);
2236         break;
2237       case 'R':        /* Read file filter */
2238         rfilter = optarg;
2239         break;
2240       case 's':        /* Set the snapshot (capture) length */
2241 #ifdef HAVE_LIBPCAP
2242         capture_opts.has_snaplen = TRUE;
2243         capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
2244 #else
2245         capture_option_specified = TRUE;
2246         arg_error = TRUE;
2247 #endif
2248         break;
2249       case 'S':        /* "Sync" mode: used for following file ala tail -f */
2250 #ifdef HAVE_LIBPCAP
2251         capture_opts.sync_mode = TRUE;
2252 #else
2253         capture_option_specified = TRUE;
2254         arg_error = TRUE;
2255 #endif
2256         break;
2257       case 't':        /* Time stamp type */
2258         if (strcmp(optarg, "r") == 0)
2259           timestamp_type = TS_RELATIVE;
2260         else if (strcmp(optarg, "a") == 0)
2261           timestamp_type = TS_ABSOLUTE;
2262         else if (strcmp(optarg, "ad") == 0)
2263           timestamp_type = TS_ABSOLUTE_WITH_DATE;
2264         else if (strcmp(optarg, "d") == 0)
2265           timestamp_type = TS_DELTA;
2266         else {
2267           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
2268             optarg);
2269           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
2270           fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
2271           exit(1);
2272         }
2273         break;
2274       case 'T':        /* Tree view pane height */
2275         tv_size = get_positive_int(optarg, "tree view pane height");
2276         break;
2277       case 'v':        /* Show version and exit */
2278         show_version();
2279 #ifdef WIN32
2280         if (console_was_created)
2281           destroy_console();
2282 #endif
2283         exit(0);
2284         break;
2285       case 'w':        /* Write to capture file xxx */
2286 #ifdef HAVE_LIBPCAP
2287         save_file = g_strdup(optarg);
2288 #else
2289         capture_option_specified = TRUE;
2290         arg_error = TRUE;
2291 #endif
2292         break;
2293       case 'y':        /* Set the pcap data link type */
2294 #ifdef HAVE_LIBPCAP
2295 #ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
2296         capture_opts.linktype = pcap_datalink_name_to_val(optarg);
2297         if (capture_opts.linktype == -1) {
2298           fprintf(stderr, "ethereal: The specified data link type \"%s\" is not valid\n",
2299                   optarg);
2300           exit(1);
2301         }
2302 #else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
2303         /* XXX - just treat it as a number */
2304         capture_opts.linktype = get_natural_int(optarg, "data link type");
2305 #endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
2306 #else /* HAVE_LIBPCAP */
2307         capture_option_specified = TRUE;
2308         arg_error = TRUE;
2309 #endif /* HAVE_LIBPCAP */
2310         break;
2311 #ifdef HAVE_LIBPCAP
2312       /* This is a hidden option supporting Sync mode, so we don't set
2313        * the error flags for the user in the non-libpcap case.
2314        */
2315       case 'W':        /* Write to capture file FD xxx */
2316         cfile.save_file_fd = atoi(optarg);
2317         break;
2318 #endif
2319       case 'z':
2320         for(tli=tap_list;tli;tli=tli->next){
2321           if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
2322             tap_opt = g_strdup(optarg);
2323             break;
2324           }
2325         }
2326         if(!tli){
2327           fprintf(stderr,"ethereal: invalid -z argument.\n");
2328           fprintf(stderr,"  -z argument must be one of :\n");
2329           for(tli=tap_list;tli;tli=tli->next){
2330             fprintf(stderr,"     %s\n",tli->cmd);
2331           }
2332           exit(1);
2333         }
2334         break;
2335
2336 #ifdef _WIN32
2337 #ifdef HAVE_LIBPCAP
2338       /* Hidden option supporting Sync mode */
2339       case 'Z':        /* Write to pipe FD XXX */
2340         /* associate stdout with pipe */
2341         i = atoi(optarg);
2342         if (dup2(i, 1) < 0) {
2343           fprintf(stderr, "Unable to dup pipe handle\n");
2344           exit(1);
2345         }
2346         break;
2347 #endif /* HAVE_LIBPCAP */
2348 #endif /* _WIN32 */
2349
2350       default:
2351       case '?':        /* Bad flag - print usage message */
2352         arg_error = TRUE;
2353         break;
2354     }
2355   }
2356   argc -= optind;
2357   argv += optind;
2358   if (argc >= 1) {
2359     if (cf_name != NULL) {
2360       /*
2361        * Input file name specified with "-r" *and* specified as a regular
2362        * command-line argument.
2363        */
2364       arg_error = TRUE;
2365     } else {
2366       /*
2367        * Input file name not specified with "-r", and a command-line argument
2368        * was specified; treat it as the input file name.
2369        *
2370        * Yes, this is different from tethereal, where non-flag command-line
2371        * arguments are a filter, but this works better on GUI desktops
2372        * where a command can be specified to be run to open a particular
2373        * file - yes, you could have "-r" as the last part of the command,
2374        * but that's a bit ugly.
2375        */
2376       cf_name = g_strdup(argv[0]);
2377     }
2378     argc--;
2379     argv++;
2380   }
2381
2382   if (argc != 0) {
2383     /*
2384      * Extra command line arguments were specified; complain.
2385      */
2386     fprintf(stderr, "Invalid argument: %s\n", argv[0]);
2387     arg_error = TRUE;
2388   }
2389
2390 #ifndef HAVE_LIBPCAP
2391   if (capture_option_specified)
2392     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
2393 #endif
2394   if (arg_error) {
2395     print_usage(FALSE);
2396     exit(1);
2397   }
2398
2399 #ifdef HAVE_LIBPCAP
2400   if (start_capture && list_link_layer_types) {
2401     /* Specifying *both* is bogus. */
2402     fprintf(stderr, "ethereal: You cannot specify both -L and a live capture.\n");
2403     exit(1);
2404   }
2405
2406   if (list_link_layer_types) {
2407     /* We're supposed to list the link-layer types for an interface;
2408        did the user also specify a capture file to be read? */
2409     if (cf_name) {
2410       /* Yes - that's bogus. */
2411       fprintf(stderr, "ethereal: You cannot specify -L and a capture file to be read.\n");
2412       exit(1);
2413     }
2414     /* No - did they specify a ring buffer option? */
2415     if (capture_opts.ringbuffer_on) {
2416       fprintf(stderr, "ethereal: Ring buffer requested, but a capture is not being done.\n");
2417       exit(1);
2418     }
2419   } else {
2420     /* We're supposed to do a live capture; did the user also specify
2421        a capture file to be read? */
2422     if (start_capture && cf_name) {
2423       /* Yes - that's bogus. */
2424       fprintf(stderr, "ethereal: You cannot specify both a live capture and a capture file to be read.\n");
2425       exit(1);
2426     }
2427
2428     /* No - was the ring buffer option specified and, if so, does it make
2429        sense? */
2430     if (capture_opts.ringbuffer_on) {
2431       /* Ring buffer works only under certain conditions:
2432          a) ring buffer does not work with temporary files;
2433          b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
2434             sync_mode takes precedence;
2435          c) it makes no sense to enable the ring buffer if the maximum
2436             file size is set to "infinite". */
2437       if (save_file == NULL) {
2438         fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
2439         capture_opts.ringbuffer_on = FALSE;
2440       }
2441       if (capture_opts.sync_mode) {
2442         fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
2443         capture_opts.ringbuffer_on = FALSE;
2444       }
2445       if (!capture_opts.has_autostop_filesize) {
2446         fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
2447         capture_opts.ringbuffer_on = FALSE;
2448       }
2449     }
2450   }
2451
2452   if (start_capture || list_link_layer_types) {
2453     /* Did the user specify an interface to use? */
2454     if (cfile.iface == NULL) {
2455       /* No - is a default specified in the preferences file? */
2456       if (prefs->capture_device != NULL) {
2457           /* Yes - use it. */
2458           cfile.iface = g_strdup(prefs->capture_device);
2459       } else {
2460         /* No - pick the first one from the list of interfaces. */
2461         if_list = get_interface_list(&err, err_str);
2462         if (if_list == NULL) {
2463           switch (err) {
2464
2465           case CANT_GET_INTERFACE_LIST:
2466               fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
2467                         err_str);
2468               break;
2469
2470           case NO_INTERFACES_FOUND:
2471               fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
2472               break;
2473           }
2474           exit(2);
2475         }
2476         if_info = if_list->data;        /* first interface */
2477         cfile.iface = g_strdup(if_info->name);
2478         free_interface_list(if_list);
2479       }
2480     }
2481   }
2482
2483   if (capture_child) {
2484     if (cfile.save_file_fd == -1) {
2485       /* XXX - send this to the standard output as something our parent
2486          should put in an error message box? */
2487       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2488       exit(1);
2489     }
2490   }
2491
2492   if (list_link_layer_types) {
2493     /* Get the list of link-layer types for the capture device. */
2494     lt_list = get_pcap_linktype_list(cfile.iface, err_str);
2495     if (lt_list == NULL) {
2496       if (err_str[0] != '\0') {
2497         fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
2498           "Please check to make sure you have sufficient permissions, and that\n"
2499           "you have the proper interface or pipe specified.\n", err_str);
2500       } else
2501         fprintf(stderr, "ethereal: The capture device has no data link types.\n");
2502       exit(2);
2503     }
2504     fprintf(stderr, "Data link types (use option -y to set):\n");
2505     for (lt_entry = lt_list; lt_entry != NULL;
2506          lt_entry = g_list_next(lt_entry)) {
2507       data_link_info = lt_entry->data;
2508       fprintf(stderr, "  %s", data_link_info->name);
2509       if (data_link_info->description != NULL)
2510         fprintf(stderr, " (%s)", data_link_info->description);
2511       else
2512         fprintf(stderr, " (not supported)");
2513       putchar('\n');
2514     }
2515     free_pcap_linktype_list(lt_list);
2516     exit(0);
2517   }
2518
2519 #endif
2520
2521   /* Notify all registered modules that have had any of their preferences
2522      changed either from one of the preferences file or from the command
2523      line that their preferences have changed. */
2524   prefs_apply_all();
2525
2526   /* disabled protocols as per configuration file */
2527   if (gdp_path == NULL && dp_path == NULL) {
2528     set_disabled_protos_list();
2529   }
2530
2531   /* Build the column format array */
2532   col_setup(&cfile.cinfo, prefs->num_cols);
2533   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2534     cfile.cinfo.col_fmt[i] = get_column_format(i);
2535     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2536     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2537       NUM_COL_FMTS);
2538     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2539     cfile.cinfo.col_data[i] = NULL;
2540     if (cfile.cinfo.col_fmt[i] == COL_INFO)
2541       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2542     else
2543       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2544     cfile.cinfo.col_fence[i] = 0;
2545     cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2546     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2547   }
2548
2549   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2550       int j;
2551
2552       for (j = 0; j < NUM_COL_FMTS; j++) {
2553          if (!cfile.cinfo.fmt_matx[i][j])
2554              continue;
2555          
2556          if (cfile.cinfo.col_first[j] == -1)
2557              cfile.cinfo.col_first[j] = i;
2558          cfile.cinfo.col_last[j] = i;
2559       }
2560   }
2561
2562 #ifdef HAVE_LIBPCAP
2563   if (capture_opts.has_snaplen) {
2564     if (capture_opts.snaplen < 1)
2565       capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
2566     else if (capture_opts.snaplen < MIN_PACKET_SIZE)
2567       capture_opts.snaplen = MIN_PACKET_SIZE;
2568   }
2569
2570   /* Check the value range of the ringbuffer_num_files parameter */
2571   if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
2572     capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
2573 #if RINGBUFFER_MIN_NUM_FILES > 0
2574   else if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
2575     capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
2576 #endif
2577 #endif
2578
2579 #ifdef WIN32
2580 #if GTK_MAJOR_VERSION >= 2
2581   try_to_get_windows_font_gtk2();
2582 #endif
2583 #endif
2584     
2585   /* read in rc file from global and personal configuration paths. */
2586   gtk_rc_parse(RC_FILE);
2587   rc_file = get_persconffile_path(RC_FILE, FALSE);
2588   gtk_rc_parse(rc_file);
2589
2590   /* Try to load the regular and boldface fixed-width fonts */
2591 #if GTK_MAJOR_VERSION < 2
2592   bold_font_name = font_boldify(prefs->gui_font_name1);
2593   m_r_font = gdk_font_load(prefs->gui_font_name1);
2594   m_b_font = gdk_font_load(bold_font_name);
2595   if (m_r_font == NULL || m_b_font == NULL) {
2596     /* XXX - pop this up as a dialog box? no */
2597     if (m_r_font == NULL) {
2598 #ifdef HAVE_LIBPCAP
2599       if (!capture_child)
2600 #endif
2601         fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2602                 prefs->gui_font_name1);
2603     } else {
2604       gdk_font_unref(m_r_font);
2605     }
2606     if (m_b_font == NULL) {
2607 #ifdef HAVE_LIBPCAP
2608       if (!capture_child)
2609 #endif
2610         fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2611                 bold_font_name);
2612     } else {
2613       gdk_font_unref(m_b_font);
2614     }
2615     g_free(bold_font_name);
2616     if ((m_r_font = gdk_font_load("6x13")) == NULL) {
2617       fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
2618       exit(1);
2619     }
2620     if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
2621       fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
2622       exit(1);
2623     }
2624     g_free(prefs->gui_font_name1);
2625     prefs->gui_font_name1 = g_strdup("6x13");
2626   }
2627 #else /* GTK_MAJOR_VERSION */
2628   m_r_font = pango_font_description_from_string(prefs->gui_font_name2);
2629   m_b_font = pango_font_description_copy(m_r_font);
2630   pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2631   if (m_r_font == NULL || m_b_font == NULL) {
2632     /* XXX - pop this up as a dialog box? no */
2633     if (m_r_font == NULL) {
2634 #ifdef HAVE_LIBPCAP
2635       if (!capture_child)
2636 #endif
2637         fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to Monospace 9\n",
2638                 prefs->gui_font_name2);
2639     } else {
2640       pango_font_description_free(m_r_font);
2641     }
2642     if (m_b_font == NULL) {
2643 #ifdef HAVE_LIBPCAP
2644       if (!capture_child)
2645 #endif
2646         fprintf(stderr, "ethereal: Warning: bold font %s not found - defaulting"
2647                         " to Monospace 9\n", prefs->gui_font_name2);
2648     } else {
2649       pango_font_description_free(m_b_font);
2650     }
2651     if ((m_r_font = pango_font_description_from_string("Monospace 9")) == NULL)
2652     {
2653       fprintf(stderr, "ethereal: Error: font Monospace 9 not found\n");
2654       exit(1);
2655     }
2656     if ((m_b_font = pango_font_description_copy(m_r_font)) == NULL) {
2657       fprintf(stderr, "ethereal: Error: font Monospace 9 bold not found\n");
2658       exit(1);
2659     }
2660     g_free(prefs->gui_font_name2);
2661     pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2662     prefs->gui_font_name2 = g_strdup("Monospace 9");
2663   }
2664 #endif /* GTK_MAJOR_VERSION */
2665
2666   /* Call this for the side-effects that set_fonts() produces */
2667   set_fonts(m_r_font, m_b_font);
2668
2669 #ifdef HAVE_LIBPCAP
2670   /* Is this a "child" ethereal, which is only supposed to pop up a
2671      capture box to let us stop the capture, and run a capture
2672      to a file that our parent will read? */
2673   if (!capture_child) {
2674 #endif
2675     /* No.  Pop up the main window, and read in a capture file if
2676        we were told to. */
2677     create_main_window(pl_size, tv_size, bv_size, prefs);
2678
2679     /* Read the recent file, as we have the gui now ready for it. */
2680     read_recent(&rf_path, &rf_open_errno);
2681
2682     /* rearrange all the widgets */
2683     main_widgets_rearrange();
2684
2685     /* Fill in column titles.  This must be done after the top level window
2686        is displayed.
2687
2688        XXX - is that still true, with fixed-width columns? */
2689     packet_list_set_column_titles();
2690
2691     menu_recent_read_finished();
2692
2693     switch (font_apply()) {
2694     case FA_SUCCESS:
2695         break;
2696     case FA_FONT_NOT_RESIZEABLE:
2697         /* "font_apply()" popped up an alert box. */
2698         /* turn off zooming - font can't be resized */
2699     case FA_FONT_NOT_AVAILABLE:
2700         /* XXX - did we successfully load the un-zoomed version earlier?
2701         If so, this *probably* means the font is available, but not at
2702         this particular zoom level, but perhaps some other failure
2703         occurred; I'm not sure you can determine which is the case,
2704         however. */
2705         /* turn off zooming - zoom level is unavailable */
2706     default:
2707         /* in any other case than FA_SUCCESS, turn off zooming */
2708         recent.gui_zoom_level = 0;      
2709         /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
2710     }
2711
2712     dnd_init(top_level);
2713
2714     colors_init();
2715     colfilter_init();
2716
2717     /* the window can be sized only, if it's not already shown, so do it now! */
2718     main_load_window_geometry(top_level);
2719
2720     /*** we have finished all init things, show the main window ***/
2721     gtk_widget_show(top_level);
2722
2723     /* the window can be maximized only, if it's visible, so do it after show! */
2724     main_load_window_geometry(top_level);
2725
2726     /* process all pending GUI events before continue */
2727     while (gtk_events_pending()) gtk_main_iteration();
2728
2729     /* If we were given the name of a capture file, read it in now;
2730        we defer it until now, so that, if we can't open it, and pop
2731        up an alert box, the alert box is more likely to come up on
2732        top of the main window - but before the preference-file-error
2733        alert box, so, if we get one of those, it's more likely to come
2734        up on top of us. */
2735     if (cf_name) {
2736       if (rfilter != NULL) {
2737         if (!dfilter_compile(rfilter, &rfcode)) {
2738           bad_dfilter_alert_box(rfilter);
2739           rfilter_parse_failed = TRUE;
2740         }
2741       }
2742       if (!rfilter_parse_failed) {
2743         if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) {
2744           /* "cf_open()" succeeded, so it closed the previous
2745              capture file, and thus destroyed any previous read filter
2746              attached to "cf". */
2747           cfile.rfcode = rfcode;
2748
2749           /* Open tap windows; we do so after creating the main window,
2750              to avoid GTK warnings, and after successfully opening the
2751              capture file, so we know we have something to tap. */
2752           if (tap_opt && tli) {
2753             (*tli->func)(tap_opt);
2754             g_free(tap_opt);
2755           }
2756
2757           /* Read the capture file. */
2758           switch (cf_read(&cfile)) {
2759
2760           case READ_SUCCESS:
2761           case READ_ERROR:
2762             /* Just because we got an error, that doesn't mean we were unable
2763                to read any of the file; we handle what we could get from the
2764                file. */
2765             break;
2766
2767           case READ_ABORTED:
2768             /* Exit now. */
2769             gtk_exit(0);
2770             break;
2771           }
2772           /* Save the name of the containing directory specified in the
2773              path name, if any; we can write over cf_name, which is a
2774              good thing, given that "get_dirname()" does write over its
2775              argument. */
2776           s = get_dirname(cf_name);
2777           /* we might already set this from the recent file, don't overwrite this */
2778           if(last_open_dir == NULL) 
2779             set_last_open_dir(s);
2780           g_free(cf_name);
2781           cf_name = NULL;
2782         } else {
2783           if (rfcode != NULL)
2784             dfilter_free(rfcode);
2785           cfile.rfcode = NULL;
2786         }
2787       }
2788     }
2789 #ifdef HAVE_LIBPCAP
2790   }
2791 #endif
2792
2793   /* If the global preferences file exists but we failed to open it
2794      or had an error reading it, pop up an alert box; we defer that
2795      until now, so that the alert box is more likely to come up on top of
2796      the main window. */
2797   if (gpf_path != NULL) {
2798     if (gpf_open_errno != 0) {
2799       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2800         "Could not open global preferences file\n\"%s\": %s.", gpf_path,
2801         strerror(gpf_open_errno));
2802     }
2803     if (gpf_read_errno != 0) {
2804       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2805         "I/O error reading global preferences file\n\"%s\": %s.", gpf_path,
2806         strerror(gpf_read_errno));
2807     }
2808   }
2809
2810   /* If the user's preferences file exists but we failed to open it
2811      or had an error reading it, pop up an alert box; we defer that
2812      until now, so that the alert box is more likely to come up on top of
2813      the main window. */
2814   if (pf_path != NULL) {
2815     if (pf_open_errno != 0) {
2816       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2817         "Could not open your preferences file\n\"%s\": %s.", pf_path,
2818         strerror(pf_open_errno));
2819     }
2820     if (pf_read_errno != 0) {
2821       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2822         "I/O error reading your preferences file\n\"%s\": %s.", pf_path,
2823         strerror(pf_read_errno));
2824     }
2825     g_free(pf_path);
2826     pf_path = NULL;
2827   }
2828
2829   /* If the user's capture filter file exists but we failed to open it,
2830      pop up an alert box; we defer that until now, so that the alert
2831      box is more likely to come up on top of the main window. */
2832   if (cf_path != NULL) {
2833       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2834         "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2835         strerror(cf_open_errno));
2836       g_free(cf_path);
2837   }
2838
2839   /* If the user's display filter file exists but we failed to open it,
2840      pop up an alert box; we defer that until now, so that the alert
2841      box is more likely to come up on top of the main window. */
2842   if (df_path != NULL) {
2843       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2844         "Could not open your display filter file\n\"%s\": %s.", df_path,
2845         strerror(df_open_errno));
2846       g_free(df_path);
2847   }
2848
2849   /* If the global disabled protocols file exists but we failed to open it,
2850      or had an error reading it, pop up an alert box; we defer that until now,
2851      so that the alert box is more likely to come up on top of the main
2852      window. */
2853   if (gdp_path != NULL) {
2854     if (gdp_open_errno != 0) {
2855       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2856         "Could not open global disabled protocols file\n\"%s\": %s.",
2857         gdp_path, strerror(gdp_open_errno));
2858     }
2859     if (gdp_read_errno != 0) {
2860       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2861         "I/O error reading global disabled protocols file\n\"%s\": %s.",
2862         gdp_path, strerror(gdp_read_errno));
2863     }
2864     g_free(gdp_path);
2865   }
2866
2867   /* If the user's disabled protocols file exists but we failed to open it,
2868      or had an error reading it, pop up an alert box; we defer that until now,
2869      so that the alert box is more likely to come up on top of the main
2870      window. */
2871   if (dp_path != NULL) {
2872     if (dp_open_errno != 0) {
2873       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2874         "Could not open your disabled protocols file\n\"%s\": %s.", dp_path,
2875         strerror(dp_open_errno));
2876     }
2877     if (dp_read_errno != 0) {
2878       simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
2879         "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path,
2880         strerror(dp_read_errno));
2881     }
2882     g_free(dp_path);
2883   }
2884
2885 #ifdef HAVE_LIBPCAP
2886   if (capture_child) {
2887     /* This is the child process for a sync mode or fork mode capture,
2888        so just do the low-level work of a capture - don't create
2889        a temporary file and fork off *another* child process (so don't
2890        call "do_capture()"). */
2891
2892        /* XXX - hand these stats to the parent process */
2893        capture(&stats_known, &stats);
2894
2895        /* The capture is done; there's nothing more for us to do. */
2896        gtk_exit(0);
2897   } else {
2898     if (start_capture) {
2899       /* "-k" was specified; start a capture. */
2900       if (do_capture(save_file)) {
2901         /* The capture started.  Open tap windows; we do so after creating
2902            the main window, to avoid GTK warnings, and after starting the
2903            capture, so we know we have something to tap. */
2904         if (tap_opt && tli) {
2905           (*tli->func)(tap_opt);
2906           g_free(tap_opt);
2907         }
2908       }
2909       if (save_file != NULL) {
2910         /* Save the directory name for future file dialogs. */
2911         s = get_dirname(save_file);  /* Overwrites save_file */
2912         set_last_open_dir(s);
2913         g_free(save_file);
2914         save_file = NULL;
2915       }
2916     }
2917     else {
2918       set_menus_for_capture_in_progress(FALSE);
2919     }
2920   }
2921
2922   if (!start_capture && (cfile.cfilter == NULL || strlen(cfile.cfilter) == 0)) {
2923     if (cfile.cfilter) {
2924       g_free(cfile.cfilter);
2925     }
2926     cfile.cfilter = g_strdup(get_conn_cfilter());
2927   }
2928 #else
2929   set_menus_for_capture_in_progress(FALSE);
2930 #endif
2931
2932   gtk_main();
2933
2934   epan_cleanup();
2935   g_free(rc_file);
2936
2937 #ifdef WIN32
2938   /* Shutdown windows sockets */
2939   WSACleanup();
2940
2941   /* For some unknown reason, the "atexit()" call in "create_console()"
2942      doesn't arrange that "destroy_console()" be called when we exit,
2943      so we call it here if a console was created. */
2944   if (console_was_created)
2945     destroy_console();
2946 #endif
2947
2948   gtk_exit(0);
2949
2950   /* This isn't reached, but we need it to keep GCC from complaining
2951      that "main()" returns without returning a value - it knows that
2952      "exit()" never returns, but it doesn't know that "gtk_exit()"
2953      doesn't, as GTK+ doesn't declare it with the attribute
2954      "noreturn". */
2955   return 0;     /* not reached */
2956 }
2957
2958 #ifdef WIN32
2959
2960 /* We build this as a GUI subsystem application on Win32, so
2961    "WinMain()", not "main()", gets called.
2962
2963    Hack shamelessly stolen from the Win32 port of the GIMP. */
2964 #ifdef __GNUC__
2965 #define _stdcall  __attribute__((stdcall))
2966 #endif
2967
2968 int _stdcall
2969 WinMain (struct HINSTANCE__ *hInstance,
2970          struct HINSTANCE__ *hPrevInstance,
2971          char               *lpszCmdLine,
2972          int                 nCmdShow)
2973 {
2974   has_no_console = TRUE;
2975   return main (__argc, __argv);
2976 }
2977
2978 /*
2979  * If this application has no console window to which its standard output
2980  * would go, create one.
2981  */
2982 static void
2983 create_console(void)
2984 {
2985   if (has_no_console) {
2986     /* We have no console to which to print the version string, so
2987        create one and make it the standard input, output, and error. */
2988     if (!AllocConsole())
2989       return;   /* couldn't create console */
2990     freopen("CONIN$", "r", stdin);
2991     freopen("CONOUT$", "w", stdout);
2992     freopen("CONOUT$", "w", stderr);
2993
2994     /* Well, we have a console now. */
2995     has_no_console = FALSE;
2996     console_was_created = TRUE;
2997
2998     /* Now register "destroy_console()" as a routine to be called just
2999        before the application exits, so that we can destroy the console
3000        after the user has typed a key (so that the console doesn't just
3001        disappear out from under them, giving the user no chance to see
3002        the message(s) we put in there). */
3003     atexit(destroy_console);
3004   }
3005 }
3006
3007 static void
3008 destroy_console(void)
3009 {
3010   printf("\n\nPress any key to exit\n");
3011   _getch();
3012   FreeConsole();
3013 }
3014
3015 /* This routine should not be necessary, at least as I read the GLib
3016    source code, as it looks as if GLib is, on Win32, *supposed* to
3017    create a console window into which to display its output.
3018
3019    That doesn't happen, however.  I suspect there's something completely
3020    broken about that code in GLib-for-Win32, and that it may be related
3021    to the breakage that forces us to just call "printf()" on the message
3022    rather than passing the message on to "g_log_default_handler()"
3023    (which is the routine that does the aforementioned non-functional
3024    console window creation). */
3025 static void
3026 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
3027                     const char *message, gpointer user_data)
3028 {
3029   create_console();
3030   if (console_was_created) {
3031     /* For some unknown reason, the above doesn't appear to actually cause
3032        anything to be sent to the standard output, so we'll just splat the
3033        message out directly, just to make sure it gets out. */
3034     printf("%s\n", message);
3035   } else
3036     g_log_default_handler(log_domain, log_level, message, user_data);
3037 }
3038 #endif
3039
3040 #if GTK_MAJOR_VERSION < 2
3041 /* Given a font name, construct the name of the next heavier version of
3042    that font. */
3043
3044 #define XLFD_WEIGHT     3       /* index of the "weight" field */
3045
3046 /* Map from a given weight to the appropriate weight for the "bold"
3047    version of a font.
3048    XXX - the XLFD says these strings shouldn't be used for font matching;
3049    can we get the weight, as a number, from GDK, and ask GDK to find us
3050    a font just like the given font, but with the appropriate higher
3051    weight? */
3052 static const struct {
3053         char    *light;
3054         char    *heavier;
3055 } weight_map[] = {
3056         { "ultralight", "light" },
3057         { "extralight", "semilight" },
3058         { "light",      "medium" },
3059         { "semilight",  "semibold" },
3060         { "medium",     "bold" },
3061         { "normal",     "bold" },
3062         { "semibold",   "extrabold" },
3063         { "bold",       "ultrabold" }
3064 };
3065 #define N_WEIGHTS       (sizeof weight_map / sizeof weight_map[0])
3066
3067 char *
3068 font_boldify(const char *font_name)
3069 {
3070         char *bold_font_name;
3071         gchar **xlfd_tokens;
3072         unsigned int i;
3073
3074         /* Is this an XLFD font?  If it begins with "-", yes, otherwise no. */
3075         if (font_name[0] == '-') {
3076                 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
3077
3078                 /*
3079                  * Make sure we *have* a weight (this might not be a valid
3080                  * XLFD font name).
3081                  */
3082                 for (i = 0; i < XLFD_WEIGHT+1; i++) {
3083                         if (xlfd_tokens[i] == NULL) {
3084                                 /*
3085                                  * We don't, so treat this as a non-XLFD
3086                                  * font name.
3087                                  */
3088                                 goto not_xlfd;
3089                         }
3090                 }
3091                 for (i = 0; i < N_WEIGHTS; i++) {
3092                         if (strcmp(xlfd_tokens[XLFD_WEIGHT],
3093                             weight_map[i].light) == 0) {
3094                                 g_free(xlfd_tokens[XLFD_WEIGHT]);
3095                                 xlfd_tokens[XLFD_WEIGHT] =
3096                                     g_strdup(weight_map[i].heavier);
3097                                 break;
3098                         }
3099                 }
3100                 bold_font_name = g_strjoinv("-", xlfd_tokens);
3101                 g_strfreev(xlfd_tokens);
3102                 return bold_font_name;
3103         }
3104
3105 not_xlfd:
3106         /*
3107          * This isn't an XLFD font name; just append "bold" to the name
3108          * of the font.
3109          */
3110         bold_font_name = g_strconcat(font_name, "bold", NULL);
3111         return bold_font_name;
3112 }
3113 #endif
3114
3115 /* Given a font name, construct the name of a version of that font with
3116    the current zoom factor applied. */
3117 static char *
3118 font_zoom(char *gui_font_name)
3119 {
3120     char new_font_name[200];
3121     char *font_name_dup;
3122     char *font_name_p;
3123     long font_point_size_l;
3124 #if GTK_MAJOR_VERSION < 2
3125     int minus_chars;
3126     char *font_foundry;
3127     char *font_family;
3128     char *font_weight;
3129     char *font_slant;
3130     char *font_set_width;
3131     char *font_add_style;
3132     char *font_pixel_size;
3133     char *font_point_size;
3134     char *font_res_x;
3135     char *font_res_y;
3136     char *font_spacing;
3137     char *font_aver_width;
3138     char *font_charset_reg;
3139     char *font_charset_encoding;
3140 #endif
3141
3142     if (recent.gui_zoom_level == 0) {
3143         /* There is no zoom factor - just return the name, so that if
3144            this is GTK+ 1.2[.x] and the font name isn't an XLFD font
3145            name, we don't fail. */
3146         return g_strdup(gui_font_name);
3147     }
3148
3149     font_name_dup = g_strdup(gui_font_name);
3150     font_name_p = font_name_dup;
3151
3152 #if GTK_MAJOR_VERSION >= 2
3153     /* find the start of the font_size string */
3154     font_name_p = strrchr(font_name_dup, ' ');
3155     *font_name_p = '\0';
3156     font_name_p++;
3157
3158     /* calculate the new font size */
3159     font_point_size_l = strtol(font_name_p, NULL, 10);
3160     font_point_size_l += recent.gui_zoom_level;
3161
3162     /* build a new font name */
3163     sprintf(new_font_name, "%s %ld", font_name_dup, font_point_size_l);
3164 #else
3165     minus_chars = 0;
3166     /* replace all '-' chars by NUL and count them */
3167     while ((font_name_p = strchr(font_name_p, '-')) != NULL) {
3168         *font_name_p = '\0';
3169         font_name_p++;
3170         minus_chars++;
3171     }
3172
3173     if (minus_chars != 14) {
3174         /*
3175          * Not a valid XLFD font name.
3176          * XXX - can we try scaling it by looking for a size at the end
3177          * and tweaking that?  Unfortunately, some fonts have numbers
3178          * at the end that aren't, as far as I know, sizes, e.g. "nil2".
3179          */
3180         return NULL;
3181     }
3182
3183     /* first element (font name registry) empty */
3184     font_name_p = font_name_dup;
3185     font_name_p += strlen(font_name_p);
3186     font_name_p++;
3187
3188     /* get pointers to all font name elements */
3189     font_foundry = font_name_p;
3190     font_name_p += strlen(font_name_p);
3191     font_name_p++;
3192
3193     font_family = font_name_p;
3194     font_name_p += strlen(font_name_p);
3195     font_name_p++;
3196
3197     font_weight = font_name_p;
3198     font_name_p += strlen(font_name_p);
3199     font_name_p++;
3200
3201     font_slant = font_name_p;
3202     font_name_p += strlen(font_name_p);
3203     font_name_p++;
3204
3205     font_set_width = font_name_p;
3206     font_name_p += strlen(font_name_p);
3207     font_name_p++;
3208
3209     font_add_style = font_name_p;
3210     font_name_p += strlen(font_name_p);
3211     font_name_p++;
3212
3213     font_pixel_size = font_name_p;
3214     font_name_p += strlen(font_name_p);
3215     font_name_p++;
3216
3217     font_point_size = font_name_p;
3218     font_name_p += strlen(font_name_p);
3219     font_name_p++;
3220
3221     font_res_x = font_name_p;
3222     font_name_p += strlen(font_name_p);
3223     font_name_p++;
3224
3225     font_res_y = font_name_p;
3226     font_name_p += strlen(font_name_p);
3227     font_name_p++;
3228
3229     font_spacing = font_name_p;
3230     font_name_p += strlen(font_name_p);
3231     font_name_p++;
3232
3233     font_aver_width = font_name_p;
3234     font_name_p += strlen(font_name_p);
3235     font_name_p++;
3236
3237     font_charset_reg = font_name_p;
3238     font_name_p += strlen(font_name_p);
3239     font_name_p++;
3240
3241     font_charset_encoding = font_name_p;
3242     font_name_p += strlen(font_name_p);
3243     font_name_p++;
3244
3245     /* calculate the new font size */
3246     font_point_size_l = strtol(font_point_size, NULL, 10);
3247     font_point_size_l += recent.gui_zoom_level*10;
3248     if (font_point_size_l <= 0)
3249         font_point_size_l = 10;
3250
3251     /* build a new font name */
3252     sprintf(new_font_name, "-%s-%s-%s-%s-%s-%s-%s-%ld-%s-%s-%s-%s-%s-%s", 
3253         font_foundry, font_family, font_weight, font_slant, font_set_width, 
3254         font_add_style, font_pixel_size, font_point_size_l, font_res_x,
3255         font_res_y, font_spacing, font_aver_width, font_charset_reg,
3256         font_charset_encoding);
3257 #endif
3258
3259     g_free(font_name_dup);
3260
3261     return g_strdup(new_font_name);
3262 }
3263
3264 fa_ret_t
3265 font_apply(void) {
3266     char *gui_font_name;
3267 #if GTK_MAJOR_VERSION < 2
3268     GdkFont *new_r_font, *new_b_font;
3269     char *bold_font_name;
3270     GdkFont *old_r_font = NULL, *old_b_font = NULL;
3271 #else
3272     PangoFontDescription *new_r_font, *new_b_font;
3273     PangoFontDescription *old_r_font = NULL, *old_b_font = NULL;
3274 #endif
3275
3276     /* convert font name to reflect the zoom level */
3277     gui_font_name = font_zoom(prefs.PREFS_GUI_FONT_NAME);
3278     if (gui_font_name == NULL) {
3279         /*
3280          * This means the font name isn't an XLFD font name.
3281          * We just report that for now as a font not available in
3282          * multiple sizes.
3283          */
3284         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
3285             "Your current font isn't available in any other sizes.\n");
3286         return FA_FONT_NOT_RESIZEABLE;
3287     }
3288
3289 #if GTK_MAJOR_VERSION < 2
3290     new_r_font = gdk_font_load(gui_font_name);
3291     bold_font_name = font_boldify(gui_font_name);
3292     new_b_font = gdk_font_load(bold_font_name);
3293 #else
3294     new_r_font = pango_font_description_from_string(gui_font_name);
3295     new_b_font = pango_font_description_copy(new_r_font);
3296     pango_font_description_set_weight(new_b_font, PANGO_WEIGHT_BOLD);
3297 #endif
3298     if (new_r_font == NULL || new_b_font == NULL) {
3299         /* We're no longer using the new fonts; unreference them. */
3300 #if GTK_MAJOR_VERSION < 2
3301         if (new_r_font != NULL)
3302             gdk_font_unref(new_r_font);
3303         if (new_b_font != NULL)
3304             gdk_font_unref(new_b_font);
3305 #else
3306         if (new_r_font != NULL)
3307             pango_font_description_free(new_r_font);
3308         if (new_b_font != NULL)
3309             pango_font_description_free(new_b_font);
3310 #endif
3311         g_free(gui_font_name);
3312
3313         /* We let our caller pop up a dialog box, as the error message
3314            depends on the context (did they zoom in or out, or did they
3315            do something else? */
3316         return FA_FONT_NOT_AVAILABLE;
3317     }
3318
3319     /* the font(s) seem to be ok */
3320     set_plist_font(new_r_font);
3321     set_ptree_font_all(new_r_font);
3322     old_r_font = m_r_font;
3323     old_b_font = m_b_font;
3324     set_fonts(new_r_font, new_b_font);
3325 #if GTK_MAJOR_VERSION < 2
3326     g_free(bold_font_name);
3327 #endif
3328
3329     /* Redraw the hex dump windows. */
3330     redraw_hex_dump_all();
3331
3332     /* Redraw the "Follow TCP Stream" windows. */
3333     follow_redraw_all();
3334
3335     /* We're no longer using the old fonts; unreference them. */
3336 #if GTK_MAJOR_VERSION < 2
3337     if (old_r_font != NULL)
3338         gdk_font_unref(old_r_font);
3339     if (old_b_font != NULL)
3340         gdk_font_unref(old_b_font);
3341 #else
3342     if (old_r_font != NULL)
3343         pango_font_description_free(old_r_font);
3344     if (old_b_font != NULL)
3345         pango_font_description_free(old_b_font);
3346 #endif
3347     g_free(gui_font_name);
3348     return FA_SUCCESS;
3349 }
3350
3351
3352 #ifdef WIN32
3353
3354 #define NAME_BUFFER_LEN 32
3355
3356 #if GTK_MAJOR_VERSION < 2
3357
3358
3359 /* The setting of the MS default font for system stuff (menus, dialogs, ...),
3360  * coming from: Allin Cottrell, http://www.ecn.wfu.edu/~cottrell/gtk_win32,
3361  * Thank you very much for this! */
3362 int get_windows_font_gtk1(char *fontspec)
3363 {
3364     HDC h_dc;
3365     HGDIOBJ h_font;
3366     TEXTMETRIC tm;
3367     char name[NAME_BUFFER_LEN];
3368     int len, pix_height;
3369
3370     h_dc = CreateDC("DISPLAY", NULL, NULL, NULL);
3371     if (h_dc == NULL) return 1;
3372     h_font = GetStockObject(DEFAULT_GUI_FONT);
3373     if (h_font == NULL || !SelectObject(h_dc, h_font)) {
3374         DeleteDC(h_dc);
3375         return 1;
3376     }
3377     len = GetTextFace(h_dc, NAME_BUFFER_LEN, name);
3378     if (len <= 0) {
3379         DeleteDC(h_dc);
3380         return 1;
3381     }
3382     if (!GetTextMetrics(h_dc, &tm)) {
3383         DeleteDC(h_dc);
3384         return 1;
3385     }
3386     pix_height = tm.tmHeight;
3387     DeleteDC(h_dc);
3388     sprintf(fontspec, "-*-%s-*-*-*-*-%i-*-*-*-p-*-iso8859-1", name,
3389             pix_height);
3390     return 0;
3391 }
3392
3393 void set_app_font_gtk1(GtkWidget *top_level_w)
3394 {
3395     GtkStyle *style;
3396     char winfont[80];
3397  
3398     style = gtk_widget_get_style(top_level);
3399     if (get_windows_font_gtk1(winfont) == 0)
3400         style->font = gdk_font_load(winfont);
3401     if (style->font) gtk_widget_set_style(top_level, style);
3402 }
3403
3404 #else /* GTK_MAJOR_VERSION */
3405 static char appfontname[128] = "tahoma 8";
3406
3407 void set_app_font_gtk2(const char *fontname)
3408 {
3409     GtkSettings *settings;
3410
3411     if (fontname != NULL && *fontname == 0) return;
3412
3413     settings = gtk_settings_get_default();
3414
3415     if (fontname == NULL) {
3416         g_object_set(G_OBJECT(settings), "gtk-font-name", appfontname, NULL);
3417     } else {
3418         GtkWidget *w;
3419         PangoFontDescription *pfd;
3420         PangoContext *pc;
3421         PangoFont *pfont;
3422
3423         w = gtk_label_new(NULL);
3424         pfd = pango_font_description_from_string(fontname);
3425         pc = gtk_widget_get_pango_context(w);
3426         pfont = pango_context_load_font(pc, pfd);
3427
3428         if (pfont != NULL) {
3429             strcpy(appfontname, fontname);
3430             g_object_set(G_OBJECT(settings), "gtk-font-name", appfontname, NULL);
3431         }
3432
3433         gtk_widget_destroy(w);
3434         pango_font_description_free(pfd);
3435     }
3436 }
3437
3438 char *default_windows_menu_fontspec_gtk2(void)
3439 {
3440     gchar *fontspec = NULL;
3441     NONCLIENTMETRICS ncm;
3442
3443     memset(&ncm, 0, sizeof ncm);
3444     ncm.cbSize = sizeof ncm;
3445
3446     if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0)) {
3447         HDC screen = GetDC(0);
3448         double y_scale = 72.0 / GetDeviceCaps(screen, LOGPIXELSY);
3449         int point_size = (int) (ncm.lfMenuFont.lfHeight * y_scale);
3450
3451         if (point_size < 0) point_size = -point_size;
3452         fontspec = g_strdup_printf("%s %d", ncm.lfMenuFont.lfFaceName,
3453                                    point_size);
3454         ReleaseDC(0, screen);
3455     }
3456
3457     return fontspec;
3458 }
3459
3460 static void try_to_get_windows_font_gtk2(void)
3461 {
3462     gchar *fontspec;
3463
3464     fontspec = default_windows_menu_fontspec_gtk2();
3465
3466     if (fontspec != NULL) {
3467         int match = 0;
3468         PangoFontDescription *pfd;
3469         PangoFont *pfont;
3470         PangoContext *pc;
3471         GtkWidget *w;
3472
3473         pfd = pango_font_description_from_string(fontspec);
3474
3475         w = gtk_label_new(NULL);
3476         pc = gtk_widget_get_pango_context(w);
3477         pfont = pango_context_load_font(pc, pfd);
3478         match = (pfont != NULL);
3479
3480         pango_font_description_free(pfd);
3481         g_object_unref(G_OBJECT(pc));
3482         gtk_widget_destroy(w);
3483
3484         if (match) set_app_font_gtk2(fontspec);
3485         g_free(fontspec);
3486     }
3487 }
3488 #endif /* GTK_MAJOR_VERSION */
3489
3490 #endif /* WIN32 */
3491
3492 GtkWidget *info_bar_new(void)
3493 {
3494     /* tip: tooltips don't work on statusbars! */
3495     info_bar = gtk_statusbar_new();
3496     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
3497     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
3498     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
3499 #if GTK_MAJOR_VERSION >= 2
3500     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
3501 #endif
3502     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
3503
3504     return info_bar;
3505 }
3506
3507 GtkWidget *packets_bar_new(void)
3508 {
3509     /* tip: tooltips don't work on statusbars! */
3510     packets_bar = gtk_statusbar_new();
3511     packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
3512     packets_bar_update();
3513
3514     return packets_bar;
3515 }
3516
3517
3518 /*
3519  * Helper for main_widgets_rearrange()
3520  */
3521 void foreach_remove_a_child(GtkWidget *widget, gpointer data) {
3522     gtk_container_remove(GTK_CONTAINER(data), widget);
3523 }
3524
3525 /*
3526  * Rearrange the main window widgets
3527  */
3528 void main_widgets_rearrange(void) {
3529     gint widgets = 0;
3530     GtkWidget *w[10];
3531     /* XXX: add this to the recent settings */
3532     gboolean filter_toolbar_show_in_statusbar = TRUE;
3533
3534
3535     /* be a bit faster */
3536     gtk_widget_hide(main_vbox);
3537
3538     /* be sure, we don't loose a widget while rearranging */
3539     gtk_widget_ref(menubar);
3540     gtk_widget_ref(main_tb);
3541     gtk_widget_ref(filter_tb);
3542     gtk_widget_ref(pkt_scrollw);
3543     gtk_widget_ref(tv_scrollw);
3544     gtk_widget_ref(byte_nb_ptr);
3545     gtk_widget_ref(upper_pane);
3546     gtk_widget_ref(lower_pane);
3547     gtk_widget_ref(stat_hbox);
3548     gtk_widget_ref(info_bar);
3549     gtk_widget_ref(packets_bar);
3550
3551     /* empty all containers participating */
3552     gtk_container_foreach(GTK_CONTAINER(main_vbox),     foreach_remove_a_child, main_vbox);
3553     gtk_container_foreach(GTK_CONTAINER(upper_pane),    foreach_remove_a_child, upper_pane);
3554     gtk_container_foreach(GTK_CONTAINER(lower_pane),    foreach_remove_a_child, lower_pane);
3555     gtk_container_foreach(GTK_CONTAINER(stat_hbox),     foreach_remove_a_child, stat_hbox);
3556
3557     /* add the menubar always at the top */
3558     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
3559
3560     /* main toolbar */
3561     if (recent.main_toolbar_show) {
3562         gtk_box_pack_start(GTK_BOX(main_vbox), main_tb, FALSE, TRUE, 0);
3563     }
3564
3565     /* filter toolbar in toolbar area */
3566     if (recent.filter_toolbar_show && !filter_toolbar_show_in_statusbar) {
3567         gtk_box_pack_start(GTK_BOX(main_vbox), filter_tb, FALSE, TRUE, 1);
3568     }
3569
3570     /* get the info, which and how many of the main widgets should be shown */
3571     if (recent.packet_list_show) {
3572         w[widgets++] = pkt_scrollw;
3573     }
3574
3575     if (recent.tree_view_show) {
3576         w[widgets++] = tv_scrollw;
3577     }
3578
3579     if (recent.byte_view_show) {
3580         w[widgets++] = byte_nb_ptr;
3581     }
3582
3583     /* show the main widgets, depending on their number */
3584     switch(widgets) {
3585     case(0):
3586         break;
3587     case(1):
3588         gtk_container_add(GTK_CONTAINER(main_vbox), w[0]);
3589         break;
3590     case(2):
3591         gtk_container_add(GTK_CONTAINER(main_vbox), upper_pane);
3592         gtk_paned_pack1(GTK_PANED(upper_pane), w[0], TRUE, TRUE);
3593         gtk_paned_pack2(GTK_PANED(upper_pane), w[1], FALSE, FALSE);
3594         break;
3595     case(3):
3596         gtk_container_add(GTK_CONTAINER(main_vbox), upper_pane);
3597         gtk_paned_add1(GTK_PANED(upper_pane), w[0]);
3598         gtk_paned_add2(GTK_PANED(upper_pane), lower_pane);
3599
3600         gtk_paned_pack1(GTK_PANED(lower_pane), w[1], TRUE, TRUE);
3601         gtk_paned_pack2(GTK_PANED(lower_pane), w[2], FALSE, FALSE);
3602         break;
3603     }
3604
3605     /* statusbar hbox */
3606     if ((recent.filter_toolbar_show && filter_toolbar_show_in_statusbar) || recent.statusbar_show) {
3607         gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
3608     }
3609
3610     /* filter toolbar in statusbar hbox */
3611     if (recent.filter_toolbar_show && filter_toolbar_show_in_statusbar) {
3612         gtk_box_pack_start(GTK_BOX(stat_hbox), filter_tb, FALSE, TRUE, 1);
3613     }
3614
3615     /* statusbar */
3616     if (recent.statusbar_show) {
3617         gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
3618         gtk_box_pack_start(GTK_BOX(stat_hbox), packets_bar, TRUE, TRUE, 0);
3619     }
3620
3621     gtk_widget_show(main_vbox);
3622 }
3623
3624 static void