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