1999-09-11 12:38:18 +00:00
|
|
|
/* main.c
|
1998-09-16 03:22:19 +00:00
|
|
|
*
|
2000-06-27 04:40:15 +00:00
|
|
|
* $Id: main.c,v 1.124 2000/06/27 04:40:15 guy Exp $
|
1998-09-16 02:39:15 +00:00
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@zing.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
1999-02-19 05:28:38 +00:00
|
|
|
* Richard Sharpe, 13-Feb-1999, added support for initializing structures
|
|
|
|
* needed by dissect routines
|
1998-09-16 02:39:15 +00:00
|
|
|
*
|
|
|
|
* 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:
|
|
|
|
* - Graphs
|
|
|
|
* - Check for end of packet in dissect_* routines.
|
|
|
|
* - Playback window
|
|
|
|
* - Multiple window support
|
|
|
|
* - Add cut/copy/paste
|
|
|
|
* - Create header parsing routines
|
|
|
|
* - Make byte view selections more fancy?
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
1998-12-17 05:42:33 +00:00
|
|
|
#include <stdlib.h>
|
1998-09-16 02:39:15 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
1999-07-13 02:53:26 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
1998-09-16 02:39:15 +00:00
|
|
|
#include <unistd.h>
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
|
|
|
|
1999-06-12 07:04:35 +00:00
|
|
|
#include <errno.h>
|
1998-09-16 02:39:15 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
1999-07-13 02:53:26 +00:00
|
|
|
|
2000-01-15 00:23:13 +00:00
|
|
|
#ifdef HAVE_IO_H
|
|
|
|
#include <io.h> /* open/close on win32 */
|
|
|
|
#endif
|
|
|
|
|
1999-07-13 02:53:26 +00:00
|
|
|
#ifdef HAVE_DIRECT_H
|
|
|
|
#include <direct.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
1998-09-16 02:39:15 +00:00
|
|
|
#include <netinet/in.h>
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
|
|
|
|
1999-05-11 18:51:10 +00:00
|
|
|
#include <signal.h>
|
1998-09-16 02:39:15 +00:00
|
|
|
|
1999-01-04 07:39:14 +00:00
|
|
|
#ifdef NEED_SNPRINTF_H
|
|
|
|
# ifdef HAVE_STDARG_H
|
|
|
|
# include <stdarg.h>
|
|
|
|
# else
|
|
|
|
# include <varargs.h>
|
|
|
|
# endif
|
|
|
|
# include "snprintf.h"
|
|
|
|
#endif
|
|
|
|
|
1999-11-29 04:31:05 +00:00
|
|
|
#if defined(HAVE_UCD_SNMP_SNMP_H)
|
1999-11-29 03:07:19 +00:00
|
|
|
#ifdef HAVE_UCD_SNMP_VERSION_H
|
|
|
|
#include <ucd-snmp/version.h>
|
1999-11-29 04:31:05 +00:00
|
|
|
#endif /* HAVE_UCD_SNMP_VERSION_H */
|
|
|
|
#elif defined(HAVE_SNMP_SNMP_H)
|
|
|
|
#ifdef HAVE_SNMP_VERSION_H
|
|
|
|
#include <snmp/version.h>
|
|
|
|
#endif /* HAVE_SNMP_VERSION_H */
|
|
|
|
#endif /* SNMP */
|
1999-11-29 03:07:19 +00:00
|
|
|
|
1999-06-14 21:46:36 +00:00
|
|
|
#ifdef NEED_STRERROR_H
|
|
|
|
#include "strerror.h"
|
|
|
|
#endif
|
|
|
|
|
2000-03-28 20:20:11 +00:00
|
|
|
#ifdef NEED_GETOPT_H
|
|
|
|
#include "getopt.h"
|
|
|
|
#endif
|
|
|
|
|
1999-09-09 02:42:40 +00:00
|
|
|
#include "main.h"
|
1999-06-19 01:14:51 +00:00
|
|
|
#include "timestamp.h"
|
1998-09-16 02:39:15 +00:00
|
|
|
#include "packet.h"
|
1999-02-09 00:35:38 +00:00
|
|
|
#include "capture.h"
|
1999-06-22 22:02:39 +00:00
|
|
|
#include "summary.h"
|
1998-09-16 02:39:15 +00:00
|
|
|
#include "file.h"
|
1999-09-09 02:42:40 +00:00
|
|
|
#include "menu.h"
|
2000-01-25 17:32:52 +00:00
|
|
|
#include "../menu.h"
|
2000-02-12 06:46:54 +00:00
|
|
|
#include "filter_prefs.h"
|
1999-09-09 03:32:03 +00:00
|
|
|
#include "prefs_dlg.h"
|
1998-11-17 04:29:13 +00:00
|
|
|
#include "column.h"
|
1998-09-16 02:39:15 +00:00
|
|
|
#include "print.h"
|
|
|
|
#include "resolv.h"
|
1998-09-17 03:12:28 +00:00
|
|
|
#include "follow.h"
|
|
|
|
#include "util.h"
|
2000-01-03 06:59:25 +00:00
|
|
|
#include "simple_dialog.h"
|
1999-09-09 02:42:40 +00:00
|
|
|
#include "proto_draw.h"
|
1999-07-07 22:52:57 +00:00
|
|
|
#include "dfilter.h"
|
1999-09-09 02:42:40 +00:00
|
|
|
#include "keys.h"
|
2000-02-29 06:24:41 +00:00
|
|
|
#include "packet_win.h"
|
1999-12-16 06:20:18 +00:00
|
|
|
#include "gtkglobals.h"
|
2000-01-04 20:37:18 +00:00
|
|
|
#include "plugins.h"
|
1999-04-06 16:24:50 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
FILE *data_out_file = NULL;
|
|
|
|
packet_info pi;
|
2000-06-27 04:36:03 +00:00
|
|
|
capture_file cfile;
|
Split "filter_dialog_cb()" into "filter_dialog_cb()", which pops up a
"global" dialog box when "Edit:Filters" is selected, so that the list of
filters can be edited, and "filter_browse_cb()", which pops up a dialog
box associated with a "Filter:" button and a text entry widget attached
to that button, so that a filter can be selected or saved (although it
also supports the same editing that the "global" dialog box does).
Have "filter_dialog_cb()" connect the window in which the "Filter:"
button lives and the filter dialog box, so that:
if the window in which the "Filter:" button lives goes away, so
does the filter dialog box (as it no longer has a text widget
into which it can stuff the selected filter);
if the "Filter:" button is clicked when there's already a filter
dialog box open, we just reactivate that existing dialog box
rather than popping up a new one.
Also keep a pointer to the "global" filter dialog box, so that we also
arrange that there's only one of them (by reactivating the existing on
if "Edit:Filters" is selected when there's already a "global" filter
dialog box open).
Keep around pointers to the dialog boxes that contain the "Filter:"
buttons, so that we can arrange that there be only one of them (that was
a side-effect of an earlier attempt at fixing the problems described
above, but it's still useful for keeping multiple competing dialog boxes
from being open - there's more of that to be done).
Make the pointer to the "Open Capture File" dialog box widget static to
"file_dlg.c" - nobody outside of "file_dlg.c cares about it.
svn path=/trunk/; revision=1774
2000-04-01 12:03:42 +00:00
|
|
|
GtkWidget *top_level, *packet_list, *tree_view, *byte_view,
|
2000-01-15 12:54:24 +00:00
|
|
|
*prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
|
2000-03-02 07:05:57 +00:00
|
|
|
static GtkWidget *bv_scrollw;
|
1998-09-16 02:39:15 +00:00
|
|
|
GdkFont *m_r_font, *m_b_font;
|
|
|
|
guint main_ctx, file_ctx;
|
1998-12-27 20:47:53 +00:00
|
|
|
gchar comp_info_str[256];
|
1999-05-11 18:51:10 +00:00
|
|
|
gchar *ethereal_path = NULL;
|
|
|
|
gchar *medium_font = MONO_MEDIUM_FONT;
|
|
|
|
gchar *bold_font = MONO_BOLD_FONT;
|
1999-08-14 19:53:31 +00:00
|
|
|
gchar *last_open_dir = NULL;
|
1998-09-16 02:39:15 +00:00
|
|
|
|
1998-09-27 22:12:47 +00:00
|
|
|
ts_type timestamp_type = RELATIVE;
|
|
|
|
|
1998-12-29 04:05:38 +00:00
|
|
|
GtkStyle *item_style;
|
|
|
|
|
1999-11-19 22:32:00 +00:00
|
|
|
/* Specifies the field currently selected in the GUI protocol tree */
|
|
|
|
field_info *finfo_selected = NULL;
|
1999-06-24 16:25:59 +00:00
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
static void follow_destroy_cb(GtkWidget *win, gpointer data);
|
|
|
|
static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
|
2000-01-12 22:07:56 +00:00
|
|
|
static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
|
1999-10-30 06:42:10 +00:00
|
|
|
static void follow_print_stream(GtkWidget *w, gpointer parent_w);
|
1999-11-19 22:32:00 +00:00
|
|
|
static char* hfinfo_numeric_format(header_field_info *hfinfo);
|
2000-01-15 12:54:24 +00:00
|
|
|
static void create_main_window(gint, gint, gint, e_prefs*);
|
1998-10-12 01:40:57 +00:00
|
|
|
|
1998-10-16 01:18:35 +00:00
|
|
|
/* About Ethereal window */
|
|
|
|
void
|
|
|
|
about_ethereal( GtkWidget *w, gpointer data ) {
|
|
|
|
simple_dialog(ESD_TYPE_INFO, NULL,
|
1999-12-16 04:11:33 +00:00
|
|
|
"Ethereal - Network Protocol Analyzer\n"
|
2000-01-15 12:54:24 +00:00
|
|
|
"Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
|
1998-12-27 20:47:53 +00:00
|
|
|
"Compiled with %s\n\n"
|
1999-12-16 04:11:33 +00:00
|
|
|
|
|
|
|
"Check the man page for complete documentation and\n"
|
|
|
|
"for the list of contributors.\n"
|
|
|
|
|
|
|
|
"\nSee http://ethereal.zing.org/ for more information.",
|
2000-01-15 12:54:24 +00:00
|
|
|
comp_info_str);
|
1998-10-16 01:18:35 +00:00
|
|
|
}
|
|
|
|
|
1999-08-17 00:10:22 +00:00
|
|
|
/* Follow the TCP stream, if any, to which the last packet that we called
|
|
|
|
a dissection routine on belongs (this might be the most recently
|
|
|
|
selected packet, or it might be the last packet in the file). */
|
1998-09-17 03:12:28 +00:00
|
|
|
void
|
1998-10-12 01:40:57 +00:00
|
|
|
follow_stream_cb( GtkWidget *w, gpointer data ) {
|
1999-08-18 02:59:05 +00:00
|
|
|
char filename1[128+1];
|
2000-03-02 07:05:57 +00:00
|
|
|
GtkWidget *streamwindow, *box, *txt_scrollw, *text, *filter_te;
|
2000-01-12 22:07:56 +00:00
|
|
|
GtkWidget *hbox, *close_bt, *print_bt;
|
|
|
|
GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
|
1999-08-16 23:58:30 +00:00
|
|
|
int tmp_fd;
|
1999-10-11 06:39:26 +00:00
|
|
|
gchar *follow_filter;
|
1998-12-22 05:52:51 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
if( pi.ipproto == 6 ) {
|
|
|
|
/* we got tcp so we can follow */
|
1999-08-16 23:58:30 +00:00
|
|
|
/* Create a temporary file into which to dump the reassembled data
|
|
|
|
from the TCP stream, and set "data_out_file" to refer to it, so
|
1999-08-17 00:10:22 +00:00
|
|
|
that the TCP code will write to it.
|
|
|
|
|
|
|
|
XXX - it might be nicer to just have the TCP code directly
|
|
|
|
append stuff to the text widget for the TCP stream window,
|
|
|
|
if we can arrange that said window not pop up until we're
|
|
|
|
done. */
|
1999-08-18 02:59:05 +00:00
|
|
|
tmp_fd = create_tempfile( filename1, sizeof filename1, "follow");
|
1999-08-16 23:58:30 +00:00
|
|
|
if (tmp_fd == -1) {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Could not create temporary file %s: %s", filename1, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
2000-06-24 05:06:29 +00:00
|
|
|
data_out_file = fdopen( tmp_fd, "wb" );
|
1999-08-16 23:58:30 +00:00
|
|
|
if( data_out_file == NULL ) {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Could not create temporary file %s: %s", filename1, strerror(errno));
|
|
|
|
close(tmp_fd);
|
|
|
|
unlink(filename1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a new filter that matches all packets in the TCP stream,
|
|
|
|
and set the display filter entry accordingly */
|
1999-07-31 13:55:16 +00:00
|
|
|
reset_tcp_reassembly();
|
1999-10-11 06:39:26 +00:00
|
|
|
follow_filter = build_follow_filter( &pi );
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1999-11-26 05:23:40 +00:00
|
|
|
/* set the display filter entry accordingly */
|
|
|
|
filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(filter_te), follow_filter);
|
|
|
|
|
1999-08-16 23:58:30 +00:00
|
|
|
/* Run the display filter so it goes in effect. */
|
2000-06-27 04:36:03 +00:00
|
|
|
filter_packets(&cfile, follow_filter);
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
/* the data_out_file should now be full of the streams information */
|
|
|
|
fclose( data_out_file );
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
/* 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" );
|
1999-11-28 14:50:23 +00:00
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
|
|
|
|
GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
|
|
|
|
|
1999-03-23 20:25:50 +00:00
|
|
|
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" );
|
|
|
|
}
|
1998-09-17 03:12:28 +00:00
|
|
|
gtk_widget_set_usize( GTK_WIDGET(streamwindow), DEF_WIDTH, DEF_HEIGHT );
|
|
|
|
gtk_container_border_width( GTK_CONTAINER(streamwindow), 2 );
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
/* setup the container */
|
|
|
|
box = gtk_vbox_new( FALSE, 0 );
|
|
|
|
gtk_container_add( GTK_CONTAINER(streamwindow), box );
|
|
|
|
gtk_widget_show( box );
|
1999-08-20 19:43:10 +00:00
|
|
|
|
2000-03-02 07:05:57 +00:00
|
|
|
/* create a scrolled window for the text */
|
|
|
|
txt_scrollw = gtk_scrolled_window_new( NULL, NULL );
|
|
|
|
gtk_box_pack_start( GTK_BOX(box), txt_scrollw, TRUE, TRUE, 0 );
|
|
|
|
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(txt_scrollw),
|
|
|
|
GTK_POLICY_NEVER,
|
|
|
|
GTK_POLICY_ALWAYS );
|
|
|
|
set_scrollbar_placement_scrollw(txt_scrollw, prefs.gui_scrollbar_on_right);
|
|
|
|
remember_scrolled_window(txt_scrollw);
|
|
|
|
gtk_widget_show( txt_scrollw );
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
/* create a text box */
|
|
|
|
text = gtk_text_new( NULL, NULL );
|
|
|
|
gtk_text_set_editable( GTK_TEXT(text), FALSE);
|
2000-03-02 07:05:57 +00:00
|
|
|
gtk_container_add( GTK_CONTAINER(txt_scrollw), text );
|
1998-09-17 03:12:28 +00:00
|
|
|
gtk_widget_show(text);
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
/* Create hbox */
|
|
|
|
hbox = gtk_hbox_new( FALSE, 1 );
|
|
|
|
gtk_box_pack_end( GTK_BOX(box), hbox, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show(hbox);
|
|
|
|
|
|
|
|
#define E_FOLLOW_ASCII_KEY "follow_ascii_key"
|
2000-01-12 22:07:56 +00:00
|
|
|
#define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
|
|
|
|
#define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
|
1999-10-19 04:11:23 +00:00
|
|
|
|
|
|
|
/* Create Radio Buttons */
|
2000-01-12 22:07:56 +00:00
|
|
|
b_ascii = gtk_radio_button_new_with_label(NULL, "ASCII");
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ascii), TRUE);
|
|
|
|
gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, b_ascii);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), b_ascii, FALSE, FALSE, 0);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(b_ascii), "toggled",
|
1999-10-19 04:11:23 +00:00
|
|
|
GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
|
|
|
|
GTK_OBJECT(streamwindow));
|
2000-01-12 22:07:56 +00:00
|
|
|
gtk_widget_show(b_ascii);
|
1999-10-19 04:11:23 +00:00
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
b_ebcdic = gtk_radio_button_new_with_label(
|
|
|
|
gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
|
1999-10-19 04:11:23 +00:00
|
|
|
"EBCDIC");
|
2000-01-12 22:07:56 +00:00
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_ebcdic), FALSE);
|
|
|
|
gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_EBCDIC_KEY, b_ebcdic);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), b_ebcdic, FALSE, FALSE, 0);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(b_ebcdic), "toggled",
|
|
|
|
GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
|
|
|
|
GTK_OBJECT(streamwindow));
|
|
|
|
gtk_widget_show(b_ebcdic);
|
|
|
|
|
|
|
|
b_hexdump = gtk_radio_button_new_with_label(
|
|
|
|
gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
|
|
|
|
"Hex. Dump");
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b_hexdump), FALSE);
|
|
|
|
gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_HEXDUMP_KEY, b_hexdump);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), b_hexdump, FALSE, FALSE, 0);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(b_hexdump), "toggled",
|
|
|
|
GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
|
|
|
|
GTK_OBJECT(streamwindow));
|
|
|
|
gtk_widget_show(b_hexdump);
|
1999-10-19 04:11:23 +00:00
|
|
|
|
|
|
|
/* Create Close Button */
|
|
|
|
close_bt = gtk_button_new_with_label("Close");
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(close_bt), "clicked",
|
|
|
|
GTK_SIGNAL_FUNC(gtk_widget_destroy),
|
|
|
|
GTK_OBJECT(streamwindow));
|
|
|
|
gtk_box_pack_end( GTK_BOX(hbox), close_bt, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show( close_bt );
|
|
|
|
|
1999-10-30 06:42:10 +00:00
|
|
|
/* Create Print Button */
|
|
|
|
print_bt = gtk_button_new_with_label("Print");
|
|
|
|
gtk_signal_connect(GTK_OBJECT(print_bt), "clicked",
|
|
|
|
GTK_SIGNAL_FUNC(follow_print_stream),
|
|
|
|
GTK_OBJECT(streamwindow));
|
|
|
|
gtk_box_pack_end( GTK_BOX(hbox), print_bt, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show( print_bt );
|
1999-10-19 04:11:23 +00:00
|
|
|
|
|
|
|
/* Tuck away the filename and textbox into streamwindow */
|
|
|
|
#define E_FOLLOW_FILENAME_KEY "follow_filename_key"
|
|
|
|
#define E_FOLLOW_TEXT_KEY "follow_text_key"
|
|
|
|
|
|
|
|
gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_FILENAME_KEY,
|
|
|
|
g_strdup(filename1));
|
|
|
|
gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
|
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
follow_load_text(text, filename1, 0);
|
1999-10-19 04:11:23 +00:00
|
|
|
|
|
|
|
data_out_file = NULL;
|
Exit from Ethereal by making the main loop exit, so that any quit
routines we register get called.
Register the "follow TCP stream" windows with "gtk_quit_add_destroy()",
so that, when Ethereal exits, they all get destroyed; this means that
their destroy callbacks get called, which means that they get to delete
their temporary files, so that, if you exit Ethereal without manually
closing the "follow TCP stream" windows, the temporary files don't get
left around.
Exit from Ethereal's "main()" function by calling "gtk_exit()", rather
than "exit()", so that we do whatever cleanup GTK+ requires. (We used
to call "gtk_exit()" in the callback for the "File:Quit" menu item and
the "delete" callback for the main window, but we now just call
"gtk_main_quit()" so that we exit from the main loop.)
svn path=/trunk/; revision=1772
2000-04-01 10:23:01 +00:00
|
|
|
|
|
|
|
/* Make sure this widget gets destroyed if we quit the main loop,
|
|
|
|
so that if we exit, we clean up any temporary files we have
|
|
|
|
for "Follow TCP Stream" windows. */
|
|
|
|
gtk_quit_add_destroy(gtk_main_level(), GTK_OBJECT(streamwindow));
|
1999-10-19 04:11:23 +00:00
|
|
|
gtk_widget_show( streamwindow );
|
|
|
|
} else {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Error following stream. Please make\n"
|
|
|
|
"sure you have a TCP packet selected.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The destroy call back has the responsibility of
|
|
|
|
* unlinking the temporary file */
|
|
|
|
static void
|
|
|
|
follow_destroy_cb(GtkWidget *win, gpointer data)
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
|
|
|
|
filename = (char*) gtk_object_get_data(GTK_OBJECT(win),
|
|
|
|
E_FOLLOW_FILENAME_KEY);
|
|
|
|
g_assert(filename);
|
|
|
|
|
|
|
|
unlink(filename);
|
|
|
|
gtk_widget_destroy(win);
|
|
|
|
}
|
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
#define E_FOLLOW_ASCII_TYPE 0
|
|
|
|
#define E_FOLLOW_EBCDIC_TYPE 1
|
|
|
|
#define E_FOLLOW_HEXDUMP_TYPE 2
|
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
/* Handles the ASCII/EBCDIC toggling */
|
|
|
|
static void
|
|
|
|
follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
|
|
|
|
{
|
2000-01-12 22:07:56 +00:00
|
|
|
guint8 show_type = E_FOLLOW_ASCII_TYPE;
|
|
|
|
GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
|
1999-10-19 04:11:23 +00:00
|
|
|
char *filename;
|
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
b_ascii = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_ASCII_KEY);
|
|
|
|
b_ebcdic = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_EBCDIC_KEY);
|
|
|
|
b_hexdump = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_HEXDUMP_KEY);
|
1999-10-19 04:11:23 +00:00
|
|
|
text = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_TEXT_KEY);
|
|
|
|
filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_FILENAME_KEY);
|
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
g_assert(b_ascii);
|
|
|
|
g_assert(b_ebcdic);
|
|
|
|
g_assert(b_hexdump);
|
1999-10-19 04:11:23 +00:00
|
|
|
g_assert(text);
|
|
|
|
g_assert(filename);
|
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
if (GTK_TOGGLE_BUTTON(b_ebcdic)->active)
|
|
|
|
show_type = E_FOLLOW_EBCDIC_TYPE;
|
|
|
|
else if (GTK_TOGGLE_BUTTON(b_hexdump)->active)
|
|
|
|
show_type = E_FOLLOW_HEXDUMP_TYPE;
|
1999-10-19 04:11:23 +00:00
|
|
|
|
2000-01-12 22:07:56 +00:00
|
|
|
follow_load_text(text, filename, show_type);
|
1999-10-19 04:11:23 +00:00
|
|
|
}
|
|
|
|
|
2000-01-06 08:20:13 +00:00
|
|
|
#define FLT_BUF_SIZE 1024
|
|
|
|
static void
|
2000-01-12 22:07:56 +00:00
|
|
|
follow_read_stream(char *filename, guint8 show_type,
|
2000-01-06 08:20:13 +00:00
|
|
|
void (*print_line)(char *, int, gboolean, void *), void *arg)
|
|
|
|
{
|
|
|
|
tcp_stream_chunk sc;
|
|
|
|
int bcount;
|
|
|
|
guint32 client_addr = 0;
|
|
|
|
guint16 client_port = 0;
|
2000-01-12 22:07:56 +00:00
|
|
|
gboolean is_server;
|
|
|
|
guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
|
|
|
|
guint16 *global_pos;
|
2000-01-06 08:20:13 +00:00
|
|
|
|
2000-06-24 05:06:29 +00:00
|
|
|
data_out_file = fopen( filename, "rb" );
|
2000-01-06 08:20:13 +00:00
|
|
|
if( data_out_file ) {
|
|
|
|
char buffer[FLT_BUF_SIZE];
|
|
|
|
int nchars;
|
|
|
|
while(fread(&sc.src_addr, 1, sizeof(sc), data_out_file)) {
|
|
|
|
if (client_addr == 0) {
|
|
|
|
client_addr = sc.src_addr;
|
|
|
|
client_port = sc.src_port;
|
|
|
|
}
|
2000-01-12 22:07:56 +00:00
|
|
|
if (client_addr == sc.src_addr && client_port == sc.src_port) {
|
|
|
|
is_server = FALSE;
|
|
|
|
global_pos = &global_client_pos;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
is_server = TRUE;
|
|
|
|
global_pos = &global_server_pos;
|
|
|
|
}
|
2000-01-06 08:20:13 +00:00
|
|
|
|
|
|
|
while (sc.dlen > 0) {
|
|
|
|
bcount = (sc.dlen < FLT_BUF_SIZE) ? sc.dlen : FLT_BUF_SIZE;
|
|
|
|
nchars = fread( buffer, 1, bcount, data_out_file );
|
|
|
|
if (nchars == 0)
|
|
|
|
break;
|
|
|
|
sc.dlen -= bcount;
|
2000-01-12 22:07:56 +00:00
|
|
|
switch (show_type) {
|
|
|
|
case E_FOLLOW_EBCDIC_TYPE:
|
|
|
|
/* If our native arch is ASCII, call: */
|
|
|
|
EBCDIC_to_ASCII(buffer, nchars);
|
|
|
|
case E_FOLLOW_ASCII_TYPE:
|
2000-01-06 08:20:13 +00:00
|
|
|
/* If our native arch is EBCDIC, call:
|
|
|
|
* ASCII_TO_EBCDIC(buffer, nchars);
|
|
|
|
*/
|
2000-01-12 22:07:56 +00:00
|
|
|
(*print_line)( buffer, nchars, is_server, arg );
|
|
|
|
break;
|
|
|
|
case E_FOLLOW_HEXDUMP_TYPE:
|
|
|
|
current_pos = 0;
|
|
|
|
while (current_pos < nchars)
|
|
|
|
{
|
|
|
|
gchar hexbuf[256];
|
|
|
|
gchar hexchars[] = "0123456789abcdef";
|
|
|
|
int i, cur;
|
|
|
|
/* is_server indentation : put 63 spaces at the begenning
|
|
|
|
* of the string */
|
|
|
|
sprintf(hexbuf, is_server ?
|
|
|
|
" "
|
|
|
|
" %08X " :
|
|
|
|
"%08X ", *global_pos);
|
|
|
|
cur = strlen(hexbuf);
|
|
|
|
for (i=0; i < 16 && current_pos+i < nchars; i++) {
|
|
|
|
hexbuf[cur++] = hexchars[(buffer[current_pos+i] & 0xf0) >> 4];
|
|
|
|
hexbuf[cur++] = hexchars[buffer[current_pos+i] & 0x0f];
|
|
|
|
if (i == 7) {
|
|
|
|
hexbuf[cur++] = ' '; hexbuf[cur++] = ' ';
|
|
|
|
}
|
|
|
|
else if (i != 15)
|
|
|
|
hexbuf[cur++] = ' ';
|
|
|
|
}
|
|
|
|
current_pos += i;
|
|
|
|
(*global_pos) += i;
|
|
|
|
hexbuf[cur++] = '\n';
|
|
|
|
hexbuf[cur] = 0;
|
|
|
|
(*print_line)( hexbuf, strlen(hexbuf), is_server, arg );
|
|
|
|
}
|
|
|
|
break;
|
2000-01-06 08:20:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( ferror( data_out_file ) ) {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Error reading temporary file %s: %s", filename, strerror(errno));
|
|
|
|
}
|
|
|
|
fclose( data_out_file );
|
2000-01-29 13:30:08 +00:00
|
|
|
data_out_file = NULL;
|
2000-01-06 08:20:13 +00:00
|
|
|
} else {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Could not open temporary file %s: %s", filename, strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX - for text printing, we probably want to wrap lines at 80 characters;
|
|
|
|
* for PostScript printing, we probably want to wrap them at the appropriate
|
|
|
|
* width, and perhaps put some kind of dingbat (to use the technical term)
|
|
|
|
* to indicate a wrapped line, along the lines of what's done when displaying
|
|
|
|
* this in a window, as per Warren Young's suggestion.
|
|
|
|
*
|
|
|
|
* For now, we support only text printing.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
follow_print_text(char *buffer, int nchars, gboolean is_server, void *arg)
|
1999-10-30 06:42:10 +00:00
|
|
|
{
|
2000-01-06 08:20:13 +00:00
|
|
|
FILE *fh = arg;
|
|
|
|
|
|
|
|
fwrite(buffer, nchars, 1, fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
follow_print_stream(GtkWidget *w, gpointer parent_w)
|
|
|
|
{
|
|
|
|
FILE *fh;
|
|
|
|
gboolean to_file;
|
|
|
|
char* print_dest;
|
1999-10-30 06:42:10 +00:00
|
|
|
char* filename;
|
2000-01-12 22:07:56 +00:00
|
|
|
guint8 show_type = E_FOLLOW_ASCII_TYPE;
|
2000-01-06 08:20:13 +00:00
|
|
|
GtkWidget *button;
|
1999-10-30 06:42:10 +00:00
|
|
|
|
|
|
|
switch (prefs.pr_dest) {
|
|
|
|
case PR_DEST_CMD:
|
|
|
|
print_dest = prefs.pr_cmd;
|
|
|
|
to_file = FALSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PR_DEST_FILE:
|
|
|
|
print_dest = prefs.pr_file;
|
|
|
|
to_file = TRUE;
|
|
|
|
break;
|
2000-01-06 08:20:13 +00:00
|
|
|
default: /* "Can't happen" */
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Couldn't figure out where to send the print "
|
|
|
|
"job. Check your preferences.");
|
|
|
|
return;
|
1999-10-30 06:42:10 +00:00
|
|
|
}
|
|
|
|
|
2000-01-06 08:20:13 +00:00
|
|
|
fh = open_print_dest(to_file, print_dest);
|
1999-10-30 06:42:10 +00:00
|
|
|
if (fh == NULL) {
|
|
|
|
switch (to_file) {
|
|
|
|
case FALSE:
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Couldn't run print command %s.", prefs.pr_cmd);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TRUE:
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
file_write_error_message(errno),
|
|
|
|
prefs.pr_file);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-01-06 08:20:13 +00:00
|
|
|
button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
2000-01-12 22:07:56 +00:00
|
|
|
E_FOLLOW_EBCDIC_KEY);
|
|
|
|
if (GTK_TOGGLE_BUTTON(button)->active)
|
|
|
|
show_type = E_FOLLOW_EBCDIC_TYPE;
|
|
|
|
button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_HEXDUMP_KEY);
|
2000-01-06 08:20:13 +00:00
|
|
|
if (GTK_TOGGLE_BUTTON(button)->active)
|
2000-01-12 22:07:56 +00:00
|
|
|
show_type = E_FOLLOW_HEXDUMP_TYPE;
|
2000-01-06 08:20:13 +00:00
|
|
|
|
1999-10-30 06:42:10 +00:00
|
|
|
filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
|
|
|
|
E_FOLLOW_FILENAME_KEY);
|
|
|
|
|
|
|
|
if (filename != NULL) {
|
2000-01-06 07:33:35 +00:00
|
|
|
print_preamble(fh, PR_FMT_TEXT);
|
2000-01-12 22:07:56 +00:00
|
|
|
follow_read_stream(filename, show_type, follow_print_text, fh);
|
2000-01-06 07:33:35 +00:00
|
|
|
print_finale(fh, PR_FMT_TEXT);
|
1999-10-30 06:42:10 +00:00
|
|
|
close_print_dest(to_file, fh);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL, "Could not find data to print.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-06 08:20:13 +00:00
|
|
|
static void
|
|
|
|
follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
|
|
|
|
{
|
|
|
|
GtkWidget *text = arg;
|
|
|
|
|
|
|
|
if (is_server)
|
|
|
|
gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_server_fg,
|
|
|
|
&prefs.st_server_bg, buffer, nchars );
|
|
|
|
else
|
|
|
|
gtk_text_insert( GTK_TEXT(text), m_r_font, &prefs.st_client_fg,
|
|
|
|
&prefs.st_client_bg, buffer, nchars );
|
|
|
|
}
|
|
|
|
|
1999-10-19 04:11:23 +00:00
|
|
|
static void
|
2000-01-12 22:07:56 +00:00
|
|
|
follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
|
1999-10-19 04:11:23 +00:00
|
|
|
{
|
2000-01-06 08:20:13 +00:00
|
|
|
int bytes_already;
|
1999-12-02 04:30:15 +00:00
|
|
|
|
|
|
|
/* Delete any info already in text box */
|
|
|
|
bytes_already = gtk_text_get_length(GTK_TEXT(text));
|
|
|
|
if (bytes_already > 0) {
|
|
|
|
gtk_text_set_point(GTK_TEXT(text), 0);
|
|
|
|
gtk_text_forward_delete(GTK_TEXT(text), bytes_already);
|
|
|
|
}
|
1999-10-19 04:11:23 +00:00
|
|
|
|
2000-01-06 08:20:13 +00:00
|
|
|
/* stop the updates while we fill the text box */
|
|
|
|
gtk_text_freeze( GTK_TEXT(text) );
|
2000-01-12 22:07:56 +00:00
|
|
|
follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
|
2000-01-06 08:20:13 +00:00
|
|
|
gtk_text_thaw( GTK_TEXT(text) );
|
1998-09-17 03:12:28 +00:00
|
|
|
}
|
|
|
|
|
1999-06-24 16:25:59 +00:00
|
|
|
/* Match selected byte pattern */
|
|
|
|
void
|
|
|
|
match_selected_cb(GtkWidget *w, gpointer data)
|
|
|
|
{
|
1999-11-19 22:32:00 +00:00
|
|
|
char *buf;
|
1999-11-26 05:23:40 +00:00
|
|
|
GtkWidget *filter_te;
|
1999-11-19 22:32:00 +00:00
|
|
|
char *ptr, *format, *stringified;
|
|
|
|
int i, dfilter_len, abbrev_len;
|
|
|
|
guint8 *c;
|
|
|
|
header_field_info *hfinfo;
|
1999-06-24 16:25:59 +00:00
|
|
|
|
1999-08-04 03:37:45 +00:00
|
|
|
filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
|
1999-06-24 16:25:59 +00:00
|
|
|
|
1999-11-19 22:32:00 +00:00
|
|
|
if (!finfo_selected) {
|
1999-06-24 16:25:59 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1999-11-19 22:32:00 +00:00
|
|
|
hfinfo = finfo_selected->hfinfo;
|
|
|
|
g_assert(hfinfo);
|
|
|
|
abbrev_len = strlen(hfinfo->abbrev);
|
|
|
|
|
|
|
|
switch(hfinfo->type) {
|
|
|
|
|
|
|
|
case FT_BOOLEAN:
|
|
|
|
dfilter_len = abbrev_len + 2;
|
|
|
|
buf = g_malloc0(dfilter_len);
|
|
|
|
snprintf(buf, dfilter_len, "%s%s", finfo_selected->value.numeric ? "" : "!",
|
|
|
|
hfinfo->abbrev);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_UINT8:
|
|
|
|
case FT_UINT16:
|
|
|
|
case FT_UINT24:
|
|
|
|
case FT_UINT32:
|
|
|
|
case FT_INT8:
|
|
|
|
case FT_INT16:
|
|
|
|
case FT_INT24:
|
|
|
|
case FT_INT32:
|
|
|
|
dfilter_len = abbrev_len + 20;
|
|
|
|
buf = g_malloc0(dfilter_len);
|
|
|
|
format = hfinfo_numeric_format(hfinfo);
|
|
|
|
snprintf(buf, dfilter_len, format, hfinfo->abbrev, finfo_selected->value.numeric);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_IPv4:
|
1999-11-19 23:01:26 +00:00
|
|
|
dfilter_len = abbrev_len + 4 + 15 + 1;
|
1999-11-19 22:32:00 +00:00
|
|
|
buf = g_malloc0(dfilter_len);
|
1999-11-19 23:01:26 +00:00
|
|
|
snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
|
|
|
|
ipv4_addr_str(&(finfo_selected->value.ipv4)));
|
1999-11-19 22:32:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_IPXNET:
|
|
|
|
dfilter_len = abbrev_len + 15;
|
|
|
|
buf = g_malloc0(dfilter_len);
|
|
|
|
snprintf(buf, dfilter_len, "%s == 0x%08x", hfinfo->abbrev,
|
|
|
|
finfo_selected->value.numeric);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_IPv6:
|
|
|
|
stringified = ip6_to_str((struct e_in6_addr*) &(finfo_selected->value.ipv6));
|
|
|
|
dfilter_len = abbrev_len + 4 + strlen(stringified) + 1;
|
|
|
|
buf = g_malloc0(dfilter_len);
|
|
|
|
snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
|
|
|
|
stringified);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_DOUBLE:
|
|
|
|
dfilter_len = abbrev_len + 30;
|
|
|
|
buf = g_malloc0(dfilter_len);
|
|
|
|
snprintf(buf, dfilter_len, "%s == %f", hfinfo->abbrev,
|
|
|
|
finfo_selected->value.floating);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_ETHER:
|
|
|
|
dfilter_len = abbrev_len + 22;
|
|
|
|
buf = g_malloc0(dfilter_len);
|
1999-11-26 05:23:40 +00:00
|
|
|
snprintf(buf, dfilter_len, "%s == %s",
|
1999-11-19 22:32:00 +00:00
|
|
|
hfinfo->abbrev,
|
1999-11-26 05:23:40 +00:00
|
|
|
ether_to_str(finfo_selected->value.ether));
|
1999-11-19 22:32:00 +00:00
|
|
|
break;
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
case FT_ABSOLUTE_TIME:
|
|
|
|
case FT_RELATIVE_TIME:
|
|
|
|
memcpy(&fi->value.time, va_arg(ap, struct timeval*),
|
|
|
|
sizeof(struct timeval));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_STRING:
|
|
|
|
/* This g_strdup'ed memory is freed in proto_tree_free_node() */
|
|
|
|
fi->value.string = g_strdup(va_arg(ap, char*));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_TEXT_ONLY:
|
|
|
|
; /* nothing */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
2000-06-27 04:36:03 +00:00
|
|
|
c = cfile.pd + finfo_selected->start;
|
1999-11-19 22:32:00 +00:00
|
|
|
buf = g_malloc0(32 + finfo_selected->length * 3);
|
|
|
|
ptr = buf;
|
|
|
|
|
1999-11-26 05:23:40 +00:00
|
|
|
sprintf(ptr, "frame[%d] == ", finfo_selected->start);
|
1999-11-19 22:32:00 +00:00
|
|
|
ptr = buf+strlen(buf);
|
|
|
|
|
|
|
|
if (finfo_selected->length == 1) {
|
|
|
|
sprintf(ptr, "0x%02x", *c++);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (i=0;i<finfo_selected->length; i++) {
|
|
|
|
if (i == 0 ) {
|
|
|
|
sprintf(ptr, "%02x", *c++);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sprintf(ptr, ":%02x", *c++);
|
|
|
|
}
|
|
|
|
ptr = buf+strlen(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
1999-06-24 16:25:59 +00:00
|
|
|
|
|
|
|
/* create a new one and set the display filter entry accordingly */
|
1999-11-26 05:23:40 +00:00
|
|
|
gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
|
|
|
|
|
1999-07-31 18:26:07 +00:00
|
|
|
/* Run the display filter so it goes in effect. */
|
2000-06-27 04:36:03 +00:00
|
|
|
filter_packets(&cfile, buf);
|
1999-11-19 22:32:00 +00:00
|
|
|
|
|
|
|
/* Don't g_free(buf) here. filter_packets() will do it the next time it's called */
|
|
|
|
}
|
|
|
|
|
|
|
|
static char*
|
|
|
|
hfinfo_numeric_format(header_field_info *hfinfo)
|
|
|
|
{
|
|
|
|
char *format = NULL;
|
|
|
|
|
|
|
|
/* Pick the proper format string */
|
|
|
|
switch(hfinfo->display) {
|
|
|
|
case BASE_DEC:
|
|
|
|
case BASE_NONE:
|
|
|
|
case BASE_OCT: /* I'm lazy */
|
|
|
|
case BASE_BIN: /* I'm lazy */
|
|
|
|
switch(hfinfo->type) {
|
|
|
|
case FT_UINT8:
|
|
|
|
case FT_UINT16:
|
|
|
|
case FT_UINT24:
|
|
|
|
case FT_UINT32:
|
|
|
|
format = "%s == %u";
|
|
|
|
break;
|
|
|
|
case FT_INT8:
|
|
|
|
case FT_INT16:
|
|
|
|
case FT_INT24:
|
|
|
|
case FT_INT32:
|
|
|
|
format = "%s == %d";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BASE_HEX:
|
|
|
|
switch(hfinfo->type) {
|
|
|
|
case FT_UINT8:
|
|
|
|
format = "%s == 0x%02x";
|
|
|
|
break;
|
|
|
|
case FT_UINT16:
|
|
|
|
format = "%s == 0x%04x";
|
|
|
|
break;
|
|
|
|
case FT_UINT24:
|
|
|
|
format = "%s == 0x%06x";
|
|
|
|
break;
|
|
|
|
case FT_UINT32:
|
|
|
|
format = "%s == 0x%08x";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
;
|
|
|
|
}
|
|
|
|
return format;
|
1999-06-24 16:25:59 +00:00
|
|
|
}
|
|
|
|
|
1999-11-19 22:32:00 +00:00
|
|
|
|
1999-07-11 08:40:52 +00:00
|
|
|
/* Run the current display filter on the current packet set, and
|
|
|
|
redisplay. */
|
|
|
|
static void
|
1999-08-13 23:47:43 +00:00
|
|
|
filter_activate_cb(GtkWidget *w, gpointer data)
|
|
|
|
{
|
1999-11-25 18:02:25 +00:00
|
|
|
GtkCombo *filter_cm = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_CM_KEY);
|
|
|
|
GList *filter_list = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_FL_KEY);
|
|
|
|
GList *li, *nl = NULL;
|
|
|
|
gboolean add_filter = TRUE;
|
|
|
|
|
1999-08-13 23:47:43 +00:00
|
|
|
char *s = gtk_entry_get_text(GTK_ENTRY(w));
|
1999-11-25 18:02:25 +00:00
|
|
|
|
|
|
|
/* GtkCombos don't let us get at their list contents easily, so we maintain
|
|
|
|
our own filter list, and feed it to gtk_combo_set_popdown_strings when
|
|
|
|
a new filter is added. */
|
2000-06-27 04:36:03 +00:00
|
|
|
if (filter_packets(&cfile, g_strdup(s))) {
|
1999-11-25 18:02:25 +00:00
|
|
|
li = g_list_first(filter_list);
|
|
|
|
while (li) {
|
|
|
|
if (li->data && strcmp(s, li->data) == 0)
|
|
|
|
add_filter = FALSE;
|
|
|
|
li = li->next;
|
|
|
|
}
|
1999-08-13 23:47:43 +00:00
|
|
|
|
1999-11-25 18:02:25 +00:00
|
|
|
if (add_filter) {
|
|
|
|
filter_list = g_list_append(filter_list, g_strdup(s));
|
|
|
|
li = g_list_first(filter_list);
|
|
|
|
while (li) {
|
|
|
|
nl = g_list_append(nl, strdup(li->data));
|
|
|
|
li = li->next;
|
|
|
|
}
|
|
|
|
gtk_combo_set_popdown_strings(filter_cm, nl);
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(filter_cm->entry), g_list_last(filter_list)->data);
|
|
|
|
}
|
|
|
|
}
|
1999-07-11 08:40:52 +00:00
|
|
|
}
|
|
|
|
|
1999-11-21 15:06:07 +00:00
|
|
|
/* redisplay with no display filter */
|
|
|
|
static void
|
|
|
|
filter_reset_cb(GtkWidget *w, gpointer data)
|
|
|
|
{
|
|
|
|
GtkWidget *filter_te = NULL;
|
|
|
|
|
|
|
|
if ((filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY))) {
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(filter_te), "");
|
|
|
|
}
|
|
|
|
|
2000-06-27 04:36:03 +00:00
|
|
|
filter_packets(&cfile, NULL);
|
1999-11-21 15:06:07 +00:00
|
|
|
}
|
|
|
|
|
2000-05-10 06:00:22 +00:00
|
|
|
/* GTKClist compare routine, overrides default to allow numeric comparison */
|
|
|
|
static gint
|
|
|
|
packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
|
|
|
|
{
|
|
|
|
/* Get row text strings */
|
|
|
|
char *text1 = GTK_CELL_TEXT (((GtkCListRow *)ptr1)->cell[clist->sort_column])->text;
|
|
|
|
char *text2 = GTK_CELL_TEXT (((GtkCListRow *)ptr2)->cell[clist->sort_column])->text;
|
|
|
|
|
|
|
|
/* Attempt to convert to numbers */
|
|
|
|
double num1 = atof(text1);
|
|
|
|
double num2 = atof(text2);
|
|
|
|
|
2000-06-27 04:36:03 +00:00
|
|
|
gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
|
2000-05-10 06:00:22 +00:00
|
|
|
|
|
|
|
if ((col_fmt == COL_NUMBER) || (col_fmt == COL_REL_TIME) || (col_fmt == COL_DELTA_TIME) ||
|
|
|
|
((col_fmt == COL_CLS_TIME) && (timestamp_type == RELATIVE)) ||
|
|
|
|
((col_fmt == COL_CLS_TIME) && (timestamp_type == DELTA)) ||
|
|
|
|
(col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
|
|
|
|
((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
|
|
|
|
(col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT))) ||
|
|
|
|
(col_fmt == COL_PACKET_LENGTH)) {
|
|
|
|
|
|
|
|
/* Compare numeric column */
|
|
|
|
|
|
|
|
if (num1 < num2)
|
|
|
|
return -1;
|
|
|
|
else if (num1 > num2)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* Compare text column */
|
|
|
|
if (!text2)
|
|
|
|
return (text1 != NULL);
|
|
|
|
|
|
|
|
if (!text1)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return strcmp(text1, text2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* What to do when a column is clicked */
|
|
|
|
static void
|
|
|
|
packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
|
|
|
|
{
|
|
|
|
if (column == clist->sort_column) {
|
|
|
|
if (clist->sort_type == GTK_SORT_ASCENDING)
|
|
|
|
clist->sort_type = GTK_SORT_DESCENDING;
|
|
|
|
else
|
|
|
|
clist->sort_type = GTK_SORT_ASCENDING;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
clist->sort_type = GTK_SORT_ASCENDING;
|
|
|
|
gtk_clist_set_sort_column(clist, column);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_clist_sort(clist);
|
|
|
|
}
|
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
/* What to do when a list item is selected/unselected */
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
static void
|
1998-09-16 02:39:15 +00:00
|
|
|
packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
|
1998-10-16 01:18:35 +00:00
|
|
|
|
1998-09-17 03:12:28 +00:00
|
|
|
blank_packetinfo();
|
2000-06-27 04:36:03 +00:00
|
|
|
select_packet(&cfile, row);
|
1998-09-16 02:39:15 +00:00
|
|
|
}
|
|
|
|
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
static void
|
1998-09-16 02:39:15 +00:00
|
|
|
packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
|
2000-06-27 04:36:03 +00:00
|
|
|
unselect_packet(&cfile);
|
1998-09-16 02:39:15 +00:00
|
|
|
}
|
|
|
|
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
static void
|
|
|
|
tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
|
|
|
|
{
|
|
|
|
field_info *finfo;
|
|
|
|
|
|
|
|
g_assert(node);
|
|
|
|
finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
|
1999-12-30 19:53:11 +00:00
|
|
|
if (!finfo) return;
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
|
|
|
|
finfo_selected = finfo;
|
1998-09-16 02:39:15 +00:00
|
|
|
|
2000-06-27 04:36:03 +00:00
|
|
|
packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame->cap_len,
|
|
|
|
finfo->start, finfo->length, cfile.current_frame->flags.encoding);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
|
|
|
|
{
|
|
|
|
finfo_selected = NULL;
|
2000-06-27 04:36:03 +00:00
|
|
|
packet_hex_print(GTK_TEXT(byte_view), cfile.pd, cfile.current_frame->cap_len,
|
|
|
|
-1, -1, cfile.current_frame->flags.encoding);
|
1998-09-16 02:39:15 +00:00
|
|
|
}
|
|
|
|
|
1999-09-11 12:38:18 +00:00
|
|
|
void collapse_all_cb(GtkWidget *widget, gpointer data) {
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.protocol_tree)
|
|
|
|
collapse_all_tree(cfile.protocol_tree, tree_view);
|
1999-09-11 12:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void expand_all_cb(GtkWidget *widget, gpointer data) {
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.protocol_tree)
|
|
|
|
expand_all_tree(cfile.protocol_tree, tree_view);
|
1999-09-11 12:38:18 +00:00
|
|
|
}
|
|
|
|
|
2000-02-20 14:52:28 +00:00
|
|
|
void resolve_name_cb(GtkWidget *widget, gpointer data) {
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.protocol_tree) {
|
2000-02-20 14:52:28 +00:00
|
|
|
int tmp = g_resolving_actif;
|
|
|
|
g_resolving_actif = 1;
|
|
|
|
gtk_clist_clear ( GTK_CLIST(tree_view) );
|
2000-06-27 04:36:03 +00:00
|
|
|
proto_tree_draw(cfile.protocol_tree, tree_view);
|
2000-02-20 14:52:28 +00:00
|
|
|
g_resolving_actif = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
/* Set the scrollbar placement of a scrolled window based upon pos value:
|
|
|
|
0 = left, 1 = right */
|
1999-12-16 06:20:18 +00:00
|
|
|
void
|
2000-02-29 06:24:41 +00:00
|
|
|
set_scrollbar_placement_scrollw(GtkWidget *scrollw, int pos) /* 0=left, 1=right */
|
1999-12-16 06:20:18 +00:00
|
|
|
{
|
|
|
|
if (pos) {
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
|
|
|
|
GTK_CORNER_TOP_LEFT);
|
|
|
|
} else {
|
|
|
|
gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrollw),
|
|
|
|
GTK_CORNER_TOP_RIGHT);
|
1999-12-16 06:20:18 +00:00
|
|
|
}
|
2000-02-29 06:24:41 +00:00
|
|
|
}
|
|
|
|
|
2000-03-02 07:05:57 +00:00
|
|
|
/* List of all scrolled windows, so we can globally set the scrollbar
|
|
|
|
placement of them. */
|
|
|
|
static GList *scrolled_windows;
|
|
|
|
|
|
|
|
/* Add a scrolled window to the list of scrolled windows. */
|
2000-02-29 06:24:41 +00:00
|
|
|
void
|
2000-03-02 07:05:57 +00:00
|
|
|
remember_scrolled_window(GtkWidget *scrollw)
|
2000-02-29 06:24:41 +00:00
|
|
|
{
|
2000-03-02 07:05:57 +00:00
|
|
|
scrolled_windows = g_list_append(scrolled_windows, scrollw);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove a scrolled window from the list of scrolled windows. */
|
|
|
|
void
|
|
|
|
forget_scrolled_window(GtkWidget *scrollw)
|
|
|
|
{
|
|
|
|
scrolled_windows = g_list_remove(scrolled_windows, scrollw);
|
1999-12-16 06:20:18 +00:00
|
|
|
}
|
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
static void
|
2000-03-02 07:05:57 +00:00
|
|
|
set_scrollbar_placement_cb(gpointer data, gpointer user_data)
|
2000-02-29 06:24:41 +00:00
|
|
|
{
|
2000-03-02 07:05:57 +00:00
|
|
|
set_scrollbar_placement_scrollw((GtkWidget *)data,
|
|
|
|
*(int *)user_data);
|
2000-02-29 06:24:41 +00:00
|
|
|
}
|
|
|
|
|
2000-03-02 07:05:57 +00:00
|
|
|
/* Set the scrollbar placement of all scrolled windows based on pos value:
|
2000-02-29 06:24:41 +00:00
|
|
|
0 = left, 1 = right */
|
|
|
|
void
|
|
|
|
set_scrollbar_placement_all(int pos)
|
|
|
|
{
|
2000-03-02 07:05:57 +00:00
|
|
|
g_list_foreach(scrolled_windows, set_scrollbar_placement_cb, &pos);
|
2000-02-29 06:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the selection mode of the packet list window. */
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
void
|
|
|
|
set_plist_sel_browse(gboolean val)
|
|
|
|
{
|
|
|
|
if (finfo_selected)
|
2000-06-27 04:36:03 +00:00
|
|
|
unselect_packet(&cfile);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
|
1999-12-30 19:53:11 +00:00
|
|
|
/* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
|
|
|
|
* "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
if (val) {
|
|
|
|
gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
|
|
|
|
}
|
|
|
|
else {
|
1999-12-30 19:53:11 +00:00
|
|
|
gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
/* Set the selection mode of a given packet tree window. */
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
void
|
2000-02-29 06:24:41 +00:00
|
|
|
set_ptree_sel_browse(GtkWidget *tv, gboolean val)
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
{
|
1999-12-30 19:53:11 +00:00
|
|
|
/* Yeah, GTK uses "browse" in the case where we do not, but oh well. I think
|
|
|
|
* "browse" in Ethereal makes more sense than "SINGLE" in GTK+ */
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
if (val) {
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_SINGLE);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
}
|
|
|
|
else {
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_clist_set_selection_mode(GTK_CLIST(tv), GTK_SELECTION_BROWSE);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
}
|
|
|
|
}
|
1999-12-16 06:20:18 +00:00
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
/* Set the selection mode of all packet tree windows. */
|
1999-12-30 23:02:56 +00:00
|
|
|
void
|
2000-02-29 06:24:41 +00:00
|
|
|
set_ptree_sel_browse_all(gboolean val)
|
|
|
|
{
|
|
|
|
set_ptree_sel_browse(tree_view, val);
|
|
|
|
set_ptree_sel_browse_packet_wins(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the line style of a given packet tree window. */
|
|
|
|
void
|
|
|
|
set_ptree_line_style(GtkWidget *tv, gint style)
|
1999-12-30 23:02:56 +00:00
|
|
|
{
|
|
|
|
/* I'm using an assert here since the preferences code limits
|
|
|
|
* the user input, both in the GUI and when reading the preferences file.
|
|
|
|
* If the value is incorrect, it's a program error, not a user-initiated error.
|
|
|
|
*/
|
|
|
|
g_assert(style >= GTK_CTREE_LINES_NONE && style <= GTK_CTREE_LINES_TABBED);
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_ctree_set_line_style( GTK_CTREE(tv), style );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the line style of all packet tree window. */
|
|
|
|
void
|
|
|
|
set_ptree_line_style_all(gint style)
|
|
|
|
{
|
|
|
|
set_ptree_line_style(tree_view, style);
|
|
|
|
set_ptree_line_style_packet_wins(style);
|
1999-12-30 23:02:56 +00:00
|
|
|
}
|
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
/* Set the expander style of a given packet tree window. */
|
1999-12-30 23:02:56 +00:00
|
|
|
void
|
2000-02-29 06:24:41 +00:00
|
|
|
set_ptree_expander_style(GtkWidget *tv, gint style)
|
1999-12-30 23:02:56 +00:00
|
|
|
{
|
|
|
|
/* I'm using an assert here since the preferences code limits
|
|
|
|
* the user input, both in the GUI and when reading the preferences file.
|
|
|
|
* If the value is incorrect, it's a program error, not a user-initiated error.
|
|
|
|
*/
|
|
|
|
g_assert(style >= GTK_CTREE_EXPANDER_NONE && style <= GTK_CTREE_EXPANDER_CIRCULAR);
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_ctree_set_expander_style( GTK_CTREE(tv), style );
|
1999-12-30 23:02:56 +00:00
|
|
|
}
|
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
void
|
|
|
|
set_ptree_expander_style_all(gint style)
|
|
|
|
{
|
|
|
|
set_ptree_expander_style(tree_view, style);
|
|
|
|
set_ptree_expander_style_packet_wins(style);
|
|
|
|
}
|
1999-12-30 23:02:56 +00:00
|
|
|
|
There's no need to catch the "delete_event" signal on "Follow TCP
Stream" windows - the window should always be deleted in that situation,
so there's no need for a signal handler that might return TRUE (meaning
"don't delete the window"), and the "destroy" handler gets called when
the window actually gets destroyed, so there's no need to do any cleanup
in the "delete_event" handler.
Catch the "delete_event" signal on the main window in a routine with the
right signature, and that returns FALSE so that the window actually gets
deleted.
Call "close_cap_file()" in the callback for the "File:Quit" menu item
(which is also called by the "delete_event" handler for the main
window), rather than calling it after "gtk_main()" returns -
"close_cap_file()" manipulates stuff in the main window, and if we do so
after "gtk_main()" returns, it appears that the main window may have
disappeared (if we are exiting because the user deleted the main
window), in which case we can get crashes or other errors when
"close_cap_file()" tries to manipulate stuff in the main window.
There's no need to catch the "destroy" signal on the main window - we do
some of the cleanup in the handler for "delete_event" (we have to, for
reasons described above), and we do the rest of it after the main
routine returns.
svn path=/trunk/; revision=1773
2000-04-01 11:30:53 +00:00
|
|
|
static gboolean
|
|
|
|
main_window_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
{
|
|
|
|
file_quit_cmd_cb(widget, data);
|
|
|
|
|
|
|
|
/* Say that the window should be deleted. */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
void
|
2000-02-13 10:36:06 +00:00
|
|
|
file_quit_cmd_cb (GtkWidget *widget, gpointer data)
|
|
|
|
{
|
There's no need to catch the "delete_event" signal on "Follow TCP
Stream" windows - the window should always be deleted in that situation,
so there's no need for a signal handler that might return TRUE (meaning
"don't delete the window"), and the "destroy" handler gets called when
the window actually gets destroyed, so there's no need to do any cleanup
in the "delete_event" handler.
Catch the "delete_event" signal on the main window in a routine with the
right signature, and that returns FALSE so that the window actually gets
deleted.
Call "close_cap_file()" in the callback for the "File:Quit" menu item
(which is also called by the "delete_event" handler for the main
window), rather than calling it after "gtk_main()" returns -
"close_cap_file()" manipulates stuff in the main window, and if we do so
after "gtk_main()" returns, it appears that the main window may have
disappeared (if we are exiting because the user deleted the main
window), in which case we can get crashes or other errors when
"close_cap_file()" tries to manipulate stuff in the main window.
There's no need to catch the "destroy" signal on the main window - we do
some of the cleanup in the handler for "delete_event" (we have to, for
reasons described above), and we do the rest of it after the main
routine returns.
svn path=/trunk/; revision=1773
2000-04-01 11:30:53 +00:00
|
|
|
/* XXX - should we check whether the capture file is an
|
|
|
|
unsaved temporary file for a live capture and, if so,
|
|
|
|
pop up a "do you want to exit without saving the capture
|
|
|
|
file?" dialog, and then just return, leaving said dialog
|
|
|
|
box to forcibly quit if the user clicks "OK"?
|
|
|
|
|
|
|
|
If so, note that this should be done in a subroutine that
|
|
|
|
returns TRUE if we do so, and FALSE otherwise, and that
|
|
|
|
"main_window_delete_event_cb()" should return its
|
|
|
|
return value. */
|
|
|
|
|
|
|
|
/* Close any capture file we have open; on some OSes, you can't
|
|
|
|
unlink a temporary capture file if you have it open.
|
|
|
|
"close_cap_file()" will unlink it after closing it if
|
|
|
|
it's a temporary file.
|
|
|
|
|
|
|
|
We do this here, rather than after the main loop returns,
|
|
|
|
as, after the main loop returns, the main window may have
|
|
|
|
been destroyed (if this is called due to a "destroy"
|
|
|
|
even on the main window rather than due to the user
|
|
|
|
selecting a menu item), and there may be a crash
|
|
|
|
or other problem when "close_cap_file()" tries to
|
|
|
|
clean up stuff in the main window.
|
|
|
|
|
|
|
|
XXX - is there a better place to put this?
|
|
|
|
Or should we have a routine that *just* closes the
|
|
|
|
capture file, and doesn't do anything with the UI,
|
|
|
|
which we'd call here, and another routine that
|
|
|
|
calls that routine and also cleans up the UI, which
|
|
|
|
we'd call elsewhere? */
|
2000-06-27 04:36:03 +00:00
|
|
|
close_cap_file(&cfile, info_bar);
|
There's no need to catch the "delete_event" signal on "Follow TCP
Stream" windows - the window should always be deleted in that situation,
so there's no need for a signal handler that might return TRUE (meaning
"don't delete the window"), and the "destroy" handler gets called when
the window actually gets destroyed, so there's no need to do any cleanup
in the "delete_event" handler.
Catch the "delete_event" signal on the main window in a routine with the
right signature, and that returns FALSE so that the window actually gets
deleted.
Call "close_cap_file()" in the callback for the "File:Quit" menu item
(which is also called by the "delete_event" handler for the main
window), rather than calling it after "gtk_main()" returns -
"close_cap_file()" manipulates stuff in the main window, and if we do so
after "gtk_main()" returns, it appears that the main window may have
disappeared (if we are exiting because the user deleted the main
window), in which case we can get crashes or other errors when
"close_cap_file()" tries to manipulate stuff in the main window.
There's no need to catch the "destroy" signal on the main window - we do
some of the cleanup in the handler for "delete_event" (we have to, for
reasons described above), and we do the rest of it after the main
routine returns.
svn path=/trunk/; revision=1773
2000-04-01 11:30:53 +00:00
|
|
|
|
Exit from Ethereal by making the main loop exit, so that any quit
routines we register get called.
Register the "follow TCP stream" windows with "gtk_quit_add_destroy()",
so that, when Ethereal exits, they all get destroyed; this means that
their destroy callbacks get called, which means that they get to delete
their temporary files, so that, if you exit Ethereal without manually
closing the "follow TCP stream" windows, the temporary files don't get
left around.
Exit from Ethereal's "main()" function by calling "gtk_exit()", rather
than "exit()", so that we do whatever cleanup GTK+ requires. (We used
to call "gtk_exit()" in the callback for the "File:Quit" menu item and
the "delete" callback for the main window, but we now just call
"gtk_main_quit()" so that we exit from the main loop.)
svn path=/trunk/; revision=1772
2000-04-01 10:23:01 +00:00
|
|
|
/* Exit by leaving the main loop, so that any quit functions
|
|
|
|
we registered get called. */
|
|
|
|
gtk_main_quit();
|
1998-09-16 02:39:15 +00:00
|
|
|
}
|
|
|
|
|
Improve the alert boxes put up for file open/read/write errors. (Some
influence came from
http://developer.apple.com/techpubs/mac/HIGuidelines/HIGuidelines-232.html
which has a section on dialog box and alert box messages. However,
we're largely dealing with technoids, not with The Rest Of Us, so I
didn't go as far as one perhaps should.)
Unfortunately, it looks like it's a bit more work to arrange that, if
you give a bad file name to the "-r" flag, the dialog box pop up only
*after* the main window pops up - it has the annoying habit of popping
up *before* the main window pops up, and sometimes getting *obscured* by
it, when I do that. The removal of the dialog box stuff from
"load_cap_file()" was intended to facilitate that work. (It might also
be nice if, when an open from the "File/Open" menu item fails, we keep
the file selection box open, and give the user a chance to correct
typos, choose another file name, etc.)
svn path=/trunk/; revision=310
1999-06-12 09:10:20 +00:00
|
|
|
static void
|
1998-09-16 02:39:15 +00:00
|
|
|
print_usage(void) {
|
|
|
|
|
2000-01-15 12:54:24 +00:00
|
|
|
fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
|
|
|
|
comp_info_str);
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-01-24 05:06:39 +00:00
|
|
|
fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
|
1998-09-16 02:39:15 +00:00
|
|
|
PACKAGE);
|
2000-01-24 05:06:39 +00:00
|
|
|
fprintf(stderr, "\t[ -c count ] [ -D ] [ -f <capture filter> ] [ -i interface ]\n");
|
|
|
|
fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
|
|
|
|
fprintf(stderr, "\t[ -R <read filter> ] [ -s snaplen ] [ -t <time stamp format> ]\n");
|
|
|
|
fprintf(stderr, "\t[ -T <tree view height> ] [ -w savefile ]\n");
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
2000-01-24 05:06:39 +00:00
|
|
|
fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
|
1999-12-07 07:12:49 +00:00
|
|
|
PACKAGE);
|
2000-01-24 05:06:39 +00:00
|
|
|
fprintf(stderr, "\t[ -m <medium font> ] [ -n ] [ -P <packet list height> ] [ -r infile ]\n");
|
|
|
|
fprintf(stderr, "\t[ -R <read filter> ] [ -t <time stamp format> ]\n");
|
|
|
|
fprintf(stderr, "\t[ -T <tree view height> ]\n");
|
1999-12-07 07:12:49 +00:00
|
|
|
#endif
|
1998-09-16 02:39:15 +00:00
|
|
|
}
|
|
|
|
|
1998-11-17 04:29:13 +00:00
|
|
|
/* And now our feature presentation... [ fade to music ] */
|
1998-09-16 02:39:15 +00:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
1999-10-21 21:47:08 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
char *command_name;
|
|
|
|
#endif
|
|
|
|
char *s;
|
1999-07-13 02:53:26 +00:00
|
|
|
int i;
|
|
|
|
int opt;
|
1998-09-16 02:39:15 +00:00
|
|
|
extern char *optarg;
|
1999-12-07 07:12:49 +00:00
|
|
|
gboolean arg_error = FALSE;
|
1999-11-04 21:04:35 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-02-09 19:18:42 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
char pcap_version[] = "0.4a6";
|
|
|
|
#else
|
1999-12-07 07:12:49 +00:00
|
|
|
extern char pcap_version[];
|
2000-02-09 19:18:42 +00:00
|
|
|
#endif
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
1999-06-12 07:04:35 +00:00
|
|
|
char *pf_path;
|
1999-12-07 07:12:49 +00:00
|
|
|
int pf_open_errno = 0;
|
|
|
|
int err;
|
Add a new global flag "capture_child", which is TRUE if we're a child
process for a sync mode or fork mode capture.
Have that flag control whether we do things that *only* the parent or
*only* the child should do, rather than basing it solely on the setting
of "sync_mode" or "fork_mode" (or, in the case of stuff done in the
child process either in sync mode or fork mode, rather than basing it on
the setting of those flags at all).
Split "do_capture()" into a "run_capture()" routine that starts a
capture (possibly by forking off and execing a child process, if we're
supposed to do sync mode or fork mode captures), and that assumes the
file to which the capture is to write has already been opened and that
"cf.save_file_fd" is the file descriptor for that file, and a
"do_capture()" routine that creates a temporary file, getting an FD for
it, and calls "run_capture()".
Use "run_capture()", rather than "capture()", for "-k" captures, so that
it'll do the capture in a child process if "-S" or "-F" was specified
("do_capture()" won't do because "-k" captures should write to the file
specified by the "-w" flag, not some random temporary file).
For child process captures, however, just use "capture()" - the child
process shouldn't itself fork off a child if we're in sync or fork mode,
and should just write to the file whose file descriptor was specified by
the "-W" flag on the command line.
All this allows you to do "ethereal -S -w <file> -i <interface> -k" to
start a sync mode capture from the command line.
svn path=/trunk/; revision=740
1999-09-30 06:50:01 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
1999-12-07 07:12:49 +00:00
|
|
|
gboolean start_capture = FALSE;
|
|
|
|
gchar *save_file = NULL;
|
2000-01-16 02:48:12 +00:00
|
|
|
GList *if_list;
|
2000-01-15 06:05:21 +00:00
|
|
|
gchar err_str[PCAP_ERRBUF_SIZE];
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
gboolean capture_option_specified = FALSE;
|
Add a new global flag "capture_child", which is TRUE if we're a child
process for a sync mode or fork mode capture.
Have that flag control whether we do things that *only* the parent or
*only* the child should do, rather than basing it solely on the setting
of "sync_mode" or "fork_mode" (or, in the case of stuff done in the
child process either in sync mode or fork mode, rather than basing it on
the setting of those flags at all).
Split "do_capture()" into a "run_capture()" routine that starts a
capture (possibly by forking off and execing a child process, if we're
supposed to do sync mode or fork mode captures), and that assumes the
file to which the capture is to write has already been opened and that
"cf.save_file_fd" is the file descriptor for that file, and a
"do_capture()" routine that creates a temporary file, getting an FD for
it, and calls "run_capture()".
Use "run_capture()", rather than "capture()", for "-k" captures, so that
it'll do the capture in a child process if "-S" or "-F" was specified
("do_capture()" won't do because "-k" captures should write to the file
specified by the "-w" flag, not some random temporary file).
For child process captures, however, just use "capture()" - the child
process shouldn't itself fork off a child if we're in sync or fork mode,
and should just write to the file whose file descriptor was specified by
the "-W" flag on the command line.
All this allows you to do "ethereal -S -w <file> -i <interface> -k" to
start a sync mode capture from the command line.
svn path=/trunk/; revision=740
1999-09-30 06:50:01 +00:00
|
|
|
#endif
|
1998-11-18 03:01:44 +00:00
|
|
|
gint pl_size = 280, tv_size = 95, bv_size = 75;
|
1999-08-10 07:16:47 +00:00
|
|
|
gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
|
1999-08-15 19:18:46 +00:00
|
|
|
dfilter *rfcode = NULL;
|
|
|
|
gboolean rfilter_parse_failed = FALSE;
|
1998-11-17 04:29:13 +00:00
|
|
|
e_prefs *prefs;
|
1998-09-16 02:39:15 +00:00
|
|
|
|
1999-05-11 18:51:10 +00:00
|
|
|
ethereal_path = argv[0];
|
|
|
|
|
1999-10-21 21:47:08 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-01-25 04:44:33 +00:00
|
|
|
command_name = get_basename(ethereal_path);
|
1999-10-21 21:47:08 +00:00
|
|
|
/* Set "capture_child" to indicate whether this is going to be a child
|
|
|
|
process for a "-S" capture. */
|
|
|
|
capture_child = (strcmp(command_name, CHILD_NAME) == 0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If invoked with the "-G" flag, we dump out a glossary of
|
|
|
|
display filter symbols.
|
|
|
|
|
|
|
|
We must do this before calling "gtk_init()", because "gtk_init()"
|
|
|
|
tries to open an X display, and we don't want to have to do any X
|
|
|
|
stuff just to do a build.
|
|
|
|
|
|
|
|
Given that we call "gtk_init()" before doing the regular argument
|
|
|
|
list processing, so that it can handle X and GTK+ arguments and
|
|
|
|
remove them from the list at which we look, this means we must do
|
|
|
|
this before doing the regular argument list processing, as well.
|
|
|
|
|
|
|
|
This means that:
|
|
|
|
|
|
|
|
you must give the "-G" flag as the first flag on the command line;
|
|
|
|
|
|
|
|
you must give it as "-G", nothing more, nothing less;
|
|
|
|
|
|
|
|
any arguments after the "-G" flag will not be used. */
|
|
|
|
if (argc >= 2 && strcmp(argv[1], "-G") == 0) {
|
2000-04-04 07:03:07 +00:00
|
|
|
dissect_init();
|
Have Ethereal, when invoked as "ethereal-dump-fields", dump out a
glossary of display filter symbols, just as it does with "-G", except
that, as it can discover that it was so invoked before even looking at
the command-line arguments, it needn't even bother calling "gtk_init()"
to process those command-line arguments GTK+ cares about, and thus
needn't do any X stuff at all when so invoked.
That allows Ethereal to be built in an environment where you don't have
an X server, and, if your connection to your X server is slow, allows
you to built it faster.
Get rid of the "-G" flag, as it had only a somewhat specialized use.
svn path=/trunk/; revision=444
1999-08-05 06:34:43 +00:00
|
|
|
proto_registrar_dump();
|
|
|
|
exit(0);
|
|
|
|
}
|
Add a new global flag "capture_child", which is TRUE if we're a child
process for a sync mode or fork mode capture.
Have that flag control whether we do things that *only* the parent or
*only* the child should do, rather than basing it solely on the setting
of "sync_mode" or "fork_mode" (or, in the case of stuff done in the
child process either in sync mode or fork mode, rather than basing it on
the setting of those flags at all).
Split "do_capture()" into a "run_capture()" routine that starts a
capture (possibly by forking off and execing a child process, if we're
supposed to do sync mode or fork mode captures), and that assumes the
file to which the capture is to write has already been opened and that
"cf.save_file_fd" is the file descriptor for that file, and a
"do_capture()" routine that creates a temporary file, getting an FD for
it, and calls "run_capture()".
Use "run_capture()", rather than "capture()", for "-k" captures, so that
it'll do the capture in a child process if "-S" or "-F" was specified
("do_capture()" won't do because "-k" captures should write to the file
specified by the "-w" flag, not some random temporary file).
For child process captures, however, just use "capture()" - the child
process shouldn't itself fork off a child if we're in sync or fork mode,
and should just write to the file whose file descriptor was specified by
the "-W" flag on the command line.
All this allows you to do "ethereal -S -w <file> -i <interface> -k" to
start a sync mode capture from the command line.
svn path=/trunk/; revision=740
1999-09-30 06:50:01 +00:00
|
|
|
|
2000-06-05 03:09:21 +00:00
|
|
|
/* Set the current locale according to the program environment.
|
|
|
|
* We haven't localized anything, but some GTK widgets are localized
|
|
|
|
* (the file selection dialogue, for example) */
|
|
|
|
gtk_set_locale();
|
|
|
|
|
1998-11-17 04:29:13 +00:00
|
|
|
/* Let GTK get its args */
|
|
|
|
gtk_init (&argc, &argv);
|
1999-05-11 18:51:10 +00:00
|
|
|
|
1999-06-12 07:04:35 +00:00
|
|
|
prefs = read_prefs(&pf_path);
|
|
|
|
if (pf_path != NULL) {
|
|
|
|
/* The preferences file exists, but couldn't be opened; "pf_path" is
|
|
|
|
its pathname. Remember "errno", as that says why the attempt
|
|
|
|
failed. */
|
|
|
|
pf_open_errno = errno;
|
|
|
|
}
|
1999-08-14 19:53:31 +00:00
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
/* Initialize the capture file struct */
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.plist = NULL;
|
|
|
|
cfile.plist_end = NULL;
|
|
|
|
cfile.wth = NULL;
|
|
|
|
cfile.filename = NULL;
|
|
|
|
cfile.user_saved = FALSE;
|
|
|
|
cfile.is_tempfile = FALSE;
|
|
|
|
cfile.rfcode = NULL;
|
|
|
|
cfile.dfilter = NULL;
|
|
|
|
cfile.dfcode = NULL;
|
1999-07-09 04:18:36 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.cfilter = g_strdup(EMPTY_FILTER);
|
1999-07-09 04:18:36 +00:00
|
|
|
#endif
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.iface = NULL;
|
|
|
|
cfile.save_file = NULL;
|
|
|
|
cfile.save_file_fd = -1;
|
|
|
|
cfile.snap = WTAP_MAX_PACKET_SIZE;
|
|
|
|
cfile.count = 0;
|
|
|
|
cfile.cinfo.num_cols = prefs->num_cols;
|
|
|
|
cfile.cinfo.col_fmt = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
|
|
|
|
cfile.cinfo.fmt_matx = (gboolean **) g_malloc(sizeof(gboolean *) * cfile.cinfo.num_cols);
|
|
|
|
cfile.cinfo.col_width = (gint *) g_malloc(sizeof(gint) * cfile.cinfo.num_cols);
|
|
|
|
cfile.cinfo.col_title = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
|
|
|
|
cfile.cinfo.col_data = (gchar **) g_malloc(sizeof(gchar *) * cfile.cinfo.num_cols);
|
1998-11-17 04:29:13 +00:00
|
|
|
|
1998-12-27 20:47:53 +00:00
|
|
|
/* Assemble the compile-time options */
|
|
|
|
snprintf(comp_info_str, 256,
|
|
|
|
#ifdef GTK_MAJOR_VERSION
|
1999-11-29 03:07:19 +00:00
|
|
|
"GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
|
1999-07-09 04:18:36 +00:00
|
|
|
GTK_MICRO_VERSION,
|
1998-12-27 20:47:53 +00:00
|
|
|
#else
|
1999-11-29 03:07:19 +00:00
|
|
|
"GTK+ (version unknown), %s%s, %s%s, %s%s",
|
1999-07-09 04:18:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBPCAP
|
1999-11-29 02:45:23 +00:00
|
|
|
"with libpcap ", pcap_version,
|
1999-07-09 04:18:36 +00:00
|
|
|
#else
|
1999-11-29 02:45:23 +00:00
|
|
|
"without libpcap", "",
|
1998-12-27 20:47:53 +00:00
|
|
|
#endif
|
1999-11-29 02:45:23 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_LIBZ
|
|
|
|
#ifdef ZLIB_VERSION
|
1999-11-29 03:07:19 +00:00
|
|
|
"with libz ", ZLIB_VERSION,
|
1999-11-29 02:45:23 +00:00
|
|
|
#else /* ZLIB_VERSION */
|
1999-11-29 03:07:19 +00:00
|
|
|
"with libz ", "(version unknown)",
|
1999-11-29 02:45:23 +00:00
|
|
|
#endif /* ZLIB_VERSION */
|
|
|
|
#else /* HAVE_LIBZ */
|
1999-11-29 03:07:19 +00:00
|
|
|
"without libz", "",
|
1999-11-29 02:45:23 +00:00
|
|
|
#endif /* HAVE_LIBZ */
|
1999-11-29 03:07:19 +00:00
|
|
|
|
1999-12-10 06:44:39 +00:00
|
|
|
/* Oh, this is pretty */
|
1999-11-29 03:07:19 +00:00
|
|
|
#if defined(HAVE_UCD_SNMP_SNMP_H)
|
|
|
|
#ifdef HAVE_UCD_SNMP_VERSION_H
|
|
|
|
"with UCD SNMP ", VersionInfo
|
1999-11-29 04:31:05 +00:00
|
|
|
#else /* HAVE_UCD_SNMP_VERSION_H */
|
1999-11-29 03:07:19 +00:00
|
|
|
"with UCD SNMP ", "(version unknown)"
|
1999-11-29 04:31:05 +00:00
|
|
|
#endif /* HAVE_UCD_SNMP_VERSION_H */
|
1999-11-29 03:07:19 +00:00
|
|
|
#elif defined(HAVE_SNMP_SNMP_H)
|
1999-11-29 04:31:05 +00:00
|
|
|
#ifdef HAVE_SNMP_VERSION_H
|
|
|
|
"with CMU SNMP ", snmp_Version()
|
|
|
|
#else /* HAVE_SNMP_VERSION_H */
|
1999-11-29 03:07:19 +00:00
|
|
|
"with CMU SNMP ", "(version unknown)"
|
1999-11-29 04:31:05 +00:00
|
|
|
#endif /* HAVE_SNMP_VERSION_H */
|
|
|
|
#else /* no SNMP */
|
1999-11-29 03:07:19 +00:00
|
|
|
"without SNMP", ""
|
|
|
|
#endif
|
1999-07-07 22:52:57 +00:00
|
|
|
);
|
1998-12-27 20:47:53 +00:00
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
/* Now get our args */
|
2000-06-15 08:02:43 +00:00
|
|
|
while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:vZ:")) != EOF) {
|
1998-09-16 02:39:15 +00:00
|
|
|
switch (opt) {
|
|
|
|
case 'b': /* Bold font */
|
|
|
|
bold_font = g_strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'B': /* Byte view pane height */
|
|
|
|
bv_size = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'c': /* Capture xxx packets */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.count = atoi(optarg);
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
|
|
|
#endif
|
1998-09-16 02:39:15 +00:00
|
|
|
break;
|
2000-01-24 04:44:58 +00:00
|
|
|
case 'D': /* Turn off DSCP printing */
|
|
|
|
g_ip_dscp_actif = FALSE;
|
|
|
|
break;
|
1999-07-13 02:53:26 +00:00
|
|
|
case 'f':
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.cfilter)
|
|
|
|
g_free(cfile.cfilter);
|
|
|
|
cfile.cfilter = g_strdup(optarg);
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
1999-12-07 07:12:49 +00:00
|
|
|
break;
|
1998-09-16 02:39:15 +00:00
|
|
|
case 'h': /* Print help and exit */
|
|
|
|
print_usage();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'i': /* Use interface xxx */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.iface = g_strdup(optarg);
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case 'k': /* Start capture immediately */
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
start_capture = TRUE;
|
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
|
|
|
#endif
|
1998-09-16 02:39:15 +00:00
|
|
|
break;
|
|
|
|
case 'm': /* Medium font */
|
|
|
|
medium_font = g_strdup(optarg);
|
|
|
|
break;
|
|
|
|
case 'n': /* No name resolution */
|
|
|
|
g_resolving_actif = 0;
|
|
|
|
break;
|
|
|
|
case 'P': /* Packet list pane height */
|
|
|
|
pl_size = atoi(optarg);
|
|
|
|
break;
|
1999-05-11 18:51:10 +00:00
|
|
|
case 'Q': /* Quit after capture (just capture to file) */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
1999-05-11 18:51:10 +00:00
|
|
|
quit_after_cap = 1;
|
Add a new global flag "capture_child", which is TRUE if we're a child
process for a sync mode or fork mode capture.
Have that flag control whether we do things that *only* the parent or
*only* the child should do, rather than basing it solely on the setting
of "sync_mode" or "fork_mode" (or, in the case of stuff done in the
child process either in sync mode or fork mode, rather than basing it on
the setting of those flags at all).
Split "do_capture()" into a "run_capture()" routine that starts a
capture (possibly by forking off and execing a child process, if we're
supposed to do sync mode or fork mode captures), and that assumes the
file to which the capture is to write has already been opened and that
"cf.save_file_fd" is the file descriptor for that file, and a
"do_capture()" routine that creates a temporary file, getting an FD for
it, and calls "run_capture()".
Use "run_capture()", rather than "capture()", for "-k" captures, so that
it'll do the capture in a child process if "-S" or "-F" was specified
("do_capture()" won't do because "-k" captures should write to the file
specified by the "-w" flag, not some random temporary file).
For child process captures, however, just use "capture()" - the child
process shouldn't itself fork off a child if we're in sync or fork mode,
and should just write to the file whose file descriptor was specified by
the "-W" flag on the command line.
All this allows you to do "ethereal -S -w <file> -i <interface> -k" to
start a sync mode capture from the command line.
svn path=/trunk/; revision=740
1999-09-30 06:50:01 +00:00
|
|
|
start_capture = TRUE; /*** -Q implies -k !! ***/
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
1999-12-07 07:12:49 +00:00
|
|
|
break;
|
1998-09-16 02:39:15 +00:00
|
|
|
case 'r': /* Read capture file xxx */
|
1999-12-02 08:28:34 +00:00
|
|
|
/* We may set "last_open_dir" to "cf_name", and if we change
|
|
|
|
"last_open_dir" later, we free the old value, so we have to
|
|
|
|
set "cf_name" to something that's been allocated. */
|
Fix bug which occurs when running ethereal with "-r" to load a file, then
loading a new file from within ethereal.
In main(), cf_name was being set to optarg, without g_strdup()'ing it.
Later, in file_open_cmd_cb(), we try to g_free last_open_dir, which is
cf_name, so blammo! We try to g_free something that we can't.
So, in main(), be sure to set cf_name to a g_strdup() of optarg, not
just optarg.
(At home I'm using debug/development versions of glib/gtk, so maybe
that's why I saw the problem only now. I could have sworn that I
have done this sequence of events successfully before).
svn path=/trunk/; revision=1180
1999-12-02 05:25:59 +00:00
|
|
|
cf_name = g_strdup(optarg);
|
1998-09-16 02:39:15 +00:00
|
|
|
break;
|
1999-08-08 01:29:24 +00:00
|
|
|
case 'R': /* Read file filter */
|
1999-08-15 19:18:46 +00:00
|
|
|
rfilter = optarg;
|
1999-08-08 01:29:24 +00:00
|
|
|
break;
|
1998-09-16 02:39:15 +00:00
|
|
|
case 's': /* Set the snapshot (capture) length */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.snap = atoi(optarg);
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
|
|
|
#endif
|
1998-09-16 02:39:15 +00:00
|
|
|
break;
|
1999-05-11 18:51:10 +00:00
|
|
|
case 'S': /* "Sync" mode: used for following file ala tail -f */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
1999-09-23 07:20:20 +00:00
|
|
|
sync_mode = TRUE;
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
1999-12-07 07:12:49 +00:00
|
|
|
break;
|
1998-09-27 22:12:47 +00:00
|
|
|
case 't': /* Time stamp type */
|
|
|
|
if (strcmp(optarg, "r") == 0)
|
|
|
|
timestamp_type = RELATIVE;
|
|
|
|
else if (strcmp(optarg, "a") == 0)
|
|
|
|
timestamp_type = ABSOLUTE;
|
|
|
|
else if (strcmp(optarg, "d") == 0)
|
|
|
|
timestamp_type = DELTA;
|
|
|
|
else {
|
|
|
|
fprintf(stderr, "ethereal: Invalid time stamp type \"%s\"\n",
|
|
|
|
optarg);
|
|
|
|
fprintf(stderr, "It must be \"r\" for relative, \"a\" for absolute,\n");
|
|
|
|
fprintf(stderr, "or \"d\" for delta.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
1998-09-16 02:39:15 +00:00
|
|
|
case 'T': /* Tree view pane height */
|
|
|
|
tv_size = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'v': /* Show version and exit */
|
1998-12-27 20:47:53 +00:00
|
|
|
printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
|
1998-09-16 02:39:15 +00:00
|
|
|
exit(0);
|
|
|
|
break;
|
Add to Wiretap the ability to write capture files; for now, it can only
write them in "libpcap" format, but the mechanism can have other formats
added.
When creating the temporary file for a capture, use "create_tempfile()",
to close a security hole opened by the fact that "tempnam()" creates a
temporary file, but doesn't open it, and we open the file with the name
it gives us - somebody could remove the file and plant a link to some
file, and, if as may well be the case when Ethereal is capturing
packets, it's running as "root", that means we write a capture on top of
that file.... (The aforementioned changes to Wiretap let you open a
capture file for writing given an file descriptor, "fdopen()"-style,
which this change requires.)
svn path=/trunk/; revision=509
1999-08-18 04:17:38 +00:00
|
|
|
case 'w': /* Write to capture file xxx */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
1999-10-02 06:26:53 +00:00
|
|
|
save_file = g_strdup(optarg);
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
|
|
|
#endif
|
1998-09-16 02:39:15 +00:00
|
|
|
break;
|
Add to Wiretap the ability to write capture files; for now, it can only
write them in "libpcap" format, but the mechanism can have other formats
added.
When creating the temporary file for a capture, use "create_tempfile()",
to close a security hole opened by the fact that "tempnam()" creates a
temporary file, but doesn't open it, and we open the file with the name
it gives us - somebody could remove the file and plant a link to some
file, and, if as may well be the case when Ethereal is capturing
packets, it's running as "root", that means we write a capture on top of
that file.... (The aforementioned changes to Wiretap let you open a
capture file for writing given an file descriptor, "fdopen()"-style,
which this change requires.)
svn path=/trunk/; revision=509
1999-08-18 04:17:38 +00:00
|
|
|
case 'W': /* Write to capture file FD xxx */
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.save_file_fd = atoi(optarg);
|
1999-12-07 07:12:49 +00:00
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
1999-07-13 02:53:26 +00:00
|
|
|
#endif
|
1999-12-07 07:12:49 +00:00
|
|
|
break;
|
2000-06-15 08:02:43 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
case 'Z': /* Write to pipe FD XXX */
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
/* associate stdout with pipe */
|
|
|
|
i = atoi(optarg);
|
|
|
|
if (dup2(i, 1) < 0) {
|
|
|
|
fprintf(stderr, "Unable to dup pipe handle\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
capture_option_specified = TRUE;
|
|
|
|
arg_error = TRUE;
|
|
|
|
#endif /* HAVE_LIBPCAP */
|
|
|
|
break;
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
1999-12-07 07:12:49 +00:00
|
|
|
default:
|
1999-10-02 20:00:46 +00:00
|
|
|
case '?': /* Bad flag - print usage message */
|
1999-12-07 07:12:49 +00:00
|
|
|
arg_error = TRUE;
|
1999-10-02 20:00:46 +00:00
|
|
|
break;
|
1998-09-16 02:39:15 +00:00
|
|
|
}
|
|
|
|
}
|
1998-12-29 04:05:38 +00:00
|
|
|
|
1999-12-07 07:12:49 +00:00
|
|
|
#ifndef HAVE_LIBPCAP
|
|
|
|
if (capture_option_specified)
|
|
|
|
fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
|
|
|
|
#endif
|
|
|
|
if (arg_error)
|
|
|
|
print_usage();
|
1999-10-02 19:33:14 +00:00
|
|
|
#ifdef HAVE_LIBPCAP
|
1999-06-15 03:46:46 +00:00
|
|
|
if (start_capture) {
|
2000-01-15 06:05:21 +00:00
|
|
|
/* We're supposed to do a live capture; did the user specify an interface
|
|
|
|
to use? */
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.iface == NULL) {
|
2000-01-16 02:48:12 +00:00
|
|
|
/* No - pick the first one from the list of interfaces. */
|
|
|
|
if_list = get_interface_list(&err, err_str);
|
|
|
|
if (if_list == NULL) {
|
|
|
|
switch (err) {
|
|
|
|
|
|
|
|
case CANT_GET_INTERFACE_LIST:
|
|
|
|
fprintf(stderr, "ethereal: Can't get list of interfaces: %s\n",
|
|
|
|
err_str);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NO_INTERFACES_FOUND:
|
|
|
|
fprintf(stderr, "ethereal: There are no interfaces on which a capture can be done\n");
|
|
|
|
break;
|
|
|
|
}
|
2000-01-15 06:05:21 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.iface = g_strdup(if_list->data); /* first interface */
|
2000-01-16 02:48:12 +00:00
|
|
|
free_interface_list(if_list);
|
1999-06-15 03:46:46 +00:00
|
|
|
}
|
1999-10-02 06:00:07 +00:00
|
|
|
}
|
|
|
|
if (capture_child) {
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.save_file_fd == -1) {
|
1999-10-02 06:00:07 +00:00
|
|
|
/* XXX - send this to the standard output as something our parent
|
|
|
|
should put in an error message box? */
|
|
|
|
fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
|
|
|
|
exit(1);
|
Add to Wiretap the ability to write capture files; for now, it can only
write them in "libpcap" format, but the mechanism can have other formats
added.
When creating the temporary file for a capture, use "create_tempfile()",
to close a security hole opened by the fact that "tempnam()" creates a
temporary file, but doesn't open it, and we open the file with the name
it gives us - somebody could remove the file and plant a link to some
file, and, if as may well be the case when Ethereal is capturing
packets, it's running as "root", that means we write a capture on top of
that file.... (The aforementioned changes to Wiretap let you open a
capture file for writing given an file descriptor, "fdopen()"-style,
which this change requires.)
svn path=/trunk/; revision=509
1999-08-18 04:17:38 +00:00
|
|
|
}
|
1999-06-15 03:46:46 +00:00
|
|
|
}
|
1999-10-02 06:00:07 +00:00
|
|
|
#endif
|
1999-06-15 03:46:46 +00:00
|
|
|
|
1998-12-29 04:05:38 +00:00
|
|
|
/* Build the column format array */
|
2000-06-27 04:36:03 +00:00
|
|
|
for (i = 0; i < cfile.cinfo.num_cols; i++) {
|
|
|
|
cfile.cinfo.col_fmt[i] = get_column_format(i);
|
|
|
|
cfile.cinfo.col_title[i] = g_strdup(get_column_title(i));
|
|
|
|
cfile.cinfo.fmt_matx[i] = (gboolean *) g_malloc0(sizeof(gboolean) *
|
1998-12-29 04:05:38 +00:00
|
|
|
NUM_COL_FMTS);
|
2000-06-27 04:36:03 +00:00
|
|
|
get_column_format_matches(cfile.cinfo.fmt_matx[i], cfile.cinfo.col_fmt[i]);
|
|
|
|
if (cfile.cinfo.col_fmt[i] == COL_INFO)
|
|
|
|
cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_INFO_LEN);
|
1999-10-15 20:33:06 +00:00
|
|
|
else
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.cinfo.col_data[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
|
1998-12-29 04:05:38 +00:00
|
|
|
}
|
|
|
|
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.snap < 1)
|
|
|
|
cfile.snap = WTAP_MAX_PACKET_SIZE;
|
|
|
|
else if (cfile.snap < MIN_PACKET_SIZE)
|
|
|
|
cfile.snap = MIN_PACKET_SIZE;
|
1998-09-16 02:39:15 +00:00
|
|
|
|
2000-01-29 16:41:28 +00:00
|
|
|
rc_file = (gchar *) g_malloc(strlen(get_home_dir()) + strlen(RC_FILE) + 4);
|
|
|
|
sprintf(rc_file, "%s/%s", get_home_dir(), RC_FILE);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_rc_parse(rc_file);
|
|
|
|
|
|
|
|
if ((m_r_font = gdk_font_load(medium_font)) == NULL) {
|
1999-06-15 03:46:46 +00:00
|
|
|
fprintf(stderr, "ethereal: Error font %s not found (use -m option)\n", medium_font);
|
1998-09-16 02:39:15 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_b_font = gdk_font_load(bold_font)) == NULL) {
|
1999-06-15 03:46:46 +00:00
|
|
|
fprintf(stderr, "ethereal: Error font %s not found (use -b option)\n", bold_font);
|
1998-09-16 02:39:15 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2000-01-15 12:54:24 +00:00
|
|
|
create_main_window(pl_size, tv_size, bv_size, prefs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Hmmm should we do it here
|
|
|
|
*/
|
|
|
|
|
2000-04-04 07:03:07 +00:00
|
|
|
dissect_init(); /* Init anything that needs initializing */
|
2000-01-15 12:54:24 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
/* Is this a "child" ethereal, which is only supposed to pop up a
|
|
|
|
capture box to let us stop the capture, and run a capture
|
|
|
|
to a file that our parent will read? */
|
|
|
|
if (!capture_child) {
|
|
|
|
#endif
|
|
|
|
/* No. Pop up the main window, and read in a capture file if
|
|
|
|
we were told to. */
|
|
|
|
|
|
|
|
gtk_widget_show(top_level);
|
2000-01-25 13:44:39 +00:00
|
|
|
set_menus_for_capture_file(FALSE);
|
2000-01-15 12:54:24 +00:00
|
|
|
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.colors = colfilter_new();
|
2000-01-15 12:54:24 +00:00
|
|
|
|
|
|
|
/* If we were given the name of a capture file, read it in now;
|
|
|
|
we defer it until now, so that, if we can't open it, and pop
|
|
|
|
up an alert box, the alert box is more likely to come up on
|
|
|
|
top of the main window - but before the preference-file-error
|
|
|
|
alert box, so, if we get one of those, it's more likely to come
|
|
|
|
up on top of us. */
|
|
|
|
if (cf_name) {
|
|
|
|
if (rfilter != NULL) {
|
|
|
|
if (dfilter_compile(rfilter, &rfcode) != 0) {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL, dfilter_error_msg);
|
|
|
|
rfilter_parse_failed = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!rfilter_parse_failed) {
|
2000-06-27 04:36:03 +00:00
|
|
|
if ((err = open_cap_file(cf_name, FALSE, &cfile)) == 0) {
|
2000-01-15 12:54:24 +00:00
|
|
|
/* "open_cap_file()" succeeded, so it closed the previous
|
|
|
|
capture file, and thus destroyed any previous read filter
|
|
|
|
attached to "cf". */
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.rfcode = rfcode;
|
|
|
|
err = read_cap_file(&cfile);
|
2000-01-25 05:48:47 +00:00
|
|
|
/* Save the name of the containing directory specified in the
|
|
|
|
path name, if any; we can write over cf_name, which is a
|
|
|
|
good thing, given that "get_dirname()" does write over its
|
|
|
|
argument. */
|
|
|
|
s = get_dirname(cf_name);
|
|
|
|
if (s != NULL)
|
|
|
|
last_open_dir = s;
|
2000-01-15 12:54:24 +00:00
|
|
|
} else {
|
|
|
|
dfilter_destroy(rfcode);
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.rfcode = NULL;
|
2000-01-15 12:54:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If we failed to open the preferences file, pop up an alert box;
|
|
|
|
we defer it until now, so that the alert box is more likely to
|
|
|
|
come up on top of the main window. */
|
|
|
|
if (pf_path != NULL) {
|
|
|
|
simple_dialog(ESD_TYPE_WARN, NULL,
|
|
|
|
"Could not open preferences file\n\"%s\": %s.", pf_path,
|
|
|
|
strerror(pf_open_errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
if (capture_child) {
|
|
|
|
/* This is the child process for a sync mode or fork mode capture,
|
|
|
|
so just do the low-level work of a capture - don't create
|
|
|
|
a temporary file and fork off *another* child process (so don't
|
|
|
|
call "do_capture()"). */
|
|
|
|
|
|
|
|
capture();
|
|
|
|
|
|
|
|
/* The capture is done; there's nothing more for us to do. */
|
|
|
|
gtk_exit(0);
|
|
|
|
} else {
|
|
|
|
if (start_capture) {
|
|
|
|
/* "-k" was specified; start a capture. */
|
|
|
|
do_capture(save_file);
|
|
|
|
}
|
2000-01-25 13:44:39 +00:00
|
|
|
else {
|
Exit from Ethereal by making the main loop exit, so that any quit
routines we register get called.
Register the "follow TCP stream" windows with "gtk_quit_add_destroy()",
so that, when Ethereal exits, they all get destroyed; this means that
their destroy callbacks get called, which means that they get to delete
their temporary files, so that, if you exit Ethereal without manually
closing the "follow TCP stream" windows, the temporary files don't get
left around.
Exit from Ethereal's "main()" function by calling "gtk_exit()", rather
than "exit()", so that we do whatever cleanup GTK+ requires. (We used
to call "gtk_exit()" in the callback for the "File:Quit" menu item and
the "delete" callback for the main window, but we now just call
"gtk_main_quit()" so that we exit from the main loop.)
svn path=/trunk/; revision=1772
2000-04-01 10:23:01 +00:00
|
|
|
set_menus_for_capture_in_progress(FALSE);
|
2000-01-25 13:44:39 +00:00
|
|
|
}
|
2000-01-15 12:54:24 +00:00
|
|
|
}
|
2000-01-25 17:57:31 +00:00
|
|
|
#else
|
|
|
|
set_menus_for_capture_in_progress(FALSE);
|
2000-01-15 12:54:24 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
|
2000-04-04 07:03:07 +00:00
|
|
|
dissect_cleanup();
|
2000-01-15 12:54:24 +00:00
|
|
|
g_free(rc_file);
|
|
|
|
|
Exit from Ethereal by making the main loop exit, so that any quit
routines we register get called.
Register the "follow TCP stream" windows with "gtk_quit_add_destroy()",
so that, when Ethereal exits, they all get destroyed; this means that
their destroy callbacks get called, which means that they get to delete
their temporary files, so that, if you exit Ethereal without manually
closing the "follow TCP stream" windows, the temporary files don't get
left around.
Exit from Ethereal's "main()" function by calling "gtk_exit()", rather
than "exit()", so that we do whatever cleanup GTK+ requires. (We used
to call "gtk_exit()" in the callback for the "File:Quit" menu item and
the "delete" callback for the main window, but we now just call
"gtk_main_quit()" so that we exit from the main loop.)
svn path=/trunk/; revision=1772
2000-04-01 10:23:01 +00:00
|
|
|
gtk_exit(0);
|
|
|
|
|
|
|
|
/* This isn't reached, but we need it to keep GCC from complaining
|
|
|
|
that "main()" returns without returning a value - it knows that
|
|
|
|
"exit()" never returns, but it doesn't know that "gtk_exit()"
|
|
|
|
doesn't, as GTK+ doesn't declare it with the attribute
|
|
|
|
"noreturn". */
|
|
|
|
return 0; /* not reached */
|
2000-01-15 12:54:24 +00:00
|
|
|
}
|
|
|
|
|
On Win32, build Ethereal as a Windows-subsystem program rather than a
console-subsystem program, so that when not run from a shell window it
doesn't cause a shell window to be popped up. (Yes, this means that any
messages it prints, when not popped up from a shell window, get lost,
but the same is true of Ethereal on UNIX/X.) Trick for doing this
shamelessly stolen from the Win32 port of the GIMP.
We do not want to build Tethereal or editcap as Windows-subsystem
programs, however, so we take the "/SUBSYSTEM" flag out of LDFLAGS and
put it into the link commands for Ethereal, Tethereal, and editcap.
svn path=/trunk/; revision=1857
2000-04-14 09:00:25 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
|
|
|
|
/* We build this as a GUI subsystem application on Win32, so
|
|
|
|
"WinMain()", not "main()", gets called.
|
|
|
|
|
|
|
|
Hack shamelessly stolen from the Win32 port of the GIMP. */
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#define _stdcall __attribute__((stdcall))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int _stdcall
|
|
|
|
WinMain (struct HINSTANCE__ *hInstance,
|
|
|
|
struct HINSTANCE__ *hPrevInstance,
|
|
|
|
char *lpszCmdLine,
|
|
|
|
int nCmdShow)
|
|
|
|
{
|
|
|
|
return main (__argc, __argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2000-01-15 12:54:24 +00:00
|
|
|
static void
|
|
|
|
create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
|
|
|
|
{
|
|
|
|
GtkWidget *main_vbox, *menubar, *u_pane, *l_pane,
|
2000-02-29 06:24:41 +00:00
|
|
|
*stat_hbox,
|
2000-01-15 12:54:24 +00:00
|
|
|
*filter_bt, *filter_cm, *filter_te,
|
|
|
|
*filter_reset;
|
|
|
|
GList *filter_list = NULL;
|
|
|
|
GtkStyle *pl_style;
|
|
|
|
GtkAccelGroup *accel;
|
|
|
|
int i;
|
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
/* Main window */
|
1999-12-09 07:19:20 +00:00
|
|
|
top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
gtk_widget_set_name(top_level, "main window");
|
There's no need to catch the "delete_event" signal on "Follow TCP
Stream" windows - the window should always be deleted in that situation,
so there's no need for a signal handler that might return TRUE (meaning
"don't delete the window"), and the "destroy" handler gets called when
the window actually gets destroyed, so there's no need to do any cleanup
in the "delete_event" handler.
Catch the "delete_event" signal on the main window in a routine with the
right signature, and that returns FALSE so that the window actually gets
deleted.
Call "close_cap_file()" in the callback for the "File:Quit" menu item
(which is also called by the "delete_event" handler for the main
window), rather than calling it after "gtk_main()" returns -
"close_cap_file()" manipulates stuff in the main window, and if we do so
after "gtk_main()" returns, it appears that the main window may have
disappeared (if we are exiting because the user deleted the main
window), in which case we can get crashes or other errors when
"close_cap_file()" tries to manipulate stuff in the main window.
There's no need to catch the "destroy" signal on the main window - we do
some of the cleanup in the handler for "delete_event" (we have to, for
reasons described above), and we do the rest of it after the main
routine returns.
svn path=/trunk/; revision=1773
2000-04-01 11:30:53 +00:00
|
|
|
gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
|
|
|
|
GTK_SIGNAL_FUNC(main_window_delete_event_cb), NULL);
|
1999-12-09 07:19:20 +00:00
|
|
|
gtk_window_set_title(GTK_WINDOW(top_level), "The Ethereal Network Analyzer");
|
|
|
|
gtk_widget_set_usize(GTK_WIDGET(top_level), DEF_WIDTH, -1);
|
|
|
|
gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
|
1998-09-16 02:39:15 +00:00
|
|
|
|
|
|
|
/* Container for menu bar, paned windows and progress/info box */
|
|
|
|
main_vbox = gtk_vbox_new(FALSE, 1);
|
|
|
|
gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
|
1999-12-09 07:19:20 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_widget_show(main_vbox);
|
|
|
|
|
|
|
|
/* Menu bar */
|
|
|
|
get_main_menu(&menubar, &accel);
|
1999-12-09 07:19:20 +00:00
|
|
|
gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
|
|
|
|
gtk_widget_show(menubar);
|
|
|
|
|
|
|
|
/* Panes for the packet list, tree, and byte view */
|
|
|
|
u_pane = gtk_vpaned_new();
|
1998-10-12 01:40:57 +00:00
|
|
|
gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
|
1998-09-16 02:39:15 +00:00
|
|
|
l_pane = gtk_vpaned_new();
|
1998-10-12 01:40:57 +00:00
|
|
|
gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_widget_show(l_pane);
|
2000-02-29 06:24:41 +00:00
|
|
|
gtk_paned_add2(GTK_PANED(u_pane), l_pane);
|
|
|
|
gtk_widget_show(u_pane);
|
1998-09-16 02:39:15 +00:00
|
|
|
|
|
|
|
/* Packet list */
|
1999-12-16 06:20:18 +00:00
|
|
|
pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
|
1999-12-13 04:20:33 +00:00
|
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
2000-03-02 07:05:57 +00:00
|
|
|
set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
|
|
|
|
remember_scrolled_window(pkt_scrollw);
|
1999-12-16 06:20:18 +00:00
|
|
|
gtk_widget_show(pkt_scrollw);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
|
|
|
|
|
2000-06-27 04:36:03 +00:00
|
|
|
packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
|
1999-12-16 06:20:18 +00:00
|
|
|
gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
|
2000-05-10 06:00:22 +00:00
|
|
|
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
set_plist_sel_browse(prefs->gui_plist_sel_browse);
|
1998-09-16 02:39:15 +00:00
|
|
|
pl_style = gtk_style_new();
|
|
|
|
gdk_font_unref(pl_style->font);
|
|
|
|
pl_style->font = m_r_font;
|
|
|
|
gtk_widget_set_style(packet_list, pl_style);
|
|
|
|
gtk_widget_set_name(packet_list, "packet list");
|
2000-05-10 06:00:22 +00:00
|
|
|
gtk_signal_connect (GTK_OBJECT (packet_list), "click_column",
|
|
|
|
GTK_SIGNAL_FUNC(packet_list_click_column_cb), NULL);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_signal_connect(GTK_OBJECT(packet_list), "select_row",
|
|
|
|
GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
|
|
|
|
GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
|
2000-06-27 04:36:03 +00:00
|
|
|
for (i = 0; i < cfile.cinfo.num_cols; i++) {
|
|
|
|
if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
|
1999-07-28 03:29:02 +00:00
|
|
|
gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
|
|
|
|
|
|
|
|
/* Right-justify the packet number column. */
|
2000-06-27 04:36:03 +00:00
|
|
|
if (cfile.cinfo.col_fmt[i] == COL_NUMBER)
|
1998-11-17 04:29:13 +00:00
|
|
|
gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
|
|
|
|
GTK_JUSTIFY_RIGHT);
|
1999-07-28 03:29:02 +00:00
|
|
|
|
|
|
|
/* Save static column sizes to use during a "-S" capture, so that
|
|
|
|
the columns don't resize during a live capture. */
|
2000-06-27 04:36:03 +00:00
|
|
|
cfile.cinfo.col_width[i] = gdk_string_width(pl_style->font,
|
2000-01-10 01:44:00 +00:00
|
|
|
get_column_longest_string(get_column_format(i)));
|
1998-11-17 04:29:13 +00:00
|
|
|
}
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_widget_set_usize(packet_list, -1, pl_size);
|
2000-01-18 08:38:18 +00:00
|
|
|
gtk_signal_connect_object(GTK_OBJECT(packet_list), "button_press_event",
|
|
|
|
GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
|
2000-05-10 06:00:22 +00:00
|
|
|
gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_widget_show(packet_list);
|
1999-12-30 23:02:56 +00:00
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
/* Tree view */
|
2000-03-02 07:05:57 +00:00
|
|
|
create_tree_view(tv_size, prefs, l_pane, &tv_scrollw, &tree_view,
|
|
|
|
prefs->gui_scrollbar_on_right);
|
Changed the protocol tree widget from a GtkTree to a GtkCTree. The two reasons
I did this:
First, Havoc Pennington, in "GTK+/Gnome Application Development", in
Appendix seciton A.3.88, recommends using GtkCTree instead of GtkTree
because GtkCtree is faster, and GtkTree has limitation on its total row
height: since it must fit inside a GdkWindow, it is limited to 32,768
pixels of height. GtkTree is more flexible with regards to the types of
widgets that can be placed in the tree, but since we deal only with text,
that doesn't matter, at least for now.
Secondly, a GtkTree doesn't allow arrow-key navigation (at least as far
as I could tell). It always bothered me that the up and down arrow keys
worked in the packet list and in the hex dump, but no in the protocol tree.
GtkCTree does allow arrow-key navigation. In fact, GtkCTree is a subclass
of GtkCList (the packet list widget), so they behave a lot alike.
I went ahead and fixed the selection bar which has been bothering Richard
for a long time now. :) In the GUI preferences dialogue, you can now set
both the packet list selection bar and the protocol tree selection bar
to either "browse" or "select" mode. "browse" mode is what you're used to:
the arrow keys move an outline of the selection bar, but do not change
the selection. "select" mode does change the selection when the arrow keys
are pressed. The default behavior is set to "select", which seems more
natural for a first-time user.
svn path=/trunk/; revision=1393
1999-12-29 20:10:12 +00:00
|
|
|
gtk_signal_connect(GTK_OBJECT(tree_view), "tree-select-row",
|
|
|
|
GTK_SIGNAL_FUNC(tree_view_select_row_cb), NULL);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(tree_view), "tree-unselect-row",
|
|
|
|
GTK_SIGNAL_FUNC(tree_view_unselect_row_cb), NULL);
|
2000-01-18 08:38:18 +00:00
|
|
|
gtk_signal_connect_object(GTK_OBJECT(tree_view), "button_press_event",
|
|
|
|
GTK_SIGNAL_FUNC(popup_menu_handler), gtk_object_get_data(GTK_OBJECT(popup_menu_object), PM_TREE_VIEW_KEY));
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_widget_show(tree_view);
|
|
|
|
|
1998-12-29 04:05:38 +00:00
|
|
|
item_style = gtk_style_new();
|
|
|
|
gdk_font_unref(item_style->font);
|
|
|
|
item_style->font = m_r_font;
|
|
|
|
|
2000-02-29 06:24:41 +00:00
|
|
|
/* Byte view. */
|
2000-03-02 07:05:57 +00:00
|
|
|
create_byte_view(bv_size, l_pane, &byte_view, &bv_scrollw,
|
|
|
|
prefs->gui_scrollbar_on_right);
|
1999-12-16 06:20:18 +00:00
|
|
|
|
1998-10-12 01:40:57 +00:00
|
|
|
/* Progress/filter/info box */
|
1998-09-16 02:39:15 +00:00
|
|
|
stat_hbox = gtk_hbox_new(FALSE, 1);
|
|
|
|
gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
|
|
|
|
gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
|
|
|
|
gtk_widget_show(stat_hbox);
|
|
|
|
|
1999-09-22 01:26:50 +00:00
|
|
|
prog_bar = gtk_progress_bar_new();
|
1998-10-12 01:40:57 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 3);
|
1998-09-16 02:39:15 +00:00
|
|
|
gtk_widget_show(prog_bar);
|
|
|
|
|
1998-10-12 01:40:57 +00:00
|
|
|
filter_bt = gtk_button_new_with_label("Filter:");
|
|
|
|
gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
|
Split "filter_dialog_cb()" into "filter_dialog_cb()", which pops up a
"global" dialog box when "Edit:Filters" is selected, so that the list of
filters can be edited, and "filter_browse_cb()", which pops up a dialog
box associated with a "Filter:" button and a text entry widget attached
to that button, so that a filter can be selected or saved (although it
also supports the same editing that the "global" dialog box does).
Have "filter_dialog_cb()" connect the window in which the "Filter:"
button lives and the filter dialog box, so that:
if the window in which the "Filter:" button lives goes away, so
does the filter dialog box (as it no longer has a text widget
into which it can stuff the selected filter);
if the "Filter:" button is clicked when there's already a filter
dialog box open, we just reactivate that existing dialog box
rather than popping up a new one.
Also keep a pointer to the "global" filter dialog box, so that we also
arrange that there's only one of them (by reactivating the existing on
if "Edit:Filters" is selected when there's already a "global" filter
dialog box open).
Keep around pointers to the dialog boxes that contain the "Filter:"
buttons, so that we can arrange that there be only one of them (that was
a side-effect of an earlier attempt at fixing the problems described
above, but it's still useful for keeping multiple competing dialog boxes
from being open - there's more of that to be done).
Make the pointer to the "Open Capture File" dialog box widget static to
"file_dlg.c" - nobody outside of "file_dlg.c cares about it.
svn path=/trunk/; revision=1774
2000-04-01 12:03:42 +00:00
|
|
|
GTK_SIGNAL_FUNC(filter_browse_cb), NULL);
|
1998-10-12 01:40:57 +00:00
|
|
|
gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
|
|
|
|
gtk_widget_show(filter_bt);
|
|
|
|
|
1999-11-25 18:02:25 +00:00
|
|
|
filter_cm = gtk_combo_new();
|
|
|
|
filter_list = g_list_append (filter_list, "");
|
|
|
|
gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list);
|
|
|
|
gtk_combo_disable_activate(GTK_COMBO(filter_cm));
|
|
|
|
filter_te = GTK_COMBO(filter_cm)->entry;
|
1998-10-12 01:40:57 +00:00
|
|
|
gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
|
1999-11-25 18:02:25 +00:00
|
|
|
gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_CM_KEY, filter_cm);
|
|
|
|
gtk_object_set_data(GTK_OBJECT(filter_te), E_DFILTER_FL_KEY, filter_list);
|
|
|
|
gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3);
|
1999-07-11 08:40:52 +00:00
|
|
|
gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
|
|
|
|
GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
|
1999-11-25 18:02:25 +00:00
|
|
|
gtk_widget_show(filter_cm);
|
1998-11-18 03:17:18 +00:00
|
|
|
|
1999-11-21 15:06:07 +00:00
|
|
|
filter_reset = gtk_button_new_with_label("Reset");
|
|
|
|
gtk_object_set_data(GTK_OBJECT(filter_reset), E_DFILTER_TE_KEY, filter_te);
|
|
|
|
gtk_signal_connect(GTK_OBJECT(filter_reset), "clicked",
|
|
|
|
GTK_SIGNAL_FUNC(filter_reset_cb), (gpointer) NULL);
|
|
|
|
gtk_box_pack_start(GTK_BOX(stat_hbox), filter_reset, FALSE, TRUE, 1);
|
|
|
|
gtk_widget_show(filter_reset);
|
|
|
|
|
1999-08-20 19:43:10 +00:00
|
|
|
/* Sets the text entry widget pointer as the E_DILTER_TE_KEY data
|
|
|
|
* of any widget that ends up calling a callback which needs
|
|
|
|
* that text entry pointer */
|
1999-06-15 04:48:57 +00:00
|
|
|
set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
|
1999-07-27 02:04:38 +00:00
|
|
|
set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
|
1999-12-10 06:28:24 +00:00
|
|
|
set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
|
1999-11-26 05:23:40 +00:00
|
|
|
set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY, filter_te);
|
|
|
|
set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY, filter_te);
|
1999-08-20 19:43:10 +00:00
|
|
|
|
1998-09-16 02:39:15 +00:00
|
|
|
info_bar = gtk_statusbar_new();
|
|
|
|
main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
|
|
|
|
file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
|
|
|
|
gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
|
|
|
|
gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show(info_bar);
|
|
|
|
}
|