3 * $Id: ethereal.c,v 1.37 1999/06/12 07:04:34 guy Exp $
5 * Ethereal - Network traffic analyzer
6 * By Gerald Combs <gerald@zing.org>
7 * Copyright 1998 Gerald Combs
9 * Richard Sharpe, 13-Feb-1999, added support for initializing structures
10 * needed by dissect routines
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.
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.
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.
28 * - Live browser/capture display
31 * - Check for end of packet in dissect_* routines.
33 * - Multiple window support
34 * - Add cut/copy/paste
35 * - Fix progress/status bar glitches? (GTK+ bug?)
36 * - Create header parsing routines
37 * - Check fopens, freads, fwrites
38 * - Make byte view scrollbars automatic?
39 * - Make byte view selections more fancy?
48 #include <pcap.h> /* needed for capture.h */
55 #include <sys/types.h>
58 #include <netinet/in.h>
61 #ifdef NEED_SNPRINTF_H
67 # include "snprintf.h"
82 #include "gtkpacket.h"
84 static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
85 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
87 FILE *data_out_file = NULL;
90 GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
92 GdkFont *m_r_font, *m_b_font;
93 guint main_ctx, file_ctx;
95 gint start_capture = 0;
96 gchar comp_info_str[256];
97 gchar *ethereal_path = NULL;
98 gchar *medium_font = MONO_MEDIUM_FONT;
99 gchar *bold_font = MONO_BOLD_FONT;
101 ts_type timestamp_type = RELATIVE;
103 GtkStyle *item_style;
105 int sync_mode; /* allow sync */
106 int sync_pipe[2]; /* used to sync father */
107 int fork_mode; /* fork a child to do the capture */
108 int sigusr2_received = 0;
109 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
111 #define E_DFILTER_TE_KEY "display_filter_te"
113 /* About Ethereal window */
115 about_ethereal( GtkWidget *w, gpointer data ) {
116 simple_dialog(ESD_TYPE_INFO, NULL,
117 "GNU Ethereal - network protocol analyzer\n"
118 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
119 "Compiled with %s\n\n"
122 "Gilbert Ramirez <gramirez@tivoli.com>\n"
123 "Hannes R. Boehm <hannes@boehm.org>\n"
124 "Mike Hall <mlh@io.com>\n"
125 "Bobo Rajec <bobo@bsp-consulting.sk>\n"
126 "Laurent Deniel <deniel@worldnet.fr>\n"
127 "Don Lafontaine <lafont02@cn.ca>\n"
128 "Guy Harris <guy@netapp.com>\n"
129 "Simon Wilkinson <sxw@dcs.ed.ac.uk>\n"
130 "Joerg Mayer <jmayer@telemation.de>\n"
131 "Martin Maciaszek <fastjack@i-s-o.net>\n"
132 "Didier Jorand <Didier.Jorand@alcatel.fr>\n"
133 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
134 "Richard Sharpe <sharpe@ns.aus.com>\n"
135 "John McDermott <jjm@jkintl.com>\n"
136 "Jeff Jahr <jjahr@shastanets.com>\n"
137 "Brad Robel-Forrest <bradr@watchguard.com>\n"
138 "Ashok Narayanan <ashokn@cisco.com>\n"
140 "\nSee http://ethereal.zing.org for more information",
141 VERSION, comp_info_str);
144 /* Things to do when the OK button is pressed */
146 file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
150 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
151 gtk_widget_hide(GTK_WIDGET (fs));
152 gtk_widget_destroy(GTK_WIDGET (fs));
154 /* this depends upon load_cap_file removing the filename from
155 * cf_name, leaving only the path to the directory. */
156 if ((err = load_cap_file(cf_name, &cf)) == 0)
160 set_menu_sensitivity("/File/Save", FALSE);
161 set_menu_sensitivity("/File/Save as", TRUE);
163 set_menu_sensitivity("<Main>/File/Save", FALSE);
164 set_menu_sensitivity("<Main>/File/Save as", TRUE);
168 /* Update the progress bar */
170 file_progress_cb(gpointer p) {
171 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
172 (gfloat) ftell(cf.fh) / (gfloat) cf.f_len);
176 /* Follow a TCP stream */
178 follow_stream_cb( GtkWidget *w, gpointer data ) {
180 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
181 GtkWidget *filter_te = NULL;
184 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
186 if( pi.ipproto == 6 ) {
187 /* we got tcp so we can follow */
188 /* check to see if we are using a filter */
189 if( cf.dfilter != NULL ) {
190 /* get rid of this one */
191 g_free( cf.dfilter );
194 /* create a new one and set the display filter entry accordingly */
195 cf.dfilter = build_follow_filter( &pi );
197 gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
198 /* reload so it goes in effect. Also we set data_out_file which
199 tells the tcp code to output the data */
200 close_cap_file( &cf, info_bar, file_ctx);
201 strcpy( filename1, tmpnam(NULL) );
202 data_out_file = fopen( filename1, "a" );
203 if( data_out_file == NULL ) {
204 fprintf( stderr, "Could not open tmp file %s\n", filename1 );
206 reset_tcp_reassembly();
207 load_cap_file( cf.filename, &cf );
208 /* the data_out_file should now be full of the streams information */
209 fclose( data_out_file );
210 /* the filename1 file now has all the text that was in the session */
211 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
212 gtk_widget_set_name( streamwindow, "TCP stream window" );
213 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
214 NULL, "WM destroy" );
215 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
216 NULL, "WM destroy" );
217 if( incomplete_tcp_stream ) {
218 gtk_window_set_title( GTK_WINDOW(streamwindow),
219 "Contents of TCP stream (incomplete)" );
221 gtk_window_set_title( GTK_WINDOW(streamwindow),
222 "Contents of TCP stream" );
224 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
225 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
226 /* setup the container */
227 box = gtk_vbox_new( FALSE, 0 );
228 gtk_container_add( GTK_CONTAINER(streamwindow), box );
229 gtk_widget_show( box );
230 /* set up the table we attach to */
231 table = gtk_table_new( 1, 2, FALSE );
232 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
233 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
234 gtk_widget_show( table );
235 /* create a text box */
236 text = gtk_text_new( NULL, NULL );
237 gtk_text_set_editable( GTK_TEXT(text), FALSE);
238 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
239 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
240 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
241 gtk_widget_show(text);
242 /* create the scrollbar */
243 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
244 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
245 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
246 gtk_widget_show( vscrollbar );
247 gtk_widget_realize( text );
248 /* stop the updates while we fill the text box */
249 gtk_text_freeze( GTK_TEXT(text) );
250 data_out_file = NULL;
251 data_out_file = fopen( filename1, "r" );
252 if( data_out_file ) {
256 nchars = fread( buffer, 1, 1024, data_out_file );
257 gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
258 if( nchars < 1024 ) {
262 fclose( data_out_file );
265 gtk_text_thaw( GTK_TEXT(text) );
266 data_out_file = NULL;
267 gtk_widget_show( streamwindow );
268 if( cf.dfilter != NULL ) {
269 g_free( cf.dfilter );
273 simple_dialog(ESD_TYPE_WARN, NULL,
274 "Error following stream. Please make\n"
275 "sure you have a TCP packet selected.");
281 file_open_cmd_cb(GtkWidget *w, gpointer data) {
282 file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
284 /* Connect the ok_button to file_ok_sel_cb function and pass along the
285 pointer to the filter entry */
286 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
287 "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel );
289 /* Gilbert --- I added this if statement. Is this right? */
291 gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
292 E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
294 /* Connect the cancel_button to destroy the widget */
295 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
296 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
297 gtk_widget_destroy, GTK_OBJECT (file_sel));
299 if( fork_mode && (cf.save_file != NULL) )
300 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
302 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
304 gtk_widget_show(file_sel);
309 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
310 close_cap_file(&cf, info_bar, file_ctx);
312 set_menu_sensitivity("/File/Close", FALSE);
313 set_menu_sensitivity("/File/Reload", FALSE);
315 set_menu_sensitivity("<Main>/File/Close", FALSE);
316 set_menu_sensitivity("<Main>/File/Reload", FALSE);
321 file_save_cmd_cb(GtkWidget *w, gpointer data) {
322 file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
324 /* Connect the ok_button to file_ok_sel_cb function and pass along the
325 pointer to the filter entry */
326 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
327 "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
329 /* Connect the cancel_button to destroy the widget */
330 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
331 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
332 gtk_widget_destroy, GTK_OBJECT (file_sel));
334 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
336 gtk_widget_show(file_sel);
340 file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
341 file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as");
343 /* Connect the ok_button to file_ok_sel_cb function and pass along the
344 pointer to the filter entry */
345 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
346 "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
348 /* Connect the cancel_button to destroy the widget */
349 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
350 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
351 gtk_widget_destroy, GTK_OBJECT (file_sel));
353 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
354 gtk_widget_show(file_sel);
358 file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
361 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
362 gtk_widget_hide(GTK_WIDGET (fs));
363 gtk_widget_destroy(GTK_WIDGET (fs));
365 if (!file_mv(cf.save_file, cf_name))
367 g_free(cf.save_file);
368 cf.save_file = g_strdup(cf_name);
370 load_cap_file(cf_name, &cf);
373 set_menu_sensitivity("/File/Save", FALSE);
374 set_menu_sensitivity("/File/Save as", TRUE);
376 set_menu_sensitivity("<Main>/File/Save", FALSE);
377 set_menu_sensitivity("<Main>/File/Save as", TRUE);
382 file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
385 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
386 gtk_widget_hide(GTK_WIDGET (fs));
387 gtk_widget_destroy(GTK_WIDGET (fs));
389 if (!file_cp(cf.save_file, cf_name))
391 g_free(cf.save_file);
392 cf.save_file = g_strdup(cf_name);
394 load_cap_file(cf_name, &cf);
397 set_menu_sensitivity("/File/Save", FALSE);
398 set_menu_sensitivity("/File/Save as", TRUE);
400 set_menu_sensitivity("<Main>/File/Save", FALSE);
401 set_menu_sensitivity("<Main>/File/Save as", TRUE);
405 /* Reload a file using the current display filter */
407 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
408 /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
409 GtkWidget *filter_te;
411 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
413 if (cf.dfilter) g_free(cf.dfilter);
414 cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
415 load_cap_file(cf.filename, &cf);
420 file_print_cmd_cb(GtkWidget *widget, gpointer data) {
421 print_tree(cf.pd, fd, GTK_TREE(tree_view));
424 /* What to do when a list item is selected/unselected */
426 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
437 gtk_text_freeze(GTK_TEXT(byte_view));
438 gtk_text_set_point(GTK_TEXT(byte_view), 0);
439 gtk_text_forward_delete(GTK_TEXT(byte_view),
440 gtk_text_get_length(GTK_TEXT(byte_view)));
441 l = g_list_nth(cf.plist_first, row);
443 fd = (frame_data *) l->data;
444 fseek(cf.fh, fd->file_off, SEEK_SET);
445 fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh);
446 dissect_packet(cf.pd, fd, (proto_tree*)tree_view);
447 packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1);
449 gtk_text_thaw(GTK_TEXT(byte_view));
453 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
454 gtk_text_freeze(GTK_TEXT(byte_view));
455 gtk_text_set_point(GTK_TEXT(byte_view), 0);
456 gtk_text_forward_delete(GTK_TEXT(byte_view),
457 gtk_text_get_length(GTK_TEXT(byte_view)));
458 gtk_text_thaw(GTK_TEXT(byte_view));
459 gtk_tree_clear_items(GTK_TREE(tree_view), 0,
460 g_list_length(GTK_TREE(tree_view)->children));
464 tree_view_cb(GtkWidget *w) {
465 gint start = -1, len = -1;
467 if (GTK_TREE(w)->selection) {
468 start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
469 E_TREEINFO_START_KEY);
470 len = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
474 gtk_text_freeze(GTK_TEXT(byte_view));
475 gtk_text_set_point(GTK_TEXT(byte_view), 0);
476 gtk_text_forward_delete(GTK_TEXT(byte_view),
477 gtk_text_get_length(GTK_TEXT(byte_view)));
478 packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, start, len);
479 gtk_text_thaw(GTK_TEXT(byte_view));
483 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
484 if (cf.save_file && !cf.user_saved) {
485 unlink(cf.save_file);
490 void blank_packetinfo() {
498 /* Things to do when the OK button is pressed */
500 main_realize_cb(GtkWidget *w, gpointer data) {
501 gchar *cf_name = (gchar *) data;
505 err = load_cap_file(cf_name, &cf);
508 set_menu_sensitivity("/File/Save as", TRUE);
510 set_menu_sensitivity("<Main>/File/Save as", TRUE);
520 sigusr2_handler(int sig) {
521 sigusr2_received = 1;
522 signal(SIGUSR2, sigusr2_handler);
526 ethereal_proto_init(void) {
535 fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
536 VERSION, comp_info_str);
537 fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n",
539 fprintf(stderr, " [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n");
540 fprintf(stderr, " [-P packet list height] [-r infile] [-s snaplen]\n");
541 fprintf(stderr, " [-t <time stamp format>] [-T tree view height] [-w savefile] \n");
544 /* And now our feature presentation... [ fade to music ] */
546 main(int argc, char *argv[])
551 int pf_open_errno = 0;
552 GtkWidget *window, *main_vbox, *menubar, *u_pane, *l_pane,
553 *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox,
554 *tv_scrollw, *filter_bt, *filter_te;
556 #ifdef GTK_HAVE_FEATURES_1_1_0
557 GtkAccelGroup *accel;
559 GtkAcceleratorTable *accel;
562 #ifdef GTK_HAVE_FEATURES_1_1_4
563 GtkWidget *packet_sw;
565 gint pl_size = 280, tv_size = 95, bv_size = 75;
566 gchar *rc_file, *cf_name = NULL;
571 ethereal_path = argv[0];
573 /* Let GTK get its args */
574 gtk_init (&argc, &argv);
577 prefs = read_prefs(&pf_path);
578 if (pf_path != NULL) {
579 /* The preferences file exists, but couldn't be opened; "pf_path" is
580 its pathname. Remember "errno", as that says why the attempt
582 pf_open_errno = errno;
585 /* Initialize the capture file struct */
587 cf.plist_first = NULL;
599 cf.snap = MAX_PACKET_SIZE;
601 cf.cinfo.num_cols = prefs->num_cols;
602 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
603 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
605 /* Assemble the compile-time options */
606 snprintf(comp_info_str, 256,
607 #ifdef GTK_MAJOR_VERSION
608 "GTK+ %d.%d.%d and %s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
611 "GTK+ (version unknown) and %s",
619 /* Now get our args */
620 while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:Ss:t:T:w:v")) != EOF) {
622 case 'b': /* Bold font */
623 bold_font = g_strdup(optarg);
625 case 'B': /* Byte view pane height */
626 bv_size = atoi(optarg);
628 case 'c': /* Capture xxx packets */
629 cf.count = atoi(optarg);
632 cf.cfilter = g_strdup(optarg);
634 case 'F': /* Fork to capture */
637 case 'h': /* Print help and exit */
641 case 'i': /* Use interface xxx */
642 cf.iface = g_strdup(optarg);
644 case 'm': /* Medium font */
645 medium_font = g_strdup(optarg);
647 case 'n': /* No name resolution */
648 g_resolving_actif = 0;
650 case 'k': /* Start capture immediately */
653 case 'P': /* Packet list pane height */
654 pl_size = atoi(optarg);
656 case 'Q': /* Quit after capture (just capture to file) */
658 start_capture = 1; /*** -Q implies -k !! ***/
660 case 'r': /* Read capture file xxx */
661 cf_name = g_strdup(optarg);
663 case 's': /* Set the snapshot (capture) length */
664 cf.snap = atoi(optarg);
666 case 'S': /* "Sync" mode: used for following file ala tail -f */
668 fork_mode = 1; /* -S implies -F */
670 case 't': /* Time stamp type */
671 if (strcmp(optarg, "r") == 0)
672 timestamp_type = RELATIVE;
673 else if (strcmp(optarg, "a") == 0)
674 timestamp_type = ABSOLUTE;
675 else if (strcmp(optarg, "d") == 0)
676 timestamp_type = DELTA;
678 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
680 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
681 fprintf(stderr, "or \"d\" for delta.\n");
685 case 'T': /* Tree view pane height */
686 tv_size = atoi(optarg);
688 case 'v': /* Show version and exit */
689 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
692 case 'w': /* Write capture file xxx */
693 cf.save_file = g_strdup(optarg);
699 signal(SIGUSR2, sigusr2_handler);
701 /* Build the column format array */
702 col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
703 col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
705 for (i = 0; i < cf.cinfo.num_cols; i++) {
706 col_fmt[i] = get_column_format(i);
707 col_title[i] = g_strdup(get_column_title(i));
708 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
710 get_column_format_matches(cf.cinfo.fmt_matx[i], col_fmt[i]);
711 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
715 cf.snap = MAX_PACKET_SIZE;
716 else if (cf.snap < MIN_PACKET_SIZE)
717 cf.snap = MIN_PACKET_SIZE;
719 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
720 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
721 gtk_rc_parse(rc_file);
723 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
724 fprintf(stderr, "Error font %s not found (use -m option)\n", medium_font);
728 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
729 fprintf(stderr, "Error font %s not found (use -b option)\n", bold_font);
734 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
735 gtk_widget_set_name(window, "main window");
736 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
737 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
738 gtk_signal_connect(GTK_OBJECT(window), "destroy",
739 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
740 gtk_signal_connect(GTK_OBJECT (window), "realize",
741 GTK_SIGNAL_FUNC(main_realize_cb), cf_name);
742 gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
743 gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
744 gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
746 /* Container for menu bar, paned windows and progress/info box */
747 main_vbox = gtk_vbox_new(FALSE, 1);
748 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
749 gtk_container_add(GTK_CONTAINER(window), main_vbox);
750 gtk_widget_show(main_vbox);
753 get_main_menu(&menubar, &accel);
754 #ifdef GTK_HAVE_FEATURES_1_1_0
755 gtk_window_add_accel_group(GTK_WINDOW(window), accel);
757 gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
759 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
760 gtk_widget_show(menubar);
762 /* Panes for the packet list, tree, and byte view */
763 u_pane = gtk_vpaned_new();
764 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
765 l_pane = gtk_vpaned_new();
766 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
767 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
768 gtk_widget_show(u_pane);
769 gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
770 gtk_widget_show(l_pane);
773 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, col_title);
774 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
775 #ifdef GTK_HAVE_FEATURES_1_1_4
776 packet_sw = gtk_scrolled_window_new(NULL, NULL);
777 gtk_widget_show(packet_sw);
778 gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
780 pl_style = gtk_style_new();
781 gdk_font_unref(pl_style->font);
782 pl_style->font = m_r_font;
783 gtk_widget_set_style(packet_list, pl_style);
784 gtk_widget_set_name(packet_list, "packet list");
785 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
786 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
787 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
788 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
789 for (i = 0; i < cf.cinfo.num_cols; i++) {
790 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
791 get_column_width(get_column_format(i), pl_style->font));
792 if (col_fmt[i] == COL_NUMBER)
793 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
796 gtk_widget_set_usize(packet_list, -1, pl_size);
797 #ifdef GTK_HAVE_FEATURES_1_1_4
798 gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
800 gtk_paned_add1(GTK_PANED(u_pane), packet_list);
802 gtk_widget_show(packet_list);
805 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
806 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
807 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
808 gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
809 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
810 gtk_widget_show(tv_scrollw);
812 tree_view = gtk_tree_new();
813 #ifdef GTK_HAVE_FEATURES_1_1_4
814 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
817 gtk_container_add(GTK_CONTAINER(tv_scrollw), tree_view);
819 gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
820 gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
821 gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE);
822 gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
823 GTK_SIGNAL_FUNC(tree_view_cb), NULL);
824 gtk_widget_show(tree_view);
826 item_style = gtk_style_new();
827 gdk_font_unref(item_style->font);
828 item_style->font = m_r_font;
831 bv_table = gtk_table_new (2, 2, FALSE);
832 gtk_paned_add2(GTK_PANED(l_pane), bv_table);
833 gtk_widget_set_usize(bv_table, -1, bv_size);
834 gtk_widget_show(bv_table);
836 byte_view = gtk_text_new(NULL, NULL);
837 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
838 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
839 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
840 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
841 gtk_widget_show(byte_view);
843 bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
844 gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
845 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
846 gtk_widget_show (bv_hscroll);
848 bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
849 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
850 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
851 gtk_widget_show(bv_vscroll);
853 /* Progress/filter/info box */
854 stat_hbox = gtk_hbox_new(FALSE, 1);
855 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
856 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
857 gtk_widget_show(stat_hbox);
859 prog_bar = gtk_progress_bar_new();
860 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
861 gtk_widget_show(prog_bar);
863 filter_bt = gtk_button_new_with_label("Filter:");
864 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
865 GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
866 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
867 gtk_widget_show(filter_bt);
869 filter_te = gtk_entry_new();
870 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
871 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
872 gtk_widget_show(filter_te);
875 set_menu_object_data("/File/Open", E_DFILTER_TE_KEY, filter_te);
876 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
877 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
880 set_menu_object_data("<Main>/File/Open", E_DFILTER_TE_KEY, filter_te);
881 set_menu_object_data("<Main>/File/Reload", E_DFILTER_TE_KEY, filter_te);
882 set_menu_object_data("<Main>/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
885 info_bar = gtk_statusbar_new();
886 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
887 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
888 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
889 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
890 gtk_widget_show(info_bar);
893 Hmmm should we do it here
896 ethereal_proto_init(); /* Init anything that needs initializing */
898 gtk_widget_show(window);
900 /* If we failed to open the preferences file, pop up an alert box;
901 we defer it until now, so that the alert box is more likely to
902 come up on top of the main window. */
903 if (pf_path != NULL) {
904 simple_dialog(ESD_TYPE_WARN, NULL,
905 "Can't open preferences file\n\"%s\": %s.", pf_path,
906 strerror(pf_open_errno));