more code cleanup from dialog things:
[obnox/wireshark/wip.git] / gtk / find_dlg.c
1 /* find_dlg.c
2  * Routines for "find frame" window
3  *
4  * $Id: find_dlg.c,v 1.53 2004/05/26 03:49:23 ulfl Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <string.h>
30 #include <ctype.h>
31
32 #include <gtk/gtk.h>
33
34 #include <epan/proto.h>
35 #include <epan/dfilter/dfilter.h>
36 #include "globals.h"
37
38 #include "ui_util.h"
39 #include "find_dlg.h"
40 #include "filter_prefs.h"
41 #include "alert_box.h"
42 #include "simple_dialog.h"
43 #include "dlg_utils.h"
44 #include "compat_macros.h"
45 #include "prefs.h"
46 #include "prefs_dlg.h"
47 #include "keys.h"
48
49 /* Capture callback data keys */
50 #define E_FIND_FILT_KEY       "find_filter_te"
51 #define E_FIND_BACKWARD_KEY   "find_backward"
52 #define E_FIND_HEXDATA_KEY    "find_hex"
53 #define E_FIND_STRINGDATA_KEY "find_string"
54 #define E_FIND_FILTERDATA_KEY "find_filter"
55 #define E_FIND_STRINGTYPE_KEY "find_string_type"
56 #define E_FIND_STRINGTYPE_LABEL_KEY "find_string_type_label"
57 #define E_CASE_SEARCH_KEY     "case_insensitive_search"
58 #define E_SOURCE_HEX_KEY      "hex_data_source"
59 #define E_SOURCE_DECODE_KEY   "decode_data_source"
60 #define E_SOURCE_SUMMARY_KEY  "summary_data_source"
61 #define E_FILT_TE_BUTTON_KEY  "find_filter_button"
62
63 static gboolean case_type = TRUE;
64 static gboolean summary_data = FALSE;
65 static gboolean decode_data = FALSE;
66
67 static void
68 find_filter_te_syntax_check_cb(GtkWidget *w, gpointer parent_w);
69
70 static void
71 find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
72
73 static void
74 find_frame_close_cb(GtkWidget *close_bt, gpointer parent_w);
75
76 static void
77 find_frame_destroy_cb(GtkWidget *win, gpointer user_data);
78
79 static void
80 hex_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w);
81
82 static void
83 string_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w);
84
85 static void
86 filter_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w);
87
88 static guint8 *
89 convert_string_to_hex(const char *string, size_t *nbytes);
90
91 /*
92  * Keep a static pointer to the current "Find Packet" window, if any, so
93  * that if somebody tries to do "Find Packet" while there's already a
94  * "Find Packet" window up, we just pop up the existing one, rather than
95  * creating a new one.
96  */
97 static GtkWidget *find_frame_w;
98 static GtkWidget *filter_text_box;
99
100 void
101 find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
102 {
103   GtkWidget     *main_vb, *main_find_hb, *main_options_hb,
104       
105                 *find_type_frame, *find_type_vb,
106                 *find_type_hb, *find_type_lb, *hex_rb, *string_rb, *filter_rb,
107                 *filter_hb, *filter_bt,
108
109                 *direction_frame, *direction_vb,
110                 *up_rb, *down_rb,
111
112                 *data_frame, *data_vb,
113                 *hex_data_rb, *decode_data_rb, *summary_data_rb,
114
115                 *string_opt_frame, *string_opt_vb,
116                 *case_cb, *combo_lb, *combo_cb, 
117
118                 *bbox, *ok_bt, *cancel_bt;
119   GtkTooltips   *tooltips;
120 #if GTK_MAJOR_VERSION < 2
121   GtkAccelGroup *accel_group;
122 #endif
123   GList *glist = NULL;
124   /* No Apply button, but "OK" not only sets our text widget, it
125      activates it (i.e., it causes us to do the search). */
126   static construct_args_t args = {
127         "Ethereal: Search Filter",
128         FALSE,
129         TRUE
130   };
131
132   if (find_frame_w != NULL) {
133     /* There's already a "Find Packet" dialog box; reactivate it. */
134     reactivate_window(find_frame_w);
135     return;
136   }
137
138   find_frame_w = dlg_window_new("Ethereal: Find Packet");
139
140   tooltips = gtk_tooltips_new ();
141
142 #if GTK_MAJOR_VERSION < 2
143   /* Accelerator group for the accelerators (or, as they're called in
144      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
145      Ctrl+<key> is an accelerator). */
146   accel_group = gtk_accel_group_new();
147   gtk_window_add_accel_group(GTK_WINDOW(find_frame_w), accel_group);
148 #endif
149
150   /* Container for each row of widgets */
151   main_vb = gtk_vbox_new(FALSE, 3);
152   gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
153   gtk_container_add(GTK_CONTAINER(find_frame_w), main_vb);
154   gtk_widget_show(main_vb);
155
156
157   /* */
158   main_find_hb = gtk_hbox_new(FALSE, 3);
159   gtk_container_add(GTK_CONTAINER(main_vb), main_find_hb);
160   gtk_widget_show(main_find_hb);
161
162
163   /* find frame */
164   find_type_frame = gtk_frame_new("Find");
165   gtk_box_pack_start(GTK_BOX(main_find_hb), find_type_frame, TRUE, TRUE, 0);
166   gtk_widget_show(find_type_frame);
167
168   find_type_vb = gtk_vbox_new(FALSE, 3);
169   gtk_container_border_width(GTK_CONTAINER(find_type_vb), 3);
170   gtk_container_add(GTK_CONTAINER(find_type_frame), find_type_vb);
171   gtk_widget_show(find_type_vb);
172
173   /* find type row */
174   find_type_hb = gtk_hbox_new(FALSE, 3);
175   gtk_container_add(GTK_CONTAINER(find_type_vb), find_type_hb);
176   gtk_widget_show(find_type_hb);
177
178   find_type_lb = gtk_label_new("By:");
179   gtk_box_pack_start(GTK_BOX(find_type_hb), find_type_lb, FALSE, FALSE, 0);
180   gtk_widget_show(find_type_lb);
181
182   /* Filter */
183   filter_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL,
184                "_Display filter", accel_group);
185   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filter_rb), !cfile.hex && !cfile.string);
186   gtk_box_pack_start(GTK_BOX(find_type_hb), filter_rb, FALSE, FALSE, 0);
187   gtk_tooltips_set_tip (tooltips, filter_rb, ("Search for data by display filter syntax.\ne.g. ip.addr==10.1.1.1"), NULL);
188   gtk_widget_show(filter_rb);
189
190   /* Hex */
191   hex_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(filter_rb,
192                "_Hex value", accel_group);
193   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hex_rb), cfile.hex);
194   gtk_box_pack_start(GTK_BOX(find_type_hb), hex_rb, FALSE, FALSE, 0);
195   gtk_tooltips_set_tip (tooltips, hex_rb, ("Search for data by hex string.\ne.g. fffffda5"), NULL);
196   gtk_widget_show(hex_rb);
197
198   /* ASCII Search */
199   string_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(filter_rb,
200                "_String", accel_group);
201   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(string_rb), cfile.string);
202   gtk_box_pack_start(GTK_BOX(find_type_hb), string_rb, FALSE, FALSE, 0);
203   gtk_tooltips_set_tip (tooltips, string_rb, ("Search for data by string value.\ne.g. My String"), NULL);
204   gtk_widget_show(string_rb);
205
206   /* Filter row */
207   filter_hb = gtk_hbox_new(FALSE, 3);
208   gtk_box_pack_start(GTK_BOX(find_type_vb), filter_hb, FALSE, FALSE, 0);
209   gtk_widget_show(filter_hb);
210
211   filter_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
212   SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
213   SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
214   OBJECT_SET_DATA(filter_bt, E_FILT_TE_BUTTON_KEY, filter_bt);
215   gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
216   gtk_tooltips_set_tip (tooltips, filter_bt, ("Click on the filter button to select a display filter,\nor enter your search criteria into the text box"), NULL);
217   gtk_widget_show(filter_bt);
218
219   filter_text_box = gtk_entry_new();
220   if (cfile.sfilter) gtk_entry_set_text(GTK_ENTRY(filter_text_box), cfile.sfilter);
221   OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_text_box);
222   OBJECT_SET_DATA(find_frame_w, E_FILT_TE_PTR_KEY, filter_text_box);
223   gtk_box_pack_start(GTK_BOX(filter_hb), filter_text_box, TRUE, TRUE, 0);
224   SIGNAL_CONNECT(filter_text_box, "changed", find_filter_te_syntax_check_cb, find_frame_w);
225   gtk_widget_show(filter_text_box);
226
227
228   /* */
229   main_options_hb = gtk_hbox_new(FALSE, 3);
230   gtk_container_add(GTK_CONTAINER(main_vb), main_options_hb);
231   gtk_widget_show(main_options_hb);
232
233
234   /* search in frame */
235   data_frame = gtk_frame_new("Search In");
236   gtk_box_pack_start(GTK_BOX(main_options_hb), data_frame, TRUE, TRUE, 0);
237   gtk_widget_show(data_frame);
238
239   /* search in row */
240   data_vb = gtk_vbox_new(TRUE, 0);
241   gtk_container_border_width(GTK_CONTAINER(data_vb), 3);
242   gtk_container_add(GTK_CONTAINER(data_frame), data_vb);
243   gtk_widget_show(data_vb);
244
245   /* Packet list */
246   summary_data_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL,
247                "Packet list", accel_group);
248   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(summary_data_rb), summary_data);
249   gtk_box_pack_start(GTK_BOX(data_vb), summary_data_rb, TRUE, TRUE, 0);
250   gtk_tooltips_set_tip (tooltips, summary_data_rb, ("Search for string in the Info column of the packet summary (top pane)"), NULL);
251   gtk_widget_show(summary_data_rb);
252
253   /* Packet details */
254   decode_data_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(summary_data_rb,
255                "Packet details", accel_group);
256   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(decode_data_rb), decode_data);
257   gtk_box_pack_start(GTK_BOX(data_vb), decode_data_rb, TRUE, TRUE, 0);
258   gtk_tooltips_set_tip (tooltips, decode_data_rb, ("Search for string in the decoded packet display (middle pane)"), NULL);
259   gtk_widget_show(decode_data_rb);
260
261   /* Packet bytes */
262   hex_data_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(summary_data_rb, 
263                 "Packet bytes", accel_group);
264   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hex_data_rb), !decode_data && !summary_data);
265   gtk_box_pack_start(GTK_BOX(data_vb), hex_data_rb, TRUE, TRUE, 0);
266   gtk_tooltips_set_tip (tooltips, hex_data_rb, ("Search for string in the packet data"), NULL);
267   gtk_widget_show(hex_data_rb);
268
269   /* string options frame */
270   string_opt_frame = gtk_frame_new("String Options");
271   gtk_box_pack_start(GTK_BOX(main_options_hb), string_opt_frame, TRUE, TRUE, 0);
272   gtk_widget_show(string_opt_frame);
273
274   string_opt_vb = gtk_vbox_new(FALSE, 0);
275   gtk_container_add(GTK_CONTAINER(string_opt_frame), string_opt_vb);
276   gtk_container_border_width(GTK_CONTAINER(string_opt_vb), 3);
277   gtk_widget_show(string_opt_vb);
278
279   case_cb = CHECK_BUTTON_NEW_WITH_MNEMONIC(
280                 "Case sensitive", accel_group);
281   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(case_cb), !case_type);
282   gtk_container_add(GTK_CONTAINER(string_opt_vb), case_cb);
283   gtk_tooltips_set_tip (tooltips, case_cb, ("Search by mixed upper/lower case?"), NULL);
284   gtk_widget_show(case_cb);
285
286   combo_lb = gtk_label_new("Character set:");
287   gtk_container_add(GTK_CONTAINER(string_opt_vb), combo_lb);
288   gtk_misc_set_alignment(GTK_MISC(combo_lb), 0.0, 0.5);
289   gtk_widget_show(combo_lb);
290
291   /* String Type Selection Dropdown Box 
292      These only apply to the Hex Window search option */
293   /* Create Combo Box */
294   combo_cb = gtk_combo_new();
295
296   glist = g_list_append(glist, "ASCII Unicode & Non-Unicode");
297   glist = g_list_append(glist, "ASCII Non-Unicode");
298   glist = g_list_append(glist, "ASCII Unicode");
299
300   gtk_combo_set_popdown_strings(GTK_COMBO(combo_cb), glist);
301   /* You only get to choose from the options we offer */
302   gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(combo_cb)->entry), FALSE);
303   gtk_container_add(GTK_CONTAINER(string_opt_vb), combo_cb);
304   gtk_widget_show(combo_cb);
305
306
307   /* direction frame */
308   direction_frame = gtk_frame_new("Direction");
309   gtk_box_pack_start(GTK_BOX(main_options_hb), direction_frame, FALSE, FALSE, 0);
310   gtk_widget_show(direction_frame);
311
312   /* Direction row: Forward and reverse radio buttons */
313   direction_vb = gtk_vbox_new(FALSE, 0);
314   gtk_container_border_width(GTK_CONTAINER(direction_vb), 3);
315   gtk_container_add(GTK_CONTAINER(direction_frame), direction_vb);
316   gtk_widget_show(direction_vb);
317
318   up_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "_Up", accel_group);
319   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(up_rb), cfile.sbackward);
320   gtk_box_pack_start(GTK_BOX(direction_vb), up_rb, FALSE, FALSE, 0);
321   gtk_widget_show(up_rb);
322
323   down_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(up_rb, "_Down", accel_group);
324   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(down_rb), !cfile.sbackward);
325   gtk_box_pack_start(GTK_BOX(direction_vb), down_rb, FALSE, FALSE, 0);
326   gtk_widget_show(down_rb);
327
328
329   /* Button row */
330   bbox = dlg_button_row_new(GTK_STOCK_FIND, GTK_STOCK_CANCEL, NULL);
331   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
332   gtk_widget_show(bbox);
333
334   ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_FIND);
335   SIGNAL_CONNECT(ok_bt, "clicked", find_frame_ok_cb, find_frame_w);
336
337   cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
338   SIGNAL_CONNECT(cancel_bt, "clicked", find_frame_close_cb, find_frame_w);
339
340   /* Attach pointers to needed widgets to the capture prefs window/object */
341   OBJECT_SET_DATA(find_frame_w, E_FIND_FILT_KEY, filter_text_box);
342   OBJECT_SET_DATA(find_frame_w, E_FIND_BACKWARD_KEY, up_rb);
343   OBJECT_SET_DATA(find_frame_w, E_FIND_FILTERDATA_KEY, filter_rb);
344   OBJECT_SET_DATA(find_frame_w, E_FIND_HEXDATA_KEY, hex_rb);
345   OBJECT_SET_DATA(find_frame_w, E_FIND_STRINGDATA_KEY, string_rb);
346   OBJECT_SET_DATA(find_frame_w, E_FIND_STRINGTYPE_LABEL_KEY, combo_lb);
347   OBJECT_SET_DATA(find_frame_w, E_FIND_STRINGTYPE_KEY, combo_cb);
348   OBJECT_SET_DATA(find_frame_w, E_CASE_SEARCH_KEY, case_cb);
349   OBJECT_SET_DATA(find_frame_w, E_SOURCE_HEX_KEY, hex_data_rb);
350   OBJECT_SET_DATA(find_frame_w, E_SOURCE_DECODE_KEY, decode_data_rb);
351   OBJECT_SET_DATA(find_frame_w, E_SOURCE_SUMMARY_KEY, summary_data_rb);
352   OBJECT_SET_DATA(find_frame_w, E_FILT_TE_BUTTON_KEY, filter_bt);
353   
354   /*
355    * Now that we've attached the pointers, connect the signals - if
356    * we do so before we've attached the pointers, the signals may
357    * be delivered before the pointers are attached; the signal
358    * handlers expect the pointers to be attached, and won't be happy.
359    */
360   SIGNAL_CONNECT(hex_rb, "clicked", hex_selected_cb, find_frame_w);
361   SIGNAL_CONNECT(string_rb, "clicked", string_selected_cb, find_frame_w);
362   SIGNAL_CONNECT(filter_rb, "clicked", filter_selected_cb, find_frame_w);
363
364   string_selected_cb(NULL, find_frame_w);
365   filter_selected_cb(NULL, find_frame_w);
366
367   window_set_cancel_button(find_frame_w, cancel_bt, window_cancel_button_cb);
368
369   gtk_widget_grab_default(ok_bt);
370
371   /* Catch the "activate" signal on the filter text entry, so that
372      if the user types Return there, we act as if the "OK" button
373      had been selected, as happens if Return is typed if some widget
374      that *doesn't* handle the Return key has the input focus. */
375   dlg_set_activate(filter_text_box, ok_bt);
376
377   /* Give the initial focus to the "Filter" entry box. */
378   gtk_widget_grab_focus(filter_text_box);
379
380   SIGNAL_CONNECT(find_frame_w, "delete_event", window_delete_event_cb, NULL);
381   SIGNAL_CONNECT(find_frame_w, "destroy", find_frame_destroy_cb, NULL);
382
383   gtk_widget_show(find_frame_w);
384   window_present(find_frame_w);
385 }
386
387 /* this function opens the find frame dialogue and sets the filter string */
388 void   
389 find_frame_with_filter(char *filter)
390 {
391         find_frame_cb(NULL, NULL);
392         gtk_entry_set_text(GTK_ENTRY(filter_text_box), filter);
393 }
394
395 /*
396  * Check the filter syntax based on the type of search we're doing.
397  */
398 static void
399 find_filter_te_syntax_check_cb(GtkWidget *w, gpointer parent_w)
400 {
401   const gchar     *strval;
402   GtkWidget       *hex_rb, *string_rb;
403   guint8          *bytes = NULL;
404   size_t           nbytes;
405
406   hex_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_HEXDATA_KEY);
407   string_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGDATA_KEY);
408
409   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb))) {
410     /*
411      * Hex search - scan the search string to make sure it's valid hex.
412      */
413     strval = gtk_entry_get_text(GTK_ENTRY(w));
414     if (strval == NULL) {
415       /* XXX - can this happen? */      
416       colorize_filter_te_as_invalid(w);
417     } else {
418       bytes = convert_string_to_hex(strval, &nbytes);
419       if (bytes == NULL)
420         colorize_filter_te_as_invalid(w);
421       else {
422         g_free(bytes);
423         colorize_filter_te_as_valid(w);
424       }
425     }
426   } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (string_rb))) {
427     /*
428      * String search.  Make sure the string isn't empty.
429      */
430     strval = gtk_entry_get_text(GTK_ENTRY(w));
431     if (strval == NULL) {
432       /* XXX - can this happen? */      
433       colorize_filter_te_as_invalid(w);
434     } else {
435       if (strcmp(strval, "") == 0)
436         colorize_filter_te_as_invalid(w);
437       else
438         colorize_filter_te_as_valid(w);
439     }
440   } else {
441     /*
442      * Display filter search; check it with "filter_te_syntax_check_cb()".
443      */
444     filter_te_syntax_check_cb(w);
445   }
446 }
447
448 /* 
449  *  This function will re-check the search text syntax.
450  */  
451 static void
452 hex_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w)
453 {
454     GtkWidget   *filter_text_box;
455
456     filter_text_box = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_FILT_TE_PTR_KEY);
457
458     /* Re-check the display filter. */
459     find_filter_te_syntax_check_cb(filter_text_box, parent_w);
460     return;
461 }
462
463 /* 
464  *  This function will disable the string options until
465  *  the string search is selected.
466  */  
467 static void
468 string_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w)
469 {
470     GtkWidget   *string_rb, *hex_data_rb, *decode_data_rb, *summary_data_rb,
471                 *data_combo_lb, *data_combo_cb, *data_case_cb, *filter_text_box;
472
473     string_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGDATA_KEY);
474     hex_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_HEX_KEY);
475     decode_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_DECODE_KEY);
476     summary_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_SUMMARY_KEY);
477     
478     data_combo_lb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_LABEL_KEY);
479     data_combo_cb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_KEY);
480     data_case_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CASE_SEARCH_KEY);
481     filter_text_box = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_FILT_TE_PTR_KEY);
482
483     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(string_rb))) {
484         gtk_widget_set_sensitive(GTK_WIDGET(hex_data_rb), TRUE);
485         gtk_widget_set_sensitive(GTK_WIDGET(decode_data_rb), TRUE);
486         gtk_widget_set_sensitive(GTK_WIDGET(summary_data_rb), TRUE);
487         gtk_widget_set_sensitive(GTK_WIDGET(data_combo_lb), TRUE);
488         gtk_widget_set_sensitive(GTK_WIDGET(data_combo_cb), TRUE);
489         gtk_widget_set_sensitive(GTK_WIDGET(data_case_cb), TRUE);
490     } else {
491         gtk_widget_set_sensitive(GTK_WIDGET(hex_data_rb), FALSE);
492         gtk_widget_set_sensitive(GTK_WIDGET(decode_data_rb), FALSE);
493         gtk_widget_set_sensitive(GTK_WIDGET(summary_data_rb), FALSE);
494         gtk_widget_set_sensitive(GTK_WIDGET(data_combo_lb), FALSE);
495         gtk_widget_set_sensitive(GTK_WIDGET(data_combo_cb), FALSE);
496         gtk_widget_set_sensitive(GTK_WIDGET(data_case_cb), FALSE);
497     }
498     /* Re-check the display filter. */
499     find_filter_te_syntax_check_cb(filter_text_box, parent_w);
500     return;
501 }
502
503 /* 
504  *  This function will disable the filter button until
505  *  the filter search is selected.
506  */  
507 static void
508 filter_selected_cb(GtkWidget *button_rb _U_, gpointer parent_w)
509 {
510     GtkWidget   *filter_bt, *filter_rb;
511
512     filter_bt = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FILT_TE_BUTTON_KEY);
513     filter_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILTERDATA_KEY);
514     
515     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filter_rb)))
516     {
517         gtk_widget_set_sensitive(GTK_WIDGET(filter_bt), TRUE);
518     }
519     else
520     {
521         gtk_widget_set_sensitive(GTK_WIDGET(filter_bt), FALSE);
522     }
523     return;
524 }
525
526 static guint8 *
527 convert_string_to_hex(const char *string, size_t *nbytes)
528 {
529   size_t n_bytes;
530   const char *p;
531   guchar c;
532   guint8 *bytes, *q, byte_val;
533
534   n_bytes = 0;
535   p = &string[0];
536   for (;;) {
537     c = *p++;
538     if (c == '\0')
539       break;
540     if (isspace(c))
541       continue; /* allow white space */
542     if (c==':' || c=='.' || c=='-')
543       continue; /* skip any ':', '.', or '-' between bytes */
544     if (!isxdigit(c)) {
545       /* Not a valid hex digit - fail */
546       return NULL;
547     }
548
549     /*
550      * We can only match bytes, not nibbles; we must have a valid
551      * hex digit immediately after that hex digit.
552      */
553     c = *p++;
554     if (!isxdigit(c))
555       return NULL;
556
557     /* 2 hex digits = 1 byte */
558     n_bytes++;
559   }
560
561   /*
562    * Were we given any hex digits?
563    */
564   if (n_bytes == 0) {
565       /* No. */
566       return NULL;
567   }
568
569   /*
570    * OK, it's valid, and it generates "n_bytes" bytes; generate the
571    * raw byte array.
572    */
573   bytes = g_malloc(n_bytes);
574   p = &string[0];
575   q = &bytes[0];
576   for (;;) {
577     c = *p++;
578     if (c == '\0')
579       break;
580     if (isspace(c))
581       continue; /* allow white space */
582     if (c==':' || c=='.' || c=='-')
583       continue; /* skip any ':', '.', or '-' between bytes */
584     /* From the loop above, we know this is a hex digit */
585     if (isdigit(c))
586       byte_val = c - '0';
587     else if (c >= 'a')
588       byte_val = (c - 'a') + 10;
589     else
590       byte_val = (c - 'A') + 10;
591     byte_val <<= 4;
592
593     /* We also know this is a hex digit */
594     c = *p++;
595     if (isdigit(c))
596       byte_val |= c - '0';
597     else if (c >= 'a')
598       byte_val |= (c - 'a') + 10;
599     else if (c >= 'A')
600       byte_val |= (c - 'A') + 10;
601
602     *q++ = byte_val;
603   }
604   *nbytes = n_bytes;
605   return bytes;
606 }
607
608 static char *
609 convert_string_case(const char *string, gboolean case_insensitive)
610 {
611   char *out_string;
612   const char *p;
613   char c;
614   char *q;
615
616   /*
617    * Copy if if it's a case-sensitive search; uppercase it if it's
618    * a case-insensitive search.
619    */
620   if (case_insensitive) {
621     out_string = g_malloc(strlen(string) + 1);
622     for (p = &string[0], q = &out_string[0]; (c = *p) != '\0'; p++, q++)
623       *q = toupper((unsigned char)*p);
624     *q = '\0';
625   } else
626     out_string = g_strdup(string);
627   return out_string;
628 }
629
630 static void
631 find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
632 {
633   GtkWidget       *filter_te, *up_rb, *hex_rb, *string_rb, *combo_cb,
634                   *case_cb, *decode_data_rb, *summary_data_rb;
635   const gchar     *filter_text, *string_type;
636   search_charset_t scs_type = SCS_ASCII_AND_UNICODE;
637   guint8          *bytes = NULL;
638   size_t           nbytes;
639   char            *string = NULL;
640   dfilter_t       *sfcode;
641   gboolean        found_packet;
642
643   filter_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILT_KEY);
644   up_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_BACKWARD_KEY);
645   hex_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_HEXDATA_KEY);
646   string_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGDATA_KEY);
647   combo_cb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_KEY);
648   case_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CASE_SEARCH_KEY);
649   decode_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_DECODE_KEY);
650   summary_data_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_SOURCE_SUMMARY_KEY);
651
652   filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
653   string_type = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_cb)->entry));
654
655   case_type = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(case_cb));
656   decode_data = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(decode_data_rb));
657   summary_data = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(summary_data_rb));
658
659   /*
660    * Process the search criterion.
661    */
662   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb))) {
663     /*
664      * Hex search - scan the search string to make sure it's valid hex
665      * and to find out how many bytes there are.
666      */
667     bytes = convert_string_to_hex(filter_text, &nbytes);
668     if (bytes == NULL) {
669       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
670            "You didn't specify a valid hex string.");
671       return;
672     }
673   } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (string_rb))) {
674     /*
675      * String search.
676      * Make sure we're searching for something, first.
677      */
678     if (strcmp(filter_text, "") == 0) {
679       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
680            "You didn't specify any text for which to search.");
681       return;
682     }
683
684     /*
685      * We are - get the character set type.
686      */
687     if (strcmp(string_type, "ASCII Unicode & Non-Unicode") == 0)
688       scs_type = SCS_ASCII_AND_UNICODE;
689     else if (strcmp(string_type, "ASCII Non-Unicode") == 0)
690       scs_type = SCS_ASCII;
691     else if (strcmp(string_type, "ASCII Unicode") == 0)
692       scs_type = SCS_UNICODE;
693     else {
694       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "You didn't choose a valid character set.");
695       return;
696     }
697     string = convert_string_case(filter_text, case_type);
698   } else {
699     /*
700      * Display filter search - try to compile the filter.
701      */
702     if (!dfilter_compile(filter_text, &sfcode)) {
703       /* The attempt failed; report an error. */
704       bad_dfilter_alert_box(filter_text);
705       return;
706     }
707
708     /* Was it empty? */
709     if (sfcode == NULL) {
710       /* Yes - complain. */
711       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
712          "You specified a filter that doesn't test anything.");
713       return;
714     }
715   }
716
717   /*
718    * Remember the search parameters.
719    */
720   if (cfile.sfilter)
721     g_free(cfile.sfilter);
722   cfile.sfilter = g_strdup(filter_text);
723   cfile.sbackward = GTK_TOGGLE_BUTTON (up_rb)->active;
724   cfile.hex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (hex_rb));
725   cfile.string = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (string_rb));
726   cfile.scs_type = scs_type;
727   cfile.case_type = case_type;
728   cfile.decode_data = decode_data;
729   cfile.summary_data = summary_data;
730
731   if (cfile.hex) {
732     found_packet = find_packet_data(&cfile, bytes, nbytes);
733     g_free(bytes);
734     if (!found_packet) {
735       /* We didn't find a packet */
736       simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
737             "%sFound no match!%s\n\n"
738             "No packet contained those bytes.",
739             simple_dialog_primary_start(), simple_dialog_primary_end());
740       g_free(bytes);
741       return;
742     }
743   } else if (cfile.string) {
744     /* OK, what are we searching? */
745     if (cfile.decode_data) {
746       /* The text in the protocol tree */
747       found_packet = find_packet_protocol_tree(&cfile, string);
748       g_free(string);
749       if (!found_packet) {
750         /* We didn't find the packet. */
751         simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
752             "%sFound no match!%s\n\n"
753             "No packet contained that string in its dissected display.",
754             simple_dialog_primary_start(), simple_dialog_primary_end());
755         return;
756       }
757     } else if (cfile.summary_data) {
758       /* The text in the summary line */
759       found_packet = find_packet_summary_line(&cfile, string);
760       g_free(string);
761       if (!found_packet) {
762         /* We didn't find the packet. */
763         simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
764             "%sFound no match!%s\n\n"
765             "No packet contained that string in its Info column.",
766             simple_dialog_primary_start(), simple_dialog_primary_end());
767         return;
768       }
769     } else {
770       /* The raw packet data */
771       found_packet = find_packet_data(&cfile, string, strlen(string));
772       g_free(string);
773       if (!found_packet) {
774         /* We didn't find the packet. */
775         simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
776             "%sFound no match!%s\n\n"
777             "No packet contained that string in its data.",
778             simple_dialog_primary_start(), simple_dialog_primary_end());
779         return;
780       }
781     }
782   } else {
783     found_packet = find_packet_dfilter(&cfile, sfcode);
784     dfilter_free(sfcode);
785     if (!found_packet) {
786       /* We didn't find a packet */
787       simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, 
788           "%sFound no match!%s\n\n"
789           "No packet matched that filter.",
790           simple_dialog_primary_start(), simple_dialog_primary_end());
791       g_free(bytes);
792       return;
793     }
794   }
795   window_destroy(GTK_WIDGET(parent_w));
796 }
797
798 static void
799 find_frame_close_cb(GtkWidget *close_bt _U_, gpointer parent_w)
800 {
801   gtk_grab_remove(GTK_WIDGET(parent_w));
802   window_destroy(GTK_WIDGET(parent_w));
803 }
804
805 static void
806 find_frame_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
807 {
808   /* Note that we no longer have a "Find Packet" dialog box. */
809   find_frame_w = NULL;
810 }
811
812 static void
813 find_previous_next(GtkWidget *w, gpointer d, gboolean sens)
814 {
815   guint8    *bytes;
816   size_t     nbytes;
817   char      *string;
818   dfilter_t *sfcode;
819
820   if (cfile.sfilter) {
821     cfile.sbackward = sens;
822     if (cfile.hex) {
823       bytes = convert_string_to_hex(cfile.sfilter, &nbytes);
824       if (bytes == NULL) {
825         /*
826          * XXX - this shouldn't happen, as we've already successfully
827          * translated the string once.
828          */
829         return;
830       }
831       find_packet_data(&cfile, bytes, nbytes);
832       g_free(bytes);
833     } else if (cfile.string) {
834       string = convert_string_case(cfile.sfilter, cfile.case_type);
835       /* OK, what are we searching? */
836       if (cfile.decode_data) {
837         /* The text in the protocol tree */
838         find_packet_protocol_tree(&cfile, string);
839       } else if (cfile.summary_data) {
840         /* The text in the summary line */
841         find_packet_summary_line(&cfile, string);
842       } else {
843         /* The raw packet data */
844         find_packet_data(&cfile, string, strlen(string));
845       }
846       g_free(string);
847     } else {
848       if (!dfilter_compile(cfile.sfilter, &sfcode)) {
849         /*
850          * XXX - this shouldn't happen, as we've already successfully
851          * translated the string once.
852          */
853         return;
854       }
855       if (sfcode == NULL) {
856         /*
857          * XXX - this shouldn't happen, as we've already found that the
858          * string wasn't null.
859          */
860         return;
861       }
862       find_packet_dfilter(&cfile, sfcode);
863       dfilter_free(sfcode);
864     }
865   } else
866      find_frame_cb(w, d);
867 }
868
869 void
870 find_next_cb(GtkWidget *w , gpointer d)
871 {
872   find_previous_next(w, d, FALSE);
873 }
874
875 void
876 find_previous_cb(GtkWidget *w , gpointer d)
877 {
878   find_previous_next(w, d, TRUE);
879 }
880
881 /* this function jumps to the next packet matching the filter */
882 void   
883 find_previous_next_frame_with_filter(char *filter, gboolean backwards)
884 {
885   dfilter_t *sfcode;
886   gboolean sbackwards_saved;
887
888   /* temporarily set the direction we want to search */
889   sbackwards_saved=cfile.sbackward;
890   cfile.sbackward = backwards;
891
892   if (!dfilter_compile(filter, &sfcode)) {
893      /*
894       * XXX - this shouldn't happen, as the filter string is machine
895       * generated
896       */
897     return;
898   }
899   if (sfcode == NULL) {
900     /*
901      * XXX - this shouldn't happen, as the filter string is machine
902      * generated.
903      */
904     return;
905   }
906   find_packet_dfilter(&cfile, sfcode);
907   dfilter_free(sfcode);
908   cfile.sbackward=sbackwards_saved;
909 }