2 * Routines for "find frame" window
4 * $Id: find_dlg.c,v 1.30 2003/08/05 00:01:27 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
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.
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.
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.
32 #include <epan/proto.h>
33 #include <epan/dfilter/dfilter.h>
38 #include "filter_prefs.h"
39 #include "simple_dialog.h"
40 #include "dlg_utils.h"
41 #include "compat_macros.h"
43 #include "prefs_dlg.h"
45 /* Capture callback data keys */
46 #define E_FIND_FILT_KEY "find_filter_te"
47 #define E_FIND_BACKWARD_KEY "find_backward"
48 #define E_FIND_HEXDATA_KEY "find_hex"
49 #define E_FIND_ASCIIDATA_KEY "find_ascii"
50 #define E_FIND_FILTERDATA_KEY "find_filter"
51 #define E_FIND_STRINGTYPE_KEY "find_string_type"
52 #define E_CASE_SEARCH_KEY "case_insensitive_search"
54 static gboolean case_type = TRUE;
57 find_frame_ok_cb(GtkWidget *ok_bt, gpointer parent_w);
60 find_frame_close_cb(GtkWidget *close_bt, gpointer parent_w);
63 find_frame_destroy_cb(GtkWidget *win, gpointer user_data);
66 * Keep a static pointer to the current "Find Frame" window, if any, so
67 * that if somebody tries to do "Find Frame" while there's already a
68 * "Find Frame" window up, we just pop up the existing one, rather than
71 static GtkWidget *find_frame_w;
74 find_frame_cb(GtkWidget *w _U_, gpointer d _U_)
76 GtkWidget *main_vb, *filter_hb, *filter_bt, *filter_te,
77 *direction_hb, *forward_rb, *backward_rb,
78 *hex_hb, *hex_rb, *ascii_rb, *filter_rb,
79 *combo_hb, *combo_cb, *combo_lb,
80 *bbox, *ok_bt, *cancel_bt, *case_cb;
81 #if GTK_MAJOR_VERSION < 2
82 GtkAccelGroup *accel_group;
85 /* No Apply button, but "OK" not only sets our text widget, it
86 activates it (i.e., it causes us to do the search). */
87 static construct_args_t args = {
88 "Ethereal: Search Filter",
93 if (find_frame_w != NULL) {
94 /* There's already a "Find Frame" dialog box; reactivate it. */
95 reactivate_window(find_frame_w);
99 find_frame_w = dlg_window_new("Ethereal: Find Frame");
100 SIGNAL_CONNECT(find_frame_w, "destroy", find_frame_destroy_cb, NULL);
102 #if GTK_MAJOR_VERSION < 2
103 /* Accelerator group for the accelerators (or, as they're called in
104 Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
105 Ctrl+<key> is an accelerator). */
106 accel_group = gtk_accel_group_new();
107 gtk_window_add_accel_group(GTK_WINDOW(find_frame_w), accel_group);
110 /* Container for each row of widgets */
111 main_vb = gtk_vbox_new(FALSE, 3);
112 gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
113 gtk_container_add(GTK_CONTAINER(find_frame_w), main_vb);
114 gtk_widget_show(main_vb);
117 filter_hb = gtk_hbox_new(FALSE, 3);
118 gtk_container_add(GTK_CONTAINER(main_vb), filter_hb);
119 gtk_widget_show(filter_hb);
121 filter_bt = gtk_button_new_with_label("Filter:");
122 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
123 SIGNAL_CONNECT(filter_bt, "destroy", filter_button_destroy_cb, NULL);
124 gtk_box_pack_start(GTK_BOX(filter_hb), filter_bt, FALSE, TRUE, 0);
125 gtk_widget_show(filter_bt);
127 filter_te = gtk_entry_new();
128 if (cfile.sfilter) gtk_entry_set_text(GTK_ENTRY(filter_te), cfile.sfilter);
129 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te);
130 gtk_box_pack_start(GTK_BOX(filter_hb), filter_te, TRUE, TRUE, 0);
131 gtk_widget_show(filter_te);
133 /* Misc row: Forward and reverse radio buttons */
134 direction_hb = gtk_hbox_new(FALSE, 3);
135 gtk_container_add(GTK_CONTAINER(main_vb), direction_hb);
136 gtk_widget_show(direction_hb);
138 #if GTK_MAJOR_VERSION < 2
139 forward_rb = dlg_radio_button_new_with_label_with_mnemonic(NULL, "_Forward",
142 forward_rb = gtk_radio_button_new_with_mnemonic(NULL, "_Forward");
144 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(forward_rb), !cfile.sbackward);
145 gtk_box_pack_start(GTK_BOX(direction_hb), forward_rb, TRUE, TRUE, 0);
146 gtk_widget_show(forward_rb);
148 #if GTK_MAJOR_VERSION < 2
149 backward_rb = dlg_radio_button_new_with_label_with_mnemonic(
150 gtk_radio_button_group(GTK_RADIO_BUTTON(forward_rb)),
151 "_Backward", accel_group);
153 backward_rb = gtk_radio_button_new_with_mnemonic_from_widget(
154 GTK_RADIO_BUTTON(forward_rb), "_Backward");
156 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(backward_rb), cfile.sbackward);
157 gtk_box_pack_start(GTK_BOX(direction_hb), backward_rb, TRUE, TRUE, 0);
158 gtk_widget_show(backward_rb);
161 /* Filter/Hex/Ascii Search */
163 hex_hb = gtk_hbox_new(FALSE, 3);
164 gtk_container_add(GTK_CONTAINER(main_vb), hex_hb);
165 gtk_widget_show(hex_hb);
167 #if GTK_MAJOR_VERSION < 2
168 filter_rb = dlg_radio_button_new_with_label_with_mnemonic(NULL, "_Display Filter",
171 filter_rb = gtk_radio_button_new_with_mnemonic(NULL, "_Display Filter");
173 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(filter_rb), !cfile.hex && !cfile.ascii);
174 gtk_box_pack_start(GTK_BOX(hex_hb), filter_rb, TRUE, TRUE, 0);
175 gtk_widget_show(filter_rb);
178 #if GTK_MAJOR_VERSION < 2
179 hex_rb = dlg_radio_button_new_with_label_with_mnemonic(
180 gtk_radio_button_group(GTK_RADIO_BUTTON(filter_rb)),
181 "_Hex", accel_group);
183 hex_rb = gtk_radio_button_new_with_mnemonic_from_widget(
184 GTK_RADIO_BUTTON(filter_rb), "_Hex");
186 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(hex_rb), cfile.hex);
187 gtk_box_pack_start(GTK_BOX(hex_hb), hex_rb, TRUE, TRUE, 0);
188 gtk_widget_show(hex_rb);
192 #if GTK_MAJOR_VERSION < 2
193 ascii_rb = dlg_radio_button_new_with_label_with_mnemonic(
194 gtk_radio_button_group(GTK_RADIO_BUTTON(filter_rb)),
195 "_String", accel_group);
197 ascii_rb = gtk_radio_button_new_with_mnemonic_from_widget(
198 GTK_RADIO_BUTTON(filter_rb), "_String");
200 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(ascii_rb), cfile.ascii);
201 gtk_box_pack_start(GTK_BOX(hex_hb), ascii_rb, TRUE, TRUE, 0);
202 gtk_widget_show(ascii_rb);
204 /* String Type Selection Dropdown Box */
205 combo_hb = gtk_hbox_new(FALSE, 3);
206 gtk_container_add(GTK_CONTAINER(main_vb), combo_hb);
207 gtk_widget_show(combo_hb);
209 combo_lb = gtk_label_new("Find String Type:");
210 gtk_box_pack_start(GTK_BOX(combo_hb), combo_lb, FALSE, FALSE, 6);
211 gtk_widget_show(combo_lb);
212 /* Create Combo Box */
213 combo_cb = gtk_combo_new();
215 glist = g_list_append(glist, "ASCII Unicode & Non-Unicode");
216 glist = g_list_append(glist, "ASCII Non-Unicode");
217 glist = g_list_append(glist, "ASCII Unicode");
218 glist = g_list_append(glist, "EBCDIC");
220 gtk_combo_set_popdown_strings(GTK_COMBO(combo_cb), glist);
221 gtk_container_add(GTK_CONTAINER(main_vb), combo_cb);
222 gtk_widget_show(combo_cb);
224 #if GTK_MAJOR_VERSION < 2
225 case_cb = dlg_check_button_new_with_label_with_mnemonic(
226 "Case Insensitive Search", accel_group);
228 case_cb = gtk_check_button_new_with_mnemonic(
229 "Case Insensitive Search");
231 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(case_cb),
233 gtk_container_add(GTK_CONTAINER(main_vb), case_cb);
234 gtk_widget_show(case_cb);
236 /* Button row: OK and cancel buttons */
237 bbox = gtk_hbutton_box_new();
238 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
239 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
240 gtk_container_add(GTK_CONTAINER(main_vb), bbox);
241 gtk_widget_show(bbox);
243 #if GTK_MAJOR_VERSION < 2
244 ok_bt = gtk_button_new_with_label ("OK");
246 ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
248 SIGNAL_CONNECT(ok_bt, "clicked", find_frame_ok_cb, find_frame_w);
249 GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
250 gtk_box_pack_start (GTK_BOX (bbox), ok_bt, TRUE, TRUE, 0);
251 gtk_widget_grab_default(ok_bt);
252 gtk_widget_show(ok_bt);
254 #if GTK_MAJOR_VERSION < 2
255 cancel_bt = gtk_button_new_with_label ("Cancel");
257 cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
259 SIGNAL_CONNECT(cancel_bt, "clicked", find_frame_close_cb, find_frame_w);
260 GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
261 gtk_box_pack_start (GTK_BOX (bbox), cancel_bt, TRUE, TRUE, 0);
262 gtk_widget_show(cancel_bt);
264 /* Attach pointers to needed widgets to the capture prefs window/object */
265 OBJECT_SET_DATA(find_frame_w, E_FIND_FILT_KEY, filter_te);
266 OBJECT_SET_DATA(find_frame_w, E_FIND_BACKWARD_KEY, backward_rb);
267 OBJECT_SET_DATA(find_frame_w, E_FIND_FILTERDATA_KEY, filter_rb);
268 OBJECT_SET_DATA(find_frame_w, E_FIND_HEXDATA_KEY, hex_rb);
269 OBJECT_SET_DATA(find_frame_w, E_FIND_ASCIIDATA_KEY, ascii_rb);
270 OBJECT_SET_DATA(find_frame_w, E_FIND_STRINGTYPE_KEY, combo_cb);
271 OBJECT_SET_DATA(find_frame_w, E_CASE_SEARCH_KEY, case_cb);
274 /* Catch the "activate" signal on the filter text entry, so that
275 if the user types Return there, we act as if the "OK" button
276 had been selected, as happens if Return is typed if some widget
277 that *doesn't* handle the Return key has the input focus. */
278 dlg_set_activate(filter_te, ok_bt);
280 /* Catch the "key_press_event" signal in the window, so that we can catch
281 the ESC key being pressed and act as if the "Cancel" button had
283 dlg_set_cancel(find_frame_w, cancel_bt);
285 /* Give the initial focus to the "Filter" entry box. */
286 gtk_widget_grab_focus(filter_te);
288 gtk_widget_show(find_frame_w);
292 find_frame_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
294 GtkWidget *filter_te, *backward_rb, *hex_rb, *ascii_rb, *combo_cb, *case_cb;
295 gchar *filter_text, *string_type;
298 filter_te = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_FILT_KEY);
299 backward_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_BACKWARD_KEY);
300 hex_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_HEXDATA_KEY);
301 ascii_rb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_ASCIIDATA_KEY);
302 combo_cb = (GtkWidget *)OBJECT_GET_DATA(parent_w, E_FIND_STRINGTYPE_KEY);
303 case_cb = (GtkWidget *) OBJECT_GET_DATA(parent_w, E_CASE_SEARCH_KEY);
305 filter_text = gtk_entry_get_text(GTK_ENTRY(filter_te));
306 string_type = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_cb)->entry));
308 case_type = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(case_cb));
311 * Try to compile the filter.
313 if (!dfilter_compile(filter_text, &sfcode) && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) {
314 /* The attempt failed; report an error. */
315 simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
320 if (sfcode == NULL && !GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active) {
321 /* Yes - complain. */
322 simple_dialog(ESD_TYPE_CRIT, NULL,
323 "You didn't specify valid search criteria.");
328 * Remember the filter.
331 g_free(cfile.sfilter);
332 cfile.sfilter = g_strdup(filter_text);
334 cfile.sbackward = GTK_TOGGLE_BUTTON (backward_rb)->active;
335 cfile.hex = GTK_TOGGLE_BUTTON (hex_rb)->active;
336 cfile.ascii = GTK_TOGGLE_BUTTON (ascii_rb)->active;
337 cfile.ftype = g_strdup(string_type);
339 if (!GTK_TOGGLE_BUTTON (hex_rb)->active && !GTK_TOGGLE_BUTTON (ascii_rb)->active ) {
340 if (!find_packet(&cfile, sfcode)) {
341 /* We didn't find the packet. */
342 simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched that filter.");
348 if (!find_ascii(&cfile, filter_text, cfile.ascii, string_type, case_type)) {
349 /* We didn't find the packet. */
350 simple_dialog(ESD_TYPE_CRIT, NULL, "No packet matched search criteria.");
354 gtk_widget_destroy(GTK_WIDGET(parent_w));
358 find_frame_close_cb(GtkWidget *close_bt _U_, gpointer parent_w)
360 gtk_grab_remove(GTK_WIDGET(parent_w));
361 gtk_widget_destroy(GTK_WIDGET(parent_w));
365 find_frame_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
367 /* Note that we no longer have a "Find Frame" dialog box. */
372 find_previous_next(GtkWidget *w, gpointer d, gboolean sens)
378 if (!dfilter_compile(cfile.sfilter, &sfcode) && !cfile.hex && !cfile.ascii)
380 if (sfcode == NULL && !cfile.hex && !cfile.ascii)
382 cfile.sbackward = sens;
383 if (cfile.hex || cfile.ascii)
385 find_ascii(&cfile, cfile.sfilter, cfile.ascii, cfile.ftype, case_type);
389 find_packet(&cfile, sfcode);
396 find_next_cb(GtkWidget *w , gpointer d)
398 find_previous_next(w, d, FALSE);
402 find_previous_cb(GtkWidget *w , gpointer d)
404 find_previous_next(w, d, TRUE);