When initializing a capture filter, assign a pointer to an empty string
[obnox/wireshark/wip.git] / gtk / main.c
1 /* main.c
2  *
3  * $Id: main.c,v 1.82 2000/01/05 22:31:46 gerald 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_DIRECT_H
57 #include <direct.h>
58 #endif
59
60 #ifdef HAVE_NETINET_IN_H
61 #include <netinet/in.h>
62 #endif
63
64 #include <signal.h>
65
66 #ifdef NEED_SNPRINTF_H
67 # ifdef HAVE_STDARG_H
68 #  include <stdarg.h>
69 # else
70 #  include <varargs.h>
71 # endif
72 # include "snprintf.h"
73 #endif
74
75 #if defined(HAVE_UCD_SNMP_SNMP_H)
76 #ifdef HAVE_UCD_SNMP_VERSION_H
77 #include <ucd-snmp/version.h>
78 #endif /* HAVE_UCD_SNMP_VERSION_H */
79 #elif defined(HAVE_SNMP_SNMP_H)
80 #ifdef HAVE_SNMP_VERSION_H
81 #include <snmp/version.h>
82 #endif /* HAVE_SNMP_VERSION_H */
83 #endif /* SNMP */
84
85 #ifdef NEED_STRERROR_H
86 #include "strerror.h"
87 #endif
88
89 #include "main.h"
90 #include "timestamp.h"
91 #include "packet.h"
92 #include "capture.h"
93 #include "summary.h"
94 #include "file.h"
95 #include "menu.h"
96 #include "prefs_dlg.h"
97 #include "column.h"
98 #include "print.h"
99 #include "resolv.h"
100 #include "follow.h"
101 #include "util.h"
102 #include "simple_dialog.h"
103 #include "proto_draw.h"
104 #include "dfilter.h"
105 #include "keys.h"
106 #include "gtkglobals.h"
107 #include "plugins.h"
108
109 FILE        *data_out_file = NULL;
110 packet_info  pi;
111 capture_file cf;
112 GtkWidget   *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
113             *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw,
114             *bv_vscroll_left, *bv_vscroll_right;
115 GdkFont     *m_r_font, *m_b_font;
116 guint        main_ctx, file_ctx;
117 gchar        comp_info_str[256];
118 gchar       *ethereal_path = NULL;
119 gchar       *medium_font = MONO_MEDIUM_FONT;
120 gchar       *bold_font = MONO_BOLD_FONT;
121 gchar       *last_open_dir = NULL;
122
123 ts_type timestamp_type = RELATIVE;
124
125 GtkStyle *item_style;
126
127 /* Specifies the field currently selected in the GUI protocol tree */
128 field_info *finfo_selected = NULL;
129
130 static void follow_destroy_cb(GtkWidget *win, gpointer data);
131 static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
132 static void follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii);
133 static void follow_print_stream(GtkWidget *w, gpointer parent_w);
134 static char* hfinfo_numeric_format(header_field_info *hfinfo);
135
136 /* About Ethereal window */
137 void
138 about_ethereal( GtkWidget *w, gpointer data ) {
139   simple_dialog(ESD_TYPE_INFO, NULL,
140                 "Ethereal - Network Protocol Analyzer\n"
141                 "Version %s (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
142                 "Compiled with %s\n\n"
143
144                 "Check the man page for complete documentation and\n"
145                 "for the list of contributors.\n"
146
147                 "\nSee http://ethereal.zing.org/ for more information.",
148                 VERSION, comp_info_str);
149 }
150
151 /* Follow the TCP stream, if any, to which the last packet that we called
152    a dissection routine on belongs (this might be the most recently
153    selected packet, or it might be the last packet in the file). */
154 void
155 follow_stream_cb( GtkWidget *w, gpointer data ) {
156   char      filename1[128+1];
157   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
158                 *filter_te;
159   GtkWidget *hbox, *close_bt, *print_bt, *button;
160   int        tmp_fd;
161   gchar     *follow_filter;
162
163   if( pi.ipproto == 6 ) {
164     /* we got tcp so we can follow */
165     /* Create a temporary file into which to dump the reassembled data
166        from the TCP stream, and set "data_out_file" to refer to it, so
167        that the TCP code will write to it.
168
169        XXX - it might be nicer to just have the TCP code directly
170        append stuff to the text widget for the TCP stream window,
171        if we can arrange that said window not pop up until we're
172        done. */
173     tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
174     if (tmp_fd == -1) {
175       simple_dialog(ESD_TYPE_WARN, NULL,
176         "Could not create temporary file %s: %s", filename1, strerror(errno));
177       return;
178     }
179     data_out_file = fdopen( tmp_fd, "w" );
180     if( data_out_file == NULL ) {
181       simple_dialog(ESD_TYPE_WARN, NULL,
182         "Could not create temporary file %s: %s", filename1, strerror(errno));
183       close(tmp_fd);
184       unlink(filename1);
185       return;
186     }
187
188     /* Create a new filter that matches all packets in the TCP stream,
189        and set the display filter entry accordingly */
190     reset_tcp_reassembly();
191     follow_filter = build_follow_filter( &pi );
192
193     /* set the display filter entry accordingly */
194     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
195     gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
196
197     /* Run the display filter so it goes in effect. */
198     filter_packets(&cf, follow_filter);
199
200     /* the data_out_file should now be full of the streams information */
201     fclose( data_out_file );
202
203     /* the filename1 file now has all the text that was in the session */
204     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
205     gtk_widget_set_name( streamwindow, "TCP stream window" );
206
207     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
208                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
209     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
210                         GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
211                         
212     if( incomplete_tcp_stream ) {
213       gtk_window_set_title( GTK_WINDOW(streamwindow), 
214                             "Contents of TCP stream (incomplete)" );
215     } else {
216       gtk_window_set_title( GTK_WINDOW(streamwindow),
217                             "Contents of TCP stream" );
218     }
219     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
220     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
221
222     /* setup the container */
223     box = gtk_vbox_new( FALSE, 0 );
224     gtk_container_add( GTK_CONTAINER(streamwindow), box );
225     gtk_widget_show( box );
226
227     /* set up the table we attach to */
228     table = gtk_table_new( 1, 2, FALSE );
229     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
230     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
231     gtk_widget_show( table );
232
233     /* create a text box */
234     text = gtk_text_new( NULL, NULL );
235     gtk_text_set_editable( GTK_TEXT(text), FALSE);
236     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
237                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
238                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
239     gtk_widget_show(text);
240
241     /* Create hbox */
242     hbox = gtk_hbox_new( FALSE, 1 );
243     gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
244     gtk_widget_show(hbox);
245
246 #define E_FOLLOW_ASCII_KEY "follow_ascii_key"
247
248     /* Create Radio Buttons */
249     button = gtk_radio_button_new_with_label(NULL, "ASCII");
250     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
251     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, button);
252     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
253     gtk_signal_connect(GTK_OBJECT(button), "toggled",
254                     GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
255                     GTK_OBJECT(streamwindow));
256     gtk_widget_show(button);
257
258     button = gtk_radio_button_new_with_label(
259                     gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
260                     "EBCDIC");
261     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
262     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
263     gtk_widget_show(button);
264
265     /* Create Close Button */
266     close_bt = gtk_button_new_with_label("Close");
267     gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
268                     GTK_SIGNAL_FUNC(gtk_widget_destroy),
269                     GTK_OBJECT(streamwindow));
270     gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
271     gtk_widget_show( close_bt );
272
273     /* Create Print Button */
274     print_bt = gtk_button_new_with_label("Print");
275     gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
276                    GTK_SIGNAL_FUNC(follow_print_stream),
277                    GTK_OBJECT(streamwindow));
278     gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
279     gtk_widget_show( print_bt );
280
281     /* create the scrollbar */
282     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
283     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
284                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
285     gtk_widget_show( vscrollbar );
286     gtk_widget_realize( text );
287
288     /* Tuck away the filename and textbox into streamwindow */
289 #define E_FOLLOW_FILENAME_KEY "follow_filename_key"
290 #define E_FOLLOW_TEXT_KEY "follow_text_key"
291
292     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
293                     g_strdup(filename1));
294     gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
295
296     follow_load_text(text, filename1, TRUE);
297
298     data_out_file = NULL;
299     gtk_widget_show( streamwindow );
300   } else {
301     simple_dialog(ESD_TYPE_WARN, NULL,
302       "Error following stream.  Please make\n"
303       "sure you have a TCP packet selected.");
304   }
305 }
306
307 /* The destroy call back has the responsibility of
308  * unlinking the temporary file */
309 static void
310 follow_destroy_cb(GtkWidget *win, gpointer data)
311 {
312         char    *filename;
313
314         filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
315                                                 E_FOLLOW_FILENAME_KEY);
316         g_assert(filename);
317
318         unlink(filename);
319         gtk_widget_destroy(win);
320 }
321
322 /* Handles the ASCII/EBCDIC toggling */
323 static void
324 follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
325 {
326         gboolean        show_ascii = FALSE;
327         GtkWidget       *button, *text;
328         char            *filename;
329
330
331         button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
332                                                 E_FOLLOW_ASCII_KEY);
333         text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
334                                                 E_FOLLOW_TEXT_KEY);
335         filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
336                                                 E_FOLLOW_FILENAME_KEY);
337
338         g_assert(button);
339         g_assert(text);
340         g_assert(filename);
341
342         if (GTK_TOGGLE_BUTTON(button)->active)
343                 show_ascii = TRUE;
344
345         follow_load_text(text, filename, show_ascii);
346 }
347
348 static void follow_print_stream(GtkWidget *w, gpointer parent_w)
349 {
350        FILE *fh = NULL;
351        int to_file = -1;
352        char* print_dest = NULL;
353        char* filename;
354
355        switch (prefs.pr_dest) {
356                case PR_DEST_CMD:
357                        print_dest = prefs.pr_cmd;
358                        to_file = FALSE;
359                        break;
360
361                case PR_DEST_FILE:
362                        print_dest = prefs.pr_file;
363                        to_file = TRUE;
364                        break;
365        }
366
367        if (print_dest != NULL) {
368                fh = open_print_dest(to_file, print_dest);
369        }
370
371        if (fh == NULL) {
372                switch (to_file) {
373                        case -1:
374                                simple_dialog(ESD_TYPE_WARN, NULL,
375                                                "Couldn't figure out where to send the print "
376                                                "job. Check your preferences.");
377                                break;
378
379                        case FALSE:
380                                simple_dialog(ESD_TYPE_WARN, NULL,
381                                                "Couldn't run print command %s.", prefs.pr_cmd);
382                                break;
383
384                        case TRUE:
385                                simple_dialog(ESD_TYPE_WARN, NULL, 
386                                                file_write_error_message(errno),
387                                                prefs.pr_file);
388                                break;
389                }
390                return;
391        }
392
393        filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
394                        E_FOLLOW_FILENAME_KEY);
395
396        if (filename != NULL) {
397                print_preamble(fh);
398                print_file(fh, filename);
399                print_finale(fh);
400                close_print_dest(to_file, fh);
401        }
402        else {
403                simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
404        }
405 }
406
407 #define FLT_BUF_SIZE 1024
408 static void
409 follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii)
410 {
411   int bytes_already, bcount;
412   tcp_stream_chunk sc;
413   guint32 client_addr = 0;
414   guint16 client_port = 0;
415
416   /* Delete any info already in text box */
417   bytes_already = gtk_text_get_length(GTK_TEXT(text));
418   if (bytes_already > 0) {
419     gtk_text_set_point(GTK_TEXT(text), 0);
420     gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
421   }
422
423     /* stop the updates while we fill the text box */
424     gtk_text_freeze( GTK_TEXT(text) );
425     data_out_file = fopen( filename, "r" );
426     if( data_out_file ) {
427       char buffer[FLT_BUF_SIZE];
428       int nchars;
429       while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
430         if (client_addr == 0) {
431           client_addr = sc.src_addr;
432           client_port = sc.src_port;
433         }
434         
435         while (sc.dlen > 0) {
436           bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
437           nchars = fread( buffer, 1, bcount, data_out_file );
438           if (nchars == 0)
439             break;
440           sc.dlen -= bcount;
441           if (show_ascii) {
442                   /* If our native arch is EBCDIC, call:
443                    * ASCII_TO_EBCDIC(buffer, nchars);
444                    */
445           }
446           else {
447                   /* If our native arch is ASCII, call: */
448                   EBCDIC_to_ASCII(buffer, nchars);
449           }
450           if (client_addr == sc.src_addr && client_port == sc.src_port)
451             gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
452               &prefs.st_client_bg, buffer, nchars );
453           else
454             gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
455               &prefs.st_server_bg, buffer, nchars );
456         }
457       }
458       if( ferror( data_out_file ) ) {
459         simple_dialog(ESD_TYPE_WARN, NULL,
460           "Error reading temporary file %s: %s", filename, strerror(errno));
461       }
462       fclose( data_out_file );
463     } else {
464       simple_dialog(ESD_TYPE_WARN, NULL,
465         "Could not open temporary file %s: %s", filename, strerror(errno));
466     }
467     gtk_text_thaw( GTK_TEXT(text) );
468 }
469
470 /* Match selected byte pattern */
471 void
472 match_selected_cb(GtkWidget *w, gpointer data)
473 {
474     char                *buf;
475     GtkWidget           *filter_te;
476     char                *ptr, *format, *stringified;
477     int                 i, dfilter_len, abbrev_len;
478     guint8              *c;
479     header_field_info   *hfinfo;
480
481     filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
482
483     if (!finfo_selected) {
484         simple_dialog(ESD_TYPE_WARN, NULL,
485                       "Error determining selected bytes.  Please make\n"
486                       "sure you have selected a field within the tree\n"
487                       "view to be matched.");
488         return;
489     }
490
491     hfinfo = finfo_selected->hfinfo;
492     g_assert(hfinfo);
493     abbrev_len = strlen(hfinfo->abbrev);
494
495         switch(hfinfo->type) {
496
497                 case FT_BOOLEAN:
498                         dfilter_len = abbrev_len + 2;
499                         buf = g_malloc0(dfilter_len);
500                         snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
501                                         hfinfo->abbrev);
502                         break;
503
504                 case FT_UINT8:
505                 case FT_UINT16:
506                 case FT_UINT24:
507                 case FT_UINT32:
508                 case FT_INT8:
509                 case FT_INT16:
510                 case FT_INT24:
511                 case FT_INT32:
512                         dfilter_len = abbrev_len + 20;
513                         buf = g_malloc0(dfilter_len);
514                         format = hfinfo_numeric_format(hfinfo);
515                         snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
516                         break;
517
518                 case FT_IPv4:
519                         dfilter_len = abbrev_len + 4 + 15 + 1;
520                         buf = g_malloc0(dfilter_len);
521                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
522                                         ipv4_addr_str(&(finfo_selected->value.ipv4)));
523                         break;
524
525                 case FT_IPXNET:
526                         dfilter_len = abbrev_len + 15;
527                         buf = g_malloc0(dfilter_len);
528                         snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
529                                         finfo_selected->value.numeric);
530                         break;
531
532                 case FT_IPv6:
533                         stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
534                         dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
535                         buf = g_malloc0(dfilter_len);
536                         snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
537                                         stringified);
538                         break;
539
540                 case FT_DOUBLE:
541                         dfilter_len = abbrev_len + 30;
542                         buf = g_malloc0(dfilter_len);
543                         snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
544                                         finfo_selected->value.floating);
545                         break;
546
547                 case FT_ETHER:
548                         dfilter_len = abbrev_len + 22;
549                         buf = g_malloc0(dfilter_len);
550                         snprintf(buf, dfilter_len, "%s == %s",
551                                         hfinfo->abbrev,
552                                         ether_to_str(finfo_selected->value.ether));
553                         break;
554 #if 0
555
556                 case FT_ABSOLUTE_TIME:
557                 case FT_RELATIVE_TIME:
558                         memcpy(&fi->value.time, va_arg(ap, struct timeval*),
559                                 sizeof(struct timeval));
560                         break;
561
562                 case FT_STRING:
563                         /* This g_strdup'ed memory is freed in proto_tree_free_node() */
564                         fi->value.string = g_strdup(va_arg(ap, char*));
565                         break;
566
567                 case FT_TEXT_ONLY:
568                         ; /* nothing */
569                         break;
570 #endif
571                 default:
572                     c = cf.pd + finfo_selected->start;
573                     buf = g_malloc0(32 + finfo_selected->length * 3);
574                     ptr = buf;
575
576                     sprintf(ptr, "frame[%d] == ", finfo_selected->start);
577                     ptr = buf+strlen(buf);
578
579                     if (finfo_selected->length == 1) {
580                         sprintf(ptr, "0x%02x", *c++);
581                     }
582                     else {
583                             for (i=0;i<finfo_selected->length; i++) {
584                                 if (i == 0 ) {
585                                         sprintf(ptr, "%02x", *c++);
586                                 }
587                                 else {
588                                         sprintf(ptr, ":%02x", *c++);
589                                 }
590                                 ptr = buf+strlen(buf);
591                             }
592                     }
593                     break;
594         }
595
596     /* create a new one and set the display filter entry accordingly */
597     gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
598
599     /* Run the display filter so it goes in effect. */
600     filter_packets(&cf, buf);
601
602     /* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
603 }
604
605 static char*
606 hfinfo_numeric_format(header_field_info *hfinfo)
607 {
608         char *format = NULL;
609
610         /* Pick the proper format string */
611         switch(hfinfo->display) {
612                 case BASE_DEC:
613                 case BASE_NONE:
614                 case BASE_OCT: /* I'm lazy */
615                 case BASE_BIN: /* I'm lazy */
616                         switch(hfinfo->type) {
617                                 case FT_UINT8:
618                                 case FT_UINT16:
619                                 case FT_UINT24:
620                                 case FT_UINT32:
621                                         format = "%s == %u";
622                                         break;
623                                 case FT_INT8:
624                                 case FT_INT16:
625                                 case FT_INT24:
626                                 case FT_INT32:
627                                         format = "%s == %d";
628                                         break;
629                                 default:
630                                         g_assert_not_reached();
631                                         ;
632                         }
633                         break;
634                 case BASE_HEX:
635                         switch(hfinfo->type) {
636                                 case FT_UINT8:
637                                         format = "%s == 0x%02x";
638                                         break;
639                                 case FT_UINT16:
640                                         format = "%s == 0x%04x";
641                                         break;
642                                 case FT_UINT24:
643                                         format = "%s == 0x%06x";
644                                         break;
645                                 case FT_UINT32:
646                                         format = "%s == 0x%08x";
647                                         break;
648                                 default:
649                                         g_assert_not_reached();
650                                         ;
651                         }
652                         break;
653                 default:
654                         g_assert_not_reached();
655                         ;
656         }
657         return format;
658 }
659
660
661 /* Run the current display filter on the current packet set, and
662    redisplay. */
663 static void
664 filter_activate_cb(GtkWidget *w, gpointer data)
665 {
666   GtkCombo  *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
667   GList     *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
668   GList     *li, *nl = NULL;
669   gboolean   add_filter = TRUE;
670   
671   char *s = gtk_entry_get_text(GTK_ENTRY(w));
672   
673   /* GtkCombos don't let us get at their list contents easily, so we maintain
674      our own filter list, and feed it to gtk_combo_set_popdown_strings when
675      a new filter is added. */
676   if (filter_packets(&cf, g_strdup(s))) {
677     li = g_list_first(filter_list);
678     while (li) {
679       if (li->data && strcmp(s, li->data) == 0)
680         add_filter = FALSE;
681       li = li->next;
682     }
683
684     if (add_filter) {
685       filter_list = g_list_append(filter_list, g_strdup(s));
686       li = g_list_first(filter_list);
687       while (li) {
688         nl = g_list_append(nl, strdup(li->data));
689         li = li->next;
690       }
691       gtk_combo_set_popdown_strings(filter_cm, nl);
692       gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
693     }
694   }
695 }
696
697 /* redisplay with no display filter */
698 static void
699 filter_reset_cb(GtkWidget *w, gpointer data)
700 {
701   GtkWidget *filter_te = NULL;
702
703   if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
704     gtk_entry_set_text(GTK_ENTRY(filter_te), "");
705   }
706
707   filter_packets(&cf, NULL);
708 }
709
710 /* What to do when a list item is selected/unselected */
711 static void
712 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
713
714 #ifdef HAVE_LIBPCAP
715   if (!sync_mode) {
716 #endif
717     if (cf.wth)
718       return; 
719 #ifdef HAVE_LIBPCAP
720   }
721 #endif
722   blank_packetinfo();
723   select_packet(&cf, row);
724 }
725
726 static void
727 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
728   unselect_packet(&cf);
729 }
730
731 static void
732 tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
733 {
734         field_info      *finfo;
735         int             tree_selected_start = -1;
736         int             tree_selected_len = -1;
737
738         g_assert(node);
739         finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
740         if (!finfo) return;
741
742         finfo_selected = finfo;
743         tree_selected_start = finfo->start;
744         tree_selected_len   = finfo->length;
745
746         packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
747                 tree_selected_start, tree_selected_len, cf.current_frame->encoding);
748 }
749
750 static void
751 tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
752 {
753         finfo_selected = NULL;
754         packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len, 
755                 -1, -1, cf.current_frame->encoding);
756 }
757
758 void collapse_all_cb(GtkWidget *widget, gpointer data) {
759   if (cf.protocol_tree)
760     collapse_all_tree(cf.protocol_tree, tree_view);
761 }
762
763 void expand_all_cb(GtkWidget *widget, gpointer data) {
764   if (cf.protocol_tree)
765     expand_all_tree(cf.protocol_tree, tree_view);
766 }
767
768 void
769 set_scrollbar_placement(int pos) /* 0=left, 1=right */
770 {
771         if (pos) {
772                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
773                                 GTK_CORNER_TOP_LEFT );
774                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
775                                 GTK_CORNER_TOP_LEFT );
776                 gtk_widget_hide(bv_vscroll_left);
777                 gtk_widget_show(bv_vscroll_right);
778         }
779         else {
780                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
781                                 GTK_CORNER_TOP_RIGHT );
782                 gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
783                                 GTK_CORNER_TOP_RIGHT );
784                 gtk_widget_hide(bv_vscroll_right);
785                 gtk_widget_show(bv_vscroll_left);
786         }
787 }
788
789 void
790 set_plist_sel_browse(gboolean val)
791 {
792         if (finfo_selected)
793                 unselect_packet(&cf);
794
795         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
796          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
797         if (val) {
798                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
799         }
800         else {
801                 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
802         }
803 }
804
805 void
806 set_ptree_sel_browse(gboolean val)
807 {
808         /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
809          * "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
810         if (val) {
811                 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
812         }
813         else {
814                 gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
815         }
816 }
817
818 void
819 set_ptree_line_style(gint style)
820 {
821         /* I'm using an assert here since the preferences code limits
822          * the user input, both in the GUI and when reading the preferences file.
823          * If the value is incorrect, it's a program error, not a user-initiated error.
824          */
825         g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
826         gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
827 }
828
829 void
830 set_ptree_expander_style(gint style)
831 {
832         /* I'm using an assert here since the preferences code limits
833          * the user input, both in the GUI and when reading the preferences file.
834          * If the value is incorrect, it's a program error, not a user-initiated error.
835          */
836         g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
837         gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
838 }
839         
840
841 void
842 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
843   /* If we have a capture file open, and it's a temporary file,
844      unlink it. */
845   if (cf.filename != NULL && cf.is_tempfile)
846         unlink(cf.filename);
847   gtk_exit(0);
848 }
849
850 /* call initialization routines at program startup time */
851 static void
852 ethereal_proto_init(void) {
853   init_dissect_rpc();
854   proto_init();
855   init_dissect_udp();
856   dfilter_init();
857   init_plugins();
858 }
859
860 static void
861 ethereal_proto_cleanup(void) {
862         proto_cleanup();
863         dfilter_cleanup();
864 }
865
866 static void 
867 print_usage(void) {
868
869   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
870           VERSION, comp_info_str);
871 #ifdef HAVE_LIBPCAP
872   fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
873           PACKAGE);
874   fprintf(stderr, "         [-f <capture filter>] [-i interface] [-m <medium font>] [-n]\n");
875   fprintf(stderr, "         [-P <packet list height>] [-r infile] [-R <read filter>]\n");
876   fprintf(stderr, "         [-s snaplen] [-t <time stamp format>] [-T <tree view height>]\n");
877   fprintf(stderr, "         [-w savefile]\n");
878 #else
879   fprintf(stderr, "%s [-vh] [-b <bold font>] [-B <byte view height>] [-m <medium font>]\n",
880           PACKAGE);
881   fprintf(stderr, "         [-n] [-P <packet list height>] [-r infile] [-R <read filter>]\n");
882   fprintf(stderr, "         [-t <time stamp format>] [-T <tree view height>]\n");
883 #endif
884 }
885
886 /* And now our feature presentation... [ fade to music ] */
887 int
888 main(int argc, char *argv[])
889 {
890 #ifdef HAVE_LIBPCAP
891   char                *command_name;
892 #endif
893   char                *s;
894   int                  i;
895 #ifndef WIN32
896   int                  opt;
897   extern char         *optarg;
898   gboolean             arg_error = FALSE;
899 #endif
900 #ifdef HAVE_LIBPCAP
901   extern char          pcap_version[];
902 #endif
903   char                *pf_path;
904   int                  pf_open_errno = 0;
905   int                  err;
906 #ifdef HAVE_LIBPCAP
907   gboolean             start_capture = FALSE;
908   gchar               *save_file = NULL;
909 #else
910   gboolean             capture_option_specified = FALSE;
911 #endif
912   GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
913                       *bv_table, *stat_hbox,
914                       *filter_bt, *filter_cm, *filter_te,
915                       *filter_reset;
916   GList               *filter_list = NULL;
917   GtkStyle            *pl_style;
918   GtkAccelGroup       *accel;
919   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
920   gchar               *rc_file, *cf_name = NULL, *rfilter = NULL;
921   dfilter             *rfcode = NULL;
922   gboolean             rfilter_parse_failed = FALSE;
923   e_prefs             *prefs;
924
925   ethereal_path = argv[0];
926
927 #ifdef HAVE_LIBPCAP
928   command_name = strrchr(ethereal_path, '/');
929   if (command_name == NULL)
930     command_name = ethereal_path;
931   else
932     command_name++;
933   /* Set "capture_child" to indicate whether this is going to be a child
934      process for a "-S" capture. */
935   capture_child = (strcmp(command_name, CHILD_NAME) == 0);
936 #endif
937
938   /* If invoked with the "-G" flag, we dump out a glossary of
939      display filter symbols.
940
941      We must do this before calling "gtk_init()", because "gtk_init()"
942      tries to open an X display, and we don't want to have to do any X
943      stuff just to do a build.
944
945      Given that we call "gtk_init()" before doing the regular argument
946      list processing, so that it can handle X and GTK+ arguments and
947      remove them from the list at which we look, this means we must do
948      this before doing the regular argument list processing, as well.
949
950      This means that:
951
952         you must give the "-G" flag as the first flag on the command line;
953
954         you must give it as "-G", nothing more, nothing less;
955
956         any arguments after the "-G" flag will not be used. */
957   if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
958     ethereal_proto_init();
959     proto_registrar_dump();
960     exit(0);
961   }
962
963   /* Let GTK get its args */
964   gtk_init (&argc, &argv);
965   
966   prefs = read_prefs(&pf_path);
967   if (pf_path != NULL) {
968     /* The preferences file exists, but couldn't be opened; "pf_path" is
969        its pathname.  Remember "errno", as that says why the attempt
970        failed. */
971     pf_open_errno = errno;
972   }
973
974   /* Initialize the capture file struct */
975   cf.plist              = NULL;
976   cf.plist_end          = NULL;
977   cf.wth                = NULL;
978   cf.fh                 = NULL;
979   cf.filename           = NULL;
980   cf.user_saved         = FALSE;
981   cf.is_tempfile        = FALSE;
982   cf.rfcode             = NULL;
983   cf.dfilter            = NULL;
984   cf.dfcode             = NULL;
985 #ifdef HAVE_LIBPCAP
986   cf.cfilter            = g_strdup(EMPTY_FILTER);
987 #endif
988   cf.iface              = NULL;
989   cf.save_file          = NULL;
990   cf.save_file_fd       = -1;
991   cf.snap               = WTAP_MAX_PACKET_SIZE;
992   cf.count              = 0;
993   cf.cinfo.num_cols     = prefs->num_cols;
994   cf.cinfo.col_fmt      = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
995   cf.cinfo.fmt_matx     = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
996   cf.cinfo.col_width    = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
997   cf.cinfo.col_title    = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
998   cf.cinfo.col_data     = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
999
1000   /* Assemble the compile-time options */
1001   snprintf(comp_info_str, 256,
1002 #ifdef GTK_MAJOR_VERSION
1003     "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
1004     GTK_MICRO_VERSION,
1005 #else
1006     "GTK+ (version unknown), %s%s, %s%s, %s%s",
1007 #endif
1008
1009 #ifdef HAVE_LIBPCAP
1010    "with libpcap ", pcap_version,
1011 #else
1012    "without libpcap", "",
1013 #endif
1014
1015 #ifdef HAVE_LIBZ
1016 #ifdef ZLIB_VERSION
1017    "with libz ", ZLIB_VERSION,
1018 #else /* ZLIB_VERSION */
1019    "with libz ", "(version unknown)",
1020 #endif /* ZLIB_VERSION */
1021 #else /* HAVE_LIBZ */
1022    "without libz", "",
1023 #endif /* HAVE_LIBZ */
1024
1025 /* Oh, this is pretty */
1026 #if defined(HAVE_UCD_SNMP_SNMP_H)
1027 #ifdef HAVE_UCD_SNMP_VERSION_H
1028    "with UCD SNMP ", VersionInfo
1029 #else /* HAVE_UCD_SNMP_VERSION_H */
1030    "with UCD SNMP ", "(version unknown)"
1031 #endif /* HAVE_UCD_SNMP_VERSION_H */
1032 #elif defined(HAVE_SNMP_SNMP_H)
1033 #ifdef HAVE_SNMP_VERSION_H
1034    "with CMU SNMP ", snmp_Version()
1035 #else /* HAVE_SNMP_VERSION_H */
1036    "with CMU SNMP ", "(version unknown)"
1037 #endif /* HAVE_SNMP_VERSION_H */
1038 #else /* no SNMP */
1039    "without SNMP", ""
1040 #endif
1041    );
1042
1043 #ifndef WIN32
1044   /* Now get our args */
1045   while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
1046     switch (opt) {
1047       case 'b':        /* Bold font */
1048         bold_font = g_strdup(optarg);
1049         break;
1050       case 'B':        /* Byte view pane height */
1051         bv_size = atoi(optarg);
1052         break;
1053       case 'c':        /* Capture xxx packets */
1054 #ifdef HAVE_LIBPCAP
1055         cf.count = atoi(optarg);
1056 #else
1057         capture_option_specified = TRUE;
1058         arg_error = TRUE;
1059 #endif
1060         break;
1061       case 'f':
1062 #ifdef HAVE_LIBPCAP
1063         if (cf.cfilter)
1064                 g_free(cf.cfilter);
1065         cf.cfilter = g_strdup(optarg);
1066 #else
1067         capture_option_specified = TRUE;
1068         arg_error = TRUE;
1069 #endif
1070         break;
1071       case 'h':        /* Print help and exit */
1072         print_usage();
1073         exit(0);
1074         break;
1075       case 'i':        /* Use interface xxx */
1076 #ifdef HAVE_LIBPCAP
1077         cf.iface = g_strdup(optarg);
1078 #else
1079         capture_option_specified = TRUE;
1080         arg_error = TRUE;
1081 #endif
1082         break;
1083       case 'k':        /* Start capture immediately */
1084 #ifdef HAVE_LIBPCAP
1085         start_capture = TRUE;
1086 #else
1087         capture_option_specified = TRUE;
1088         arg_error = TRUE;
1089 #endif
1090         break;
1091       case 'm':        /* Medium font */
1092         medium_font = g_strdup(optarg);
1093         break;
1094       case 'n':        /* No name resolution */
1095         g_resolving_actif = 0;
1096         break;
1097       case 'P':        /* Packet list pane height */
1098         pl_size = atoi(optarg);
1099         break;
1100       case 'Q':        /* Quit after capture (just capture to file) */
1101 #ifdef HAVE_LIBPCAP
1102         quit_after_cap = 1;
1103         start_capture = TRUE;  /*** -Q implies -k !! ***/
1104 #else
1105         capture_option_specified = TRUE;
1106         arg_error = TRUE;
1107 #endif
1108         break;
1109       case 'r':        /* Read capture file xxx */
1110         /* We may set "last_open_dir" to "cf_name", and if we change
1111            "last_open_dir" later, we free the old value, so we have to
1112            set "cf_name" to something that's been allocated. */
1113         cf_name = g_strdup(optarg);
1114         break;
1115       case 'R':        /* Read file filter */
1116         rfilter = optarg;
1117         break;
1118       case 's':        /* Set the snapshot (capture) length */
1119 #ifdef HAVE_LIBPCAP
1120         cf.snap = atoi(optarg);
1121 #else
1122         capture_option_specified = TRUE;
1123         arg_error = TRUE;
1124 #endif
1125         break;
1126       case 'S':        /* "Sync" mode: used for following file ala tail -f */
1127 #ifdef HAVE_LIBPCAP
1128         sync_mode = TRUE;
1129 #else
1130         capture_option_specified = TRUE;
1131         arg_error = TRUE;
1132 #endif
1133         break;
1134       case 't':        /* Time stamp type */
1135         if (strcmp(optarg, "r") == 0)
1136           timestamp_type = RELATIVE;
1137         else if (strcmp(optarg, "a") == 0)
1138           timestamp_type = ABSOLUTE;
1139         else if (strcmp(optarg, "d") == 0)
1140           timestamp_type = DELTA;
1141         else {
1142           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
1143             optarg);
1144           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
1145           fprintf(stderr, "or \"d\" for delta.\n");
1146           exit(1);
1147         }
1148         break;
1149       case 'T':        /* Tree view pane height */
1150         tv_size = atoi(optarg);
1151         break;
1152       case 'v':        /* Show version and exit */
1153         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
1154         exit(0);
1155         break;
1156       case 'w':        /* Write to capture file xxx */
1157 #ifdef HAVE_LIBPCAP
1158         save_file = g_strdup(optarg);
1159 #else
1160         capture_option_specified = TRUE;
1161         arg_error = TRUE;
1162 #endif
1163         break;
1164       case 'W':        /* Write to capture file FD xxx */
1165 #ifdef HAVE_LIBPCAP
1166         cf.save_file_fd = atoi(optarg);
1167 #else
1168         capture_option_specified = TRUE;
1169         arg_error = TRUE;
1170 #endif
1171         break;
1172       default:
1173       case '?':        /* Bad flag - print usage message */
1174         arg_error = TRUE;
1175         break;
1176     }
1177   }
1178 #endif
1179
1180 #ifndef HAVE_LIBPCAP
1181   if (capture_option_specified)
1182     fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
1183 #endif
1184   if (arg_error)
1185     print_usage();
1186 #ifdef HAVE_LIBPCAP
1187   if (start_capture) {
1188     if (cf.iface == NULL) {
1189       fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
1190       exit(1);
1191     }
1192   }
1193   if (capture_child) {
1194     if (cf.save_file_fd == -1) {
1195       /* XXX - send this to the standard output as something our parent
1196          should put in an error message box? */
1197       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
1198       exit(1);
1199     }
1200   }
1201 #endif
1202
1203   /* Build the column format array */  
1204   for (i = 0; i < cf.cinfo.num_cols; i++) {
1205     cf.cinfo.col_fmt[i] = get_column_format(i);
1206     cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
1207     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
1208       NUM_COL_FMTS);
1209     get_column_format_matches(cf.cinfo.fmt_matx[i], cf.cinfo.col_fmt[i]);
1210     if (cf.cinfo.col_fmt[i] == COL_INFO)
1211       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
1212     else
1213       cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
1214   }
1215
1216   if (cf.snap < 1)
1217     cf.snap = WTAP_MAX_PACKET_SIZE;
1218   else if (cf.snap < MIN_PACKET_SIZE)
1219     cf.snap = MIN_PACKET_SIZE;
1220   
1221   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
1222   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
1223   gtk_rc_parse(rc_file);
1224
1225   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
1226     fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
1227     exit(1);
1228   }
1229
1230   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
1231     fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
1232     exit(1);
1233   }
1234
1235   /* Main window */  
1236   top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1237   gtk_widget_set_name(top_level, "main window");
1238   gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
1239     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1240   gtk_signal_connect(GTK_OBJECT(top_level), "destroy", 
1241     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
1242   gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
1243   gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
1244   gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
1245
1246   /* Container for menu bar, paned windows and progress/info box */
1247   main_vbox = gtk_vbox_new(FALSE, 1);
1248   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
1249   gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
1250   gtk_widget_show(main_vbox);
1251
1252   /* Menu bar */
1253   get_main_menu(&menubar, &accel);
1254   gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
1255   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
1256   gtk_widget_show(menubar);
1257
1258   /* Panes for the packet list, tree, and byte view */
1259   u_pane = gtk_vpaned_new();
1260   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
1261   l_pane = gtk_vpaned_new();
1262   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
1263   gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
1264   gtk_widget_show(u_pane);
1265   gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
1266   gtk_widget_show(l_pane);
1267
1268   /* Packet list */
1269   pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
1270   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
1271     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1272   gtk_widget_show(pkt_scrollw);
1273   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
1274
1275   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
1276   gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
1277   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
1278   set_plist_sel_browse(prefs->gui_plist_sel_browse);
1279   pl_style = gtk_style_new();
1280   gdk_font_unref(pl_style->font);
1281   pl_style->font = m_r_font;
1282   gtk_widget_set_style(packet_list, pl_style);
1283   gtk_widget_set_name(packet_list, "packet list");
1284   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
1285     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
1286   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
1287     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
1288   for (i = 0; i < cf.cinfo.num_cols; i++) {
1289     if (get_column_resize_type(cf.cinfo.col_fmt[i]) != RESIZE_MANUAL)
1290       gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
1291
1292     /* Right-justify the packet number column. */
1293     if (cf.cinfo.col_fmt[i] == COL_NUMBER)
1294       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
1295         GTK_JUSTIFY_RIGHT);
1296
1297     /* Save static column sizes to use during a "-S" capture, so that
1298        the columns don't resize during a live capture. */
1299     cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
1300                                                 pl_style->font);
1301   }
1302   gtk_widget_set_usize(packet_list, -1, pl_size);
1303   gtk_widget_show(packet_list);
1304   
1305   /* Tree view */
1306   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
1307   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
1308     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1309   gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
1310   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
1311   gtk_widget_show(tv_scrollw);
1312   
1313   tree_view = gtk_ctree_new(1, 0);
1314   /* I need this next line to make the widget work correctly with hidden
1315    * column titles and GTK_SELECTION_BROWSE */
1316   gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
1317   gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
1318   set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
1319   set_ptree_line_style(prefs->gui_ptree_line_style);
1320   set_ptree_expander_style(prefs->gui_ptree_expander_style);
1321
1322   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
1323     GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
1324   gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
1325     GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
1326   gtk_widget_show(tree_view);
1327
1328   item_style = gtk_style_new();
1329   gdk_font_unref(item_style->font);
1330   item_style->font = m_r_font;
1331
1332   /* Byte view. The table is only one row high, but 3 columns
1333    * wide. The middle column contains the GtkText with the hex dump.
1334    * The left and right columns contain vertical scrollbars. They both
1335    * do the same thing, but only one will be shown at a time, in accordance
1336    * with where the user wants the other vertical scrollbars places
1337    * (on the left or the right).
1338    */
1339   bv_table = gtk_table_new (1, 3, FALSE);
1340   gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
1341   gtk_widget_set_usize(bv_table, -1, bv_size);
1342   gtk_widget_show(bv_table);
1343
1344   byte_view = gtk_text_new(NULL, NULL);
1345   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
1346   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
1347   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
1348     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
1349   gtk_widget_show(byte_view);
1350
1351   /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
1352    * in the GTK+ distribution, so I removed the horizontal scroll bar
1353    * that used to be here. I tried the gtk_text widget with a 
1354    * gtk_scrolled_window w/ viewport, but the vertical scrollowing
1355    * did not work well, and sometimes a few pixels were cut off on
1356    * the bottom. */
1357
1358   bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1359   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
1360     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1361
1362   bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
1363   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
1364     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
1365  
1366   /* Now that the 3 panes are created, set the vertical scrollbar
1367    * on the left or right according to the user's preference */
1368   set_scrollbar_placement(prefs->gui_scrollbar_on_right);
1369
1370   /* Progress/filter/info box */
1371   stat_hbox = gtk_hbox_new(FALSE, 1);
1372   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1373   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
1374   gtk_widget_show(stat_hbox);
1375
1376   prog_bar = gtk_progress_bar_new();
1377   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1378   gtk_widget_show(prog_bar);
1379
1380   filter_bt = gtk_button_new_with_label("Filter:");
1381   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1382     GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
1383   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1384   gtk_widget_show(filter_bt);
1385   
1386   filter_cm = gtk_combo_new();
1387   filter_list = g_list_append (filter_list, "");
1388   gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
1389   gtk_combo_disable_activate(GTK_COMBO(filter_cm));
1390   filter_te = GTK_COMBO(filter_cm)->entry;
1391   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1392   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
1393   gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
1394   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
1395   gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1396     GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1397   gtk_widget_show(filter_cm);
1398
1399   filter_reset = gtk_button_new_with_label("Reset");
1400   gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
1401   gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
1402                      GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
1403   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
1404   gtk_widget_show(filter_reset);
1405
1406   /* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
1407    * of any widget that ends up calling a callback which needs
1408    * that text entry pointer */
1409   set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1410   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1411   set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
1412   set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
1413   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
1414
1415   info_bar = gtk_statusbar_new();
1416   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1417   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1418   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1419   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1420   gtk_widget_show(info_bar);
1421
1422 /* 
1423    Hmmm should we do it here
1424 */
1425
1426   ethereal_proto_init();   /* Init anything that needs initializing */
1427
1428 #ifdef HAVE_LIBPCAP
1429   /* Is this a "child" ethereal, which is only supposed to pop up a
1430      capture box to let us stop the capture, and run a capture
1431      to a file that our parent will read? */
1432   if (!capture_child) {
1433 #endif
1434     /* No.  Pop up the main window, and read in a capture file if
1435        we were told to. */
1436
1437     gtk_widget_show(top_level);
1438
1439     cf.colors = colfilter_new();
1440
1441     /* If we were given the name of a capture file, read it in now;
1442        we defer it until now, so that, if we can't open it, and pop
1443        up an alert box, the alert box is more likely to come up on
1444        top of the main window - but before the preference-file-error
1445        alert box, so, if we get one of those, it's more likely to come
1446        up on top of us. */
1447     if (cf_name) {
1448       if (rfilter != NULL) {
1449         if (dfilter_compile(rfilter, &rfcode) != 0) {
1450           simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
1451           rfilter_parse_failed = TRUE;
1452         }
1453       }
1454       if (!rfilter_parse_failed) {
1455         if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
1456           /* "open_cap_file()" succeeded, so it closed the previous
1457              capture file, and thus destroyed any previous read filter
1458              attached to "cf". */
1459           cf.rfcode = rfcode;
1460           err = read_cap_file(&cf);
1461           s = strrchr(cf_name, '/');
1462           if (s) {
1463             last_open_dir = cf_name;
1464             *s = '\0';
1465           }
1466         } else {
1467           dfilter_destroy(rfcode);
1468           cf.rfcode = NULL;
1469         }
1470       }
1471     }
1472 #ifdef HAVE_LIBPCAP
1473   }
1474 #endif
1475
1476   /* If we failed to open the preferences file, pop up an alert box;
1477      we defer it until now, so that the alert box is more likely to
1478      come up on top of the main window. */
1479   if (pf_path != NULL) {
1480       simple_dialog(ESD_TYPE_WARN, NULL,
1481         "Could not open preferences file\n\"%s\": %s.", pf_path,
1482         strerror(pf_open_errno));
1483   }
1484
1485 #ifdef HAVE_LIBPCAP
1486   if (capture_child) {
1487     /* This is the child process for a sync mode or fork mode capture,
1488        so just do the low-level work of a capture - don't create
1489        a temporary file and fork off *another* child process (so don't
1490        call "do_capture()"). */
1491
1492        capture();
1493
1494        /* The capture is done; there's nothing more for us to do. */
1495        gtk_exit(0);
1496   } else {
1497     if (start_capture) {
1498       /* "-k" was specified; start a capture. */
1499       do_capture(save_file);
1500     }
1501   }
1502 #endif
1503
1504   gtk_main();
1505
1506   ethereal_proto_cleanup();
1507   g_free(rc_file);
1508
1509   exit(0);
1510 }