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