aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cfile.h21
-rw-r--r--file.c819
-rw-r--r--file.h10
-rw-r--r--gtk/find_dlg.c345
4 files changed, 605 insertions, 590 deletions
diff --git a/cfile.h b/cfile.h
index f6939e39f0..f2e8b29e85 100644
--- a/cfile.h
+++ b/cfile.h
@@ -1,7 +1,7 @@
/* cfile.h
* capture_file definition & GUI-independent manipulation
*
- * $Id: cfile.h,v 1.2 2003/07/22 23:08:47 guy Exp $
+ * $Id: cfile.h,v 1.3 2003/08/29 04:03:45 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -33,6 +33,14 @@ typedef enum {
FILE_READ_DONE /* Read completed */
} file_state;
+/* Character set for text search. */
+typedef enum {
+ SCS_ASCII_AND_UNICODE,
+ SCS_ASCII,
+ SCS_UNICODE
+ /* add EBCDIC when it's implemented */
+} search_charset_t;
+
typedef struct _capture_file {
file_state state; /* Current state of capture file */
int filed; /* File descriptor of capture file */
@@ -64,10 +72,13 @@ typedef struct _capture_file {
gchar *cfilter; /* Capture filter string */
#endif
gchar *sfilter; /* Search filter string */
- gboolean sbackward; /* TRUE if search is backward, FALSE if forward */
- gboolean hex; /* TRUE is Hex search is being performed */
- gboolean ascii; /* TRUE is ASCII search is being performed */
- char *ftype; /* Find Frame String Type */
+ gboolean sbackward; /* TRUE if search is backward, FALSE if forward */
+ gboolean hex; /* TRUE is raw data search is being performed */
+ gboolean ascii; /* TRUE is text search is being performed */
+ search_charset_t scs_type; /* Character set for text search */
+ gboolean case_type; /* TRUE if case-insensitive text search */
+ gboolean decode_data; /* TRUE if searching protocol tree text */
+ gboolean summary_data; /* TRUE if searching Info column text */
union wtap_pseudo_header pseudo_header; /* Packet pseudo_header */
guint8 pd[WTAP_MAX_PACKET_SIZE]; /* Packet data */
GMemChunk *plist_chunk; /* Memory chunk for frame_data structures */
diff --git a/file.c b/file.c
index ca8f80f041..53d74b0969 100644
--- a/file.c
+++ b/file.c
@@ -1,7 +1,7 @@
/* file.c
* File I/O routines
*
- * $Id: file.c,v 1.303 2003/08/14 22:32:45 sharpe Exp $
+ * $Id: file.c,v 1.304 2003/08/29 04:03:45 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -42,6 +42,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <signal.h>
@@ -97,14 +98,31 @@ static void read_packet(capture_file *cf, long offset);
static void rescan_packets(capture_file *cf, const char *action, const char *action_item,
gboolean refilter, gboolean redissect);
+static gboolean match_protocol_tree(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static void match_subtree_text(GNode *node, gpointer data);
+static gboolean match_summary_line(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static gboolean match_ascii_and_unicode(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static gboolean match_ascii(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static gboolean match_unicode(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static gboolean match_binary(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static gboolean match_dfilter(capture_file *cf, frame_data *fdata,
+ void *criterion);
+static gboolean find_packet(capture_file *cf,
+ gboolean (*match_function)(capture_file *, frame_data *, void *),
+ void *criterion);
+
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[MAX_DECODE_BUFFER_SIZE];
/* Update the progress bar this many times when reading a file. */
#define N_PROGBAR_UPDATES 100
@@ -1448,543 +1466,333 @@ change_time_formats(capture_file *cf)
thaw_plist(cf);
}
-guint8
-get_int_value(char char_val)
-{
- switch (char_val) {
- case 'a':
- case 'A':
- return(10);
- case 'b':
- case 'B':
- return(11);
- case 'c':
- case 'C':
- return(12);
- case 'd':
- case 'D':
- return(13);
- case 'e':
- case 'E':
- return(14);
- case 'f':
- case 'F':
- return(15);
- default:
- return(atoi(&char_val));
- }
-}
+typedef struct {
+ const char *string;
+ size_t string_len;
+ capture_file *cf;
+ gboolean frame_matched;
+} match_data;
-static char*
-get_info_string(epan_dissect_t* edt)
+gboolean
+find_packet_protocol_tree(capture_file *cf, const char *string)
{
- int i;
+ match_data mdata;
- 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;
+ mdata.string = string;
+ mdata.string_len = strlen(string);
+ return find_packet(cf, match_protocol_tree, &mdata);
}
-/*
- * 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)
+static gboolean
+match_protocol_tree(capture_file *cf, frame_data *fdata, void *criterion)
{
- 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 */
+ match_data *mdata = criterion;
+ epan_dissect_t *edt;
+
+ /* Construct the protocol tree, including the displayed text */
+ edt = epan_dissect_new(TRUE, TRUE);
+ /* We don't need the column information */
+ epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
+
+ /* Iterate through all the nodes, seeing if they have text that matches. */
+ mdata->cf = cf;
+ mdata->frame_matched = FALSE;
+ g_node_children_foreach((GNode*) edt->tree, G_TRAVERSE_ALL,
+ match_subtree_text, mdata);
+ epan_dissect_free(edt);
+ return mdata->frame_matched;
}
-/* Print a tree's data, and any child nodes to the buffer. */
-static
-void proto_tree_get_node(GNode *node, gpointer data)
+static void
+match_subtree_text(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;
+ match_data *mdata = (match_data*) data;
+ const gchar *string = mdata->string;
+ size_t string_len = mdata->string_len;
+ capture_file *cf = mdata->cf;
+ field_info *fi = PITEM_FINFO(node);
+ gchar label_str[ITEM_LABEL_LENGTH];
+ gchar *label_ptr;
+ size_t label_len;
+ guint32 i;
+ guint8 c_char;
+ size_t c_match = 0;
+
+ if (mdata->frame_matched) {
+ /* We already had a match; don't bother doing any more work. */
+ return;
+ }
- /* Don't print invisible entries. */
- if (!fi->visible)
- return;
+ /* Don't match 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);
- }
+ /* 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);
+ }
- if (strlen(string_ptr)+strlen(label_ptr) < MAX_DECODE_BUFFER_SIZE) {
- strcat(string_ptr, label_ptr);
- }
- else
- {
- simple_dialog(ESD_TYPE_CRIT, NULL, "Decode Buffer Size Exceeded.");
- return;
- }
+ /* Does that label match? */
+ label_len = strlen(label_ptr);
+ for (i = 0; i < label_len; i++) {
+ c_char = label_ptr[i];
+ if (cf->case_type)
+ c_char = toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ /* No need to look further; we have a match */
+ mdata->frame_matched = TRUE;
+ return;
+ }
+ } else
+ c_match = 0;
+ }
+
+ /* Recurse into the subtree, if it exists */
+ if (g_node_n_children(node) > 0)
+ g_node_children_foreach(node, G_TRAVERSE_ALL, match_subtree_text, mdata);
+}
- /*
- * Find the data for this field.
- */
- pd = get_field_data(pdata->src_list, fi);
- if (pd!=NULL) {
- if (strlen(pd) > 0) {
- if (strlen(pd)+strlen(string_ptr) < MAX_DECODE_BUFFER_SIZE ) {
- strcat(string_ptr, pd);
- }
- else
- {
- simple_dialog(ESD_TYPE_CRIT, NULL, "Decode Buffer Size Exceeded.");
- return;
- }
- }
- }
+gboolean
+find_packet_summary_line(capture_file *cf, const char *string)
+{
+ match_data mdata;
- /* 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--;
- }
- }
+ mdata.string = string;
+ mdata.string_len = strlen(string);
+ return find_packet(cf, match_summary_line, &mdata);
}
-gboolean
-find_in_gtk_data(capture_file *cf, gpointer *data, char *ascii_text, gboolean case_type, gboolean summary_search)
+static gboolean
+match_summary_line(capture_file *cf, frame_data *fdata, void *criterion)
{
- 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);
+ match_data *mdata = criterion;
+ const gchar *string = mdata->string;
+ size_t string_len = mdata->string_len;
+ epan_dissect_t *edt;
+ const char *info_column;
+ size_t info_column_len;
+ gboolean frame_matched = FALSE;
+ gint colx;
+ guint32 i;
+ guint8 c_char;
+ size_t c_match = 0;
+
+ /* Don't bother constructing the protocol tree */
+ edt = epan_dissect_new(FALSE, FALSE);
+ /* Get the column information */
+ epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
+
+ /* Find the Info column */
+ for (colx = 0; colx < cf->cinfo.num_cols; colx++) {
+ if (cf->cinfo.fmt_matx[colx][COL_INFO]) {
+ /* Found it. See if we match. */
+ info_column = edt->pi.cinfo->col_data[colx];
+ info_column_len = strlen(info_column);
+ for (i = 0; i < info_column_len; i++) {
+ c_char = info_column[i];
+ if (cf->case_type)
+ c_char = toupper(c_char);
+ if (c_char == string[c_match]) {
+ c_match++;
+ if (c_match == string_len) {
+ frame_matched = TRUE;
+ break;
+ }
+ } else
+ c_match = 0;
}
+ break;
+ }
+ }
+ epan_dissect_free(edt);
+ return frame_matched;
+}
- 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;
+typedef struct {
+ const guint8 *data;
+ size_t data_len;
+} cbs_t; /* "Counted byte string" */
- /* 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);
- }
+gboolean
+find_packet_data(capture_file *cf, const guint8 *string, size_t string_size)
+{
+ cbs_t info;
- cf->progbar_nextstep += cf->progbar_quantum;
- }
+ info.data = string;
+ info.data_len = string_size;
- if (stop_flag) {
- /* Well, the user decided to abort the search. Go back to the
- frame where we started. */
- new_fd = start_fd;
- break;
- }
+ /* String or hex search? */
+ if (cf->ascii) {
+ /* String search - what type of string? */
+ switch (cf->scs_type) {
- /* 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 */
- }
+ case SCS_ASCII_AND_UNICODE:
+ return find_packet(cf, match_ascii_and_unicode, &info);
- 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);
- }
+ case SCS_ASCII:
+ return find_packet(cf, match_ascii, &info);
- 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;
- }
- }
+ case SCS_UNICODE:
+ return find_packet(cf, match_unicode, &info);
- /* We're done scanning the packets; destroy the progress bar if it
- was created. */
- if (progbar != NULL)
- destroy_progress_dlg(progbar);
+ default:
+ g_assert_not_reached();
+ return FALSE;
}
+ } else
+ return find_packet(cf, match_binary, &info);
+}
- 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);
+static gboolean
+match_ascii_and_unicode(capture_file *cf, frame_data *fdata, void *criterion)
+{
+ cbs_t *info = criterion;
+ const char *ascii_text = info->data;
+ size_t textlen = info->data_len;
+ gboolean frame_matched;
+ guint32 buf_len;
+ guint32 i;
+ guint8 c_char;
+ size_t c_match = 0;
+
+ frame_matched = FALSE;
+ buf_len = fdata->pkt_len;
+ for (i = 0; i < buf_len; i++) {
+ c_char = cf->pd[i];
+ if (cf->case_type)
+ c_char = toupper(c_char);
+ if (c_char != 0) {
+ if (c_char == ascii_text[c_match]) {
+ c_match++;
+ if (c_match == textlen) {
+ frame_matched = TRUE;
+ break;
+ }
+ } else
+ c_match = 0;
+ }
+ }
+ return frame_matched;
+}
- /* Select that row, make it the focus row, and make it visible. */
- packet_list_set_selected_row(row);
- return TRUE; /* success */
+static gboolean
+match_ascii(capture_file *cf, frame_data *fdata, void *criterion)
+{
+ cbs_t *info = criterion;
+ const char *ascii_text = info->data;
+ size_t textlen = info->data_len;
+ gboolean frame_matched;
+ guint32 buf_len;
+ guint32 i;
+ guint8 c_char;
+ size_t c_match = 0;
+
+ frame_matched = FALSE;
+ buf_len = fdata->pkt_len;
+ for (i = 0; i < buf_len; i++) {
+ c_char = cf->pd[i];
+ if (cf->case_type)
+ c_char = toupper(c_char);
+ if (c_char == ascii_text[c_match]) {
+ c_match++;
+ if (c_match == textlen) {
+ frame_matched = TRUE;
+ break;
+ }
} else
- return FALSE; /* failure */
+ c_match = 0;
+ }
+ return frame_matched;
}
-gboolean
-find_ascii(capture_file *cf, char *ascii_text, gboolean ascii_search, char *ftype, gboolean case_type)
+static gboolean
+match_unicode(capture_file *cf, frame_data *fdata, void *criterion)
{
- 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;
-
- 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 && ascii_search) {
- g_strup(ascii_text);
+ cbs_t *info = criterion;
+ const char *ascii_text = info->data;
+ size_t textlen = info->data_len;
+ gboolean frame_matched;
+ guint32 buf_len;
+ guint32 i;
+ guint8 c_char;
+ size_t c_match = 0;
+
+ frame_matched = FALSE;
+ buf_len = fdata->pkt_len;
+ for (i = 0; i < buf_len; i++) {
+ c_char = cf->pd[i];
+ if (cf->case_type)
+ c_char = toupper(c_char);
+ if (c_char == ascii_text[c_match]) {
+ c_match++;
+ i++;
+ if (c_match == textlen) {
+ frame_matched = TRUE;
+ break;
}
+ } else
+ c_match = 0;
+ }
+ return frame_matched;
+}
- 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);
- frame_matched = FALSE;
- buf_len = fdata->pkt_len;
- for (i=0;i<buf_len;i++) {
- if (ascii_search && case_type) {
- uppercase = &cf->pd[i];
- g_strup(uppercase);
- c_char = uppercase[0];
- }
- else
- c_char = cf->pd[i];
- /* Check to see if this is an String or Hex search */
- if (ascii_search) {
- /* Now check the String Type */
- if(strcmp(ftype,"ASCII Unicode & Non-Unicode")==0)
- {
- if (c_char != 0) {
- if (c_char == ascii_text[c_match]) {
- c_match++;
- if (c_match == strlen(ascii_text)) {
- frame_matched = TRUE;
- break;
- }
- }
- else
- {
- c_match = 0;
- }
- }
- }
- else if(strcmp(ftype,"ASCII Non-Unicode")==0)
- {
- if (c_char == ascii_text[c_match]) {
- c_match++;
- if (c_match == strlen(ascii_text)) {
- frame_matched = TRUE;
- break;
- }
- }
- else
- {
- c_match = 0;
- }
- }
- else if(strcmp(ftype, "ASCII Unicode")==0)
- {
- if (c_char == ascii_text[c_match]) {
- c_match++;
- i++;
- if (c_match == strlen(ascii_text)) {
- frame_matched = TRUE;
- break;
- }
- }
- else
- {
- c_match = 0;
- }
- }
- else if(strcmp(ftype,"EBCDIC")==0)
- {
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "EBCDIC Find Not supported yet.");
- return TRUE;
- }
- else
- {
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Invalid String type specified.");
- return TRUE;
- }
- }
- else /* Hex Search */
- {
- char_val = ascii_text[c_match];
- num1 = get_int_value(char_val);
- char_val = ascii_text[++c_match];
- num2 = get_int_value(char_val);
- hex_val = (num1*0x10)+num2;
- if ( c_char == hex_val) {
- 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! */
- }
- }
-
- 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;
- }
+static gboolean
+match_binary(capture_file *cf, frame_data *fdata, void *criterion)
+{
+ cbs_t *info = criterion;
+ const guint8 *binary_data = info->data;
+ size_t datalen = info->data_len;
+ gboolean frame_matched;
+ guint32 buf_len;
+ guint32 i;
+ size_t c_match = 0;
+
+ frame_matched = FALSE;
+ buf_len = fdata->pkt_len;
+ for (i = 0; i < buf_len; i++) {
+ if (cf->pd[i] == binary_data[c_match]) {
+ c_match++;
+ if (c_match == datalen) {
+ frame_matched = TRUE;
+ break;
}
+ } else
+ c_match = 0;
+ }
+ return frame_matched;
+}
- /* We're done scanning the packets; destroy the progress bar if it
- was created. */
- if (progbar != NULL)
- destroy_progress_dlg(progbar);
- }
+gboolean
+find_packet_dfilter(capture_file *cf, dfilter_t *sfcode)
+{
+ return find_packet(cf, match_dfilter, sfcode);
+}
- 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);
+static gboolean
+match_dfilter(capture_file *cf, frame_data *fdata, void *criterion)
+{
+ dfilter_t *sfcode = criterion;
+ epan_dissect_t *edt;
+ gboolean frame_matched;
- /* 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 */
+ edt = epan_dissect_new(TRUE, FALSE);
+ epan_dissect_prime_dfilter(edt, sfcode);
+ epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+ epan_dissect_free(edt);
+ return frame_matched;
}
-gboolean
-find_packet(capture_file *cf, dfilter_t *sfcode)
+static gboolean
+find_packet(capture_file *cf,
+ gboolean (*match_function)(capture_file *, frame_data *, void *),
+ void *criterion)
{
frame_data *start_fd;
frame_data *fdata;
@@ -1993,9 +1801,7 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
gboolean stop_flag;
int count;
int err;
- gboolean frame_matched;
int row;
- epan_dissect_t *edt;
float prog_val;
GTimeVal start_time;
gchar status_str[100];
@@ -2069,16 +1875,13 @@ find_packet(capture_file *cf, dfilter_t *sfcode)
/* Is this packet in the display? */
if (fdata->flags.passed_dfilter) {
- /* Yes. Does it match the search filter? */
+ /* Yes. Load its data. */
/* XXX - do something with "err" */
wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header,
cf->pd, fdata->cap_len, &err);
- edt = epan_dissect_new(TRUE, FALSE);
- epan_dissect_prime_dfilter(edt, sfcode);
- epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, NULL);
- frame_matched = dfilter_apply_edt(sfcode, edt);
- epan_dissect_free(edt);
- if (frame_matched) {
+
+ /* Does it match the search criterion? */
+ if ((*match_function)(cf, fdata, criterion)) {
new_fd = fdata;
break; /* found it! */
}
diff --git a/file.h b/file.h
index 94ce1895cc..0a7396802b 100644
--- a/file.h
+++ b/file.h
@@ -1,7 +1,7 @@
/* file.h
* Definitions for file structures and routines
*
- * $Id: file.h,v 1.103 2003/08/11 22:41:09 sharpe Exp $
+ * $Id: file.h,v 1.104 2003/08/29 04:03:45 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -55,7 +55,13 @@ void colorize_packets(capture_file *);
void redissect_packets(capture_file *cf);
int print_packets(capture_file *cf, print_args_t *print_args);
void change_time_formats(capture_file *);
-gboolean find_packet(capture_file *cf, dfilter_t *sfcode);
+
+gboolean find_packet_protocol_tree(capture_file *cf, const char *string);
+gboolean find_packet_summary_line(capture_file *cf, const char *string);
+gboolean find_packet_data(capture_file *cf, const guint8 *string,
+ size_t string_size);
+gboolean find_packet_dfilter(capture_file *cf, dfilter_t *sfcode);
+
guint8 get_int_value(char char_val);
gboolean find_ascii(capture_file *cf, char *ascii_text, gboolean ascii_search, char *ftype, gboolean case_type);
gboolean find_in_gtk_data(capture_file *cf, gpointer *data, char *ascii_text, gboolean case_type, gboolean search_type);
diff --git a/gtk/find_dlg.c b/gtk/find_dlg.c
index cbdb97b3b8..c0ca252f1d 100644
--- a/gtk/find_dlg.c
+++ b/gtk/find_dlg.c
@@ -1,7 +1,7 @@
/* find_dlg.c
* Routines for "find frame" window
*
- * $Id: find_dlg.c,v 1.32 2003/08/28 23:25:55 guy Exp $
+ * $Id: find_dlg.c,v 1.33 2003/08/29 04:03:46 guy Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@@ -22,11 +22,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#include <string.h>
+#include <ctype.h>
+
#include <gtk/gtk.h>
#include <epan/proto.h>
@@ -44,17 +46,17 @@
#include "keys.h"
/* Capture callback data keys */
-#define E_FIND_FILT_KEY "find_filter_te"
-#define E_FIND_BACKWARD_KEY "find_backward"
-#define E_FIND_HEXDATA_KEY "find_hex"
-#define E_FIND_ASCIIDATA_KEY "find_ascii"
+#define E_FIND_FILT_KEY "find_filter_te"
+#define E_FIND_BACKWARD_KEY "find_backward"
+#define E_FIND_HEXDATA_KEY "find_hex"
+#define E_FIND_ASCIIDATA_KEY "find_ascii"
#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"
-#define E_FILT_TE_BUTTON_KEY "find_filter_button"
+#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"
+#define E_FILT_TE_BUTTON_KEY "find_filter_button"
static gboolean case_type = TRUE;
static gboolean summary_data = FALSE;
@@ -207,7 +209,6 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_rb), !cfile.hex && !cfile.ascii);
gtk_box_pack_start(GTK_BOX(hex_hb), filter_rb, TRUE, TRUE, 0);
gtk_tooltips_set_tip (tooltips, filter_rb, ("Search for data by display filter syntax.\ne.g. ip.addr==10.1.1.1"), NULL);
- SIGNAL_CONNECT(filter_rb, "clicked", filter_selected_cb, find_frame_w);
gtk_widget_show(filter_rb);
/* Hex */
@@ -237,7 +238,6 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
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);
gtk_tooltips_set_tip (tooltips, ascii_rb, ("Search for data by string value.\ne.g. My String"), NULL);
- SIGNAL_CONNECT(ascii_rb, "clicked", ascii_selected_cb, find_frame_w);
gtk_widget_show(ascii_rb);
string_window_frame = gtk_frame_new("Search in");
@@ -306,8 +306,8 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
glist = g_list_append(glist, "ASCII Unicode & Non-Unicode");
glist = g_list_append(glist, "ASCII Non-Unicode");
glist = g_list_append(glist, "ASCII Unicode");
- glist = g_list_append(glist, "EBCDIC");
+ /* XXX - make it non-editable - or make this an option menu instead */
gtk_combo_set_popdown_strings(GTK_COMBO(combo_cb), glist);
gtk_container_border_width(GTK_CONTAINER(combo_cb), 1);
gtk_container_add(GTK_CONTAINER(string_char_frame), combo_cb);
@@ -375,6 +375,14 @@ find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
OBJECT_SET_DATA(find_frame_w, E_SOURCE_SUMMARY_KEY, summary_data_rb);
OBJECT_SET_DATA(find_frame_w, E_FILT_TE_BUTTON_KEY, filter_bt);
+ /*
+ * Now that we've attached the pointers, connect the signals - if
+ * we do so before we've attached the pointers, the signals may
+ * be delivered before the pointers are attached; the signal
+ * handlers expect the pointers to be attached, and won't be happy.
+ */
+ SIGNAL_CONNECT(ascii_rb, "clicked", ascii_selected_cb, find_frame_w);
+ SIGNAL_CONNECT(filter_rb, "clicked", filter_selected_cb, find_frame_w);
ascii_selected_cb(NULL, find_frame_w);
filter_selected_cb(NULL, find_frame_w);
@@ -452,14 +460,118 @@ filter_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w)
return;
}
+static guint8 *
+convert_string_to_hex(const char *string, size_t *nbytes)
+{
+ size_t n_bytes;
+ const char *p;
+ guchar c;
+ guint8 *bytes, *q, byte_val;
+
+ n_bytes = 0;
+ p = &string[0];
+ for (;;) {
+ c = *p++;
+ if (c == '\0')
+ break;
+ if (isspace(c))
+ continue; /* allow white space */
+ if (!isxdigit(c)) {
+ /* Not a valid hex digit - fail */
+ return NULL;
+ }
+
+ /*
+ * We can only match bytes, not nibbles; we must have a valid
+ * hex digit immediately after that hex digit.
+ */
+ c = *p++;
+ if (!isxdigit(c))
+ return NULL;
+
+ /* 2 hex digits = 1 byte */
+ n_bytes++;
+ }
+
+ /*
+ * Were we given any hex digits?
+ */
+ if (n_bytes == 0) {
+ /* No. */
+ return NULL;
+ }
+
+ /*
+ * OK, it's valid, and it generates "n_bytes" bytes; generate the
+ * raw byte array.
+ */
+ bytes = g_malloc(n_bytes);
+ p = &string[0];
+ q = &bytes[0];
+ for (;;) {
+ c = *p++;
+ if (c == '\0')
+ break;
+ if (isspace(c))
+ continue; /* allow white space */
+ /* From the loop above, we know this is a hex digit */
+ if (isdigit(c))
+ byte_val = c - '0';
+ else if (c >= 'a')
+ byte_val = (c - 'a') + 10;
+ else
+ byte_val = (c - 'A') + 10;
+ byte_val <<= 4;
+
+ /* We also know this is a hex digit */
+ c = *p++;
+ if (isdigit(c))
+ byte_val |= c - '0';
+ else if (c >= 'a')
+ byte_val |= (c - 'a') + 10;
+ else if (c >= 'A')
+ byte_val |= (c - 'A') + 10;
+
+ *q++ = byte_val;
+ }
+ *nbytes = n_bytes;
+ return bytes;
+}
+
+static char *
+convert_string_case(const char *string, gboolean case_insensitive)
+{
+ char *out_string;
+ const char *p;
+ char c;
+ char *q;
+
+ /*
+ * Copy if if it's a case-sensitive search; uppercase it if it's
+ * a case-insensitive search.
+ */
+ if (case_insensitive) {
+ out_string = g_malloc(strlen(string) + 1);
+ for (p = &string[0], q = &out_string[0]; (c = *p) != '\0'; p++, q++)
+ *q = toupper((unsigned char)*p);
+ *q = '\0';
+ } else
+ out_string = g_strdup(string);
+ return out_string;
+}
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,
- *decode_data_rb, *summary_data_rb;
- gchar *filter_text, *string_type;
- dfilter_t *sfcode;
+ GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb,
+ *case_cb, *decode_data_rb, *summary_data_rb;
+ gchar *filter_text, *string_type;
+ search_charset_t scs_type = SCS_ASCII_AND_UNICODE;
+ guint8 *bytes = NULL;
+ size_t nbytes;
+ char *string = NULL;
+ dfilter_t *sfcode;
+ gboolean found_packet;
filter_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILT_KEY);
backward_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_BACKWARD_KEY);
@@ -478,61 +590,116 @@ find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
summary_data = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(summary_data_rb));
/*
- * Try to compile the filter.
+ * Process the search criterion.
*/
- if (!dfilter_compile(filter_text, &sfcode) && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) {
- /* The attempt failed; report an error. */
- simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
- return;
- }
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb))) {
+ /*
+ * Hex search - scan the search string to make sure it's valid hex
+ * and to find out how many bytes there are.
+ */
+ bytes = convert_string_to_hex(filter_text, &nbytes);
+ if (bytes == NULL) {
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "You didn't specify a valid hex string.");
+ return;
+ }
+ } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (ascii_rb))) {
+ /*
+ * String search.
+ * Get the character set type.
+ */
+ if (strcmp(string_type, "ASCII Unicode & Non-Unicode") == 0)
+ scs_type = SCS_ASCII_AND_UNICODE;
+ else if (strcmp(string_type, "ASCII Non-Unicode") == 0)
+ scs_type = SCS_ASCII;
+ else if (strcmp(string_type, "ASCII Unicode") == 0)
+ scs_type = SCS_UNICODE;
+ else {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a valid character set.");
+ return;
+ }
+ string = convert_string_case(filter_text, case_type);
+ } else {
+ /*
+ * Display filter search - try to compile the filter.
+ */
+ if (!dfilter_compile(filter_text, &sfcode)) {
+ /* The attempt failed; report an error. */
+ simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
+ return;
+ }
- /* Was it empty? */
- if (sfcode == NULL && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) {
- /* Yes - complain. */
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "You didn't specify valid search criteria.");
- return;
+ /* Was it empty? */
+ if (sfcode == NULL) {
+ /* Yes - complain. */
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "You didn't specify a valid filter expression.");
+ return;
+ }
}
/*
- * Remember the filter.
+ * Remember the search parameters.
*/
if (cfile.sfilter)
g_free(cfile.sfilter);
cfile.sfilter = g_strdup(filter_text);
-
cfile.sbackward = GTK_TOGGLE_BUTTON (backward_rb)->active;
- cfile.hex = GTK_TOGGLE_BUTTON (hex_rb)->active;
- cfile.ascii = GTK_TOGGLE_BUTTON (ascii_rb)->active;
- cfile.ftype = g_strdup(string_type);
-
- if (!GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active ) {
- if (!find_packet(&cfile, sfcode)) {
+ cfile.hex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb));
+ cfile.ascii = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (ascii_rb));
+ cfile.scs_type = scs_type;
+ cfile.case_type = case_type;
+ cfile.decode_data = decode_data;
+ cfile.summary_data = summary_data;
+
+ if (cfile.hex) {
+ found_packet = find_packet_data(&cfile, bytes, nbytes);
+ g_free(bytes);
+ if (!found_packet) {
+ /* We didn't find a packet */
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained those bytes.");
+ g_free(bytes);
+ return;
+ }
+ } else if (cfile.ascii) {
+ /* OK, what are we searching? */
+ if (cfile.decode_data) {
+ /* The text in the protocol tree */
+ found_packet = find_packet_protocol_tree(&cfile, string);
+ g_free(string);
+ if (!found_packet) {
/* We didn't find the packet. */
- simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched that filter.");
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained that string in its dissected display.");
return;
}
- }
- else
- {
- 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 if (cfile.summary_data) {
+ /* The text in the summary line */
+ found_packet = find_packet_summary_line(&cfile, string);
+ g_free(string);
+ if (!found_packet) {
+ /* We didn't find the packet. */
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained that string in its Info column.");
+ 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;
- }
+ } else {
+ /* The raw packet data */
+ found_packet = find_packet_data(&cfile, string, strlen(string));
+ g_free(string);
+ if (!found_packet) {
+ /* We didn't find the packet. */
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet contained that string in its data.");
+ return;
}
+ }
+ } else {
+ found_packet = find_packet_dfilter(&cfile, sfcode);
+ dfilter_free(sfcode);
+ if (!found_packet) {
+ /* We didn't find a packet */
+ simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched that filter.");
+ g_free(bytes);
+ return;
+ }
}
gtk_widget_destroy(GTK_WIDGET(parent_w));
}
@@ -554,28 +721,56 @@ find_frame_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
static void
find_previous_next(GtkWidget *w, gpointer d, gboolean sens)
{
+ guint8 *bytes;
+ size_t nbytes;
+ char *string;
dfilter_t *sfcode;
-
if (cfile.sfilter) {
- if (!dfilter_compile(cfile.sfilter, &sfcode) && !cfile.hex && !cfile.ascii)
+ cfile.sbackward = sens;
+ if (cfile.hex) {
+ bytes = convert_string_to_hex(cfile.sfilter, &nbytes);
+ if (bytes == NULL) {
+ /*
+ * XXX - this shouldn't happen, as we've already successfully
+ * translated the string once.
+ */
return;
- if (sfcode == NULL && !cfile.hex && !cfile.ascii)
+ }
+ find_packet_data(&cfile, bytes, nbytes);
+ g_free(bytes);
+ } else if (cfile.ascii) {
+ string = convert_string_case(cfile.sfilter, cfile.case_type);
+ /* OK, what are we searching? */
+ if (cfile.decode_data) {
+ /* The text in the protocol tree */
+ find_packet_protocol_tree(&cfile, string);
+ } else if (cfile.summary_data) {
+ /* The text in the summary line */
+ find_packet_summary_line(&cfile, string);
+ } else {
+ /* The raw packet data */
+ find_packet_data(&cfile, string, strlen(string));
+ }
+ g_free(string);
+ } else {
+ if (!dfilter_compile(cfile.sfilter, &sfcode)) {
+ /*
+ * XXX - this shouldn't happen, as we've already successfully
+ * translated the string once.
+ */
return;
- cfile.sbackward = sens;
- if (cfile.hex || cfile.ascii)
- {
- 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
- {
- find_packet(&cfile, sfcode);
- }
+ }
+ if (sfcode == NULL) {
+ /*
+ * XXX - this shouldn't happen, as we've already found that the
+ * string wasn't null.
+ */
+ return;
+ }
+ find_packet_dfilter(&cfile, sfcode);
+ dfilter_free(sfcode);
+ }
} else
find_frame_cb(w, d);
}