Fixes to the TCP reassembly code to correctly handle too short
[obnox/wireshark/wip.git] / ethereal.c
1 /* ethereal.c
2  *
3  * $Id: ethereal.c,v 1.26 1999/03/23 20:25:50 deniel 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  * - Live browser/capture display
29  * - Graphs
30  * - Get AIX to work
31  * - Check for end of packet in dissect_* routines.
32  * - Playback window
33  * - Multiple window support
34  * - Add cut/copy/paste
35  * - Handle snoop files
36  * - Fix progress/status bar glitches?  (GTK+ bug?)
37  * - Create header parsing routines
38  * - Check fopens, freads, fwrites
39  * - Make byte view scrollbars automatic?
40  * - Make byte view selections more fancy?
41  *
42  */
43
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
47
48 #include <gtk/gtk.h>
49 #include <pcap.h> /* needed for capture.h */
50
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <netinet/in.h>
59
60 #ifdef NEED_SNPRINTF_H
61 # ifdef HAVE_STDARG_H
62 #  include <stdarg.h>
63 # else
64 #  include <varargs.h>
65 # endif
66 # include "snprintf.h"
67 #endif
68
69 #include "ethereal.h"
70 #include "packet.h"
71 #include "capture.h"
72 #include "file.h"
73 #include "menu.h"
74 #include "etypes.h"
75 #include "prefs.h"
76 #include "column.h"
77 #include "print.h"
78 #include "resolv.h"
79 #include "follow.h"
80 #include "util.h"
81 #include "gtkpacket.h"
82
83 FILE        *data_out_file = NULL;
84 packet_info  pi;
85 capture_file cf;
86 GtkWidget   *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
87             *info_bar;
88 GdkFont     *m_r_font, *m_b_font;
89 guint        main_ctx, file_ctx;
90 frame_data  *fd;
91 gint         start_capture = 0;
92 gchar        comp_info_str[256];
93
94 ts_type timestamp_type = RELATIVE;
95
96 GtkStyle *item_style;
97
98 #define E_DFILTER_TE_KEY "display_filter_te"
99
100 /* About Ethereal window */
101 void
102 about_ethereal( GtkWidget *w, gpointer data ) {
103   simple_dialog(ESD_TYPE_INFO, NULL,
104                 "GNU Ethereal - network protocol analyzer\n"
105                 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
106                 "Compiled with %s\n\n"
107                 "Contributors:\n"
108                 "Gilbert Ramirez Jr. <gram@verdict.uthscsa.edu>\n"
109                 "Hannes R. Boehm     <hannes@boehm.org>\n"
110                 "Mike Hall           <mlh@io.com>\n"
111                 "Bobo Rajec          <bobo@bsp-consulting.sk>\n"
112                 "Laurent Deniel      <deniel@worldnet.fr>\n"
113                 "Don Lafontaine      <lafont02@cn.ca>\n"
114                 "Guy Harris          <guy@netapp.com>\n"
115                 "Simon Wilkinson     <sxw@dcs.ed.ac.uk>\n"
116                 "Joerg Mayer         <jmayer@telemation.de>\n\n"
117                 "See http://ethereal.zing.org for more information",
118                 VERSION, comp_info_str);
119 }
120
121 /* Things to do when the OK button is pressed */
122 void
123 file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
124   gchar     *cf_name;
125   int        err;
126   GtkWidget *filter_te = NULL;
127
128   /* Gilbert --- I added this if statement. Is this right? */
129   if (w)
130         filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
131
132   cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
133   gtk_widget_hide(GTK_WIDGET (fs));
134   gtk_widget_destroy(GTK_WIDGET (fs));
135
136   if (w && cf.dfilter) {
137           g_free(cf.dfilter);
138           cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
139   }
140   if ((err = load_cap_file(cf_name, &cf)) == 0)
141     chdir(cf_name);
142   g_free(cf_name);
143 }
144
145 /* Update the progress bar */
146 gint
147 file_progress_cb(gpointer p) {
148   gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
149     (gfloat) ftell(cf.fh) / (gfloat) cf.f_len);
150   return TRUE;
151 }
152
153 /* Follow a TCP stream */
154 void
155 follow_stream_cb( GtkWidget *w, gpointer data ) {
156   char filename1[128];
157   GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
158   GtkWidget *filter_te = NULL;
159
160   if (w)
161         filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
162
163   if( pi.ipproto == 6 ) {
164     /* we got tcp so we can follow */
165     /* check to see if we are using a filter */
166     if( cf.dfilter != NULL ) {
167       /* get rid of this one */
168       g_free( cf.dfilter );
169       cf.dfilter = NULL;
170     }
171     /* create a new one and set the display filter entry accordingly */
172     cf.dfilter = build_follow_filter( &pi );
173     if (filter_te)
174             gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
175     /* reload so it goes in effect. Also we set data_out_file which 
176        tells the tcp code to output the data */
177     close_cap_file( &cf, info_bar, file_ctx);
178     strcpy( filename1, tmpnam(NULL) );
179     data_out_file = fopen( filename1, "a" );
180     if( data_out_file == NULL ) {
181       fprintf( stderr, "Could not open tmp file %s\n", filename1 );
182     }
183     reset_tcp_reassembly();
184     load_cap_file( cf.filename, &cf );
185     /* the data_out_file should now be full of the streams information */
186     fclose( data_out_file );
187     /* the filename1 file now has all the text that was in the session */
188     streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
189     gtk_widget_set_name( streamwindow, "TCP stream window" );
190     gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
191                         NULL, "WM destroy" );
192     gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
193                         NULL, "WM destroy" );
194     if( incomplete_tcp_stream ) {
195       gtk_window_set_title( GTK_WINDOW(streamwindow), 
196                             "Contents of TCP stream (incomplete)" );
197     } else {
198       gtk_window_set_title( GTK_WINDOW(streamwindow),
199                             "Contents of TCP stream" );
200     }
201     gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
202     gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
203     /* setup the container */
204     box = gtk_vbox_new( FALSE, 0 );
205     gtk_container_add( GTK_CONTAINER(streamwindow), box );
206     gtk_widget_show( box );
207     /* set up the table we attach to */
208     table = gtk_table_new( 1, 2, FALSE );
209     gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
210     gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
211     gtk_widget_show( table );
212     /* create a text box */
213     text = gtk_text_new( NULL, NULL );
214     gtk_text_set_editable( GTK_TEXT(text), FALSE);
215     gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
216                       GTK_EXPAND | GTK_SHRINK | GTK_FILL,
217                       GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
218     gtk_widget_show(text);
219     /* create the scrollbar */
220     vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
221     gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
222                       GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
223     gtk_widget_show( vscrollbar );
224     gtk_widget_realize( text );
225     /* stop the updates while we fill the text box */
226     gtk_text_freeze( GTK_TEXT(text) );
227     data_out_file = NULL;
228     data_out_file = fopen( filename1, "r" );
229     if( data_out_file ) {
230       char buffer[1024];
231       int nchars;
232       while( 1 ) {
233         nchars = fread( buffer, 1, 1024, data_out_file );
234         gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
235         if( nchars < 1024 ) {
236           break;
237         }
238       }
239       fclose( data_out_file );
240       unlink( filename1 );
241     }
242     gtk_text_thaw( GTK_TEXT(text) );
243     data_out_file = NULL;
244     gtk_widget_show( streamwindow );
245     if( cf.dfilter != NULL ) {
246       g_free( cf.dfilter );
247       cf.dfilter = NULL;
248     }
249   } else {
250     simple_dialog(ESD_TYPE_WARN, NULL,
251       "Error following stream.  Please make\n"
252       "sure you have a TCP packet selected.");
253   }
254 }
255
256 /* Open a file */
257 void
258 file_open_cmd_cb(GtkWidget *w, gpointer data) {
259   file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
260   
261   /* Connect the ok_button to file_ok_sel_cb function and pass along the
262      pointer to the filter entry */
263   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
264     "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel );
265
266   /* Gilbert --- I added this if statement. Is this right? */
267   if (w)
268   gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
269     E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
270
271   /* Connect the cancel_button to destroy the widget */
272   gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
273     (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
274     gtk_widget_destroy, GTK_OBJECT (file_sel));
275
276   gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
277
278   gtk_widget_show(file_sel);
279 }
280
281 /* Close a file */
282 void
283 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
284   close_cap_file(&cf, info_bar, file_ctx);
285 #ifdef USE_ITEM
286   set_menu_sensitivity("/File/Close", FALSE);
287   set_menu_sensitivity("/File/Reload", FALSE);
288 #else
289   set_menu_sensitivity("<Main>/File/Close", FALSE);
290   set_menu_sensitivity("<Main>/File/Reload", FALSE);
291 #endif
292 }
293
294 /* Reload a file using the current display filter */
295 void
296 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
297   GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
298
299   filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
300
301   if (cf.dfilter) g_free(cf.dfilter);
302   cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
303   load_cap_file(cf.filename, &cf);
304 }
305
306 /* Print a packet */
307 void
308 file_print_cmd_cb(GtkWidget *widget, gpointer data) {
309     print_tree(cf.pd, fd, GTK_TREE(tree_view));
310 }
311
312 /* What to do when a list item is selected/unselected */
313 void
314 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
315   GList      *l;
316
317 #ifdef WITH_WIRETAP
318   if (cf.wth) return; 
319 #else
320   if (cf.pfh) return;
321 #endif
322   blank_packetinfo();
323   gtk_text_freeze(GTK_TEXT(byte_view));
324   gtk_text_set_point(GTK_TEXT(byte_view), 0);
325   gtk_text_forward_delete(GTK_TEXT(byte_view),
326     gtk_text_get_length(GTK_TEXT(byte_view)));
327   l = g_list_nth(cf.plist, row);
328   if (l) {
329     fd = (frame_data *) l->data;
330     fseek(cf.fh, fd->file_off, SEEK_SET);
331     fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh);
332     dissect_packet(cf.pd, fd, (proto_tree*)tree_view);
333     packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1);
334   }
335   gtk_text_thaw(GTK_TEXT(byte_view));
336 }
337
338 void
339 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
340   gtk_text_freeze(GTK_TEXT(byte_view));
341   gtk_text_set_point(GTK_TEXT(byte_view), 0);
342   gtk_text_forward_delete(GTK_TEXT(byte_view),
343     gtk_text_get_length(GTK_TEXT(byte_view)));
344   gtk_text_thaw(GTK_TEXT(byte_view));
345   gtk_tree_clear_items(GTK_TREE(tree_view), 0,
346     g_list_length(GTK_TREE(tree_view)->children));
347 }
348
349 void
350 tree_view_cb(GtkWidget *w) {
351   gint       start = -1, len = -1;
352
353   if (GTK_TREE(w)->selection) {
354     start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
355       E_TREEINFO_START_KEY);
356     len   = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
357       E_TREEINFO_LEN_KEY);
358   }
359
360   gtk_text_freeze(GTK_TEXT(byte_view));
361   gtk_text_set_point(GTK_TEXT(byte_view), 0);
362   gtk_text_forward_delete(GTK_TEXT(byte_view),
363     gtk_text_get_length(GTK_TEXT(byte_view)));
364   packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, start, len);
365   gtk_text_thaw(GTK_TEXT(byte_view));
366 }
367
368 void
369 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
370   gtk_exit(0);
371 }
372
373 void blank_packetinfo() {
374   pi.srcip    = 0;
375   pi.destip   = 0;
376   pi.ipproto  = 0;
377   pi.srcport  = 0;
378   pi.destport = 0;
379 }
380
381 /* Things to do when the OK button is pressed */
382 void
383 main_realize_cb(GtkWidget *w, gpointer data) {
384   gchar  *cf_name = (gchar *) data;
385   int     err;
386   
387   if (cf_name) {
388     err = load_cap_file(cf_name, &cf);
389     cf_name[0] = '\0';
390   }
391   if (start_capture) {
392     if (cf.save_file)
393       capture(1);
394     else
395       capture(0);
396     start_capture = 0;
397   }
398 }
399
400 static void
401 ethereal_proto_init(void) {
402
403   init_dissect_udp();
404
405 }
406
407 void 
408 print_usage(void) {
409
410   fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
411   VERSION, comp_info_str);
412   fprintf(stderr, "%s [-v] [-b bold font] [-B byte view height] [-c count] [-h]\n",
413           PACKAGE);
414   fprintf(stderr, "         [-i interface] [-m medium font] [-n] [-P packet list height]\n");
415   fprintf(stderr, "         [-r infile] [-s snaplen] [-t <time stamp format>]\n");
416   fprintf(stderr, "         [-T tree view height] [-w savefile] \n");
417 }
418
419 /* And now our feature presentation... [ fade to music ] */
420 int
421 main(int argc, char *argv[])
422 {
423   int                  opt, i;
424   extern char         *optarg;
425   GtkWidget           *window, *main_vbox, *menubar, *u_pane, *l_pane,
426                       *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, 
427                       *tv_scrollw, *filter_bt, *filter_te;
428   GtkStyle            *pl_style;
429 #ifdef GTK_HAVE_FEATURES_1_1_0
430   GtkAccelGroup *accel;
431 #else
432   GtkAcceleratorTable *accel;
433 #endif
434
435 #ifdef GTK_HAVE_FEATURES_1_1_4
436   GtkWidget     *packet_sw;
437 #endif
438   gint                 pl_size = 280, tv_size = 95, bv_size = 75;
439   gchar               *rc_file, *cf_name = NULL;
440   gchar               *medium_font = MONO_MEDIUM_FONT;
441   gchar               *bold_font = MONO_BOLD_FONT;
442   e_prefs             *prefs;
443   gint                *col_fmt;
444   gchar              **col_title;
445
446   /* Let GTK get its args */
447   gtk_init (&argc, &argv);
448
449   prefs = read_prefs();
450     
451   /* Initialize the capture file struct */
452   cf.plist     = NULL;
453 #ifdef WITH_WIRETAP
454   cf.wth       = NULL;
455 #else
456   cf.pfh       = NULL;
457 #endif
458   cf.fh        = NULL;
459   cf.dfilter   = NULL;
460   cf.cfilter   = NULL;
461   cf.iface     = NULL;
462   cf.save_file = NULL;
463   cf.snap      = MIN_PACKET_SIZE;
464   cf.count     = 0;
465   cf.cinfo.num_cols = prefs->num_cols;
466   cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) *
467     cf.cinfo.num_cols);
468   cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) *
469     cf.cinfo.num_cols);
470
471   /* Assemble the compile-time options */
472   snprintf(comp_info_str, 256,
473 #ifdef GTK_MAJOR_VERSION
474     "GTK+ %d.%d.%d and %s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
475     GTK_MICRO_VERSION,
476 #else
477     "GTK+ (version unknown) and %s",
478 #endif
479 #ifdef WITH_WIRETAP
480     "wiretap");
481 #else
482     "libpcap");
483 #endif
484
485   /* Now get our args */
486   while ((opt = getopt(argc, argv, "b:B:c:hi:m:nP:r:s:t:T:w:v")) != EOF) {
487     switch (opt) {
488       case 'b':        /* Bold font */
489         bold_font = g_strdup(optarg);
490         break;
491       case 'B':        /* Byte view pane height */
492         bv_size = atoi(optarg);
493         break;
494       case 'c':        /* Capture xxx packets */
495         cf.count = atoi(optarg);
496         break;
497       case 'h':        /* Print help and exit */
498         print_usage();
499         exit(0);
500         break;
501       case 'i':        /* Use interface xxx */
502         cf.iface = g_strdup(optarg);
503         break;
504       case 'm':        /* Medium font */
505         medium_font = g_strdup(optarg);
506         break;
507       case 'n':        /* No name resolution */
508         g_resolving_actif = 0;
509         break;
510       case 'k':        /* Start capture immediately */
511         start_capture = 1;
512         break;
513       case 'P':        /* Packet list pane height */
514         pl_size = atoi(optarg);
515         break;
516       case 'r':        /* Read capture file xxx */
517         cf_name = g_strdup(optarg);
518         break;
519       case 's':        /* Set the snapshot (capture) length */
520         cf.snap = atoi(optarg);
521         break;
522       case 't':        /* Time stamp type */
523         if (strcmp(optarg, "r") == 0)
524           timestamp_type = RELATIVE;
525         else if (strcmp(optarg, "a") == 0)
526           timestamp_type = ABSOLUTE;
527         else if (strcmp(optarg, "d") == 0)
528           timestamp_type = DELTA;
529         else {
530           fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
531             optarg);
532           fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
533           fprintf(stderr, "or \"d\" for delta.\n");
534           exit(1);
535         }
536         break;
537       case 'T':        /* Tree view pane height */
538         tv_size = atoi(optarg);
539         break;
540       case 'v':        /* Show version and exit */
541         printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
542         exit(0);
543         break;
544       case 'w':        /* Write capture file xxx */
545         cf.save_file = g_strdup(optarg);
546         break;
547     }
548   }
549
550   /* Build the column format array */  
551   col_fmt   = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
552   col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
553   
554   for (i = 0; i < cf.cinfo.num_cols; i++) {
555     col_fmt[i]   = get_column_format(i);
556     col_title[i] = g_strdup(get_column_title(i));
557     cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
558       NUM_COL_FMTS);
559     get_column_format_matches(cf.cinfo.fmt_matx[i], col_fmt[i]);
560     cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
561   }
562
563   if (cf.snap < 1)
564     cf.snap = MAX_PACKET_SIZE;
565   else if (cf.snap < MIN_PACKET_SIZE)
566     cf.snap = MIN_PACKET_SIZE;
567   
568   rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
569   sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
570   gtk_rc_parse(rc_file);
571
572   if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
573     fprintf(stderr, "Error font %s not found (use -m option)\n", medium_font);
574     exit(1);
575   }
576
577   if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
578     fprintf(stderr, "Error font %s not found (use -b option)\n", bold_font);
579     exit(1);
580   }
581
582   /* Main window */  
583   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
584   gtk_widget_set_name(window, "main window");
585   gtk_signal_connect(GTK_OBJECT(window), "delete_event",
586     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
587   gtk_signal_connect(GTK_OBJECT(window), "destroy", 
588     GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
589   gtk_signal_connect(GTK_OBJECT (window), "realize",
590     GTK_SIGNAL_FUNC(main_realize_cb), cf_name);
591   gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
592   gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
593   gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
594
595   /* Container for menu bar, paned windows and progress/info box */
596   main_vbox = gtk_vbox_new(FALSE, 1);
597   gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
598   gtk_container_add(GTK_CONTAINER(window), main_vbox);
599   gtk_widget_show(main_vbox);
600
601   /* Menu bar */
602   get_main_menu(&menubar, &accel);
603 #ifdef GTK_HAVE_FEATURES_1_1_0
604   gtk_window_add_accel_group(GTK_WINDOW(window), accel);
605 #else
606   gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
607 #endif
608   gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
609   gtk_widget_show(menubar);
610
611   /* Panes for the packet list, tree, and byte view */
612   u_pane = gtk_vpaned_new();
613   gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
614   l_pane = gtk_vpaned_new();
615   gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
616   gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
617   gtk_widget_show(u_pane);
618   gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
619   gtk_widget_show(l_pane);
620
621   /* Packet list */
622   packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, col_title);
623   gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
624 #ifdef GTK_HAVE_FEATURES_1_1_4
625   packet_sw = gtk_scrolled_window_new(NULL, NULL);
626   gtk_widget_show(packet_sw);
627   gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
628 #endif
629   pl_style = gtk_style_new();
630   gdk_font_unref(pl_style->font);
631   pl_style->font = m_r_font;
632   gtk_widget_set_style(packet_list, pl_style);
633   gtk_widget_set_name(packet_list, "packet list");
634   gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
635     GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
636   gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
637     GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
638   for (i = 0; i < cf.cinfo.num_cols; i++) {
639     gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
640       get_column_width(get_column_format(i), pl_style->font));
641     if (col_fmt[i] == COL_NUMBER)
642       gtk_clist_set_column_justification(GTK_CLIST(packet_list), i, 
643         GTK_JUSTIFY_RIGHT);
644   }
645   gtk_widget_set_usize(packet_list, -1, pl_size);
646 #ifdef GTK_HAVE_FEATURES_1_1_4
647   gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
648 #else
649   gtk_paned_add1(GTK_PANED(u_pane), packet_list);
650 #endif
651   gtk_widget_show(packet_list);
652   
653   /* Tree view */
654   tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
655   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
656     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
657   gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
658   gtk_widget_set_usize(tv_scrollw, -1, tv_size);
659   gtk_widget_show(tv_scrollw);
660   
661   tree_view = gtk_tree_new();
662 #ifdef GTK_HAVE_FEATURES_1_1_4
663   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
664                   tree_view);
665 #else
666   gtk_container_add(GTK_CONTAINER(tv_scrollw), tree_view);
667 #endif
668   gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
669   gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
670   gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE);
671   gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
672     GTK_SIGNAL_FUNC(tree_view_cb), NULL);
673   gtk_widget_show(tree_view);
674
675   item_style = gtk_style_new();
676   gdk_font_unref(item_style->font);
677   item_style->font = m_r_font;
678
679   /* Byte view */
680   bv_table = gtk_table_new (2, 2, FALSE);
681   gtk_paned_add2(GTK_PANED(l_pane), bv_table);
682   gtk_widget_set_usize(bv_table, -1, bv_size);
683   gtk_widget_show(bv_table);
684
685   byte_view = gtk_text_new(NULL, NULL);
686   gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
687   gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
688   gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
689     GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
690   gtk_widget_show(byte_view);
691
692   bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
693   gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
694     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
695   gtk_widget_show (bv_hscroll);
696
697   bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
698   gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
699     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
700   gtk_widget_show(bv_vscroll);
701   
702   /* Progress/filter/info box */
703   stat_hbox = gtk_hbox_new(FALSE, 1);
704   gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
705   gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
706   gtk_widget_show(stat_hbox);
707
708   prog_bar = gtk_progress_bar_new();  
709   gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
710   gtk_widget_show(prog_bar);
711
712   filter_bt = gtk_button_new_with_label("Filter:");
713   gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
714     GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
715   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
716   gtk_widget_show(filter_bt);
717   
718   filter_te = gtk_entry_new();
719   gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
720   gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
721   gtk_widget_show(filter_te);
722
723 #ifdef USE_ITEM
724   set_menu_object_data("/File/Open", E_DFILTER_TE_KEY, filter_te);
725   set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
726   set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
727     filter_te);
728 #else
729   set_menu_object_data("<Main>/File/Open", E_DFILTER_TE_KEY, filter_te);
730   set_menu_object_data("<Main>/File/Reload", E_DFILTER_TE_KEY, filter_te);
731   set_menu_object_data("<Main>/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
732     filter_te);
733 #endif
734   info_bar = gtk_statusbar_new();
735   main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
736   file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
737   gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
738   gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
739   gtk_widget_show(info_bar);
740
741 /* 
742    Hmmm should we do it here
743 */
744
745   ethereal_proto_init();   /* Init anything that needs initializing */
746
747   gtk_widget_show(window);
748   gtk_main();
749
750   exit(0);
751 }