3 * $Id: ethereal.c,v 1.48 1999/07/07 22:51:37 gram 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"
70 #ifdef NEED_STRERROR_H
75 #include "timestamp.h"
88 #include "gtkpacket.h"
91 static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
92 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
94 FILE *data_out_file = NULL;
97 proto_tree *protocol_tree = NULL;
98 GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
100 GdkFont *m_r_font, *m_b_font;
102 guint main_ctx, file_ctx;
104 gint start_capture = 0;
105 gchar comp_info_str[256];
106 gchar *ethereal_path = NULL;
107 gchar *medium_font = MONO_MEDIUM_FONT;
108 gchar *bold_font = MONO_BOLD_FONT;
110 ts_type timestamp_type = RELATIVE;
112 GtkStyle *item_style;
114 int sync_mode; /* allow sync */
115 int sync_pipe[2]; /* used to sync father */
116 int fork_mode; /* fork a child to do the capture */
117 int sigusr2_received = 0;
118 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
120 /* Specifies byte offsets for object selected in tree */
121 static gint tree_selected_start=-1, tree_selected_len=-1;
123 #define E_DFILTER_TE_KEY "display_filter_te"
125 /* About Ethereal window */
127 about_ethereal( GtkWidget *w, gpointer data ) {
128 simple_dialog(ESD_TYPE_INFO, NULL,
129 "GNU Ethereal - network protocol analyzer\n"
130 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
131 "Compiled with %s\n\n"
134 "Gilbert Ramirez <gramirez@tivoli.com>\n"
135 "Hannes R. Boehm <hannes@boehm.org>\n"
136 "Mike Hall <mlh@io.com>\n"
137 "Bobo Rajec <bobo@bsp-consulting.sk>\n"
138 "Laurent Deniel <deniel@worldnet.fr>\n"
139 "Don Lafontaine <lafont02@cn.ca>\n"
140 "Guy Harris <guy@netapp.com>\n"
141 "Simon Wilkinson <sxw@dcs.ed.ac.uk>\n"
142 "Joerg Mayer <jmayer@telemation.de>\n"
143 "Martin Maciaszek <fastjack@i-s-o.net>\n"
144 "Didier Jorand <Didier.Jorand@alcatel.fr>\n"
145 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
146 "Richard Sharpe <sharpe@ns.aus.com>\n"
147 "John McDermott <jjm@jkintl.com>\n"
148 "Jeff Jahr <jjahr@shastanets.com>\n"
149 "Brad Robel-Forrest <bradr@watchguard.com>\n"
150 "Ashok Narayanan <ashokn@cisco.com>\n"
151 "Aaron Hillegass <aaron@classmax.com>\n"
152 "Jason Lango <jal@netapp.com>\n"
154 "\nSee http://ethereal.zing.org for more information",
155 VERSION, comp_info_str);
158 /* Things to do when the OK button is pressed */
160 file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
164 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
165 gtk_widget_hide(GTK_WIDGET (fs));
166 gtk_widget_destroy(GTK_WIDGET (fs));
168 /* this depends upon load_cap_file removing the filename from
169 * cf_name, leaving only the path to the directory. */
170 if ((err = load_cap_file(cf_name, &cf)) == 0)
173 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
178 set_menu_sensitivity("/File/Save", FALSE);
179 set_menu_sensitivity("/File/Save As...", TRUE);
180 set_menu_sensitivity("/Tools/Summary", TRUE);
182 set_menu_sensitivity("<Main>/File/Save", FALSE);
183 set_menu_sensitivity("<Main>/File/Save As...", TRUE);
184 set_menu_sensitivity("<Main>/Tools/Summary", TRUE);
188 /* Update the progress bar */
190 file_progress_cb(gpointer p) {
191 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
192 (gfloat) ftell(cf.fh) / (gfloat) cf.f_len);
196 /* Follow a TCP stream */
198 follow_stream_cb( GtkWidget *w, gpointer data ) {
200 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
201 GtkWidget *filter_te = NULL;
205 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
207 if( pi.ipproto == 6 ) {
208 /* we got tcp so we can follow */
209 /* check to see if we are using a filter */
210 if( cf.dfilter != NULL ) {
211 /* get rid of this one */
212 g_free( cf.dfilter );
215 /* create a new one and set the display filter entry accordingly */
216 cf.dfilter = build_follow_filter( &pi );
218 gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
219 /* reload so it goes in effect. Also we set data_out_file which
220 tells the tcp code to output the data */
221 close_cap_file( &cf, info_bar, file_ctx);
222 strcpy( filename1, tmpnam(NULL) );
223 data_out_file = fopen( filename1, "a" );
224 if( data_out_file == NULL ) {
225 fprintf( stderr, "Could not open tmp file %s\n", filename1 );
227 reset_tcp_reassembly();
228 err = load_cap_file( cf.filename, &cf );
230 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
233 /* the data_out_file should now be full of the streams information */
234 fclose( data_out_file );
235 /* the filename1 file now has all the text that was in the session */
236 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
237 gtk_widget_set_name( streamwindow, "TCP stream window" );
238 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
239 NULL, "WM destroy" );
240 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
241 NULL, "WM destroy" );
242 if( incomplete_tcp_stream ) {
243 gtk_window_set_title( GTK_WINDOW(streamwindow),
244 "Contents of TCP stream (incomplete)" );
246 gtk_window_set_title( GTK_WINDOW(streamwindow),
247 "Contents of TCP stream" );
249 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
250 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
251 /* setup the container */
252 box = gtk_vbox_new( FALSE, 0 );
253 gtk_container_add( GTK_CONTAINER(streamwindow), box );
254 gtk_widget_show( box );
255 /* set up the table we attach to */
256 table = gtk_table_new( 1, 2, FALSE );
257 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
258 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
259 gtk_widget_show( table );
260 /* create a text box */
261 text = gtk_text_new( NULL, NULL );
262 gtk_text_set_editable( GTK_TEXT(text), FALSE);
263 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
264 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
265 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
266 gtk_widget_show(text);
267 /* create the scrollbar */
268 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
269 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
270 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
271 gtk_widget_show( vscrollbar );
272 gtk_widget_realize( text );
273 /* stop the updates while we fill the text box */
274 gtk_text_freeze( GTK_TEXT(text) );
275 data_out_file = NULL;
276 data_out_file = fopen( filename1, "r" );
277 if( data_out_file ) {
281 nchars = fread( buffer, 1, 1024, data_out_file );
282 gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
283 if( nchars < 1024 ) {
287 fclose( data_out_file );
290 gtk_text_thaw( GTK_TEXT(text) );
291 data_out_file = NULL;
292 gtk_widget_show( streamwindow );
293 if( cf.dfilter != NULL ) {
294 g_free( cf.dfilter );
298 simple_dialog(ESD_TYPE_WARN, NULL,
299 "Error following stream. Please make\n"
300 "sure you have a TCP packet selected.");
304 /* Match selected byte pattern */
306 match_selected_cb(GtkWidget *w, gpointer data)
308 char *buf = malloc(1024);
309 GtkWidget *filter_te = NULL;
312 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
314 if (tree_selected_start<0) {
315 simple_dialog(ESD_TYPE_WARN, NULL,
316 "Error determining selected bytes. Please make\n"
317 "sure you have selected a field within the tree\n"
318 "view to be matched.");
331 simple_dialog(ESD_TYPE_WARN, NULL,
332 "Unsupported frame type format. Only Ethernet and FDDI\n"
333 "frame formats are supported.");
338 sprintf(buf, "("); ptr = buf+strlen(buf);
339 for (i=0, c=cf.pd+tree_selected_start; i+4<tree_selected_len; i+=4, c+=4) {
340 sprintf(ptr, "(ether[%d : 4]=0x%02X%02X%02X%02X) and ",
341 tree_selected_start+i,
346 ptr = buf+strlen(buf);
349 sprintf(ptr, "(ether[%d : %d]=0x",
350 tree_selected_start+i,
351 tree_selected_len - i);
352 ptr = buf+strlen(buf);
353 for (;i<tree_selected_len; i++) {
354 sprintf(ptr, "%02X", *c++);
355 ptr = buf+strlen(buf);
360 if( cf.dfilter != NULL ) {
361 /* get rid of this one */
362 g_free( cf.dfilter );
365 /* create a new one and set the display filter entry accordingly */
368 gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
369 /* reload so it goes in effect. */
370 close_cap_file( &cf, info_bar, file_ctx);
371 load_cap_file( cf.filename, &cf );
372 if( cf.dfilter != NULL ) {
373 g_free( cf.dfilter );
381 file_open_cmd_cb(GtkWidget *w, gpointer data) {
382 file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
384 /* Connect the ok_button to file_ok_sel_cb function and pass along the
385 pointer to the filter entry */
386 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
387 "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel );
389 /* Gilbert --- I added this if statement. Is this right? */
391 gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
392 E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
394 /* Connect the cancel_button to destroy the widget */
395 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
396 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
397 gtk_widget_destroy, GTK_OBJECT (file_sel));
399 if( fork_mode && (cf.save_file != NULL) )
400 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
402 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
404 gtk_widget_show(file_sel);
409 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
410 close_cap_file(&cf, info_bar, file_ctx);
412 set_menu_sensitivity("/File/Close", FALSE);
413 set_menu_sensitivity("/File/Reload", FALSE);
414 set_menu_sensitivity("/Tools/Summary", FALSE);
416 set_menu_sensitivity("<Main>/File/Close", FALSE);
417 set_menu_sensitivity("<Main>/File/Reload", FALSE);
418 set_menu_sensitivity("<Main>/Tools/Summary", FALSE);
423 file_save_cmd_cb(GtkWidget *w, gpointer data) {
424 file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
426 /* Connect the ok_button to file_ok_sel_cb function and pass along the
427 pointer to the filter entry */
428 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
429 "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
431 /* Connect the cancel_button to destroy the widget */
432 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
433 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
434 gtk_widget_destroy, GTK_OBJECT (file_sel));
436 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
438 gtk_widget_show(file_sel);
442 file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
443 file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as");
445 /* Connect the ok_button to file_ok_sel_cb function and pass along the
446 pointer to the filter entry */
447 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
448 "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
450 /* Connect the cancel_button to destroy the widget */
451 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
452 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
453 gtk_widget_destroy, GTK_OBJECT (file_sel));
455 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
456 gtk_widget_show(file_sel);
460 file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
464 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
465 gtk_widget_hide(GTK_WIDGET (fs));
466 gtk_widget_destroy(GTK_WIDGET (fs));
468 if (!file_mv(cf.save_file, cf_name))
470 g_free(cf.save_file);
471 cf.save_file = g_strdup(cf_name);
473 err = load_cap_file(cf_name, &cf);
475 simple_dialog(ESD_TYPE_WARN, NULL,
476 file_open_error_message(err, FALSE), cf_name);
480 set_menu_sensitivity("/File/Save", FALSE);
481 set_menu_sensitivity("/File/Save As...", TRUE);
483 set_menu_sensitivity("<Main>/File/Save", FALSE);
484 set_menu_sensitivity("<Main>/File/Save As...", TRUE);
489 file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
493 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
494 gtk_widget_hide(GTK_WIDGET (fs));
495 gtk_widget_destroy(GTK_WIDGET (fs));
497 if (!file_cp(cf.save_file, cf_name))
499 g_free(cf.save_file);
500 cf.save_file = g_strdup(cf_name);
502 err = load_cap_file(cf_name, &cf);
504 simple_dialog(ESD_TYPE_WARN, NULL,
505 file_open_error_message(err, FALSE), cf_name);
509 set_menu_sensitivity("/File/Save", FALSE);
510 set_menu_sensitivity("/File/Save As...", TRUE);
512 set_menu_sensitivity("<Main>/File/Save", FALSE);
513 set_menu_sensitivity("<Main>/File/Save As...", TRUE);
517 /* Reload a file using the current display filter */
519 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
520 /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
521 GtkWidget *filter_te;
524 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
526 if (cf.dfilter) g_free(cf.dfilter);
527 cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
528 err = load_cap_file(cf.filename, &cf);
530 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
537 file_print_cmd_cb(GtkWidget *widget, gpointer data) {
538 print_tree(cf.pd, fd, GTK_TREE(tree_view));
541 /* What to do when a list item is selected/unselected */
543 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
549 gtk_text_freeze(GTK_TEXT(byte_view));
550 gtk_text_set_point(GTK_TEXT(byte_view), 0);
551 gtk_text_forward_delete(GTK_TEXT(byte_view),
552 gtk_text_get_length(GTK_TEXT(byte_view)));
554 /* get the frame data struct pointer for this frame */
555 fd = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
556 fseek(cf.fh, fd->file_off, SEEK_SET);
557 fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh);
559 /* create the logical protocol tree */
561 proto_tree_free(protocol_tree);
562 protocol_tree = proto_tree_create_root();
563 dissect_packet(cf.pd, fd, protocol_tree);
565 /* display the GUI protocol tree and hex dump */
566 proto_tree_draw(protocol_tree, tree_view);
567 packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1);
568 gtk_text_thaw(GTK_TEXT(byte_view));
572 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
573 gtk_text_freeze(GTK_TEXT(byte_view));
574 gtk_text_set_point(GTK_TEXT(byte_view), 0);
575 gtk_text_forward_delete(GTK_TEXT(byte_view),
576 gtk_text_get_length(GTK_TEXT(byte_view)));
577 gtk_text_thaw(GTK_TEXT(byte_view));
578 gtk_tree_clear_items(GTK_TREE(tree_view), 0,
579 g_list_length(GTK_TREE(tree_view)->children));
583 tree_view_cb(GtkWidget *w) {
585 tree_selected_start = -1;
586 tree_selected_len = -1;
588 if (GTK_TREE(w)->selection) {
589 tree_selected_start =
590 (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
591 E_TREEINFO_START_KEY);
593 (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
597 gtk_text_freeze(GTK_TEXT(byte_view));
598 gtk_text_set_point(GTK_TEXT(byte_view), 0);
599 gtk_text_forward_delete(GTK_TEXT(byte_view),
600 gtk_text_get_length(GTK_TEXT(byte_view)));
601 packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len,
605 gtk_text_thaw(GTK_TEXT(byte_view));
609 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
610 if (cf.save_file && !cf.user_saved) {
611 unlink(cf.save_file);
616 void blank_packetinfo() {
624 /* Things to do when the main window is realized */
626 main_realize_cb(GtkWidget *w, gpointer data) {
634 sigusr2_handler(int sig) {
635 sigusr2_received = 1;
636 signal(SIGUSR2, sigusr2_handler);
639 /* call initialization routines at program startup time */
641 ethereal_proto_init(void) {
650 fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
651 VERSION, comp_info_str);
652 fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n",
654 fprintf(stderr, " [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n");
655 fprintf(stderr, " [-P packet list height] [-r infile] [-s snaplen]\n");
656 fprintf(stderr, " [-t <time stamp format>] [-T tree view height] [-w savefile] \n");
659 /* And now our feature presentation... [ fade to music ] */
661 main(int argc, char *argv[])
666 int pf_open_errno = 0;
668 GtkWidget *window, *main_vbox, *menubar, *u_pane, *l_pane,
669 *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox,
670 *tv_scrollw, *filter_bt, *filter_te;
671 #ifdef GTK_HAVE_FEATURES_1_1_0
672 GtkAccelGroup *accel;
674 GtkAcceleratorTable *accel;
677 #ifdef GTK_HAVE_FEATURES_1_1_4
678 GtkWidget *packet_sw;
680 gint pl_size = 280, tv_size = 95, bv_size = 75;
681 gchar *rc_file, *cf_name = NULL;
685 ethereal_path = argv[0];
687 /* Let GTK get its args */
688 gtk_init (&argc, &argv);
691 prefs = read_prefs(&pf_path);
692 if (pf_path != NULL) {
693 /* The preferences file exists, but couldn't be opened; "pf_path" is
694 its pathname. Remember "errno", as that says why the attempt
696 pf_open_errno = errno;
699 /* Initialize the capture file struct */
709 cf.snap = MAX_PACKET_SIZE;
711 cf.cinfo.num_cols = prefs->num_cols;
712 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
713 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
714 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
715 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
717 /* Assemble the compile-time options */
718 snprintf(comp_info_str, 256,
719 #ifdef GTK_MAJOR_VERSION
720 "GTK+ %d.%d.%d", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
723 "GTK+ (version unknown)"
727 /* Now get our args */
728 while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:Ss:t:T:w:v")) != EOF) {
730 case 'b': /* Bold font */
731 bold_font = g_strdup(optarg);
733 case 'B': /* Byte view pane height */
734 bv_size = atoi(optarg);
736 case 'c': /* Capture xxx packets */
737 cf.count = atoi(optarg);
740 cf.cfilter = g_strdup(optarg);
742 case 'F': /* Fork to capture */
745 case 'h': /* Print help and exit */
749 case 'i': /* Use interface xxx */
750 cf.iface = g_strdup(optarg);
752 case 'm': /* Medium font */
753 medium_font = g_strdup(optarg);
755 case 'n': /* No name resolution */
756 g_resolving_actif = 0;
758 case 'k': /* Start capture immediately */
761 case 'P': /* Packet list pane height */
762 pl_size = atoi(optarg);
764 case 'Q': /* Quit after capture (just capture to file) */
766 start_capture = 1; /*** -Q implies -k !! ***/
768 case 'r': /* Read capture file xxx */
769 cf_name = g_strdup(optarg);
771 case 's': /* Set the snapshot (capture) length */
772 cf.snap = atoi(optarg);
774 case 'S': /* "Sync" mode: used for following file ala tail -f */
776 fork_mode = 1; /* -S implies -F */
778 case 't': /* Time stamp type */
779 if (strcmp(optarg, "r") == 0)
780 timestamp_type = RELATIVE;
781 else if (strcmp(optarg, "a") == 0)
782 timestamp_type = ABSOLUTE;
783 else if (strcmp(optarg, "d") == 0)
784 timestamp_type = DELTA;
786 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
788 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
789 fprintf(stderr, "or \"d\" for delta.\n");
793 case 'T': /* Tree view pane height */
794 tv_size = atoi(optarg);
796 case 'v': /* Show version and exit */
797 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
800 case 'w': /* Write capture file xxx */
801 cf.save_file = g_strdup(optarg);
807 if (cf.iface == NULL) {
808 fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
811 if (cf.save_file == NULL) {
812 fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-w\" flag\n");
818 signal(SIGUSR2, sigusr2_handler);
820 /* Build the column format array */
821 col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
823 for (i = 0; i < cf.cinfo.num_cols; i++) {
824 col_fmt[i] = get_column_format(i);
825 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
826 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
828 get_column_format_matches(cf.cinfo.fmt_matx[i], col_fmt[i]);
829 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
830 cf.cinfo.col_width[i] = 0;
834 cf.snap = MAX_PACKET_SIZE;
835 else if (cf.snap < MIN_PACKET_SIZE)
836 cf.snap = MIN_PACKET_SIZE;
838 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
839 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
840 gtk_rc_parse(rc_file);
842 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
843 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
847 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
848 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
853 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
854 gtk_widget_set_name(window, "main window");
855 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
856 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
857 gtk_signal_connect(GTK_OBJECT(window), "destroy",
858 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
859 gtk_signal_connect(GTK_OBJECT (window), "realize",
860 GTK_SIGNAL_FUNC(main_realize_cb), NULL);
861 gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
862 gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
863 gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
865 /* Container for menu bar, paned windows and progress/info box */
866 main_vbox = gtk_vbox_new(FALSE, 1);
867 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
868 gtk_container_add(GTK_CONTAINER(window), main_vbox);
869 gtk_widget_show(main_vbox);
872 get_main_menu(&menubar, &accel);
873 #ifdef GTK_HAVE_FEATURES_1_1_0
874 gtk_window_add_accel_group(GTK_WINDOW(window), accel);
876 gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
878 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
879 gtk_widget_show(menubar);
881 /* Panes for the packet list, tree, and byte view */
882 u_pane = gtk_vpaned_new();
883 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
884 l_pane = gtk_vpaned_new();
885 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
886 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
887 gtk_widget_show(u_pane);
888 gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
889 gtk_widget_show(l_pane);
892 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols,
894 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
895 #ifdef GTK_HAVE_FEATURES_1_1_4
896 packet_sw = gtk_scrolled_window_new(NULL, NULL);
897 gtk_widget_show(packet_sw);
898 gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
900 pl_style = gtk_style_new();
901 gdk_font_unref(pl_style->font);
902 pl_style->font = m_r_font;
903 gtk_widget_set_style(packet_list, pl_style);
904 gtk_widget_set_name(packet_list, "packet list");
905 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
906 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
907 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
908 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
909 for (i = 0; i < cf.cinfo.num_cols; i++) {
910 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
911 gdk_string_width(pl_style->font, cf.cinfo.col_title[i]));
912 if (col_fmt[i] == COL_NUMBER)
913 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
916 gtk_widget_set_usize(packet_list, -1, pl_size);
917 #ifdef GTK_HAVE_FEATURES_1_1_4
918 gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
920 gtk_paned_add1(GTK_PANED(u_pane), packet_list);
922 gtk_widget_show(packet_list);
925 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
926 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
927 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
928 gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
929 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
930 gtk_widget_show(tv_scrollw);
932 tree_view = gtk_tree_new();
933 #ifdef GTK_HAVE_FEATURES_1_1_4
934 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
937 gtk_container_add(GTK_CONTAINER(tv_scrollw), tree_view);
939 gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
940 gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
941 gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE);
942 gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
943 GTK_SIGNAL_FUNC(tree_view_cb), NULL);
944 gtk_widget_show(tree_view);
946 item_style = gtk_style_new();
947 gdk_font_unref(item_style->font);
948 item_style->font = m_r_font;
951 bv_table = gtk_table_new (2, 2, FALSE);
952 gtk_paned_add2(GTK_PANED(l_pane), bv_table);
953 gtk_widget_set_usize(bv_table, -1, bv_size);
954 gtk_widget_show(bv_table);
956 byte_view = gtk_text_new(NULL, NULL);
957 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
958 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
959 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
960 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
961 gtk_widget_show(byte_view);
963 bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
964 gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
965 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
966 gtk_widget_show (bv_hscroll);
968 bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
969 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
970 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
971 gtk_widget_show(bv_vscroll);
973 /* Progress/filter/info box */
974 stat_hbox = gtk_hbox_new(FALSE, 1);
975 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
976 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
977 gtk_widget_show(stat_hbox);
979 prog_bar = gtk_progress_bar_new();
980 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
981 gtk_widget_show(prog_bar);
983 filter_bt = gtk_button_new_with_label("Filter:");
984 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
985 GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
986 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
987 gtk_widget_show(filter_bt);
989 filter_te = gtk_entry_new();
990 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
991 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
992 gtk_widget_show(filter_te);
995 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
996 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
997 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
1000 set_menu_object_data("<Main>/File/Open...", E_DFILTER_TE_KEY, filter_te);
1001 set_menu_object_data("<Main>/File/Reload", E_DFILTER_TE_KEY, filter_te);
1002 set_menu_object_data("<Main>/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
1005 info_bar = gtk_statusbar_new();
1006 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1007 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1008 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1009 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1010 gtk_widget_show(info_bar);
1013 Hmmm should we do it here
1016 ethereal_proto_init(); /* Init anything that needs initializing */
1018 gtk_widget_show(window);
1020 /* If we were given the name of a capture file, read it in now;
1021 we defer it until now, so that, if we can't open it, and pop
1022 up an alert box, the alert box is more likely to cmoe up on
1023 top of the main window - but before the preference-file-error
1024 alert box, so, if we get one of those, it's more likely to come
1027 err = load_cap_file(cf_name, &cf);
1029 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
1034 set_menu_sensitivity("/File/Save As...", TRUE);
1035 set_menu_sensitivity("/Tools/Summary", TRUE);
1037 set_menu_sensitivity("<Main>/File/Save As...", TRUE);
1038 set_menu_sensitivity("<Main>/Tools/Summary", TRUE);
1042 /* If we failed to open the preferences file, pop up an alert box;
1043 we defer it until now, so that the alert box is more likely to
1044 come up on top of the main window. */
1045 if (pf_path != NULL) {
1046 simple_dialog(ESD_TYPE_WARN, NULL,
1047 "Can't open preferences file\n\"%s\": %s.", pf_path,
1048 strerror(pf_open_errno));