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