Write and read the temporary file for "Follow TCP Stream" as a binary
[metze/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.122 2000/06/24 05:06:29 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 cf;
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(&cf, 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 = cf.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(&cf, 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(&cf, 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(&cf, 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 = cf.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(&cf, row);
902 }
903
904 static void
905 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
906   unselect_packet(&cf);
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), cf.pd, cf.current_frame->cap_len, 
921                 finfo->start, finfo->length, cf.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), cf.pd, cf.current_frame->cap_len, 
929                 -1, -1, cf.current_frame->flags.encoding);
930 }
931
932 void collapse_all_cb(GtkWidget *widget, gpointer data) {
933   if (cf.protocol_tree)
934     collapse_all_tree(cf.protocol_tree, tree_view);
935 }
936
937 void expand_all_cb(GtkWidget *widget, gpointer data) {
938   if (cf.protocol_tree)
939     expand_all_tree(cf.protocol_tree, tree_view);
940 }
941
942 void resolve_name_cb(GtkWidget *widget, gpointer data) {
943   if (cf.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(cf.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(&cf);
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(&cf, info_bar);
1120
1121         /* Exit by leaving the main loop, so that any quit functions
1122            we registered get called. */
1123         gtk_main_quit();
1124 }
1125
1126 static void 
1127 print_usage(void) {
1128
1129   fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
1130           comp_info_str);
1131 #ifdef HAVE_LIBPCAP
1132   fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1133           PACKAGE);
1134   fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
1135   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1136   fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
1137   fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
1138 #else
1139   fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
1140           PACKAGE);
1141   fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
1142   fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
1143   fprintf(stderr, "\t[ -T <tree view height> ]\n");
1144 #endif
1145 }
1146
1147 /* And now our feature presentation... [ fade to music ] */
1148 int
1149 main(int argc, char *argv[])
1150 {
1151 #ifdef HAVE_LIBPCAP
1152   char                *command_name;
1153 #endif
1154   char                *s;
1155   int                  i;
1156   int                  opt;
1157   extern char         *optarg;
1158   gboolean             arg_error = FALSE;
1159 #ifdef HAVE_LIBPCAP
1160 #ifdef WIN32
1161   char pcap_version[] = "0.4a6";
1162 #else
1163   extern char          pcap_version[];
1164 #endif
1165 #endif
1166   char                *pf_path;
1167   int                  pf_open_errno = 0;
1168   int                  err;
1169 #ifdef HAVE_LIBPCAP
1170   gboolean             start_capture = FALSE;
1171   gchar               *save_file = NULL;
1172   GList               *if_list;
1173   gchar                err_str[PCAP_ERRBUF_SIZE];
1174 #else
1175   gboolean             capture_option_specified = FALSE;
1176 #endif
1177   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
1178   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
1179   dfilter             *rfcode = NULL;
1180   gboolean             rfilter_parse_failed = FALSE;
1181   e_prefs             *prefs;
1182
1183   ethereal_path = argv[0];
1184
1185 #ifdef HAVE_LIBPCAP
1186   command_name = get_basename(ethereal_path);
1187   /* Set "capture_child" to indicate whether this is going to be a child
1188      process for a "-S" capture. */
1189   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
1190 #endif
1191
1192   /* If invoked with the "-G" flag, we dump out a glossary of
1193      display filter symbols.
1194
1195      We must do this before calling "gtk_init()", because "gtk_init()"
1196      tries to open an X display, and we don't want to have to do any X
1197      stuff just to do a build.
1198
1199      Given that we call "gtk_init()" before doing the regular argument
1200      list processing, so that it can handle X and GTK+ arguments and
1201      remove them from the list at which we look, this means we must do
1202      this before doing the regular argument list processing, as well.
1203
1204      This means that:
1205
1206         you must give the "-G" flag as the first flag on the command line;
1207
1208         you must give it as "-G", nothing more, nothing less;
1209
1210         any arguments after the "-G" flag will not be used. */
1211   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
1212     dissect_init();
1213     proto_registrar_dump();
1214     exit(0);
1215   }
1216
1217   /* Set the current locale according to the program environment. 
1218    * We haven't localized anything, but some GTK widgets are localized
1219    * (the file selection dialogue, for example) */
1220   gtk_set_locale();
1221
1222   /* Let GTK get its args */
1223   gtk_init (&argc, &argv);
1224   
1225   prefs = read_prefs(&pf_path);
1226   if (pf_path != NULL) {
1227     /* The preferences file exists, but couldn't be opened; "pf_path" is
1228        its pathname.  Remember "errno", as that says why the attempt
1229        failed. */
1230     pf_open_errno = errno;
1231   }
1232
1233   /* Initialize the capture file struct */
1234   cf.plist              = NULL;
1235   cf.plist_end          = NULL;
1236   cf.wth                = NULL;
1237   cf.filename           = NULL;
1238   cf.user_saved         = FALSE;
1239   cf.is_tempfile        = FALSE;
1240   cf.rfcode             = NULL;
1241   cf.dfilter            = NULL;
1242   cf.dfcode             = NULL;
1243 #ifdef HAVE_LIBPCAP
1244   cf.cfilter            = g_strdup(EMPTY_FILTER);
1245 #endif
1246   cf.iface              = NULL;
1247   cf.save_file          = NULL;
1248   cf.save_file_fd       = -1;
1249   cf.snap               = WTAP_MAX_PACKET_SIZE;
1250   cf.count              = 0;
1251   cf.cinfo.num_cols     = prefs->num_cols;
1252   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1253   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
1254   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
1255   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1256   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
1257
1258   /* Assemble the compile-time options */
1259   snprintf(comp_info_str, 256,
1260 #ifdef GTK_MAJOR_VERSION
1261     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1262     GTK_MICRO_VERSION,
1263 #else
1264     "GTK+ (version unknown), %s%s, %s%s, %s%s",
1265 #endif
1266
1267 #ifdef HAVE_LIBPCAP
1268    "with libpcap ", pcap_version,
1269 #else
1270    "without libpcap", "",
1271 #endif
1272
1273 #ifdef HAVE_LIBZ
1274 #ifdef ZLIB_VERSION
1275    "with libz ", ZLIB_VERSION,
1276 #else /* ZLIB_VERSION */
1277    "with libz ", "(version unknown)",
1278 #endif /* ZLIB_VERSION */
1279 #else /* HAVE_LIBZ */
1280    "without libz", "",
1281 #endif /* HAVE_LIBZ */
1282
1283 /* Oh, this is pretty */
1284 #if defined(HAVE_UCD_SNMP_SNMP_H)
1285 #ifdef HAVE_UCD_SNMP_VERSION_H
1286    "with UCD SNMP ", VersionInfo
1287 #else /* HAVE_UCD_SNMP_VERSION_H */
1288    "with UCD SNMP ", "(version unknown)"
1289 #endif /* HAVE_UCD_SNMP_VERSION_H */
1290 #elif defined(HAVE_SNMP_SNMP_H)
1291 #ifdef HAVE_SNMP_VERSION_H
1292    "with CMU SNMP ", snmp_Version()
1293 #else /* HAVE_SNMP_VERSION_H */
1294    "with CMU SNMP ", "(version unknown)"
1295 #endif /* HAVE_SNMP_VERSION_H */
1296 #else /* no SNMP */
1297    "without SNMP", ""
1298 #endif
1299    );
1300
1301   /* Now get our args */
1302   while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
1303     switch (opt) {
1304       case 'b':        /* Bold font */
1305         bold_font = g_strdup(optarg);
1306         break;
1307       case 'B':        /* Byte view pane height */
1308         bv_size = atoi(optarg);
1309         break;
1310       case 'c':        /* Capture xxx packets */
1311 #ifdef HAVE_LIBPCAP
1312         cf.count = atoi(optarg);
1313 #else
1314         capture_option_specified = TRUE;
1315         arg_error = TRUE;
1316 #endif
1317         break;
1318       case 'D':        /* Turn off DSCP printing */
1319         g_ip_dscp_actif = FALSE;
1320         break;
1321       case 'f':
1322 #ifdef HAVE_LIBPCAP
1323         if (cf.cfilter)
1324                 g_free(cf.cfilter);
1325         cf.cfilter = g_strdup(optarg);
1326 #else
1327         capture_option_specified = TRUE;
1328         arg_error = TRUE;
1329 #endif
1330         break;
1331       case 'h':        /* Print help and exit */
1332         print_usage();
1333         exit(0);
1334         break;
1335       case 'i':        /* Use interface xxx */
1336 #ifdef HAVE_LIBPCAP
1337         cf.iface = g_strdup(optarg);
1338 #else
1339         capture_option_specified = TRUE;
1340         arg_error = TRUE;
1341 #endif
1342         break;
1343       case 'k':        /* Start capture immediately */
1344 #ifdef HAVE_LIBPCAP
1345         start_capture = TRUE;
1346 #else
1347         capture_option_specified = TRUE;
1348         arg_error = TRUE;
1349 #endif
1350         break;
1351       case 'm':        /* Medium font */
1352         medium_font = g_strdup(optarg);
1353         break;
1354       case 'n':        /* No name resolution */
1355         g_resolving_actif = 0;
1356         break;
1357       case 'P':        /* Packet list pane height */
1358         pl_size = atoi(optarg);
1359         break;
1360       case 'Q':        /* Quit after capture (just capture to file) */
1361 #ifdef HAVE_LIBPCAP
1362         quit_after_cap = 1;
1363         start_capture = TRUE;  /*** -Q implies -k !! ***/
1364 #else
1365         capture_option_specified = TRUE;
1366         arg_error = TRUE;
1367 #endif
1368         break;
1369       case 'r':        /* Read capture file xxx */
1370         /* We may set "last_open_dir" to "cf_name", and if we change
1371            "last_open_dir" later, we free the old value, so we have to
1372            set "cf_name" to something that's been allocated. */
1373         cf_name = g_strdup(optarg);
1374         break;
1375       case 'R':        /* Read file filter */
1376         rfilter = optarg;
1377         break;
1378       case 's':        /* Set the snapshot (capture) length */
1379 #ifdef HAVE_LIBPCAP
1380         cf.snap = atoi(optarg);
1381 #else
1382         capture_option_specified = TRUE;
1383         arg_error = TRUE;
1384 #endif
1385         break;
1386       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1387 #ifdef HAVE_LIBPCAP
1388         sync_mode = TRUE;
1389 #else
1390         capture_option_specified = TRUE;
1391         arg_error = TRUE;
1392 #endif
1393         break;
1394       case 't':        /* Time stamp type */
1395         if (strcmp(optarg, "r") == 0)
1396           timestamp_type = RELATIVE;
1397         else if (strcmp(optarg, "a") == 0)
1398           timestamp_type = ABSOLUTE;
1399         else if (strcmp(optarg, "d") == 0)
1400           timestamp_type = DELTA;
1401         else {
1402           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1403             optarg);
1404           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1405           fprintf(stderr, "or \"d\" for delta.\n");
1406           exit(1);
1407         }
1408         break;
1409       case 'T':        /* Tree view pane height */
1410         tv_size = atoi(optarg);
1411         break;
1412       case 'v':        /* Show version and exit */
1413         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1414         exit(0);
1415         break;
1416       case 'w':        /* Write to capture file xxx */
1417 #ifdef HAVE_LIBPCAP
1418         save_file = g_strdup(optarg);
1419 #else
1420         capture_option_specified = TRUE;
1421         arg_error = TRUE;
1422 #endif
1423         break;
1424       case 'W':        /* Write to capture file FD xxx */
1425 #ifdef HAVE_LIBPCAP
1426         cf.save_file_fd = atoi(optarg);
1427 #else
1428         capture_option_specified = TRUE;
1429         arg_error = TRUE;
1430 #endif
1431         break;
1432
1433 #ifdef _WIN32
1434       case 'Z':        /* Write to pipe FD XXX */
1435 #ifdef HAVE_LIBPCAP
1436         /* associate stdout with pipe */
1437         i = atoi(optarg);
1438         if (dup2(i, 1) < 0) {
1439           fprintf(stderr, "Unable to dup pipe handle\n");
1440           exit(1);
1441         }
1442 #else
1443         capture_option_specified = TRUE;
1444         arg_error = TRUE;
1445 #endif /* HAVE_LIBPCAP */
1446         break;
1447 #endif /* _WIN32 */
1448
1449       default:
1450       case '?':        /* Bad flag - print usage message */
1451         arg_error = TRUE;
1452         break;
1453     }
1454   }
1455
1456 #ifndef HAVE_LIBPCAP
1457   if (capture_option_specified)
1458     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1459 #endif
1460   if (arg_error)
1461     print_usage();
1462 #ifdef HAVE_LIBPCAP
1463   if (start_capture) {
1464     /* We're supposed to do a live capture; did the user specify an interface
1465        to use? */
1466     if (cf.iface == NULL) {
1467       /* No - pick the first one from the list of interfaces. */
1468       if_list = get_interface_list(&err, err_str);
1469       if (if_list == NULL) {
1470         switch (err) {
1471
1472         case CANT_GET_INTERFACE_LIST:
1473             fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
1474                         err_str);
1475             break;
1476
1477         case NO_INTERFACES_FOUND:
1478             fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
1479             break;
1480         }
1481         exit(2);
1482       }
1483       cf.iface = g_strdup(if_list->data);       /* first interface */
1484       free_interface_list(if_list);
1485     }
1486   }
1487   if (capture_child) {
1488     if (cf.save_file_fd == -1) {
1489       /* XXX - send this to the standard output as something our parent
1490          should put in an error message box? */
1491       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1492       exit(1);
1493     }
1494   }
1495 #endif
1496
1497   /* Build the column format array */  
1498   for (i = 0; i < cf.cinfo.num_cols; i++) {
1499     cf.cinfo.col_fmt[i] = get_column_format(i);
1500     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1501     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1502       NUM_COL_FMTS);
1503     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1504     if (cf.cinfo.col_fmt[i] == COL_INFO)
1505       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1506     else
1507       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1508   }
1509
1510   if (cf.snap < 1)
1511     cf.snap = WTAP_MAX_PACKET_SIZE;
1512   else if (cf.snap < MIN_PACKET_SIZE)
1513     cf.snap = MIN_PACKET_SIZE;
1514   
1515   rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
1516   sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
1517   gtk_rc_parse(rc_file);
1518
1519   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1520     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1521     exit(1);
1522   }
1523
1524   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1525     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1526     exit(1);
1527   }
1528
1529   create_main_window(pl_size, tv_size, bv_size, prefs);
1530
1531 /* 
1532    Hmmm should we do it here
1533 */
1534
1535   dissect_init();   /* Init anything that needs initializing */
1536
1537 #ifdef HAVE_LIBPCAP
1538   /* Is this a "child" ethereal, which is only supposed to pop up a
1539      capture box to let us stop the capture, and run a capture
1540      to a file that our parent will read? */
1541   if (!capture_child) {
1542 #endif
1543     /* No.  Pop up the main window, and read in a capture file if
1544        we were told to. */
1545
1546     gtk_widget_show(top_level);
1547     set_menus_for_capture_file(FALSE);
1548
1549     cf.colors = colfilter_new();
1550
1551     /* If we were given the name of a capture file, read it in now;
1552        we defer it until now, so that, if we can't open it, and pop
1553        up an alert box, the alert box is more likely to come up on
1554        top of the main window - but before the preference-file-error
1555        alert box, so, if we get one of those, it's more likely to come
1556        up on top of us. */
1557     if (cf_name) {
1558       if (rfilter != NULL) {
1559         if (dfilter_compile(rfilter, &rfcode) != 0) {
1560           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1561           rfilter_parse_failed = TRUE;
1562         }
1563       }
1564       if (!rfilter_parse_failed) {
1565         if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1566           /* "open_cap_file()" succeeded, so it closed the previous
1567              capture file, and thus destroyed any previous read filter
1568              attached to "cf". */
1569           cf.rfcode = rfcode;
1570           err = read_cap_file(&cf);
1571           /* Save the name of the containing directory specified in the
1572              path name, if any; we can write over cf_name, which is a
1573              good thing, given that "get_dirname()" does write over its
1574              argument. */
1575           s = get_dirname(cf_name);
1576           if (s != NULL)
1577             last_open_dir = s;
1578         } else {
1579           dfilter_destroy(rfcode);
1580           cf.rfcode = NULL;
1581         }
1582       }
1583     }
1584 #ifdef HAVE_LIBPCAP
1585   }
1586 #endif
1587
1588   /* If we failed to open the preferences file, pop up an alert box;
1589      we defer it until now, so that the alert box is more likely to
1590      come up on top of the main window. */
1591   if (pf_path != NULL) {
1592       simple_dialog(ESD_TYPE_WARN, NULL,
1593         "Could not open preferences file\n\"%s\": %s.", pf_path,
1594         strerror(pf_open_errno));
1595   }
1596
1597 #ifdef HAVE_LIBPCAP
1598   if (capture_child) {
1599     /* This is the child process for a sync mode or fork mode capture,
1600        so just do the low-level work of a capture - don't create
1601        a temporary file and fork off *another* child process (so don't
1602        call "do_capture()"). */
1603
1604        capture();
1605
1606        /* The capture is done; there's nothing more for us to do. */
1607        gtk_exit(0);
1608   } else {
1609     if (start_capture) {
1610       /* "-k" was specified; start a capture. */
1611       do_capture(save_file);
1612     }
1613     else {
1614       set_menus_for_capture_in_progress(FALSE);
1615     }
1616   }
1617 #else
1618   set_menus_for_capture_in_progress(FALSE);
1619 #endif
1620
1621   gtk_main();
1622
1623   dissect_cleanup();
1624   g_free(rc_file);
1625
1626   gtk_exit(0);
1627
1628   /* This isn't reached, but we need it to keep GCC from complaining
1629      that "main()" returns without returning a value - it knows that
1630      "exit()" never returns, but it doesn't know that "gtk_exit()"
1631      doesn't, as GTK+ doesn't declare it with the attribute
1632      "noreturn". */
1633   return 0;     /* not reached */
1634 }
1635
1636 #ifdef WIN32
1637
1638 /* We build this as a GUI subsystem application on Win32, so
1639    "WinMain()", not "main()", gets called.
1640
1641    Hack shamelessly stolen from the Win32 port of the GIMP. */
1642 #ifdef __GNUC__
1643 #define _stdcall  __attribute__((stdcall))
1644 #endif
1645
1646 int _stdcall
1647 WinMain (struct HINSTANCE__ *hInstance,
1648          struct HINSTANCE__ *hPrevInstance,
1649          char               *lpszCmdLine,
1650          int                 nCmdShow)
1651 {
1652   return main (__argc, __argv);
1653 }
1654
1655 #endif
1656
1657 static void
1658 create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
1659 {
1660   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
1661                       *stat_hbox,
1662                       *filter_bt, *filter_cm, *filter_te,
1663                       *filter_reset;
1664   GList               *filter_list = NULL;
1665   GtkStyle            *pl_style;
1666   GtkAccelGroup       *accel;
1667   int                   i;
1668
1669   /* Main window */  
1670   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1671   gtk_widget_set_name(top_level, "main window");
1672   gtk_signal_connect(GTK_OBJECT(top_level), "delete_event", 
1673     GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
1674   gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1675   gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1676   gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1677
1678   /* Container for menu bar, paned windows and progress/info box */
1679   main_vbox = gtk_vbox_new(FALSE, 1);
1680   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1681   gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1682   gtk_widget_show(main_vbox);
1683
1684   /* Menu bar */
1685   get_main_menu(&menubar, &accel);
1686   gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1687   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1688   gtk_widget_show(menubar);
1689
1690   /* Panes for the packet list, tree, and byte view */
1691   u_pane = gtk_vpaned_new();
1692   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1693   l_pane = gtk_vpaned_new();
1694   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1695   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
1696   gtk_widget_show(l_pane);
1697   gtk_paned_add2(GTK_PANED(u_pane), l_pane);
1698   gtk_widget_show(u_pane);
1699
1700   /* Packet list */
1701   pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1702   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1703     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1704   set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
1705   remember_scrolled_window(pkt_scrollw);
1706   gtk_widget_show(pkt_scrollw);
1707   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1708
1709   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1710   gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1711   
1712   set_plist_sel_browse(prefs->gui_plist_sel_browse);
1713   pl_style = gtk_style_new();
1714   gdk_font_unref(pl_style->font);
1715   pl_style->font = m_r_font;
1716   gtk_widget_set_style(packet_list, pl_style);
1717   gtk_widget_set_name(packet_list, "packet list");
1718   gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
1719     GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
1720   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1721     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1722   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1723     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1724   for (i = 0; i < cf.cinfo.num_cols; i++) {
1725     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1726       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1727
1728     /* Right-justify the packet number column. */
1729     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1730       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1731         GTK_JUSTIFY_RIGHT);
1732
1733     /* Save static column sizes to use during a "-S" capture, so that
1734        the columns don't resize during a live capture. */
1735     cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
1736                                 get_column_longest_string(get_column_format(i)));
1737   }
1738   gtk_widget_set_usize(packet_list, -1, pl_size);
1739   gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
1740     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
1741   gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
1742   gtk_widget_show(packet_list);
1743
1744   /* Tree view */
1745   create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
1746                         prefs->gui_scrollbar_on_right);
1747   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1748     GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1749   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1750     GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1751   gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
1752     GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
1753   gtk_widget_show(tree_view);
1754
1755   item_style = gtk_style_new();
1756   gdk_font_unref(item_style->font);
1757   item_style->font = m_r_font;
1758
1759   /* Byte view. */
1760   create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
1761                         prefs->gui_scrollbar_on_right);
1762
1763   /* Progress/filter/info box */
1764   stat_hbox = gtk_hbox_new(FALSE, 1);
1765   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1766   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1767   gtk_widget_show(stat_hbox);
1768
1769   prog_bar = gtk_progress_bar_new();
1770   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1771   gtk_widget_show(prog_bar);
1772
1773   filter_bt = gtk_button_new_with_label("Filter:");
1774   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1775     GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
1776   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1777   gtk_widget_show(filter_bt);
1778   
1779   filter_cm = gtk_combo_new();
1780   filter_list = g_list_append (filter_list, "");
1781   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1782   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1783   filter_te = GTK_COMBO(filter_cm)->entry;
1784   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1785   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1786   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1787   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1788   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1789     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1790   gtk_widget_show(filter_cm);
1791
1792   filter_reset = gtk_button_new_with_label("Reset");
1793   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1794   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1795                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1796   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1797   gtk_widget_show(filter_reset);
1798
1799   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1800    * of any widget that ends up calling a callback which needs
1801    * that text entry pointer */
1802   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1803   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1804   set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1805   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1806   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1807
1808   info_bar = gtk_statusbar_new();
1809   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1810   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1811   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1812   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1813   gtk_widget_show(info_bar);
1814 }