From abd16b297f4750ea7f74137e87582c64153440f4 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Thu, 14 Oct 2004 23:45:09 +0000 Subject: [PATCH] From Jeff Morriss: PREF_RANGE preference type, for ranges of integers. svn path=/trunk/; revision=12300 --- doc/README.developer | 8 +++++ epan/dissectors/packet-tcap.c | 66 ++++++++++++++++++++++++----------- epan/prefs-int.h | 4 +++ epan/prefs.c | 41 ++++++++++++++++++++++ epan/prefs.h | 9 +++++ epan/range.c | 60 ++++++++++++++++++++++++++++++- epan/range.h | 8 +++++ gtk/prefs_dlg.c | 63 +++++++++++++++++++++++++++++++++ 8 files changed, 237 insertions(+), 22 deletions(-) diff --git a/doc/README.developer b/doc/README.developer index 300be484f4..ec82fc2022 100644 --- a/doc/README.developer +++ b/doc/README.developer @@ -2442,6 +2442,13 @@ Then you can register the fields that can be configured by the user with these r void prefs_register_string_preference(module_t *module, const char *name, const char *title, const char *description, char **var) + /* Register a preference with a range of unsigned integers (e.g., + * "1-20,30-40"). + */ + void prefs_register_range_preference(module_t *module, const char *name, + const char *title, const char *description, range_t *var, + guint32 max_value) + Where: module - Returned by the prefs_register_protocol routine name - This is appended to the name of the protocol, with a "." between them, to construct a name that identifies @@ -2472,6 +2479,7 @@ Where: module - Returned by the prefs_register_protocol routine preferences dialog as a set of radio buttons, FALSE if it is to be displayed as an option menu + max_value - The maximum allowed value for a range (0 is the minimum). An example from packet-beep.c - diff --git a/epan/dissectors/packet-tcap.c b/epan/dissectors/packet-tcap.c index 5941e33e3c..ec2c764b32 100644 --- a/epan/dissectors/packet-tcap.c +++ b/epan/dissectors/packet-tcap.c @@ -66,6 +66,10 @@ Tcap_Standard_Type tcap_standard = ITU_TCAP_STANDARD; +#define MAX_SSN 254 +static range_t global_ssn_range; +static range_t ssn_range; + /* saved pinfo */ static packet_info *g_pinfo = NULL; static proto_tree *g_tcap_tree = NULL; @@ -2741,6 +2745,8 @@ dissect_tcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* Register the protocol with Ethereal */ +void proto_reg_handoff_tcap(void); + /* this format is require because a script is used to build the C function that calls all the protocol registration. */ @@ -2846,7 +2852,7 @@ proto_register_tcap(void) proto_register_field_array(proto_tcap, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); - tcap_module = prefs_register_protocol(proto_tcap, NULL); + tcap_module = prefs_register_protocol(proto_tcap, proto_reg_handoff_tcap); prefs_register_enum_preference(tcap_module, "standard", "TCAP standard", "The SS7 standard used in TCAP packets", @@ -2856,6 +2862,14 @@ proto_register_tcap(void) "Always show TCAP in Info column", &lock_info_col); + /* Set default SSNs */ + range_convert_str(&global_ssn_range, "5-12", MAX_SSN); + memset(&ssn_range, 0, sizeof(ssn_range)); + + prefs_register_range_preference(tcap_module, "ssn", "SCCP SSNs", + "SCCP (and SUA) SSNs to decode as TCAP", + &global_ssn_range, MAX_SSN); + /* we will fake a ssn subfield which has the same value obtained from sccp */ tcap_itu_ssn_dissector_table = register_dissector_table("tcap.itu_ssn", "ITU TCAP SSN", FT_UINT8, BASE_DEC); tcap_ansi_ssn_dissector_table = register_dissector_table("tcap.ansi_ssn", "ANSI TCAP SSN", FT_UINT8, BASE_DEC); @@ -2869,28 +2883,38 @@ proto_register_tcap(void) void proto_reg_handoff_tcap(void) { - dissector_handle_t tcap_handle; + static dissector_handle_t tcap_handle; + static gboolean prefs_initialized = FALSE; - tcap_handle = create_dissector_handle(dissect_tcap, - proto_tcap); + static void range_delete_callback(guint32 ssn) + { + if (ssn) { + dissector_delete("sccp.ssn", ssn, tcap_handle); + dissector_delete("sua.ssn", ssn, tcap_handle); + } + } + static void range_add_callback(guint32 ssn) + { + if (ssn) { + dissector_add("sccp.ssn", ssn, tcap_handle); + dissector_add("sua.ssn", ssn, tcap_handle); + } + } - dissector_add("sccp.ssn", 5, tcap_handle); /* MAP*/ - dissector_add("sccp.ssn", 6, tcap_handle); /* HLR*/ - dissector_add("sccp.ssn", 7, tcap_handle); /* VLR */ - dissector_add("sccp.ssn", 8, tcap_handle); /* MSC */ - dissector_add("sccp.ssn", 9, tcap_handle); /* EIR */ - dissector_add("sccp.ssn", 10, tcap_handle); /* EIR */ - dissector_add("sccp.ssn", 11, tcap_handle); /* SMS/MC */ - dissector_add("sccp.ssn", 12, tcap_handle); /* IS41 OTAF */ + if (!prefs_initialized) { - dissector_add("sua.ssn", 5, tcap_handle); /* MAP*/ - dissector_add("sua.ssn", 6, tcap_handle); /* HLR*/ - dissector_add("sua.ssn", 7, tcap_handle); /* VLR */ - dissector_add("sua.ssn", 8, tcap_handle); /* MSC */ - dissector_add("sua.ssn", 9, tcap_handle); /* EIR */ - dissector_add("sua.ssn", 10, tcap_handle); /* EIR */ - dissector_add("sua.ssn", 11, tcap_handle); /* SMS/MC */ - dissector_add("sua.ssn", 12, tcap_handle); /* IS41 OTAF */ + tcap_handle = create_dissector_handle(dissect_tcap, proto_tcap); + data_handle = find_dissector("data"); + + prefs_initialized = TRUE; + + } else { + + range_foreach(&ssn_range, range_delete_callback); + } + + ssn_range = global_ssn_range; + + range_foreach(&ssn_range, range_add_callback); - data_handle = find_dissector("data"); } diff --git a/epan/prefs-int.h b/epan/prefs-int.h index 055c980d06..e3b5617301 100644 --- a/epan/prefs-int.h +++ b/epan/prefs-int.h @@ -53,6 +53,7 @@ typedef enum { PREF_BOOL, PREF_ENUM, PREF_STRING, + PREF_RANGE, PREF_OBSOLETE } pref_type_t; @@ -67,15 +68,18 @@ struct preference { gboolean *boolp; gint *enump; char **string; + range_t *rangep; } varp; /* pointer to variable storing the value */ union { guint uint; gboolean boolval; gint enumval; char *string; + range_t rangeval; } saved_val; /* original value, when editing from the GUI */ union { guint base; /* input/output base, for PREF_UINT */ + guint32 max_value; /* maximum value of a range */ struct { const enum_val_t *enumvals; /* list of name & values */ gboolean radio_buttons; /* TRUE if it should be shown as diff --git a/epan/prefs.c b/epan/prefs.c index 1def43c844..e88f1eccba 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -579,6 +579,24 @@ prefs_register_string_preference(module_t *module, const char *name, preference->saved_val.string = NULL; } +/* + * Register a preference with a ranged value. + */ +void +prefs_register_range_preference(module_t *module, const char *name, + const char *title, const char *description, range_t *var, + guint32 max_value) +{ + pref_t *preference; + + preference = register_preference(module, name, title, description, + PREF_RANGE); + preference->info.max_value = max_value; + + preference->varp.rangep = var; + memset(&preference->saved_val.rangeval, 0, sizeof(preference->saved_val.rangeval)); +} + /* * Register a preference that used to be supported but no longer is. */ @@ -1992,6 +2010,19 @@ set_pref(gchar *pref_name, gchar *value) } break; + case PREF_RANGE: + { + range_t newrange; + + range_convert_str(&newrange, value, pref->info.max_value); + + if (!ranges_are_equal(pref->varp.rangep, &newrange)) { + module->prefs_changed = TRUE; + *pref->varp.rangep = newrange; + } + break; + } + case PREF_OBSOLETE: return PREFS_SET_OBSOLETE; /* no such preference any more */ } @@ -2091,6 +2122,16 @@ write_pref(gpointer data, gpointer user_data) *pref->varp.string); break; + case PREF_RANGE: + { + char range_string[MAXRANGESTRING]; + + fprintf(arg->pf, "# A string denoting an positive integer range (e.g., \"1-20,30-40\").\n"); + fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name, + range_convert_range(pref->varp.rangep, range_string)); + break; + } + case PREF_OBSOLETE: g_assert_not_reached(); break; diff --git a/epan/prefs.h b/epan/prefs.h index 5a6f589a4b..f4cb4e023f 100644 --- a/epan/prefs.h +++ b/epan/prefs.h @@ -29,6 +29,8 @@ #include "color.h" +#include + #define PR_DEST_CMD 0 #define PR_DEST_FILE 1 @@ -274,6 +276,13 @@ extern void prefs_register_enum_preference(module_t *module, const char *name, extern void prefs_register_string_preference(module_t *module, const char *name, const char *title, const char *description, char **var); +/* + * Register a preference with a ranged value. + */ +extern void prefs_register_range_preference(module_t *module, const char *name, + const char *title, const char *description, range_t *var, + guint32 max_value); + /* * Register a preference that used to be supported but no longer is. */ diff --git a/epan/range.c b/epan/range.c index dde4d966cf..5da7d7028e 100644 --- a/epan/range.c +++ b/epan/range.c @@ -37,6 +37,7 @@ #include #include +#include /* init the range struct */ void range_init(range_t *range) { @@ -73,7 +74,8 @@ void range_init(range_t *range) { void range_convert_str(range_t *range, const gchar *es, guint32 max_value) { - gchar EntryStr[255], OrgStr[255], value[255], p; + gchar EntryStr[MAXRANGESTRING], OrgStr[MAXRANGESTRING]; + gchar value[MAXRANGESTRING], p; guint i, j=0; guint32 tmp, val; gboolean hyphenseen; @@ -241,6 +243,62 @@ gboolean value_is_in_range(range_t *range, guint32 val) return(FALSE); } +/* This function returns TRUE if the two given range_t's are equal. + */ +gboolean ranges_are_equal(range_t *a, range_t *b) +{ + guint i; + + if (a->nranges != b->nranges) + return FALSE; + + for (i=0; i <= a->nranges; i++) { + if (a->ranges[i].low != b->ranges[i].low) + return FALSE; + + if (a->ranges[i].high != b->ranges[i].high) + return FALSE; + } + + return TRUE; + +} + +/* This function calls the provided callback function for each value in + * in the range. + */ +void +range_foreach(range_t *range, void (*callback)(guint32 val)) +{ + guint32 i, j; + + for (i=0; i <= range->nranges; i++) { + for (j = range->ranges[i].low; j <= range->ranges[i].high; j++) + callback(j); + } +} + +/* This function converts a range_t to a (caller-provided) string. */ +char * +range_convert_range(range_t *range, char *string) +{ + guint32 i, k; + + k = 0; + string[k] = '\0'; + + for (i=0; i <= range->nranges; i++) { + if (i != 0) + string[k++] = ','; + + k += sprintf(&string[k], "%d-%d", range->ranges[i].low, + range->ranges[i].high); + } + + return(string); + +} + #if 0 /* This is a debug function to check the range functionality */ static void value_is_in_range_check(range_t *range, guint32 val) diff --git a/epan/range.h b/epan/range.h index 7dc46eb0cf..314f3c5ed7 100644 --- a/epan/range.h +++ b/epan/range.h @@ -35,6 +35,8 @@ /* Range parser variables */ #define MaxRange 30 +#define MAXRANGESTRING 255 + typedef struct range_admin_tag { guint32 low; guint32 high; @@ -53,4 +55,10 @@ extern void range_convert_str(range_t *range, const gchar *es, extern gboolean value_is_in_range(range_t *range, guint32 val); +extern gboolean ranges_are_equal(range_t *a, range_t *b); + +extern void range_foreach(range_t *range, void (*callback)(guint32 val)); + +extern char *range_convert_range(range_t *range, char *string); + #endif /* __RANGE_H__ */ diff --git a/gtk/prefs_dlg.c b/gtk/prefs_dlg.c index cf329a0524..a5fcde6b3e 100644 --- a/gtk/prefs_dlg.c +++ b/gtk/prefs_dlg.c @@ -202,6 +202,18 @@ pref_show(pref_t *pref, gpointer user_data) pref->saved_val.string); break; + case PREF_RANGE: + { + char range_string[MAXRANGESTRING]; + + pref->saved_val.rangeval = *pref->varp.rangep; + range_convert_range(pref->varp.rangep, range_string); + pref->control = create_preference_entry(main_tb, pref->ordinal, + label_string, pref->description, + range_string); + break; + } + case PREF_OBSOLETE: g_assert_not_reached(); break; @@ -886,6 +898,24 @@ pref_check(pref_t *pref, gpointer user_data) /* Value can't be bad. */ break; + case PREF_RANGE: + str_val = gtk_entry_get_text(GTK_ENTRY(pref->control)); + + if (strlen(str_val)) { + range_t newrange; + + range_convert_str(&newrange, str_val, pref->info.max_value); + if (newrange.nranges == 0) { + /* If the user specified a string of non-zero length but + * range_convert_str() couldn't find a single range in it, + * it must be bad. + */ + *badpref = pref; + return PREFS_SET_SYNTAX_ERR; /* range was bad */ + } + } + break; + case PREF_OBSOLETE: g_assert_not_reached(); break; @@ -960,6 +990,22 @@ pref_fetch(pref_t *pref, gpointer user_data) } break; + case PREF_RANGE: + { + range_t newrange; + + str_val = gtk_entry_get_text(GTK_ENTRY(pref->control)); + range_convert_str(&newrange, str_val, pref->info.max_value); + + if (!ranges_are_equal(pref->varp.rangep, &newrange)) + { + *pref_changed_p = TRUE; + *pref->varp.rangep = newrange; + } + + break; + } + case PREF_OBSOLETE: g_assert_not_reached(); break; @@ -1007,6 +1053,9 @@ pref_clean(pref_t *pref, gpointer user_data _U_) } break; + case PREF_RANGE: + break; + case PREF_OBSOLETE: g_assert_not_reached(); break; @@ -1042,6 +1091,12 @@ prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect) badpref->title); return FALSE; + case PREF_RANGE: + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "The value for \"%s\" is not a valid range.", + badpref->title); + return FALSE; + default: g_assert_not_reached(); break; @@ -1257,6 +1312,14 @@ pref_revert(pref_t *pref, gpointer user_data) } break; + case PREF_RANGE: + if (!ranges_are_equal(pref->varp.rangep, &pref->saved_val.rangeval)) + { + *pref_changed_p = TRUE; + *pref->varp.rangep = pref->saved_val.rangeval; + } + break; + case PREF_OBSOLETE: g_assert_not_reached(); break;