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