/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.301 2003/08/05 00:01:26 guy Exp $
+ * $Id: file.c,v 1.302 2003/08/11 22:41:09 sharpe Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#include <gtk/gtk.h>
+#include <gtk/keys.h>
+#include <gtk/compat_macros.h>
#include <time.h>
#include "globals.h"
#include <epan/epan_dissect.h>
#include "tap.h"
+#include "packet-data.h"
#ifdef HAVE_LIBPCAP
gboolean auto_scroll_live;
static void freeze_plist(capture_file *cf);
static void thaw_plist(capture_file *cf);
+static void proto_tree_get_node(GNode *node, gpointer data);
static char *file_rename_error_message(int err);
static char *file_close_error_message(int err);
static gboolean copy_binary_file(char *from_filename, char *to_filename);
+static char decode_data[16536];
/* Update the progress bar this many times when reading a file. */
#define N_PROGBAR_UPDATES 100
XXX - is this the right number? */
#define FRAME_DATA_CHUNK_SIZE 1024
+
+typedef struct {
+ int level;
+ FILE *fh;
+ GSList *src_list;
+ gboolean print_all_levels;
+ gboolean print_hex_for_data;
+ char_enc encoding;
+ gint format; /* text or PostScript */
+} print_data;
+
+
int
open_cap_file(char *fname, gboolean is_tempfile, capture_file *cf)
{
}
}
+static char*
+get_info_string(epan_dissect_t* edt)
+{
+ int i;
+
+ for (i=0;i<edt->pi.cinfo->num_cols;i++) {
+ if (strcmp(edt->pi.cinfo->col_title[i], "Info")==0) {
+ return edt->pi.cinfo->col_data[i];
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Find the data source for a specified field, and return a pointer
+ * to the data in it.
+ */
+static const guint8 *
+get_field_data(GSList *src_list, field_info *fi)
+{
+ GSList *src_le;
+ data_source *src;
+ tvbuff_t *src_tvb;
+
+ for (src_le = src_list; src_le != NULL; src_le = src_le->next) {
+ src = src_le->data;
+ src_tvb = src->tvb;
+ if (fi->ds_tvb == src_tvb) {
+ /*
+ * Found it.
+ */
+ if(tvb_length_remaining(src_tvb, 0) < fi->length+fi->start){
+ return NULL;
+ }
+ return tvb_get_ptr(src_tvb, fi->start, fi->length);
+ }
+ }
+ return NULL; /* not found */
+}
+
+/* Print a tree's data, and any child nodes to the buffer. */
+static
+void proto_tree_get_node(GNode *node, gpointer data)
+{
+ field_info *fi = PITEM_FINFO(node);
+ print_data *pdata = (print_data*) data;
+ const guint8 *pd;
+ gchar label_str[ITEM_LABEL_LENGTH];
+ gchar *label_ptr, *string_ptr;
+
+ string_ptr = decode_data;
+
+ /* Don't print invisible entries. */
+ if (!fi->visible)
+ return;
+
+ /* was a free format label produced? */
+ if (fi->representation) {
+ label_ptr = fi->representation;
+ }
+ else { /* no, make a generic label */
+ label_ptr = label_str;
+ proto_item_fill_label(fi, label_str);
+ }
+
+ strcat(string_ptr, label_ptr);
+
+ /*
+ * Find the data for this field.
+ */
+ pd = get_field_data(pdata->src_list, fi);
+ if (pd!=NULL) {
+ if (strlen(pd) > 0) {
+ strcat(string_ptr, pd);
+ }
+ }
+
+ /* If we're printing all levels, or if this node is one with a
+ subtree and its subtree is expanded, recurse into the subtree,
+ if it exists. */
+ g_assert(fi->tree_type >= -1 && fi->tree_type < num_tree_types);
+ if (pdata->print_all_levels ||
+ (fi->tree_type >= 0 && tree_is_expanded[fi->tree_type])) {
+ if (g_node_n_children(node) > 0) {
+ pdata->level++;
+ g_node_children_foreach(node, G_TRAVERSE_ALL,
+ proto_tree_get_node, pdata);
+ pdata->level--;
+ }
+ }
+}
+
+gboolean
+find_in_gtk_data(capture_file *cf, gpointer *data, char *ascii_text, gboolean case_type, gboolean summary_search)
+{
+ frame_data *start_fd;
+ frame_data *fdata;
+ frame_data *new_fd = NULL;
+ progdlg_t *progbar = NULL;
+ gboolean stop_flag;
+ int count;
+ int err;
+ guint32 i;
+ guint16 c_match=0;
+ gboolean frame_matched;
+ int row;
+ float prog_val;
+ GTimeVal start_time;
+ gchar status_str[100];
+ guint8 c_char=0;
+ guint32 buf_len=0;
+ guint8 hex_val=0;
+ char char_val;
+ guint8 num1, num2;
+ gchar *uppercase;
+ epan_dissect_t* new_edt;
+ char *info_string;
+ print_data ndata;
+
+ start_fd = cf->current_frame;
+ if (start_fd != NULL) {
+ /* Iterate through the list of packets, starting at the packet we've
+ picked, calling a routine to run the filter on the packet, see if
+ it matches, and stop if so. */
+ count = 0;
+ fdata = start_fd;
+
+ if (case_type) {
+ g_strup(ascii_text);
+ }
+
+ cf->progbar_nextstep = 0;
+ /* When we reach the value that triggers a progress bar update,
+ bump that value by this amount. */
+ cf->progbar_quantum = cf->count/N_PROGBAR_UPDATES;
+
+ stop_flag = FALSE;
+ g_get_current_time(&start_time);
+
+ fdata = start_fd;
+ for (;;) {
+ /* Update the progress bar, but do it only N_PROGBAR_UPDATES times;
+ when we update it, we have to run the GTK+ main loop to get it
+ to repaint what's pending, and doing so may involve an "ioctl()"
+ to see if there's any pending input from an X server, and doing
+ that for every packet can be costly, especially on a big file. */
+ if (count >= cf->progbar_nextstep) {
+ /* let's not divide by zero. I should never be started
+ * with count == 0, so let's assert that
+ */
+ g_assert(cf->count > 0);
+
+ prog_val = (gfloat) count / cf->count;
+
+ /* Create the progress bar if necessary */
+ if (progbar == NULL)
+ progbar = delayed_create_progress_dlg("Searching", cf->sfilter, "Cancel",
+ &stop_flag, &start_time, prog_val);
+
+ if (progbar != NULL) {
+ g_snprintf(status_str, sizeof(status_str),
+ "%4u of %u frames", count, cf->count);
+ update_progress_dlg(progbar, prog_val, status_str);
+ }
+
+ cf->progbar_nextstep += cf->progbar_quantum;
+ }
+
+ if (stop_flag) {
+ /* Well, the user decided to abort the search. Go back to the
+ frame where we started. */
+ new_fd = start_fd;
+ break;
+ }
+
+ /* Go past the current frame. */
+ if (cf->sbackward) {
+ /* Go on to the previous frame. */
+ fdata = fdata->prev;
+ if (fdata == NULL)
+ fdata = cf->plist_end; /* wrap around */
+ } else {
+ /* Go on to the next frame. */
+ fdata = fdata->next;
+ if (fdata == NULL)
+ fdata = cf->plist; /* wrap around */
+ }
+
+ count++;
+
+ /* Is this packet in the display? */
+ if (fdata->flags.passed_dfilter) {
+ /* Yes. Does it match the search filter? */
+ /* XXX - do something with "err" */
+ wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
+ cf->pd, fdata->cap_len, &err);
+ new_edt = epan_dissect_new(TRUE, TRUE);
+ epan_dissect_run(new_edt, &cfile.pseudo_header, cfile.pd, fdata, &cfile.cinfo);
+ if (summary_search) {
+ info_string = get_info_string(new_edt);
+ if (info_string == NULL) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "Can't find info column. Terminating.");
+ return FALSE;
+ }
+ }
+ else
+ {
+ strcpy(decode_data,"\0");
+ info_string = decode_data;
+ ndata.level = 0;
+ ndata.fh = NULL;
+ ndata.src_list = new_edt->pi.data_src;
+ ndata.encoding = new_edt->pi.fd->flags.encoding;
+ ndata.print_all_levels = TRUE;
+ ndata.print_hex_for_data = FALSE;
+ ndata.format = 0;
+ g_node_children_foreach((GNode*) new_edt->tree, G_TRAVERSE_ALL,
+ proto_tree_get_node, &ndata);
+ }
+ if (case_type) {
+ g_strup(info_string);
+ }
+ frame_matched = FALSE;
+ buf_len = strlen(info_string);
+ for (i=0;i<buf_len;i++) {
+ c_char = info_string[i];
+ if (c_char == ascii_text[c_match]) {
+ c_match++;
+ if (c_match == strlen(ascii_text)) {
+ frame_matched = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ c_match = 0;
+ }
+ }
+ if (frame_matched) {
+ new_fd = fdata;
+ break; /* found it! */
+ }
+ epan_dissect_free(new_edt);
+ }
+
+ if (fdata == start_fd) {
+ /* We're back to the frame we were on originally, and that frame
+ doesn't match the search filter. The search failed. */
+ break;
+ }
+ }
+
+ /* We're done scanning the packets; destroy the progress bar if it
+ was created. */
+ if (progbar != NULL)
+ destroy_progress_dlg(progbar);
+ }
+
+ if (new_fd != NULL) {
+ /* We found a frame. Find what row it's in. */
+ row = packet_list_find_row_from_data(new_fd);
+ g_assert(row != -1);
+
+ /* Select that row, make it the focus row, and make it visible. */
+ packet_list_set_selected_row(row);
+ return TRUE; /* success */
+ } else
+ return FALSE; /* failure */
+}
+
gboolean
find_ascii(capture_file *cf, char *ascii_text, gboolean ascii_search, char *ftype, gboolean case_type)
{
/* find_dlg.c
* Routines for "find frame" window
*
- * $Id: find_dlg.c,v 1.30 2003/08/05 00:01:27 guy Exp $
+ * $Id: find_dlg.c,v 1.31 2003/08/11 22:41:10 sharpe Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
#include "compat_macros.h"
#include "prefs.h"
#include "prefs_dlg.h"
+#include "keys.h"
/* Capture callback data keys */
#define E_FIND_FILT_KEY "find_filter_te"
#define E_FIND_FILTERDATA_KEY "find_filter"
#define E_FIND_STRINGTYPE_KEY "find_string_type"
#define E_CASE_SEARCH_KEY "case_insensitive_search"
+#define E_SOURCE_HEX_KEY "hex_data_source"
+#define E_SOURCE_DECODE_KEY "decode_data_source"
+#define E_SOURCE_SUMMARY_KEY "summary_data_source"
static gboolean case_type = TRUE;
+static gboolean summary_data = FALSE;
+static gboolean decode_data = FALSE;
static void
find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
static void
find_frame_destroy_cb(GtkWidget *win, gpointer user_data);
+static void
+ascii_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w);
+
/*
* Keep a static pointer to the current "Find Frame" window, if any, so
* that if somebody tries to do "Find Frame" while there's already a
GtkWidget *main_vb, *filter_hb, *filter_bt, *filter_te,
*direction_hb, *forward_rb, *backward_rb,
*hex_hb, *hex_rb, *ascii_rb, *filter_rb,
+ *data_hb, *hex_data_rb, *decode_data_rb, *summary_data_rb,
*combo_hb, *combo_cb, *combo_lb,
*bbox, *ok_bt, *cancel_bt, *case_cb;
#if GTK_MAJOR_VERSION < 2
#endif
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ascii_rb), cfile.ascii);
gtk_box_pack_start(GTK_BOX(hex_hb), ascii_rb, TRUE, TRUE, 0);
+ SIGNAL_CONNECT(ascii_rb, "clicked", ascii_selected_cb, find_frame_w);
gtk_widget_show(ascii_rb);
- /* String Type Selection Dropdown Box */
+ /* Hex, Decode, or Summary Data Search */
+ /* Source Hex Data Search Window*/
+ data_hb = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(main_vb), data_hb);
+ gtk_widget_show(data_hb);
+
+#if GTK_MAJOR_VERSION < 2
+ hex_data_rb = dlg_radio_button_new_with_label_with_mnemonic(NULL, "Hex",
+ accel_group);
+#else
+ hex_data_rb = gtk_radio_button_new_with_mnemonic(NULL, "Hex");
+#endif
+ gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(hex_data_rb), !decode_data && !summary_data);
+ gtk_box_pack_start(GTK_BOX(data_hb), hex_data_rb, TRUE, TRUE, 0);
+ gtk_widget_show(hex_data_rb);
+
+ /* Search Decode Window */
+#if GTK_MAJOR_VERSION < 2
+ decode_data_rb = dlg_radio_button_new_with_label_with_mnemonic(
+ gtk_radio_button_group(GTK_RADIO_BUTTON(hex_data_rb)),
+ "Decode", accel_group);
+#else
+ decode_data_rb = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(hex_data_rb), "Decode");
+#endif
+ gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(decode_data_rb), decode_data);
+ gtk_box_pack_start(GTK_BOX(data_hb), decode_data_rb, TRUE, TRUE, 0);
+ gtk_widget_show(decode_data_rb);
+
+ /* Search Summary Window */
+
+#if GTK_MAJOR_VERSION < 2
+ summary_data_rb = dlg_radio_button_new_with_label_with_mnemonic(
+ gtk_radio_button_group(GTK_RADIO_BUTTON(hex_data_rb)),
+ "Summary", accel_group);
+#else
+ summary_data_rb = gtk_radio_button_new_with_mnemonic_from_widget(
+ GTK_RADIO_BUTTON(hex_data_rb), "Summary");
+#endif
+ gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(summary_data_rb), summary_data);
+ gtk_box_pack_start(GTK_BOX(data_hb), summary_data_rb, TRUE, TRUE, 0);
+ gtk_widget_show(summary_data_rb);
+
+ /* String Type Selection Dropdown Box
+ These only apply to the Hex Window search option */
combo_hb = gtk_hbox_new(FALSE, 3);
gtk_container_add(GTK_CONTAINER(main_vb), combo_hb);
gtk_widget_show(combo_hb);
OBJECT_SET_DATA(find_frame_w, E_FIND_ASCIIDATA_KEY, ascii_rb);
OBJECT_SET_DATA(find_frame_w, E_FIND_STRINGTYPE_KEY, combo_cb);
OBJECT_SET_DATA(find_frame_w, E_CASE_SEARCH_KEY, case_cb);
+ OBJECT_SET_DATA(find_frame_w, E_SOURCE_HEX_KEY, hex_data_rb);
+ OBJECT_SET_DATA(find_frame_w, E_SOURCE_DECODE_KEY, decode_data_rb);
+ OBJECT_SET_DATA(find_frame_w, E_SOURCE_SUMMARY_KEY, summary_data_rb);
+ ascii_selected_cb(NULL, find_frame_w);
/* Catch the "activate" signal on the filter text entry, so that
if the user types Return there, we act as if the "OK" button
had been selected, as happens if Return is typed if some widget
gtk_widget_show(find_frame_w);
}
+/*
+ * This function will disable the string options until
+ * the string search is selected.
+ */
+static void
+ascii_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w)
+{
+ GtkWidget *ascii_rb, *hex_data_rb, *decode_data_rb, *summary_data_rb,
+ *data_combo_cb, *data_case_cb;
+
+ ascii_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_ASCIIDATA_KEY);
+ hex_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_HEX_KEY);
+ decode_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_DECODE_KEY);
+ summary_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_SUMMARY_KEY);
+ data_combo_cb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_KEY);
+ data_case_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CASE_SEARCH_KEY);
+
+
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ascii_rb))) {
+ gtk_widget_set_sensitive(GTK_WIDGET(hex_data_rb), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(decode_data_rb), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(summary_data_rb), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(data_combo_cb), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(data_case_cb), TRUE);
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(hex_data_rb), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(decode_data_rb), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(summary_data_rb), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(data_combo_cb), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(data_case_cb), FALSE);
+ }
+ return;
+}
+
+
static void
find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
{
- GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb, *case_cb;
+ GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb, *case_cb,
+ *decode_data_rb, *summary_data_rb;
gchar *filter_text, *string_type;
dfilter_t *sfcode;
ascii_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_ASCIIDATA_KEY);
combo_cb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_KEY);
case_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CASE_SEARCH_KEY);
+ decode_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_DECODE_KEY);
+ summary_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_SUMMARY_KEY);
filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
string_type = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_cb)->entry));
case_type = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(case_cb));
+ decode_data = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(decode_data_rb));
+ summary_data = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(summary_data_rb));
/*
* Try to compile the filter.
}
else
{
- if (!find_ascii(&cfile, filter_text, cfile.ascii, string_type, case_type)) {
- /* We didn't find the packet. */
- simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria.");
- return;
+ if (!decode_data && !summary_data) {
+ if (!find_ascii(&cfile, filter_text, cfile.ascii, string_type, case_type)) {
+ /* We didn't find the packet. */
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria.");
+ return;
+ }
+ }
+ else
+ {
+ /* Use the cfile.hex to indicate if summary or decode search */
+ /* This way the Next and Previous find options will work */
+ cfile.hex = summary_data;
+ if (!find_in_gtk_data(&cfile, parent_w, filter_text, case_type, summary_data)) {
+ /* We didn't find the packet. */
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria.");
+ return;
+ }
}
}
gtk_widget_destroy(GTK_WIDGET(parent_w));
cfile.sbackward = sens;
if (cfile.hex || cfile.ascii)
{
- find_ascii(&cfile, cfile.sfilter, cfile.ascii, cfile.ftype, case_type);
+ if (!decode_data && !summary_data) {
+ find_ascii(&cfile, cfile.sfilter, cfile.ascii, cfile.ftype, case_type);
+ }
+ else {
+ find_in_gtk_data(&cfile, d, cfile.sfilter, case_type, cfile.hex);
+ }
}
else
{