Patch from Ben Fowler to rename the global variable "cf" to "cfile", to
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.123 2000/06/27 04:36:01 guy Exp $
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@zing.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10  *                              needed by dissect routines
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  *
27  * To do:
28  * - Graphs
29  * - Check for end of packet in dissect_* routines.
30  * - Playback window
31  * - Multiple window support
32  * - Add cut/copy/paste
33  * - Create header parsing routines
34  * - Make byte view selections more fancy?
35  *
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <gtk/gtk.h>
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51
52 #include <errno.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55
56 #ifdef HAVE_IO_H
57 #include <io.h> /* open/close on win32 */
58 #endif
59
60 #ifdef HAVE_DIRECT_H
61 #include <direct.h>
62 #endif
63
64 #ifdef HAVE_NETINET_IN_H
65 #include <netinet/in.h>
66 #endif
67
68 #include <signal.h>
69
70 #ifdef NEED_SNPRINTF_H
71 # ifdef HAVE_STDARG_H
72 #  include <stdarg.h>
73 # else
74 #  include <varargs.h>
75 # endif
76 # include "snprintf.h"
77 #endif
78
79 #if defined(HAVE_UCD_SNMP_SNMP_H)
80 #ifdef HAVE_UCD_SNMP_VERSION_H
81 #include <ucd-snmp/version.h>
82 #endif /* HAVE_UCD_SNMP_VERSION_H */
83 #elif defined(HAVE_SNMP_SNMP_H)
84 #ifdef HAVE_SNMP_VERSION_H
85 #include <snmp/version.h>
86 #endif /* HAVE_SNMP_VERSION_H */
87 #endif /* SNMP */
88
89 #ifdef NEED_STRERROR_H
90 #include "strerror.h"
91 #endif
92
93 #ifdef NEED_GETOPT_H
94 #include "getopt.h"
95 #endif
96
97 #include "main.h"
98 #include "timestamp.h"
99 #include "packet.h"
100 #include "capture.h"
101 #include "summary.h"
102 #include "file.h"
103 #include "menu.h"
104 #include "../menu.h"
105 #include "filter_prefs.h"
106 #include "prefs_dlg.h"
107 #include "column.h"
108 #include "print.h"
109 #include "resolv.h"
110 #include "follow.h"
111 #include "util.h"
112 #include "simple_dialog.h"
113 #include "proto_draw.h"
114 #include "dfilter.h"
115 #include "keys.h"
116 #include "packet_win.h"
117 #include "gtkglobals.h"
118 #include "plugins.h"
119
120 FILE        *data_out_file = NULL;
121 packet_info  pi;
122 capture_file cfile;
123 GtkWidget   *top_level, *packet_list, *tree_view, *byte_view,
124             *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
125 static GtkWidget        *bv_scrollw;
126 GdkFont     *m_r_font, *m_b_font;
127 guint        main_ctx, file_ctx;
128 gchar        comp_info_str[256];
129 gchar       *ethereal_path = NULL;
130 gchar       *medium_font = MONO_MEDIUM_FONT;
131 gchar       *bold_font = MONO_BOLD_FONT;
132 gchar       *last_open_dir = NULL;
133
134 ts_type timestamp_type = RELATIVE;
135
136 GtkStyle *item_style;
137
138 /* Specifies the field currently selected in the GUI protocol tree */
139 field_info *finfo_selected = NULL;
140
141 static void follow_destroy_cb(GtkWidget *win, gpointer data);
142 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
143 static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
144 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
145 static char* hfinfo_numeric_format(header_field_info *hfinfo);
146 static void create_main_window(gint, gint, gint, e_prefs*);
147
148 /* About Ethereal window */
149 void
150 about_ethereal( GtkWidget *w, gpointer data ) {
151   simple_dialog(ESD_TYPE_INFO, NULL,
152                 "Ethereal - Network Protocol Analyzer\n"
153                 "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
154                 "Compiled with %s\n\n"
155
156                 "Check the man page for complete documentation and\n"
157                 "for the list of contributors.\n"
158
159                 "\nSee http://ethereal.zing.org/ for more information.",
160                  comp_info_str);
161 }
162
163 /* Follow the TCP stream, if any, to which the last packet that we called
164    a dissection routine on belongs (this might be the most recently
165    selected packet, or it might be the last packet in the file). */
166 void
167 follow_stream_cb( GtkWidget *w, gpointer data ) {
168   char      filename1[128+1];
169   GtkWidget *streamwindow, *box, *txt_scrollw, *text, *filter_te;
170   GtkWidget *hbox, *close_bt, *print_bt;
171   GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
172   int        tmp_fd;
173   gchar     *follow_filter;
174
175   if( pi.ipproto == 6 ) {
176     /* we got tcp so we can follow */
177     /* Create a temporary file into which to dump the reassembled data
178        from the TCP stream, and set "data_out_file" to refer to it, so
179        that the TCP code will write to it.
180
181        XXX - it might be nicer to just have the TCP code directly
182        append stuff to the text widget for the TCP stream window,
183        if we can arrange that said window not pop up until we're
184        done. */
185     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
186     if (tmp_fd == -1) {
187       simple_dialog(ESD_TYPE_WARN, NULL,
188         "Could not create temporary file %s: %s", filename1, strerror(errno));
189       return;
190     }
191     data_out_file = fdopen( tmp_fd, "wb" );
192     if( data_out_file == NULL ) {
193       simple_dialog(ESD_TYPE_WARN, NULL,
194         "Could not create temporary file %s: %s", filename1, strerror(errno));
195       close(tmp_fd);
196       unlink(filename1);
197       return;
198     }
199
200     /* Create a new filter that matches all packets in the TCP stream,
201        and set the display filter entry accordingly */
202     reset_tcp_reassembly();
203     follow_filter = build_follow_filter( &pi );
204
205     /* set the display filter entry accordingly */
206     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
207     gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
208
209     /* Run the display filter so it goes in effect. */
210     filter_packets(&cfile, follow_filter);
211
212     /* the data_out_file should now be full of the streams information */
213     fclose( data_out_file );
214
215     /* the filename1 file now has all the text that was in the session */
216     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
217     gtk_widget_set_name( streamwindow, "TCP stream window" );
218
219     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
220                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
221                         
222     if( incomplete_tcp_stream ) {
223       gtk_window_set_title( GTK_WINDOW(streamwindow), 
224                             "Contents of TCP stream (incomplete)" );
225     } else {
226       gtk_window_set_title( GTK_WINDOW(streamwindow),
227                             "Contents of TCP stream" );
228     }
229     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
230     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
231
232     /* setup the container */
233     box = gtk_vbox_new( FALSE, 0 );
234     gtk_container_add( GTK_CONTAINER(streamwindow), box );
235     gtk_widget_show( box );
236
237     /* create a scrolled window for the text */
238     txt_scrollw = gtk_scrolled_window_new( NULL, NULL );
239     gtk_box_pack_start( GTK_BOX(box), txt_scrollw, TRUE, TRUE, 0 );
240     gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(txt_scrollw),
241                                         GTK_POLICY_NEVER,
242                                         GTK_POLICY_ALWAYS );
243     set_scrollbar_placement_scrollw(txt_scrollw, prefs.gui_scrollbar_on_right);
244     remember_scrolled_window(txt_scrollw);
245     gtk_widget_show( txt_scrollw );
246
247     /* create a text box */
248     text = gtk_text_new( NULL, NULL );
249     gtk_text_set_editable( GTK_TEXT(text), FALSE);
250     gtk_container_add( GTK_CONTAINER(txt_scrollw), text );
251     gtk_widget_show(text);
252
253     /* Create hbox */
254     hbox = gtk_hbox_new( FALSE, 1 );
255     gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
256     gtk_widget_show(hbox);
257
258 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
259 #define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
260 #define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
261
262     /* Create Radio Buttons */
263     b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
264     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
265     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
266     gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
267     gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
268                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
269                     GTK_OBJECT(streamwindow));
270     gtk_widget_show(b_ascii);
271
272     b_ebcdic = gtk_radio_button_new_with_label(
273                     gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
274                     "EBCDIC");
275     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
276     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
277     gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
278     gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
279                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
280                     GTK_OBJECT(streamwindow));
281     gtk_widget_show(b_ebcdic);
282
283     b_hexdump = gtk_radio_button_new_with_label(
284                     gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
285                     "Hex. Dump");
286     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
287     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
288     gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
289     gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
290                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
291                     GTK_OBJECT(streamwindow));
292     gtk_widget_show(b_hexdump);
293
294     /* Create Close Button */
295     close_bt = gtk_button_new_with_label("Close");
296     gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
297                     GTK_SIGNAL_FUNC(gtk_widget_destroy),
298                     GTK_OBJECT(streamwindow));
299     gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
300     gtk_widget_show( close_bt );
301
302     /* Create Print Button */
303     print_bt = gtk_button_new_with_label("Print");
304     gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
305                    GTK_SIGNAL_FUNC(follow_print_stream),
306                    GTK_OBJECT(streamwindow));
307     gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
308     gtk_widget_show( print_bt );
309
310     /* Tuck away the filename and textbox into streamwindow */
311 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
312 #define E_FOLLOW_TEXT_KEY "follow_text_key"
313
314     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
315                     g_strdup(filename1));
316     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
317
318     follow_load_text(text, filename1, 0);
319
320     data_out_file = NULL;
321
322     /* Make sure this widget gets destroyed if we quit the main loop,
323        so that if we exit, we clean up any temporary files we have
324        for "Follow TCP Stream" windows. */
325     gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(streamwindow));
326     gtk_widget_show( streamwindow );
327   } else {
328     simple_dialog(ESD_TYPE_WARN, NULL,
329       "Error following stream.  Please make\n"
330       "sure you have a TCP packet selected.");
331   }
332 }
333
334 /* The destroy call back has the responsibility of
335  * unlinking the temporary file */
336 static void
337 follow_destroy_cb(GtkWidget *win, gpointer data)
338 {
339         char    *filename;
340
341         filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
342                                                 E_FOLLOW_FILENAME_KEY);
343         g_assert(filename);
344
345         unlink(filename);
346         gtk_widget_destroy(win);
347 }
348
349 #define E_FOLLOW_ASCII_TYPE     0
350 #define E_FOLLOW_EBCDIC_TYPE    1
351 #define E_FOLLOW_HEXDUMP_TYPE   2
352
353 /* Handles the ASCII/EBCDIC toggling */
354 static void
355 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
356 {
357         guint8          show_type = E_FOLLOW_ASCII_TYPE;
358         GtkWidget       *b_ascii, *b_ebcdic, *b_hexdump, *text;
359         char            *filename;
360
361         b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
362                                                    E_FOLLOW_ASCII_KEY);
363         b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
364                                                     E_FOLLOW_EBCDIC_KEY);
365         b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
366                                                      E_FOLLOW_HEXDUMP_KEY);
367         text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
368                                                 E_FOLLOW_TEXT_KEY);
369         filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
370                                                 E_FOLLOW_FILENAME_KEY);
371
372         g_assert(b_ascii);
373         g_assert(b_ebcdic);
374         g_assert(b_hexdump);
375         g_assert(text);
376         g_assert(filename);
377
378         if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
379                 show_type = E_FOLLOW_EBCDIC_TYPE;
380         else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
381                 show_type = E_FOLLOW_HEXDUMP_TYPE;
382
383         follow_load_text(text, filename, show_type);
384 }
385
386 #define FLT_BUF_SIZE 1024
387 static void
388 follow_read_stream(char *filename, guint8 show_type,
389    void (*print_line)(char *, int, gboolean, void *), void *arg)
390 {
391   tcp_stream_chunk sc;
392   int bcount;
393   guint32 client_addr = 0;
394   guint16 client_port = 0;
395   gboolean is_server;
396   guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
397   guint16 *global_pos;
398
399   data_out_file = fopen( filename, "rb" );
400   if( data_out_file ) {
401     char buffer[FLT_BUF_SIZE];
402     int nchars;
403     while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
404       if (client_addr == 0) {
405         client_addr = sc.src_addr;
406         client_port = sc.src_port;
407       }
408       if (client_addr == sc.src_addr && client_port == sc.src_port) {
409         is_server = FALSE;
410         global_pos = &global_client_pos;
411       }
412       else {
413         is_server = TRUE;
414         global_pos = &global_server_pos;
415       }
416         
417       while (sc.dlen > 0) {
418         bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
419         nchars = fread( buffer, 1, bcount, data_out_file );
420         if (nchars == 0)
421           break;
422         sc.dlen -= bcount;
423         switch (show_type) {
424         case E_FOLLOW_EBCDIC_TYPE:
425                 /* If our native arch is ASCII, call: */
426                 EBCDIC_to_ASCII(buffer, nchars);
427         case E_FOLLOW_ASCII_TYPE:
428                 /* If our native arch is EBCDIC, call:
429                  * ASCII_TO_EBCDIC(buffer, nchars);
430                  */
431                 (*print_line)( buffer, nchars, is_server, arg );
432                 break;
433         case E_FOLLOW_HEXDUMP_TYPE:
434                 current_pos = 0;
435                 while (current_pos < nchars)
436                 {
437                     gchar hexbuf[256];
438                     gchar hexchars[] = "0123456789abcdef";
439                     int i, cur;
440                     /* is_server indentation : put 63 spaces at the begenning
441                      * of the string */
442                     sprintf(hexbuf, is_server ?
443                             "                                 "
444                             "                              %08X  " :
445                             "%08X  ", *global_pos);
446                     cur = strlen(hexbuf);
447                     for (i=0; i < 16 && current_pos+i < nchars; i++) {
448                         hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
449                         hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
450                         if (i == 7) {
451                             hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
452                         }
453                         else if (i != 15)
454                             hexbuf[cur++] = ' ';
455                     }
456                     current_pos += i;
457                     (*global_pos) += i;
458                     hexbuf[cur++] = '\n';
459                     hexbuf[cur] = 0;
460                     (*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
461                 }
462                 break;
463         }
464       }
465     }
466     if( ferror( data_out_file ) ) {
467       simple_dialog(ESD_TYPE_WARN, NULL,
468         "Error reading temporary file %s: %s", filename, strerror(errno));
469     }
470     fclose( data_out_file );
471     data_out_file = NULL;
472   } else {
473     simple_dialog(ESD_TYPE_WARN, NULL,
474       "Could not open temporary file %s: %s", filename, strerror(errno));
475   }
476 }
477
478 /*
479  * XXX - for text printing, we probably want to wrap lines at 80 characters;
480  * for PostScript printing, we probably want to wrap them at the appropriate
481  * width, and perhaps put some kind of dingbat (to use the technical term)
482  * to indicate a wrapped line, along the lines of what's done when displaying
483  * this in a window, as per Warren Young's suggestion.
484  *
485  * For now, we support only text printing.
486  */
487 static void
488 follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
489 {
490   FILE *fh = arg;
491
492   fwrite(buffer, nchars, 1, fh);
493 }
494
495 static void
496 follow_print_stream(GtkWidget *w, gpointer parent_w)
497 {
498        FILE *fh;
499        gboolean to_file;
500        char* print_dest;
501        char* filename;
502        guint8 show_type = E_FOLLOW_ASCII_TYPE;
503        GtkWidget *button;
504
505        switch (prefs.pr_dest) {
506                case PR_DEST_CMD:
507                        print_dest = prefs.pr_cmd;
508                        to_file = FALSE;
509                        break;
510
511                case PR_DEST_FILE:
512                        print_dest = prefs.pr_file;
513                        to_file = TRUE;
514                        break;
515                default: /* "Can't happen" */
516                        simple_dialog(ESD_TYPE_WARN, NULL,
517                                "Couldn't figure out where to send the print "
518                                "job. Check your preferences.");
519                        return;
520        }
521
522        fh = open_print_dest(to_file, print_dest);
523        if (fh == NULL) {
524                switch (to_file) {
525                        case FALSE:
526                                simple_dialog(ESD_TYPE_WARN, NULL,
527                                                "Couldn't run print command %s.", prefs.pr_cmd);
528                                break;
529
530                        case TRUE:
531                                simple_dialog(ESD_TYPE_WARN, NULL, 
532                                                file_write_error_message(errno),
533                                                prefs.pr_file);
534                                break;
535                }
536                return;
537        }
538
539        button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
540                        E_FOLLOW_EBCDIC_KEY);
541        if (GTK_TOGGLE_BUTTON(button)->active)
542                show_type = E_FOLLOW_EBCDIC_TYPE;
543        button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
544                        E_FOLLOW_HEXDUMP_KEY);
545        if (GTK_TOGGLE_BUTTON(button)->active)
546                show_type = E_FOLLOW_HEXDUMP_TYPE;
547
548        filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
549                        E_FOLLOW_FILENAME_KEY);
550
551        if (filename != NULL) {
552                print_preamble(fh, PR_FMT_TEXT);
553                follow_read_stream(filename, show_type, follow_print_text, fh);
554                print_finale(fh, PR_FMT_TEXT);
555                close_print_dest(to_file, fh);
556        }
557        else {
558                simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
559        }
560 }
561
562 static void
563 follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
564 {
565   GtkWidget *text = arg;
566
567   if (is_server)
568     gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
569             &prefs.st_server_bg, buffer, nchars );
570   else
571     gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
572             &prefs.st_client_bg, buffer, nchars );
573 }
574
575 static void
576 follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
577 {
578   int bytes_already;
579
580   /* Delete any info already in text box */
581   bytes_already = gtk_text_get_length(GTK_TEXT(text));
582   if (bytes_already > 0) {
583     gtk_text_set_point(GTK_TEXT(text), 0);
584     gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
585   }
586
587   /* stop the updates while we fill the text box */
588   gtk_text_freeze( GTK_TEXT(text) );
589   follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
590   gtk_text_thaw( GTK_TEXT(text) );
591 }
592
593 /* Match selected byte pattern */
594 void
595 match_selected_cb(GtkWidget *w, gpointer data)
596 {
597     char                *buf;
598     GtkWidget           *filter_te;
599     char                *ptr, *format, *stringified;
600     int                 i, dfilter_len, abbrev_len;
601     guint8              *c;
602     header_field_info   *hfinfo;
603
604     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
605
606     if (!finfo_selected) {
607         simple_dialog(ESD_TYPE_WARN, NULL,
608                       "Error determining selected bytes.  Please make\n"
609                       "sure you have selected a field within the tree\n"
610                       "view to be matched.");
611         return;
612     }
613
614     hfinfo = finfo_selected->hfinfo;
615     g_assert(hfinfo);
616     abbrev_len = strlen(hfinfo->abbrev);
617
618         switch(hfinfo->type) {
619
620                 case FT_BOOLEAN:
621                         dfilter_len = abbrev_len + 2;
622                         buf = g_malloc0(dfilter_len);
623                         snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
624                                         hfinfo->abbrev);
625                         break;
626
627                 case FT_UINT8:
628                 case FT_UINT16:
629                 case FT_UINT24:
630                 case FT_UINT32:
631                 case FT_INT8:
632                 case FT_INT16:
633                 case FT_INT24:
634                 case FT_INT32:
635                         dfilter_len = abbrev_len + 20;
636                         buf = g_malloc0(dfilter_len);
637                         format = hfinfo_numeric_format(hfinfo);
638                         snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
639                         break;
640
641                 case FT_IPv4:
642                         dfilter_len = abbrev_len + 4 + 15 + 1;
643                         buf = g_malloc0(dfilter_len);
644                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
645                                         ipv4_addr_str(&(finfo_selected->value.ipv4)));
646                         break;
647
648                 case FT_IPXNET:
649                         dfilter_len = abbrev_len + 15;
650                         buf = g_malloc0(dfilter_len);
651                         snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
652                                         finfo_selected->value.numeric);
653                         break;
654
655                 case FT_IPv6:
656                         stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
657                         dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
658                         buf = g_malloc0(dfilter_len);
659                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
660                                         stringified);
661                         break;
662
663                 case FT_DOUBLE:
664                         dfilter_len = abbrev_len + 30;
665                         buf = g_malloc0(dfilter_len);
666                         snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
667                                         finfo_selected->value.floating);
668                         break;
669
670                 case FT_ETHER:
671                         dfilter_len = abbrev_len + 22;
672                         buf = g_malloc0(dfilter_len);
673                         snprintf(buf, dfilter_len, "%s == %s",
674                                         hfinfo->abbrev,
675                                         ether_to_str(finfo_selected->value.ether));
676                         break;
677 #if 0
678
679                 case FT_ABSOLUTE_TIME:
680                 case FT_RELATIVE_TIME:
681                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
682                                 sizeof(struct timeval));
683                         break;
684
685                 case FT_STRING:
686                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
687                         fi->value.string = g_strdup(va_arg(ap, char*));
688                         break;
689
690                 case FT_TEXT_ONLY:
691                         ; /* nothing */
692                         break;
693 #endif
694                 default:
695                     c = cfile.pd + finfo_selected->start;
696                     buf = g_malloc0(32 + finfo_selected->length * 3);
697                     ptr = buf;
698
699                     sprintf(ptr, "frame[%d] == ", finfo_selected->start);
700                     ptr = buf+strlen(buf);
701
702                     if (finfo_selected->length == 1) {
703                         sprintf(ptr, "0x%02x", *c++);
704                     }
705                     else {
706                             for (i=0;i<finfo_selected->length; i++) {
707                                 if (i == 0 ) {
708                                         sprintf(ptr, "%02x", *c++);
709                                 }
710                                 else {
711                                         sprintf(ptr, ":%02x", *c++);
712                                 }
713                                 ptr = buf+strlen(buf);
714                             }
715                     }
716                     break;
717         }
718
719     /* create a new one and set the display filter entry accordingly */
720     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
721
722     /* Run the display filter so it goes in effect. */
723     filter_packets(&cfile, buf);
724
725     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
726 }
727
728 static char*
729 hfinfo_numeric_format(header_field_info *hfinfo)
730 {
731         char *format = NULL;
732
733         /* Pick the proper format string */
734         switch(hfinfo->display) {
735                 case BASE_DEC:
736                 case BASE_NONE:
737                 case BASE_OCT: /* I'm lazy */
738                 case BASE_BIN: /* I'm lazy */
739                         switch(hfinfo->type) {
740                                 case FT_UINT8:
741                                 case FT_UINT16:
742                                 case FT_UINT24:
743                                 case FT_UINT32:
744                                         format = "%s == %u";
745                                         break;
746                                 case FT_INT8:
747                                 case FT_INT16:
748                                 case FT_INT24:
749                                 case FT_INT32:
750                                         format = "%s == %d";
751                                         break;
752                                 default:
753                                         g_assert_not_reached();
754                                         ;
755                         }
756                         break;
757                 case BASE_HEX:
758                         switch(hfinfo->type) {
759                                 case FT_UINT8:
760                                         format = "%s == 0x%02x";
761                                         break;
762                                 case FT_UINT16:
763                                         format = "%s == 0x%04x";
764                                         break;
765                                 case FT_UINT24:
766                                         format = "%s == 0x%06x";
767                                         break;
768                                 case FT_UINT32:
769                                         format = "%s == 0x%08x";
770                                         break;
771                                 default:
772                                         g_assert_not_reached();
773                                         ;
774                         }
775                         break;
776                 default:
777                         g_assert_not_reached();
778                         ;
779         }
780         return format;
781 }
782
783
784 /* Run the current display filter on the current packet set, and
785    redisplay. */
786 static void
787 filter_activate_cb(GtkWidget *w, gpointer data)
788 {
789   GtkCombo  *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
790   GList     *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
791   GList     *li, *nl = NULL;
792   gboolean   add_filter = TRUE;
793   
794   char *s = gtk_entry_get_text(GTK_ENTRY(w));
795   
796   /* GtkCombos don't let us get at their list contents easily, so we maintain
797      our own filter list, and feed it to gtk_combo_set_popdown_strings when
798      a new filter is added. */
799   if (filter_packets(&cfile, g_strdup(s))) {
800     li = g_list_first(filter_list);
801     while (li) {
802       if (li->data && strcmp(s, li->data) == 0)
803         add_filter = FALSE;
804       li = li->next;
805     }
806
807     if (add_filter) {
808       filter_list = g_list_append(filter_list, g_strdup(s));
809       li = g_list_first(filter_list);
810       while (li) {
811         nl = g_list_append(nl, strdup(li->data));
812         li = li->next;
813       }
814       gtk_combo_set_popdown_strings(filter_cm, nl);
815       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
816     }
817   }
818 }
819
820 /* redisplay with no display filter */
821 static void
822 filter_reset_cb(GtkWidget *w, gpointer data)
823 {
824   GtkWidget *filter_te = NULL;
825
826   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
827     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
828   }
829
830   filter_packets(&cfile, NULL);
831 }
832
833 /* GTKClist compare routine, overrides default to allow numeric comparison */
834 static gint
835 packet_list_compare(GtkCList *clist, gconstpointer  ptr1, gconstpointer  ptr2)
836 {
837   /* Get row text strings */
838   char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
839   char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
840
841   /* Attempt to convert to numbers */
842   double  num1 = atof(text1);
843   double  num2 = atof(text2);
844   
845   gint  col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
846   
847   if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
848       ((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
849       ((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA))    ||
850       (col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
851       ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
852                                       (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
853       (col_fmt == COL_PACKET_LENGTH)) {
854
855     /* Compare numeric column */
856
857     if (num1 < num2)
858       return -1;
859     else if (num1 > num2)
860       return 1;
861     else
862       return 0;
863   }
864   
865   else {
866     
867     /* Compare text column */
868     if (!text2)
869       return (text1 != NULL);
870
871     if (!text1)
872       return -1;
873
874     return strcmp(text1, text2);
875   }
876 }
877
878 /* What to do when a column is clicked */
879 static void 
880 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
881 {
882   if (column == clist->sort_column) {
883     if (clist->sort_type == GTK_SORT_ASCENDING)
884       clist->sort_type = GTK_SORT_DESCENDING;
885     else
886       clist->sort_type = GTK_SORT_ASCENDING;
887   }
888   else {
889     clist->sort_type = GTK_SORT_ASCENDING;
890     gtk_clist_set_sort_column(clist, column);
891   }
892
893   gtk_clist_sort(clist);
894 }
895
896 /* What to do when a list item is selected/unselected */
897 static void
898 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
899
900   blank_packetinfo();
901   select_packet(&cfile, row);
902 }
903
904 static void
905 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
906   unselect_packet(&cfile);
907 }
908
909 static void
910 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
911 {
912         field_info      *finfo;
913
914         g_assert(node);
915         finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
916         if (!finfo) return;
917
918         finfo_selected = finfo;
919
920         packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame->cap_len, 
921                 finfo->start, finfo->length, cfile.current_frame->flags.encoding);
922 }
923
924 static void
925 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
926 {
927         finfo_selected = NULL;
928         packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame->cap_len, 
929                 -1, -1, cfile.current_frame->flags.encoding);
930 }
931
932 void collapse_all_cb(GtkWidget *widget, gpointer data) {
933   if (cfile.protocol_tree)
934     collapse_all_tree(cfile.protocol_tree, tree_view);
935 }
936
937 void expand_all_cb(GtkWidget *widget, gpointer data) {
938   if (cfile.protocol_tree)
939     expand_all_tree(cfile.protocol_tree, tree_view);
940 }
941
942 void resolve_name_cb(GtkWidget *widget, gpointer data) {
943   if (cfile.protocol_tree) {
944     int tmp = g_resolving_actif;
945     g_resolving_actif = 1;
946     gtk_clist_clear ( GTK_CLIST(tree_view) );
947     proto_tree_draw(cfile.protocol_tree, tree_view);
948     g_resolving_actif = tmp;
949   }
950 }
951
952 /* Set the scrollbar placement of a scrolled window based upon pos value:
953    0 = left, 1 = right */
954 void
955 set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
956 {
957         if (pos) {
958                 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
959                                 GTK_CORNER_TOP_LEFT);
960         } else {
961                 gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
962                                 GTK_CORNER_TOP_RIGHT);
963         }
964 }
965
966 /* List of all scrolled windows, so we can globally set the scrollbar
967    placement of them. */
968 static GList *scrolled_windows;
969
970 /* Add a scrolled window to the list of scrolled windows. */
971 void
972 remember_scrolled_window(GtkWidget *scrollw)
973 {
974   scrolled_windows = g_list_append(scrolled_windows, scrollw);
975 }
976
977 /* Remove a scrolled window from the list of scrolled windows. */
978 void
979 forget_scrolled_window(GtkWidget *scrollw)
980 {
981   scrolled_windows = g_list_remove(scrolled_windows, scrollw);
982 }
983
984 static void
985 set_scrollbar_placement_cb(gpointer data, gpointer user_data)
986 {
987         set_scrollbar_placement_scrollw((GtkWidget *)data,
988             *(int *)user_data);
989 }
990
991 /* Set the scrollbar placement of all scrolled windows based on pos value:
992    0 = left, 1 = right */
993 void
994 set_scrollbar_placement_all(int pos)
995 {
996         g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
997 }
998
999 /* Set the selection mode of the packet list window. */
1000 void
1001 set_plist_sel_browse(gboolean val)
1002 {
1003         if (finfo_selected)
1004                 unselect_packet(&cfile);
1005
1006         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
1007          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
1008         if (val) {
1009                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
1010         }
1011         else {
1012                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
1013         }
1014 }
1015
1016 /* Set the selection mode of a given packet tree window. */
1017 void
1018 set_ptree_sel_browse(GtkWidget *tv, gboolean val)
1019 {
1020         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
1021          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
1022         if (val) {
1023                 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_SINGLE);
1024         }
1025         else {
1026                 gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_BROWSE);
1027         }
1028 }
1029
1030 /* Set the selection mode of all packet tree windows. */
1031 void
1032 set_ptree_sel_browse_all(gboolean val)
1033 {
1034         set_ptree_sel_browse(tree_view, val);
1035         set_ptree_sel_browse_packet_wins(val);
1036 }
1037
1038 /* Set the line style of a given packet tree window. */
1039 void
1040 set_ptree_line_style(GtkWidget *tv, gint style)
1041 {
1042         /* I'm using an assert here since the preferences code limits
1043          * the user input, both in the GUI and when reading the preferences file.
1044          * If the value is incorrect, it's a program error, not a user-initiated error.
1045          */
1046         g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
1047         gtk_ctree_set_line_style( GTK_CTREE(tv), style );
1048 }
1049
1050 /* Set the line style of all packet tree window. */
1051 void
1052 set_ptree_line_style_all(gint style)
1053 {
1054         set_ptree_line_style(tree_view, style);
1055         set_ptree_line_style_packet_wins(style);
1056 }
1057
1058 /* Set the expander style of a given packet tree window. */
1059 void
1060 set_ptree_expander_style(GtkWidget *tv, gint style)
1061 {
1062         /* I'm using an assert here since the preferences code limits
1063          * the user input, both in the GUI and when reading the preferences file.
1064          * If the value is incorrect, it's a program error, not a user-initiated error.
1065          */
1066         g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
1067         gtk_ctree_set_expander_style( GTK_CTREE(tv), style );
1068 }
1069         
1070 void
1071 set_ptree_expander_style_all(gint style)
1072 {
1073         set_ptree_expander_style(tree_view, style);
1074         set_ptree_expander_style_packet_wins(style);
1075 }
1076
1077 static gboolean
1078 main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
1079 {
1080         file_quit_cmd_cb(widget, data);
1081
1082         /* Say that the window should be deleted. */
1083         return FALSE;
1084 }
1085
1086 void
1087 file_quit_cmd_cb (GtkWidget *widget, gpointer data)
1088 {
1089         /* XXX - should we check whether the capture file is an
1090            unsaved temporary file for a live capture and, if so,
1091            pop up a "do you want to exit without saving the capture
1092            file?" dialog, and then just return, leaving said dialog
1093            box to forcibly quit if the user clicks "OK"?
1094
1095            If so, note that this should be done in a subroutine that
1096            returns TRUE if we do so, and FALSE otherwise, and that
1097            "main_window_delete_event_cb()" should return its
1098            return value. */
1099
1100         /* Close any capture file we have open; on some OSes, you can't
1101            unlink a temporary capture file if you have it open.
1102            "close_cap_file()" will unlink it after closing it if
1103            it's a temporary file.
1104
1105            We do this here, rather than after the main loop returns,
1106            as, after the main loop returns, the main window may have
1107            been destroyed (if this is called due to a "destroy"
1108            even on the main window rather than due to the user
1109            selecting a menu item), and there may be a crash
1110            or other problem when "close_cap_file()" tries to
1111            clean up stuff in the main window.
1112
1113            XXX - is there a better place to put this?
1114            Or should we have a routine that *just* closes the
1115            capture file, and doesn't do anything with the UI,
1116            which we'd call here, and another routine that
1117            calls that routine and also cleans up the UI, which
1118            we'd call elsewhere? */
1119         close_cap_file(&cfile, info_bar);
1120
1121   fprintf( stderr, "file_quit_cmd_cb: About to call gtk_main_quit()\n");
1122         /* Exit by leaving the main loop, so that any quit functions
1123            we registered get called. */
1124         gtk_main_quit();
1125 }
1126
1127 static void 
1128 print_usage(void) {
1129
1130   fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1131           comp_info_str);
1132 #ifdef HAVE_LIBPCAP
1133   fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1134           PACKAGE);
1135   fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1136   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1137   fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1138   fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1139 #else
1140   fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1141           PACKAGE);
1142   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1143   fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1144   fprintf(stderr, "\t[ -T <tree view height> ]\n");
1145 #endif
1146 }
1147
1148 /* And now our feature presentation... [ fade to music ] */
1149 int
1150 main(int argc, char *argv[])
1151 {
1152 #ifdef HAVE_LIBPCAP
1153   char                *command_name;
1154 #endif
1155   char                *s;
1156   int                  i;
1157   int                  opt;
1158   extern char         *optarg;
1159   gboolean             arg_error = FALSE;
1160 #ifdef HAVE_LIBPCAP
1161 #ifdef WIN32
1162   char pcap_version[] = "0.4a6";
1163 #else
1164   extern char          pcap_version[];
1165 #endif
1166 #endif
1167   char                *pf_path;
1168   int                  pf_open_errno = 0;
1169   int                  err;
1170 #ifdef HAVE_LIBPCAP
1171   gboolean             start_capture = FALSE;
1172   gchar               *save_file = NULL;
1173   GList               *if_list;
1174   gchar                err_str[PCAP_ERRBUF_SIZE];
1175 #else
1176   gboolean             capture_option_specified = FALSE;
1177 #endif
1178   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1179   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1180   dfilter             *rfcode = NULL;
1181   gboolean             rfilter_parse_failed = FALSE;
1182   e_prefs             *prefs;
1183
1184   ethereal_path = argv[0];
1185
1186 #ifdef HAVE_LIBPCAP
1187   command_name = get_basename(ethereal_path);
1188   /* Set "capture_child" to indicate whether this is going to be a child
1189      process for a "-S" capture. */
1190   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1191 #endif
1192
1193   /* If invoked with the "-G" flag, we dump out a glossary of
1194      display filter symbols.
1195
1196      We must do this before calling "gtk_init()", because "gtk_init()"
1197      tries to open an X display, and we don't want to have to do any X
1198      stuff just to do a build.
1199
1200      Given that we call "gtk_init()" before doing the regular argument
1201      list processing, so that it can handle X and GTK+ arguments and
1202      remove them from the list at which we look, this means we must do
1203      this before doing the regular argument list processing, as well.
1204
1205      This means that:
1206
1207         you must give the "-G" flag as the first flag on the command line;
1208
1209         you must give it as "-G", nothing more, nothing less;
1210
1211         any arguments after the "-G" flag will not be used. */
1212   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1213     dissect_init();
1214     proto_registrar_dump();
1215     exit(0);
1216   }
1217
1218   /* Set the current locale according to the program environment. 
1219    * We haven't localized anything, but some GTK widgets are localized
1220    * (the file selection dialogue, for example) */
1221   gtk_set_locale();
1222
1223   /* Let GTK get its args */
1224   gtk_init (&argc, &argv);
1225   
1226   prefs = read_prefs(&pf_path);
1227   if (pf_path != NULL) {
1228     /* The preferences file exists, but couldn't be opened; "pf_path" is
1229        its pathname.  Remember "errno", as that says why the attempt
1230        failed. */
1231     pf_open_errno = errno;
1232   }
1233
1234   /* Initialize the capture file struct */
1235   cfile.plist           = NULL;
1236   cfile.plist_end               = NULL;
1237   cfile.wth             = NULL;
1238   cfile.filename                = NULL;
1239   cfile.user_saved              = FALSE;
1240   cfile.is_tempfile     = FALSE;
1241   cfile.rfcode          = NULL;
1242   cfile.dfilter         = NULL;
1243   cfile.dfcode          = NULL;
1244 #ifdef HAVE_LIBPCAP
1245   cfile.cfilter         = g_strdup(EMPTY_FILTER);
1246 #endif
1247   cfile.iface           = NULL;
1248   cfile.save_file               = NULL;
1249   cfile.save_file_fd    = -1;
1250   cfile.snap            = WTAP_MAX_PACKET_SIZE;
1251   cfile.count           = 0;
1252   cfile.cinfo.num_cols  = prefs->num_cols;
1253   cfile.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
1254   cfile.cinfo.fmt_matx  = (gboolean **) g_malloc(sizeof(gboolean *) * cfile.cinfo.num_cols);
1255   cfile.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
1256   cfile.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
1257   cfile.cinfo.col_data  = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
1258
1259   /* Assemble the compile-time options */
1260   snprintf(comp_info_str, 256,
1261 #ifdef GTK_MAJOR_VERSION
1262     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1263     GTK_MICRO_VERSION,
1264 #else
1265     "GTK+ (version unknown), %s%s, %s%s, %s%s",
1266 #endif
1267
1268 #ifdef HAVE_LIBPCAP
1269    "with libpcap ", pcap_version,
1270 #else
1271    "without libpcap", "",
1272 #endif
1273
1274 #ifdef HAVE_LIBZ
1275 #ifdef ZLIB_VERSION
1276    "with libz ", ZLIB_VERSION,
1277 #else /* ZLIB_VERSION */
1278    "with libz ", "(version unknown)",
1279 #endif /* ZLIB_VERSION */
1280 #else /* HAVE_LIBZ */
1281    "without libz", "",
1282 #endif /* HAVE_LIBZ */
1283
1284 /* Oh, this is pretty */
1285 #if defined(HAVE_UCD_SNMP_SNMP_H)
1286 #ifdef HAVE_UCD_SNMP_VERSION_H
1287    "with UCD SNMP ", VersionInfo
1288 #else /* HAVE_UCD_SNMP_VERSION_H */
1289    "with UCD SNMP ", "(version unknown)"
1290 #endif /* HAVE_UCD_SNMP_VERSION_H */
1291 #elif defined(HAVE_SNMP_SNMP_H)
1292 #ifdef HAVE_SNMP_VERSION_H
1293    "with CMU SNMP ", snmp_Version()
1294 #else /* HAVE_SNMP_VERSION_H */
1295    "with CMU SNMP ", "(version unknown)"
1296 #endif /* HAVE_SNMP_VERSION_H */
1297 #else /* no SNMP */
1298    "without SNMP", ""
1299 #endif
1300    );
1301
1302   /* Now get our args */
1303   while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
1304     switch (opt) {
1305       case 'b':        /* Bold font */
1306         bold_font = g_strdup(optarg);
1307         break;
1308       case 'B':        /* Byte view pane height */
1309         bv_size = atoi(optarg);
1310         break;
1311       case 'c':        /* Capture xxx packets */
1312 #ifdef HAVE_LIBPCAP
1313         cfile.count = atoi(optarg);
1314 #else
1315         capture_option_specified = TRUE;
1316         arg_error = TRUE;
1317 #endif
1318         break;
1319       case 'D':        /* Turn off DSCP printing */
1320         g_ip_dscp_actif = FALSE;
1321         break;
1322       case 'f':
1323 #ifdef HAVE_LIBPCAP
1324         if (cfile.cfilter)
1325                 g_free(cfile.cfilter);
1326         cfile.cfilter = g_strdup(optarg);
1327 #else
1328         capture_option_specified = TRUE;
1329         arg_error = TRUE;
1330 #endif
1331         break;
1332       case 'h':        /* Print help and exit */
1333         print_usage();
1334         exit(0);
1335         break;
1336       case 'i':        /* Use interface xxx */
1337 #ifdef HAVE_LIBPCAP
1338         cfile.iface = g_strdup(optarg);
1339 #else
1340         capture_option_specified = TRUE;
1341         arg_error = TRUE;
1342 #endif
1343         break;
1344       case 'k':        /* Start capture immediately */
1345 #ifdef HAVE_LIBPCAP
1346         start_capture = TRUE;
1347 #else
1348         capture_option_specified = TRUE;
1349         arg_error = TRUE;
1350 #endif
1351         break;
1352       case 'm':        /* Medium font */
1353         medium_font = g_strdup(optarg);
1354         break;
1355       case 'n':        /* No name resolution */
1356         g_resolving_actif = 0;
1357         break;
1358       case 'P':        /* Packet list pane height */
1359         pl_size = atoi(optarg);
1360         break;
1361       case 'Q':        /* Quit after capture (just capture to file) */
1362 #ifdef HAVE_LIBPCAP
1363         quit_after_cap = 1;
1364         start_capture = TRUE;  /*** -Q implies -k !! ***/
1365 #else
1366         capture_option_specified = TRUE;
1367         arg_error = TRUE;
1368 #endif
1369         break;
1370       case 'r':        /* Read capture file xxx */
1371         /* We may set "last_open_dir" to "cf_name", and if we change
1372            "last_open_dir" later, we free the old value, so we have to
1373            set "cf_name" to something that's been allocated. */
1374         cf_name = g_strdup(optarg);
1375         break;
1376       case 'R':        /* Read file filter */
1377         rfilter = optarg;
1378         break;
1379       case 's':        /* Set the snapshot (capture) length */
1380 #ifdef HAVE_LIBPCAP
1381         cfile.snap = atoi(optarg);
1382 #else
1383         capture_option_specified = TRUE;
1384         arg_error = TRUE;
1385 #endif
1386         break;
1387       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1388 #ifdef HAVE_LIBPCAP
1389         sync_mode = TRUE;
1390 #else
1391         capture_option_specified = TRUE;
1392         arg_error = TRUE;
1393 #endif
1394         break;
1395       case 't':        /* Time stamp type */
1396         if (strcmp(optarg, "r") == 0)
1397           timestamp_type = RELATIVE;
1398         else if (strcmp(optarg, "a") == 0)
1399           timestamp_type = ABSOLUTE;
1400         else if (strcmp(optarg, "d") == 0)
1401           timestamp_type = DELTA;
1402         else {
1403           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1404             optarg);
1405           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1406           fprintf(stderr, "or \"d\" for delta.\n");
1407           exit(1);
1408         }
1409         break;
1410       case 'T':        /* Tree view pane height */
1411         tv_size = atoi(optarg);
1412         break;
1413       case 'v':        /* Show version and exit */
1414         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1415         exit(0);
1416         break;
1417       case 'w':        /* Write to capture file xxx */
1418 #ifdef HAVE_LIBPCAP
1419         save_file = g_strdup(optarg);
1420 #else
1421         capture_option_specified = TRUE;
1422         arg_error = TRUE;
1423 #endif
1424         break;
1425       case 'W':        /* Write to capture file FD xxx */
1426 #ifdef HAVE_LIBPCAP
1427         cfile.save_file_fd = atoi(optarg);
1428 #else
1429         capture_option_specified = TRUE;
1430         arg_error = TRUE;
1431 #endif
1432         break;
1433
1434 #ifdef _WIN32
1435       case 'Z':        /* Write to pipe FD XXX */
1436 #ifdef HAVE_LIBPCAP
1437         /* associate stdout with pipe */
1438         i = atoi(optarg);
1439         if (dup2(i, 1) < 0) {
1440           fprintf(stderr, "Unable to dup pipe handle\n");
1441           exit(1);
1442         }
1443 #else
1444         capture_option_specified = TRUE;
1445         arg_error = TRUE;
1446 #endif /* HAVE_LIBPCAP */
1447         break;
1448 #endif /* _WIN32 */
1449
1450       default:
1451       case '?':        /* Bad flag - print usage message */
1452         arg_error = TRUE;
1453         break;
1454     }
1455   }
1456
1457 #ifndef HAVE_LIBPCAP
1458   if (capture_option_specified)
1459     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1460 #endif
1461   if (arg_error)
1462     print_usage();
1463 #ifdef HAVE_LIBPCAP
1464   if (start_capture) {
1465     /* We're supposed to do a live capture; did the user specify an interface
1466        to use? */
1467     if (cfile.iface == NULL) {
1468       /* No - pick the first one from the list of interfaces. */
1469       if_list = get_interface_list(&err, err_str);
1470       if (if_list == NULL) {
1471         switch (err) {
1472
1473         case CANT_GET_INTERFACE_LIST:
1474             fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1475                         err_str);
1476             break;
1477
1478         case NO_INTERFACES_FOUND:
1479             fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1480             break;
1481         }
1482         exit(2);
1483       }
1484       cfile.iface = g_strdup(if_list->data);    /* first interface */
1485       free_interface_list(if_list);
1486     }
1487   }
1488   if (capture_child) {
1489     if (cfile.save_file_fd == -1) {
1490       /* XXX - send this to the standard output as something our parent
1491          should put in an error message box? */
1492       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1493       exit(1);
1494     }
1495   }
1496 #endif
1497
1498   /* Build the column format array */  
1499   for (i = 0; i < cfile.cinfo.num_cols; i++) {
1500     cfile.cinfo.col_fmt[i] = get_column_format(i);
1501     cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
1502     cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1503       NUM_COL_FMTS);
1504     get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
1505     if (cfile.cinfo.col_fmt[i] == COL_INFO)
1506       cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1507     else
1508       cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1509   }
1510
1511   if (cfile.snap < 1)
1512     cfile.snap = WTAP_MAX_PACKET_SIZE;
1513   else if (cfile.snap < MIN_PACKET_SIZE)
1514     cfile.snap = MIN_PACKET_SIZE;
1515   
1516   rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1517   sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1518   gtk_rc_parse(rc_file);
1519
1520   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1521     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1522     exit(1);
1523   }
1524
1525   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1526     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1527     exit(1);
1528   }
1529
1530   create_main_window(pl_size, tv_size, bv_size, prefs);
1531
1532 /* 
1533    Hmmm should we do it here
1534 */
1535
1536   dissect_init();   /* Init anything that needs initializing */
1537
1538 #ifdef HAVE_LIBPCAP
1539   /* Is this a "child" ethereal, which is only supposed to pop up a
1540      capture box to let us stop the capture, and run a capture
1541      to a file that our parent will read? */
1542   if (!capture_child) {
1543 #endif
1544     /* No.  Pop up the main window, and read in a capture file if
1545        we were told to. */
1546
1547     gtk_widget_show(top_level);
1548     set_menus_for_capture_file(FALSE);
1549
1550     cfile.colors = colfilter_new();
1551
1552     /* If we were given the name of a capture file, read it in now;
1553        we defer it until now, so that, if we can't open it, and pop
1554        up an alert box, the alert box is more likely to come up on
1555        top of the main window - but before the preference-file-error
1556        alert box, so, if we get one of those, it's more likely to come
1557        up on top of us. */
1558     if (cf_name) {
1559       if (rfilter != NULL) {
1560         if (dfilter_compile(rfilter, &rfcode) != 0) {
1561           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1562           rfilter_parse_failed = TRUE;
1563         }
1564       }
1565       if (!rfilter_parse_failed) {
1566         if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
1567           /* "open_cap_file()" succeeded, so it closed the previous
1568              capture file, and thus destroyed any previous read filter
1569              attached to "cf". */
1570           cfile.rfcode = rfcode;
1571           err = read_cap_file(&cfile);
1572           /* Save the name of the containing directory specified in the
1573              path name, if any; we can write over cf_name, which is a
1574              good thing, given that "get_dirname()" does write over its
1575              argument. */
1576           s = get_dirname(cf_name);
1577           if (s != NULL)
1578             last_open_dir = s;
1579         } else {
1580           dfilter_destroy(rfcode);
1581           cfile.rfcode = NULL;
1582         }
1583       }
1584     }
1585 #ifdef HAVE_LIBPCAP
1586   }
1587 #endif
1588
1589   /* If we failed to open the preferences file, pop up an alert box;
1590      we defer it until now, so that the alert box is more likely to
1591      come up on top of the main window. */
1592   if (pf_path != NULL) {
1593       simple_dialog(ESD_TYPE_WARN, NULL,
1594         "Could not open preferences file\n\"%s\": %s.", pf_path,
1595         strerror(pf_open_errno));
1596   }
1597
1598 #ifdef HAVE_LIBPCAP
1599   if (capture_child) {
1600     /* This is the child process for a sync mode or fork mode capture,
1601        so just do the low-level work of a capture - don't create
1602        a temporary file and fork off *another* child process (so don't
1603        call "do_capture()"). */
1604
1605        capture();
1606
1607        /* The capture is done; there's nothing more for us to do. */
1608        gtk_exit(0);
1609   } else {
1610     if (start_capture) {
1611       /* "-k" was specified; start a capture. */
1612       do_capture(save_file);
1613     }
1614     else {
1615       set_menus_for_capture_in_progress(FALSE);
1616     }
1617   }
1618 #else
1619   set_menus_for_capture_in_progress(FALSE);
1620 #endif
1621
1622   gtk_main();
1623
1624   dissect_cleanup();
1625   g_free(rc_file);
1626
1627   gtk_exit(0);
1628
1629   /* This isn't reached, but we need it to keep GCC from complaining
1630      that "main()" returns without returning a value - it knows that
1631      "exit()" never returns, but it doesn't know that "gtk_exit()"
1632      doesn't, as GTK+ doesn't declare it with the attribute
1633      "noreturn". */
1634   return 0;     /* not reached */
1635 }
1636
1637 #ifdef WIN32
1638
1639 /* We build this as a GUI subsystem application on Win32, so
1640    "WinMain()", not "main()", gets called.
1641
1642    Hack shamelessly stolen from the Win32 port of the GIMP. */
1643 #ifdef __GNUC__
1644 #define _stdcall  __attribute__((stdcall))
1645 #endif
1646
1647 int _stdcall
1648 WinMain (struct HINSTANCE__ *hInstance,
1649          struct HINSTANCE__ *hPrevInstance,
1650          char               *lpszCmdLine,
1651          int                 nCmdShow)
1652 {
1653   return main (__argc, __argv);
1654 }
1655
1656 #endif
1657
1658 static void
1659 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1660 {
1661   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
1662                       *stat_hbox,
1663                       *filter_bt, *filter_cm, *filter_te,
1664                       *filter_reset;
1665   GList               *filter_list = NULL;
1666   GtkStyle            *pl_style;
1667   GtkAccelGroup       *accel;
1668   int                   i;
1669
1670   /* Main window */  
1671   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1672   gtk_widget_set_name(top_level, "main window");
1673   gtk_signal_connect(GTK_OBJECT(top_level), "delete_event", 
1674     GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1675   gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1676   gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1677   gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1678
1679   /* Container for menu bar, paned windows and progress/info box */
1680   main_vbox = gtk_vbox_new(FALSE, 1);
1681   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1682   gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1683   gtk_widget_show(main_vbox);
1684
1685   /* Menu bar */
1686   get_main_menu(&menubar, &accel);
1687   gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1688   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1689   gtk_widget_show(menubar);
1690
1691   /* Panes for the packet list, tree, and byte view */
1692   u_pane = gtk_vpaned_new();
1693   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1694   l_pane = gtk_vpaned_new();
1695   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1696   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1697   gtk_widget_show(l_pane);
1698   gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1699   gtk_widget_show(u_pane);
1700
1701   /* Packet list */
1702   pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1703   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1704     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1705   set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1706   remember_scrolled_window(pkt_scrollw);
1707   gtk_widget_show(pkt_scrollw);
1708   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1709
1710   packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
1711   gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1712   
1713   set_plist_sel_browse(prefs->gui_plist_sel_browse);
1714   pl_style = gtk_style_new();
1715   gdk_font_unref(pl_style->font);
1716   pl_style->font = m_r_font;
1717   gtk_widget_set_style(packet_list, pl_style);
1718   gtk_widget_set_name(packet_list, "packet list");
1719   gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1720     GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1721   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1722     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1723   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1724     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1725   for (i = 0; i < cfile.cinfo.num_cols; i++) {
1726     if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1727       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1728
1729     /* Right-justify the packet number column. */
1730     if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
1731       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1732         GTK_JUSTIFY_RIGHT);
1733
1734     /* Save static column sizes to use during a "-S" capture, so that
1735        the columns don't resize during a live capture. */
1736     cfile.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1737                                 get_column_longest_string(get_column_format(i)));
1738   }
1739   gtk_widget_set_usize(packet_list, -1, pl_size);
1740   gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1741     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1742   gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1743   gtk_widget_show(packet_list);
1744
1745   /* Tree view */
1746   create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1747                         prefs->gui_scrollbar_on_right);
1748   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1749     GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1750   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1751     GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1752   gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1753     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1754   gtk_widget_show(tree_view);
1755
1756   item_style = gtk_style_new();
1757   gdk_font_unref(item_style->font);
1758   item_style->font = m_r_font;
1759
1760   /* Byte view. */
1761   create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1762                         prefs->gui_scrollbar_on_right);
1763
1764   /* Progress/filter/info box */
1765   stat_hbox = gtk_hbox_new(FALSE, 1);
1766   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1767   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1768   gtk_widget_show(stat_hbox);
1769
1770   prog_bar = gtk_progress_bar_new();
1771   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1772   gtk_widget_show(prog_bar);
1773
1774   filter_bt = gtk_button_new_with_label("Filter:");
1775   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1776     GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1777   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1778   gtk_widget_show(filter_bt);
1779   
1780   filter_cm = gtk_combo_new();
1781   filter_list = g_list_append (filter_list, "");
1782   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1783   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1784   filter_te = GTK_COMBO(filter_cm)->entry;
1785   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1786   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1787   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1788   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1789   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1790     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1791   gtk_widget_show(filter_cm);
1792
1793   filter_reset = gtk_button_new_with_label("Reset");
1794   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1795   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1796                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1797   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1798   gtk_widget_show(filter_reset);
1799
1800   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1801    * of any widget that ends up calling a callback which needs
1802    * that text entry pointer */
1803   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1804   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1805   set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1806   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1807   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1808
1809   info_bar = gtk_statusbar_new();
1810   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1811   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1812   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1813   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1814   gtk_widget_show(info_bar);
1815 }