aboutsummaryrefslogtreecommitdiffstats
path: root/gtk/find_dlg.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2003-08-29 04:03:46 +0000
committerGuy Harris <guy@alum.mit.edu>2003-08-29 04:03:46 +0000
commit1cf6565adc2cc5eb7d51bb4ed9d44d0944d2361d (patch)
tree3b1ce973a5f1d1270672807ce6c88cbcdef63dce /gtk/find_dlg.c
parent6fc18311a67219ed55c788a829b85e0a0bcb79a0 (diff)
Get rid of the EBCDIC stuff in the find dialog - it's not supported yet,
so we shouldn't torment the users by offering it. Check the string type and convert it to an internal representation in the GUI code; have the search code deal only with the internal representation. Save the case-sensitivity flag, and the indication of where string searches look, along with other search parameters. Upper-casify the string, for case-insensitive searches, in the GUI code; don't save the upper-casified string, so it doesn't SHOUT at you when you next pop up a "find" dialog. Convert the hex value string to raw binary data in the GUI code, rather than doing so in the search code. Check that it's a valid string. Connect the signals to the radio buttons after the pointers have been attached to various GUI items - the signal handlers expect some of those pointers to be attached, and aren't happy if they're not. Have "find_packet()" contain a framework for searching, but not contain the matching code; instead, pass it a pointer to a matching routine and an opaque pointer to be passed to the matching routine. Have all the routines that do different types of searching have their own matching routines, and use the common "find_packet()" code, rather than duplicating that code. Search for the Info column by column type, not by name (the user can change the name). When matching on the protocol tree, don't format the entire protocol tree into a big buffer - just have a routine that matches the text representation of a protocol tree item against a string, and, if it finds a match, sets a "we found a match flag" and returns; have that routine not bother doing any more work if that flag is set. (Unfortunately, you can't abort "g_node_children_foreach()" in the middle of a traversal.) Free the generated display filter code after a find-by-display-filter finishes. svn path=/trunk/; revision=8306
Diffstat (limited to 'gtk/find_dlg.c')
-rw-r--r--gtk/find_dlg.c345
1 files changed, 270 insertions, 75 deletions
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);
}