3 * $Id: ethereal.c,v 1.54 1999/07/13 03:08:04 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?
58 #include <sys/types.h>
66 #ifdef HAVE_NETINET_IN_H
67 #include <netinet/in.h>
72 #ifdef NEED_SNPRINTF_H
78 # include "snprintf.h"
81 #ifdef NEED_STRERROR_H
86 #include "timestamp.h"
99 #include "gtkpacket.h"
102 static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs);
103 static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs);
105 FILE *data_out_file = NULL;
108 proto_tree *protocol_tree = NULL;
109 GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
111 GdkFont *m_r_font, *m_b_font;
113 guint main_ctx, file_ctx;
115 gint start_capture = 0;
116 gchar comp_info_str[256];
117 gchar *ethereal_path = NULL;
118 gchar *medium_font = MONO_MEDIUM_FONT;
119 gchar *bold_font = MONO_BOLD_FONT;
121 ts_type timestamp_type = RELATIVE;
123 GtkStyle *item_style;
126 int sync_mode; /* allow sync */
127 int sync_pipe[2]; /* used to sync father */
128 int fork_mode; /* fork a child to do the capture */
129 int sigusr2_received = 0;
130 int quit_after_cap; /* Makes a "capture only mode". Implies -k */
133 /* Specifies byte offsets for object selected in tree */
134 static gint tree_selected_start=-1, tree_selected_len=-1;
136 #define E_DFILTER_TE_KEY "display_filter_te"
138 /* About Ethereal window */
140 about_ethereal( GtkWidget *w, gpointer data ) {
141 simple_dialog(ESD_TYPE_INFO, NULL,
142 "GNU Ethereal - network protocol analyzer\n"
143 "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
144 "Compiled with %s\n\n"
147 "Gilbert Ramirez <gramirez@tivoli.com>\n"
148 "Hannes R. Boehm <hannes@boehm.org>\n"
149 "Mike Hall <mlh@io.com>\n"
150 "Bobo Rajec <bobo@bsp-consulting.sk>\n"
151 "Laurent Deniel <deniel@worldnet.fr>\n"
152 "Don Lafontaine <lafont02@cn.ca>\n"
153 "Guy Harris <guy@netapp.com>\n"
154 "Simon Wilkinson <sxw@dcs.ed.ac.uk>\n"
155 "Joerg Mayer <jmayer@telemation.de>\n"
156 "Martin Maciaszek <fastjack@i-s-o.net>\n"
157 "Didier Jorand <Didier.Jorand@alcatel.fr>\n"
158 "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
159 "Richard Sharpe <sharpe@ns.aus.com>\n"
160 "John McDermott <jjm@jkintl.com>\n"
161 "Jeff Jahr <jjahr@shastanets.com>\n"
162 "Brad Robel-Forrest <bradr@watchguard.com>\n"
163 "Ashok Narayanan <ashokn@cisco.com>\n"
164 "Aaron Hillegass <aaron@classmax.com>\n"
165 "Jason Lango <jal@netapp.com>\n"
166 "Johan Feyaerts <Johan.Feyaerts@siemens.atea.be>\n"
168 "\nSee http://ethereal.zing.org for more information",
169 VERSION, comp_info_str);
172 /* Things to do when the OK button is pressed */
174 file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
178 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
179 gtk_widget_hide(GTK_WIDGET (fs));
180 gtk_widget_destroy(GTK_WIDGET (fs));
182 /* this depends upon load_cap_file removing the filename from
183 * cf_name, leaving only the path to the directory. */
184 if ((err = load_cap_file(cf_name, &cf)) == 0)
187 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
191 set_menu_sensitivity("/File/Save", FALSE);
192 set_menu_sensitivity("/File/Save As...", TRUE);
193 set_menu_sensitivity("/Tools/Summary", TRUE);
196 /* Update the progress bar */
198 file_progress_cb(gpointer p) {
199 gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar),
200 (gfloat) ftell(cf.fh) / (gfloat) cf.f_len);
204 /* Follow a TCP stream */
206 follow_stream_cb( GtkWidget *w, gpointer data ) {
208 GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
209 GtkWidget *filter_te = NULL;
213 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
215 if( pi.ipproto == 6 ) {
216 /* we got tcp so we can follow */
217 /* check to see if we are using a filter */
218 if( cf.dfilter != NULL ) {
219 /* get rid of this one */
220 g_free( cf.dfilter );
223 /* create a new one and set the display filter entry accordingly */
224 cf.dfilter = build_follow_filter( &pi );
226 gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
227 /* reload so it goes in effect. Also we set data_out_file which
228 tells the tcp code to output the data */
229 close_cap_file( &cf, info_bar, file_ctx);
230 strcpy( filename1, tmpnam(NULL) );
231 data_out_file = fopen( filename1, "a" );
232 if( data_out_file == NULL ) {
233 fprintf( stderr, "Could not open tmp file %s\n", filename1 );
235 reset_tcp_reassembly();
236 err = load_cap_file( cf.filename, &cf );
238 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
241 /* the data_out_file should now be full of the streams information */
242 fclose( data_out_file );
243 /* the filename1 file now has all the text that was in the session */
244 streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
245 gtk_widget_set_name( streamwindow, "TCP stream window" );
246 gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
247 NULL, "WM destroy" );
248 gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
249 NULL, "WM destroy" );
250 if( incomplete_tcp_stream ) {
251 gtk_window_set_title( GTK_WINDOW(streamwindow),
252 "Contents of TCP stream (incomplete)" );
254 gtk_window_set_title( GTK_WINDOW(streamwindow),
255 "Contents of TCP stream" );
257 gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
258 gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
259 /* setup the container */
260 box = gtk_vbox_new( FALSE, 0 );
261 gtk_container_add( GTK_CONTAINER(streamwindow), box );
262 gtk_widget_show( box );
263 /* set up the table we attach to */
264 table = gtk_table_new( 1, 2, FALSE );
265 gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2);
266 gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 );
267 gtk_widget_show( table );
268 /* create a text box */
269 text = gtk_text_new( NULL, NULL );
270 gtk_text_set_editable( GTK_TEXT(text), FALSE);
271 gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1,
272 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
273 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
274 gtk_widget_show(text);
275 /* create the scrollbar */
276 vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj );
277 gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1,
278 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 );
279 gtk_widget_show( vscrollbar );
280 gtk_widget_realize( text );
281 /* stop the updates while we fill the text box */
282 gtk_text_freeze( GTK_TEXT(text) );
283 data_out_file = NULL;
284 data_out_file = fopen( filename1, "r" );
285 if( data_out_file ) {
289 nchars = fread( buffer, 1, 1024, data_out_file );
290 gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
291 if( nchars < 1024 ) {
295 fclose( data_out_file );
298 gtk_text_thaw( GTK_TEXT(text) );
299 data_out_file = NULL;
300 gtk_widget_show( streamwindow );
301 if( cf.dfilter != NULL ) {
302 g_free( cf.dfilter );
306 simple_dialog(ESD_TYPE_WARN, NULL,
307 "Error following stream. Please make\n"
308 "sure you have a TCP packet selected.");
312 /* Match selected byte pattern */
314 match_selected_cb(GtkWidget *w, gpointer data)
317 char *buf = malloc(1024);
319 GtkWidget *filter_te = NULL;
322 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
324 if (tree_selected_start<0) {
325 simple_dialog(ESD_TYPE_WARN, NULL,
326 "Error determining selected bytes. Please make\n"
327 "sure you have selected a field within the tree\n"
328 "view to be matched.");
341 simple_dialog(ESD_TYPE_WARN, NULL,
342 "Unsupported frame type format. Only Ethernet and FDDI\n"
343 "frame formats are supported.");
348 sprintf(buf, "("); ptr = buf+strlen(buf);
349 for (i=0, c=cf.pd+tree_selected_start; i+4<tree_selected_len; i+=4, c+=4) {
350 sprintf(ptr, "(ether[%d : 4]=0x%02X%02X%02X%02X) and ",
351 tree_selected_start+i,
356 ptr = buf+strlen(buf);
359 sprintf(ptr, "(ether[%d : %d]=0x",
360 tree_selected_start+i,
361 tree_selected_len - i);
362 ptr = buf+strlen(buf);
363 for (;i<tree_selected_len; i++) {
364 sprintf(ptr, "%02X", *c++);
365 ptr = buf+strlen(buf);
370 if( cf.dfilter != NULL ) {
371 /* get rid of this one */
372 g_free( cf.dfilter );
375 /* create a new one and set the display filter entry accordingly */
378 gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter);
379 /* reload so it goes in effect. */
380 close_cap_file( &cf, info_bar, file_ctx);
381 load_cap_file( cf.filename, &cf );
382 if( cf.dfilter != NULL ) {
383 g_free( cf.dfilter );
391 file_open_cmd_cb(GtkWidget *w, gpointer data) {
392 file_sel = gtk_file_selection_new ("Ethereal: Open Capture File");
394 /* Connect the ok_button to file_ok_sel_cb function and pass along the
395 pointer to the filter entry */
396 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
397 "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel );
399 /* Gilbert --- I added this if statement. Is this right? */
401 gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button),
402 E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY));
404 /* Connect the cancel_button to destroy the widget */
405 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
406 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
407 gtk_widget_destroy, GTK_OBJECT (file_sel));
410 if( fork_mode && (cf.save_file != NULL) )
412 if( cf.save_file != NULL )
414 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file);
416 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
418 gtk_widget_show(file_sel);
423 file_close_cmd_cb(GtkWidget *widget, gpointer data) {
424 close_cap_file(&cf, info_bar, file_ctx);
425 set_menu_sensitivity("/File/Close", FALSE);
426 set_menu_sensitivity("/File/Reload", FALSE);
427 set_menu_sensitivity("/Tools/Summary", FALSE);
431 file_save_cmd_cb(GtkWidget *w, gpointer data) {
432 file_sel = gtk_file_selection_new ("Ethereal: Save Capture File");
434 /* Connect the ok_button to file_ok_sel_cb function and pass along the
435 pointer to the filter entry */
436 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
437 "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel );
439 /* Connect the cancel_button to destroy the widget */
440 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
441 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
442 gtk_widget_destroy, GTK_OBJECT (file_sel));
444 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
446 gtk_widget_show(file_sel);
450 file_save_as_cmd_cb(GtkWidget *w, gpointer data) {
451 file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as");
453 /* Connect the ok_button to file_ok_sel_cb function and pass along the
454 pointer to the filter entry */
455 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button),
456 "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel );
458 /* Connect the cancel_button to destroy the widget */
459 gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION
460 (file_sel)->cancel_button), "clicked", (GtkSignalFunc)
461 gtk_widget_destroy, GTK_OBJECT (file_sel));
463 gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), "");
464 gtk_widget_show(file_sel);
468 file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
472 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
473 gtk_widget_hide(GTK_WIDGET (fs));
474 gtk_widget_destroy(GTK_WIDGET (fs));
476 if (!file_mv(cf.save_file, cf_name))
478 g_free(cf.save_file);
479 cf.save_file = g_strdup(cf_name);
481 err = load_cap_file(cf_name, &cf);
483 simple_dialog(ESD_TYPE_WARN, NULL,
484 file_open_error_message(err, FALSE), cf_name);
487 set_menu_sensitivity("/File/Save", FALSE);
488 set_menu_sensitivity("/File/Save As...", TRUE);
492 file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) {
496 cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)));
497 gtk_widget_hide(GTK_WIDGET (fs));
498 gtk_widget_destroy(GTK_WIDGET (fs));
500 if (!file_cp(cf.save_file, cf_name))
502 g_free(cf.save_file);
503 cf.save_file = g_strdup(cf_name);
505 err = load_cap_file(cf_name, &cf);
507 simple_dialog(ESD_TYPE_WARN, NULL,
508 file_open_error_message(err, FALSE), cf_name);
511 set_menu_sensitivity("/File/Save", FALSE);
512 set_menu_sensitivity("/File/Save As...", TRUE);
515 /* Reload a file using the current display filter */
517 file_reload_cmd_cb(GtkWidget *w, gpointer data) {
518 /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/
519 GtkWidget *filter_te;
522 filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
524 if (cf.dfilter) g_free(cf.dfilter);
525 cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te)));
526 err = load_cap_file(cf.filename, &cf);
528 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
533 /* Run the current display filter on the current packet set, and
536 filter_activate_cb(GtkWidget *w, gpointer data) {
537 if (cf.dfilter) g_free(cf.dfilter);
538 cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(w)));
544 file_print_cmd_cb(GtkWidget *widget, gpointer data) {
545 print_tree(cf.pd, fd, GTK_TREE(tree_view));
548 /* What to do when a list item is selected/unselected */
550 packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
561 gtk_text_freeze(GTK_TEXT(byte_view));
562 gtk_text_set_point(GTK_TEXT(byte_view), 0);
563 gtk_text_forward_delete(GTK_TEXT(byte_view),
564 gtk_text_get_length(GTK_TEXT(byte_view)));
566 /* get the frame data struct pointer for this frame */
567 fd = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(w), row);
568 fseek(cf.fh, fd->file_off, SEEK_SET);
569 fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh);
571 /* create the logical protocol tree */
573 proto_tree_free(protocol_tree);
574 protocol_tree = proto_tree_create_root();
575 dissect_packet(cf.pd, fd, protocol_tree);
577 /* display the GUI protocol tree and hex dump */
578 proto_tree_draw(protocol_tree, tree_view);
579 packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1);
580 gtk_text_thaw(GTK_TEXT(byte_view));
584 packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
585 gtk_text_freeze(GTK_TEXT(byte_view));
586 gtk_text_set_point(GTK_TEXT(byte_view), 0);
587 gtk_text_forward_delete(GTK_TEXT(byte_view),
588 gtk_text_get_length(GTK_TEXT(byte_view)));
589 gtk_text_thaw(GTK_TEXT(byte_view));
590 gtk_tree_clear_items(GTK_TREE(tree_view), 0,
591 g_list_length(GTK_TREE(tree_view)->children));
595 tree_view_cb(GtkWidget *w) {
597 tree_selected_start = -1;
598 tree_selected_len = -1;
600 if (GTK_TREE(w)->selection) {
601 tree_selected_start =
602 (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
603 E_TREEINFO_START_KEY);
605 (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
609 gtk_text_freeze(GTK_TEXT(byte_view));
610 gtk_text_set_point(GTK_TEXT(byte_view), 0);
611 gtk_text_forward_delete(GTK_TEXT(byte_view),
612 gtk_text_get_length(GTK_TEXT(byte_view)));
613 packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len,
617 gtk_text_thaw(GTK_TEXT(byte_view));
621 file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
622 if (cf.save_file && !cf.user_saved) {
623 unlink(cf.save_file);
628 void blank_packetinfo() {
636 /* Things to do when the main window is realized */
638 main_realize_cb(GtkWidget *w, gpointer data) {
649 sigusr2_handler(int sig) {
650 sigusr2_received = 1;
651 signal(SIGUSR2, sigusr2_handler);
655 /* call initialization routines at program startup time */
657 ethereal_proto_init(void) {
666 fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
667 VERSION, comp_info_str);
668 fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n",
670 fprintf(stderr, " [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n");
671 fprintf(stderr, " [-P packet list height] [-r infile] [-s snaplen]\n");
672 fprintf(stderr, " [-t <time stamp format>] [-T tree view height] [-w savefile] \n");
675 /* And now our feature presentation... [ fade to music ] */
677 main(int argc, char *argv[])
685 int pf_open_errno = 0;
687 GtkWidget *window, *main_vbox, *menubar, *u_pane, *l_pane,
688 *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox,
689 *tv_scrollw, *filter_bt, *filter_te;
690 GtkAccelGroup *accel;
691 GtkWidget *packet_sw;
692 gint pl_size = 280, tv_size = 95, bv_size = 75;
693 gchar *rc_file, *cf_name = NULL;
697 ethereal_path = argv[0];
699 /* Let GTK get its args */
700 gtk_init (&argc, &argv);
703 prefs = read_prefs(&pf_path);
704 if (pf_path != NULL) {
705 /* The preferences file exists, but couldn't be opened; "pf_path" is
706 its pathname. Remember "errno", as that says why the attempt
708 pf_open_errno = errno;
711 /* Initialize the capture file struct */
723 cf.snap = MAX_PACKET_SIZE;
725 cf.cinfo.num_cols = prefs->num_cols;
726 cf.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
727 cf.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cf.cinfo.num_cols);
728 cf.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cf.cinfo.num_cols);
729 cf.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
731 /* Assemble the compile-time options */
732 snprintf(comp_info_str, 256,
733 #ifdef GTK_MAJOR_VERSION
734 "GTK+ %d.%d.%d, %s libpcap", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
737 "GTK+ (version unknown), %s libpcap",
748 /* Now get our args */
749 while ((opt = getopt(argc, argv, "b:B:c:f:Fhi:km:nP:Qr:Ss:t:T:w:v")) != EOF) {
751 case 'b': /* Bold font */
752 bold_font = g_strdup(optarg);
754 case 'B': /* Byte view pane height */
755 bv_size = atoi(optarg);
757 case 'c': /* Capture xxx packets */
758 cf.count = atoi(optarg);
762 cf.cfilter = g_strdup(optarg);
764 case 'F': /* Fork to capture */
768 case 'h': /* Print help and exit */
772 case 'i': /* Use interface xxx */
773 cf.iface = g_strdup(optarg);
775 case 'm': /* Medium font */
776 medium_font = g_strdup(optarg);
778 case 'n': /* No name resolution */
779 g_resolving_actif = 0;
782 case 'k': /* Start capture immediately */
786 case 'P': /* Packet list pane height */
787 pl_size = atoi(optarg);
790 case 'Q': /* Quit after capture (just capture to file) */
792 start_capture = 1; /*** -Q implies -k !! ***/
795 case 'r': /* Read capture file xxx */
796 cf_name = g_strdup(optarg);
799 case 's': /* Set the snapshot (capture) length */
800 cf.snap = atoi(optarg);
802 case 'S': /* "Sync" mode: used for following file ala tail -f */
804 fork_mode = 1; /* -S implies -F */
807 case 't': /* Time stamp type */
808 if (strcmp(optarg, "r") == 0)
809 timestamp_type = RELATIVE;
810 else if (strcmp(optarg, "a") == 0)
811 timestamp_type = ABSOLUTE;
812 else if (strcmp(optarg, "d") == 0)
813 timestamp_type = DELTA;
815 fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
817 fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
818 fprintf(stderr, "or \"d\" for delta.\n");
822 case 'T': /* Tree view pane height */
823 tv_size = atoi(optarg);
825 case 'v': /* Show version and exit */
826 printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
830 case 'w': /* Write capture file xxx */
831 cf.save_file = g_strdup(optarg);
839 if (cf.iface == NULL) {
840 fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
843 if (cf.save_file == NULL) {
844 fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-w\" flag\n");
851 signal(SIGUSR2, sigusr2_handler);
854 /* Build the column format array */
855 col_fmt = (gint *) g_malloc(sizeof(gint) * cf.cinfo.num_cols);
857 for (i = 0; i < cf.cinfo.num_cols; i++) {
858 col_fmt[i] = get_column_format(i);
859 cf.cinfo.col_title[i] = g_strdup(get_column_title(i));
860 cf.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
862 get_column_format_matches(cf.cinfo.fmt_matx[i], col_fmt[i]);
863 cf.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
864 cf.cinfo.col_width[i] = 0;
868 cf.snap = MAX_PACKET_SIZE;
869 else if (cf.snap < MIN_PACKET_SIZE)
870 cf.snap = MIN_PACKET_SIZE;
872 rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4);
873 sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE);
874 gtk_rc_parse(rc_file);
876 if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
877 fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
881 if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
882 fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
887 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
888 gtk_widget_set_name(window, "main window");
889 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
890 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
891 gtk_signal_connect(GTK_OBJECT(window), "destroy",
892 GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
893 gtk_signal_connect(GTK_OBJECT (window), "realize",
894 GTK_SIGNAL_FUNC(main_realize_cb), NULL);
895 gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
896 gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
897 gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
899 /* Container for menu bar, paned windows and progress/info box */
900 main_vbox = gtk_vbox_new(FALSE, 1);
901 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
902 gtk_container_add(GTK_CONTAINER(window), main_vbox);
903 gtk_widget_show(main_vbox);
906 get_main_menu(&menubar, &accel);
907 gtk_window_add_accel_group(GTK_WINDOW(window), accel);
908 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
909 gtk_widget_show(menubar);
911 /* Panes for the packet list, tree, and byte view */
912 u_pane = gtk_vpaned_new();
913 gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
914 l_pane = gtk_vpaned_new();
915 gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
916 gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
917 gtk_widget_show(u_pane);
918 gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
919 gtk_widget_show(l_pane);
922 packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols,
924 gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
925 packet_sw = gtk_scrolled_window_new(NULL, NULL);
926 gtk_widget_show(packet_sw);
927 gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
928 pl_style = gtk_style_new();
929 gdk_font_unref(pl_style->font);
930 pl_style->font = m_r_font;
931 gtk_widget_set_style(packet_list, pl_style);
932 gtk_widget_set_name(packet_list, "packet list");
933 gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
934 GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
935 gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
936 GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
937 for (i = 0; i < cf.cinfo.num_cols; i++) {
938 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
939 gdk_string_width(pl_style->font, cf.cinfo.col_title[i]));
940 if (col_fmt[i] == COL_NUMBER)
941 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
944 gtk_widget_set_usize(packet_list, -1, pl_size);
945 gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
946 gtk_widget_show(packet_list);
949 tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
950 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
951 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
952 gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
953 gtk_widget_set_usize(tv_scrollw, -1, tv_size);
954 gtk_widget_show(tv_scrollw);
956 tree_view = gtk_tree_new();
957 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
959 gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
960 gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
961 gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE);
962 gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
963 GTK_SIGNAL_FUNC(tree_view_cb), NULL);
964 gtk_widget_show(tree_view);
966 item_style = gtk_style_new();
967 gdk_font_unref(item_style->font);
968 item_style->font = m_r_font;
971 bv_table = gtk_table_new (2, 2, FALSE);
972 gtk_paned_add2(GTK_PANED(l_pane), bv_table);
973 gtk_widget_set_usize(bv_table, -1, bv_size);
974 gtk_widget_show(bv_table);
976 byte_view = gtk_text_new(NULL, NULL);
977 gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
978 gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
979 gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
980 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
981 gtk_widget_show(byte_view);
983 bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
984 gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
985 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
986 gtk_widget_show (bv_hscroll);
988 bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
989 gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
990 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
991 gtk_widget_show(bv_vscroll);
993 /* Progress/filter/info box */
994 stat_hbox = gtk_hbox_new(FALSE, 1);
995 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
996 gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
997 gtk_widget_show(stat_hbox);
999 prog_bar = gtk_progress_bar_new();
1000 gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
1001 gtk_widget_show(prog_bar);
1003 filter_bt = gtk_button_new_with_label("Filter:");
1004 gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
1005 GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
1006 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
1007 gtk_widget_show(filter_bt);
1009 filter_te = gtk_entry_new();
1010 gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
1011 gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
1012 gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
1013 GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
1014 gtk_widget_show(filter_te);
1016 set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
1017 set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
1018 set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
1020 info_bar = gtk_statusbar_new();
1021 main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
1022 file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
1023 gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
1024 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1025 gtk_widget_show(info_bar);
1028 Hmmm should we do it here
1031 ethereal_proto_init(); /* Init anything that needs initializing */
1033 gtk_widget_show(window);
1035 /* If we were given the name of a capture file, read it in now;
1036 we defer it until now, so that, if we can't open it, and pop
1037 up an alert box, the alert box is more likely to cmoe up on
1038 top of the main window - but before the preference-file-error
1039 alert box, so, if we get one of those, it's more likely to come
1042 err = load_cap_file(cf_name, &cf);
1044 simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE),
1048 set_menu_sensitivity("/File/Save As...", TRUE);
1049 set_menu_sensitivity("/Tools/Summary", TRUE);
1052 /* If we failed to open the preferences file, pop up an alert box;
1053 we defer it until now, so that the alert box is more likely to
1054 come up on top of the main window. */
1055 if (pf_path != NULL) {
1056 simple_dialog(ESD_TYPE_WARN, NULL,
1057 "Can't open preferences file\n\"%s\": %s.", pf_path,
1058 strerror(pf_open_errno));