3 * Allow the user to construct a subexpression of a display filter
4 * expression, testing a particular field; display the tree of fields
5 * and the relations and values with which it can be compared.
7 * Copyright 2000, Jeffrey C. Foster <jfoste@woodward.com> and
8 * Guy Harris <guy@alum.mit.edu>
12 * Wireshark - Network traffic analyzer
13 * By Gerald Combs <gerald@wireshark.org>
14 * Copyright 2000 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32 * may want to check the enable field to decide if protocol should be in tree
33 * improve speed of dialog box creation
34 * - I believe this is slow because of tree widget creation.
35 * 1) could improve the widget
36 * 2) keep a copy in memory after the first time.
37 * user can pop multiple tree dialogs by pressing the "Tree" button multiple
38 * times. not a good thing.
39 * Sort the protocols and children
50 #include "../simple_dialog.h"
53 #include "gtk/gui_utils.h"
54 #include "gtk/dlg_utils.h"
55 #include "gtk/proto_dlg.h"
56 #include "gtk/filter_dlg.h"
57 #include "gtk/dfilter_expr_dlg.h"
60 #define E_DFILTER_EXPR_TREE_KEY "dfilter_expr_tree"
61 #define E_DFILTER_EXPR_CURRENT_VAR_KEY "dfilter_expr_current_var"
62 #define E_DFILTER_EXPR_RELATION_LIST_KEY "dfilter_expr_relation_list"
63 #define E_DFILTER_EXPR_RANGE_LABEL_KEY "dfilter_expr_range_label"
64 #define E_DFILTER_EXPR_RANGE_ENTRY_KEY "dfilter_expr_range_entry"
65 #define E_DFILTER_EXPR_VALUE_LABEL_KEY "dfilter_expr_value_label"
66 #define E_DFILTER_EXPR_VALUE_ENTRY_KEY "dfilter_expr_value_entry"
67 #define E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY "dfilter_expr_value_list_label"
68 #define E_DFILTER_EXPR_VALUE_LIST_KEY "dfilter_expr_value_list"
69 #define E_DFILTER_EXPR_VALUE_LIST_SW_KEY "dfilter_expr_value_list_sw"
70 #define E_DFILTER_EXPR_OK_BT_KEY "dfilter_expr_accept_bt"
71 #define E_DFILTER_EXPR_VALUE_KEY "dfilter_expr_value"
73 typedef struct protocol_data {
78 static void show_relations(GtkWidget *relation_list, ftenum_t ftype);
79 static gboolean relation_is_presence_test(const char *string);
80 static void add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive);
81 static void build_boolean_values(GtkWidget *value_list_scrolled_win,
82 GtkWidget *value_list,
83 const true_false_string *values);
84 static void build_enum_values(GtkWidget *value_list_scrolled_win,
85 GtkWidget *value_list,
86 const value_string *values);
87 static void add_value_list_item(GtkWidget *value_list, const gchar *string,
89 static void display_value_fields(header_field_info *hfinfo,
90 gboolean is_comparison, GtkWidget *value_label,
91 GtkWidget *value_entry,
92 GtkWidget *value_list_label, GtkWidget *value_list,
93 GtkWidget *value_list_scrolled_win,
94 GtkWidget *range_label,
95 GtkWidget *range_entry);
98 * Note that this is called every time the user clicks on an item,
99 * whether it is already selected or not.
102 field_select_row_cb(GtkTreeSelection *sel, gpointer tree)
104 GtkWidget *window = gtk_widget_get_toplevel(tree);
105 GtkWidget *relation_list = g_object_get_data(G_OBJECT(window),
106 E_DFILTER_EXPR_RELATION_LIST_KEY);
107 GtkWidget *range_label = g_object_get_data(G_OBJECT(window),
108 E_DFILTER_EXPR_RANGE_LABEL_KEY);
109 GtkWidget *range_entry = g_object_get_data(G_OBJECT(window),
110 E_DFILTER_EXPR_RANGE_ENTRY_KEY);
111 GtkWidget *value_label = g_object_get_data(G_OBJECT(window),
112 E_DFILTER_EXPR_VALUE_LABEL_KEY);
113 GtkWidget *value_entry = g_object_get_data(G_OBJECT(window),
114 E_DFILTER_EXPR_VALUE_ENTRY_KEY);
115 GtkWidget *value_list_label = g_object_get_data(G_OBJECT(window),
116 E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
117 GtkWidget *value_list = g_object_get_data(G_OBJECT(window),
118 E_DFILTER_EXPR_VALUE_LIST_KEY);
119 GtkWidget *value_list_scrolled_win = g_object_get_data(G_OBJECT(window),
120 E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
121 GtkWidget *ok_bt = g_object_get_data(G_OBJECT(window),
122 E_DFILTER_EXPR_OK_BT_KEY);
123 header_field_info *hfinfo, *cur_hfinfo;
124 const char *value_type;
125 char value_label_string[1024+1]; /* XXX - should be large enough */
129 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
131 gtk_tree_model_get(model, &iter, 1, &hfinfo, -1);
134 * What was the item that was last selected?
136 cur_hfinfo = g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
137 if (cur_hfinfo == hfinfo) {
139 * It's still selected; no need to change anything.
145 * Mark it as currently selected.
147 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY, hfinfo);
149 show_relations(relation_list, hfinfo->type);
152 * Set the label for the value to indicate what type of value
155 value_type = ftype_pretty_name(hfinfo->type);
156 if (value_type != NULL) {
158 * Indicate what type of value it is.
160 g_snprintf(value_label_string, sizeof value_label_string,
161 "Value (%s)", value_type);
162 gtk_label_set_text(GTK_LABEL(value_label), value_label_string);
166 * Clear the entry widget for the value, as whatever
167 * was there before doesn't apply.
169 gtk_entry_set_text(GTK_ENTRY(value_entry), "");
171 switch (hfinfo->type) {
175 * The list of values should be the strings for "true"
176 * and "false"; show them in the value list.
178 build_boolean_values(value_list_scrolled_win, value_list,
191 * If this has a value_string table (not a range_string table) associated with it,
192 * fill up the list of values, otherwise clear the list of values.
194 /* XXX: ToDo: Implement "range-string" filter ? */
195 if ((hfinfo->strings != NULL) && !(hfinfo->display & BASE_RANGE_STRING)) {
196 const value_string *vals = hfinfo->strings;
197 if (hfinfo->display & BASE_EXT_STRING)
198 vals = VALUE_STRING_EXT_VS_P((value_string_ext *) vals);
199 build_enum_values(value_list_scrolled_win, value_list, vals);
201 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
206 * Clear the list of values.
208 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
213 * Display various items for the value, as appropriate.
214 * The relation we start out with is never a comparison.
216 display_value_fields(hfinfo, FALSE, value_label, value_entry,
217 value_list_label, value_list, value_list_scrolled_win, range_label, range_entry);
220 * XXX - in browse mode, there always has to be something
221 * selected, so this should always be sensitive.
223 gtk_widget_set_sensitive(ok_bt, TRUE);
227 show_relations(GtkWidget *relation_list, ftenum_t ftype)
231 * Clear out the currently displayed list of relations.
233 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list))));
236 * Add the supported relations.
238 add_relation_list(relation_list, "is present", TRUE);
239 add_relation_list(relation_list, "==",
240 ftype_can_eq(ftype) || (ftype_can_slice(ftype) && ftype_can_eq(FT_BYTES)));
241 add_relation_list(relation_list, "!=",
242 ftype_can_ne(ftype) || (ftype_can_slice(ftype) && ftype_can_ne(FT_BYTES)));
243 add_relation_list(relation_list, ">",
244 ftype_can_gt(ftype) || (ftype_can_slice(ftype) && ftype_can_gt(FT_BYTES)));
246 add_relation_list(relation_list, "<",
247 ftype_can_lt(ftype) || (ftype_can_slice(ftype) && ftype_can_lt(FT_BYTES)));
248 add_relation_list(relation_list, ">=",
249 ftype_can_ge(ftype) || (ftype_can_slice(ftype) && ftype_can_ge(FT_BYTES)));
250 add_relation_list(relation_list, "<=",
251 ftype_can_le(ftype) || (ftype_can_slice(ftype) && ftype_can_le(FT_BYTES)));
252 add_relation_list(relation_list, "contains",
253 ftype_can_contains(ftype) || (ftype_can_slice(ftype) && ftype_can_contains(FT_BYTES)));
254 #if defined(HAVE_LIBPCRE) || GLIB_CHECK_VERSION(2,14,0)
255 add_relation_list(relation_list, "matches",
256 ftype_can_matches(ftype) || (ftype_can_slice(ftype) && ftype_can_matches(FT_BYTES)));
259 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)), &iter);
260 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)), &iter);
264 * Given a string that represents a test to be made on a field, returns
265 * TRUE if it tests for the field's presence, FALSE otherwise.
268 relation_is_presence_test(const char *string)
270 return (strcmp(string, "is present") == 0);
274 add_relation_list(GtkWidget *relation_list, const char *relation, gboolean sensitive)
276 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(relation_list)));
279 /* XXX: I currently see no way to insensitive the item,
280 * so for a first step, just don't show it (as before these changes :-) */
285 gtk_list_store_append(store, &iter);
286 gtk_list_store_set(store, &iter, 0, relation, -1);
290 relation_list_sel_cb(GtkTreeSelection *sel, gpointer user_data _U_)
292 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
293 GtkWidget *range_label =
294 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_LABEL_KEY);
295 GtkWidget *range_entry =
296 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY);
297 GtkWidget *value_label =
298 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LABEL_KEY);
299 GtkWidget *value_entry =
300 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY);
301 GtkWidget *value_list_label =
302 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY);
303 GtkWidget *value_list =
304 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_KEY);
305 GtkWidget *value_list_scrolled_win =
306 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_SW_KEY);
307 header_field_info *hfinfo =
308 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
314 * What's the relation?
316 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
318 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
321 * Update the display of various items for the value, as appropriate.
323 display_value_fields(hfinfo,
324 !relation_is_presence_test(item_str),
325 value_label, value_entry, value_list_label, value_list,
326 value_list_scrolled_win, range_label, range_entry);
331 build_boolean_values(GtkWidget *value_list_scrolled_win, GtkWidget *value_list,
332 const true_false_string *values)
334 static const true_false_string true_false = { "True", "False" };
335 GtkTreeSelection *sel;
338 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
341 * Clear out the items for the list, and put in the names
342 * from the value_string list.
344 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
347 * Put the list in single mode, so we don't get any selection
348 * events while we're building it (i.e., so we don't get any
349 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
350 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
352 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
358 values = &true_false;
359 add_value_list_item(value_list, values->true_string, (gpointer) values);
360 add_value_list_item(value_list, values->false_string, NULL);
363 * OK, we're done, so we can finally put it in browse mode.
364 * Select the first item, so that the user doesn't have to, under
365 * the assumption that they're most likely to test if something
366 * is true, not false.
368 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
369 gtk_tree_model_get_iter_first(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)), &iter);
370 gtk_tree_selection_select_iter(sel, &iter);
372 gtk_widget_show_all(value_list_scrolled_win);
376 build_enum_values(GtkWidget *value_list_scrolled_win _U_, GtkWidget *value_list,
377 const value_string *values)
379 GtkTreeSelection *sel;
381 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
383 * Clear out the items for the list, and put in the names
384 * from the value_string list.
386 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list))));
389 * Put the list in single mode, so we don't get any selection
390 * events while we're building it (i.e., so we don't get any
391 * on a list item BEFORE WE GET TO SET THE DATA FOR THE LIST
392 * ITEM SO THAT THE HANDLER CAN HANDLE IT).
394 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
399 while (values->strptr != NULL) {
400 add_value_list_item(value_list, values->strptr, (gpointer) values);
405 * OK, we're done, so we can finally put it in browse mode.
407 gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
411 add_value_list_item(GtkWidget *value_list, const gchar *string, const gpointer data)
413 GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(value_list)));
416 gtk_list_store_append(store, &iter);
417 gtk_list_store_set(store, &iter, 0, string, 1, data, -1);
421 * Show or hide the various values fields as appropriate for the field
422 * and currently-selected relation.
425 display_value_fields(header_field_info *hfinfo, gboolean is_comparison,
426 GtkWidget *value_label, GtkWidget *value_entry,
427 GtkWidget *value_list_label,
428 GtkWidget *value_list _U_,
429 GtkWidget *value_list_scrolled_win, GtkWidget *range_label,
430 GtkWidget *range_entry)
433 gboolean show_value_label = FALSE;
434 gboolean show_value_list = FALSE;
435 gboolean show_range = FALSE;
440 * this is an FT_NONE variable, in which case you can
441 * only check whether it's present or absent in the
446 * this is a Boolean variable, in which case you
447 * can't specify a value to compare with, you can
448 * only specify whether to test for the Boolean
449 * being true or to test for it being false
453 * this isn't a Boolean variable, in which case you
454 * can test for its presence in the protocol tree,
455 * and the relation is such a test, in
456 * which case you don't compare with a value
458 * so we hide the value entry.
461 switch (hfinfo->type) {
465 show_value_label = TRUE; /* XXX: Allow value entry (contrary to the comment above) ?? */
466 show_value_list = TRUE;
479 show_value_label = TRUE;
480 if ((hfinfo->strings != NULL) && !(hfinfo->display & BASE_RANGE_STRING)) {
482 * We have a list of values to show.
484 show_value_list = TRUE;
491 * There is no list of names for values; only show the value_label if needed.
494 show_value_label = TRUE;
498 gtk_widget_set_sensitive(value_label, show_value_label);
499 gtk_widget_set_sensitive(value_entry, show_value_label);
501 gtk_widget_set_sensitive(value_list_label, show_value_list);
502 gtk_widget_set_sensitive(value_list_scrolled_win, show_value_list);
505 * Is this a comparison, and are ranges supported by this type?
506 * If both are true, show the range stuff, otherwise hide it.
508 show_range = (is_comparison && ftype_can_slice(hfinfo->type));
509 gtk_widget_set_sensitive(range_label, show_range);
510 gtk_widget_set_sensitive(range_entry, show_range);
514 value_list_sel_cb(GtkTreeSelection *sel, gpointer value_entry_arg)
516 GtkWidget *value_entry = value_entry_arg;
517 GtkWidget *window = gtk_widget_get_toplevel(GTK_WIDGET(gtk_tree_selection_get_tree_view(sel)));
520 header_field_info *hfinfo = g_object_get_data(G_OBJECT(window),
521 E_DFILTER_EXPR_CURRENT_VAR_KEY);
522 const value_string *value = NULL;
523 gchar *value_display_string = NULL;
525 if (!gtk_tree_selection_get_selected(sel, &model, &iter))
527 gtk_tree_model_get(model, &iter, 1, &value, -1);
530 * This should either be a numeric type or a Boolean type.
532 if (hfinfo->type == FT_BOOLEAN) {
534 * Boolean type; if the value key for the selected item
535 * is non-null, it's the item for "true", otherwise it's
536 * the item for "false". Compare with 1 if we're
537 * testing for "true", and compare with 0 if we're
538 * testing for "false".
541 value_display_string = g_strdup("1");
543 value_display_string = g_strdup("0");
546 * Numeric type; get the value corresponding to the
547 * selected item, and display it in the base for this
550 switch ((hfinfo->display) & BASE_DISPLAY_E_MASK) {
554 switch (hfinfo->type) {
560 value_display_string = g_strdup_printf("%u", value->value);
567 value_display_string = g_strdup_printf("%d", value->value);
571 g_assert_not_reached();
576 value_display_string = g_strdup_printf("0x%x", value->value);
580 value_display_string = g_strdup_printf("%#o", value->value);
584 g_assert_not_reached();
588 gtk_entry_set_text(GTK_ENTRY(value_entry), value_display_string);
589 g_free (value_display_string);
593 dfilter_report_bad_value(const char *format, ...)
595 char error_msg_buf[1024];
598 va_start(args, format);
599 g_vsnprintf(error_msg_buf, sizeof error_msg_buf, format, args);
602 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_msg_buf);
606 dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg)
608 GtkWidget *filter_te = filter_te_arg;
609 GtkWidget *window = gtk_widget_get_toplevel(w);
610 GtkWidget *relation_list =
611 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RELATION_LIST_KEY);
612 GtkWidget *range_entry =
613 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY);
614 GtkWidget *value_entry =
615 g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY);
616 header_field_info *hfinfo;
618 gchar *range_str, *stripped_range_str;
619 gchar *value_str, *stripped_value_str;
623 gboolean can_compare;
630 * Get the variable to be tested.
632 hfinfo = g_object_get_data(G_OBJECT(window), E_DFILTER_EXPR_CURRENT_VAR_KEY);
635 * Get the relation operator to use.
637 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
639 gtk_tree_model_get(model, &iter, 0, &item_str, -1);
641 /* Nothing selected */
646 * Get the range to use, if any.
648 #if GTK_CHECK_VERSION(2,20,0)
649 if (gtk_widget_get_sensitive(range_entry)) {
651 if (GTK_WIDGET_SENSITIVE(range_entry)) {
653 range_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(range_entry)));
655 * XXX - strip this even for strings?
656 * Doing so for strings means you can't match a string that has
657 * leading or trailing whitespace, but you can't see trailing
658 * whitespace in a text field, so it's not clear that it's
659 * a good idea to allow that.
661 stripped_range_str = g_strstrip(range_str);
662 if (strcmp(stripped_range_str, "") == 0) {
664 * No range was specified.
668 stripped_range_str = NULL;
672 * XXX - check it for validity?
676 stripped_range_str = NULL;
680 * If a range was specified, the type of the LHS of the
681 * comparison is FT_BYTES; otherwise, it's the type of the field.
683 if (range_str == NULL)
684 ftype = hfinfo->type;
689 * Make sure the relation is valid for the type in question.
690 * We may be offering relations that the type of the field
691 * can't support, because the field's type supports slicing,
692 * and the relation *is* supported on byte strings.
694 if (strcmp(item_str, "==") == 0)
695 can_compare = ftype_can_eq(ftype);
696 else if (strcmp(item_str, "!=") == 0)
697 can_compare = ftype_can_ne(ftype);
698 else if (strcmp(item_str, ">") == 0)
699 can_compare = ftype_can_gt(ftype);
700 else if (strcmp(item_str, "<") == 0)
701 can_compare = ftype_can_lt(ftype);
702 else if (strcmp(item_str, ">=") == 0)
703 can_compare = ftype_can_ge(ftype);
704 else if (strcmp(item_str, "<=") == 0)
705 can_compare = ftype_can_le(ftype);
706 else if (strcmp(item_str, "contains") == 0)
707 can_compare = ftype_can_contains(ftype);
708 else if (strcmp(item_str, "matches") == 0)
709 can_compare = ftype_can_matches(ftype);
711 can_compare = TRUE; /* not a comparison */
713 if (range_str == NULL) {
714 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
715 "That field can't be tested with \"%s\".",
718 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
719 "Ranges of that field can't be tested with \"%s\".",
728 * Get the value to use, if any.
730 #if GTK_CHECK_VERSION(2,20,0)
731 if (gtk_widget_get_sensitive(value_entry)) {
733 if (GTK_WIDGET_SENSITIVE(value_entry)) {
735 value_str = g_strdup(gtk_entry_get_text(GTK_ENTRY(value_entry)));
736 stripped_value_str = g_strstrip(value_str);
737 if (strcmp(stripped_value_str, "") == 0) {
739 * This field takes a value, but they didn't supply
742 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
743 "That field must be compared with a value, "
744 "but you didn't specify a value with which to "
753 * Make sure the value is valid.
755 * If no range string was specified, it must be valid
756 * for the type of the field; if a range string was
757 * specified, must be valid for FT_BYTES.
759 if (strcmp(item_str, "contains") == 0) {
760 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE,
761 dfilter_report_bad_value);
764 fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE,
765 dfilter_report_bad_value);
767 if (fvalue == NULL) {
771 * The dialog box was already popped up by
772 * "dfilter_report_bad_value()".
782 stripped_value_str = NULL;
786 * Insert the expression at the current cursor position.
787 * If there's a non-whitespace character to the left of it,
788 * insert a blank first; if there's a non-whitespace character
789 * to the right of it, insert a blank after it.
791 pos = gtk_editable_get_position(GTK_EDITABLE(filter_te));
792 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos, pos + 1);
793 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
794 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
797 gtk_editable_insert_text(GTK_EDITABLE(filter_te), hfinfo->abbrev,
798 (gint) strlen(hfinfo->abbrev), &pos);
799 if (range_str != NULL) {
800 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "[", 1, &pos);
801 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
802 stripped_range_str, (gint) strlen(stripped_range_str), &pos);
803 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "]", 1, &pos);
806 if (item_str != NULL && !relation_is_presence_test(item_str)) {
807 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
808 gtk_editable_insert_text(GTK_EDITABLE(filter_te), item_str,
809 (gint) strlen(item_str), &pos);
811 if (value_str != NULL) {
812 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
814 * XXX - we should do this by generating an appropriate display
815 * filter value string for this field; that requires us to have
816 * a "generate display filter string" method for every FT_ type.
818 switch (hfinfo->type) {
823 case FT_ABSOLUTE_TIME:
825 * Always put quotes around the string.
832 * If the string contains white space, put quotes around it.
834 quote_it = (strpbrk(stripped_value_str, " \t") != NULL);
839 * Put quotes around the string.
841 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
844 gtk_editable_insert_text(GTK_EDITABLE(filter_te),
845 stripped_value_str, (gint) strlen(stripped_value_str), &pos);
848 * Put quotes around the string.
850 gtk_editable_insert_text(GTK_EDITABLE(filter_te), "\"",
855 chars = gtk_editable_get_chars(GTK_EDITABLE(filter_te), pos + 1, pos + 2);
856 if (strcmp(chars, "") != 0 && !isspace((unsigned char)chars[0]))
857 gtk_editable_insert_text(GTK_EDITABLE(filter_te), " ", 1, &pos);
861 * Put the cursor after the expression we just entered into
862 * the text entry widget.
864 gtk_editable_set_position(GTK_EDITABLE(filter_te), pos);
867 * We're done; destroy the dialog box (which is the top-level
868 * widget for the "Accept" button).
870 window_destroy(window);
875 dfilter_expr_dlg_cancel_cb(GtkWidget *w _U_, gpointer parent_w)
878 * User pressed the cancel button; close the dialog box.
880 window_destroy(GTK_WIDGET(parent_w));
883 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
885 dfilter_expr_dlg_delete_event_cb(GtkWidget *w _U_, GdkEvent *event _U_,
888 dfilter_expr_dlg_cancel_cb(NULL, parent_w);
893 dfilter_expr_dlg_destroy_cb(GtkWidget *w, gpointer filter_te)
896 * The dialog box is being destroyed; disconnect from the
897 * "destroy" signal on the text entry box to which we're
898 * attached, as the handler for that signal is supposed
899 * to destroy us, but we're already gone.
901 g_signal_handlers_disconnect_by_func(filter_te, dfilter_expr_dlg_cancel_cb, w);
905 * Length of string used for protocol fields.
907 #define TAG_STRING_LEN 256
910 dfilter_expr_dlg_new(GtkWidget *filter_te)
912 GtkWidget *window, *main_vb, *main_hb;
914 GtkWidget *field_vb, *field_tree_lb, *field_tree, *tree_scrolled_win;
916 GtkWidget *relation_vb, *relation_label, *relation_list, *relation_list_scrolled_win;
917 /* GtkWidget *relation_present_rb, *relation_equals_rb, *relation_unequals_rb,
918 *relation_greater_rb, *relation_less_rb,
919 *relation_greaterequal_rb, *relation_lessequal_rb,
920 *relation_contains_rb, *relation_matches_rb;*/
922 GtkWidget *value_vb, *value_label, *value_entry;
923 GtkWidget *value_list_label, *value_list_scrolled_win, *value_list;
924 GtkWidget *range_label, *range_entry;
926 GtkWidget *list_bb, *ok_bt, *cancel_bt;
927 header_field_info *hfinfo;
929 protocol_t *protocol;
931 GtkTreeSelection *selection;
932 GtkCellRenderer *renderer;
933 GtkTreeViewColumn *column;
934 GtkListStore *l_store;
935 GtkTreeSelection *l_sel;
937 proto_initialize_all_prefixes();
939 window = dlg_conf_window_new("Wireshark: Filter Expression");
940 gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
941 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
943 main_vb = gtk_vbox_new(FALSE, 5);
944 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
945 gtk_container_add(GTK_CONTAINER(window), main_vb);
947 main_hb = gtk_hbox_new(FALSE, 5);
948 gtk_container_set_border_width(GTK_CONTAINER(main_hb), 5);
949 gtk_container_add(GTK_CONTAINER(main_vb), main_hb);
951 field_vb = gtk_vbox_new(FALSE, 5);
952 gtk_container_set_border_width(GTK_CONTAINER(field_vb), 5);
953 gtk_container_add(GTK_CONTAINER(main_hb), field_vb);
955 field_tree_lb = gtk_label_new("Field name");
956 gtk_misc_set_alignment(GTK_MISC(field_tree_lb), 0.0f, 0.0f);
957 gtk_box_pack_start(GTK_BOX(field_vb), field_tree_lb, FALSE, FALSE, 0);
959 tree_scrolled_win = scrolled_window_new(NULL, NULL);
960 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(tree_scrolled_win),
962 gtk_box_pack_start(GTK_BOX(field_vb), tree_scrolled_win, TRUE, TRUE, 0);
963 gtk_widget_set_size_request(tree_scrolled_win, 300, -1);
966 store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
967 field_tree = tree_view_new(GTK_TREE_MODEL(store));
968 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(field_tree), FALSE);
969 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(field_tree));
970 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
971 renderer = gtk_cell_renderer_text_new();
972 column = gtk_tree_view_column_new_with_attributes("Field name", renderer,
974 gtk_tree_view_append_column(GTK_TREE_VIEW(field_tree), column);
975 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
976 gtk_tree_view_column_set_sort_column_id(column, 0);
977 g_signal_connect(selection, "changed", G_CALLBACK(field_select_row_cb), field_tree);
978 gtk_container_add(GTK_CONTAINER(tree_scrolled_win), field_tree);
980 relation_vb = gtk_vbox_new(FALSE, 5);
981 gtk_container_set_border_width(GTK_CONTAINER(relation_vb), 5);
982 gtk_container_add(GTK_CONTAINER(main_hb), relation_vb);
984 relation_label = gtk_label_new("Relation");
985 gtk_misc_set_alignment(GTK_MISC(relation_label), 0.0f, 0.0f);
986 gtk_box_pack_start(GTK_BOX(relation_vb), relation_label, FALSE, FALSE, 0);
988 relation_list_scrolled_win = scrolled_window_new(NULL, NULL);
989 /* never use a scrollbar in x direction, show the complete relation string */
990 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
991 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
992 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(relation_list_scrolled_win),
995 l_store = gtk_list_store_new(1, G_TYPE_STRING);
996 relation_list = tree_view_new(GTK_TREE_MODEL(l_store));
997 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(relation_list), FALSE);
998 g_object_unref(G_OBJECT(l_store));
999 renderer = gtk_cell_renderer_text_new();
1000 column = gtk_tree_view_column_new_with_attributes("relation", renderer,
1002 gtk_tree_view_append_column(GTK_TREE_VIEW(relation_list), column);
1003 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list));
1004 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_BROWSE);
1005 gtk_container_add(GTK_CONTAINER(relation_list_scrolled_win), relation_list);
1006 gtk_box_pack_start(GTK_BOX(relation_vb), relation_list_scrolled_win, TRUE, TRUE, 0);
1009 * OK, show the relation label and range stuff as it would be
1010 * with everything turned on, so it'll request as much space
1011 * as it'll ever need, so the dialog box and widgets start out
1012 * with the right sizes.
1014 * XXX - this doesn't work. It *doesn't* request as much space
1015 * as it'll ever need.
1017 * XXX - FT_UINT8 doesn't support ranges, so even if it did work,
1018 * it wouldn't work right.
1020 * XXX - this no longer affects the range stuff, as that's
1021 * controlled both by the type and by the relational operator
1024 show_relations(relation_list, FT_UINT8);
1027 relation_present_rb = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "is present");
1028 gtk_box_pack_start(GTK_BOX(relation_vb), relation_present_rb, FALSE, FALSE, 0);
1030 relation_equals_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "==");
1031 gtk_box_pack_start(GTK_BOX(relation_vb), relation_equals_rb, FALSE, FALSE, 0);
1033 relation_unequals_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "!=");
1034 gtk_box_pack_start(GTK_BOX(relation_vb), relation_unequals_rb, FALSE, FALSE, 0);
1036 relation_greater_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), ">");
1037 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greater_rb, FALSE, FALSE, 0);
1039 relation_less_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "<");
1040 gtk_box_pack_start(GTK_BOX(relation_vb), relation_less_rb, FALSE, FALSE, 0);
1042 relation_greaterequal_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), ">=");
1043 gtk_box_pack_start(GTK_BOX(relation_vb), relation_greaterequal_rb, FALSE, FALSE, 0);
1045 relation_lessequal_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "<=");
1046 gtk_box_pack_start(GTK_BOX(relation_vb), relation_lessequal_rb, FALSE, FALSE, 0);
1048 relation_contains_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "contains");
1049 gtk_box_pack_start(GTK_BOX(relation_vb), relation_contains_rb, FALSE, FALSE, 0);
1051 relation_matches_rb = gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(relation_present_rb), "matches");
1052 gtk_box_pack_start(GTK_BOX(relation_vb), relation_matches_rb, FALSE, FALSE, 0);
1055 value_vb = gtk_vbox_new(FALSE, 5);
1056 gtk_container_set_border_width(GTK_CONTAINER(value_vb), 5);
1057 gtk_container_add(GTK_CONTAINER(main_hb), value_vb);
1059 value_label = gtk_label_new("Value");
1060 gtk_misc_set_alignment(GTK_MISC(value_label), 0.0f, 0.0f);
1061 gtk_box_pack_start(GTK_BOX(value_vb), value_label, FALSE, FALSE, 0);
1063 value_entry = gtk_entry_new();
1064 gtk_box_pack_start(GTK_BOX(value_vb), value_entry, FALSE, FALSE, 0);
1066 value_list_label = gtk_label_new("Predefined values:");
1067 gtk_misc_set_alignment(GTK_MISC(value_list_label), 0.0f, 0.0f);
1068 gtk_box_pack_start(GTK_BOX(value_vb), value_list_label, FALSE, FALSE, 0);
1070 value_list_scrolled_win = scrolled_window_new(NULL, NULL);
1071 gtk_box_pack_start(GTK_BOX(value_vb), value_list_scrolled_win, TRUE,
1074 l_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
1075 value_list = tree_view_new(GTK_TREE_MODEL(l_store));
1076 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(value_list), FALSE);
1077 g_object_unref(G_OBJECT(l_store));
1078 renderer = gtk_cell_renderer_text_new();
1079 column = gtk_tree_view_column_new_with_attributes("value", renderer,
1081 gtk_tree_view_append_column(GTK_TREE_VIEW(value_list), column);
1082 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list)),
1083 "changed", G_CALLBACK(value_list_sel_cb), value_entry);
1086 * The value stuff may be hidden or shown depending on what
1087 * relation was selected; connect to the "changed" signal
1088 * for the relation list, so we can make that happen.
1090 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(relation_list)),
1091 "changed", G_CALLBACK(relation_list_sel_cb), NULL);
1092 l_sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(value_list));
1093 gtk_tree_selection_set_mode(l_sel, GTK_SELECTION_SINGLE);
1094 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(value_list_scrolled_win),
1096 /* This remains hidden until an enumerated field is selected */
1099 * Put the items in the Tree; we don't want to do that until
1100 * we've constructed the value list and set the tree's
1101 * E_DFILTER_EXPR_VALUE_LIST_KEY data to point to it, and
1102 * constructed the "Accept" button and set the tree's
1103 * E_DFILTER_EXPR_OK_BT_KEY data to point to it, so that
1104 * when the list item is "helpfully" automatically selected for us
1105 * we're ready to cope with the selection signal.
1109 /* GTK2 code using two levels iterator to enumerate all protocol fields */
1111 GtkTreeIter iter, child_iter;
1112 void *cookie, *cookie2;
1114 for (i = proto_get_first_protocol(&cookie); i != -1;
1115 i = proto_get_next_protocol(&cookie)) {
1116 char *strp, str[TAG_STRING_LEN+1];
1118 protocol = find_protocol_by_id(i);
1120 if (!proto_is_protocol_enabled(protocol)) {
1124 g_snprintf(str, TAG_STRING_LEN, "%s - %s",
1125 proto_get_protocol_short_name(protocol),
1126 proto_get_protocol_long_name(protocol));
1129 hfinfo = proto_registrar_get_nth(i);
1131 gtk_tree_store_append(store, &iter, NULL);
1132 gtk_tree_store_set(store, &iter, 0, strp, 1, hfinfo, -1);
1134 for (hfinfo = proto_get_first_protocol_field(i, &cookie2); hfinfo != NULL;
1135 hfinfo = proto_get_next_protocol_field(&cookie2)) {
1137 if (hfinfo->same_name_prev != NULL) /* ignore duplicate names */
1140 if (hfinfo->blurb != NULL && hfinfo->blurb[0] != '\0') {
1141 g_snprintf(str, TAG_STRING_LEN, "%s - %s (%s)",
1142 hfinfo->abbrev, hfinfo->name, hfinfo->blurb);
1144 g_snprintf(str, TAG_STRING_LEN, "%s - %s", hfinfo->abbrev,
1147 gtk_tree_store_append(store, &child_iter, &iter);
1148 gtk_tree_store_set(store, &child_iter, 0, strp, 1, hfinfo, -1);
1151 g_object_unref(G_OBJECT(store));
1154 range_label = gtk_label_new("Range (offset:length)");
1155 gtk_misc_set_alignment(GTK_MISC(range_label), 0.0f, 0.0f);
1156 gtk_box_pack_start(GTK_BOX(value_vb), range_label, FALSE, FALSE, 0);
1158 range_entry = gtk_entry_new();
1159 gtk_box_pack_start(GTK_BOX(value_vb), range_entry, FALSE, FALSE, 0);
1163 list_bb = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
1164 gtk_box_pack_start(GTK_BOX(main_vb), list_bb, FALSE, FALSE, 0);
1165 gtk_container_set_border_width (GTK_CONTAINER (list_bb), 0);
1167 ok_bt = g_object_get_data(G_OBJECT(list_bb), GTK_STOCK_OK);
1168 gtk_widget_set_sensitive(ok_bt, FALSE);
1169 g_signal_connect(ok_bt, "clicked", G_CALLBACK(dfilter_expr_dlg_accept_cb), filter_te);
1171 cancel_bt = g_object_get_data(G_OBJECT(list_bb), GTK_STOCK_CANCEL);
1172 window_set_cancel_button(window, cancel_bt, NULL);
1173 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(dfilter_expr_dlg_cancel_cb), window);
1175 gtk_widget_grab_default(ok_bt);
1177 /* Catch the "activate" signal on the range and value text entries,
1178 so that if the user types Return there, we act as if the "Accept"
1179 button had been selected, as happens if Return is typed if some
1180 widget that *doesn't* handle the Return key has the input focus. */
1181 dlg_set_activate(range_entry, ok_bt);
1182 dlg_set_activate(value_entry, ok_bt);
1184 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RELATION_LIST_KEY, relation_list);
1185 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_LABEL_KEY, range_label);
1186 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_RANGE_ENTRY_KEY, range_entry);
1187 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LABEL_KEY, value_label);
1188 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_ENTRY_KEY, value_entry);
1189 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_KEY, value_list);
1190 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_LABEL_KEY, value_list_label);
1191 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_VALUE_LIST_SW_KEY,
1192 value_list_scrolled_win);
1193 g_object_set_data(G_OBJECT(window), E_DFILTER_EXPR_OK_BT_KEY, ok_bt);
1195 g_signal_connect(window, "delete_event", G_CALLBACK(dfilter_expr_dlg_delete_event_cb), window);
1198 * Catch the "destroy" signal on our top-level window, and,
1199 * when it's destroyed, disconnect the signal we'll be
1202 g_signal_connect(window, "destroy", G_CALLBACK(dfilter_expr_dlg_destroy_cb), filter_te);
1205 * Catch the "destroy" signal on the text entry widget to which
1206 * we're attached; if it's destroyed, we should destroy ourselves
1209 g_signal_connect(filter_te, "destroy", G_CALLBACK(dfilter_expr_dlg_cancel_cb), window);
1211 gtk_widget_show_all(window);
1212 window_present(window);