Get rid of unneeded includes of "../ui_util.h".
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.284 2003/03/02 22:31:24 guy 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 #include <gtk/gtk.h>
43
44 #include <string.h>
45 #include <ctype.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #ifdef HAVE_IO_H
52 #include <io.h> /* open/close on win32 */
53 #endif
54
55 #ifdef HAVE_LIBPCAP
56 #include <pcap.h>
57 #endif
58
59 #ifdef HAVE_LIBZ
60 #include <zlib.h>       /* to get the libz version number */
61 #endif
62
63 #ifdef NEED_SNPRINTF_H
64 # include "snprintf.h"
65 #endif
66
67 #ifdef HAVE_SOME_SNMP
68
69 #ifdef HAVE_NET_SNMP
70 #include <net-snmp/version.h>
71 #endif /* HAVE_NET_SNMP */
72
73 #ifdef HAVE_UCD_SNMP
74 #include <ucd-snmp/version.h>
75 #endif /* HAVE_UCD_SNMP */
76
77 #endif /* HAVE_SOME_SNMP */
78
79 #ifdef NEED_STRERROR_H
80 #include "strerror.h"
81 #endif
82
83 #ifdef NEED_GETOPT_H
84 #include "getopt.h"
85 #endif
86
87 #ifdef WIN32 /* Needed for console I/O */
88 #include <fcntl.h>
89 #include <conio.h>
90 #endif
91
92 #include <epan/epan.h>
93 #include <epan/filesystem.h>
94 #include <epan/epan_dissect.h>
95
96 #include "main.h"
97 #include <epan/timestamp.h>
98 #include <epan/packet.h>
99 #include "capture.h"
100 #include "summary.h"
101 #include "file.h"
102 #include "filters.h"
103 #include "prefs.h"
104 #include "menu.h"
105 #include "../menu.h"
106 #include "color.h"
107 #include "color_filters.h"
108 #include "color_utils.h"
109 #include "filter_prefs.h"
110 #include "file_dlg.h"
111 #include "column.h"
112 #include "print.h"
113 #include <epan/resolv.h>
114 #ifdef HAVE_LIBPCAP
115 #include "pcap-util.h"
116 #endif
117 #include "statusbar.h"
118 #include "simple_dialog.h"
119 #include "proto_draw.h"
120 #include <epan/dfilter/dfilter.h>
121 #include "keys.h"
122 #include "packet_win.h"
123 #include "gtkglobals.h"
124 #include <epan/plugins.h>
125 #include "colors.h"
126 #include <epan/strutil.h>
127 #include "register.h"
128 #include "ringbuffer.h"
129 #include "ui_util.h"
130 #include "image/clist_ascend.xpm"
131 #include "image/clist_descend.xpm"
132 #include "../tap.h"
133 #include "compat_macros.h"
134
135 #ifdef WIN32
136 #include "capture-wpcap.h"
137 #endif
138
139 typedef struct column_arrows {
140   GtkWidget *table;
141   GtkWidget *ascend_pm;
142   GtkWidget *descend_pm;
143 } column_arrows;
144
145 capture_file cfile;
146 GtkWidget   *top_level, *packet_list, *tree_view, *byte_nb_ptr,
147             *tv_scrollw, *pkt_scrollw;
148 static GtkWidget        *info_bar;
149 #if GTK_MAJOR_VERSION < 2
150 GdkFont     *m_r_font, *m_b_font;
151 guint        m_font_height, m_font_width;
152 #else
153 PangoFontDescription *m_r_font, *m_b_font;
154 #endif
155 static guint    main_ctx, file_ctx, help_ctx;
156 static GString *comp_info_str;
157 gchar       *ethereal_path = NULL;
158 gchar       *last_open_dir = NULL;
159 gint   root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
160
161 ts_type timestamp_type = RELATIVE;
162
163 #if GTK_MAJOR_VERSION < 2
164 GtkStyle *item_style;
165 #endif
166
167 /* Specifies the field currently selected in the GUI protocol tree */
168 field_info *finfo_selected = NULL;
169
170 #ifdef WIN32
171 static gboolean has_no_console; /* TRUE if app has no console */
172 static gboolean console_was_created; /* TRUE if console was created */
173 static void create_console(void);
174 static void destroy_console(void);
175 static void console_log_handler(const char *log_domain,
176     GLogLevelFlags log_level, const char *message, gpointer user_data);
177 #endif
178
179 static void create_main_window(gint, gint, gint, e_prefs*);
180
181 #define E_DFILTER_CM_KEY          "display_filter_combo"
182 #define E_DFILTER_FL_KEY          "display_filter_list"
183
184 /* About Ethereal window */
185 void
186 about_ethereal( GtkWidget *w _U_, gpointer data _U_ ) {
187   simple_dialog(ESD_TYPE_INFO, NULL,
188                 "Ethereal - Network Protocol Analyzer\n"
189                 "Version " VERSION " (C) 1998-2002 Gerald Combs <gerald@ethereal.com>\n"
190                 "Compiled %s\n\n"
191
192                 "Check the man page for complete documentation and\n"
193                 "for the list of contributors.\n"
194
195                 "\nSee http://www.ethereal.com/ for more information.",
196                  comp_info_str->str);
197 }
198
199 #if GTK_MAJOR_VERSION < 2
200 void
201 set_fonts(GdkFont *regular, GdkFont *bold)
202 #else
203 void
204 set_fonts(PangoFontDescription *regular, PangoFontDescription *bold)
205 #endif
206 {
207         /* Yes, assert. The code that loads the font should check
208          * for NULL and provide its own error message. */
209         g_assert(m_r_font && m_b_font);
210         m_r_font = regular;
211         m_b_font = bold;
212
213 #if GTK_MAJOR_VERSION < 2
214         m_font_height = m_r_font->ascent + m_r_font->descent;
215         m_font_width = gdk_string_width(m_r_font, "0");
216 #endif
217 }
218
219 /*
220  * Go to frame specified by currently selected protocol tree item.
221  */
222 void
223 goto_framenum_cb(GtkWidget *w _U_, gpointer data _U_)
224 {
225     if (finfo_selected) {
226         header_field_info       *hfinfo;
227         guint32                 framenum;
228
229         hfinfo = finfo_selected->hfinfo;
230         g_assert(hfinfo);
231         if (hfinfo->type == FT_FRAMENUM) {
232             framenum = fvalue_get_integer(finfo_selected->value);
233             if (framenum != 0)
234                 goto_frame(&cfile, framenum);
235         }
236     }
237 }
238
239 /* Match selected byte pattern */
240 static void
241 match_selected_cb_do(gpointer data, int action, gchar *text)
242 {
243     GtkWidget           *filter_te;
244     char                *cur_filter, *new_filter;
245
246     if (!text)
247         return;
248     g_assert(data);
249     filter_te = OBJECT_GET_DATA(data, E_DFILTER_TE_KEY);
250     g_assert(filter_te);
251
252     cur_filter = gtk_editable_get_chars(GTK_EDITABLE(filter_te), 0, -1);
253
254     switch (action&MATCH_SELECTED_MASK) {
255
256     case MATCH_SELECTED_REPLACE:
257         new_filter = g_strdup(text);
258         break;
259
260     case MATCH_SELECTED_AND:
261         if ((!cur_filter) || (0 == strlen(cur_filter)))
262             new_filter = g_strdup(text);
263         else
264             new_filter = g_strconcat("(", cur_filter, ") && (", text, ")", NULL);
265         break;
266
267     case MATCH_SELECTED_OR:
268         if ((!cur_filter) || (0 == strlen(cur_filter)))
269             new_filter = g_strdup(text);
270         else
271             new_filter = g_strconcat("(", cur_filter, ") || (", text, ")", NULL);
272         break;
273
274     case MATCH_SELECTED_NOT:
275         new_filter = g_strconcat("!(", text, ")", NULL);
276         break;
277
278     case MATCH_SELECTED_AND_NOT:
279         if ((!cur_filter) || (0 == strlen(cur_filter)))
280             new_filter = g_strconcat("!(", text, ")", NULL);
281         else
282             new_filter = g_strconcat("(", cur_filter, ") && !(", text, ")", NULL);
283         break;
284
285     case MATCH_SELECTED_OR_NOT:
286         if ((!cur_filter) || (0 == strlen(cur_filter)))
287             new_filter = g_strconcat("!(", text, ")", NULL);
288         else
289             new_filter = g_strconcat("(", cur_filter, ") || !(", text, ")", NULL);
290         break;
291
292     default:
293         g_assert_not_reached();
294         new_filter = NULL;
295         break;
296     }
297
298     /* Free up the copy we got of the old filter text. */
299     g_free(cur_filter);
300
301     /* create a new one and set the display filter entry accordingly */
302     gtk_entry_set_text(GTK_ENTRY(filter_te), new_filter);
303
304     /* Run the display filter so it goes in effect. */
305     if (action&MATCH_SELECTED_APPLY_NOW)
306         filter_packets(&cfile, new_filter);
307
308     /* Free up the new filter text. */
309     g_free(new_filter);
310
311     /* Free up the generated text we were handed. */
312     g_free(text);
313 }
314
315 void
316 match_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
317 {
318     if (finfo_selected)
319         match_selected_cb_do((data ? data : w),
320             MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
321             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
322 }
323
324 void
325 match_selected_cb_and_ptree(GtkWidget *w, gpointer data)
326 {
327     if (finfo_selected)
328         match_selected_cb_do((data ? data : w),
329             MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
330             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
331 }
332
333 void
334 match_selected_cb_or_ptree(GtkWidget *w, gpointer data)
335 {
336     if (finfo_selected)
337         match_selected_cb_do((data ? data : w),
338             MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
339             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
340 }
341
342 void
343 match_selected_cb_not_ptree(GtkWidget *w, gpointer data)
344 {
345     if (finfo_selected)
346         match_selected_cb_do((data ? data : w),
347             MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
348             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
349 }
350
351 void
352 match_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
353 {
354     if (finfo_selected)
355         match_selected_cb_do((data ? data : w),
356             MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
357             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
358 }
359
360 void
361 match_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
362 {
363     if (finfo_selected)
364         match_selected_cb_do((data ? data : w),
365             MATCH_SELECTED_OR_NOT,
366             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
367 }
368
369 void
370 prepare_selected_cb_replace_ptree(GtkWidget *w, gpointer data)
371 {
372     if (finfo_selected)
373         match_selected_cb_do((data ? data : w),
374             MATCH_SELECTED_REPLACE,
375             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
376 }
377
378 void
379 prepare_selected_cb_and_ptree(GtkWidget *w, gpointer data)
380 {
381     if (finfo_selected)
382         match_selected_cb_do((data ? data : w),
383             MATCH_SELECTED_AND,
384             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
385 }
386
387 void
388 prepare_selected_cb_or_ptree(GtkWidget *w, gpointer data)
389 {
390     if (finfo_selected)
391         match_selected_cb_do((data ? data : w),
392             MATCH_SELECTED_OR,
393             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
394 }
395
396 void
397 prepare_selected_cb_not_ptree(GtkWidget *w, gpointer data)
398 {
399     if (finfo_selected)
400         match_selected_cb_do((data ? data : w),
401             MATCH_SELECTED_NOT,
402             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
403 }
404
405 void
406 prepare_selected_cb_and_ptree_not(GtkWidget *w, gpointer data)
407 {
408     if (finfo_selected)
409         match_selected_cb_do((data ? data : w),
410             MATCH_SELECTED_AND_NOT,
411             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
412 }
413
414 void
415 prepare_selected_cb_or_ptree_not(GtkWidget *w, gpointer data)
416 {
417     if (finfo_selected)
418         match_selected_cb_do((data ? data : w),
419             MATCH_SELECTED_OR_NOT,
420             proto_alloc_dfilter_string(finfo_selected, cfile.pd));
421 }
422
423 static gchar *
424 get_text_from_packet_list(gpointer data)
425 {
426     gint        row = (gint)OBJECT_GET_DATA(data, E_MPACKET_LIST_ROW_KEY);
427     gint        column = (gint)OBJECT_GET_DATA(data, E_MPACKET_LIST_COL_KEY);
428     frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
429     epan_dissect_t *edt;
430     gchar      *buf=NULL;
431     int         len;
432     int         err;
433
434     if (fdata != NULL) {
435         /* XXX - do something with "err" */
436         wtap_seek_read(cfile.wth, fdata->file_off, &cfile.pseudo_header,
437                        cfile.pd, fdata->cap_len, &err);
438
439         edt = epan_dissect_new(FALSE, FALSE);
440         epan_dissect_run(edt, &cfile.pseudo_header, cfile.pd, fdata,
441                          &cfile.cinfo);
442         epan_dissect_fill_in_columns(edt);
443
444         if (strlen(cfile.cinfo.col_expr[column]) != 0 &&
445             strlen(cfile.cinfo.col_expr_val[column]) != 0) {
446             len = strlen(cfile.cinfo.col_expr[column]) +
447                   strlen(cfile.cinfo.col_expr_val[column]) + 5;
448             buf = g_malloc0(len);
449             snprintf(buf, len, "%s == %s", cfile.cinfo.col_expr[column],
450                      cfile.cinfo.col_expr_val[column]);
451         }
452
453         epan_dissect_free(edt);
454     }
455
456     return buf;
457 }
458
459 void
460 match_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
461 {
462     match_selected_cb_do(data,
463         MATCH_SELECTED_REPLACE|MATCH_SELECTED_APPLY_NOW,
464         get_text_from_packet_list(data));
465 }
466
467 void
468 match_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
469 {
470     match_selected_cb_do(data,
471         MATCH_SELECTED_AND|MATCH_SELECTED_APPLY_NOW,
472         get_text_from_packet_list(data));
473 }
474
475 void
476 match_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
477 {
478     match_selected_cb_do(data,
479         MATCH_SELECTED_OR|MATCH_SELECTED_APPLY_NOW,
480         get_text_from_packet_list(data));
481 }
482
483 void
484 match_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
485 {
486     match_selected_cb_do(data,
487         MATCH_SELECTED_NOT|MATCH_SELECTED_APPLY_NOW,
488         get_text_from_packet_list(data));
489 }
490
491 void
492 match_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
493 {
494     match_selected_cb_do(data,
495         MATCH_SELECTED_AND_NOT|MATCH_SELECTED_APPLY_NOW,
496         get_text_from_packet_list(data));
497 }
498
499 void
500 match_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
501 {
502     match_selected_cb_do(data,
503         MATCH_SELECTED_OR_NOT|MATCH_SELECTED_APPLY_NOW,
504         get_text_from_packet_list(data));
505 }
506
507 void
508 prepare_selected_cb_replace_plist(GtkWidget *w _U_, gpointer data)
509 {
510     match_selected_cb_do(data,
511         MATCH_SELECTED_REPLACE,
512         get_text_from_packet_list(data));
513 }
514
515 void
516 prepare_selected_cb_and_plist(GtkWidget *w _U_, gpointer data)
517 {
518     match_selected_cb_do(data,
519         MATCH_SELECTED_AND,
520         get_text_from_packet_list(data));
521 }
522
523 void
524 prepare_selected_cb_or_plist(GtkWidget *w _U_, gpointer data)
525 {
526     match_selected_cb_do(data,
527         MATCH_SELECTED_OR,
528         get_text_from_packet_list(data));
529 }
530
531 void
532 prepare_selected_cb_not_plist(GtkWidget *w _U_, gpointer data)
533 {
534     match_selected_cb_do(data,
535         MATCH_SELECTED_NOT,
536         get_text_from_packet_list(data));
537 }
538
539 void
540 prepare_selected_cb_and_plist_not(GtkWidget *w _U_, gpointer data)
541 {
542     match_selected_cb_do(data,
543         MATCH_SELECTED_AND_NOT,
544         get_text_from_packet_list(data));
545 }
546
547 void
548 prepare_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data)
549 {
550     match_selected_cb_do(data,
551         MATCH_SELECTED_OR_NOT,
552         get_text_from_packet_list(data));
553 }
554
555 /* Run the current display filter on the current packet set, and
556    redisplay. */
557 static void
558 filter_activate_cb(GtkWidget *w, gpointer data)
559 {
560   GtkCombo  *filter_cm = OBJECT_GET_DATA(w, E_DFILTER_CM_KEY);
561   GList     *filter_list = OBJECT_GET_DATA(filter_cm, E_DFILTER_FL_KEY);
562   GList     *li;
563   gboolean   add_filter = TRUE;
564   gboolean   free_filter = TRUE;
565   char      *s;
566
567   g_assert(data);
568   s = g_strdup(gtk_entry_get_text(GTK_ENTRY(data)));
569
570   /* GtkCombos don't let us get at their list contents easily, so we maintain
571      our own filter list, and feed it to gtk_combo_set_popdown_strings when
572      a new filter is added. */
573   if (filter_packets(&cfile, s)) {
574     li = g_list_first(filter_list);
575     while (li) {
576       if (li->data && strcmp(s, li->data) == 0)
577         add_filter = FALSE;
578       li = li->next;
579     }
580
581     if (add_filter) {
582       free_filter = FALSE;
583       filter_list = g_list_append(filter_list, s);
584       OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
585       gtk_combo_set_popdown_strings(filter_cm, filter_list);
586       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
587     }
588   }
589   if (free_filter)
590     g_free(s);
591 }
592
593 /* redisplay with no display filter */
594 static void
595 filter_reset_cb(GtkWidget *w, gpointer data _U_)
596 {
597   GtkWidget *filter_te = NULL;
598
599   if ((filter_te = OBJECT_GET_DATA(w, E_DFILTER_TE_KEY))) {
600     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
601   }
602   filter_packets(&cfile, NULL);
603 }
604
605 /* GTKClist compare routine, overrides default to allow numeric comparison */
606 static gint
607 packet_list_compare(GtkCList *clist, gconstpointer  ptr1, gconstpointer  ptr2)
608 {
609   /* Get row text strings */
610   char *text1 = GTK_CELL_TEXT (((const GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
611   char *text2 = GTK_CELL_TEXT (((const GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
612
613   /* Attempt to convert to numbers */
614   double  num1 = atof(text1);
615   double  num2 = atof(text2);
616
617   gint  col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
618
619   if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
620       ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
621       ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA))    ||
622       (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
623       ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
624                                       (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
625       (col_fmt == COL_PACKET_LENGTH)) {
626
627     /* Compare numeric column */
628
629     if (num1 < num2)
630       return -1;
631     else if (num1 > num2)
632       return 1;
633     else
634       return 0;
635   }
636
637   else {
638
639     /* Compare text column */
640     if (!text2)
641       return (text1 != NULL);
642
643     if (!text1)
644       return -1;
645
646     return strcmp(text1, text2);
647   }
648 }
649
650 /* What to do when a column is clicked */
651 static void
652 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
653 {
654   column_arrows *col_arrows = (column_arrows *) data;
655   int i;
656
657   gtk_clist_freeze(clist);
658
659   for (i = 0; i < cfile.cinfo.num_cols; i++) {
660     gtk_widget_hide(col_arrows[i].ascend_pm);
661     gtk_widget_hide(col_arrows[i].descend_pm);
662   }
663
664   if (column == clist->sort_column) {
665     if (clist->sort_type == GTK_SORT_ASCENDING) {
666       clist->sort_type = GTK_SORT_DESCENDING;
667       gtk_widget_show(col_arrows[column].descend_pm);
668     } else {
669       clist->sort_type = GTK_SORT_ASCENDING;
670       gtk_widget_show(col_arrows[column].ascend_pm);
671     }
672   }
673   else {
674     clist->sort_type = GTK_SORT_ASCENDING;
675     gtk_widget_show(col_arrows[column].ascend_pm);
676     gtk_clist_set_sort_column(clist, column);
677   }
678   gtk_clist_thaw(clist);
679
680   gtk_clist_sort(clist);
681 }
682
683 /* mark packets */
684 static void
685 set_frame_mark(gboolean set, frame_data *frame, gint row) {
686   GdkColor fg, bg;
687
688   if (row == -1)
689     return;
690   if (set) {
691     mark_frame(&cfile, frame);
692     color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
693     color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
694     gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
695     gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
696   } else {
697     unmark_frame(&cfile, frame);
698     gtk_clist_set_background(GTK_CLIST(packet_list), row, NULL);
699     gtk_clist_set_foreground(GTK_CLIST(packet_list), row, NULL);
700   }
701   file_set_save_marked_sensitive();
702 }
703
704 #if GTK_MAJOR_VERSION < 2
705 static void
706 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
707 {
708     GdkEventButton *event_button = (GdkEventButton *)event;
709     gint row, column;
710
711     if (w == NULL || event == NULL)
712         return;
713
714     if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
715         gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
716                                      event_button->y, &row, &column)) {
717         frame_data *fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w),
718                                                                   row);
719         set_frame_mark(!fdata->flags.marked, fdata, row);
720     }
721 }
722 #else
723 static gint
724 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
725 {
726     GdkEventButton *event_button = (GdkEventButton *)event;
727     gint row, column;
728
729     if (w == NULL || event == NULL)
730         return FALSE;
731
732     if (event->type == GDK_BUTTON_PRESS &&
733         gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
734                                      event_button->y, &row, &column)) {
735         if (event_button->button == 2)
736         {
737             frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w), row);
738             set_frame_mark(!fdata->flags.marked, fdata, row);
739             return TRUE;
740         }
741         else if (event_button->button == 1) {
742             gtk_clist_select_row(GTK_CLIST(w), row, column);
743             return TRUE;
744         }
745     }
746     return FALSE;
747 }
748 #endif
749
750 void mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
751   if (cfile.current_frame) {
752     /* XXX hum, should better have a "cfile->current_row" here ... */
753     set_frame_mark(!cfile.current_frame->flags.marked,
754                    cfile.current_frame,
755                    gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
756                                                 cfile.current_frame));
757   }
758 }
759
760 static void mark_all_frames(gboolean set) {
761   frame_data *fdata;
762   for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
763     set_frame_mark(set,
764                    fdata,
765                    gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
766   }
767 }
768
769 void update_marked_frames(void) {
770   frame_data *fdata;
771   if (cfile.plist == NULL) return;
772   for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
773     if (fdata->flags.marked)
774       set_frame_mark(TRUE,
775                      fdata,
776                      gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
777                                                   fdata));
778   }
779 }
780
781 void mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
782   mark_all_frames(TRUE);
783 }
784
785 void unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
786   mark_all_frames(FALSE);
787 }
788
789 /* What to do when a list item is selected/unselected */
790 static void
791 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
792
793 /* Remove the hex display tabbed pages */
794   while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
795     gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
796
797   select_packet(&cfile, row);
798 }
799
800
801 static void
802 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
803
804   unselect_packet(&cfile);
805 }
806
807
808 #if GTK_MAJOR_VERSION < 2
809 static void
810 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column _U_,
811                         gpointer user_data _U_)
812 #else
813 static void
814 tree_view_selection_changed_cb(GtkTreeSelection *sel, gpointer user_data _U_)
815 #endif
816 {
817     field_info   *finfo;
818     gchar        *help_str = NULL;
819     gchar         len_str[2+10+1+5+1]; /* ", {N} bytes\0",
820                                           N < 4294967296 */
821     gboolean      has_blurb = FALSE;
822     guint         length = 0, byte_len;
823     GtkWidget    *byte_view;
824     const guint8 *byte_data;
825 #if GTK_MAJOR_VERSION >= 2
826     GtkTreeModel *model;
827     GtkTreeIter   iter;
828 #endif
829
830 #if GTK_MAJOR_VERSION >= 2
831     /* if nothing is selected */
832     if (!gtk_tree_selection_get_selected(sel, &model, &iter))
833     {
834         /*
835          * Which byte view is displaying the current protocol tree
836          * row's data?
837          */
838         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
839         if (byte_view == NULL)
840             return;     /* none */
841
842         byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
843         if (byte_data == NULL)
844             return;     /* none */
845
846         unselect_field();
847         packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data,
848                          cfile.current_frame, NULL, byte_len);
849         return;
850     }
851     gtk_tree_model_get(model, &iter, 1, &finfo, -1);
852 #else
853     g_assert(node);
854     finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
855 #endif
856     if (!finfo) return;
857
858     set_notebook_page(byte_nb_ptr, finfo->ds_tvb);
859
860     byte_view = get_notebook_bv_ptr(byte_nb_ptr);
861     byte_data = get_byte_view_data_and_length(byte_view, &byte_len);
862     g_assert(byte_data != NULL);
863
864     finfo_selected = finfo;
865     set_menus_for_selected_tree_row(TRUE);
866
867     if (finfo->hfinfo) {
868         if (finfo->hfinfo->blurb != NULL &&
869             finfo->hfinfo->blurb[0] != '\0') {
870             has_blurb = TRUE;
871             length = strlen(finfo->hfinfo->blurb);
872         } else {
873             length = strlen(finfo->hfinfo->name);
874         }
875         if (finfo->length == 0) {
876             len_str[0] = '\0';
877         } else if (finfo->length == 1) {
878             strcpy (len_str, ", 1 byte");
879         } else {
880             snprintf (len_str, sizeof len_str, ", %d bytes", finfo->length);
881         }
882         statusbar_pop_field_msg();      /* get rid of current help msg */
883         if (length) {
884             length += strlen(finfo->hfinfo->abbrev) + strlen(len_str) + 10;
885             help_str = g_malloc(sizeof(gchar) * length);
886             sprintf(help_str, "%s (%s)%s",
887                     (has_blurb) ? finfo->hfinfo->blurb : finfo->hfinfo->name,
888                     finfo->hfinfo->abbrev, len_str);
889             statusbar_push_field_msg(help_str);
890             g_free(help_str);
891         } else {
892             /*
893              * Don't show anything if the field name is zero-length;
894              * the pseudo-field for "proto_tree_add_text()" is such
895              * a field, and we don't want "Text (text)" showing up
896              * on the status line if you've selected such a field.
897              *
898              * XXX - there are zero-length fields for which we *do*
899              * want to show the field name.
900              *
901              * XXX - perhaps the name and abbrev field should be null
902              * pointers rather than null strings for that pseudo-field,
903              * but we'd have to add checks for null pointers in some
904              * places if we did that.
905              *
906              * Or perhaps protocol tree items added with
907              * "proto_tree_add_text()" should have -1 as the field index,
908              * with no pseudo-field being used, but that might also
909              * require special checks for -1 to be added.
910              */
911             statusbar_push_field_msg("");
912         }
913     }
914
915 #if GTK_MAJOR_VERSION < 2
916     packet_hex_print(GTK_TEXT(byte_view), byte_data, cfile.current_frame,
917                      finfo, byte_len);
918 #else
919     packet_hex_print(GTK_TEXT_VIEW(byte_view), byte_data, cfile.current_frame,
920                      finfo, byte_len);
921 #endif
922 }
923
924 #if GTK_MAJOR_VERSION < 2
925 static void
926 tree_view_unselect_row_cb(GtkCTree *ctree _U_, GList *node _U_, gint column _U_,
927                           gpointer user_data _U_)
928 {
929         GtkWidget       *byte_view;
930         const guint8    *data;
931         guint           len;
932
933         /*
934          * Which byte view is displaying the current protocol tree
935          * row's data?
936          */
937         byte_view = get_notebook_bv_ptr(byte_nb_ptr);
938         if (byte_view == NULL)
939                 return; /* none */
940
941         data = get_byte_view_data_and_length(byte_view, &len);
942         if (data == NULL)
943                 return; /* none */
944
945         unselect_field();
946         packet_hex_print(GTK_TEXT(byte_view), data, cfile.current_frame,
947                 NULL, len);
948 }
949 #endif
950
951 void collapse_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
952   if (cfile.edt->tree)
953     collapse_all_tree(cfile.edt->tree, tree_view);
954 }
955
956 void expand_all_cb(GtkWidget *widget _U_, gpointer data _U_) {
957   if (cfile.edt->tree)
958     expand_all_tree(cfile.edt->tree, tree_view);
959 }
960
961 void resolve_name_cb(GtkWidget *widget _U_, gpointer data _U_) {
962   if (cfile.edt->tree) {
963     guint32 tmp = g_resolv_flags;
964     g_resolv_flags = RESOLV_ALL;
965     proto_tree_draw(cfile.edt->tree, tree_view);
966     g_resolv_flags = tmp;
967   }
968 }
969
970 /* Set the selection mode of the packet list window. */
971 void
972 set_plist_sel_browse(gboolean val)
973 {
974         gboolean old_val;
975
976         old_val =
977             (GTK_CLIST(packet_list)->selection_mode == GTK_SELECTION_SINGLE);
978
979         if (val == old_val) {
980                 /*
981                  * The mode isn't changing, so don't do anything.
982                  * In particular, don't gratuitiously unselect the
983                  * current packet.
984                  *
985                  * XXX - why do we have to unselect the current packet
986                  * ourselves?  The documentation for the GtkCList at
987                  *
988                  *      http://developer.gnome.org/doc/API/gtk/gtkclist.html
989                  *
990                  * says "Note that setting the widget's selection mode to
991                  * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
992                  * cause all the items in the GtkCList to become deselected."
993                  */
994                 return;
995         }
996
997         if (finfo_selected)
998                 unselect_packet(&cfile);
999
1000         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
1001          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
1002         if (val) {
1003                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
1004         }
1005         else {
1006                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
1007         }
1008 }
1009
1010 /* Set the font of the packet list window. */
1011 #if GTK_MAJOR_VERSION < 2
1012 void
1013 set_plist_font(GdkFont *font)
1014 #else
1015 void
1016 set_plist_font(PangoFontDescription *font)
1017 #endif
1018 {
1019         int i;
1020 #if GTK_MAJOR_VERSION < 2
1021         GtkStyle *style;
1022
1023         style = gtk_style_new();
1024         gdk_font_unref(style->font);
1025         style->font = font;
1026         gdk_font_ref(font);
1027
1028         gtk_widget_set_style(packet_list, style);
1029 #else
1030         PangoLayout *layout;
1031
1032         gtk_widget_modify_font(packet_list, font);
1033 #endif
1034
1035         /* Compute static column sizes to use during a "-S" capture, so that
1036            the columns don't resize during a live capture. */
1037         for (i = 0; i < cfile.cinfo.num_cols; i++) {
1038 #if GTK_MAJOR_VERSION < 2
1039                 cfile.cinfo.col_width[i] = gdk_string_width(font,
1040                         get_column_longest_string(get_column_format(i)));
1041 #else
1042                 layout = gtk_widget_create_pango_layout(packet_list,
1043                     get_column_longest_string(get_column_format(i)));
1044                 pango_layout_get_pixel_size(layout, &cfile.cinfo.col_width[i],
1045                                             NULL);
1046                 g_object_unref(G_OBJECT(layout));
1047 #endif
1048         }
1049 }
1050
1051 /*
1052  * Push a message referring to file access onto the statusbar.
1053  */
1054 void
1055 statusbar_push_file_msg(gchar *msg)
1056 {
1057         gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
1058 }
1059
1060 /*
1061  * Pop a message referring to file access off the statusbar.
1062  */
1063 void
1064 statusbar_pop_file_msg(void)
1065 {
1066         gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
1067 }
1068
1069 /*
1070  * XXX - do we need multiple statusbar contexts?
1071  */
1072
1073 /*
1074  * Push a message referring to the currently-selected field onto the statusbar.
1075  */
1076 void
1077 statusbar_push_field_msg(gchar *msg)
1078 {
1079         gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
1080 }
1081
1082 /*
1083  * Pop a message referring to the currently-selected field off the statusbar.
1084  */
1085 void
1086 statusbar_pop_field_msg(void)
1087 {
1088         gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
1089 }
1090
1091 static gboolean
1092 do_quit(void)
1093 {
1094         /* XXX - should we check whether the capture file is an
1095            unsaved temporary file for a live capture and, if so,
1096            pop up a "do you want to exit without saving the capture
1097            file?" dialog, and then just return, leaving said dialog
1098            box to forcibly quit if the user clicks "OK"?
1099
1100            If so, note that this should be done in a subroutine that
1101            returns TRUE if we do so, and FALSE otherwise, and if it
1102            returns TRUE we should return TRUE without nuking anything.
1103
1104            Note that, if we do that, we might also want to check if
1105            an "Update list of packets in real time" capture is in
1106            progress and, if so, ask whether they want to terminate
1107            the capture and discard it, and return TRUE, before nuking
1108            any child capture, if they say they don't want to do so. */
1109
1110 #ifdef HAVE_LIBPCAP
1111         /* Nuke any child capture in progress. */
1112         kill_capture_child();
1113 #endif
1114
1115         /* Are we in the middle of reading a capture? */
1116         if (cfile.state == FILE_READ_IN_PROGRESS) {
1117                 /* Yes, so we can't just close the file and quit, as
1118                    that may yank the rug out from under the read in
1119                    progress; instead, just set the state to
1120                    "FILE_READ_ABORTED" and return - the code doing the read
1121                    will check for that and, if it sees that, will clean
1122                    up and quit. */
1123                 cfile.state = FILE_READ_ABORTED;
1124
1125                 /* Say that the window should *not* be deleted;
1126                    that'll be done by the code that cleans up. */
1127                 return TRUE;
1128         } else {
1129                 /* Close any capture file we have open; on some OSes, you
1130                    can't unlink a temporary capture file if you have it
1131                    open.
1132                    "close_cap_file()" will unlink it after closing it if
1133                    it's a temporary file.
1134
1135                    We do this here, rather than after the main loop returns,
1136                    as, after the main loop returns, the main window may have
1137                    been destroyed (if this is called due to a "destroy"
1138                    even on the main window rather than due to the user
1139                    selecting a menu item), and there may be a crash
1140                    or other problem when "close_cap_file()" tries to
1141                    clean up stuff in the main window.
1142
1143                    XXX - is there a better place to put this?
1144                    Or should we have a routine that *just* closes the
1145                    capture file, and doesn't do anything with the UI,
1146                    which we'd call here, and another routine that
1147                    calls that routine and also cleans up the UI, which
1148                    we'd call elsewhere? */
1149                 close_cap_file(&cfile);
1150
1151                 /* Exit by leaving the main loop, so that any quit functions
1152                    we registered get called. */
1153                 gtk_main_quit();
1154
1155                 /* Say that the window should be deleted. */
1156                 return FALSE;
1157         }
1158 }
1159
1160 static gboolean
1161 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
1162 {
1163         gint desk_x, desk_y;
1164
1165         /* Try to grab our geometry */
1166         gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
1167         if (gdk_window_get_deskrelative_origin(top_level->window,
1168                                 &desk_x, &desk_y)) {
1169                 if (desk_x <= root_x && desk_y <= root_y) {
1170                         root_x = desk_x;
1171                         root_y = desk_y;
1172                 }
1173         }
1174
1175         /* XXX - Is this the "approved" method? */
1176         gdk_window_get_size(top_level->window, &top_width, &top_height);
1177
1178         /* "do_quit()" indicates whether the main window should be deleted. */
1179         return do_quit();
1180 }
1181
1182 void
1183 file_quit_cmd_cb (GtkWidget *widget _U_, gpointer data _U_)
1184 {
1185         do_quit();
1186 }
1187
1188 static void
1189 print_usage(gboolean print_ver) {
1190
1191   if (print_ver) {
1192     fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled %s\n",
1193           comp_info_str->str);
1194   }
1195 #ifdef HAVE_LIBPCAP
1196   fprintf(stderr, "\n%s [ -vh ] [ -klpQS ] [ -a <capture autostop condition> ] ...\n",
1197           PACKAGE);
1198   fprintf(stderr, "\t[ -b <number of ringbuffer files> ] [ -B <byte view height> ]\n");
1199   fprintf(stderr, "\t[ -c <count> ] [ -f <capture filter> ] [ -i <interface> ]\n");
1200   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -N <resolving> ]\n");
1201   fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
1202   fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
1203   fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
1204   fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n");
1205 #else
1206   fprintf(stderr, "\n%s [ -vh ] [ -B <byte view height> ] [ -m <medium font> ]\n",
1207           PACKAGE);
1208   fprintf(stderr, "\t[ -n ] [ -N <resolving> ]\n");
1209   fprintf(stderr, "\t[ -o <preference setting> ... [ -P <packet list height> ]\n");
1210   fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -t <time stamp format> ]\n");
1211   fprintf(stderr, "\t[ -T <tree view height> ] [ <infile> ]\n");
1212 #endif
1213 }
1214
1215 static void
1216 show_version(void)
1217 {
1218 #ifdef WIN32
1219   create_console();
1220 #endif
1221
1222   printf("%s %s, %s\n", PACKAGE, VERSION, comp_info_str->str);
1223 }
1224
1225 static int
1226 get_positive_int(const char *string, const char *name)
1227 {
1228   long number;
1229   char *p;
1230
1231   number = strtol(string, &p, 10);
1232   if (p == string || *p != '\0') {
1233     fprintf(stderr, "ethereal: The specified %s \"%s\" is not a decimal number\n",
1234             name, string);
1235     exit(1);
1236   }
1237   if (number < 0) {
1238     fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
1239             name, string);
1240     exit(1);
1241   }
1242   if (number == 0) {
1243     fprintf(stderr, "ethereal: The specified %s \"%s\" is zero\n",
1244             name, string);
1245     exit(1);
1246   }
1247   if (number > INT_MAX) {
1248     fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
1249             name, string, INT_MAX);
1250     exit(1);
1251   }
1252   return number;
1253 }
1254
1255 #ifdef HAVE_LIBPCAP
1256 /*
1257  * Given a string of the form "<autostop criterion>:<value>", as might appear
1258  * as an argument to a "-a" option, parse it and set the criterion in
1259  * question.  Return an indication of whether it succeeded or failed
1260  * in some fashion.
1261  */
1262 static gboolean
1263 set_autostop_criterion(const char *autostoparg)
1264 {
1265   guchar *p, *colonp;
1266
1267   colonp = strchr(autostoparg, ':');
1268   if (colonp == NULL)
1269     return FALSE;
1270
1271   p = colonp;
1272   *p++ = '\0';
1273
1274   /*
1275    * Skip over any white space (there probably won't be any, but
1276    * as we allow it in the preferences file, we might as well
1277    * allow it here).
1278    */
1279   while (isspace(*p))
1280     p++;
1281   if (*p == '\0') {
1282     /*
1283      * Put the colon back, so if our caller uses, in an
1284      * error message, the string they passed us, the message
1285      * looks correct.
1286      */
1287     *colonp = ':';
1288     return FALSE;
1289   }
1290   if (strcmp(autostoparg,"duration") == 0) {
1291     capture_opts.has_autostop_duration = TRUE;
1292     capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
1293   } else if (strcmp(autostoparg,"filesize") == 0) {
1294     capture_opts.has_autostop_filesize = TRUE;
1295     capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
1296   } else {
1297     return FALSE;
1298   }
1299   *colonp = ':'; /* put the colon back */
1300   return TRUE;
1301 }
1302 #endif
1303
1304 #if defined WIN32 || GTK_MAJOR_VERSION < 2
1305 /* 
1306    Once every 3 seconds we get a callback here which we use to update
1307    the tap extensions. Since Gtk1 is single threaded we dont have to
1308    worry about any locking or critical regions.
1309  */
1310 static gint
1311 update_cb(gpointer data _U_)
1312 {
1313         draw_tap_listeners(FALSE);
1314         return 1;
1315 }
1316 #else
1317
1318 /* if these three functions are copied to gtk1 ethereal, since gtk1 does not
1319    use threads all updte_thread_mutex can be dropped and protect/unprotect 
1320    would just be empty functions.
1321
1322    This allows gtk2-rpcstat.c and friends to be copied unmodified to 
1323    gtk1-ethereal and it will just work.
1324  */
1325 static GStaticMutex update_thread_mutex = G_STATIC_MUTEX_INIT;
1326 gpointer
1327 update_thread(gpointer data _U_)
1328 {
1329     while(1){
1330         GTimeVal tv1, tv2;
1331         g_get_current_time(&tv1);
1332         g_static_mutex_lock(&update_thread_mutex);
1333         gdk_threads_enter();
1334         draw_tap_listeners(FALSE);
1335         gdk_threads_leave();
1336         g_static_mutex_unlock(&update_thread_mutex);
1337         g_thread_yield();
1338         g_get_current_time(&tv2);
1339         if( ((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) >
1340             (tv2.tv_sec * 1000000 + tv2.tv_usec) ){
1341             g_usleep(((tv1.tv_sec + 2) * 1000000 + tv1.tv_usec) -
1342                      (tv2.tv_sec * 1000000 + tv2.tv_usec));
1343         }
1344     }
1345     return NULL;
1346 }
1347 #endif
1348 void
1349 protect_thread_critical_region(void)
1350 {
1351 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2
1352     g_static_mutex_lock(&update_thread_mutex);
1353 #endif
1354 }
1355 void
1356 unprotect_thread_critical_region(void)
1357 {
1358 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2
1359     g_static_mutex_unlock(&update_thread_mutex);
1360 #endif
1361 }
1362
1363 /* structure to keep track of what tap listeners have been registered.
1364  */
1365 typedef struct _ethereal_tap_list {
1366         struct _ethereal_tap_list *next;
1367         char *cmd;
1368         void (*func)(char *arg);
1369 } ethereal_tap_list;
1370 static ethereal_tap_list *tap_list=NULL;
1371
1372 void
1373 register_ethereal_tap(char *cmd, void (*func)(char *arg), char *dummy _U_, void (*dummy2)(void) _U_)
1374 {
1375         ethereal_tap_list *newtl;
1376
1377         newtl=malloc(sizeof(ethereal_tap_list));
1378         newtl->next=tap_list;
1379         tap_list=newtl;
1380         newtl->cmd=cmd;
1381         newtl->func=func;
1382
1383 }
1384
1385 /* And now our feature presentation... [ fade to music ] */
1386 int
1387 main(int argc, char *argv[])
1388 {
1389 #ifdef HAVE_LIBPCAP
1390   char                *command_name;
1391 #endif
1392   char                *s;
1393   int                  i;
1394   int                  opt;
1395   extern char         *optarg;
1396   gboolean             arg_error = FALSE;
1397 #ifdef HAVE_LIBPCAP
1398 #ifdef HAVE_PCAP_VERSION
1399   extern char          pcap_version[];
1400 #endif /* HAVE_PCAP_VERSION */
1401 #endif /* HAVE_LIBPCAP */
1402
1403 #ifdef WIN32
1404   WSADATA              wsaData;
1405 #endif  /* WIN32 */
1406
1407   char                *gpf_path, *cf_path, *df_path;
1408   char                *pf_path;
1409   int                  gpf_open_errno, pf_open_errno, cf_open_errno, df_open_errno;
1410   int                  err;
1411 #ifdef HAVE_LIBPCAP
1412   gboolean             start_capture = FALSE;
1413   gchar               *save_file = NULL;
1414   GList               *if_list;
1415   gchar                err_str[PCAP_ERRBUF_SIZE];
1416   gboolean             stats_known;
1417   struct pcap_stat     stats;
1418 #else
1419   gboolean             capture_option_specified = FALSE;
1420 #endif
1421   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1422   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1423   dfilter_t           *rfcode = NULL;
1424   gboolean             rfilter_parse_failed = FALSE;
1425   e_prefs             *prefs;
1426   char                 badopt;
1427 #if GTK_MAJOR_VERSION < 2
1428   char                *bold_font_name;
1429 #endif
1430   gint                 desk_x, desk_y;
1431   gboolean             prefs_write_needed = FALSE;
1432   ethereal_tap_list   *tli = NULL;
1433   gchar               *tap_opt = NULL;
1434
1435 #define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vz:"
1436
1437 #ifdef HAVE_LIBPCAP
1438 #ifdef WIN32
1439 #define OPTSTRING_CHILD "W:Z:"
1440 #else
1441 #define OPTSTRING_CHILD "W:"
1442 #endif  /* WIN32 */
1443 #else
1444 #define OPTSTRING_CHILD ""
1445 #endif  /* HAVE_LIBPCAP */
1446
1447   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_CHILD) - 1] =
1448     OPTSTRING_INIT;
1449
1450   ethereal_path = argv[0];
1451
1452 #ifdef WIN32
1453   /* Arrange that if we have no console window, and a GLib message logging
1454      routine is called to log a message, we pop up a console window.
1455
1456      We do that by inserting our own handler for all messages logged
1457      to the default domain; that handler pops up a console if necessary,
1458      and then calls the default handler. */
1459   g_log_set_handler(NULL,
1460                     G_LOG_LEVEL_ERROR|
1461                     G_LOG_LEVEL_CRITICAL|
1462                     G_LOG_LEVEL_WARNING|
1463                     G_LOG_LEVEL_MESSAGE|
1464                     G_LOG_LEVEL_INFO|
1465                     G_LOG_LEVEL_DEBUG|
1466                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION,
1467                     console_log_handler, NULL);
1468 #endif
1469
1470 #ifdef HAVE_LIBPCAP
1471   command_name = get_basename(ethereal_path);
1472   /* Set "capture_child" to indicate whether this is going to be a child
1473      process for a "-S" capture. */
1474   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1475   if (capture_child)
1476     strcat(optstring, OPTSTRING_CHILD);
1477 #endif
1478
1479   /* Register all dissectors; we must do this before checking for the
1480      "-G" flag, as the "-G" flag dumps information registered by the
1481      dissectors, and we must do it before we read the preferences, in
1482      case any dissectors register preferences. */
1483   epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs);
1484   register_all_tap_listeners();
1485
1486   /* Now register the preferences for any non-dissector modules.
1487      We must do that before we read the preferences as well. */
1488   prefs_register_modules();
1489
1490   /* If invoked with the "-G" flag, we dump out information based on
1491      the argument to the "-G" flag; if no argument is specified,
1492      for backwards compatibility we dump out a glossary of display
1493      filter symbols.
1494
1495      We must do this before calling "gtk_init()", because "gtk_init()"
1496      tries to open an X display, and we don't want to have to do any X
1497      stuff just to do a build.
1498
1499      Given that we call "gtk_init()" before doing the regular argument
1500      list processing, so that it can handle X and GTK+ arguments and
1501      remove them from the list at which we look, this means we must do
1502      this before doing the regular argument list processing, as well.
1503
1504      This means that:
1505
1506         you must give the "-G" flag as the first flag on the command line;
1507
1508         you must give it as "-G", nothing more, nothing less;
1509
1510         the first argument after the "-G" flag, if present, will be used
1511         to specify the information to dump;
1512
1513         arguments after that will not be used. */
1514   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1515     if (argc == 2)
1516       proto_registrar_dump_fields();
1517     else {
1518       if (strcmp(argv[2], "fields") == 0)
1519         proto_registrar_dump_fields();
1520       else if (strcmp(argv[2], "protocols") == 0)
1521         proto_registrar_dump_protocols();
1522       else {
1523         fprintf(stderr, "tethereal: Invalid \"%s\" option for -G flag\n",
1524                 argv[2]);
1525         exit(1);
1526       }
1527     }
1528     exit(0);
1529   }
1530
1531   /* multithread support currently doesn't seem to work in win32 gtk2.0.6 */
1532 #if ! defined WIN32 && GTK_MAJOR_VERSION >= 2 && defined G_THREADS_ENABLED
1533   {
1534       GThread *ut;
1535       g_thread_init(NULL);
1536       gdk_threads_init();
1537       ut=g_thread_create(update_thread, NULL, FALSE, NULL);
1538       g_thread_set_priority(ut, G_THREAD_PRIORITY_LOW);
1539   }
1540 #else  /* WIN32 || GTK1.2 || !G_THREADS_ENABLED */
1541   /* this is to keep tap extensions updating once every 3 seconds */
1542   gtk_timeout_add(3000, (GtkFunction)update_cb,(gpointer)NULL);
1543 #endif /* !WIN32 && GTK2 && G_THREADS_ENABLED */
1544
1545   /* Set the current locale according to the program environment.
1546    * We haven't localized anything, but some GTK widgets are localized
1547    * (the file selection dialogue, for example).
1548    * This also sets the C-language locale to the native environment. */
1549   gtk_set_locale();
1550
1551   /* Let GTK get its args */
1552   gtk_init (&argc, &argv);
1553
1554   /* Read the preference files. */
1555   prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
1556
1557 #ifdef HAVE_LIBPCAP
1558   capture_opts.has_snaplen = FALSE;
1559   capture_opts.snaplen = MIN_PACKET_SIZE;
1560   capture_opts.has_autostop_count = FALSE;
1561   capture_opts.autostop_count = 1;
1562   capture_opts.has_autostop_duration = FALSE;
1563   capture_opts.autostop_duration = 1;
1564   capture_opts.has_autostop_filesize = FALSE;
1565   capture_opts.autostop_filesize = 1;
1566   capture_opts.ringbuffer_on = FALSE;
1567   capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
1568
1569   /* If this is a capture child process, it should pay no attention
1570      to the "prefs.capture_prom_mode" setting in the preferences file;
1571      it should do what the parent process tells it to do, and if
1572      the parent process wants it not to run in promiscuous mode, it'll
1573      tell it so with a "-p" flag.
1574
1575      Otherwise, set promiscuous mode from the preferences setting. */
1576   if (capture_child)
1577     capture_opts.promisc_mode = TRUE;
1578   else
1579     capture_opts.promisc_mode = prefs->capture_prom_mode;
1580
1581   /* Set "Update list of packets in real time" mode from the preferences
1582      setting. */
1583   capture_opts.sync_mode = prefs->capture_real_time;
1584
1585   /* And do the same for "Automatic scrolling in live capture" mode. */
1586   auto_scroll_live = prefs->capture_auto_scroll;
1587 #endif
1588
1589   /* Set the name resolution code's flags from the preferences. */
1590   g_resolv_flags = prefs->name_resolve;
1591
1592   /* Read the capture filter file. */
1593   read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
1594
1595   /* Read the display filter file. */
1596   read_filter_list(DFILTER_LIST, &df_path, &df_open_errno);
1597
1598   init_cap_file(&cfile);
1599
1600   /* Assemble the compile-time options */
1601   comp_info_str = g_string_new("");
1602
1603   g_string_append(comp_info_str, "with ");
1604   g_string_sprintfa(comp_info_str,
1605 #ifdef GTK_MAJOR_VERSION
1606                     "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1607                     GTK_MICRO_VERSION);
1608 #else
1609                     "GTK+ (version unknown)");
1610 #endif
1611
1612   g_string_append(comp_info_str, ", with ");
1613   g_string_sprintfa(comp_info_str,
1614 #ifdef GLIB_MAJOR_VERSION
1615                     "GLib %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION,
1616                     GLIB_MICRO_VERSION);
1617 #else
1618                     "GLib (version unknown)");
1619 #endif
1620
1621 #ifdef HAVE_LIBPCAP
1622   g_string_append(comp_info_str, ", with libpcap ");
1623 #ifdef HAVE_PCAP_VERSION
1624   g_string_append(comp_info_str, pcap_version);
1625 #else /* HAVE_PCAP_VERSION */
1626   g_string_append(comp_info_str, "(version unknown)");
1627 #endif /* HAVE_PCAP_VERSION */
1628 #else /* HAVE_LIBPCAP */
1629   g_string_append(comp_info_str, ", without libpcap");
1630 #endif /* HAVE_LIBPCAP */
1631
1632 #ifdef HAVE_LIBZ
1633   g_string_append(comp_info_str, ", with libz ");
1634 #ifdef ZLIB_VERSION
1635   g_string_append(comp_info_str, ZLIB_VERSION);
1636 #else /* ZLIB_VERSION */
1637   g_string_append(comp_info_str, "(version unknown)");
1638 #endif /* ZLIB_VERSION */
1639 #else /* HAVE_LIBZ */
1640   g_string_append(comp_info_str, ", without libz");
1641 #endif /* HAVE_LIBZ */
1642
1643 /* Oh, this is pretty. */
1644 /* Oh, ha.  you think that was pretty.  Try this:! --Wes */
1645 #ifdef HAVE_SOME_SNMP
1646
1647 #ifdef HAVE_UCD_SNMP
1648   g_string_append(comp_info_str, ", with UCD-SNMP ");
1649   g_string_append(comp_info_str, VersionInfo);
1650 #endif /* HAVE_UCD_SNMP */
1651
1652 #ifdef HAVE_NET_SNMP
1653   g_string_append(comp_info_str, ", with Net-SNMP ");
1654   g_string_append(comp_info_str, netsnmp_get_version());
1655 #endif /* HAVE_NET_SNMP */
1656
1657 #else /* no SNMP library */
1658   g_string_append(comp_info_str, ", without UCD-SNMP or Net-SNMP");
1659 #endif /* HAVE_SOME_SNMP */
1660
1661   /* Now get our args */
1662   while ((opt = getopt(argc, argv, optstring)) != -1) {
1663     switch (opt) {
1664       case 'a':        /* autostop criteria */
1665 #ifdef HAVE_LIBPCAP
1666         if (set_autostop_criterion(optarg) == FALSE) {
1667           fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
1668           exit(1);
1669         }
1670 #else
1671         capture_option_specified = TRUE;
1672         arg_error = TRUE;
1673 #endif
1674         break;
1675       case 'b':        /* Ringbuffer option */
1676 #ifdef HAVE_LIBPCAP
1677         capture_opts.ringbuffer_on = TRUE;
1678         capture_opts.ringbuffer_num_files =
1679           get_positive_int(optarg, "number of ring buffer files");
1680 #else
1681         capture_option_specified = TRUE;
1682         arg_error = TRUE;
1683 #endif
1684         break;
1685       case 'B':        /* Byte view pane height */
1686         bv_size = get_positive_int(optarg, "byte view pane height");
1687         break;
1688       case 'c':        /* Capture xxx packets */
1689 #ifdef HAVE_LIBPCAP
1690         capture_opts.has_autostop_count = TRUE;
1691         capture_opts.autostop_count = get_positive_int(optarg, "packet count");
1692 #else
1693         capture_option_specified = TRUE;
1694         arg_error = TRUE;
1695 #endif
1696         break;
1697       case 'f':
1698 #ifdef HAVE_LIBPCAP
1699         if (cfile.cfilter)
1700                 g_free(cfile.cfilter);
1701         cfile.cfilter = g_strdup(optarg);
1702 #else
1703         capture_option_specified = TRUE;
1704         arg_error = TRUE;
1705 #endif
1706         break;
1707       case 'h':        /* Print help and exit */
1708         print_usage(TRUE);
1709         exit(0);
1710         break;
1711       case 'i':        /* Use interface xxx */
1712 #ifdef HAVE_LIBPCAP
1713         cfile.iface = g_strdup(optarg);
1714 #else
1715         capture_option_specified = TRUE;
1716         arg_error = TRUE;
1717 #endif
1718         break;
1719       case 'k':        /* Start capture immediately */
1720 #ifdef HAVE_LIBPCAP
1721         start_capture = TRUE;
1722 #else
1723         capture_option_specified = TRUE;
1724         arg_error = TRUE;
1725 #endif
1726         break;
1727       case 'l':        /* Automatic scrolling in live capture mode */
1728 #ifdef HAVE_LIBPCAP
1729         auto_scroll_live = TRUE;
1730 #else
1731         capture_option_specified = TRUE;
1732         arg_error = TRUE;
1733 #endif
1734         break;
1735       case 'm':        /* Fixed-width font for the display */
1736         if (prefs->gui_font_name != NULL)
1737           g_free(prefs->gui_font_name);
1738         prefs->gui_font_name = g_strdup(optarg);
1739         break;
1740       case 'n':        /* No name resolution */
1741         g_resolv_flags = RESOLV_NONE;
1742         break;
1743       case 'N':        /* Select what types of addresses/port #s to resolve */
1744         if (g_resolv_flags == RESOLV_ALL)
1745           g_resolv_flags = RESOLV_NONE;
1746         badopt = string_to_name_resolve(optarg, &g_resolv_flags);
1747         if (badopt != '\0') {
1748           fprintf(stderr, "ethereal: -N specifies unknown resolving option '%c'; valid options are 'm', 'n', and 't'\n",
1749                         badopt);
1750           exit(1);
1751         }
1752         break;
1753       case 'o':        /* Override preference from command line */
1754         switch (prefs_set_pref(optarg)) {
1755
1756         case PREFS_SET_SYNTAX_ERR:
1757           fprintf(stderr, "ethereal: Invalid -o flag \"%s\"\n", optarg);
1758           exit(1);
1759           break;
1760
1761         case PREFS_SET_NO_SUCH_PREF:
1762         case PREFS_SET_OBSOLETE:
1763           fprintf(stderr, "ethereal: -o flag \"%s\" specifies unknown preference\n",
1764                         optarg);
1765           exit(1);
1766           break;
1767         }
1768         break;
1769       case 'p':        /* Don't capture in promiscuous mode */
1770 #ifdef HAVE_LIBPCAP
1771         capture_opts.promisc_mode = FALSE;
1772 #else
1773         capture_option_specified = TRUE;
1774         arg_error = TRUE;
1775 #endif
1776         break;
1777       case 'P':        /* Packet list pane height */
1778         pl_size = get_positive_int(optarg, "packet list pane height");
1779         break;
1780       case 'Q':        /* Quit after capture (just capture to file) */
1781 #ifdef HAVE_LIBPCAP
1782         quit_after_cap = 1;
1783         start_capture = TRUE;  /*** -Q implies -k !! ***/
1784 #else
1785         capture_option_specified = TRUE;
1786         arg_error = TRUE;
1787 #endif
1788         break;
1789       case 'r':        /* Read capture file xxx */
1790         /* We may set "last_open_dir" to "cf_name", and if we change
1791            "last_open_dir" later, we free the old value, so we have to
1792            set "cf_name" to something that's been allocated. */
1793         cf_name = g_strdup(optarg);
1794         break;
1795       case 'R':        /* Read file filter */
1796         rfilter = optarg;
1797         break;
1798       case 's':        /* Set the snapshot (capture) length */
1799 #ifdef HAVE_LIBPCAP
1800         capture_opts.has_snaplen = TRUE;
1801         capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
1802 #else
1803         capture_option_specified = TRUE;
1804         arg_error = TRUE;
1805 #endif
1806         break;
1807       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1808 #ifdef HAVE_LIBPCAP
1809         capture_opts.sync_mode = TRUE;
1810 #else
1811         capture_option_specified = TRUE;
1812         arg_error = TRUE;
1813 #endif
1814         break;
1815       case 't':        /* Time stamp type */
1816         if (strcmp(optarg, "r") == 0)
1817           timestamp_type = RELATIVE;
1818         else if (strcmp(optarg, "a") == 0)
1819           timestamp_type = ABSOLUTE;
1820         else if (strcmp(optarg, "ad") == 0)
1821           timestamp_type = ABSOLUTE_WITH_DATE;
1822         else if (strcmp(optarg, "d") == 0)
1823           timestamp_type = DELTA;
1824         else {
1825           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1826             optarg);
1827           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1828           fprintf(stderr, "\"ad\" for absolute with date, or \"d\" for delta.\n");
1829           exit(1);
1830         }
1831         break;
1832       case 'T':        /* Tree view pane height */
1833         tv_size = get_positive_int(optarg, "tree view pane height");
1834         break;
1835       case 'v':        /* Show version and exit */
1836         show_version();
1837 #ifdef WIN32
1838         if (console_was_created)
1839           destroy_console();
1840 #endif
1841         exit(0);
1842         break;
1843       case 'w':        /* Write to capture file xxx */
1844 #ifdef HAVE_LIBPCAP
1845         save_file = g_strdup(optarg);
1846 #else
1847         capture_option_specified = TRUE;
1848         arg_error = TRUE;
1849 #endif
1850         break;
1851 #ifdef HAVE_LIBPCAP
1852       /* This is a hidden option supporting Sync mode, so we don't set
1853        * the error flags for the user in the non-libpcap case.
1854        */
1855       case 'W':        /* Write to capture file FD xxx */
1856         cfile.save_file_fd = atoi(optarg);
1857         break;
1858 #endif
1859       case 'z':
1860         for(tli=tap_list;tli;tli=tli->next){
1861           if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
1862             tap_opt = g_strdup(optarg);
1863             break;
1864           }
1865         }
1866         if(!tli){
1867           fprintf(stderr,"ethereal: invalid -z argument.\n");
1868           fprintf(stderr,"  -z argument must be one of :\n");
1869           for(tli=tap_list;tli;tli=tli->next){
1870             fprintf(stderr,"     %s\n",tli->cmd);
1871           }
1872           exit(1);
1873         }
1874         break;
1875
1876 #ifdef _WIN32
1877 #ifdef HAVE_LIBPCAP
1878       /* Hidden option supporting Sync mode */
1879       case 'Z':        /* Write to pipe FD XXX */
1880         /* associate stdout with pipe */
1881         i = atoi(optarg);
1882         if (dup2(i, 1) < 0) {
1883           fprintf(stderr, "Unable to dup pipe handle\n");
1884           exit(1);
1885         }
1886         break;
1887 #endif /* HAVE_LIBPCAP */
1888 #endif /* _WIN32 */
1889
1890       default:
1891       case '?':        /* Bad flag - print usage message */
1892         arg_error = TRUE;
1893         break;
1894     }
1895   }
1896   argc -= optind;
1897   argv += optind;
1898   if (argc >= 1) {
1899     if (cf_name != NULL) {
1900       /*
1901        * Input file name specified with "-r" *and* specified as a regular
1902        * command-line argument.
1903        */
1904       arg_error = TRUE;
1905     } else {
1906       /*
1907        * Input file name not specified with "-r", and a command-line argument
1908        * was specified; treat it as the input file name.
1909        *
1910        * Yes, this is different from tethereal, where non-flag command-line
1911        * arguments are a filter, but this works better on GUI desktops
1912        * where a command can be specified to be run to open a particular
1913        * file - yes, you could have "-r" as the last part of the command,
1914        * but that's a bit ugly.
1915        */
1916       cf_name = g_strdup(argv[0]);
1917     }
1918     argc--;
1919     argv++;
1920   }
1921
1922   if (argc != 0) {
1923     /*
1924      * Extra command line arguments were specified; complain.
1925      */
1926     fprintf(stderr, "Invalid argument: %s\n", argv[0]);
1927     arg_error = TRUE;
1928   }
1929   if (arg_error) {
1930     print_usage(FALSE);
1931     exit(1);
1932   }
1933
1934 #ifdef HAVE_LIBPCAP
1935   if (capture_opts.ringbuffer_on) {
1936     /* Ring buffer works only under certain conditions:
1937        a) ring buffer does not work with temporary files;
1938        b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
1939           sync_mode takes precedence;
1940        c) it makes no sense to enable the ring buffer if the maximum
1941           file size is set to "infinite". */
1942     if (save_file == NULL) {
1943       fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
1944       capture_opts.ringbuffer_on = FALSE;
1945     }
1946     if (capture_opts.sync_mode) {
1947       fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
1948       capture_opts.ringbuffer_on = FALSE;
1949     }
1950     if (!capture_opts.has_autostop_filesize) {
1951       fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
1952       capture_opts.ringbuffer_on = FALSE;
1953     }
1954   }
1955 #endif
1956
1957 #ifdef WIN32
1958   /* Load wpcap if possible */
1959   load_wpcap();
1960
1961   /* Start windows sockets */
1962   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
1963 #endif  /* WIN32 */
1964
1965   /* Notify all registered modules that have had any of their preferences
1966      changed either from one of the preferences file or from the command
1967      line that their preferences have changed. */
1968   prefs_apply_all();
1969
1970 #ifndef HAVE_LIBPCAP
1971   if (capture_option_specified)
1972     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1973 #endif
1974 #ifdef HAVE_LIBPCAP
1975   if (start_capture) {
1976     /* We're supposed to do a live capture; did the user specify an interface
1977        to use? */
1978     if (cfile.iface == NULL) {
1979       /* No - is a default specified in the preferences file? */
1980       if (prefs->capture_device != NULL) {
1981           /* Yes - use it. */
1982           cfile.iface = g_strdup(prefs->capture_device);
1983       } else {
1984         /* No - pick the first one from the list of interfaces. */
1985         if_list = get_interface_list(&err, err_str);
1986         if (if_list == NULL) {
1987           switch (err) {
1988
1989           case CANT_GET_INTERFACE_LIST:
1990               fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1991                         err_str);
1992               break;
1993
1994           case NO_INTERFACES_FOUND:
1995               fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1996               break;
1997           }
1998           exit(2);
1999         }
2000         cfile.iface = g_strdup(if_list->data);  /* first interface */
2001         free_interface_list(if_list);
2002       }
2003     }
2004   }
2005   if (capture_child) {
2006     if (cfile.save_file_fd == -1) {
2007       /* XXX - send this to the standard output as something our parent
2008          should put in an error message box? */
2009       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
2010       exit(1);
2011     }
2012   }
2013 #endif
2014
2015   /* Build the column format array */
2016   col_init(&cfile.cinfo, prefs->num_cols);
2017   for (i = 0; i < cfile.cinfo.num_cols; i++) {
2018     cfile.cinfo.col_fmt[i] = get_column_format(i);
2019     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
2020     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
2021       NUM_COL_FMTS);
2022     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
2023     cfile.cinfo.col_data[i] = NULL;
2024     if (cfile.cinfo.col_fmt[i] == COL_INFO)
2025       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
2026     else
2027       cfile.cinfo.col_buf[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2028     cfile.cinfo.col_expr[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2029     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
2030   }
2031
2032 #ifdef HAVE_LIBPCAP
2033   if (capture_opts.has_snaplen) {
2034     if (capture_opts.snaplen < 1)
2035       capture_opts.snaplen = WTAP_MAX_PACKET_SIZE;
2036     else if (capture_opts.snaplen < MIN_PACKET_SIZE)
2037       capture_opts.snaplen = MIN_PACKET_SIZE;
2038   }
2039
2040   /* Check the value range of the ringbuffer_num_files parameter */
2041   if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
2042     capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
2043   else if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
2044     capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
2045 #endif
2046
2047   rc_file = get_persconffile_path(RC_FILE, FALSE);
2048   gtk_rc_parse(rc_file);
2049
2050   /* Try to load the regular and boldface fixed-width fonts */
2051 #if GTK_MAJOR_VERSION < 2
2052   bold_font_name = boldify(prefs->gui_font_name);
2053   m_r_font = gdk_font_load(prefs->gui_font_name);
2054   m_b_font = gdk_font_load(bold_font_name);
2055 #else
2056   m_r_font = pango_font_description_from_string(prefs->gui_font_name);
2057   m_b_font = pango_font_description_copy(m_r_font);
2058   pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2059 #endif
2060   if (m_r_font == NULL || m_b_font == NULL) {
2061     /* XXX - pop this up as a dialog box? no */
2062     if (m_r_font == NULL) {
2063 #ifdef HAVE_LIBPCAP
2064       if (!capture_child)
2065 #endif
2066 #if GTK_MAJOR_VERSION < 2
2067         fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2068 #else
2069         fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to Monospace 9\n",
2070 #endif
2071                 prefs->gui_font_name);
2072     } else {
2073 #if GTK_MAJOR_VERSION < 2
2074       gdk_font_unref(m_r_font);
2075 #else
2076       pango_font_description_free(m_r_font);
2077 #endif
2078     }
2079     if (m_b_font == NULL) {
2080 #ifdef HAVE_LIBPCAP
2081       if (!capture_child)
2082 #endif
2083 #if GTK_MAJOR_VERSION < 2
2084         fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
2085                 bold_font_name);
2086 #else
2087         fprintf(stderr, "ethereal: Warning: bold font %s not found - defaulting"
2088                         " to Monospace 9\n", prefs->gui_font_name);
2089 #endif
2090     } else {
2091 #if GTK_MAJOR_VERSION < 2
2092       gdk_font_unref(m_b_font);
2093 #else
2094       pango_font_description_free(m_b_font);
2095 #endif
2096     }
2097 #if GTK_MAJOR_VERSION < 2
2098     g_free(bold_font_name);
2099     if ((m_r_font = gdk_font_load("6x13")) == NULL) {
2100       fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
2101 #else
2102     if ((m_r_font = pango_font_description_from_string("Monospace 9")) == NULL)
2103     {
2104             fprintf(stderr, "ethereal: Error: font Monospace 9 not found\n");
2105 #endif
2106       exit(1);
2107     }
2108 #if GTK_MAJOR_VERSION < 2
2109     if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
2110       fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
2111 #else
2112     if ((m_b_font = pango_font_description_copy(m_r_font)) == NULL) {
2113             fprintf(stderr, "ethereal: Error: font Monospace 9 bold not found\n");
2114 #endif
2115       exit(1);
2116     }
2117     g_free(prefs->gui_font_name);
2118 #if GTK_MAJOR_VERSION < 2
2119     prefs->gui_font_name = g_strdup("6x13");
2120 #else
2121     pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
2122     prefs->gui_font_name = g_strdup("Monospace 9");
2123 #endif
2124   }
2125
2126   /* Call this for the side-effects that set_fonts() produces */
2127   set_fonts(m_r_font, m_b_font);
2128
2129
2130 #ifdef HAVE_LIBPCAP
2131   /* Is this a "child" ethereal, which is only supposed to pop up a
2132      capture box to let us stop the capture, and run a capture
2133      to a file that our parent will read? */
2134   if (!capture_child) {
2135 #endif
2136     /* No.  Pop up the main window, and read in a capture file if
2137        we were told to. */
2138
2139     create_main_window(pl_size, tv_size, bv_size, prefs);
2140     set_menus_for_capture_file(FALSE);
2141
2142     /* open tap windows after creating the main window to avoid GTK warnings */
2143     if (tap_opt && tli) {
2144       (*tli->func)(tap_opt);
2145       g_free(tap_opt);
2146     }
2147
2148     colors_init();
2149     colfilter_init();
2150
2151     /* If we were given the name of a capture file, read it in now;
2152        we defer it until now, so that, if we can't open it, and pop
2153        up an alert box, the alert box is more likely to come up on
2154        top of the main window - but before the preference-file-error
2155        alert box, so, if we get one of those, it's more likely to come
2156        up on top of us. */
2157     if (cf_name) {
2158       if (rfilter != NULL) {
2159         if (!dfilter_compile(rfilter, &rfcode)) {
2160           simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
2161           rfilter_parse_failed = TRUE;
2162         }
2163       }
2164       if (!rfilter_parse_failed) {
2165         if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
2166           /* "open_cap_file()" succeeded, so it closed the previous
2167              capture file, and thus destroyed any previous read filter
2168              attached to "cf". */
2169           cfile.rfcode = rfcode;
2170           switch (read_cap_file(&cfile, &err)) {
2171
2172           case READ_SUCCESS:
2173           case READ_ERROR:
2174             /* Just because we got an error, that doesn't mean we were unable
2175                to read any of the file; we handle what we could get from the
2176                file. */
2177             break;
2178
2179           case READ_ABORTED:
2180             /* Exit now. */
2181             gtk_exit(0);
2182             break;
2183           }
2184           /* Save the name of the containing directory specified in the
2185              path name, if any; we can write over cf_name, which is a
2186              good thing, given that "get_dirname()" does write over its
2187              argument. */
2188           s = get_dirname(cf_name);
2189           set_last_open_dir(s);
2190           g_free(cf_name);
2191           cf_name = NULL;
2192         } else {
2193           if (rfcode != NULL)
2194             dfilter_free(rfcode);
2195           cfile.rfcode = NULL;
2196         }
2197       }
2198     }
2199 #ifdef HAVE_LIBPCAP
2200   }
2201 #endif
2202
2203   /* If the global preferences file exists but we failed to open it,
2204      pop up an alert box; we defer that until now, so that the alert
2205      box is more likely to come up on top of the main window. */
2206   if (gpf_path != NULL) {
2207       simple_dialog(ESD_TYPE_WARN, NULL,
2208         "Could not open global preferences file\n\"%s\": %s.", gpf_path,
2209         strerror(gpf_open_errno));
2210   }
2211
2212   /* If the user's preferences file exists but we failed to open it,
2213      pop up an alert box; we defer that until now, so that the alert
2214      box is more likely to come up on top of the main window. */
2215   if (pf_path != NULL) {
2216       simple_dialog(ESD_TYPE_WARN, NULL,
2217         "Could not open your preferences file\n\"%s\": %s.", pf_path,
2218         strerror(pf_open_errno));
2219       g_free(pf_path);
2220       pf_path = NULL;
2221   }
2222
2223   /* If the user's capture filter file exists but we failed to open it,
2224      pop up an alert box; we defer that until now, so that the alert
2225      box is more likely to come up on top of the main window. */
2226   if (cf_path != NULL) {
2227       simple_dialog(ESD_TYPE_WARN, NULL,
2228         "Could not open your capture filter file\n\"%s\": %s.", cf_path,
2229         strerror(cf_open_errno));
2230       g_free(cf_path);
2231   }
2232
2233   /* If the user's display filter file exists but we failed to open it,
2234      pop up an alert box; we defer that until now, so that the alert
2235      box is more likely to come up on top of the main window. */
2236   if (df_path != NULL) {
2237       simple_dialog(ESD_TYPE_WARN, NULL,
2238         "Could not open your display filter file\n\"%s\": %s.", df_path,
2239         strerror(df_open_errno));
2240       g_free(df_path);
2241   }
2242
2243 #ifdef HAVE_LIBPCAP
2244   if (capture_child) {
2245     /* This is the child process for a sync mode or fork mode capture,
2246        so just do the low-level work of a capture - don't create
2247        a temporary file and fork off *another* child process (so don't
2248        call "do_capture()"). */
2249
2250        /* XXX - hand these stats to the parent process */
2251        capture(&stats_known, &stats);
2252
2253        /* The capture is done; there's nothing more for us to do. */
2254        gtk_exit(0);
2255   } else {
2256     if (start_capture) {
2257       /* "-k" was specified; start a capture. */
2258       do_capture(save_file);
2259       if (save_file != NULL) {
2260         /* Save the directory name for future file dialogs. */
2261         s = get_dirname(save_file);  /* Overwrites save_file */
2262         set_last_open_dir(s);
2263         g_free(save_file);
2264         save_file = NULL;
2265       }
2266     }
2267     else {
2268       set_menus_for_capture_in_progress(FALSE);
2269     }
2270   }
2271 #else
2272   set_menus_for_capture_in_progress(FALSE);
2273 #endif
2274
2275   gtk_main();
2276
2277         /* Try to save our geometry.  GTK+ provides two routines to get a
2278                  window's position relative to the X root window.  If I understand the
2279                  documentation correctly, gdk_window_get_deskrelative_origin applies
2280                  mainly to Enlightenment and gdk_window_get_root_origin applies for
2281                  all other WMs.
2282
2283            The code below tries both routines, and picks the one that returns
2284            the upper-left-most coordinates.
2285
2286            More info at:
2287
2288            http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
2289            http://www.gtk.org/faq/#AEN600 */
2290
2291         /* Re-read our saved preferences. */
2292         /* XXX - Move all of this into a separate function? */
2293         prefs = read_prefs(&gpf_open_errno, &gpf_path, &pf_open_errno, &pf_path);
2294
2295         if (pf_path == NULL) {
2296                 if (prefs->gui_geometry_save_position) {
2297                         if (top_level->window != NULL) {
2298                                 gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
2299                                 if (gdk_window_get_deskrelative_origin(top_level->window,
2300                                                         &desk_x, &desk_y)) {
2301                                         if (desk_x <= root_x && desk_y <= root_y) {
2302                                                 root_x = desk_x;
2303                                                 root_y = desk_y;
2304                                         }
2305                                 }
2306                         }
2307                         if (prefs->gui_geometry_main_x != root_x) {
2308                                 prefs->gui_geometry_main_x = root_x;
2309                                 prefs_write_needed = TRUE;
2310                         }
2311                         if (prefs->gui_geometry_main_y != root_y) {
2312                                 prefs->gui_geometry_main_y = root_y;
2313                                 prefs_write_needed = TRUE;
2314                         }
2315                 }
2316
2317                 if (prefs->gui_geometry_save_size) {
2318                         if (top_level->window != NULL) {
2319                                 /* XXX - Is this the "approved" method? */
2320                                 gdk_window_get_size(top_level->window, &top_width, &top_height);
2321                         }
2322                         if (prefs->gui_geometry_main_width != top_width) {
2323                                 prefs->gui_geometry_main_width = top_width;
2324                                 prefs_write_needed = TRUE;
2325                         }
2326                         if (prefs->gui_geometry_main_height != top_height) {
2327                                 prefs->gui_geometry_main_height = top_height;
2328                                 prefs_write_needed = TRUE;
2329                         }
2330                 }
2331
2332                 if (prefs_write_needed) {
2333                         write_prefs(&pf_path);
2334                 }
2335         } else {
2336                 /* Ignore errors silently */
2337                 g_free(pf_path);
2338         }
2339
2340   epan_cleanup();
2341   g_free(rc_file);
2342
2343 #ifdef WIN32
2344   /* Shutdown windows sockets */
2345   WSACleanup();
2346
2347   /* For some unknown reason, the "atexit()" call in "create_console()"
2348      doesn't arrange that "destroy_console()" be called when we exit,
2349      so we call it here if a console was created. */
2350   if (console_was_created)
2351     destroy_console();
2352 #endif
2353
2354   gtk_exit(0);
2355
2356   /* This isn't reached, but we need it to keep GCC from complaining
2357      that "main()" returns without returning a value - it knows that
2358      "exit()" never returns, but it doesn't know that "gtk_exit()"
2359      doesn't, as GTK+ doesn't declare it with the attribute
2360      "noreturn". */
2361   return 0;     /* not reached */
2362 }
2363
2364 #ifdef WIN32
2365
2366 /* We build this as a GUI subsystem application on Win32, so
2367    "WinMain()", not "main()", gets called.
2368
2369    Hack shamelessly stolen from the Win32 port of the GIMP. */
2370 #ifdef __GNUC__
2371 #define _stdcall  __attribute__((stdcall))
2372 #endif
2373
2374 int _stdcall
2375 WinMain (struct HINSTANCE__ *hInstance,
2376          struct HINSTANCE__ *hPrevInstance,
2377          char               *lpszCmdLine,
2378          int                 nCmdShow)
2379 {
2380   has_no_console = TRUE;
2381   return main (__argc, __argv);
2382 }
2383
2384 /*
2385  * If this application has no console window to which its standard output
2386  * would go, create one.
2387  */
2388 static void
2389 create_console(void)
2390 {
2391   if (has_no_console) {
2392     /* We have no console to which to print the version string, so
2393        create one and make it the standard input, output, and error. */
2394     if (!AllocConsole())
2395       return;   /* couldn't create console */
2396     freopen("CONIN$", "r", stdin);
2397     freopen("CONOUT$", "w", stdout);
2398     freopen("CONOUT$", "w", stderr);
2399
2400     /* Well, we have a console now. */
2401     has_no_console = FALSE;
2402     console_was_created = TRUE;
2403
2404     /* Now register "destroy_console()" as a routine to be called just
2405        before the application exits, so that we can destroy the console
2406        after the user has typed a key (so that the console doesn't just
2407        disappear out from under them, giving the user no chance to see
2408        the message(s) we put in there). */
2409     atexit(destroy_console);
2410   }
2411 }
2412
2413 static void
2414 destroy_console(void)
2415 {
2416   printf("\n\nPress any key to exit\n");
2417   _getch();
2418   FreeConsole();
2419 }
2420
2421 /* This routine should not be necessary, at least as I read the GLib
2422    source code, as it looks as if GLib is, on Win32, *supposed* to
2423    create a console window into which to display its output.
2424
2425    That doesn't happen, however.  I suspect there's something completely
2426    broken about that code in GLib-for-Win32, and that it may be related
2427    to the breakage that forces us to just call "printf()" on the message
2428    rather than passing the message on to "g_log_default_handler()"
2429    (which is the routine that does the aforementioned non-functional
2430    console window creation). */
2431 static void
2432 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
2433                     const char *message, gpointer user_data)
2434 {
2435   create_console();
2436   if (console_was_created) {
2437     /* For some unknown reason, the above doesn't appear to actually cause
2438        anything to be sent to the standard output, so we'll just splat the
2439        message out directly, just to make sure it gets out. */
2440     printf("%s\n", message);
2441   } else
2442     g_log_default_handler(log_domain, log_level, message, user_data);
2443 }
2444 #endif
2445
2446 #if GTK_MAJOR_VERSION < 2
2447 /* Given a font name, construct the name of the next heavier version of
2448    that font. */
2449
2450 #define XLFD_WEIGHT     3       /* index of the "weight" field */
2451
2452 /* Map from a given weight to the appropriate weight for the "bold"
2453    version of a font.
2454    XXX - the XLFD says these strings shouldn't be used for font matching;
2455    can we get the weight, as a number, from GDK, and ask GDK to find us
2456    a font just like the given font, but with the appropriate higher
2457    weight? */
2458 static const struct {
2459         char    *light;
2460         char    *heavier;
2461 } weight_map[] = {
2462         { "ultralight", "light" },
2463         { "extralight", "semilight" },
2464         { "light",      "medium" },
2465         { "semilight",  "semibold" },
2466         { "medium",     "bold" },
2467         { "normal",     "bold" },
2468         { "semibold",   "extrabold" },
2469         { "bold",       "ultrabold" }
2470 };
2471 #define N_WEIGHTS       (sizeof weight_map / sizeof weight_map[0])
2472
2473 char *
2474 boldify(const char *font_name)
2475 {
2476         char *bold_font_name;
2477         gchar **xlfd_tokens;
2478         unsigned int i;
2479
2480         /* Is this an XLFD font?  If it begins with "-", yes, otherwise no. */
2481         if (font_name[0] == '-') {
2482                 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
2483
2484                 /*
2485                  * Make sure we *have* a weight (this might not be a valid
2486                  * XLFD font name).
2487                  */
2488                 for (i = 0; i < XLFD_WEIGHT+1; i++) {
2489                         if (xlfd_tokens[i] == NULL) {
2490                                 /*
2491                                  * We don't, so treat this as a non-XLFD
2492                                  * font name.
2493                                  */
2494                                 goto not_xlfd;
2495                         }
2496                 }
2497                 for (i = 0; i < N_WEIGHTS; i++) {
2498                         if (strcmp(xlfd_tokens[XLFD_WEIGHT],
2499                             weight_map[i].light) == 0) {
2500                                 g_free(xlfd_tokens[XLFD_WEIGHT]);
2501                                 xlfd_tokens[XLFD_WEIGHT] =
2502                                     g_strdup(weight_map[i].heavier);
2503                                 break;
2504                         }
2505                 }
2506                 bold_font_name = g_strjoinv("-", xlfd_tokens);
2507                 g_strfreev(xlfd_tokens);
2508                 return bold_font_name;
2509         }
2510
2511 not_xlfd:
2512         /*
2513          * This isn't an XLFD font name; just append "bold" to the name
2514          * of the font.
2515          */
2516         bold_font_name = g_strconcat(font_name, "bold", NULL);
2517         return bold_font_name;
2518 }
2519 #endif
2520
2521 static void
2522 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
2523 {
2524     GtkWidget     *main_vbox, *menubar, *u_pane, *l_pane,
2525                   *stat_hbox, *column_lb,
2526                   *filter_bt, *filter_cm, *filter_te,
2527                   *filter_apply,
2528                   *filter_reset;
2529     GList         *filter_list = NULL;
2530     GtkAccelGroup *accel;
2531     GtkStyle      *win_style;
2532     GdkBitmap     *ascend_bm, *descend_bm;
2533     GdkPixmap     *ascend_pm, *descend_pm;
2534     column_arrows *col_arrows;
2535     int            i;
2536     /* Display filter construct dialog has an Apply button, and "OK" not
2537        only sets our text widget, it activates it (i.e., it causes us to
2538        filter the capture). */
2539     static construct_args_t args = {
2540         "Ethereal: Display Filter",
2541         TRUE,
2542         TRUE
2543     };
2544
2545     /* Main window */
2546     top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2547     gtk_widget_set_name(top_level, "main window");
2548     SIGNAL_CONNECT(top_level, "delete_event", main_window_delete_event_cb,
2549                    NULL);
2550     SIGNAL_CONNECT(top_level, "realize", window_icon_realize_cb, NULL);
2551     gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
2552     if (prefs->gui_geometry_save_position) {
2553         gtk_widget_set_uposition(GTK_WIDGET(top_level),
2554                                  prefs->gui_geometry_main_x,
2555                                  prefs->gui_geometry_main_y);
2556     }
2557     if (prefs->gui_geometry_save_size) {
2558         WIDGET_SET_SIZE(top_level, prefs->gui_geometry_main_width,
2559                         prefs->gui_geometry_main_height);
2560     } else {
2561         WIDGET_SET_SIZE(top_level, DEF_WIDTH, -1);
2562     }
2563     gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
2564
2565     /* Container for menu bar, paned windows and progress/info box */
2566     main_vbox = gtk_vbox_new(FALSE, 1);
2567     gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
2568     gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
2569     gtk_widget_show(main_vbox);
2570
2571     /* Menu bar */
2572     get_main_menu(&menubar, &accel);
2573     gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
2574     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
2575     gtk_widget_show(menubar);
2576
2577     /* Panes for the packet list, tree, and byte view */
2578     u_pane = gtk_vpaned_new();
2579     gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
2580     l_pane = gtk_vpaned_new();
2581     gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
2582     gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
2583     gtk_widget_show(l_pane);
2584     gtk_paned_add2(GTK_PANED(u_pane), l_pane);
2585     gtk_widget_show(u_pane);
2586
2587     /* Packet list */
2588     pkt_scrollw = scrolled_window_new(NULL, NULL);
2589     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
2590                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2591     gtk_widget_show(pkt_scrollw);
2592     gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
2593
2594     packet_list = gtk_clist_new(cfile.cinfo.num_cols);
2595     /* Column titles are filled in below */
2596     gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
2597
2598     col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
2599                                             cfile.cinfo.num_cols);
2600
2601     set_plist_sel_browse(prefs->gui_plist_sel_browse);
2602     set_plist_font(m_r_font);
2603     gtk_widget_set_name(packet_list, "packet list");
2604     SIGNAL_CONNECT(packet_list, "click-column", packet_list_click_column_cb,
2605                    col_arrows);
2606     SIGNAL_CONNECT(packet_list, "select-row", packet_list_select_cb, NULL);
2607     SIGNAL_CONNECT(packet_list, "unselect-row", packet_list_unselect_cb, NULL);
2608     for (i = 0; i < cfile.cinfo.num_cols; i++) {
2609         if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
2610             gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
2611
2612         /* Right-justify the packet number column. */
2613         if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
2614             gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
2615                                                GTK_JUSTIFY_RIGHT);
2616     }
2617     WIDGET_SET_SIZE(packet_list, -1, pl_size);
2618     SIGNAL_CONNECT(packet_list, "button_press_event", popup_menu_handler,
2619                    OBJECT_GET_DATA(popup_menu_object, PM_PACKET_LIST_KEY));
2620     SIGNAL_CONNECT(packet_list, "button_press_event",
2621                    packet_list_button_pressed_cb, NULL);
2622     gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
2623     gtk_widget_show(packet_list);
2624
2625     /* Tree view */
2626 #if GTK_MAJOR_VERSION < 2
2627     item_style = gtk_style_new();
2628     gdk_font_unref(item_style->font);
2629     item_style->font = m_r_font;
2630 #endif
2631     create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view);
2632 #if GTK_MAJOR_VERSION < 2
2633     SIGNAL_CONNECT(tree_view, "tree-select-row", tree_view_select_row_cb, NULL);
2634     SIGNAL_CONNECT(tree_view, "tree-unselect-row", tree_view_unselect_row_cb,
2635                    NULL);
2636 #else
2637     SIGNAL_CONNECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
2638                    "changed", tree_view_selection_changed_cb, NULL);
2639 #endif
2640     SIGNAL_CONNECT(tree_view, "button_press_event", popup_menu_handler,
2641                    OBJECT_GET_DATA(popup_menu_object, PM_TREE_VIEW_KEY));
2642     gtk_widget_show(tree_view);
2643
2644     /* Byte view. */
2645     byte_nb_ptr = create_byte_view(bv_size, l_pane);
2646
2647     SIGNAL_CONNECT(byte_nb_ptr, "button_press_event", popup_menu_handler,
2648                    OBJECT_GET_DATA(popup_menu_object, PM_HEXDUMP_KEY));
2649
2650     /* Filter/info box */
2651     stat_hbox = gtk_hbox_new(FALSE, 1);
2652     gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
2653     gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
2654     gtk_widget_show(stat_hbox);
2655
2656     filter_bt = gtk_button_new_with_label("Filter:");
2657     SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
2658     gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
2659     gtk_widget_show(filter_bt);
2660
2661     filter_cm = gtk_combo_new();
2662     filter_list = g_list_append (filter_list, "");
2663     gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
2664     gtk_combo_disable_activate(GTK_COMBO(filter_cm));
2665     gtk_combo_set_case_sensitive(GTK_COMBO(filter_cm), TRUE);
2666     OBJECT_SET_DATA(filter_cm, E_DFILTER_FL_KEY, filter_list);
2667     filter_te = GTK_COMBO(filter_cm)->entry;
2668     OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
2669     OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm);
2670     gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
2671     SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te);
2672     gtk_widget_show(filter_cm);
2673
2674 #if GTK_MAJOR_VERSION < 2
2675     filter_reset = gtk_button_new_with_label("Reset");
2676 #else
2677     filter_reset = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
2678 #endif    
2679     OBJECT_SET_DATA(filter_reset, E_DFILTER_TE_KEY, filter_te);
2680     SIGNAL_CONNECT(filter_reset, "clicked", filter_reset_cb, NULL);
2681     gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
2682     gtk_widget_show(filter_reset);
2683
2684 #if GTK_MAJOR_VERSION < 2
2685     filter_apply = gtk_button_new_with_label("Apply");
2686 #else
2687     filter_apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
2688 #endif
2689     OBJECT_SET_DATA(filter_apply, E_DFILTER_CM_KEY, filter_cm);
2690     SIGNAL_CONNECT(filter_apply, "clicked", filter_activate_cb, filter_te);
2691     gtk_box_pack_start(GTK_BOX(stat_hbox), filter_apply, FALSE, TRUE, 1);
2692     gtk_widget_show(filter_apply);
2693
2694     /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
2695      * of any widget that ends up calling a callback which needs
2696      * that text entry pointer */
2697     set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
2698     set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
2699     set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
2700     set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
2701                          filter_te);
2702     set_menu_object_data("/Display/Match/Selected", E_DFILTER_TE_KEY,
2703                          filter_te);
2704     set_menu_object_data("/Display/Match/Not Selected", E_DFILTER_TE_KEY,
2705                          filter_te);
2706     set_menu_object_data("/Display/Match/And Selected", E_DFILTER_TE_KEY,
2707                          filter_te);
2708     set_menu_object_data("/Display/Match/Or Selected", E_DFILTER_TE_KEY,
2709                          filter_te);
2710     set_menu_object_data("/Display/Match/And Not Selected", E_DFILTER_TE_KEY,
2711                          filter_te);
2712     set_menu_object_data("/Display/Match/Or Not Selected", E_DFILTER_TE_KEY,
2713                          filter_te);
2714     set_menu_object_data("/Display/Prepare/Selected", E_DFILTER_TE_KEY,
2715                          filter_te);
2716     set_menu_object_data("/Display/Prepare/Not Selected", E_DFILTER_TE_KEY,
2717                          filter_te);
2718     set_menu_object_data("/Display/Prepare/And Selected", E_DFILTER_TE_KEY,
2719                          filter_te);
2720     set_menu_object_data("/Display/Prepare/Or Selected", E_DFILTER_TE_KEY,
2721                          filter_te);
2722     set_menu_object_data("/Display/Prepare/And Not Selected", E_DFILTER_TE_KEY,
2723                          filter_te);
2724     set_menu_object_data("/Display/Prepare/Or Not Selected", E_DFILTER_TE_KEY,
2725                          filter_te);
2726     OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
2727     OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
2728
2729     info_bar = gtk_statusbar_new();
2730     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
2731     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
2732     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
2733     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
2734     gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2735     gtk_widget_show(info_bar);
2736
2737     gtk_widget_show(top_level);
2738
2739     /* Fill in column titles.  This must be done after the top level window
2740        is displayed. */
2741     win_style = gtk_widget_get_style(top_level);
2742     ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
2743                                              &win_style->bg[GTK_STATE_NORMAL],
2744                                              (gchar **)clist_ascend_xpm);
2745     descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
2746                                               &win_style->bg[GTK_STATE_NORMAL],
2747                                               (gchar **)clist_descend_xpm);
2748     for (i = 0; i < cfile.cinfo.num_cols; i++) {
2749         col_arrows[i].table = gtk_table_new(2, 2, FALSE);
2750         gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
2751         column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
2752         gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
2753                          GTK_SHRINK, GTK_SHRINK, 0, 0);
2754         gtk_widget_show(column_lb);
2755         col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
2756         gtk_table_attach(GTK_TABLE(col_arrows[i].table),
2757                          col_arrows[i].ascend_pm,
2758                          1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
2759         if (i == 0) {
2760             gtk_widget_show(col_arrows[i].ascend_pm);
2761         }
2762         col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
2763         gtk_table_attach(GTK_TABLE(col_arrows[i].table),
2764                          col_arrows[i].descend_pm,
2765                          1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
2766         gtk_clist_set_column_widget(GTK_CLIST(packet_list), i,
2767                                     col_arrows[i].table);
2768         gtk_widget_show(col_arrows[i].table);
2769     }
2770     gtk_clist_column_titles_show(GTK_CLIST(packet_list));
2771 }
2772
2773
2774 void
2775 set_last_open_dir(char *dirname)
2776 {
2777         int len;
2778
2779         if (last_open_dir) {
2780                 g_free(last_open_dir);
2781         }
2782
2783         if (dirname) {
2784                 len = strlen(dirname);
2785                 if (dirname[len-1] == G_DIR_SEPARATOR) {
2786                         last_open_dir = g_strconcat(dirname, NULL);
2787                 }
2788                 else {
2789                         last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
2790                                 NULL);
2791                 }
2792         }
2793         else {
2794                 last_open_dir = NULL;
2795         }
2796 }