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