/* ethereal.c * * $Id: ethereal.c,v 1.64 1999/07/27 02:04:35 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Richard Sharpe, 13-Feb-1999, added support for initializing structures * needed by dissect routines * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * To do: * - Live browser/capture display * - Graphs * - Get AIX to work * - Check for end of packet in dissect_* routines. * - Playback window * - Multiple window support * - Add cut/copy/paste * - Create header parsing routines * - Check fopens, freads, fwrites * - Make byte view scrollbars automatic? * - Make byte view selections more fancy? * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #ifdef HAVE_DIRECT_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H # include # else # include # endif # include "snprintf.h" #endif #ifdef NEED_STRERROR_H #include "strerror.h" #endif #include "ethereal.h" #include "timestamp.h" #include "packet.h" #include "capture.h" #include "summary.h" #include "file.h" #include "menu.h" #include "etypes.h" #include "prefs.h" #include "column.h" #include "print.h" #include "resolv.h" #include "follow.h" #include "util.h" #include "gtkpacket.h" #include "dfilter.h" static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs); static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs); static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data); static void print_file_cb(GtkWidget *file_bt, gpointer file_te); static void print_fs_ok_cb(GtkWidget *w, gpointer data); static void print_fs_cancel_cb(GtkWidget *w, gpointer data); static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w); static void print_close_cb(GtkWidget *close_bt, gpointer parent_w); FILE *data_out_file = NULL; packet_info pi; capture_file cf; GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar, *info_bar; GdkFont *m_r_font, *m_b_font; guint main_ctx, file_ctx; gint start_capture = 0; gchar comp_info_str[256]; gchar *ethereal_path = NULL; gchar *medium_font = MONO_MEDIUM_FONT; gchar *bold_font = MONO_BOLD_FONT; ts_type timestamp_type = RELATIVE; GtkStyle *item_style; #ifdef HAVE_LIBPCAP int sync_mode; /* allow sync */ int sync_pipe[2]; /* used to sync father */ int fork_mode; /* fork a child to do the capture */ int sigusr2_received = 0; int quit_after_cap; /* Makes a "capture only mode". Implies -k */ #endif /* Specifies byte offsets for object selected in tree */ static gint tree_selected_start=-1, tree_selected_len=-1; #define E_DFILTER_TE_KEY "display_filter_te" /* About Ethereal window */ void about_ethereal( GtkWidget *w, gpointer data ) { simple_dialog(ESD_TYPE_INFO, NULL, "GNU Ethereal - network protocol analyzer\n" "Version %s (C) 1998 Gerald Combs \n" "Compiled with %s\n\n" "Contributors:\n" "Gilbert Ramirez \n" "Hannes R. Boehm \n" "Mike Hall \n" "Bobo Rajec \n" "Laurent Deniel \n" "Don Lafontaine \n" "Guy Harris \n" "Simon Wilkinson \n" "Joerg Mayer \n" "Martin Maciaszek \n" "Didier Jorand \n" "Jun-ichiro itojun Hagino \n" "Richard Sharpe \n" "John McDermott \n" "Jeff Jahr \n" "Brad Robel-Forrest \n" "Ashok Narayanan \n" "Aaron Hillegass \n" "Jason Lango \n" "Johan Feyaerts \n" "\nSee http://ethereal.zing.org for more information", VERSION, comp_info_str); } /* Things to do when the OK button is pressed */ void file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) { gchar *cf_name; int err; cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs))); gtk_widget_hide(GTK_WIDGET (fs)); gtk_widget_destroy(GTK_WIDGET (fs)); /* this depends upon load_cap_file removing the filename from * cf_name, leaving only the path to the directory. */ if ((err = load_cap_file(cf_name, &cf)) == 0) chdir(cf_name); else { simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE), cf_name); } g_free(cf_name); set_menu_sensitivity("/File/Save", FALSE); set_menu_sensitivity("/File/Save As...", TRUE); } /* Update the progress bar */ gint file_progress_cb(gpointer p) { gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), (gfloat) ftell(cf.fh) / (gfloat) cf.f_len); return TRUE; } /* Follow a TCP stream */ void follow_stream_cb( GtkWidget *w, gpointer data ) { char filename1[128]; GtkWidget *streamwindow, *box, *text, *vscrollbar, *table; GtkWidget *filter_te = NULL; int err; if (w) filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); if( pi.ipproto == 6 ) { /* we got tcp so we can follow */ /* check to see if we are using a filter */ if( cf.dfilter != NULL ) { /* get rid of this one */ g_free( cf.dfilter ); cf.dfilter = NULL; } /* create a new one and set the display filter entry accordingly */ cf.dfilter = build_follow_filter( &pi ); if (filter_te) gtk_entry_set_text(GTK_ENTRY(filter_te), cf.dfilter); /* reload so it goes in effect. Also we set data_out_file which tells the tcp code to output the data */ close_cap_file( &cf, info_bar, file_ctx); strcpy( filename1, tmpnam(NULL) ); data_out_file = fopen( filename1, "a" ); if( data_out_file == NULL ) { fprintf( stderr, "Could not open tmp file %s\n", filename1 ); } reset_tcp_reassembly(); err = load_cap_file( cf.filename, &cf ); if (err != 0) { simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE), cf.filename); } /* the data_out_file should now be full of the streams information */ fclose( data_out_file ); /* the filename1 file now has all the text that was in the session */ streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL); gtk_widget_set_name( streamwindow, "TCP stream window" ); gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event", NULL, "WM destroy" ); gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy", NULL, "WM destroy" ); if( incomplete_tcp_stream ) { gtk_window_set_title( GTK_WINDOW(streamwindow), "Contents of TCP stream (incomplete)" ); } else { gtk_window_set_title( GTK_WINDOW(streamwindow), "Contents of TCP stream" ); } gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT ); gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 ); /* setup the container */ box = gtk_vbox_new( FALSE, 0 ); gtk_container_add( GTK_CONTAINER(streamwindow), box ); gtk_widget_show( box ); /* set up the table we attach to */ table = gtk_table_new( 1, 2, FALSE ); gtk_table_set_col_spacing( GTK_TABLE(table), 0, 2); gtk_box_pack_start( GTK_BOX(box), table, TRUE, TRUE, 0 ); gtk_widget_show( table ); /* create a text box */ text = gtk_text_new( NULL, NULL ); gtk_text_set_editable( GTK_TEXT(text), FALSE); gtk_table_attach( GTK_TABLE(table), text, 0, 1, 0, 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 ); gtk_widget_show(text); /* create the scrollbar */ vscrollbar = gtk_vscrollbar_new( GTK_TEXT(text)->vadj ); gtk_table_attach( GTK_TABLE(table), vscrollbar, 1, 2, 0, 1, GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0 ); gtk_widget_show( vscrollbar ); gtk_widget_realize( text ); /* stop the updates while we fill the text box */ gtk_text_freeze( GTK_TEXT(text) ); data_out_file = NULL; data_out_file = fopen( filename1, "r" ); if( data_out_file ) { char buffer[1024]; int nchars; while( 1 ) { nchars = fread( buffer, 1, 1024, data_out_file ); gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars ); if( nchars < 1024 ) { break; } } fclose( data_out_file ); unlink( filename1 ); } gtk_text_thaw( GTK_TEXT(text) ); data_out_file = NULL; gtk_widget_show( streamwindow ); if( cf.dfilter != NULL ) { g_free( cf.dfilter ); cf.dfilter = NULL; } } else { simple_dialog(ESD_TYPE_WARN, NULL, "Error following stream. Please make\n" "sure you have a TCP packet selected."); } } /* Match selected byte pattern */ void match_selected_cb(GtkWidget *w, gpointer data) { #if 0 char *buf = malloc(1024); #endif GtkWidget *filter_te = NULL; if (w) filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); if (tree_selected_start<0) { simple_dialog(ESD_TYPE_WARN, NULL, "Error determining selected bytes. Please make\n" "sure you have selected a field within the tree\n" "view to be matched."); return; } #if 0 switch (cf.lnk_t) { case DLT_EN10MB : c="ether"; break; case DLT_FDDI : c="fddi"; break; default : #endif simple_dialog(ESD_TYPE_WARN, NULL, "Unsupported frame type format. Only Ethernet and FDDI\n" "frame formats are supported."); return; #if 0 } sprintf(buf, "("); ptr = buf+strlen(buf); for (i=0, c=cf.pd+tree_selected_start; i+4ok_button), "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel ); /* Gilbert --- I added this if statement. Is this right? */ if (w) gtk_object_set_data(GTK_OBJECT(GTK_FILE_SELECTION(file_sel)->ok_button), E_DFILTER_TE_KEY, gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY)); /* Connect the cancel_button to destroy the widget */ gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (file_sel)); #ifdef HAVE_LIBPCAP if( fork_mode && (cf.save_file != NULL) ) #else if( cf.save_file != NULL ) #endif gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), cf.save_file); else gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), ""); gtk_widget_show(file_sel); } /* Close a file */ void file_close_cmd_cb(GtkWidget *widget, gpointer data) { close_cap_file(&cf, info_bar, file_ctx); } void file_save_cmd_cb(GtkWidget *w, gpointer data) { file_sel = gtk_file_selection_new ("Ethereal: Save Capture File"); /* Connect the ok_button to file_ok_sel_cb function and pass along the pointer to the filter entry */ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", (GtkSignalFunc) file_save_ok_cb, file_sel ); /* Connect the cancel_button to destroy the widget */ gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (file_sel)); gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), ""); gtk_widget_show(file_sel); } void file_save_as_cmd_cb(GtkWidget *w, gpointer data) { file_sel = gtk_file_selection_new ("Ethereal: Save Capture File as"); /* Connect the ok_button to file_ok_sel_cb function and pass along the pointer to the filter entry */ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", (GtkSignalFunc) file_save_as_ok_cb, file_sel ); /* Connect the cancel_button to destroy the widget */ gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (file_sel)); gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), ""); gtk_widget_show(file_sel); } static void file_save_ok_cb(GtkWidget *w, GtkFileSelection *fs) { gchar *cf_name; int err; cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs))); gtk_widget_hide(GTK_WIDGET (fs)); gtk_widget_destroy(GTK_WIDGET (fs)); if (!file_mv(cf.save_file, cf_name)) return; g_free(cf.save_file); cf.save_file = g_strdup(cf_name); cf.user_saved = 1; err = load_cap_file(cf_name, &cf); if (err != 0) { simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE), cf_name); } set_menu_sensitivity("/File/Save", FALSE); set_menu_sensitivity("/File/Save As...", TRUE); } static void file_save_as_ok_cb(GtkWidget *w, GtkFileSelection *fs) { gchar *cf_name; int err; cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs))); gtk_widget_hide(GTK_WIDGET (fs)); gtk_widget_destroy(GTK_WIDGET (fs)); if (!file_cp(cf.save_file, cf_name)) return; g_free(cf.save_file); cf.save_file = g_strdup(cf_name); cf.user_saved = 1; err = load_cap_file(cf_name, &cf); if (err != 0) { simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE), cf_name); } set_menu_sensitivity("/File/Save", FALSE); set_menu_sensitivity("/File/Save As...", TRUE); } /* Reload a file using the current display filter */ void file_reload_cmd_cb(GtkWidget *w, gpointer data) { /*GtkWidget *filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);*/ GtkWidget *filter_te; int err; filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY); if (cf.dfilter) g_free(cf.dfilter); cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(filter_te))); err = load_cap_file(cf.filename, &cf); if (err != 0) { simple_dialog(ESD_TYPE_WARN, NULL, file_open_error_message(err, FALSE), cf.filename); } } /* Run the current display filter on the current packet set, and redisplay. */ static void filter_activate_cb(GtkWidget *w, gpointer data) { if (cf.dfilter) g_free(cf.dfilter); cf.dfilter = g_strdup(gtk_entry_get_text(GTK_ENTRY(w))); filter_packets(&cf); } /* * Remember whether we printed to a printer or a file the last time we * printed something. */ static int print_to_file; /* Keys for gtk_object_set_data */ #define PRINT_CMD_LB_KEY "printer_command_label" #define PRINT_CMD_TE_KEY "printer_command_entry" #define PRINT_FILE_BT_KEY "printer_file_button" #define PRINT_FILE_TE_KEY "printer_file_entry" #define PRINT_DEST_RB_KEY "printer_destination_radio_button" /* Print the capture */ void file_print_cmd_cb(GtkWidget *widget, gpointer data) { GtkWidget *print_w; GtkWidget *main_vb, *main_tb, *button; #if 0 GtkWidget *format_hb, *format_lb; GSList *format_grp; #endif GtkWidget *dest_rb; GtkWidget *dest_hb, *dest_lb; GtkWidget *cmd_lb, *cmd_te; GtkWidget *file_bt_hb, *file_bt, *file_te; GSList *dest_grp; GtkWidget *bbox, *ok_bt, *cancel_bt; /* XXX - don't pop up one if there's already one open; instead, give it the input focus if that's possible. */ print_w = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(print_w), "Ethereal: Print"); /* Enclosing containers for each row of widgets */ main_vb = gtk_vbox_new(FALSE, 5); gtk_container_border_width(GTK_CONTAINER(main_vb), 5); gtk_container_add(GTK_CONTAINER(print_w), main_vb); gtk_widget_show(main_vb); main_tb = gtk_table_new(4, 2, FALSE); gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0); gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10); gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15); gtk_widget_show(main_tb); /* XXX - printing multiple frames in PostScript looks as if it's tricky - you have to deal with page boundaries, I think - and I'll have to spend some time learning enough about PostScript to figure it out, so, for now, we only print multiple frames as text. */ #if 0 /* Output format */ format_lb = gtk_label_new("Format:"); gtk_misc_set_alignment(GTK_MISC(format_lb), 1.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(main_tb), format_lb, 0, 1, 0, 1); gtk_widget_show(format_lb); format_hb = gtk_hbox_new(FALSE, 0); gtk_table_attach_defaults(GTK_TABLE(main_tb), format_hb, 1, 2, 0, 1); gtk_widget_show(format_hb); button = gtk_radio_button_new_with_label(NULL, "Plain Text"); if (prefs.pr_format == PR_FMT_TEXT) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button)); gtk_box_pack_start(GTK_BOX(format_hb), button, FALSE, FALSE, 10); gtk_widget_show(button); button = gtk_radio_button_new_with_label(format_grp, "PostScript"); if (prefs.pr_format == PR_FMT_PS) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); gtk_box_pack_start(GTK_BOX(format_hb), button, FALSE, FALSE, 10); gtk_widget_show(button); #endif /* Output destination */ dest_lb = gtk_label_new("Print to:"); gtk_misc_set_alignment(GTK_MISC(dest_lb), 1.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(main_tb), dest_lb, 0, 1, 1, 2); gtk_widget_show(dest_lb); dest_hb = gtk_hbox_new(FALSE, 0); gtk_table_attach_defaults(GTK_TABLE(main_tb), dest_hb, 1, 2, 1, 2); gtk_widget_show(dest_hb); button = gtk_radio_button_new_with_label(NULL, "Command"); if (!print_to_file) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); dest_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button)); gtk_box_pack_start(GTK_BOX(dest_hb), button, FALSE, FALSE, 10); gtk_widget_show(button); dest_rb = gtk_radio_button_new_with_label(dest_grp, "File"); if (print_to_file) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(dest_rb), TRUE); gtk_signal_connect(GTK_OBJECT(dest_rb), "toggled", GTK_SIGNAL_FUNC(print_cmd_toggle_dest), NULL); gtk_box_pack_start(GTK_BOX(dest_hb), dest_rb, FALSE, FALSE, 10); gtk_widget_show(dest_rb); /* Command text entry */ cmd_lb = gtk_label_new("Command:"); gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_CMD_LB_KEY, cmd_lb); gtk_misc_set_alignment(GTK_MISC(cmd_lb), 1.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(main_tb), cmd_lb, 0, 1, 2, 3); gtk_widget_set_sensitive(cmd_lb, !print_to_file); gtk_widget_show(cmd_lb); cmd_te = gtk_entry_new(); gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_CMD_TE_KEY, cmd_te); if (prefs.pr_cmd) gtk_entry_set_text(GTK_ENTRY(cmd_te), prefs.pr_cmd); gtk_table_attach_defaults(GTK_TABLE(main_tb), cmd_te, 1, 2, 2, 3); gtk_widget_set_sensitive(cmd_te, !print_to_file); gtk_widget_show(cmd_te); /* File button and text entry */ file_bt_hb = gtk_hbox_new(FALSE, 0); gtk_table_attach_defaults(GTK_TABLE(main_tb), file_bt_hb, 0, 1, 3, 4); gtk_widget_show(file_bt_hb); file_bt = gtk_button_new_with_label("File:"); gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_FILE_BT_KEY, file_bt); gtk_box_pack_end(GTK_BOX(file_bt_hb), file_bt, FALSE, FALSE, 0); gtk_widget_set_sensitive(file_bt, print_to_file); gtk_widget_show(file_bt); file_te = gtk_entry_new(); gtk_object_set_data(GTK_OBJECT(dest_rb), PRINT_FILE_TE_KEY, file_te); gtk_table_attach_defaults(GTK_TABLE(main_tb), file_te, 1, 2, 3, 4); gtk_widget_set_sensitive(file_te, print_to_file); gtk_widget_show(file_te); gtk_signal_connect(GTK_OBJECT(file_bt), "clicked", GTK_SIGNAL_FUNC(print_file_cb), GTK_OBJECT(file_te)); /* Button row: OK and Cancel buttons */ bbox = gtk_hbutton_box_new(); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); gtk_container_add(GTK_CONTAINER(main_vb), bbox); gtk_widget_show(bbox); ok_bt = gtk_button_new_with_label ("OK"); gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_DEST_RB_KEY, dest_rb); gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_CMD_TE_KEY, cmd_te); gtk_object_set_data(GTK_OBJECT(ok_bt), PRINT_FILE_TE_KEY, file_te); gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", GTK_SIGNAL_FUNC(print_ok_cb), GTK_OBJECT(print_w)); GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0); gtk_widget_grab_default(ok_bt); gtk_widget_show(ok_bt); cancel_bt = gtk_button_new_with_label ("Cancel"); gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked", GTK_SIGNAL_FUNC(print_close_cb), GTK_OBJECT(print_w)); GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT); gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0); gtk_widget_show(cancel_bt); #if 0 display_opt_window_active = TRUE; #endif gtk_widget_show(print_w); } static void print_cmd_toggle_dest(GtkWidget *widget, gpointer data) { GtkWidget *cmd_lb, *cmd_te, *file_bt, *file_te; int to_file; cmd_lb = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), PRINT_CMD_LB_KEY)); cmd_te = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), PRINT_CMD_TE_KEY)); file_bt = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), PRINT_FILE_BT_KEY)); file_te = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(widget), PRINT_FILE_TE_KEY)); if (GTK_TOGGLE_BUTTON (widget)->active) { /* They selected "Print to File" */ to_file = TRUE; } else { /* They selected "Print to Command" */ to_file = FALSE; } gtk_widget_set_sensitive(cmd_lb, !to_file); gtk_widget_set_sensitive(cmd_te, !to_file); gtk_widget_set_sensitive(file_bt, to_file); gtk_widget_set_sensitive(file_te, to_file); } static void print_file_cb(GtkWidget *file_bt, gpointer file_te) { GtkWidget *fs; fs = gtk_file_selection_new ("Ethereal: Print to File"); gtk_object_set_data(GTK_OBJECT(fs), PRINT_FILE_TE_KEY, file_te); gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button), "clicked", (GtkSignalFunc) print_fs_ok_cb, fs); /* Connect the cancel_button to destroy the widget */ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button), "clicked", (GtkSignalFunc) print_fs_cancel_cb, fs); gtk_widget_show(fs); } static void print_fs_ok_cb(GtkWidget *w, gpointer data) { gtk_entry_set_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(data), PRINT_FILE_TE_KEY)), gtk_file_selection_get_filename (GTK_FILE_SELECTION(data))); gtk_widget_destroy(GTK_WIDGET(data)); } static void print_fs_cancel_cb(GtkWidget *w, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } static void print_ok_cb(GtkWidget *ok_bt, gpointer parent_w) { GtkWidget *button; char *dest; button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(ok_bt), PRINT_DEST_RB_KEY); if (GTK_TOGGLE_BUTTON (button)->active) print_to_file = TRUE; else print_to_file = FALSE; if (print_to_file) dest = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(ok_bt), PRINT_FILE_TE_KEY)))); else dest = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(ok_bt), PRINT_CMD_TE_KEY)))); gtk_widget_destroy(GTK_WIDGET(parent_w)); #if 0 display_opt_window_active = FALSE; #endif /* Now print the packets */ if (!print_packets(&cf, print_to_file, dest)) { if (print_to_file) simple_dialog(ESD_TYPE_WARN, NULL, file_write_error_message(errno), dest); else simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't run print command %s.", prefs.pr_cmd); } g_free(dest); } static void print_close_cb(GtkWidget *close_bt, gpointer parent_w) { gtk_grab_remove(GTK_WIDGET(parent_w)); gtk_widget_destroy(GTK_WIDGET(parent_w)); #if 0 display_opt_window_active = FALSE; #endif } /* Print a packet */ void file_print_packet_cmd_cb(GtkWidget *widget, gpointer data) { FILE *fh; switch (prefs.pr_dest) { case PR_DEST_CMD: fh = popen(prefs.pr_cmd, "w"); break; case PR_DEST_FILE: fh = fopen(prefs.pr_file, "w"); break; default: fh = NULL; /* XXX - "can't happen" */ break; } if (fh == NULL) { switch (prefs.pr_dest) { case PR_DEST_CMD: simple_dialog(ESD_TYPE_WARN, NULL, "Couldn't run print command %s.", prefs.pr_cmd); break; case PR_DEST_FILE: simple_dialog(ESD_TYPE_WARN, NULL, file_write_error_message(errno), prefs.pr_file); break; } return; } print_preamble(fh); proto_tree_print(-1, (GNode*) cf.protocol_tree, cf.pd, cf.fd, fh); print_finale(fh); close_print_dest(prefs.pr_dest == PR_DEST_FILE, fh); } /* What to do when a list item is selected/unselected */ void packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) { #ifdef HAVE_LIBPCAP if (!sync_mode) { #endif if (cf.wth) return; #ifdef HAVE_LIBPCAP } #endif blank_packetinfo(); select_packet(&cf, row); } void packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) { unselect_packet(&cf); } void tree_view_cb(GtkWidget *w) { tree_selected_start = -1; tree_selected_len = -1; if (GTK_TREE(w)->selection) { tree_selected_start = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data), E_TREEINFO_START_KEY); tree_selected_len = (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data), E_TREEINFO_LEN_KEY); } gtk_text_freeze(GTK_TEXT(byte_view)); gtk_text_set_point(GTK_TEXT(byte_view), 0); gtk_text_forward_delete(GTK_TEXT(byte_view), gtk_text_get_length(GTK_TEXT(byte_view))); packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.fd->cap_len, tree_selected_start, tree_selected_len); gtk_text_thaw(GTK_TEXT(byte_view)); } void file_quit_cmd_cb (GtkWidget *widget, gpointer data) { if (cf.save_file && !cf.user_saved) { unlink(cf.save_file); } gtk_exit(0); } void blank_packetinfo() { pi.srcip = 0; pi.destip = 0; pi.ipproto = 0; pi.srcport = 0; pi.destport = 0; } /* Things to do when the main window is realized */ void main_realize_cb(GtkWidget *w, gpointer data) { #ifdef HAVE_LIBPCAP if (start_capture) { capture(); start_capture = 0; } #endif } #ifdef HAVE_LIBPCAP static void sigusr2_handler(int sig) { sigusr2_received = 1; signal(SIGUSR2, sigusr2_handler); } #endif /* call initialization routines at program startup time */ static void ethereal_proto_init(void) { proto_init(); init_dissect_udp(); dfilter_init(); } static void print_usage(void) { fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE, VERSION, comp_info_str); fprintf(stderr, "%s [-vh] [-FkQS] [-b bold font] [-B byte view height] [-c count]\n", PACKAGE); fprintf(stderr, " [-f \"filter expression\"] [-i interface] [-m medium font] [-n]\n"); fprintf(stderr, " [-P packet list height] [-r infile] [-s snaplen]\n"); fprintf(stderr, " [-t