/* main.c
*
- * $Id: main.c,v 1.32 1999/11/06 06:27:07 guy Exp $
+ * $Id: main.c,v 1.96 2000/01/25 04:44:33 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
*
* To do:
* - Graphs
- * - Get AIX to work
* - Check for end of packet in dissect_* routines.
* - Playback window
* - Multiple window support
* - Add cut/copy/paste
* - Create header parsing routines
- * - Make byte view scrollbars automatic?
* - Make byte view selections more fancy?
*
*/
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef HAVE_IO_H
+#include <io.h> /* open/close on win32 */
+#endif
+
#ifdef HAVE_DIRECT_H
#include <direct.h>
#endif
# include "snprintf.h"
#endif
+#if defined(HAVE_UCD_SNMP_SNMP_H)
+#ifdef HAVE_UCD_SNMP_VERSION_H
+#include <ucd-snmp/version.h>
+#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 */
+
#ifdef NEED_STRERROR_H
#include "strerror.h"
#endif
#include "resolv.h"
#include "follow.h"
#include "util.h"
+#include "simple_dialog.h"
#include "proto_draw.h"
#include "dfilter.h"
#include "keys.h"
+#include "gtkglobals.h"
+#include "plugins.h"
FILE *data_out_file = NULL;
packet_info pi;
capture_file cf;
-GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar,
- *info_bar;
+GtkWidget *top_level, *file_sel, *packet_list, *tree_view, *byte_view,
+ *prog_bar, *info_bar, *tv_scrollw, *pkt_scrollw;
+static GtkWidget *bv_vscroll_left, *bv_vscroll_right;
GdkFont *m_r_font, *m_b_font;
guint main_ctx, file_ctx;
gchar comp_info_str[256];
GtkStyle *item_style;
-/* Specifies byte offsets for object selected in tree */
-static gint tree_selected_start=-1, tree_selected_len=-1;
+/* Specifies the field currently selected in the GUI protocol tree */
+field_info *finfo_selected = NULL;
static void follow_destroy_cb(GtkWidget *win, gpointer data);
static void follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w);
-static void follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii);
+static void follow_load_text(GtkWidget *text, char *filename, guint8 show_type);
static void follow_print_stream(GtkWidget *w, gpointer parent_w);
+static char* hfinfo_numeric_format(header_field_info *hfinfo);
+static void create_main_window(gint, gint, gint, e_prefs*);
/* About Ethereal window */
void
about_ethereal( GtkWidget *w, gpointer data ) {
simple_dialog(ESD_TYPE_INFO, NULL,
- "GNU Ethereal - network protocol analyzer\n"
- "Version %s (C) 1998 Gerald Combs <gerald@zing.org>\n"
+ "Ethereal - Network Protocol Analyzer\n"
+ "Version " VERSION " (C) 1998-2000 Gerald Combs <gerald@zing.org>\n"
"Compiled with %s\n\n"
- "Contributors:\n"
-
- "Gilbert Ramirez <gramirez@tivoli.com>\n"
- "Hannes R. Boehm <hannes@boehm.org>\n"
- "Mike Hall <mlh@io.com>\n"
- "Bobo Rajec <bobo@bsp-consulting.sk>\n"
- "Laurent Deniel <deniel@worldnet.fr>\n"
- "Don Lafontaine <lafont02@cn.ca>\n"
- "Guy Harris <guy@netapp.com>\n"
- "Simon Wilkinson <sxw@dcs.ed.ac.uk>\n"
- "Joerg Mayer <jmayer@telemation.de>\n"
- "Martin Maciaszek <fastjack@i-s-o.net>\n"
- "Didier Jorand <Didier.Jorand@alcatel.fr>\n"
- "Jun-ichiro itojun Hagino <itojun@iijlab.net>\n"
- "Richard Sharpe <sharpe@ns.aus.com>\n"
- "John McDermott <jjm@jkintl.com>\n"
- "Jeff Jahr <jjahr@shastanets.com>\n"
- "Brad Robel-Forrest <bradr@watchguard.com>\n"
- "Ashok Narayanan <ashokn@cisco.com>\n"
- "Aaron Hillegass <aaron@classmax.com>\n"
- "Jason Lango <jal@netapp.com>\n"
- "Johan Feyaerts <Johan.Feyaerts@siemens.atea.be>\n"
- "Olivier Abad <abad@daba.dhis.org>\n"
- "Thierry Andry <Thierry.Andry@advalvas.be>\n"
- "Jeff Foster <jfoste@woodward.com>\n"
- "Peter Torvals <petertv@xoommail.com>\n"
- "Christophe Tronche <ch.tronche@computer.org>\n"
- "Nathan Neulinger <nneul@umr.edu>\n"
- "Tomislav Vujec <tvujec@carnet.hr>\n"
- "Kojak <kojak@bigwig.net>\n"
- "Uwe Girlich <Uwe.Girlich@philosys.de>\n"
- "Warren Young <tangent@mail.com>\n"
-
- "\nSee http://ethereal.zing.org for more information",
- VERSION, comp_info_str);
+
+ "Check the man page for complete documentation and\n"
+ "for the list of contributors.\n"
+
+ "\nSee http://ethereal.zing.org/ for more information.",
+ comp_info_str);
}
/* Follow the TCP stream, if any, to which the last packet that we called
void
follow_stream_cb( GtkWidget *w, gpointer data ) {
char filename1[128+1];
- GtkWidget *streamwindow, *box, *text, *vscrollbar, *table;
- GtkWidget *hbox, *close_bt, *print_bt, *button;
+ GtkWidget *streamwindow, *box, *text, *vscrollbar, *table,
+ *filter_te;
+ GtkWidget *hbox, *close_bt, *print_bt;
+ GtkWidget *b_ascii, *b_ebcdic, *b_hexdump;
int tmp_fd;
gchar *follow_filter;
reset_tcp_reassembly();
follow_filter = build_follow_filter( &pi );
+ /* 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);
+
/* Run the display filter so it goes in effect. */
filter_packets(&cf, follow_filter);
/* the filename1 file now has all the text that was in the session */
streamwindow = gtk_window_new( GTK_WINDOW_TOPLEVEL);
gtk_widget_set_name( streamwindow, "TCP stream window" );
-/* gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
- NULL, "WM destroy" );
- gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
- NULL, "WM destroy" );*/
+
gtk_signal_connect( GTK_OBJECT(streamwindow), "delete_event",
GTK_SIGNAL_FUNC(follow_destroy_cb), NULL);
gtk_signal_connect( GTK_OBJECT(streamwindow), "destroy",
gtk_widget_show(hbox);
#define E_FOLLOW_ASCII_KEY "follow_ascii_key"
+#define E_FOLLOW_EBCDIC_KEY "follow_ebcdic_key"
+#define E_FOLLOW_HEXDUMP_KEY "follow_hexdump_key"
/* Create Radio Buttons */
- button = gtk_radio_button_new_with_label(NULL, "ASCII");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
- gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_ASCII_KEY, button);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_signal_connect(GTK_OBJECT(button), "toggled",
+ 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",
GTK_SIGNAL_FUNC(follow_charset_toggle_cb),
GTK_OBJECT(streamwindow));
- gtk_widget_show(button);
+ gtk_widget_show(b_ascii);
- button = gtk_radio_button_new_with_label(
- gtk_radio_button_group(GTK_RADIO_BUTTON(button)),
+ b_ebcdic = gtk_radio_button_new_with_label(
+ gtk_radio_button_group(GTK_RADIO_BUTTON(b_ascii)),
"EBCDIC");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
- gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
- gtk_widget_show(button);
+ 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);
/* Create Close Button */
close_bt = gtk_button_new_with_label("Close");
g_strdup(filename1));
gtk_object_set_data(GTK_OBJECT(streamwindow), E_FOLLOW_TEXT_KEY, text);
- follow_load_text(text, filename1, TRUE);
+ follow_load_text(text, filename1, 0);
data_out_file = NULL;
gtk_widget_show( streamwindow );
gtk_widget_destroy(win);
}
+#define E_FOLLOW_ASCII_TYPE 0
+#define E_FOLLOW_EBCDIC_TYPE 1
+#define E_FOLLOW_HEXDUMP_TYPE 2
+
/* Handles the ASCII/EBCDIC toggling */
static void
follow_charset_toggle_cb(GtkWidget *w, gpointer parent_w)
{
- gboolean show_ascii = FALSE;
- GtkWidget *button, *text;
+ guint8 show_type = E_FOLLOW_ASCII_TYPE;
+ GtkWidget *b_ascii, *b_ebcdic, *b_hexdump, *text;
char *filename;
-
- button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
- E_FOLLOW_ASCII_KEY);
+ 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);
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);
- g_assert(button);
+ g_assert(b_ascii);
+ g_assert(b_ebcdic);
+ g_assert(b_hexdump);
g_assert(text);
g_assert(filename);
- if (GTK_TOGGLE_BUTTON(button)->active)
- show_ascii = TRUE;
+ 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;
+
+ follow_load_text(text, filename, show_type);
+}
+
+#define FLT_BUF_SIZE 1024
+static void
+follow_read_stream(char *filename, guint8 show_type,
+ void (*print_line)(char *, int, gboolean, void *), void *arg)
+{
+ tcp_stream_chunk sc;
+ int bcount;
+ guint32 client_addr = 0;
+ guint16 client_port = 0;
+ gboolean is_server;
+ guint16 current_pos, global_client_pos = 0, global_server_pos = 0;
+ guint16 *global_pos;
+
+ data_out_file = fopen( filename, "r" );
+ 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;
+ }
+ 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;
+ }
+
+ 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;
+ 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:
+ /* If our native arch is EBCDIC, call:
+ * ASCII_TO_EBCDIC(buffer, nchars);
+ */
+ (*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;
+ }
+ }
+ }
+ if( ferror( data_out_file ) ) {
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Error reading temporary file %s: %s", filename, strerror(errno));
+ }
+ fclose( data_out_file );
+ } 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)
+{
+ FILE *fh = arg;
- follow_load_text(text, filename, show_ascii);
+ fwrite(buffer, nchars, 1, fh);
}
-static void follow_print_stream(GtkWidget *w, gpointer parent_w)
+static void
+follow_print_stream(GtkWidget *w, gpointer parent_w)
{
- FILE *fh = NULL;
- int to_file = -1;
- char* print_dest = NULL;
+ FILE *fh;
+ gboolean to_file;
+ char* print_dest;
char* filename;
+ guint8 show_type = E_FOLLOW_ASCII_TYPE;
+ GtkWidget *button;
switch (prefs.pr_dest) {
case PR_DEST_CMD:
print_dest = prefs.pr_file;
to_file = TRUE;
break;
+ default: /* "Can't happen" */
+ simple_dialog(ESD_TYPE_WARN, NULL,
+ "Couldn't figure out where to send the print "
+ "job. Check your preferences.");
+ return;
}
- if (print_dest != NULL) {
- fh = open_print_dest(to_file, print_dest);
- }
-
+ fh = open_print_dest(to_file, print_dest);
if (fh == NULL) {
switch (to_file) {
- case -1:
- simple_dialog(ESD_TYPE_WARN, NULL,
- "Couldn't figure out where to send the print "
- "job. Check your preferences.");
- break;
-
case FALSE:
simple_dialog(ESD_TYPE_WARN, NULL,
"Couldn't run print command %s.", prefs.pr_cmd);
return;
}
+ button = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(parent_w),
+ 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);
+ if (GTK_TOGGLE_BUTTON(button)->active)
+ show_type = E_FOLLOW_HEXDUMP_TYPE;
+
filename = (char*) gtk_object_get_data(GTK_OBJECT(parent_w),
E_FOLLOW_FILENAME_KEY);
if (filename != NULL) {
- print_preamble(fh);
- print_file(fh, filename);
- print_finale(fh);
+ print_preamble(fh, PR_FMT_TEXT);
+ follow_read_stream(filename, show_type, follow_print_text, fh);
+ print_finale(fh, PR_FMT_TEXT);
close_print_dest(to_file, fh);
}
else {
}
static void
-follow_load_text(GtkWidget *text, char *filename, gboolean show_ascii)
+follow_add_to_gtk_text(char *buffer, int nchars, gboolean is_server, void *arg)
{
- int bytes_already;
+ GtkWidget *text = arg;
- /* 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);
- }
+ 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 );
+}
- /* stop the updates while we fill the text box */
- gtk_text_freeze( GTK_TEXT(text) );
- data_out_file = fopen( filename, "r" );
- if( data_out_file ) {
- char buffer[1024];
- int nchars;
- while( 1 ) {
- nchars = fread( buffer, 1, 1024, data_out_file );
- if (show_ascii) {
- /* If our native arch is EBCDIC, call:
- * ASCII_TO_EBCDIC(buffer, nchars);
- */
- }
- else {
- /* If our native arch is ASCII, call: */
- EBCDIC_to_ASCII(buffer, nchars);
- }
- gtk_text_insert( GTK_TEXT(text), m_r_font, NULL, NULL, buffer, nchars );
- if( nchars < 1024 ) {
- break;
- }
- }
- if( ferror( data_out_file ) ) {
- simple_dialog(ESD_TYPE_WARN, NULL,
- "Error reading temporary file %s: %s", filename, strerror(errno));
- }
- fclose( data_out_file );
- } else {
- simple_dialog(ESD_TYPE_WARN, NULL,
- "Could not open temporary file %s: %s", filename, strerror(errno));
- }
- gtk_text_thaw( GTK_TEXT(text) );
+static void
+follow_load_text(GtkWidget *text, char *filename, guint8 show_type)
+{
+ int bytes_already;
+
+ /* 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);
+ }
+
+ /* stop the updates while we fill the text box */
+ gtk_text_freeze( GTK_TEXT(text) );
+ follow_read_stream(filename, show_type, follow_add_to_gtk_text, text);
+ gtk_text_thaw( GTK_TEXT(text) );
}
/* Match selected byte pattern */
void
match_selected_cb(GtkWidget *w, gpointer data)
{
- char *buf;
- GtkWidget *filter_te = NULL;
- char *ptr;
- int i;
- guint8 *c;
+ char *buf;
+ GtkWidget *filter_te;
+ char *ptr, *format, *stringified;
+ int i, dfilter_len, abbrev_len;
+ guint8 *c;
+ header_field_info *hfinfo;
filter_te = gtk_object_get_data(GTK_OBJECT(w), E_DFILTER_TE_KEY);
- if (tree_selected_start<0) {
+ if (!finfo_selected) {
simple_dialog(ESD_TYPE_WARN, NULL,
"Error determining selected bytes. Please make\n"
"sure you have selected a field within the tree\n"
return;
}
- c = cf.pd + tree_selected_start;
- buf = g_malloc(32 + tree_selected_len * 3);
- ptr = buf;
-
- sprintf(ptr, "frame[%d : %d] == ", tree_selected_start, tree_selected_len);
- ptr = buf+strlen(buf);
-
- if (tree_selected_len == 1) {
- sprintf(ptr, "0x%02x", *c++);
- }
- else {
- for (i=0;i<tree_selected_len; i++) {
- if (i == 0 ) {
- sprintf(ptr, "%02x", *c++);
- }
- else {
- sprintf(ptr, ":%02x", *c++);
- }
- ptr = buf+strlen(buf);
- }
- }
+ 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:
+ dfilter_len = abbrev_len + 4 + 15 + 1;
+ buf = g_malloc0(dfilter_len);
+ snprintf(buf, dfilter_len, "%s == %s", hfinfo->abbrev,
+ ipv4_addr_str(&(finfo_selected->value.ipv4)));
+ 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);
+ snprintf(buf, dfilter_len, "%s == %s",
+ hfinfo->abbrev,
+ ether_to_str(finfo_selected->value.ether));
+ 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:
+ c = cf.pd + finfo_selected->start;
+ buf = g_malloc0(32 + finfo_selected->length * 3);
+ ptr = buf;
+
+ sprintf(ptr, "frame[%d] == ", finfo_selected->start);
+ 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;
+ }
/* create a new one and set the display filter entry accordingly */
- if (filter_te) {
- gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
- }
+ gtk_entry_set_text(GTK_ENTRY(filter_te), buf);
+
/* Run the display filter so it goes in effect. */
filter_packets(&cf, buf);
+
+ /* 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;
}
+
/* Run the current display filter on the current packet set, and
redisplay. */
static void
filter_activate_cb(GtkWidget *w, gpointer data)
{
+ 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;
+
char *s = gtk_entry_get_text(GTK_ENTRY(w));
+
+ /* 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. */
+ if (filter_packets(&cf, g_strdup(s))) {
+ li = g_list_first(filter_list);
+ while (li) {
+ if (li->data && strcmp(s, li->data) == 0)
+ add_filter = FALSE;
+ li = li->next;
+ }
+
+ 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);
+ }
+ }
+}
+
+/* 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), "");
+ }
- filter_packets(&cf, g_strdup(s));
+ filter_packets(&cf, NULL);
}
/* What to do when a list item is selected/unselected */
-void
+static void
packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
#ifdef HAVE_LIBPCAP
select_packet(&cf, row);
}
-void
+static void
packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) {
unselect_packet(&cf);
}
-void
-tree_view_cb(GtkWidget *w, gpointer data) {
-
- tree_selected_start = -1;
- tree_selected_len = -1;
-
- if (GTK_TREE(w)->selection) {
- tree_selected_start =
- (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
- E_TREEINFO_START_KEY);
- tree_selected_len =
- (gint) gtk_object_get_data(GTK_OBJECT(GTK_TREE(w)->selection->data),
- E_TREEINFO_LEN_KEY);
- }
+static void
+tree_view_select_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
+{
+ field_info *finfo;
+ int tree_selected_start = -1;
+ int tree_selected_len = -1;
- gtk_text_freeze(GTK_TEXT(byte_view));
- gtk_text_set_point(GTK_TEXT(byte_view), 0);
- gtk_text_forward_delete(GTK_TEXT(byte_view),
- gtk_text_get_length(GTK_TEXT(byte_view)));
- packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
- tree_selected_start,
- tree_selected_len);
-
- gtk_text_thaw(GTK_TEXT(byte_view));
+ g_assert(node);
+ finfo = gtk_ctree_node_get_row_data( ctree, GTK_CTREE_NODE(node) );
+ if (!finfo) return;
+
+ finfo_selected = finfo;
+ tree_selected_start = finfo->start;
+ tree_selected_len = finfo->length;
+
+ packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
+ tree_selected_start, tree_selected_len, cf.current_frame->encoding);
+}
+
+static void
+tree_view_unselect_row_cb(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
+{
+ finfo_selected = NULL;
+ packet_hex_print(GTK_TEXT(byte_view), cf.pd, cf.current_frame->cap_len,
+ -1, -1, cf.current_frame->encoding);
}
void collapse_all_cb(GtkWidget *widget, gpointer data) {
expand_all_tree(cf.protocol_tree, tree_view);
}
+void
+set_scrollbar_placement(int pos) /* 0=left, 1=right */
+{
+ if (pos) {
+ gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
+ GTK_CORNER_TOP_LEFT );
+ gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
+ GTK_CORNER_TOP_LEFT );
+ gtk_widget_hide(bv_vscroll_left);
+ gtk_widget_show(bv_vscroll_right);
+ }
+ else {
+ gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(pkt_scrollw),
+ GTK_CORNER_TOP_RIGHT );
+ gtk_scrolled_window_set_placement( GTK_SCROLLED_WINDOW(tv_scrollw),
+ GTK_CORNER_TOP_RIGHT );
+ gtk_widget_hide(bv_vscroll_right);
+ gtk_widget_show(bv_vscroll_left);
+ }
+}
+
+void
+set_plist_sel_browse(gboolean val)
+{
+ if (finfo_selected)
+ unselect_packet(&cf);
+
+ /* 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+ */
+ if (val) {
+ gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_SINGLE);
+ }
+ else {
+ gtk_clist_set_selection_mode(GTK_CLIST(packet_list), GTK_SELECTION_BROWSE);
+ }
+}
+
+void
+set_ptree_sel_browse(gboolean val)
+{
+ /* 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+ */
+ if (val) {
+ gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_SINGLE);
+ }
+ else {
+ gtk_clist_set_selection_mode(GTK_CLIST(tree_view), GTK_SELECTION_BROWSE);
+ }
+}
+
+void
+set_ptree_line_style(gint style)
+{
+ /* 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);
+ gtk_ctree_set_line_style( GTK_CTREE(tree_view), style );
+}
+
+void
+set_ptree_expander_style(gint style)
+{
+ /* 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);
+ gtk_ctree_set_expander_style( GTK_CTREE(tree_view), style );
+}
+
+
void
file_quit_cmd_cb (GtkWidget *widget, gpointer data) {
- if (cf.save_file && !cf.user_saved) {
- unlink(cf.save_file);
- }
+ /* If we have a capture file open, and it's a temporary file,
+ unlink it. */
+ if (cf.filename != NULL && cf.is_tempfile)
+ unlink(cf.filename);
gtk_exit(0);
}
proto_init();
init_dissect_udp();
dfilter_init();
+#ifdef HAVE_PLUGINS
+ init_plugins();
+#endif
}
static void
static void
print_usage(void) {
- fprintf(stderr, "This is GNU %s %s, compiled with %s\n", PACKAGE,
- VERSION, comp_info_str);
- fprintf(stderr, "%s [-vh] [-kQS] [-b <bold font>] [-B <byte view height>] [-c count]\n",
+ fprintf(stderr, "This is GNU " PACKAGE " " VERSION ", compiled with %s\n",
+ comp_info_str);
+#ifdef HAVE_LIBPCAP
+ fprintf(stderr, "%s [ -vh ] [ -kQS ] [ -b <bold font> ] [ -B <byte view height> ]\n",
+ PACKAGE);
+ 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");
+#else
+ fprintf(stderr, "%s [ -vh ] [ -b <bold font> ] [ -B <byte view height> ]\n",
PACKAGE);
- fprintf(stderr, " [-f <filter expression>] [-i interface] [-m <medium font>] [-n]\n");
- fprintf(stderr, " [-P <packet list height>] [-r infile] [-s snaplen]\n");
- fprintf(stderr, " [-t <time stamp format>] [-T <tree view height>] [-w savefile] \n");
+ 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");
+#endif
}
/* And now our feature presentation... [ fade to music ] */
#ifndef WIN32
int opt;
extern char *optarg;
+ gboolean arg_error = FALSE;
#endif
#ifdef HAVE_LIBPCAP
- extern char pcap_version[];
+ extern char pcap_version[];
#endif
char *pf_path;
- int pf_open_errno = 0;
- int err;
+ int pf_open_errno = 0;
+ int err;
#ifdef HAVE_LIBPCAP
- gboolean start_capture = FALSE;
- gchar *save_file = NULL;
+ gboolean start_capture = FALSE;
+ gchar *save_file = NULL;
+ GList *if_list;
+ gchar err_str[PCAP_ERRBUF_SIZE];
+#else
+ gboolean capture_option_specified = FALSE;
#endif
- GtkWidget *window, *main_vbox, *menubar, *u_pane, *l_pane,
- *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox,
- *tv_scrollw, *filter_bt, *filter_te;
- GtkStyle *pl_style;
- GtkAccelGroup *accel;
- GtkWidget *packet_sw;
gint pl_size = 280, tv_size = 95, bv_size = 75;
gchar *rc_file, *cf_name = NULL, *rfilter = NULL;
dfilter *rfcode = NULL;
ethereal_path = argv[0];
#ifdef HAVE_LIBPCAP
- command_name = strrchr(ethereal_path, '/');
- if (command_name == NULL)
- command_name = ethereal_path;
- else
- command_name++;
+ command_name = get_basename(ethereal_path);
/* 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);
cf.plist_end = NULL;
cf.wth = NULL;
cf.fh = NULL;
+ cf.filename = NULL;
+ cf.user_saved = FALSE;
+ cf.is_tempfile = FALSE;
cf.rfcode = NULL;
cf.dfilter = NULL;
cf.dfcode = NULL;
#ifdef HAVE_LIBPCAP
- cf.cfilter = NULL;
+ cf.cfilter = g_strdup(EMPTY_FILTER);
#endif
cf.iface = NULL;
cf.save_file = NULL;
cf.save_file_fd = -1;
- cf.user_saved = 0;
cf.snap = WTAP_MAX_PACKET_SIZE;
cf.count = 0;
cf.cinfo.num_cols = prefs->num_cols;
/* Assemble the compile-time options */
snprintf(comp_info_str, 256,
#ifdef GTK_MAJOR_VERSION
- "GTK+ %d.%d.%d, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
+ "GTK+ %d.%d.%d, %s%s, %s%s, %s%s", GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
GTK_MICRO_VERSION,
#else
- "GTK+ (version unknown), %s%s",
+ "GTK+ (version unknown), %s%s, %s%s, %s%s",
#endif
#ifdef HAVE_LIBPCAP
- "with libpcap ", pcap_version
+ "with libpcap ", pcap_version,
#else
- "without libpcap", ""
+ "without libpcap", "",
+#endif
+
+#ifdef HAVE_LIBZ
+#ifdef ZLIB_VERSION
+ "with libz ", ZLIB_VERSION,
+#else /* ZLIB_VERSION */
+ "with libz ", "(version unknown)",
+#endif /* ZLIB_VERSION */
+#else /* HAVE_LIBZ */
+ "without libz", "",
+#endif /* HAVE_LIBZ */
+
+/* Oh, this is pretty */
+#if defined(HAVE_UCD_SNMP_SNMP_H)
+#ifdef HAVE_UCD_SNMP_VERSION_H
+ "with UCD SNMP ", VersionInfo
+#else /* HAVE_UCD_SNMP_VERSION_H */
+ "with UCD SNMP ", "(version unknown)"
+#endif /* HAVE_UCD_SNMP_VERSION_H */
+#elif defined(HAVE_SNMP_SNMP_H)
+#ifdef HAVE_SNMP_VERSION_H
+ "with CMU SNMP ", snmp_Version()
+#else /* HAVE_SNMP_VERSION_H */
+ "with CMU SNMP ", "(version unknown)"
+#endif /* HAVE_SNMP_VERSION_H */
+#else /* no SNMP */
+ "without SNMP", ""
#endif
);
#ifndef WIN32
/* Now get our args */
- while ((opt = getopt(argc, argv, "b:B:c:f:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
+ while ((opt = getopt(argc, argv, "b:B:c:Df:hi:km:nP:Qr:R:Ss:t:T:w:W:v")) != EOF) {
switch (opt) {
case 'b': /* Bold font */
bold_font = g_strdup(optarg);
bv_size = atoi(optarg);
break;
case 'c': /* Capture xxx packets */
+#ifdef HAVE_LIBPCAP
cf.count = atoi(optarg);
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
+#endif
break;
-#ifdef HAVE_LIBPCAP
+ case 'D': /* Turn off DSCP printing */
+ g_ip_dscp_actif = FALSE;
+ break;
case 'f':
+#ifdef HAVE_LIBPCAP
+ if (cf.cfilter)
+ g_free(cf.cfilter);
cf.cfilter = g_strdup(optarg);
- break;
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
#endif
+ break;
case 'h': /* Print help and exit */
print_usage();
exit(0);
break;
case 'i': /* Use interface xxx */
+#ifdef HAVE_LIBPCAP
cf.iface = g_strdup(optarg);
+#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
break;
case 'm': /* Medium font */
medium_font = g_strdup(optarg);
case 'n': /* No name resolution */
g_resolving_actif = 0;
break;
-#ifdef HAVE_LIBPCAP
- case 'k': /* Start capture immediately */
- start_capture = TRUE;
- break;
-#endif
case 'P': /* Packet list pane height */
pl_size = atoi(optarg);
break;
-#ifdef HAVE_LIBPCAP
case 'Q': /* Quit after capture (just capture to file) */
+#ifdef HAVE_LIBPCAP
quit_after_cap = 1;
start_capture = TRUE; /*** -Q implies -k !! ***/
- break;
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
#endif
+ break;
case 'r': /* Read capture file xxx */
+ /* 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. */
cf_name = g_strdup(optarg);
break;
case 'R': /* Read file filter */
rfilter = optarg;
break;
-#ifdef HAVE_LIBPCAP
case 's': /* Set the snapshot (capture) length */
+#ifdef HAVE_LIBPCAP
cf.snap = atoi(optarg);
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
+#endif
break;
case 'S': /* "Sync" mode: used for following file ala tail -f */
+#ifdef HAVE_LIBPCAP
sync_mode = TRUE;
- break;
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
#endif
+ break;
case 't': /* Time stamp type */
if (strcmp(optarg, "r") == 0)
timestamp_type = RELATIVE;
printf("%s %s, with %s\n", PACKAGE, VERSION, comp_info_str);
exit(0);
break;
-#ifdef HAVE_LIBPCAP
case 'w': /* Write to capture file xxx */
+#ifdef HAVE_LIBPCAP
save_file = g_strdup(optarg);
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
+#endif
break;
case 'W': /* Write to capture file FD xxx */
+#ifdef HAVE_LIBPCAP
cf.save_file_fd = atoi(optarg);
- break;
+#else
+ capture_option_specified = TRUE;
+ arg_error = TRUE;
#endif
+ break;
+ default:
case '?': /* Bad flag - print usage message */
- print_usage();
+ arg_error = TRUE;
break;
}
}
#endif
+#ifndef HAVE_LIBPCAP
+ if (capture_option_specified)
+ fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
+#endif
+#ifndef WIN32
+ if (arg_error)
+ print_usage();
+#endif
#ifdef HAVE_LIBPCAP
if (start_capture) {
+ /* We're supposed to do a live capture; did the user specify an interface
+ to use? */
if (cf.iface == NULL) {
- fprintf(stderr, "ethereal: \"-k\" flag was specified without \"-i\" flag\n");
- exit(1);
+ /* 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;
+ }
+ exit(2);
+ }
+ cf.iface = g_strdup(if_list->data); /* first interface */
+ free_interface_list(if_list);
}
}
if (capture_child) {
exit(1);
}
+ create_main_window(pl_size, tv_size, bv_size, prefs);
+
+/*
+ Hmmm should we do it here
+*/
+
+ ethereal_proto_init(); /* Init anything that needs initializing */
+
+#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);
+
+ cf.colors = colfilter_new();
+
+ /* 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) {
+ if ((err = open_cap_file(cf_name, FALSE, &cf)) == 0) {
+ /* "open_cap_file()" succeeded, so it closed the previous
+ capture file, and thus destroyed any previous read filter
+ attached to "cf". */
+ cf.rfcode = rfcode;
+ err = read_cap_file(&cf);
+ s = strrchr(cf_name, '/');
+ if (s) {
+ last_open_dir = cf_name;
+ *s = '\0';
+ }
+ } else {
+ dfilter_destroy(rfcode);
+ cf.rfcode = NULL;
+ }
+ }
+ }
+#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);
+ }
+ }
+#endif
+
+ gtk_main();
+
+ ethereal_proto_cleanup();
+ g_free(rc_file);
+
+ exit(0);
+}
+
+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,
+ *bv_table, *stat_hbox,
+ *filter_bt, *filter_cm, *filter_te,
+ *filter_reset;
+ GList *filter_list = NULL;
+ GtkStyle *pl_style;
+ GtkAccelGroup *accel;
+ int i;
+
/* Main window */
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_widget_set_name(window, "main window");
- gtk_signal_connect(GTK_OBJECT(window), "delete_event",
+ top_level = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name(top_level, "main window");
+ gtk_signal_connect(GTK_OBJECT(top_level), "delete_event",
GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
- gtk_signal_connect(GTK_OBJECT(window), "destroy",
+ gtk_signal_connect(GTK_OBJECT(top_level), "destroy",
GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy");
- gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer");
- gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1);
- gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
+ 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);
/* 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);
- gtk_container_add(GTK_CONTAINER(window), main_vbox);
+ gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
gtk_widget_show(main_vbox);
/* Menu bar */
get_main_menu(&menubar, &accel);
- gtk_window_add_accel_group(GTK_WINDOW(window), accel);
+ gtk_window_add_accel_group(GTK_WINDOW(top_level), accel);
gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
gtk_widget_show(menubar);
gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
l_pane = gtk_vpaned_new();
gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
- gtk_container_add(GTK_CONTAINER(main_vbox), u_pane);
+ gtk_container_add(GTK_CONTAINER(main_vbox), l_pane);
gtk_widget_show(u_pane);
- gtk_paned_add2 (GTK_PANED(u_pane), l_pane);
+ gtk_paned_add1 (GTK_PANED(l_pane), u_pane);
gtk_widget_show(l_pane);
/* Packet list */
+ pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_widget_show(pkt_scrollw);
+ gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
+
packet_list = gtk_clist_new_with_titles(cf.cinfo.num_cols, cf.cinfo.col_title);
+ gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
gtk_clist_column_titles_passive(GTK_CLIST(packet_list));
- packet_sw = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_show(packet_sw);
- gtk_container_add(GTK_CONTAINER(packet_sw), packet_list);
+ set_plist_sel_browse(prefs->gui_plist_sel_browse);
pl_style = gtk_style_new();
gdk_font_unref(pl_style->font);
pl_style->font = m_r_font;
/* Save static column sizes to use during a "-S" capture, so that
the columns don't resize during a live capture. */
- cf.cinfo.col_width[i] = get_column_width(get_column_format(i),
- pl_style->font);
+ cf.cinfo.col_width[i] = gdk_string_width(pl_style->font,
+ get_column_longest_string(get_column_format(i)));
}
gtk_widget_set_usize(packet_list, -1, pl_size);
- gtk_paned_add1(GTK_PANED(u_pane), packet_sw);
+ 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));
gtk_widget_show(packet_list);
/* Tree view */
tv_scrollw = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw);
+ gtk_paned_add2(GTK_PANED(u_pane), tv_scrollw);
gtk_widget_set_usize(tv_scrollw, -1, tv_size);
gtk_widget_show(tv_scrollw);
- tree_view = gtk_tree_new();
- gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(tv_scrollw),
- tree_view);
- gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE);
-
- /* XXX - what's the difference between the next two lines? */
- gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE);
- gtk_tree_set_view_mode(GTK_TREE(tree_view), GTK_TREE_VIEW_ITEM);
-
- gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed",
- GTK_SIGNAL_FUNC(tree_view_cb), NULL);
+ tree_view = gtk_ctree_new(1, 0);
+ /* I need this next line to make the widget work correctly with hidden
+ * column titles and GTK_SELECTION_BROWSE */
+ gtk_clist_set_column_auto_resize( GTK_CLIST(tree_view), 0, TRUE );
+ gtk_container_add( GTK_CONTAINER(tv_scrollw), tree_view );
+ set_ptree_sel_browse(prefs->gui_ptree_sel_browse);
+ set_ptree_line_style(prefs->gui_ptree_line_style);
+ set_ptree_expander_style(prefs->gui_ptree_expander_style);
+
+ 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);
+ 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));
gtk_widget_show(tree_view);
item_style = gtk_style_new();
gdk_font_unref(item_style->font);
item_style->font = m_r_font;
- /* Byte view */
- bv_table = gtk_table_new (2, 2, FALSE);
- gtk_paned_add2(GTK_PANED(l_pane), bv_table);
+ /* Byte view. The table is only one row high, but 3 columns
+ * wide. The middle column contains the GtkText with the hex dump.
+ * The left and right columns contain vertical scrollbars. They both
+ * do the same thing, but only one will be shown at a time, in accordance
+ * with where the user wants the other vertical scrollbars places
+ * (on the left or the right).
+ */
+ bv_table = gtk_table_new (1, 3, FALSE);
+ gtk_paned_pack2(GTK_PANED(l_pane), bv_table, FALSE, FALSE);
gtk_widget_set_usize(bv_table, -1, bv_size);
gtk_widget_show(bv_table);
byte_view = gtk_text_new(NULL, NULL);
gtk_text_set_editable(GTK_TEXT(byte_view), FALSE);
gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE);
- gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1,
+ gtk_table_attach (GTK_TABLE (bv_table), byte_view, 1, 2, 0, 1,
GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
gtk_widget_show(byte_view);
- bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj);
- gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2,
- GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (bv_hscroll);
+ /* The gtk_text widget doesn't scroll horizontally (see gtktext.c)
+ * in the GTK+ distribution, so I removed the horizontal scroll bar
+ * that used to be here. I tried the gtk_text widget with a
+ * gtk_scrolled_window w/ viewport, but the vertical scrollowing
+ * did not work well, and sometimes a few pixels were cut off on
+ * the bottom. */
- bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
- gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1,
+ bv_vscroll_left = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
+ gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_left, 0, 1, 0, 1,
GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
- gtk_widget_show(bv_vscroll);
-
+
+ bv_vscroll_right = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj);
+ gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll_right, 2, 3, 0, 1,
+ GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
+
+ /* Now that the 3 panes are created, set the vertical scrollbar
+ * on the left or right according to the user's preference */
+ set_scrollbar_placement(prefs->gui_scrollbar_on_right);
+
/* Progress/filter/info box */
stat_hbox = gtk_hbox_new(FALSE, 1);
gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
filter_bt = gtk_button_new_with_label("Filter:");
gtk_signal_connect(GTK_OBJECT(filter_bt), "clicked",
- GTK_SIGNAL_FUNC(prefs_cb), (gpointer) E_PR_PG_FILTER);
+ GTK_SIGNAL_FUNC(filter_dialog_cb), NULL);
gtk_box_pack_start(GTK_BOX(stat_hbox), filter_bt, FALSE, TRUE, 0);
gtk_widget_show(filter_bt);
- filter_te = gtk_entry_new();
+ 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;
gtk_object_set_data(GTK_OBJECT(filter_bt), E_FILT_TE_PTR_KEY, filter_te);
- gtk_box_pack_start(GTK_BOX(stat_hbox), filter_te, TRUE, TRUE, 3);
+ 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);
gtk_signal_connect(GTK_OBJECT(filter_te), "activate",
GTK_SIGNAL_FUNC(filter_activate_cb), (gpointer) NULL);
- gtk_widget_show(filter_te);
+ gtk_widget_show(filter_cm);
+
+ 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);
/* 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 */
set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
- set_menu_object_data("/Display/Match Selected", E_DFILTER_TE_KEY,
- filter_te);
+ set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
+ 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);
info_bar = gtk_statusbar_new();
main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
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);
-
-/*
- Hmmm should we do it here
-*/
-
- ethereal_proto_init(); /* Init anything that needs initializing */
-
-#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(window);
-
- colors_init(&cf);
-
- /* 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) {
- if ((err = open_cap_file(cf_name, &cf)) == 0) {
- /* "open_cap_file()" succeeded, so it closed the previous
- capture file, and thus destroyed any previous read filter
- attached to "cf". */
- cf.rfcode = rfcode;
- err = read_cap_file(&cf);
- s = strrchr(cf_name, '/');
- if (s) {
- last_open_dir = cf_name;
- *s = '\0';
- }
- set_menu_sensitivity("/File/Save As...", TRUE);
- } else {
- dfilter_destroy(rfcode);
- cf.rfcode = NULL;
- }
- }
- }
-#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);
- }
- }
-#endif
-
- gtk_main();
-
- ethereal_proto_cleanup();
-
- exit(0);
}