Bug Summary

File:builds/wireshark/wireshark/epan/prefs.c
Warning:line 4887, column 21
Value of 'errno' was not checked and may be overwritten by function 'getc_unlocked'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name prefs.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /usr/include/lua5.4 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2026-03-11-100403-3621-1 -x c /builds/wireshark/wireshark/epan/prefs.c
1/* prefs.c
2 * Routines for handling preferences
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <[email protected]>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "config.h"
12#define WS_LOG_DOMAIN"Epan" LOG_DOMAIN_EPAN"Epan"
13
14#include "ws_diag_control.h"
15
16#include <stdlib.h>
17#include <string.h>
18#include <errno(*__errno_location ()).h>
19#ifdef _WIN32
20#include <windows.h>
21#endif
22
23#include <glib.h>
24
25#include <stdio.h>
26#include <wsutil/filesystem.h>
27#include <epan/addr_resolv.h>
28#include <epan/oids.h>
29#include <epan/maxmind_db.h>
30#include <epan/packet.h>
31#include <epan/prefs.h>
32#include <epan/proto.h>
33#include <epan/strutil.h>
34#include <epan/column.h>
35#include <epan/decode_as.h>
36#include <ui/capture_opts.h>
37#include <wsutil/file_util.h>
38#include <wsutil/report_message.h>
39#include <wsutil/wslog.h>
40#include <wsutil/ws_assert.h>
41#include <wsutil/array.h>
42
43#include <epan/prefs-int.h>
44#include <epan/uat-int.h>
45
46#include "epan/filter_expressions.h"
47#include "epan/aggregation_fields.h"
48
49#include "epan/wmem_scopes.h"
50#include <epan/stats_tree.h>
51
52#define REG_HKCU_WIRESHARK_KEY"Software\\Wireshark" "Software\\Wireshark"
53
54/*
55 * Module alias.
56 */
57typedef struct pref_module_alias {
58 const char *name; /**< name of module alias */
59 module_t *module; /**< module for which it's an alias */
60} module_alias_t;
61
62/* Internal functions */
63static void prefs_register_modules(void);
64static module_t *prefs_find_module_alias(const char *name);
65static prefs_set_pref_e set_pref(char*, const char*, void *, bool_Bool);
66static void free_col_info(GList *);
67static void prefs_set_global_defaults(wmem_allocator_t* pref_scope, const char** col_fmt, int num_cols);
68static bool_Bool prefs_is_column_visible(const char *cols_hidden, int col);
69static bool_Bool prefs_is_column_fmt_visible(const char *cols_hidden, fmt_data *cfmt);
70static int find_val_for_string(const char *needle, const enum_val_t *haystack, int default_value);
71
72#define PF_NAME"preferences" "preferences"
73#define OLD_GPF_NAME"wireshark.conf" "wireshark.conf" /* old name for global preferences file */
74
75static char *gpf_path;
76static char *cols_hidden_list;
77static char *cols_hidden_fmt_list;
78static bool_Bool gui_theme_is_dark;
79
80e_prefs prefs;
81
82static const enum_val_t gui_console_open_type[] = {
83 {"NEVER", "NEVER", LOG_CONSOLE_OPEN_NEVER},
84 {"AUTOMATIC", "AUTOMATIC", LOG_CONSOLE_OPEN_AUTO},
85 {"ALWAYS", "ALWAYS", LOG_CONSOLE_OPEN_ALWAYS},
86 {NULL((void*)0), NULL((void*)0), -1}
87};
88
89static const enum_val_t gui_version_placement_type[] = {
90 {"WELCOME", "WELCOME", version_welcome_only},
91 {"TITLE", "TITLE", version_title_only},
92 {"BOTH", "BOTH", version_both},
93 {"NEITHER", "NEITHER", version_neither},
94 {NULL((void*)0), NULL((void*)0), -1}
95};
96
97static const enum_val_t gui_fileopen_style[] = {
98 {"LAST_OPENED", "LAST_OPENED", FO_STYLE_LAST_OPENED0},
99 {"SPECIFIED", "SPECIFIED", FO_STYLE_SPECIFIED1},
100 {"CWD", "CWD", FO_STYLE_CWD2},
101 {NULL((void*)0), NULL((void*)0), -1}
102};
103
104static const enum_val_t gui_toolbar_style[] = {
105 {"ICONS", "ICONS", 0},
106 {"TEXT", "TEXT", 1},
107 {"BOTH", "BOTH", 2},
108 {NULL((void*)0), NULL((void*)0), -1}
109};
110
111static const enum_val_t gui_layout_content[] = {
112 {"NONE", "NONE", 0},
113 {"PLIST", "PLIST", 1},
114 {"PDETAILS", "PDETAILS", 2},
115 {"PBYTES", "PBYTES", 3},
116 {"PDIAGRAM", "PDIAGRAM", 4},
117 {NULL((void*)0), NULL((void*)0), -1}
118};
119
120static const enum_val_t gui_packet_dialog_layout[] = {
121 {"vertical", "Vertical (Stacked)", layout_vertical},
122 {"horizontal", "Horizontal (Side-by-side)", layout_horizontal},
123 {NULL((void*)0), NULL((void*)0), -1}
124};
125
126static const enum_val_t gui_update_channel[] = {
127 {"DEVELOPMENT", "DEVELOPMENT", UPDATE_CHANNEL_DEVELOPMENT},
128 {"STABLE", "STABLE", UPDATE_CHANNEL_STABLE},
129 {NULL((void*)0), NULL((void*)0), -1}
130};
131
132static const enum_val_t gui_selection_style[] = {
133 {"DEFAULT", "DEFAULT", COLOR_STYLE_DEFAULT0},
134 {"FLAT", "FLAT", COLOR_STYLE_FLAT1},
135 {"GRADIENT", "GRADIENT", COLOR_STYLE_GRADIENT2},
136 {NULL((void*)0), NULL((void*)0), -1}
137};
138
139static const enum_val_t gui_color_scheme[] = {
140 {"system", "System Default", COLOR_SCHEME_DEFAULT0},
141 {"light", "Light Mode", COLOR_SCHEME_LIGHT1},
142 {"dark", "Dark Mode", COLOR_SCHEME_DARK2},
143 {NULL((void*)0), NULL((void*)0), -1}
144};
145
146static const enum_val_t gui_packet_list_copy_format_options_for_keyboard_shortcut[] = {
147 {"TEXT", "Text", COPY_FORMAT_TEXT},
148 {"CSV", "CSV", COPY_FORMAT_CSV},
149 {"YAML", "YAML", COPY_FORMAT_YAML},
150 {"HTML", "HTML", COPY_FORMAT_HTML},
151 {NULL((void*)0), NULL((void*)0), -1}
152};
153
154/* None : Historical behavior, no deinterlacing */
155#define CONV_DEINT_CHOICE_NONE0 0
156/* MI : MAC & Interface */
157#define CONV_DEINT_CHOICE_MI0x04 + 0x02 CONV_DEINT_KEY_MAC0x04 + CONV_DEINT_KEY_INTERFACE0x02
158/* VM : VLAN & MAC */
159#define CONV_DEINT_CHOICE_VM0x08 + 0x04 CONV_DEINT_KEY_VLAN0x08 + CONV_DEINT_KEY_MAC0x04
160/* VMI : VLAN & MAC & Interface */
161#define CONV_DEINT_CHOICE_VMI0x08 + 0x04 + 0x02 CONV_DEINT_KEY_VLAN0x08 + CONV_DEINT_KEY_MAC0x04 + CONV_DEINT_KEY_INTERFACE0x02
162
163static const enum_val_t conv_deint_options[] = {
164 {"NONE", "NONE", CONV_DEINT_CHOICE_NONE0},
165 {".MI", ".MI", CONV_DEINT_CHOICE_MI0x04 + 0x02 },
166 {"VM.", "VM.", CONV_DEINT_CHOICE_VM0x08 + 0x04 },
167 {"VMI", "VMI", CONV_DEINT_CHOICE_VMI0x08 + 0x04 + 0x02 },
168 {NULL((void*)0), NULL((void*)0), -1}
169};
170
171static const enum_val_t abs_time_format_options[] = {
172 {"NEVER", "Never", ABS_TIME_ASCII_NEVER},
173 {"TREE", "Protocol tree only", ABS_TIME_ASCII_TREE},
174 {"COLUMN", "Protocol tree and columns", ABS_TIME_ASCII_COLUMN},
175 {"ALWAYS", "Always", ABS_TIME_ASCII_ALWAYS},
176 {NULL((void*)0), NULL((void*)0), -1}
177};
178
179static int num_capture_cols = 7;
180static const char *capture_cols[7] = {
181 "INTERFACE",
182 "LINK",
183 "PMODE",
184 "SNAPLEN",
185 "MONITOR",
186 "BUFFER",
187 "FILTER"
188};
189#define CAPTURE_COL_TYPE_DESCRIPTION"Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n" \
190 "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
191
192static const enum_val_t gui_packet_list_elide_mode[] = {
193 {"LEFT", "LEFT", ELIDE_LEFT},
194 {"RIGHT", "RIGHT", ELIDE_RIGHT},
195 {"MIDDLE", "MIDDLE", ELIDE_MIDDLE},
196 {"NONE", "NONE", ELIDE_NONE},
197 {NULL((void*)0), NULL((void*)0), -1}
198};
199
200/** Struct to hold preference data */
201struct preference {
202 const char *name; /**< name of preference */
203 const char *title; /**< title to use in GUI */
204 const char *description; /**< human-readable description of preference */
205 wmem_allocator_t* scope; /**< memory scope allocator for this preference */
206 int ordinal; /**< ordinal number of this preference */
207 pref_type_e type; /**< type of that preference */
208 bool_Bool obsolete; /**< obsolete preference flag */
209 unsigned int effect_flags; /**< Flags of types effected by preference (PREF_EFFECT_DISSECTION, PREF_EFFECT_CAPTURE, etc).
210 Flags must be non-zero to ensure saving to disk */
211 union { /* The Qt preference code assumes that these will all be pointers (and unique) */
212 unsigned *uint;
213 bool_Bool *boolp;
214 int *enump;
215 int* intp;
216 double* floatp;
217 char **string;
218 range_t **range;
219 struct epan_uat* uat;
220 color_t *colorp;
221 GList** list;
222 } varp; /**< pointer to variable storing the value */
223 union {
224 unsigned uint;
225 bool_Bool boolval;
226 int enumval;
227 int intval;
228 double floatval;
229 char *string;
230 range_t *range;
231 color_t color;
232 GList* list;
233 } stashed_val; /**< original value, when editing from the GUI */
234 union {
235 unsigned uint;
236 bool_Bool boolval;
237 int enumval;
238 int intval;
239 double floatval;
240 char *string;
241 range_t *range;
242 color_t color;
243 GList* list;
244 } default_val; /**< the default value of the preference */
245 union {
246 unsigned base; /**< input/output base, for PREF_UINT */
247 uint32_t max_value; /**< maximum value of a range */
248 struct {
249 const enum_val_t *enumvals; /**< list of name & values */
250 bool_Bool radio_buttons; /**< true if it should be shown as
251 radio buttons rather than as an
252 option menu or combo box in
253 the preferences tab */
254 } enum_info; /**< for PREF_ENUM */
255 } info; /**< display/text file information */
256 struct pref_custom_cbs custom_cbs; /**< for PREF_CUSTOM */
257 const char *dissector_table; /**< for PREF_DECODE_AS_RANGE */
258 const char *dissector_desc; /**< for PREF_DECODE_AS_RANGE */
259};
260
261const char* prefs_get_description(pref_t *pref)
262{
263 return pref->description;
264}
265
266const char* prefs_get_title(pref_t *pref)
267{
268 return pref->title;
269}
270
271int prefs_get_type(pref_t *pref)
272{
273 return pref->type;
274}
275
276const char* prefs_get_name(pref_t *pref)
277{
278 return pref->name;
279}
280
281uint32_t prefs_get_max_value(pref_t *pref)
282{
283 return pref->info.max_value;
284}
285
286const char* prefs_get_dissector_table(pref_t *pref)
287{
288 return pref->dissector_table;
289}
290
291static const char* prefs_get_dissector_description(pref_t *pref)
292{
293 return pref->dissector_desc;
294}
295
296/*
297 * List of all modules with preference settings.
298 */
299static wmem_tree_t *prefs_modules;
300
301/*
302 * List of all modules that should show up at the top level of the
303 * tree in the preference dialog box.
304 */
305static wmem_tree_t *prefs_top_level_modules;
306
307/*
308 * List of aliases for modules.
309 */
310static wmem_tree_t *prefs_module_aliases;
311
312/*
313 * Regex to match line terminators. Prefs are written and read to file line by
314 * line, so unescaped line terminators cause unexpected behavior.
315 */
316static GRegex *prefs_regex;
317
318/** Sets up memory used by proto routines. Called at program startup */
319void
320prefs_init(const char** col_fmt, int num_cols)
321{
322 memset(&prefs, 0, sizeof(prefs));
323 prefs_modules = wmem_tree_new(wmem_epan_scope());
324 prefs_top_level_modules = wmem_tree_new(wmem_epan_scope());
325 prefs_module_aliases = wmem_tree_new(wmem_epan_scope());
326 if (!prefs_regex)
327 prefs_regex = g_regex_new("\\s*\\R\\s*", (GRegexCompileFlags)G_REGEX_OPTIMIZE,
328 (GRegexMatchFlags)G_REGEX_MATCH_BSR_ANYCRLF, NULL((void*)0));
329
330 prefs_set_global_defaults(wmem_epan_scope(), col_fmt, num_cols);
331 prefs_register_modules();
332}
333
334const wmem_tree_t* prefs_get_module_tree(void)
335{
336 return prefs_modules;
337}
338
339/*
340 * Free the strings for a string-like preference.
341 */
342static void
343free_string_like_preference(pref_t *pref)
344{
345 wmem_free(pref->scope, *pref->varp.string);
346 *pref->varp.string = NULL((void*)0);
347 wmem_free(pref->scope, pref->default_val.string);
348 pref->default_val.string = NULL((void*)0);
349}
350
351void
352pref_free_individual(void *data, void *user_data _U___attribute__((unused)))
353{
354 pref_t *pref = (pref_t *)data;
355
356 switch (pref->type) {
357 case PREF_BOOL:
358 case PREF_ENUM:
359 case PREF_UINT:
360 case PREF_INT:
361 case PREF_FLOAT:
362 case PREF_STATIC_TEXT:
363 case PREF_UAT:
364 case PREF_COLOR:
365 break;
366 case PREF_STRING:
367 case PREF_SAVE_FILENAME:
368 case PREF_OPEN_FILENAME:
369 case PREF_DIRNAME:
370 case PREF_PASSWORD:
371 case PREF_DISSECTOR:
372 free_string_like_preference(pref);
373 break;
374 case PREF_RANGE:
375 case PREF_DECODE_AS_RANGE:
376 wmem_free(pref->scope, *pref->varp.range);
377 *pref->varp.range = NULL((void*)0);
378 wmem_free(pref->scope, pref->default_val.range);
379 pref->default_val.range = NULL((void*)0);
380 break;
381 case PREF_CUSTOM:
382 if (strcmp(pref->name, "columns") == 0)
383 pref->stashed_val.boolval = true1;
384 pref->custom_cbs.free_cb(pref);
385 break;
386 /* non-generic preferences */
387 case PREF_PROTO_TCP_SNDAMB_ENUM:
388 break;
389 }
390
391 wmem_free(pref->scope, pref);
392}
393
394static unsigned
395free_module_prefs(module_t *module, void *data _U___attribute__((unused)))
396{
397 if (module->prefs) {
398 g_list_foreach(module->prefs, pref_free_individual, NULL((void*)0));
399 g_list_free(module->prefs);
400 }
401 module->prefs = NULL((void*)0);
402 module->numprefs = 0;
403 if (module->submodules) {
404 prefs_module_list_foreach(module->submodules, free_module_prefs, NULL((void*)0), false0);
405 }
406 /* We don't free the actual module: its submodules pointer points to
407 a wmem_tree and the module itself is stored in a wmem_tree
408 */
409
410 return 0;
411}
412
413/** Frees memory used by proto routines. Called at program shutdown */
414void
415prefs_cleanup(void)
416{
417 /* This isn't strictly necessary since we're exiting anyway, but let's
418 * do what clean up we can.
419 */
420 prefs_module_list_foreach(prefs_modules, free_module_prefs, NULL((void*)0), false0);
421
422 /* Clean the uats */
423 uat_cleanup();
424
425 /* Shut down mmdbresolve */
426 maxmind_db_pref_cleanup();
427
428 g_free(prefs.saved_at_version);
429 g_free(gpf_path);
430 gpf_path = NULL((void*)0);
431 g_regex_unref(prefs_regex);
432 prefs_regex = NULL((void*)0);
433}
434
435void prefs_set_gui_theme_is_dark(bool_Bool is_dark)
436{
437 gui_theme_is_dark = is_dark;
438}
439
440static void
441prefs_deregister_module(wmem_tree_t* pref_tree, const char *name, const char *title, wmem_tree_t *all_modules)
442{
443 /* Remove this module from the list of all modules */
444 module_t *module = (module_t *)wmem_tree_remove_string(all_modules, name, WMEM_TREE_STRING_NOCASE0x00000001);
445
446 if (!module)
447 return;
448
449 wmem_tree_remove_string(pref_tree, title, WMEM_TREE_STRING_NOCASE0x00000001);
450 free_module_prefs(module, NULL((void*)0));
451 wmem_free(module->scope, module);
452}
453
454static void
455prefs_update_existing_subtree(module_t* module, const char* name, const char* description,
456 const char* help, void (*apply_cb)(void), wmem_tree_t* master_pref_tree)
457{
458 module->name = name;
459 module->apply_cb = apply_cb;
460 module->description = description;
461 module->help = help;
462
463 /* Registering it as a module (not just as a subtree) twice is an
464 * error in the code for the same reason as below. */
465 if (prefs_find_module(name) != NULL((void*)0)) {
466 ws_error("Preference module \"%s\" is being registered twice", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 466
, __func__, "Preference module \"%s\" is being registered twice"
, name)
;
467 }
468 wmem_tree_insert_string(master_pref_tree, name, module,
469 WMEM_TREE_STRING_NOCASE0x00000001);
470}
471
472static module_t*
473prefs_create_module(wmem_allocator_t* scope, module_t* parent, const char* name,
474 const char* title, const char* description,
475 const char* help, void (*apply_cb)(void),
476 bool_Bool use_gui)
477{
478 module_t* module = wmem_new(scope, module_t)((module_t*)wmem_alloc((scope), sizeof(module_t)));
479 module->name = name;
480 module->title = title;
481 module->description = description;
482 module->help = help;
483 module->apply_cb = apply_cb;
484 module->scope = scope;
485 module->prefs = NULL((void*)0); /* no preferences, to start */
486 module->parent = parent;
487 module->submodules = NULL((void*)0); /* no submodules, to start */
488 module->numprefs = 0;
489 module->prefs_changed_flags = 0;
490 module->obsolete = false0;
491 module->use_gui = use_gui;
492 /* A module's preferences affects dissection unless otherwise told */
493 module->effect_flags = PREF_EFFECT_DISSECTION(1u << 0);
494
495 return module;
496}
497
498/*
499 * Register a module that will have preferences.
500 * Specify the module under which to register it, the name used for the
501 * module in the preferences file, the title used in the tab for it
502 * in a preferences dialog box, and a routine to call back when the
503 * preferences are applied.
504 */
505module_t*
506prefs_register_module(wmem_tree_t* pref_tree, wmem_tree_t* master_pref_tree, const char* name, const char* title,
507 const char* description, const char* help, void (*apply_cb)(void),
508 const bool_Bool use_gui)
509{
510 module_t* module;
511
512 /* this module may have been created as a subtree item previously */
513 if ((module = (module_t*)wmem_tree_lookup_string(pref_tree, title, WMEM_TREE_STRING_NOCASE0x00000001))) {
514 /* the module is currently a subtree */
515 prefs_update_existing_subtree(module, name, description, help, apply_cb, master_pref_tree);
516 return module;
517 }
518
519 module = prefs_create_module(wmem_tree_get_data_scope(master_pref_tree), NULL((void*)0), name, title, description, help, apply_cb, use_gui);
520
521 /* Accept any letter case to conform with protocol names. ASN1 protocols
522 * don't use lower case names, so we can't require lower case.
523 */
524 if (module_check_valid_name(name, false0) != '\0') {
525 ws_error("Preference module \"%s\" contains invalid characters", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 525
, __func__, "Preference module \"%s\" contains invalid characters"
, name)
;
526 }
527
528 /*
529 * Make sure there's not already a module with that
530 * name. Crash if there is, as that's an error in the
531 * code, and the code has to be fixed not to register
532 * more than one module with the same name.
533 *
534 * We search the list of all modules; the subtree stuff
535 * doesn't require preferences in subtrees to have names
536 * that reflect the subtree they're in (that would require
537 * protocol preferences to have a bogus "protocol.", or
538 * something such as that, to be added to all their names).
539 */
540 if (wmem_tree_lookup_string(master_pref_tree, name, WMEM_TREE_STRING_NOCASE0x00000001) != NULL((void*)0))
541 ws_error("Preference module \"%s\" is being registered twice", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 541
, __func__, "Preference module \"%s\" is being registered twice"
, name)
;
542
543 /*
544 * Insert this module in the list of all modules.
545 */
546 wmem_tree_insert_string(master_pref_tree, name, module, WMEM_TREE_STRING_NOCASE0x00000001);
547
548 /*
549 * It goes at the top.
550 */
551 wmem_tree_insert_string(pref_tree, title, module, WMEM_TREE_STRING_NOCASE0x00000001);
552
553 return module;
554}
555
556static module_t*
557prefs_register_submodule(module_t* parent, wmem_tree_t* master_pref_tree, const char* name, const char* title,
558 const char* description, const char* help, void (*apply_cb)(void),
559 const bool_Bool use_gui)
560{
561 module_t* module;
562
563 /* this module may have been created as a subtree item previously */
564 if ((module = (module_t*)wmem_tree_lookup_string(parent->submodules, title, WMEM_TREE_STRING_NOCASE0x00000001))) {
565 /* the module is currently a subtree */
566 prefs_update_existing_subtree(module, name, description, help, apply_cb, master_pref_tree);
567 return module;
568 }
569
570 module = prefs_create_module(wmem_tree_get_data_scope(master_pref_tree), parent, name, title, description, help, apply_cb, use_gui);
571
572 /* Accept any letter case to conform with protocol names. ASN1 protocols
573 * don't use lower case names, so we can't require lower case. */
574 if (module_check_valid_name(name, false0) != '\0') {
575 ws_error("Preference module \"%s\" contains invalid characters", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 575
, __func__, "Preference module \"%s\" contains invalid characters"
, name)
;
576 }
577
578 /*
579 * Make sure there's not already a module with that
580 * name. Crash if there is, as that's an error in the
581 * code, and the code has to be fixed not to register
582 * more than one module with the same name.
583 *
584 * We search the list of all modules; the subtree stuff
585 * doesn't require preferences in subtrees to have names
586 * that reflect the subtree they're in (that would require
587 * protocol preferences to have a bogus "protocol.", or
588 * something such as that, to be added to all their names).
589 */
590 if (wmem_tree_lookup_string(master_pref_tree, name, WMEM_TREE_STRING_NOCASE0x00000001) != NULL((void*)0))
591 ws_error("Preference module \"%s\" is being registered twice", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 591
, __func__, "Preference module \"%s\" is being registered twice"
, name)
;
592
593 /*
594 * Insert this module in the list of all modules.
595 */
596 wmem_tree_insert_string(master_pref_tree, name, module, WMEM_TREE_STRING_NOCASE0x00000001);
597
598 /*
599 * It goes into the list for this module.
600 */
601
602 if (parent->submodules == NULL((void*)0))
603 parent->submodules = wmem_tree_new(parent->scope);
604
605 wmem_tree_insert_string(parent->submodules, title, module, WMEM_TREE_STRING_NOCASE0x00000001);
606
607 return module;
608}
609
610/*
611 * Register a subtree that will have modules under it.
612 * Specify the module under which to register it or NULL to register it
613 * at the top level and the title used in the tab for it in a preferences
614 * dialog box.
615 */
616static module_t*
617prefs_register_subtree(module_t* parent, wmem_tree_t* master_pref_tree, const char* title, const char* description,
618 void (*apply_cb)(void))
619{
620 module_t* module;
621
622 /* this module may have been created as a subtree item previously */
623 if ((module = (module_t*)wmem_tree_lookup_string(parent->submodules, title, WMEM_TREE_STRING_NOCASE0x00000001))) {
624 /* the module is currently a subtree */
625 prefs_update_existing_subtree(module, NULL((void*)0), description, NULL((void*)0), apply_cb, master_pref_tree);
626 return module;
627 }
628
629 module = prefs_create_module(wmem_tree_get_data_scope(master_pref_tree), parent, NULL((void*)0), title, description, NULL((void*)0), apply_cb, parent->use_gui);
630
631
632 /*
633 * It goes into the list for this module.
634 */
635 if (parent->submodules == NULL((void*)0))
636 parent->submodules = wmem_tree_new(parent->scope);
637
638 wmem_tree_insert_string(parent->submodules, title, module, WMEM_TREE_STRING_NOCASE0x00000001);
639
640 return module;
641}
642
643void
644prefs_register_module_alias(const char *name, module_t *module)
645{
646 module_alias_t *alias;
647
648 /*
649 * Accept any name that can occur in protocol names. We allow upper-case
650 * letters, to handle the Diameter dissector having used "Diameter" rather
651 * than "diameter" as its preference module name in the past.
652 *
653 * Crash if the name is invalid, as that's an error in the code, but the name
654 * can be used on the command line, and shouldn't require quoting, etc.
655 */
656 if (module_check_valid_name(name, false0) != '\0') {
657 ws_error("Preference module alias \"%s\" contains invalid characters", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 657
, __func__, "Preference module alias \"%s\" contains invalid characters"
, name)
;
658 }
659
660 /*
661 * Make sure there's not already an alias with that
662 * name. Crash if there is, as that's an error in the
663 * code, and the code has to be fixed not to register
664 * more than one alias with the same name.
665 *
666 * We search the list of all aliases.
667 */
668 if (prefs_find_module_alias(name) != NULL((void*)0))
669 ws_error("Preference module alias \"%s\" is being registered twice", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 669
, __func__, "Preference module alias \"%s\" is being registered twice"
, name)
;
670
671 alias = wmem_new(wmem_tree_get_data_scope(prefs_module_aliases), module_alias_t)((module_alias_t*)wmem_alloc((wmem_tree_get_data_scope(prefs_module_aliases
)), sizeof(module_alias_t)))
;
672 alias->name = name;
673 alias->module = module;
674
675 /*
676 * Insert this module in the list of all modules.
677 */
678 wmem_tree_insert_string(prefs_module_aliases, name, alias, WMEM_TREE_STRING_NOCASE0x00000001);
679}
680
681/*
682 * Register that a protocol has preferences.
683 */
684static module_t *protocols_module;
685
686module_t *
687prefs_register_protocol(int id, void (*apply_cb)(void))
688{
689 protocol_t *protocol = find_protocol_by_id(id);
690 if (protocol == NULL((void*)0))
691 ws_error("Protocol preferences being registered with an invalid protocol ID")ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 691
, __func__, "Protocol preferences being registered with an invalid protocol ID"
)
;
692 return prefs_register_submodule(protocols_module, prefs_modules,
693 proto_get_protocol_filter_name(id),
694 proto_get_protocol_short_name(protocol),
695 proto_get_protocol_name(id), NULL((void*)0), apply_cb, true1);
696}
697
698void
699prefs_deregister_protocol (int id)
700{
701 protocol_t *protocol = find_protocol_by_id(id);
702 if (protocol == NULL((void*)0))
703 ws_error("Protocol preferences being de-registered with an invalid protocol ID")ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 703
, __func__, "Protocol preferences being de-registered with an invalid protocol ID"
)
;
704 prefs_deregister_module (protocols_module->submodules,
705 proto_get_protocol_filter_name(id),
706 proto_get_protocol_short_name(protocol),
707 prefs_modules);
708}
709
710module_t *
711prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void))
712{
713 protocol_t *protocol;
714 module_t *subtree_module;
715 module_t *new_module;
716 char *sep = NULL((void*)0), *ptr = NULL((void*)0), *orig = NULL((void*)0);
717
718 subtree_module = protocols_module;
719
720 if (subtree) {
721 /* take a copy of the buffer, orig keeps a base pointer while ptr
722 * walks through the string */
723 orig = ptr = wmem_strdup(subtree_module->scope, subtree);
724
725 while (ptr && *ptr) {
726
727 if ((sep = strchr(ptr, '/')))
728 *sep++ = '\0';
729
730 if (!(new_module = (module_t*)wmem_tree_lookup_string(subtree_module->submodules, ptr, WMEM_TREE_STRING_NOCASE0x00000001))) {
731 /*
732 * There's no such module; create it, with the description
733 * being the name (if it's later registered explicitly
734 * with a description, that will override it).
735 */
736 ptr = wmem_strdup(wmem_tree_get_data_scope(prefs_modules), ptr);
737 new_module = prefs_register_subtree(subtree_module, prefs_modules, ptr, ptr, NULL((void*)0));
738 }
739
740 subtree_module = new_module;
741 ptr = sep;
742
743 }
744
745 wmem_free(subtree_module->scope, orig);
746 }
747
748 protocol = find_protocol_by_id(id);
749 if (protocol == NULL((void*)0))
750 ws_error("Protocol subtree being registered with an invalid protocol ID")ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 750
, __func__, "Protocol subtree being registered with an invalid protocol ID"
)
;
751 return prefs_register_submodule(subtree_module, prefs_modules,
752 proto_get_protocol_filter_name(id),
753 proto_get_protocol_short_name(protocol),
754 proto_get_protocol_name(id), NULL((void*)0), apply_cb, true1);
755}
756
757
758/*
759 * Register that a protocol used to have preferences but no longer does,
760 * by creating an "obsolete" module for it.
761 */
762module_t *
763prefs_register_protocol_obsolete(int id)
764{
765 module_t *module;
766 protocol_t *protocol = find_protocol_by_id(id);
767 if (protocol == NULL((void*)0))
768 ws_error("Protocol being registered with an invalid protocol ID")ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 768
, __func__, "Protocol being registered with an invalid protocol ID"
)
;
769 module = prefs_register_submodule(protocols_module, prefs_modules,
770 proto_get_protocol_filter_name(id),
771 proto_get_protocol_short_name(protocol),
772 proto_get_protocol_name(id), NULL((void*)0), NULL((void*)0), true1);
773 module->obsolete = true1;
774 return module;
775}
776
777/*
778 * Register that a statistical tap has preferences.
779 *
780 * "name" is a name for the tap to use on the command line with "-o"
781 * and in preference files.
782 *
783 * "title" is a short human-readable name for the tap.
784 *
785 * "description" is a longer human-readable description of the tap.
786 */
787module_t *stats_module;
788
789module_t *
790prefs_register_stat(const char *name, const char *title,
791 const char *description, void (*apply_cb)(void))
792{
793 return prefs_register_submodule(stats_module, prefs_modules, name, title, description, NULL((void*)0),
794 apply_cb, true1);
795}
796
797/*
798 * Register that a codec has preferences.
799 *
800 * "name" is a name for the codec to use on the command line with "-o"
801 * and in preference files.
802 *
803 * "title" is a short human-readable name for the codec.
804 *
805 * "description" is a longer human-readable description of the codec.
806 */
807module_t *codecs_module;
808
809module_t *
810prefs_register_codec(const char *name, const char *title,
811 const char *description, void (*apply_cb)(void))
812{
813 return prefs_register_submodule(codecs_module, prefs_modules, name, title, description, NULL((void*)0),
814 apply_cb, true1);
815}
816
817module_t *
818prefs_find_module(const char *name)
819{
820 return (module_t *)wmem_tree_lookup_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE0x00000001);
821}
822
823/*
824 * Call a callback function, with a specified argument, for each module
825 * in a list of modules. If the list is NULL, searches the top-level
826 * list in the display tree of modules. If any callback returns a
827 * non-zero value, we stop and return that value, otherwise we
828 * return 0.
829 *
830 * Normally "obsolete" modules are ignored; their sole purpose is to allow old
831 * preferences for dissectors that no longer have preferences to be
832 * silently ignored in preference files. Does not ignore subtrees,
833 * as this can be used when walking the display tree of modules.
834 */
835
836typedef struct {
837 module_cb callback;
838 void *user_data;
839 unsigned ret;
840 bool_Bool skip_obsolete;
841} call_foreach_t;
842
843static bool_Bool
844call_foreach_cb(const void *key _U___attribute__((unused)), void *value, void *data)
845{
846 module_t *module = (module_t*)value;
847 call_foreach_t *call_data = (call_foreach_t*)data;
848
849 if (!call_data->skip_obsolete || !module->obsolete)
850 call_data->ret = (*call_data->callback)(module, call_data->user_data);
851
852 return (call_data->ret != 0);
853}
854
855unsigned
856prefs_module_list_foreach(const wmem_tree_t *module_list, module_cb callback,
857 void *user_data, bool_Bool skip_obsolete)
858{
859 call_foreach_t call_data;
860
861 call_data.callback = callback;
862 call_data.user_data = user_data;
863 call_data.ret = 0;
864 call_data.skip_obsolete = skip_obsolete;
865 wmem_tree_foreach(module_list, call_foreach_cb, &call_data);
866 return call_data.ret;
867}
868
869/*
870 * Returns true if module has any submodules
871 */
872bool_Bool
873prefs_module_has_submodules(module_t *module)
874{
875 if (module->submodules == NULL((void*)0)) {
876 return false0;
877 }
878
879 if (wmem_tree_is_empty(module->submodules)) {
880 return false0;
881 }
882
883 return true1;
884}
885
886/*
887 * Call a callback function, with a specified argument, for each module
888 * in the list of all modules. (This list does not include subtrees.)
889 *
890 * Ignores "obsolete" modules; their sole purpose is to allow old
891 * preferences for dissectors that no longer have preferences to be
892 * silently ignored in preference files.
893 */
894unsigned
895prefs_modules_foreach(const wmem_tree_t* module, module_cb callback, void *user_data)
896{
897 return prefs_module_list_foreach(module, callback, user_data, true1);
898}
899
900/*
901 * Call a callback function, with a specified argument, for each submodule
902 * of specified modules. If the module is NULL, goes through the top-level
903 * list in the display tree of modules.
904 *
905 * Ignores "obsolete" modules; their sole purpose is to allow old
906 * preferences for dissectors that no longer have preferences to be
907 * silently ignored in preference files. Does not ignore subtrees,
908 * as this can be used when walking the display tree of modules.
909 */
910unsigned
911prefs_modules_foreach_submodules(const wmem_tree_t* module, module_cb callback,
912 void *user_data)
913{
914 return prefs_module_list_foreach(module, callback, user_data, true1);
915}
916
917unsigned prefs_modules_for_all_modules(module_cb callback, void* user_data)
918{
919 return prefs_module_list_foreach(prefs_top_level_modules, callback, user_data, true1);
920}
921
922static bool_Bool
923call_apply_cb(const void *key _U___attribute__((unused)), void *value, void *data _U___attribute__((unused)))
924{
925 module_t *module = (module_t *)value;
926
927 if (module->obsolete)
928 return false0;
929 if (module->prefs_changed_flags) {
930 if (module->apply_cb != NULL((void*)0))
931 (*module->apply_cb)();
932 module->prefs_changed_flags = 0;
933 }
934 if (module->submodules)
935 wmem_tree_foreach(module->submodules, call_apply_cb, NULL((void*)0));
936 return false0;
937}
938
939/*
940 * Call the "apply" callback function for each module if any of its
941 * preferences have changed, and then clear the flag saying its
942 * preferences have changed, as the module has been notified of that
943 * fact.
944 */
945void
946prefs_apply_all(void)
947{
948 wmem_tree_foreach(prefs_modules, call_apply_cb, NULL((void*)0));
949}
950
951/*
952 * Call the "apply" callback function for a specific module if any of
953 * its preferences have changed, and then clear the flag saying its
954 * preferences have changed, as the module has been notified of that
955 * fact.
956 */
957void
958prefs_apply(module_t *module)
959{
960 if (module && module->prefs_changed_flags)
961 call_apply_cb(NULL((void*)0), module, NULL((void*)0));
962}
963
964static module_t *
965prefs_find_module_alias(const char *name)
966{
967 module_alias_t *alias;
968
969 alias = (module_alias_t *)wmem_tree_lookup_string(prefs_module_aliases, name, WMEM_TREE_STRING_NOCASE0x00000001);
970 if (alias == NULL((void*)0))
971 return NULL((void*)0);
972 return alias->module;
973}
974
975/*
976 * Register a preference in a module's list of preferences.
977 * If it has a title, give it an ordinal number; otherwise, it's a
978 * preference that won't show up in the UI, so it shouldn't get an
979 * ordinal number (the ordinal should be the ordinal in the set of
980 * *visible* preferences).
981 */
982static pref_t *
983register_preference(module_t *module, const char *name, const char *title,
984 const char *description, pref_type_e type, bool_Bool obsolete)
985{
986 pref_t *preference;
987 const char *p;
988 const char *name_prefix = (module->name != NULL((void*)0)) ? module->name : module->parent->name;
989
990 preference = wmem_new(module->scope, pref_t)((pref_t*)wmem_alloc((module->scope), sizeof(pref_t)));
991 preference->name = name;
992 preference->title = title;
993 preference->scope = module->scope;
994 preference->description = description;
995 preference->type = type;
996 preference->obsolete = obsolete;
997 /* Default to module's preference effects */
998 preference->effect_flags = module->effect_flags;
999
1000 if (title != NULL((void*)0))
1001 preference->ordinal = module->numprefs;
1002 else
1003 preference->ordinal = -1; /* no ordinal for you */
1004
1005 /*
1006 * Make sure that only lower-case ASCII letters, numbers,
1007 * underscores, and dots appear in the preference name.
1008 *
1009 * Crash if there is, as that's an error in the code;
1010 * you can make the title and description nice strings
1011 * with capitalization, white space, punctuation, etc.,
1012 * but the name can be used on the command line,
1013 * and shouldn't require quoting, shifting, etc.
1014 */
1015 for (p = name; *p != '\0'; p++)
1016 if (!(g_ascii_islower(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_LOWER) != 0) || g_ascii_isdigit(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_DIGIT) != 0) || *p == '_' || *p == '.'))
1017 ws_error("Preference \"%s.%s\" contains invalid characters", module->name, name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1017
, __func__, "Preference \"%s.%s\" contains invalid characters"
, module->name, name)
;
1018
1019 /*
1020 * Make sure there's not already a preference with that
1021 * name. Crash if there is, as that's an error in the
1022 * code, and the code has to be fixed not to register
1023 * more than one preference with the same name.
1024 */
1025 if (prefs_find_preference(module, name) != NULL((void*)0))
1026 ws_error("Preference %s has already been registered", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1026
, __func__, "Preference %s has already been registered", name
)
;
1027
1028 if ((!preference->obsolete) &&
1029 /* Don't compare if it's a subtree */
1030 (module->name != NULL((void*)0))) {
1031 /*
1032 * Make sure the preference name doesn't begin with the
1033 * module name, as that's redundant and Just Silly.
1034 */
1035 if (!((strncmp(name, module->name, strlen(module->name)) != 0) ||
1036 (((name[strlen(module->name)]) != '.') && ((name[strlen(module->name)]) != '_'))))
1037 ws_error("Preference %s begins with the module name", name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1037
, __func__, "Preference %s begins with the module name", name
)
;
1038 }
1039
1040 /* The title shows up in the preferences dialog. Make sure it's UI-friendly. */
1041 if (preference->title) {
1042 const char *cur_char;
1043 if (preference->type != PREF_STATIC_TEXT && g_utf8_strlen(preference->title, -1) > 80) { // Arbitrary.
1044 ws_error("Title for preference %s.%s is too long: %s", name_prefix, preference->name, preference->title)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1044
, __func__, "Title for preference %s.%s is too long: %s", name_prefix
, preference->name, preference->title)
;
1045 }
1046
1047 if (!g_utf8_validate(preference->title, -1, NULL((void*)0))) {
1048 ws_error("Title for preference %s.%s isn't valid UTF-8.", name_prefix, preference->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1048
, __func__, "Title for preference %s.%s isn't valid UTF-8.", name_prefix
, preference->name)
;
1049 }
1050
1051 for (cur_char = preference->title; *cur_char; cur_char = g_utf8_next_char(cur_char)(char *)((cur_char) + g_utf8_skip[*(const guchar *)(cur_char)
])
) {
1052 if (!g_unichar_isprint(g_utf8_get_char(cur_char))) {
1053 ws_error("Title for preference %s.%s isn't printable UTF-8.", name_prefix, preference->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1053
, __func__, "Title for preference %s.%s isn't printable UTF-8."
, name_prefix, preference->name)
;
1054 }
1055 }
1056 }
1057
1058 if (preference->description) {
1059 if (!g_utf8_validate(preference->description, -1, NULL((void*)0))) {
1060 ws_error("Description for preference %s.%s isn't valid UTF-8.", name_prefix, preference->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1060
, __func__, "Description for preference %s.%s isn't valid UTF-8."
, name_prefix, preference->name)
;
1061 }
1062 }
1063
1064 /*
1065 * We passed all of our checks. Add the preference.
1066 */
1067 module->prefs = g_list_append(module->prefs, preference);
1068 if (title != NULL((void*)0))
1069 module->numprefs++;
1070
1071 return preference;
1072}
1073
1074/*
1075 * Find a preference in a module's list of preferences, given the module
1076 * and the preference's name.
1077 */
1078typedef struct {
1079 GList *list_entry;
1080 const char *name;
1081 module_t *submodule;
1082} find_pref_arg_t;
1083
1084static int
1085preference_match(const void *a, const void *b)
1086{
1087 const pref_t *pref = (const pref_t *)a;
1088 const char *name = (const char *)b;
1089
1090 return strcmp(name, pref->name);
1091}
1092
1093static bool_Bool
1094module_find_pref_cb(const void *key _U___attribute__((unused)), void *value, void *data)
1095{
1096 find_pref_arg_t* arg = (find_pref_arg_t*)data;
1097 GList *list_entry;
1098 module_t *module = (module_t *)value;
1099
1100 if (module == NULL((void*)0))
1101 return false0;
1102
1103 list_entry = g_list_find_custom(module->prefs, arg->name,
1104 preference_match);
1105
1106 if (list_entry == NULL((void*)0))
1107 return false0;
1108
1109 arg->list_entry = list_entry;
1110 arg->submodule = module;
1111 return true1;
1112}
1113
1114/* Tries to find a preference, setting containing_module to the (sub)module
1115 * holding this preference. */
1116static pref_t *
1117prefs_find_preference_with_submodule(module_t *module, const char *name,
1118 module_t **containing_module)
1119{
1120 find_pref_arg_t arg;
1121 GList *list_entry;
1122
1123 if (module == NULL((void*)0))
1124 return NULL((void*)0); /* invalid parameters */
1125
1126 list_entry = g_list_find_custom(module->prefs, name,
1127 preference_match);
1128 arg.submodule = NULL((void*)0);
1129
1130 if (list_entry == NULL((void*)0))
1131 {
1132 arg.list_entry = NULL((void*)0);
1133 if (module->submodules != NULL((void*)0))
1134 {
1135 arg.name = name;
1136 wmem_tree_foreach(module->submodules, module_find_pref_cb, &arg);
1137 }
1138
1139 list_entry = arg.list_entry;
1140 }
1141
1142 if (list_entry == NULL((void*)0))
1143 return NULL((void*)0); /* no such preference */
1144
1145 if (containing_module)
1146 *containing_module = arg.submodule ? arg.submodule : module;
1147
1148 return (pref_t *) list_entry->data;
1149}
1150
1151pref_t *
1152prefs_find_preference(module_t *module, const char *name)
1153{
1154 return prefs_find_preference_with_submodule(module, name, NULL((void*)0));
1155}
1156
1157/*
1158 * Returns true if the given protocol has registered preferences
1159 */
1160bool_Bool
1161prefs_is_registered_protocol(const char *name)
1162{
1163 module_t *m = prefs_find_module(name);
1164
1165 return (m != NULL((void*)0) && !m->obsolete);
1166}
1167
1168/*
1169 * Returns the module title of a registered protocol
1170 */
1171const char *
1172prefs_get_title_by_name(const char *name)
1173{
1174 module_t *m = prefs_find_module(name);
1175
1176 return (m != NULL((void*)0) && !m->obsolete) ? m->title : NULL((void*)0);
1177}
1178
1179/*
1180 * Register a preference with an unsigned integral value.
1181 */
1182void
1183prefs_register_uint_preference(module_t *module, const char *name,
1184 const char *title, const char *description,
1185 unsigned base, unsigned *var)
1186{
1187 pref_t *preference;
1188
1189 preference = register_preference(module, name, title, description,
1190 PREF_UINT, false0);
1191 preference->varp.uint = var;
1192 preference->default_val.uint = *var;
1193 ws_assert(base > 0 && base != 1 && base < 37)do { if ((1) && !(base > 0 && base != 1 &&
base < 37)) ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c"
, 1193, __func__, "assertion failed: %s", "base > 0 && base != 1 && base < 37"
); } while (0)
;
1194 preference->info.base = base;
1195}
1196
1197/*
1198 * XXX Add a prefs_register_{uint16|port}_preference which sets max_value?
1199 */
1200
1201
1202/*
1203 * Register a preference with an integer value.
1204 */
1205void
1206prefs_register_int_preference(module_t* module, const char* name,
1207 const char* title, const char* description, int* var)
1208{
1209 pref_t* preference;
1210
1211 preference = register_preference(module, name, title, description,
1212 PREF_INT, false0);
1213 preference->varp.intp = var;
1214 preference->default_val.intval = *var;
1215}
1216
1217/*
1218 * Register a preference with a float (doube) value.
1219 */
1220void prefs_register_float_preference(module_t* module, const char* name,
1221 const char* title, const char* description, unsigned num_decimal, double* var)
1222{
1223 pref_t* preference;
1224
1225 preference = register_preference(module, name, title, description,
1226 PREF_FLOAT, false0);
1227 preference->varp.floatp = var;
1228 preference->default_val.floatval = *var;
1229 ws_assert(num_decimal <= 10)do { if ((1) && !(num_decimal <= 10)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1229, __func__, "assertion failed: %s"
, "num_decimal <= 10"); } while (0)
;
1230 preference->info.base = num_decimal;
1231}
1232
1233/*
1234 * Register a "custom" preference with a unsigned integral value.
1235 * XXX - This should be temporary until we can find a better way
1236 * to do "custom" preferences
1237 */
1238static void
1239prefs_register_uint_custom_preference(module_t *module, const char *name,
1240 const char *title, const char *description,
1241 struct pref_custom_cbs* custom_cbs, unsigned *var)
1242{
1243 pref_t *preference;
1244
1245 preference = register_preference(module, name, title, description,
1246 PREF_CUSTOM, false0);
1247
1248 preference->custom_cbs = *custom_cbs;
1249 preference->varp.uint = var;
1250 preference->default_val.uint = *var;
1251}
1252
1253/*
1254 * Register a preference with an Boolean value.
1255 */
1256void
1257prefs_register_bool_preference(module_t *module, const char *name,
1258 const char *title, const char *description,
1259 bool_Bool *var)
1260{
1261 pref_t *preference;
1262
1263 preference = register_preference(module, name, title, description,
1264 PREF_BOOL, false0);
1265 preference->varp.boolp = var;
1266 preference->default_val.boolval = *var;
1267}
1268
1269unsigned int prefs_set_bool_value(pref_t *pref, bool_Bool value, pref_source_t source)
1270{
1271 unsigned int changed = 0;
1272
1273 switch (source)
1274 {
1275 case pref_default:
1276 if (pref->default_val.boolval != value) {
1277 pref->default_val.boolval = value;
1278 changed = prefs_get_effect_flags(pref);
1279 }
1280 break;
1281 case pref_stashed:
1282 if (pref->stashed_val.boolval != value) {
1283 pref->stashed_val.boolval = value;
1284 changed = prefs_get_effect_flags(pref);
1285 }
1286 break;
1287 case pref_current:
1288 if (*pref->varp.boolp != value) {
1289 *pref->varp.boolp = value;
1290 changed = prefs_get_effect_flags(pref);
1291 }
1292 break;
1293 default:
1294 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1294
, __func__, "assertion \"not reached\" failed")
;
1295 break;
1296 }
1297
1298 return changed;
1299}
1300
1301void prefs_invert_bool_value(pref_t *pref, pref_source_t source)
1302{
1303 switch (source)
1304 {
1305 case pref_default:
1306 pref->default_val.boolval = !pref->default_val.boolval;
1307 break;
1308 case pref_stashed:
1309 pref->stashed_val.boolval = !pref->stashed_val.boolval;
1310 break;
1311 case pref_current:
1312 *pref->varp.boolp = !(*pref->varp.boolp);
1313 break;
1314 default:
1315 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1315
, __func__, "assertion \"not reached\" failed")
;
1316 break;
1317 }
1318}
1319
1320bool_Bool prefs_get_bool_value(pref_t *pref, pref_source_t source)
1321{
1322 switch (source)
1323 {
1324 case pref_default:
1325 return pref->default_val.boolval;
1326 case pref_stashed:
1327 return pref->stashed_val.boolval;
1328 case pref_current:
1329 return *pref->varp.boolp;
1330 default:
1331 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1331
, __func__, "assertion \"not reached\" failed")
;
1332 break;
1333 }
1334
1335 return false0;
1336}
1337
1338/*
1339 * Register a preference with an enumerated value.
1340 */
1341/*
1342 * XXX Should we get rid of the radio_buttons parameter and make that
1343 * behavior automatic depending on the number of items?
1344 */
1345void
1346prefs_register_enum_preference(module_t *module, const char *name,
1347 const char *title, const char *description,
1348 int *var, const enum_val_t *enumvals,
1349 bool_Bool radio_buttons)
1350{
1351 pref_t *preference;
1352
1353 /* Validate that the "name one would use on the command line for the value"
1354 * doesn't require quoting, etc. It's all treated case-insensitively so we
1355 * don't care about upper vs lower case.
1356 */
1357 for (size_t i = 0; enumvals[i].name != NULL((void*)0); i++) {
1358 for (const char *p = enumvals[i].name; *p != '\0'; p++)
1359 if (!(g_ascii_isalnum(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_ALNUM) != 0) || *p == '_' || *p == '.' || *p == '-'))
1360 ws_error("Preference \"%s.%s\" enum value name \"%s\" contains invalid characters",ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1361
, __func__, "Preference \"%s.%s\" enum value name \"%s\" contains invalid characters"
, module->name, name, enumvals[i].name)
1361 module->name, name, enumvals[i].name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1361
, __func__, "Preference \"%s.%s\" enum value name \"%s\" contains invalid characters"
, module->name, name, enumvals[i].name)
;
1362 }
1363
1364
1365 preference = register_preference(module, name, title, description,
1366 PREF_ENUM, false0);
1367 preference->varp.enump = var;
1368 preference->default_val.enumval = *var;
1369 preference->info.enum_info.enumvals = enumvals;
1370 preference->info.enum_info.radio_buttons = radio_buttons;
1371}
1372
1373unsigned int prefs_set_enum_value(pref_t *pref, int value, pref_source_t source)
1374{
1375 unsigned int changed = 0;
1376
1377 switch (source)
1378 {
1379 case pref_default:
1380 if (pref->default_val.enumval != value) {
1381 pref->default_val.enumval = value;
1382 changed = prefs_get_effect_flags(pref);
1383 }
1384 break;
1385 case pref_stashed:
1386 if (pref->stashed_val.enumval != value) {
1387 pref->stashed_val.enumval = value;
1388 changed = prefs_get_effect_flags(pref);
1389 }
1390 break;
1391 case pref_current:
1392 if (*pref->varp.enump != value) {
1393 *pref->varp.enump = value;
1394 changed = prefs_get_effect_flags(pref);
1395 }
1396 break;
1397 default:
1398 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1398
, __func__, "assertion \"not reached\" failed")
;
1399 break;
1400 }
1401
1402 return changed;
1403}
1404
1405unsigned int prefs_set_enum_string_value(pref_t *pref, const char *value, pref_source_t source)
1406{
1407 int enum_val = find_val_for_string(value, pref->info.enum_info.enumvals, *pref->varp.enump);
1408
1409 return prefs_set_enum_value(pref, enum_val, source);
1410}
1411
1412int prefs_get_enum_value(pref_t *pref, pref_source_t source)
1413{
1414 switch (source)
1415 {
1416 case pref_default:
1417 return pref->default_val.enumval;
1418 case pref_stashed:
1419 return pref->stashed_val.enumval;
1420 case pref_current:
1421 return *pref->varp.enump;
1422 default:
1423 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1423
, __func__, "assertion \"not reached\" failed")
;
1424 break;
1425 }
1426
1427 return 0;
1428}
1429
1430const enum_val_t* prefs_get_enumvals(pref_t *pref)
1431{
1432 return pref->info.enum_info.enumvals;
1433}
1434
1435bool_Bool prefs_get_enum_radiobuttons(pref_t *pref)
1436{
1437 return pref->info.enum_info.radio_buttons;
1438}
1439
1440/*
1441 * For use by UI code that sets preferences.
1442 */
1443unsigned int
1444prefs_set_custom_value(pref_t *pref, const char *value, pref_source_t source _U___attribute__((unused)))
1445{
1446 /* XXX - support pref source for custom preferences */
1447 unsigned int changed = 0;
1448 pref->custom_cbs.set_cb(pref, value, &changed);
1449 return changed;
1450}
1451
1452static void
1453register_string_like_preference(module_t *module, const char *name,
1454 const char *title, const char *description,
1455 char **var, pref_type_e type,
1456 struct pref_custom_cbs* custom_cbs,
1457 bool_Bool free_tmp)
1458{
1459 pref_t *pref;
1460 char *tmp;
1461
1462 pref = register_preference(module, name, title, description, type, false0);
1463
1464 /*
1465 * String preference values should be non-null (as you can't
1466 * keep them null after using the preferences GUI, you can at best
1467 * have them be null strings) and freeable (as we free them
1468 * if we change them).
1469 *
1470 * If the value is a null pointer, make it a copy of a null
1471 * string, otherwise make it a copy of the value.
1472 */
1473 tmp = *var;
1474 if (*var == NULL((void*)0)) {
1475 *var = wmem_strdup(pref->scope, "");
1476 } else {
1477 *var = wmem_strdup(pref->scope, *var);
1478 }
1479 if (free_tmp) {
1480 wmem_free(pref->scope, tmp);
1481 }
1482 pref->varp.string = var;
1483 pref->default_val.string = wmem_strdup(pref->scope, *var);
1484 pref->stashed_val.string = NULL((void*)0);
1485 if (type == PREF_CUSTOM) {
1486 ws_assert(custom_cbs)do { if ((1) && !(custom_cbs)) ws_log_fatal_full("Epan"
, LOG_LEVEL_ERROR, "epan/prefs.c", 1486, __func__, "assertion failed: %s"
, "custom_cbs"); } while (0)
;
1487 pref->custom_cbs = *custom_cbs;
1488 }
1489}
1490
1491/*
1492 * Assign to a string preference.
1493 */
1494static void
1495pref_set_string_like_pref_value(pref_t *pref, const char *value)
1496{
1497 wmem_free(pref->scope, *pref->varp.string);
1498 *pref->varp.string = wmem_strdup(pref->scope, value);
1499}
1500
1501/*
1502 * For use by UI code that sets preferences.
1503 */
1504unsigned int
1505prefs_set_string_value(pref_t *pref, const char* value, pref_source_t source)
1506{
1507 unsigned int changed = 0;
1508
1509 switch (source)
1510 {
1511 case pref_default:
1512 if (*pref->default_val.string) {
1513 if (strcmp(pref->default_val.string, value) != 0) {
1514 changed = prefs_get_effect_flags(pref);
1515 wmem_free(pref->scope, pref->default_val.string);
1516 pref->default_val.string = wmem_strdup(pref->scope, value);
1517 }
1518 } else if (value) {
1519 pref->default_val.string = wmem_strdup(pref->scope, value);
1520 }
1521 break;
1522 case pref_stashed:
1523 if (pref->stashed_val.string) {
1524 if (strcmp(pref->stashed_val.string, value) != 0) {
1525 changed = prefs_get_effect_flags(pref);
1526 wmem_free(pref->scope, pref->stashed_val.string);
1527 pref->stashed_val.string = wmem_strdup(pref->scope, value);
1528 }
1529 } else if (value) {
1530 pref->stashed_val.string = wmem_strdup(pref->scope, value);
1531 }
1532 break;
1533 case pref_current:
1534 if (*pref->varp.string) {
1535 if (strcmp(*pref->varp.string, value) != 0) {
1536 changed = prefs_get_effect_flags(pref);
1537 pref_set_string_like_pref_value(pref, value);
1538 }
1539 } else if (value) {
1540 pref_set_string_like_pref_value(pref, value);
1541 }
1542 break;
1543 default:
1544 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1544
, __func__, "assertion \"not reached\" failed")
;
1545 break;
1546 }
1547
1548 return changed;
1549}
1550
1551const char *prefs_get_string_value(pref_t *pref, pref_source_t source)
1552{
1553 switch (source)
1554 {
1555 case pref_default:
1556 return pref->default_val.string;
1557 case pref_stashed:
1558 return pref->stashed_val.string;
1559 case pref_current:
1560 return *pref->varp.string;
1561 default:
1562 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1562
, __func__, "assertion \"not reached\" failed")
;
1563 break;
1564 }
1565
1566 return NULL((void*)0);
1567}
1568
1569/*
1570 * Reset the value of a string-like preference.
1571 */
1572static void
1573reset_string_like_preference(pref_t *pref)
1574{
1575 wmem_free(pref->scope, *pref->varp.string);
1576 *pref->varp.string = wmem_strdup(pref->scope, pref->default_val.string);
1577}
1578
1579/*
1580 * Register a preference with a character-string value.
1581 */
1582void
1583prefs_register_string_preference(module_t *module, const char *name,
1584 const char *title, const char *description,
1585 const char **var)
1586{
1587DIAG_OFF(cast-qual)clang diagnostic push clang diagnostic ignored "-Wcast-qual"
1588 register_string_like_preference(module, name, title, description,
1589 (char **)var, PREF_STRING, NULL((void*)0), false0);
1590DIAG_ON(cast-qual)clang diagnostic pop
1591}
1592
1593/*
1594 * Register a preference with a file name (string) value.
1595 */
1596void
1597prefs_register_filename_preference(module_t *module, const char *name,
1598 const char *title, const char *description,
1599 const char **var, bool_Bool for_writing)
1600{
1601DIAG_OFF(cast-qual)clang diagnostic push clang diagnostic ignored "-Wcast-qual"
1602 register_string_like_preference(module, name, title, description, (char **)var,
1603 for_writing ? PREF_SAVE_FILENAME : PREF_OPEN_FILENAME, NULL((void*)0), false0);
1604DIAG_ON(cast-qual)clang diagnostic pop
1605}
1606
1607/*
1608 * Register a preference with a directory name (string) value.
1609 */
1610void
1611prefs_register_directory_preference(module_t *module, const char *name,
1612 const char *title, const char *description,
1613 const char **var)
1614{
1615DIAG_OFF(cast-qual)clang diagnostic push clang diagnostic ignored "-Wcast-qual"
1616 register_string_like_preference(module, name, title, description,
1617 (char **)var, PREF_DIRNAME, NULL((void*)0), false0);
1618DIAG_ON(cast-qual)clang diagnostic pop
1619}
1620
1621/* Refactoring to handle both PREF_RANGE and PREF_DECODE_AS_RANGE */
1622static pref_t*
1623prefs_register_range_preference_common(module_t *module, const char *name,
1624 const char *title, const char *description,
1625 range_t **var, uint32_t max_value, pref_type_e type)
1626{
1627 pref_t *preference;
1628
1629 preference = register_preference(module, name, title, description, type, false0);
1630 preference->info.max_value = max_value;
1631
1632 /*
1633 * Range preference values should be non-null (as you can't
1634 * keep them null after using the preferences GUI, you can at best
1635 * have them be empty ranges) and freeable (as we free them
1636 * if we change them).
1637 *
1638 * If the value is a null pointer, make it an empty range.
1639 */
1640 if (*var == NULL((void*)0))
1641 *var = range_empty(preference->scope);
1642 preference->varp.range = var;
1643 preference->default_val.range = range_copy(preference->scope, *var);
1644 preference->stashed_val.range = NULL((void*)0);
1645
1646 return preference;
1647}
1648
1649/*
1650 * Register a preference with a ranged value.
1651 */
1652void
1653prefs_register_range_preference(module_t *module, const char *name,
1654 const char *title, const char *description,
1655 range_t **var, uint32_t max_value)
1656{
1657 prefs_register_range_preference_common(module, name, title,
1658 description, var, max_value, PREF_RANGE);
1659}
1660
1661bool_Bool
1662prefs_set_range_value_work(pref_t *pref, const char *value,
1663 bool_Bool return_range_errors, unsigned int *changed_flags)
1664{
1665 range_t *newrange;
1666
1667 if (range_convert_str_work(pref->scope, &newrange, value, pref->info.max_value,
1668 return_range_errors) != CVT_NO_ERROR) {
1669 return false0; /* number was bad */
1670 }
1671
1672 if (!ranges_are_equal(*pref->varp.range, newrange)) {
1673 *changed_flags |= prefs_get_effect_flags(pref);
1674 wmem_free(pref->scope, *pref->varp.range);
1675 *pref->varp.range = newrange;
1676 } else {
1677 wmem_free(pref->scope, newrange);
1678 }
1679 return true1;
1680}
1681
1682/*
1683 * For use by UI code that sets preferences.
1684 */
1685unsigned int
1686prefs_set_stashed_range_value(pref_t *pref, const char *value)
1687{
1688 range_t *newrange;
1689
1690 if (range_convert_str_work(pref->scope, &newrange, value, pref->info.max_value,
1691 true1) != CVT_NO_ERROR) {
1692 return 0; /* number was bad */
1693 }
1694
1695 if (!ranges_are_equal(pref->stashed_val.range, newrange)) {
1696 wmem_free(pref->scope, pref->stashed_val.range);
1697 pref->stashed_val.range = newrange;
1698 } else {
1699 wmem_free(pref->scope, newrange);
1700 }
1701 return prefs_get_effect_flags(pref);
1702
1703}
1704
1705bool_Bool prefs_add_list_value(pref_t *pref, void* value, pref_source_t source)
1706{
1707 switch (source)
1708 {
1709 case pref_default:
1710 pref->default_val.list = g_list_prepend(pref->default_val.list, value);
1711 break;
1712 case pref_stashed:
1713 pref->stashed_val.list = g_list_prepend(pref->stashed_val.list, value);
1714 break;
1715 case pref_current:
1716 *pref->varp.list = g_list_prepend(*pref->varp.list, value);
1717 break;
1718 default:
1719 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1719
, __func__, "assertion \"not reached\" failed")
;
1720 break;
1721 }
1722
1723 return true1;
1724}
1725
1726GList* prefs_get_list_value(pref_t *pref, pref_source_t source)
1727{
1728 switch (source)
1729 {
1730 case pref_default:
1731 return pref->default_val.list;
1732 case pref_stashed:
1733 return pref->stashed_val.list;
1734 case pref_current:
1735 return *pref->varp.list;
1736 default:
1737 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1737
, __func__, "assertion \"not reached\" failed")
;
1738 break;
1739 }
1740
1741 return NULL((void*)0);
1742}
1743
1744bool_Bool prefs_set_range_value(pref_t *pref, range_t *value, pref_source_t source)
1745{
1746 bool_Bool changed = false0;
1747
1748 switch (source)
1749 {
1750 case pref_default:
1751 if (!ranges_are_equal(pref->default_val.range, value)) {
1752 wmem_free(pref->scope, pref->default_val.range);
1753 pref->default_val.range = range_copy(pref->scope, value);
1754 changed = true1;
1755 }
1756 break;
1757 case pref_stashed:
1758 if (!ranges_are_equal(pref->stashed_val.range, value)) {
1759 wmem_free(pref->scope, pref->stashed_val.range);
1760 pref->stashed_val.range = range_copy(pref->scope, value);
1761 changed = true1;
1762 }
1763 break;
1764 case pref_current:
1765 if (!ranges_are_equal(*pref->varp.range, value)) {
1766 wmem_free(pref->scope, *pref->varp.range);
1767 *pref->varp.range = range_copy(pref->scope, value);
1768 changed = true1;
1769 }
1770 break;
1771 default:
1772 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1772
, __func__, "assertion \"not reached\" failed")
;
1773 break;
1774 }
1775
1776 return changed;
1777}
1778
1779range_t* prefs_get_range_value_real(pref_t *pref, pref_source_t source)
1780{
1781 switch (source)
1782 {
1783 case pref_default:
1784 return pref->default_val.range;
1785 case pref_stashed:
1786 return pref->stashed_val.range;
1787 case pref_current:
1788 return *pref->varp.range;
1789 default:
1790 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1790
, __func__, "assertion \"not reached\" failed")
;
1791 break;
1792 }
1793
1794 return NULL((void*)0);
1795}
1796
1797range_t* prefs_get_range_value(const char *module_name, const char* pref_name)
1798{
1799 pref_t *pref = prefs_find_preference(prefs_find_module(module_name), pref_name);
1800 if (pref == NULL((void*)0)) {
1801 return NULL((void*)0);
1802 }
1803 return prefs_get_range_value_real(pref, pref_current);
1804}
1805
1806void
1807prefs_range_add_value(pref_t *pref, uint32_t val)
1808{
1809 range_add_value(pref->scope, pref->varp.range, val);
1810}
1811
1812void
1813prefs_range_remove_value(pref_t *pref, uint32_t val)
1814{
1815 range_remove_value(pref->scope, pref->varp.range, val);
1816}
1817
1818/*
1819 * Register a static text 'preference'. It can be used to add explanatory
1820 * text inline with other preferences in the GUI.
1821 * Note: Static preferences are not saved to the preferences file.
1822 */
1823void
1824prefs_register_static_text_preference(module_t *module, const char *name,
1825 const char *title,
1826 const char *description)
1827{
1828 register_preference(module, name, title, description, PREF_STATIC_TEXT, false0);
1829}
1830
1831/*
1832 * Register a uat 'preference'. It adds a button that opens the uat's window in the
1833 * preferences tab of the module.
1834 */
1835extern void
1836prefs_register_uat_preference(module_t *module, const char *name,
1837 const char *title, const char *description,
1838 uat_t* uat)
1839{
1840 pref_t* preference = register_preference(module, name, title, description, PREF_UAT, false0);
1841
1842 preference->varp.uat = uat;
1843}
1844
1845struct epan_uat* prefs_get_uat_value(pref_t *pref)
1846{
1847 return pref->varp.uat;
1848}
1849
1850/*
1851 * Register a color preference.
1852 */
1853void
1854prefs_register_color_preference(module_t *module, const char *name,
1855 const char *title, const char *description,
1856 color_t *color)
1857{
1858 pref_t* preference = register_preference(module, name, title, description, PREF_COLOR, false0);
1859
1860 preference->varp.colorp = color;
1861 preference->default_val.color = *color;
1862}
1863
1864bool_Bool prefs_set_color_value(pref_t *pref, color_t value, pref_source_t source)
1865{
1866 bool_Bool changed = false0;
1867
1868 switch (source)
1869 {
1870 case pref_default:
1871 if ((pref->default_val.color.red != value.red) ||
1872 (pref->default_val.color.green != value.green) ||
1873 (pref->default_val.color.blue != value.blue)) {
1874 changed = true1;
1875 pref->default_val.color = value;
1876 }
1877 break;
1878 case pref_stashed:
1879 if ((pref->stashed_val.color.red != value.red) ||
1880 (pref->stashed_val.color.green != value.green) ||
1881 (pref->stashed_val.color.blue != value.blue)) {
1882 changed = true1;
1883 pref->stashed_val.color = value;
1884 }
1885 break;
1886 case pref_current:
1887 if ((pref->varp.colorp->red != value.red) ||
1888 (pref->varp.colorp->green != value.green) ||
1889 (pref->varp.colorp->blue != value.blue)) {
1890 changed = true1;
1891 *pref->varp.colorp = value;
1892 }
1893 break;
1894 default:
1895 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1895
, __func__, "assertion \"not reached\" failed")
;
1896 break;
1897 }
1898
1899 return changed;
1900}
1901
1902color_t* prefs_get_color_value(pref_t *pref, pref_source_t source)
1903{
1904 switch (source)
1905 {
1906 case pref_default:
1907 return &pref->default_val.color;
1908 case pref_stashed:
1909 return &pref->stashed_val.color;
1910 case pref_current:
1911 return pref->varp.colorp;
1912 default:
1913 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 1913
, __func__, "assertion \"not reached\" failed")
;
1914 break;
1915 }
1916
1917 return NULL((void*)0);
1918}
1919
1920/*
1921 * Register a "custom" preference with a list.
1922 * XXX - This should be temporary until we can find a better way
1923 * to do "custom" preferences
1924 */
1925typedef void (*pref_custom_list_init_cb) (pref_t* pref, GList** value);
1926
1927static void
1928prefs_register_list_custom_preference(module_t *module, const char *name,
1929 const char *title, const char *description,
1930 struct pref_custom_cbs* custom_cbs,
1931 pref_custom_list_init_cb init_cb,
1932 GList** list)
1933{
1934 pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM, false0);
1935
1936 preference->custom_cbs = *custom_cbs;
1937 init_cb(preference, list);
1938}
1939
1940/*
1941 * Register a custom preference.
1942 */
1943void
1944prefs_register_custom_preference(module_t *module, const char *name,
1945 const char *title, const char *description,
1946 struct pref_custom_cbs* custom_cbs,
1947 void **custom_data _U___attribute__((unused)))
1948{
1949 pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM, false0);
1950
1951 preference->custom_cbs = *custom_cbs;
1952 /* XXX - wait until we can handle void** pointers
1953 preference->custom_cbs.init_cb(preference, custom_data);
1954 */
1955}
1956
1957/*
1958 * Register a dedicated TCP preference for SEQ analysis overriding.
1959 * This is similar to the data structure from enum preference, except
1960 * that when a preference dialog is used, the stashed value is the list
1961 * of frame data pointers whose sequence analysis override will be set
1962 * to the current value if the dialog is accepted.
1963 *
1964 * We don't need to read or write the value from the preferences file
1965 * (or command line), because the override is reset to the default (0)
1966 * for each frame when a new capture file is loaded.
1967 */
1968void
1969prefs_register_custom_preference_TCP_Analysis(module_t *module, const char *name,
1970 const char *title, const char *description,
1971 int *var, const enum_val_t *enumvals,
1972 bool_Bool radio_buttons)
1973{
1974 pref_t *preference;
1975
1976 preference = register_preference(module, name, title, description,
1977 PREF_PROTO_TCP_SNDAMB_ENUM, false0);
1978 preference->varp.enump = var;
1979 preference->default_val.enumval = *var;
1980 preference->stashed_val.list = NULL((void*)0);
1981 preference->info.enum_info.enumvals = enumvals;
1982 preference->info.enum_info.radio_buttons = radio_buttons;
1983}
1984
1985/*
1986 * Register a (internal) "Decode As" preference with a ranged value.
1987 */
1988void prefs_register_decode_as_range_preference(module_t *module, const char *name,
1989 const char *title, const char *description, range_t **var,
1990 uint32_t max_value, const char *dissector_table, const char *dissector_description)
1991{
1992 pref_t *preference;
1993
1994 preference = prefs_register_range_preference_common(module, name, title,
1995 description, var, max_value, PREF_DECODE_AS_RANGE);
1996 preference->dissector_desc = dissector_description;
1997 preference->dissector_table = dissector_table;
1998}
1999
2000/*
2001 * Register a preference with password value.
2002 */
2003void
2004prefs_register_password_preference(module_t *module, const char *name,
2005 const char *title, const char *description,
2006 const char **var)
2007{
2008DIAG_OFF(cast-qual)clang diagnostic push clang diagnostic ignored "-Wcast-qual"
2009 register_string_like_preference(module, name, title, description,
2010 (char **)var, PREF_PASSWORD, NULL((void*)0), false0);
2011DIAG_ON(cast-qual)clang diagnostic pop
2012}
2013
2014/*
2015 * Register a preference with a dissector name.
2016 */
2017void
2018prefs_register_dissector_preference(module_t *module, const char *name,
2019 const char *title, const char *description,
2020 const char **var)
2021{
2022DIAG_OFF(cast-qual)clang diagnostic push clang diagnostic ignored "-Wcast-qual"
2023 register_string_like_preference(module, name, title, description,
2024 (char **)var, PREF_DISSECTOR, NULL((void*)0), false0);
2025DIAG_ON(cast-qual)clang diagnostic pop
2026}
2027
2028bool_Bool prefs_add_decode_as_value(pref_t *pref, unsigned value, bool_Bool replace)
2029{
2030 switch(pref->type)
2031 {
2032 case PREF_DECODE_AS_RANGE:
2033 if (replace)
2034 {
2035 /* If range has single value, replace it */
2036 if (((*pref->varp.range)->nranges == 1) &&
2037 ((*pref->varp.range)->ranges[0].low == (*pref->varp.range)->ranges[0].high)) {
2038 wmem_free(pref->scope, *pref->varp.range);
2039 *pref->varp.range = range_empty(pref->scope);
2040 }
2041 }
2042
2043 prefs_range_add_value(pref, value);
2044 break;
2045 default:
2046 /* XXX - Worth asserting over? */
2047 break;
2048 }
2049
2050 return true1;
2051}
2052
2053bool_Bool prefs_remove_decode_as_value(pref_t *pref, unsigned value, bool_Bool set_default _U___attribute__((unused)))
2054{
2055 switch(pref->type)
2056 {
2057 case PREF_DECODE_AS_RANGE:
2058 /* XXX - We could set to the default if the value is the only one
2059 * in the range.
2060 */
2061 prefs_range_remove_value(pref, value);
2062 break;
2063 default:
2064 break;
2065 }
2066
2067 return true1;
2068}
2069
2070/*
2071 * Register a preference that used to be supported but no longer is.
2072 */
2073void
2074prefs_register_obsolete_preference(module_t *module, const char *name)
2075{
2076 register_preference(module, name, NULL((void*)0), NULL((void*)0), PREF_STATIC_TEXT, true1);
2077}
2078
2079bool_Bool
2080prefs_is_preference_obsolete(pref_t *pref)
2081{
2082 return pref->obsolete;
2083}
2084
2085void
2086prefs_set_preference_effect_fields(module_t *module, const char *name)
2087{
2088 prefs_set_preference_effect(module, name, PREF_EFFECT_FIELDS(1u << 3));
2089}
2090
2091void prefs_set_preference_effect(module_t* module, const char* name, unsigned flags) {
2092 pref_t* pref = prefs_find_preference(module, name);
2093 if (pref) {
2094 prefs_set_effect_flags(pref, prefs_get_effect_flags(pref) | flags);
2095 }
2096}
2097
2098unsigned
2099pref_stash(pref_t *pref, void *unused _U___attribute__((unused)))
2100{
2101 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2101, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2102
2103 switch (pref->type) {
2104
2105 case PREF_UINT:
2106 pref->stashed_val.uint = *pref->varp.uint;
2107 break;
2108
2109 case PREF_BOOL:
2110 pref->stashed_val.boolval = *pref->varp.boolp;
2111 break;
2112
2113 case PREF_ENUM:
2114 pref->stashed_val.enumval = *pref->varp.enump;
2115 break;
2116
2117 case PREF_INT:
2118 pref->stashed_val.intval = *pref->varp.intp;
2119 break;
2120
2121 case PREF_FLOAT:
2122 pref->stashed_val.floatval = *pref->varp.floatp;
2123 break;
2124
2125 case PREF_STRING:
2126 case PREF_SAVE_FILENAME:
2127 case PREF_OPEN_FILENAME:
2128 case PREF_DIRNAME:
2129 case PREF_PASSWORD:
2130 case PREF_DISSECTOR:
2131 wmem_free(pref->scope, pref->stashed_val.string);
2132 pref->stashed_val.string = wmem_strdup(pref->scope, *pref->varp.string);
2133 break;
2134
2135 case PREF_DECODE_AS_RANGE:
2136 case PREF_RANGE:
2137 wmem_free(pref->scope, pref->stashed_val.range);
2138 pref->stashed_val.range = range_copy(pref->scope, *pref->varp.range);
2139 break;
2140
2141 case PREF_COLOR:
2142 pref->stashed_val.color = *pref->varp.colorp;
2143 break;
2144
2145 case PREF_STATIC_TEXT:
2146 case PREF_UAT:
2147 case PREF_CUSTOM:
2148 case PREF_PROTO_TCP_SNDAMB_ENUM:
2149 break;
2150
2151 default:
2152 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2152
, __func__, "assertion \"not reached\" failed")
;
2153 break;
2154 }
2155 return 0;
2156}
2157
2158unsigned
2159pref_unstash(pref_t *pref, void *unstash_data_p)
2160{
2161 pref_unstash_data_t *unstash_data = (pref_unstash_data_t *)unstash_data_p;
2162 dissector_table_t sub_dissectors = NULL((void*)0);
2163 dissector_handle_t handle = NULL((void*)0);
2164
2165 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2165, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2166
2167 /* Revert the preference to its saved value. */
2168 switch (pref->type) {
2169
2170 case PREF_UINT:
2171 if (*pref->varp.uint != pref->stashed_val.uint) {
2172 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2173 *pref->varp.uint = pref->stashed_val.uint;
2174 }
2175 break;
2176
2177 case PREF_INT:
2178 if (*pref->varp.intp != pref->stashed_val.intval) {
2179 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2180 *pref->varp.intp = pref->stashed_val.intval;
2181 }
2182 break;
2183
2184 case PREF_FLOAT:
2185 if (*pref->varp.floatp != pref->stashed_val.floatval) {
2186 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2187 *pref->varp.floatp = pref->stashed_val.floatval;
2188 }
2189 break;
2190
2191 case PREF_BOOL:
2192 if (*pref->varp.boolp != pref->stashed_val.boolval) {
2193 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2194 *pref->varp.boolp = pref->stashed_val.boolval;
2195 }
2196 break;
2197
2198 case PREF_ENUM:
2199 if (*pref->varp.enump != pref->stashed_val.enumval) {
2200 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2201 *pref->varp.enump = pref->stashed_val.enumval;
2202 }
2203 break;
2204
2205 case PREF_PROTO_TCP_SNDAMB_ENUM:
2206 {
2207 /* The preference dialogs are modal so the frame_data pointers should
2208 * still be valid; otherwise we could store the frame numbers to
2209 * change.
2210 */
2211 frame_data *fdata;
2212 for (GList* elem = pref->stashed_val.list; elem != NULL((void*)0); elem = elem->next) {
2213 fdata = (frame_data*)elem->data;
2214 if (fdata->tcp_snd_manual_analysis != *pref->varp.enump) {
2215 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2216 fdata->tcp_snd_manual_analysis = *pref->varp.enump;
2217 }
2218 }
2219 break;
2220 }
2221 case PREF_STRING:
2222 case PREF_SAVE_FILENAME:
2223 case PREF_OPEN_FILENAME:
2224 case PREF_DIRNAME:
2225 case PREF_PASSWORD:
2226 case PREF_DISSECTOR:
2227 if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0) {
2228 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2229 wmem_free(pref->scope, *pref->varp.string);
2230 *pref->varp.string = wmem_strdup(pref->scope, pref->stashed_val.string);
2231 }
2232 break;
2233
2234 case PREF_DECODE_AS_RANGE:
2235 {
2236 const char* table_name = prefs_get_dissector_table(pref);
2237 if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2238 uint32_t i, j;
2239 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2240
2241 if (unstash_data->handle_decode_as) {
2242 sub_dissectors = find_dissector_table(table_name);
2243 if (sub_dissectors != NULL((void*)0)) {
2244 const char *handle_desc = prefs_get_dissector_description(pref);
2245 // It should perhaps be possible to get this via dissector name.
2246 handle = dissector_table_get_dissector_handle(sub_dissectors, handle_desc);
2247 if (handle != NULL((void*)0)) {
2248 /* Set the current handle to NULL for all the old values
2249 * in the dissector table. If there isn't an initial
2250 * handle, this actually deletes the entry. (If there
2251 * is an initial entry, keep it around so that the
2252 * user can see the original value.)
2253 *
2254 * XXX - If there's an initial handle which is not this,
2255 * reset it instead? At least this leaves the initial
2256 * handle visible in the Decode As table.
2257 */
2258 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2259 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2260 dissector_change_uint(table_name, j, NULL((void*)0));
2261 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j)((gpointer) (gulong) (j)), NULL((void*)0), NULL((void*)0));
2262 }
2263
2264 dissector_change_uint(table_name, (*pref->varp.range)->ranges[i].high, NULL((void*)0));
2265 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high)((gpointer) (gulong) ((*pref->varp.range)->ranges[i].high
))
, NULL((void*)0), NULL((void*)0));
2266 }
2267 }
2268 }
2269 }
2270
2271 wmem_free(pref->scope, *pref->varp.range);
2272 *pref->varp.range = range_copy(pref->scope, pref->stashed_val.range);
2273
2274 if (unstash_data->handle_decode_as) {
2275 if ((sub_dissectors != NULL((void*)0)) && (handle != NULL((void*)0))) {
2276
2277 /* Add new values to the dissector table */
2278 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2279
2280 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2281 dissector_change_uint(table_name, j, handle);
2282 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j)((gpointer) (gulong) (j)), NULL((void*)0), NULL((void*)0));
2283 }
2284
2285 dissector_change_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
2286 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high)((gpointer) (gulong) ((*pref->varp.range)->ranges[i].high
))
, NULL((void*)0), NULL((void*)0));
2287 }
2288 }
2289 }
2290 }
2291 break;
2292 }
2293 case PREF_RANGE:
2294 if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2295 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2296 wmem_free(pref->scope, *pref->varp.range);
2297 *pref->varp.range = range_copy(pref->scope, pref->stashed_val.range);
2298 }
2299 break;
2300
2301 case PREF_COLOR:
2302 if ((pref->varp.colorp->blue != pref->stashed_val.color.blue) ||
2303 (pref->varp.colorp->red != pref->stashed_val.color.red) ||
2304 (pref->varp.colorp->green != pref->stashed_val.color.green)) {
2305 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2306 *pref->varp.colorp = pref->stashed_val.color;
2307 }
2308 break;
2309 case PREF_UAT:
2310 if (pref->varp.uat && pref->varp.uat->changed) {
2311 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2312 }
2313 break;
2314 case PREF_STATIC_TEXT:
2315 case PREF_CUSTOM:
2316 break;
2317
2318 default:
2319 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2319
, __func__, "assertion \"not reached\" failed")
;
2320 break;
2321 }
2322 return 0;
2323}
2324
2325void
2326reset_stashed_pref(pref_t *pref) {
2327
2328 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2328, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2329
2330 switch (pref->type) {
2331
2332 case PREF_UINT:
2333 pref->stashed_val.uint = pref->default_val.uint;
2334 break;
2335
2336 case PREF_INT:
2337 pref->stashed_val.intval = pref->default_val.intval;
2338 break;
2339
2340 case PREF_FLOAT:
2341 pref->stashed_val.floatval = pref->default_val.floatval;
2342 break;
2343
2344 case PREF_BOOL:
2345 pref->stashed_val.boolval = pref->default_val.boolval;
2346 break;
2347
2348 case PREF_ENUM:
2349 pref->stashed_val.enumval = pref->default_val.enumval;
2350 break;
2351
2352 case PREF_STRING:
2353 case PREF_SAVE_FILENAME:
2354 case PREF_OPEN_FILENAME:
2355 case PREF_DIRNAME:
2356 case PREF_PASSWORD:
2357 case PREF_DISSECTOR:
2358 wmem_free(pref->scope, pref->stashed_val.string);
2359 pref->stashed_val.string = wmem_strdup(pref->scope, pref->default_val.string);
2360 break;
2361
2362 case PREF_DECODE_AS_RANGE:
2363 case PREF_RANGE:
2364 wmem_free(pref->scope, pref->stashed_val.range);
2365 pref->stashed_val.range = range_copy(pref->scope, pref->default_val.range);
2366 break;
2367
2368 case PREF_PROTO_TCP_SNDAMB_ENUM:
2369 if (pref->stashed_val.list != NULL((void*)0)) {
2370 g_list_free(pref->stashed_val.list);
2371 pref->stashed_val.list = NULL((void*)0);
2372 }
2373 break;
2374
2375 case PREF_COLOR:
2376 memcpy(&pref->stashed_val.color, &pref->default_val.color, sizeof(color_t));
2377 break;
2378
2379 case PREF_STATIC_TEXT:
2380 case PREF_UAT:
2381 case PREF_CUSTOM:
2382 break;
2383
2384 default:
2385 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2385
, __func__, "assertion \"not reached\" failed")
;
2386 break;
2387 }
2388}
2389
2390unsigned
2391pref_clean_stash(pref_t *pref, void *unused _U___attribute__((unused)))
2392{
2393 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2393, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2394
2395 switch (pref->type) {
2396
2397 case PREF_UINT:
2398 case PREF_INT:
2399 case PREF_FLOAT:
2400 case PREF_BOOL:
2401 case PREF_ENUM:
2402 break;
2403
2404 case PREF_STRING:
2405 case PREF_SAVE_FILENAME:
2406 case PREF_OPEN_FILENAME:
2407 case PREF_DIRNAME:
2408 case PREF_PASSWORD:
2409 case PREF_DISSECTOR:
2410 if (pref->stashed_val.string != NULL((void*)0)) {
2411 wmem_free(pref->scope, pref->stashed_val.string);
2412 pref->stashed_val.string = NULL((void*)0);
2413 }
2414 break;
2415
2416 case PREF_DECODE_AS_RANGE:
2417 case PREF_RANGE:
2418 if (pref->stashed_val.range != NULL((void*)0)) {
2419 wmem_free(pref->scope, pref->stashed_val.range);
2420 pref->stashed_val.range = NULL((void*)0);
2421 }
2422 break;
2423
2424 case PREF_STATIC_TEXT:
2425 case PREF_UAT:
2426 case PREF_COLOR:
2427 case PREF_CUSTOM:
2428 break;
2429
2430 case PREF_PROTO_TCP_SNDAMB_ENUM:
2431 if (pref->stashed_val.list != NULL((void*)0)) {
2432 g_list_free(pref->stashed_val.list);
2433 pref->stashed_val.list = NULL((void*)0);
2434 }
2435 break;
2436
2437 default:
2438 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2438
, __func__, "assertion \"not reached\" failed")
;
2439 break;
2440 }
2441 return 0;
2442}
2443
2444/*
2445 * Call a callback function, with a specified argument, for each preference
2446 * in a given module.
2447 *
2448 * If any of the callbacks return a non-zero value, stop and return that
2449 * value, otherwise return 0.
2450 */
2451unsigned
2452prefs_pref_foreach(module_t *module, pref_cb callback, void *user_data)
2453{
2454 GList *elem;
2455 pref_t *pref;
2456 unsigned ret;
2457
2458 for (elem = g_list_first(module->prefs); elem != NULL((void*)0); elem = g_list_next(elem)((elem) ? (((GList *)(elem))->next) : ((void*)0))) {
2459 pref = (pref_t *)elem->data;
2460 if (!pref || pref->obsolete) {
2461 /*
2462 * This preference is no longer supported; it's
2463 * not a real preference, so we don't call the
2464 * callback for it (i.e., we treat it as if it
2465 * weren't found in the list of preferences,
2466 * and we weren't called in the first place).
2467 */
2468 continue;
2469 }
2470
2471 ret = (*callback)(pref, user_data);
2472 if (ret != 0)
2473 return ret;
2474 }
2475 return 0;
2476}
2477
2478static const enum_val_t st_sort_col_vals[] = {
2479 { "name", "Node name (topic/item)", ST_SORT_COL_NAME1 },
2480 { "count", "Item count", ST_SORT_COL_COUNT2 },
2481 { "average", "Average value of the node", ST_SORT_COL_AVG3 },
2482 { "min", "Minimum value of the node", ST_SORT_COL_MIN4 },
2483 { "max", "Maximum value of the node", ST_SORT_COL_MAX5 },
2484 { "burst", "Burst rate of the node", ST_SORT_COL_BURSTRATE6 },
2485 { NULL((void*)0), NULL((void*)0), 0 }
2486};
2487
2488static const enum_val_t st_format_vals[] = {
2489 { "text", "Plain text", ST_FORMAT_PLAIN },
2490 { "csv", "Comma separated values", ST_FORMAT_CSV },
2491 { "xml", "XML document", ST_FORMAT_XML },
2492 { "yaml", "YAML document", ST_FORMAT_YAML },
2493 { NULL((void*)0), NULL((void*)0), 0 }
2494};
2495
2496static void
2497stats_callback(void)
2498{
2499 /* Test for a sane tap update interval */
2500 if (prefs.tap_update_interval < 100 || prefs.tap_update_interval > 10000)
2501 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
2502
2503 /* burst resolution can't be less than 1 (ms) */
2504 if (prefs.st_burst_resolution < 1) {
2505 prefs.st_burst_resolution = 1;
2506 }
2507 else if (prefs.st_burst_resolution > ST_MAX_BURSTRES600000) {
2508 prefs.st_burst_resolution = ST_MAX_BURSTRES600000;
2509 }
2510 /* make sure burst window value makes sense */
2511 if (prefs.st_burst_windowlen < prefs.st_burst_resolution) {
2512 prefs.st_burst_windowlen = prefs.st_burst_resolution;
2513 }
2514 /* round burst window down to multiple of resolution */
2515 prefs.st_burst_windowlen -= prefs.st_burst_windowlen%prefs.st_burst_resolution;
2516 if ((prefs.st_burst_windowlen/prefs.st_burst_resolution) > ST_MAX_BURSTBUCKETS100) {
2517 prefs.st_burst_windowlen = prefs.st_burst_resolution*ST_MAX_BURSTBUCKETS100;
2518 }
2519}
2520
2521static void
2522gui_callback(void)
2523{
2524 /* Ensure there is at least one file count */
2525 if (prefs.gui_recent_files_count_max == 0)
2526 prefs.gui_recent_files_count_max = 10;
2527
2528 /* Ensure there is at least one display filter entry */
2529 if (prefs.gui_recent_df_entries_max == 0)
2530 prefs.gui_recent_df_entries_max = 10;
2531
2532 /* number of decimal places should be between 2 and 10 */
2533 if (prefs.gui_decimal_places1 < 2) {
2534 prefs.gui_decimal_places1 = 2;
2535 } else if (prefs.gui_decimal_places1 > 10) {
2536 prefs.gui_decimal_places1 = 10;
2537 }
2538 /* number of decimal places should be between 2 and 10 */
2539 if (prefs.gui_decimal_places2 < 2) {
2540 prefs.gui_decimal_places2 = 2;
2541 } else if (prefs.gui_decimal_places2 > 10) {
2542 prefs.gui_decimal_places2 = 10;
2543 }
2544 /* number of decimal places should be between 2 and 10 */
2545 if (prefs.gui_decimal_places3 < 2) {
2546 prefs.gui_decimal_places3 = 2;
2547 } else if (prefs.gui_decimal_places3 > 10) {
2548 prefs.gui_decimal_places3 = 10;
2549 }
2550}
2551
2552static void
2553gui_layout_callback(void)
2554{
2555 if (prefs.gui_layout_type == layout_unused ||
2556 prefs.gui_layout_type >= layout_type_max) {
2557 /* XXX - report an error? It's not a syntax error - we'd need to
2558 add a way of reporting a *semantic* error. */
2559 prefs.gui_layout_type = layout_type_2;
2560 }
2561}
2562
2563/******************************************************
2564 * All custom preference function callbacks
2565 ******************************************************/
2566static void custom_pref_no_cb(pref_t* pref _U___attribute__((unused))) {}
2567
2568/*
2569 * Column preference functions
2570 */
2571#define PRS_COL_HIDDEN_FMT"column.hidden" "column.hidden"
2572#define PRS_COL_HIDDEN"column.hide" "column.hide"
2573#define PRS_COL_FMT"column.format" "column.format"
2574#define PRS_COL_NUM"column.number" "column.number"
2575static module_t *gui_column_module;
2576
2577static prefs_set_pref_e
2578column_hidden_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
2579{
2580 GList *clp;
2581 fmt_data *cfmt;
2582 pref_t *format_pref;
2583
2584 /*
2585 * Prefer the new preference to the old format-based preference if we've
2586 * read it. (We probably could just compare the string to NULL and "".)
2587 */
2588 prefs.cols_hide_new = true1;
2589
2590 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2591
2592 /*
2593 * Set the "visible" flag for the existing columns; we need to
2594 * do this if we set PRS_COL_HIDDEN but don't set PRS_COL_FMT
2595 * after setting it (which might be the case if, for example, we
2596 * set PRS_COL_HIDDEN on the command line).
2597 */
2598 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2599 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2600 int cidx = 1;
2601 while (clp) {
2602 cfmt = (fmt_data *)clp->data;
2603 cfmt->visible = prefs_is_column_visible(*pref->varp.string, cidx);
2604 cidx++;
2605 clp = clp->next;
2606 }
2607
2608 return PREFS_SET_OK;
2609}
2610
2611static const char *
2612column_hidden_type_name_cb(void)
2613{
2614 return "Packet list hidden columns";
2615}
2616
2617static char *
2618column_hidden_type_description_cb(void)
2619{
2620 return g_strdup("List all column indices (1-indexed) to hide in the packet list.")g_strdup_inline ("List all column indices (1-indexed) to hide in the packet list."
)
;
2621}
2622
2623static char *
2624column_hidden_to_str_cb(pref_t* pref, bool_Bool default_val)
2625{
2626 GString *cols_hidden;
2627 GList *clp;
2628 fmt_data *cfmt;
2629 pref_t *format_pref;
2630 int cidx = 1;
2631
2632 if (default_val)
2633 return g_strdup(pref->default_val.string)g_strdup_inline (pref->default_val.string);
2634
2635 cols_hidden = g_string_new("");
2636 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2637 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2638 while (clp) {
2639 cfmt = (fmt_data *) clp->data;
2640 if (!cfmt->visible) {
2641 if (cols_hidden->len)
2642 g_string_append (cols_hidden, ",")(__builtin_constant_p (",") ? __extension__ ({ const char * const
__val = (","); g_string_append_len_inline (cols_hidden, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (cols_hidden
, ",", (gssize) -1))
;
2643 g_string_append_printf (cols_hidden, "%i", cidx);
2644 }
2645 clp = clp->next;
2646 cidx++;
2647 }
2648
2649 return g_string_free (cols_hidden, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((cols_hidden
), ((0))) : g_string_free_and_steal (cols_hidden)) : (g_string_free
) ((cols_hidden), ((0))))
;
2650}
2651
2652static bool_Bool
2653column_hidden_is_default_cb(pref_t* pref)
2654{
2655 char *cur_hidden_str = column_hidden_to_str_cb(pref, false0);
2656 bool_Bool is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2657
2658 g_free(cur_hidden_str);
2659 return is_default;
2660}
2661
2662static prefs_set_pref_e
2663column_hidden_fmt_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
2664{
2665 GList *clp;
2666 fmt_data *cfmt;
2667 pref_t *format_pref;
2668
2669 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2670
2671 /*
2672 * Set the "visible" flag for the existing columns; we need to
2673 * do this if we set PRS_COL_HIDDEN_FMT but don't set PRS_COL_FMT
2674 * after setting it (which might be the case if, for example, we
2675 * set PRS_COL_HIDDEN_FMT on the command line; it shouldn't happen
2676 * when reading the configuration file because we write (both of)
2677 * the hidden column prefs before the column format prefs.)
2678 */
2679 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2680 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2681 while (clp) {
2682 cfmt = (fmt_data *)clp->data;
2683 cfmt->visible = prefs_is_column_fmt_visible(*pref->varp.string, cfmt);
2684 clp = clp->next;
2685 }
2686
2687 return PREFS_SET_OK;
2688}
2689
2690static const char *
2691column_hidden_fmt_type_name_cb(void)
2692{
2693 return "Packet list hidden column formats (deprecated)";
2694}
2695
2696static char *
2697column_hidden_fmt_type_description_cb(void)
2698{
2699 return g_strdup("List all column formats to hide in the packet list. Deprecated in favor of the index-based preference.")g_strdup_inline ("List all column formats to hide in the packet list. Deprecated in favor of the index-based preference."
)
;
2700}
2701
2702static char *
2703column_hidden_fmt_to_str_cb(pref_t* pref, bool_Bool default_val)
2704{
2705 GString *cols_hidden;
2706 GList *clp;
2707 fmt_data *cfmt;
2708 pref_t *format_pref;
2709
2710 if (default_val)
2711 return g_strdup(pref->default_val.string)g_strdup_inline (pref->default_val.string);
2712
2713 cols_hidden = g_string_new("");
2714 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2715 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2716 while (clp) {
2717 char *prefs_fmt;
2718 cfmt = (fmt_data *) clp->data;
2719 if (!cfmt->visible) {
2720 if (cols_hidden->len)
2721 g_string_append (cols_hidden, ",")(__builtin_constant_p (",") ? __extension__ ({ const char * const
__val = (","); g_string_append_len_inline (cols_hidden, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (cols_hidden
, ",", (gssize) -1))
;
2722 prefs_fmt = column_fmt_data_to_str(cfmt);
2723 g_string_append(cols_hidden, prefs_fmt)(__builtin_constant_p (prefs_fmt) ? __extension__ ({ const char
* const __val = (prefs_fmt); g_string_append_len_inline (cols_hidden
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (cols_hidden
, prefs_fmt, (gssize) -1))
;
2724 g_free(prefs_fmt);
2725 }
2726 clp = clp->next;
2727 }
2728
2729 return g_string_free (cols_hidden, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((cols_hidden
), ((0))) : g_string_free_and_steal (cols_hidden)) : (g_string_free
) ((cols_hidden), ((0))))
;
2730}
2731
2732static bool_Bool
2733column_hidden_fmt_is_default_cb(pref_t* pref)
2734{
2735 char *cur_hidden_str = column_hidden_fmt_to_str_cb(pref, false0);
2736 bool_Bool is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2737
2738 g_free(cur_hidden_str);
2739 return is_default;
2740}
2741
2742/* Number of columns "preference". This is only used internally and is not written to the
2743 * preference file
2744 */
2745static void
2746column_num_reset_cb(pref_t* pref)
2747{
2748 *pref->varp.uint = pref->default_val.uint;
2749}
2750
2751static prefs_set_pref_e
2752column_num_set_cb(pref_t* pref _U___attribute__((unused)), const char* value _U___attribute__((unused)), unsigned int* changed_flags _U___attribute__((unused)))
2753{
2754 /* Don't write this to the preferences file */
2755 return PREFS_SET_OK;
2756}
2757
2758static const char *
2759column_num_type_name_cb(void)
2760{
2761 return NULL((void*)0);
2762}
2763
2764static char *
2765column_num_type_description_cb(void)
2766{
2767 return g_strdup("")g_strdup_inline ("");
2768}
2769
2770static bool_Bool
2771column_num_is_default_cb(pref_t* pref _U___attribute__((unused)))
2772{
2773 return true1;
2774}
2775
2776static char *
2777column_num_to_str_cb(pref_t* pref _U___attribute__((unused)), bool_Bool default_val _U___attribute__((unused)))
2778{
2779 return g_strdup("")g_strdup_inline ("");
2780}
2781
2782/*
2783 * Column format custom preference functions
2784 */
2785static void
2786column_format_init_cb(pref_t* pref, GList** value)
2787{
2788 fmt_data *src_cfmt, *dest_cfmt;
2789 GList *entry;
2790
2791 pref->varp.list = value;
2792
2793 pref->default_val.list = NULL((void*)0);
2794 for (entry = *pref->varp.list; entry != NULL((void*)0); entry = g_list_next(entry)((entry) ? (((GList *)(entry))->next) : ((void*)0))) {
2795 src_cfmt = (fmt_data *)entry->data;
2796 dest_cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2797 dest_cfmt->title = g_strdup(src_cfmt->title)g_strdup_inline (src_cfmt->title);
2798 dest_cfmt->fmt = src_cfmt->fmt;
2799 if (src_cfmt->custom_fields) {
2800 dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields)g_strdup_inline (src_cfmt->custom_fields);
2801 dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2802 } else {
2803 dest_cfmt->custom_fields = NULL((void*)0);
2804 dest_cfmt->custom_occurrence = 0;
2805 }
2806 dest_cfmt->visible = src_cfmt->visible;
2807 dest_cfmt->display = src_cfmt->display;
2808 pref->default_val.list = g_list_append(pref->default_val.list, dest_cfmt);
2809 }
2810
2811 column_register_fields();
2812}
2813
2814static void
2815column_format_free_cb(pref_t* pref)
2816{
2817 free_col_info(*pref->varp.list);
2818 free_col_info(pref->default_val.list);
2819}
2820
2821static void
2822column_format_reset_cb(pref_t* pref)
2823{
2824 fmt_data *src_cfmt, *dest_cfmt;
2825 GList *entry;
2826 pref_t *col_num_pref;
2827
2828 free_col_info(*pref->varp.list);
2829 *pref->varp.list = NULL((void*)0);
2830
2831 for (entry = pref->default_val.list; entry != NULL((void*)0); entry = g_list_next(entry)((entry) ? (((GList *)(entry))->next) : ((void*)0))) {
2832 src_cfmt = (fmt_data *)entry->data;
2833 dest_cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2834 dest_cfmt->title = g_strdup(src_cfmt->title)g_strdup_inline (src_cfmt->title);
2835 dest_cfmt->fmt = src_cfmt->fmt;
2836 if (src_cfmt->custom_fields) {
2837 dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields)g_strdup_inline (src_cfmt->custom_fields);
2838 dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2839 } else {
2840 dest_cfmt->custom_fields = NULL((void*)0);
2841 dest_cfmt->custom_occurrence = 0;
2842 }
2843 dest_cfmt->visible = src_cfmt->visible;
2844 dest_cfmt->display = src_cfmt->display;
2845 *pref->varp.list = g_list_append(*pref->varp.list, dest_cfmt);
2846 }
2847
2848 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2849 ws_assert(col_num_pref != NULL)do { if ((1) && !(col_num_pref != ((void*)0))) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2849, __func__, "assertion failed: %s"
, "col_num_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2850 column_num_reset_cb(col_num_pref);
2851}
2852
2853static prefs_set_pref_e
2854column_format_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags _U___attribute__((unused)))
2855{
2856 GList *col_l, *col_l_elt;
2857 fmt_data *cfmt;
2858 int llen;
2859 pref_t *hidden_pref, *col_num_pref;
2860
2861 col_l = prefs_get_string_list(value);
2862 if (col_l == NULL((void*)0))
2863 return PREFS_SET_SYNTAX_ERR;
2864 if ((g_list_length(col_l) % 2) != 0) {
2865 /* A title didn't have a matching format. */
2866 prefs_clear_string_list(col_l);
2867 return PREFS_SET_SYNTAX_ERR;
2868 }
2869 /* Check to make sure all column formats are valid. */
2870 col_l_elt = g_list_first(col_l);
2871 while (col_l_elt) {
2872 fmt_data cfmt_check;
2873
2874 /* Go past the title. */
2875 col_l_elt = col_l_elt->next;
2876
2877 /* Some predefined columns have been migrated to use custom columns.
2878 * We'll convert these silently here */
2879 try_convert_to_custom_column((char **)&col_l_elt->data);
2880
2881 /* Parse the format to see if it's valid. */
2882 if (!parse_column_format(&cfmt_check, (char *)col_l_elt->data)) {
2883 /* It's not a valid column format. */
2884 prefs_clear_string_list(col_l);
2885 return PREFS_SET_SYNTAX_ERR;
2886 }
2887 if (cfmt_check.fmt == COL_CUSTOM) {
2888 /* We don't need the custom column field on this pass. */
2889 g_free(cfmt_check.custom_fields);
2890 }
2891
2892 /* Go past the format. */
2893 col_l_elt = col_l_elt->next;
2894 }
2895
2896 /* They're all valid; process them. */
2897 free_col_info(*pref->varp.list);
2898 *pref->varp.list = NULL((void*)0);
2899 if (prefs.cols_hide_new) {
2900 hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN"column.hide");
2901 } else {
2902 hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN_FMT"column.hidden");
2903 }
2904 ws_assert(hidden_pref != NULL)do { if ((1) && !(hidden_pref != ((void*)0))) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2904, __func__, "assertion failed: %s"
, "hidden_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2905 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2906 ws_assert(col_num_pref != NULL)do { if ((1) && !(col_num_pref != ((void*)0))) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2906, __func__, "assertion failed: %s"
, "col_num_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2907 llen = g_list_length(col_l);
2908 *col_num_pref->varp.uint = llen / 2;
2909 col_l_elt = g_list_first(col_l);
2910 int cidx = 1;
2911 while (col_l_elt) {
2912 cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2913 cfmt->title = g_strdup((char *)col_l_elt->data)g_strdup_inline ((char *)col_l_elt->data);
2914 col_l_elt = col_l_elt->next;
2915 parse_column_format(cfmt, (char *)col_l_elt->data);
2916 if (prefs.cols_hide_new) {
2917 cfmt->visible = prefs_is_column_visible(*hidden_pref->varp.string, cidx);
2918 } else {
2919 cfmt->visible = prefs_is_column_fmt_visible(*hidden_pref->varp.string, cfmt);
2920 }
2921 col_l_elt = col_l_elt->next;
2922 *pref->varp.list = g_list_append(*pref->varp.list, cfmt);
2923 cidx++;
2924 }
2925
2926 prefs_clear_string_list(col_l);
2927 free_string_like_preference(hidden_pref);
2928 column_register_fields();
2929 return PREFS_SET_OK;
2930}
2931
2932
2933static const char *
2934column_format_type_name_cb(void)
2935{
2936 return "Packet list column format";
2937}
2938
2939static char *
2940column_format_type_description_cb(void)
2941{
2942 return g_strdup("Each pair of strings consists of a column title and its format")g_strdup_inline ("Each pair of strings consists of a column title and its format"
)
;
2943}
2944
2945static bool_Bool
2946column_format_is_default_cb(pref_t* pref)
2947{
2948 GList *clp = *pref->varp.list,
2949 *pref_col = g_list_first(clp),
2950 *def_col = g_list_first(pref->default_val.list);
2951 fmt_data *cfmt, *def_cfmt;
2952 bool_Bool is_default = true1;
2953 pref_t *col_num_pref;
2954
2955 /* See if the column data has changed from the default */
2956 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2957 if (col_num_pref && *col_num_pref->varp.uint != col_num_pref->default_val.uint) {
2958 is_default = false0;
2959 } else {
2960 while (pref_col && def_col) {
2961 cfmt = (fmt_data *) pref_col->data;
2962 def_cfmt = (fmt_data *) def_col->data;
2963 if ((g_strcmp0(cfmt->title, def_cfmt->title) != 0) ||
2964 (cfmt->fmt != def_cfmt->fmt) ||
2965 (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) &&
2966 ((g_strcmp0(cfmt->custom_fields, def_cfmt->custom_fields) != 0) ||
2967 (cfmt->display != def_cfmt->display)))) {
2968 is_default = false0;
2969 break;
2970 }
2971
2972 pref_col = pref_col->next;
2973 def_col = def_col->next;
2974 }
2975 }
2976
2977 return is_default;
2978}
2979
2980static char *
2981column_format_to_str_cb(pref_t* pref, bool_Bool default_val)
2982{
2983 GList *pref_l = default_val ? pref->default_val.list : *pref->varp.list;
2984 GList *clp = g_list_first(pref_l);
2985 GList *col_l;
2986 fmt_data *cfmt;
2987 char *column_format_str;
2988
2989 col_l = NULL((void*)0);
2990 while (clp) {
2991 cfmt = (fmt_data *) clp->data;
2992 col_l = g_list_append(col_l, g_strdup(cfmt->title)g_strdup_inline (cfmt->title));
2993 col_l = g_list_append(col_l, column_fmt_data_to_str(cfmt));
2994 clp = clp->next;
2995 }
2996
2997 column_format_str = join_string_list(col_l);
2998 prefs_clear_string_list(col_l);
2999 return column_format_str;
3000}
3001
3002
3003/****** Capture column custom preference functions ******/
3004
3005/* This routine is only called when Wireshark is started, NOT when another profile is selected.
3006 Copy the pref->capture_columns list (just loaded with the capture_cols[] struct values)
3007 to prefs->default_val.list.
3008*/
3009static void
3010capture_column_init_cb(pref_t* pref, GList** capture_cols_values)
3011{
3012 GList *ccv_list = *capture_cols_values,
3013 *dlist = NULL((void*)0);
3014
3015 /* */
3016 while (ccv_list) {
3017 dlist = g_list_append(dlist, g_strdup((char *)ccv_list->data)g_strdup_inline ((char *)ccv_list->data));
3018 ccv_list = ccv_list->next;
3019 }
3020
3021 pref->default_val.list = dlist;
3022 pref->varp.list = &prefs.capture_columns;
3023 pref->stashed_val.boolval = false0;
3024}
3025
3026/* Free the prefs->capture_columns list strings and remove the list entries.
3027 Note that since pref->varp.list points to &prefs.capture_columns, it is
3028 also freed.
3029*/
3030static void
3031capture_column_free_cb(pref_t* pref)
3032{
3033 prefs_clear_string_list(prefs.capture_columns);
3034 prefs.capture_columns = NULL((void*)0);
3035
3036 if (pref->stashed_val.boolval == true1) {
3037 prefs_clear_string_list(pref->default_val.list);
3038 pref->default_val.list = NULL((void*)0);
3039 }
3040}
3041
3042/* Copy pref->default_val.list to *pref->varp.list.
3043*/
3044static void
3045capture_column_reset_cb(pref_t* pref)
3046{
3047 GList *vlist = NULL((void*)0), *dlist;
3048
3049 /* Free the column name strings and remove the links from *pref->varp.list */
3050 prefs_clear_string_list(*pref->varp.list);
3051
3052 for (dlist = pref->default_val.list; dlist != NULL((void*)0); dlist = g_list_next(dlist)((dlist) ? (((GList *)(dlist))->next) : ((void*)0))) {
3053 vlist = g_list_append(vlist, g_strdup((char *)dlist->data)g_strdup_inline ((char *)dlist->data));
3054 }
3055 *pref->varp.list = vlist;
3056}
3057
3058static prefs_set_pref_e
3059capture_column_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags _U___attribute__((unused)))
3060{
3061 GList *col_l = prefs_get_string_list(value);
3062 GList *col_l_elt;
3063 char *col_name;
3064 int i;
3065
3066 if (col_l == NULL((void*)0))
3067 return PREFS_SET_SYNTAX_ERR;
3068
3069 capture_column_free_cb(pref);
3070
3071 /* If value (the list of capture.columns read from preferences) is empty, set capture.columns
3072 to the full list of valid capture column names. */
3073 col_l_elt = g_list_first(col_l);
3074 if (!(*(char *)col_l_elt->data)) {
3075 for (i = 0; i < num_capture_cols; i++) {
3076 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
3077 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
3078 }
3079 }
3080
3081 /* Verify that all the column names are valid. If not, use the entire list of valid columns.
3082 */
3083 while (col_l_elt) {
3084 bool_Bool found_match = false0;
3085 col_name = (char *)col_l_elt->data;
3086
3087 for (i = 0; i < num_capture_cols; i++) {
3088 if (strcmp(col_name, capture_cols[i])==0) {
3089 found_match = true1;
3090 break;
3091 }
3092 }
3093 if (!found_match) {
3094 /* One or more cols are invalid so use the entire list of valid cols. */
3095 for (i = 0; i < num_capture_cols; i++) {
3096 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
3097 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
3098 }
3099 pref->varp.list = &prefs.capture_columns;
3100 prefs_clear_string_list(col_l);
3101 return PREFS_SET_SYNTAX_ERR;
3102 }
3103 col_l_elt = col_l_elt->next;
3104 }
3105
3106 col_l_elt = g_list_first(col_l);
3107 while (col_l_elt) {
3108 col_name = (char *)col_l_elt->data;
3109 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
3110 col_l_elt = col_l_elt->next;
3111 }
3112 pref->varp.list = &prefs.capture_columns;
3113 g_list_free(col_l);
3114 return PREFS_SET_OK;
3115}
3116
3117
3118static const char *
3119capture_column_type_name_cb(void)
3120{
3121 return "Column list";
3122}
3123
3124static char *
3125capture_column_type_description_cb(void)
3126{
3127 return g_strdup(g_strdup_inline ("List of columns to be displayed in the capture options dialog.\n"
"Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
)
3128 "List of columns to be displayed in the capture options dialog.\n"g_strdup_inline ("List of columns to be displayed in the capture options dialog.\n"
"Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
)
3129 CAPTURE_COL_TYPE_DESCRIPTION)g_strdup_inline ("List of columns to be displayed in the capture options dialog.\n"
"Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
)
;
3130}
3131
3132static bool_Bool
3133capture_column_is_default_cb(pref_t* pref)
3134{
3135 GList *pref_col = g_list_first(prefs.capture_columns),
3136 *def_col = g_list_first(pref->default_val.list);
3137 bool_Bool is_default = true1;
3138
3139 /* See if the column data has changed from the default */
3140 while (pref_col && def_col) {
3141 if (strcmp((char *)pref_col->data, (char *)def_col->data) != 0) {
3142 is_default = false0;
3143 break;
3144 }
3145 pref_col = pref_col->next;
3146 def_col = def_col->next;
3147 }
3148
3149 /* Ensure the same column count */
3150 if (((pref_col == NULL((void*)0)) && (def_col != NULL((void*)0))) ||
3151 ((pref_col != NULL((void*)0)) && (def_col == NULL((void*)0))))
3152 is_default = false0;
3153
3154 return is_default;
3155}
3156
3157static char *
3158capture_column_to_str_cb(pref_t* pref, bool_Bool default_val)
3159{
3160
3161 GList *pref_l = default_val ? pref->default_val.list : prefs.capture_columns;
3162 GList *clp = g_list_first(pref_l);
3163 GList *col_l = NULL((void*)0);
3164 char *col;
3165 char *capture_column_str;
3166
3167 while (clp) {
3168 col = (char *) clp->data;
3169 col_l = g_list_append(col_l, g_strdup(col)g_strdup_inline (col));
3170 clp = clp->next;
3171 }
3172
3173 capture_column_str = join_string_list(col_l);
3174 prefs_clear_string_list(col_l);
3175 return capture_column_str;
3176}
3177
3178static prefs_set_pref_e
3179colorized_frame_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
3180{
3181 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
3182 return PREFS_SET_OK;
3183}
3184
3185static const char *
3186colorized_frame_type_name_cb(void)
3187{
3188 /* Don't write the colors of the 10 easy-access-colorfilters to the preferences
3189 * file until the colors can be changed in the GUI. Currently this is not really
3190 * possible since the STOCK-icons for these colors are hardcoded.
3191 *
3192 * XXX Find a way to change the colors of the STOCK-icons on the fly and then
3193 * add these 10 colors to the list of colors that can be changed through
3194 * the preferences.
3195 *
3196 */
3197 return NULL((void*)0);
3198}
3199
3200static char *
3201colorized_frame_type_description_cb(void)
3202{
3203 return g_strdup("")g_strdup_inline ("");
3204}
3205
3206static bool_Bool
3207colorized_frame_is_default_cb(pref_t* pref _U___attribute__((unused)))
3208{
3209 return true1;
3210}
3211
3212static char *
3213colorized_frame_to_str_cb(pref_t* pref _U___attribute__((unused)), bool_Bool default_val _U___attribute__((unused)))
3214{
3215 return g_strdup("")g_strdup_inline ("");
3216}
3217
3218/*
3219 * Register all non-dissector modules' preferences.
3220 */
3221static module_t *gui_module;
3222static module_t *gui_color_module;
3223static module_t *nameres_module;
3224
3225static void
3226prefs_register_modules(void)
3227{
3228 module_t *printing, *capture_module, *console_module,
3229 *gui_layout_module, *gui_font_module;
3230 module_t *extcap_module;
3231 unsigned int layout_gui_flags;
3232 struct pref_custom_cbs custom_cbs;
3233
3234 if (protocols_module != NULL((void*)0)) {
3235 /* Already setup preferences */
3236 return;
3237 }
3238
3239 /* GUI
3240 * These are "simple" GUI preferences that can be read/written using the
3241 * preference module API. These preferences still use their own
3242 * configuration screens for access, but this cuts down on the
3243 * preference "string compare list" in set_pref()
3244 */
3245 extcap_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "extcap", "Extcap Utilities",
3246 "Extcap Utilities", NULL((void*)0), NULL((void*)0), false0);
3247
3248 /* Setting default value to true */
3249 prefs.extcap_save_on_start = true1;
3250 prefs_register_bool_preference(extcap_module, "gui_save_on_start",
3251 "Save arguments on start of capture",
3252 "Save arguments on start of capture",
3253 &prefs.extcap_save_on_start);
3254
3255 /* GUI
3256 * These are "simple" GUI preferences that can be read/written using the
3257 * preference module API. These preferences still use their own
3258 * configuration screens for access, but this cuts down on the
3259 * preference "string compare list" in set_pref()
3260 */
3261 gui_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "gui", "User Interface",
3262 "User Interface", NULL((void*)0), &gui_callback, false0);
3263 /*
3264 * The GUI preferences don't affect dissection in general.
3265 * Any changes are signaled in other ways, so PREF_EFFECT_GUI doesn't
3266 * explicitly do anything, but wslua_set_preference expects *some*
3267 * effect flag to be set if the preference was changed.
3268 * We have to do this again for all the submodules (except for the
3269 * layout submodule, which has its own effect flag).
3270 */
3271 unsigned gui_effect_flags = prefs_get_module_effect_flags(gui_module);
3272 gui_effect_flags |= PREF_EFFECT_GUI(1u << 4);
3273 gui_effect_flags &= (~PREF_EFFECT_DISSECTION(1u << 0));
3274 prefs_set_module_effect_flags(gui_module, gui_effect_flags);
3275
3276 /*
3277 * gui.console_open is stored in the registry in addition to the
3278 * preferences file. It is also read independently by ws_log_init()
3279 * for early log initialization of the console.
3280 */
3281 prefs_register_enum_preference(gui_module, "console_open",
3282 "Open a console window",
3283 "Open a console window (Windows only)",
3284 (int *)&ws_log_console_open, gui_console_open_type, false0);
3285
3286 prefs_register_obsolete_preference(gui_module, "scrollbar_on_right");
3287 prefs_register_obsolete_preference(gui_module, "packet_list_sel_browse");
3288 prefs_register_obsolete_preference(gui_module, "protocol_tree_sel_browse");
3289 prefs_register_obsolete_preference(gui_module, "tree_view_altern_colors");
3290 prefs_register_obsolete_preference(gui_module, "expert_composite_eyecandy");
3291 prefs_register_obsolete_preference(gui_module, "filter_toolbar_show_in_statusbar");
3292
3293 prefs_register_bool_preference(gui_module, "restore_filter_after_following_stream",
3294 "Restore current display filter after following a stream",
3295 "Restore current display filter after following a stream?",
3296 &prefs.restore_filter_after_following_stream);
3297
3298 prefs_register_obsolete_preference(gui_module, "protocol_tree_line_style");
3299
3300 prefs_register_obsolete_preference(gui_module, "protocol_tree_expander_style");
3301
3302 prefs_register_obsolete_preference(gui_module, "hex_dump_highlight_style");
3303
3304 prefs_register_obsolete_preference(gui_module, "packet_editor.enabled");
3305
3306 gui_column_module = prefs_register_subtree(gui_module, prefs_modules, "Columns", "Columns", NULL((void*)0));
3307 prefs_set_module_effect_flags(gui_column_module, gui_effect_flags);
3308 /* For reading older preference files with "column." preferences */
3309 prefs_register_module_alias("column", gui_column_module);
3310
3311
3312 custom_cbs.free_cb = free_string_like_preference;
3313 custom_cbs.reset_cb = reset_string_like_preference;
3314 custom_cbs.set_cb = column_hidden_set_cb;
3315 custom_cbs.type_name_cb = column_hidden_type_name_cb;
3316 custom_cbs.type_description_cb = column_hidden_type_description_cb;
3317 custom_cbs.is_default_cb = column_hidden_is_default_cb;
3318 custom_cbs.to_str_cb = column_hidden_to_str_cb;
3319 register_string_like_preference(gui_column_module, PRS_COL_HIDDEN"column.hide", "Packet list hidden columns",
3320 "List all column indices (1-indexed) to hide in the packet list",
3321 &cols_hidden_list, PREF_CUSTOM, &custom_cbs, false0);
3322
3323 custom_cbs.set_cb = column_hidden_fmt_set_cb;
3324 custom_cbs.type_name_cb = column_hidden_fmt_type_name_cb;
3325 custom_cbs.type_description_cb = column_hidden_fmt_type_description_cb;
3326 custom_cbs.is_default_cb = column_hidden_fmt_is_default_cb;
3327 custom_cbs.to_str_cb = column_hidden_fmt_to_str_cb;
3328
3329 register_string_like_preference(gui_column_module, PRS_COL_HIDDEN_FMT"column.hidden", "Packet list hidden column formats (deprecated)",
3330 "List all column formats to hide in the packet list; deprecated in favor of the index-based preference",
3331 &cols_hidden_fmt_list, PREF_CUSTOM, &custom_cbs, false0);
3332
3333 custom_cbs.free_cb = column_format_free_cb;
3334 custom_cbs.reset_cb = column_format_reset_cb;
3335 custom_cbs.set_cb = column_format_set_cb;
3336 custom_cbs.type_name_cb = column_format_type_name_cb;
3337 custom_cbs.type_description_cb = column_format_type_description_cb;
3338 custom_cbs.is_default_cb = column_format_is_default_cb;
3339 custom_cbs.to_str_cb = column_format_to_str_cb;
3340
3341 prefs_register_list_custom_preference(gui_column_module, PRS_COL_FMT"column.format", "Packet list column format",
3342 "Each pair of strings consists of a column title and its format", &custom_cbs,
3343 column_format_init_cb, &prefs.col_list);
3344
3345 /* Number of columns. This is only used internally and is not written to the
3346 * preference file
3347 */
3348 custom_cbs.free_cb = custom_pref_no_cb;
3349 custom_cbs.reset_cb = column_num_reset_cb;
3350 custom_cbs.set_cb = column_num_set_cb;
3351 custom_cbs.type_name_cb = column_num_type_name_cb;
3352 custom_cbs.type_description_cb = column_num_type_description_cb;
3353 custom_cbs.is_default_cb = column_num_is_default_cb;
3354 custom_cbs.to_str_cb = column_num_to_str_cb;
3355 prefs_register_uint_custom_preference(gui_column_module, PRS_COL_NUM"column.number", "Number of columns",
3356 "Number of columns in col_list", &custom_cbs, &prefs.num_cols);
3357
3358 /* User Interface : Font */
3359 gui_font_module = prefs_register_subtree(gui_module, prefs_modules, "Font", "Font", NULL((void*)0));
3360 prefs_set_module_effect_flags(gui_font_module, gui_effect_flags);
3361
3362 prefs_register_obsolete_preference(gui_font_module, "font_name");
3363
3364 prefs_register_obsolete_preference(gui_font_module, "gtk2.font_name");
3365
3366 register_string_like_preference(gui_font_module, "qt.font_name", "Font name",
3367 "Font name for packet list, protocol tree, and hex dump panes. (Qt)",
3368 &prefs.gui_font_name, PREF_STRING, NULL((void*)0), true1);
3369
3370 /* User Interface : Colors */
3371 gui_color_module = prefs_register_subtree(gui_module, prefs_modules, "Colors", "Colors", NULL((void*)0));
3372 unsigned gui_color_effect_flags = gui_effect_flags | PREF_EFFECT_GUI_COLOR(1u << 5);
3373 prefs_set_module_effect_flags(gui_color_module, gui_color_effect_flags);
3374
3375 prefs_register_enum_preference(gui_color_module, "color_scheme", "Color scheme", "Color scheme",
3376 &prefs.gui_color_scheme, gui_color_scheme, false0);
3377
3378 prefs_register_color_preference(gui_color_module, "active_frame.fg", "Foreground color for an active selected item",
3379 "Foreground color for an active selected item", &prefs.gui_active_fg);
3380
3381 prefs_register_color_preference(gui_color_module, "active_frame.bg", "Background color for an active selected item",
3382 "Background color for an active selected item", &prefs.gui_active_bg);
3383
3384 prefs_register_enum_preference(gui_color_module, "active_frame.style", "Color style for an active selected item",
3385 "Color style for an active selected item", &prefs.gui_active_style, gui_selection_style, false0);
3386
3387 prefs_register_color_preference(gui_color_module, "inactive_frame.fg", "Foreground color for an inactive selected item",
3388 "Foreground color for an inactive selected item", &prefs.gui_inactive_fg);
3389
3390 prefs_register_color_preference(gui_color_module, "inactive_frame.bg", "Background color for an inactive selected item",
3391 "Background color for an inactive selected item", &prefs.gui_inactive_bg);
3392
3393 prefs_register_enum_preference(gui_color_module, "inactive_frame.style", "Color style for an inactive selected item",
3394 "Color style for an inactive selected item", &prefs.gui_inactive_style, gui_selection_style, false0);
3395
3396 prefs_register_color_preference(gui_color_module, "marked_frame.fg", "Color preferences for a marked frame",
3397 "Color preferences for a marked frame", &prefs.gui_marked_fg);
3398
3399 prefs_register_color_preference(gui_color_module, "marked_frame.bg", "Color preferences for a marked frame",
3400 "Color preferences for a marked frame", &prefs.gui_marked_bg);
3401
3402 prefs_register_color_preference(gui_color_module, "ignored_frame.fg", "Color preferences for a ignored frame",
3403 "Color preferences for a ignored frame", &prefs.gui_ignored_fg);
3404
3405 prefs_register_color_preference(gui_color_module, "ignored_frame.bg", "Color preferences for a ignored frame",
3406 "Color preferences for a ignored frame", &prefs.gui_ignored_bg);
3407
3408 prefs_register_color_preference(gui_color_module, "stream.client.fg", "TCP stream window color preference",
3409 "TCP stream window color preference", &prefs.st_client_fg);
3410
3411 prefs_register_color_preference(gui_color_module, "stream.client.bg", "TCP stream window color preference",
3412 "TCP stream window color preference", &prefs.st_client_bg);
3413
3414 prefs_register_color_preference(gui_color_module, "stream.server.fg", "TCP stream window color preference",
3415 "TCP stream window color preference", &prefs.st_server_fg);
3416
3417 prefs_register_color_preference(gui_color_module, "stream.server.bg", "TCP stream window color preference",
3418 "TCP stream window color preference", &prefs.st_server_bg);
3419
3420 custom_cbs.free_cb = free_string_like_preference;
3421 custom_cbs.reset_cb = reset_string_like_preference;
3422 custom_cbs.set_cb = colorized_frame_set_cb;
3423 custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3424 custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3425 custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3426 custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3427 register_string_like_preference(gui_column_module, "colorized_frame.fg", "Colorized Foreground",
3428 "Filter Colorized Foreground",
3429 &prefs.gui_colorized_fg, PREF_CUSTOM, &custom_cbs, true1);
3430
3431 custom_cbs.free_cb = free_string_like_preference;
3432 custom_cbs.reset_cb = reset_string_like_preference;
3433 custom_cbs.set_cb = colorized_frame_set_cb;
3434 custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3435 custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3436 custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3437 custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3438 register_string_like_preference(gui_column_module, "colorized_frame.bg", "Colorized Background",
3439 "Filter Colorized Background",
3440 &prefs.gui_colorized_bg, PREF_CUSTOM, &custom_cbs, true1);
3441
3442 prefs_register_color_preference(gui_color_module, "color_filter_fg.valid", "Valid color filter foreground",
3443 "Valid color filter foreground", &prefs.gui_filter_valid_fg);
3444 prefs_register_color_preference(gui_color_module, "color_filter_bg.valid", "Valid color filter background",
3445 "Valid color filter background", &prefs.gui_filter_valid_bg);
3446
3447 prefs_register_color_preference(gui_color_module, "color_filter_fg.invalid", "Invalid color filter foreground",
3448 "Invalid color filter foreground", &prefs.gui_filter_invalid_fg);
3449 prefs_register_color_preference(gui_color_module, "color_filter_bg.invalid", "Invalid color filter background",
3450 "Invalid color filter background", &prefs.gui_filter_invalid_bg);
3451
3452 prefs_register_color_preference(gui_color_module, "color_filter_fg.deprecated", "Deprecated color filter foreground",
3453 "Deprecated color filter foreground", &prefs.gui_filter_deprecated_fg);
3454 prefs_register_color_preference(gui_color_module, "color_filter_bg.deprecated", "Deprecated color filter background",
3455 "Deprecated color filter background", &prefs.gui_filter_deprecated_bg);
3456
3457 prefs_register_enum_preference(gui_module, "fileopen.style",
3458 "Where to start the File Open dialog box",
3459 "Where to start the File Open dialog box",
3460 (int*)&prefs.gui_fileopen_style, gui_fileopen_style, false0);
3461
3462 prefs_register_uint_preference(gui_module, "recent_files_count.max",
3463 "The max. number of items in the open recent files list",
3464 "The max. number of items in the open recent files list",
3465 10,
3466 &prefs.gui_recent_files_count_max);
3467
3468 prefs_register_uint_preference(gui_module, "recent_display_filter_entries.max",
3469 "The max. number of entries in the display filter list",
3470 "The max. number of entries in the display filter list",
3471 10,
3472 &prefs.gui_recent_df_entries_max);
3473
3474 register_string_like_preference(gui_module, "fileopen.dir", "Start Directory",
3475 "Directory to start in when opening File Open dialog.",
3476 &prefs.gui_fileopen_dir, PREF_DIRNAME, NULL((void*)0), true1);
3477
3478 prefs_register_obsolete_preference(gui_module, "fileopen.remembered_dir");
3479
3480 prefs_register_uint_preference(gui_module, "fileopen.preview",
3481 "The preview timeout in the File Open dialog",
3482 "The preview timeout in the File Open dialog",
3483 10,
3484 &prefs.gui_fileopen_preview);
3485
3486 register_string_like_preference(gui_module, "tlskeylog_command", "Program to launch with TLS Keylog",
3487 "Program path or command line to launch with SSLKEYLOGFILE",
3488 &prefs.gui_tlskeylog_command, PREF_STRING, NULL((void*)0), true1);
3489
3490 prefs_register_bool_preference(gui_module, "ask_unsaved",
3491 "Ask to save unsaved capture files",
3492 "Ask to save unsaved capture files?",
3493 &prefs.gui_ask_unsaved);
3494
3495 prefs_register_bool_preference(gui_module, "autocomplete_filter",
3496 "Display autocompletion for filter text",
3497 "Display an autocomplete suggestion for display and capture filter controls",
3498 &prefs.gui_autocomplete_filter);
3499
3500 prefs_register_bool_preference(gui_module, "find_wrap",
3501 "Wrap to beginning/end of file during search",
3502 "Wrap to beginning/end of file during search?",
3503 &prefs.gui_find_wrap);
3504
3505 prefs_register_obsolete_preference(gui_module, "use_pref_save");
3506
3507 prefs_register_bool_preference(gui_module, "geometry.save.position",
3508 "Save window position at exit",
3509 "Save window position at exit?",
3510 &prefs.gui_geometry_save_position);
3511
3512 prefs_register_bool_preference(gui_module, "geometry.save.size",
3513 "Save window size at exit",
3514 "Save window size at exit?",
3515 &prefs.gui_geometry_save_size);
3516
3517 prefs_register_bool_preference(gui_module, "geometry.save.maximized",
3518 "Save window maximized state at exit",
3519 "Save window maximized state at exit?",
3520 &prefs.gui_geometry_save_maximized);
3521
3522 prefs_register_obsolete_preference(gui_module, "macosx_style");
3523
3524 prefs_register_obsolete_preference(gui_module, "geometry.main.x");
3525 prefs_register_obsolete_preference(gui_module, "geometry.main.y");
3526 prefs_register_obsolete_preference(gui_module, "geometry.main.width");
3527 prefs_register_obsolete_preference(gui_module, "geometry.main.height");
3528 prefs_register_obsolete_preference(gui_module, "toolbar_main_show");
3529
3530 prefs_register_enum_preference(gui_module, "toolbar_main_style",
3531 "Main Toolbar style",
3532 "Main Toolbar style",
3533 &prefs.gui_toolbar_main_style, gui_toolbar_style, false0);
3534
3535 prefs_register_obsolete_preference(gui_module, "toolbar_filter_style");
3536 prefs_register_obsolete_preference(gui_module, "webbrowser");
3537
3538 prefs_register_bool_preference(gui_module, "update.enabled",
3539 "Check for updates",
3540 "Check for updates (Windows and macOS only)",
3541 &prefs.gui_update_enabled);
3542
3543 prefs_register_enum_preference(gui_module, "update.channel",
3544 "Update channel",
3545 "The type of update to fetch. You should probably leave this set to STABLE.",
3546 (int*)(void*)(&prefs.gui_update_channel), gui_update_channel, false0);
3547
3548 prefs_register_uint_preference(gui_module, "update.interval",
3549 "How often to check for software updates",
3550 "How often to check for software updates in seconds",
3551 10,
3552 &prefs.gui_update_interval);
3553
3554 prefs_register_uint_preference(gui_module, "debounce.timer",
3555 "How long to wait before processing computationally intensive user input",
3556 "How long to wait (in milliseconds) before processing "
3557 "computationally intensive user input. "
3558 "If you type quickly, consider lowering the value for a 'snappier' "
3559 "experience. "
3560 "If you type slowly, consider increasing the value to avoid performance issues. "
3561 "This is currently used to delay searches in View -> Internals -> Supported Protocols "
3562 "and Preferences -> Advanced menu.",
3563 10,
3564 &prefs.gui_debounce_timer);
3565
3566 register_string_like_preference(gui_module, "window_title", "Custom window title",
3567 "Custom window title to be appended to the existing title\n"
3568 "%C = capture comment from command line\n"
3569 "%F = file path of the capture file\n"
3570 "%P = profile name\n"
3571 "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3572 "%V = version info",
3573 &prefs.gui_window_title, PREF_STRING, NULL((void*)0), true1);
3574
3575 register_string_like_preference(gui_module, "prepend_window_title", "Custom window title prefix",
3576 "Custom window title to be prepended to the existing title\n"
3577 "%C = capture comment from command line\n"
3578 "%F = file path of the capture file\n"
3579 "%P = profile name\n"
3580 "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3581 "%V = version info",
3582 &prefs.gui_prepend_window_title, PREF_STRING, NULL((void*)0), true1);
3583
3584 register_string_like_preference(gui_module, "start_title", "Custom start page title",
3585 "Custom start page title",
3586 &prefs.gui_start_title, PREF_STRING, NULL((void*)0), true1);
3587
3588 prefs_register_enum_preference(gui_module, "version_placement",
3589 "Show version in the start page and/or main screen's title bar",
3590 "Show version in the start page and/or main screen's title bar",
3591 (int*)(void*)(&prefs.gui_version_placement), gui_version_placement_type, false0);
3592
3593 prefs_register_obsolete_preference(gui_module, "auto_scroll_on_expand");
3594 prefs_register_obsolete_preference(gui_module, "auto_scroll_percentage");
3595
3596 prefs_register_uint_preference(gui_module, "max_export_objects",
3597 "Maximum number of exported objects",
3598 "The maximum number of objects that can be exported",
3599 10,
3600 &prefs.gui_max_export_objects);
3601 prefs_register_uint_preference(gui_module, "max_tree_items",
3602 "Maximum number of tree items",
3603 "The maximum number of items that can be added to the dissection tree (Increase with caution)",
3604 10,
3605 &prefs.gui_max_tree_items);
3606 /*
3607 * Used independently by proto_tree_add_node, call_dissector*, dissector_try_heuristic,
3608 * and increment_dissection_depth.
3609 */
3610 prefs_register_uint_preference(gui_module, "max_tree_depth",
3611 "Maximum dissection depth",
3612 "The maximum depth for dissection tree and protocol layer checks. (Increase with caution)",
3613 10,
3614 &prefs.gui_max_tree_depth);
3615
3616 prefs_register_bool_preference(gui_module, "welcome_page.show_recent",
3617 "Show recent files on the welcome page",
3618 "This will enable or disable the 'Open' list on the welcome page.",
3619 &prefs.gui_welcome_page_show_recent);
3620
3621 /* User Interface : Layout */
3622 gui_layout_module = prefs_register_subtree(gui_module, prefs_modules, "Layout", "Layout", gui_layout_callback);
3623 /* Adjust the preference effects of layout GUI for better handling of preferences at Wireshark (GUI) level */
3624 layout_gui_flags = prefs_get_module_effect_flags(gui_layout_module);
3625 layout_gui_flags |= PREF_EFFECT_GUI_LAYOUT(1u << 2);
3626 layout_gui_flags &= (~PREF_EFFECT_DISSECTION(1u << 0));
3627
3628 prefs_register_uint_preference(gui_layout_module, "layout_type",
3629 "Layout type",
3630 "Layout type (1-6)",
3631 10,
3632 (unsigned*)(void*)(&prefs.gui_layout_type));
3633 prefs_set_effect_flags_by_name(gui_layout_module, "layout_type", layout_gui_flags);
3634
3635 prefs_register_enum_preference(gui_layout_module, "layout_content_1",
3636 "Layout content of the pane 1",
3637 "Layout content of the pane 1",
3638 (int*)(void*)(&prefs.gui_layout_content_1), gui_layout_content, false0);
3639 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_1", layout_gui_flags);
3640
3641 prefs_register_enum_preference(gui_layout_module, "layout_content_2",
3642 "Layout content of the pane 2",
3643 "Layout content of the pane 2",
3644 (int*)(void*)(&prefs.gui_layout_content_2), gui_layout_content, false0);
3645 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_2", layout_gui_flags);
3646
3647 prefs_register_enum_preference(gui_layout_module, "layout_content_3",
3648 "Layout content of the pane 3",
3649 "Layout content of the pane 3",
3650 (int*)(void*)(&prefs.gui_layout_content_3), gui_layout_content, false0);
3651 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_3", layout_gui_flags);
3652
3653 prefs_register_bool_preference(gui_layout_module, "packet_list_separator.enabled",
3654 "Enable Packet List Separator",
3655 "Enable Packet List Separator",
3656 &prefs.gui_packet_list_separator);
3657
3658 prefs_register_bool_preference(gui_layout_module, "packet_header_column_definition.enabled",
3659 "Show column definition in packet list header",
3660 "Show column definition in packet list header",
3661 &prefs.gui_packet_header_column_definition);
3662
3663 /* packet_list_hover_style affects the colors, not the layout.
3664 * It's in the layout module to group it with the other packet list
3665 * preferences for the user's benefit with the dialog.
3666 */
3667 prefs_register_bool_preference(gui_layout_module, "packet_list_hover_style.enabled",
3668 "Enable Packet List mouse-over colorization",
3669 "Enable Packet List mouse-over colorization",
3670 &prefs.gui_packet_list_hover_style);
3671 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_hover_style.enabled", gui_color_effect_flags);
3672
3673 prefs_register_bool_preference(gui_layout_module, "show_selected_packet.enabled",
3674 "Show selected packet in the Status Bar",
3675 "Show selected packet in the Status Bar",
3676 &prefs.gui_show_selected_packet);
3677
3678 prefs_register_bool_preference(gui_layout_module, "show_file_load_time.enabled",
3679 "Show file load time in the Status Bar",
3680 "Show file load time in the Status Bar",
3681 &prefs.gui_show_file_load_time);
3682
3683 prefs_register_enum_preference(gui_layout_module, "packet_dialog_layout",
3684 "Packet Dialog layout",
3685 "Packet Dialog layout",
3686 (int*)(&prefs.gui_packet_dialog_layout), gui_packet_dialog_layout, false0);
3687
3688 prefs_register_enum_preference(gui_module, "packet_list_elide_mode",
3689 "Elide mode",
3690 "The position of \"...\" (ellipsis) in packet list text.",
3691 (int*)(void*)(&prefs.gui_packet_list_elide_mode), gui_packet_list_elide_mode, false0);
3692 prefs_register_uint_preference(gui_module, "decimal_places1",
3693 "Count of decimal places for values of type 1",
3694 "Sets the count of decimal places for values of type 1."
3695 "Type 1 values are defined by authors."
3696 "Value can be in range 2 to 10.",
3697 10,&prefs.gui_decimal_places1);
3698
3699 prefs_register_uint_preference(gui_module, "decimal_places2",
3700 "Count of decimal places for values of type 2",
3701 "Sets the count of decimal places for values of type 2."
3702 "Type 2 values are defined by authors."
3703 "Value can be in range 2 to 10.",
3704 10,&prefs.gui_decimal_places2);
3705
3706 prefs_register_uint_preference(gui_module, "decimal_places3",
3707 "Count of decimal places for values of type 3",
3708 "Sets the count of decimal places for values of type 3."
3709 "Type 3 values are defined by authors."
3710 "Value can be in range 2 to 10.",
3711 10,&prefs.gui_decimal_places3);
3712
3713 prefs_register_bool_preference(gui_module, "rtp_player_use_disk1",
3714 "RTP Player saves temporary data to disk",
3715 "If set to true, RTP Player saves temporary data to "
3716 "temp files on disk. If not set, it uses memory."
3717 "Every stream uses one file therefore you might touch "
3718 "OS limit for count of opened files."
3719 "When ui.rtp_player_use_disk2 is set to true too, it uses "
3720 " two files per RTP stream together."
3721 ,&prefs.gui_rtp_player_use_disk1);
3722
3723 prefs_register_bool_preference(gui_module, "rtp_player_use_disk2",
3724 "RTP Player saves temporary dictionary for data to disk",
3725 "If set to true, RTP Player saves temporary dictionary to "
3726 "temp files on disk. If not set, it uses memory."
3727 "Every stream uses one file therefore you might touch "
3728 "OS limit for count of opened files."
3729 "When ui.rtp_player_use_disk1 is set to true too, it uses "
3730 " two files per RTP stream."
3731 ,&prefs.gui_rtp_player_use_disk2);
3732
3733 prefs_register_enum_preference(gui_layout_module, "gui_packet_list_copy_format_options_for_keyboard_shortcut",
3734 "Allows text to be copied with selected format",
3735 "Allows text to be copied with selected format when copied via keyboard",
3736 (int*)(void*)(&prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut),
3737 gui_packet_list_copy_format_options_for_keyboard_shortcut, false0);
3738
3739 prefs_register_bool_preference(gui_layout_module, "gui_packet_list_copy_text_with_aligned_columns",
3740 "Allows text to be copied with aligned columns",
3741 "Allows text to be copied with aligned columns when copied via menu or keyboard",
3742 &prefs.gui_packet_list_copy_text_with_aligned_columns);
3743
3744 prefs_register_bool_preference(gui_layout_module, "packet_list_show_related",
3745 "Show Related Packets",
3746 "Show related packet indicators in the first column",
3747 &prefs.gui_packet_list_show_related);
3748
3749 prefs_register_bool_preference(gui_layout_module, "packet_list_show_minimap",
3750 "Enable Intelligent Scroll Bar",
3751 "Show the intelligent scroll bar (a minimap of packet list colors in the scrollbar)",
3752 &prefs.gui_packet_list_show_minimap);
3753
3754 prefs_register_bool_preference(gui_module, "packet_list_is_sortable",
3755 "Allow packet list to be sortable",
3756 "To prevent sorting by mistake (which can take some time to calculate), it can be disabled",
3757 &prefs.gui_packet_list_sortable);
3758
3759 prefs_register_uint_preference(gui_module, "packet_list_cached_rows_max",
3760 "Maximum cached rows",
3761 "Maximum number of rows that can be sorted by columns that require dissection. Increasing this increases memory consumption by caching column text",
3762 10,
3763 &prefs.gui_packet_list_cached_rows_max);
3764
3765 prefs_register_bool_preference(gui_module, "interfaces_show_hidden",
3766 "Show hidden interfaces",
3767 "Show all interfaces, including interfaces marked as hidden",
3768 &prefs.gui_interfaces_show_hidden);
3769
3770 prefs_register_bool_preference(gui_module, "interfaces_remote_display",
3771 "Show Remote interfaces",
3772 "Show remote interfaces in the interface selection",
3773 &prefs.gui_interfaces_remote_display);
3774
3775 register_string_like_preference(gui_module, "interfaces_hidden_types", "Hide interface types in list",
3776 "Hide the given interface types in the startup list.\n"
3777 "A comma-separated string of interface type values (e.g. 5,9).\n"
3778 "0 = Wired,\n"
3779 "1 = AirPCAP,\n"
3780 "2 = Pipe,\n"
3781 "3 = STDIN,\n"
3782 "4 = Bluetooth,\n"
3783 "5 = Wireless,\n"
3784 "6 = Dial-Up,\n"
3785 "7 = USB,\n"
3786 "8 = External Capture,\n"
3787 "9 = Virtual",
3788 &prefs.gui_interfaces_hide_types, PREF_STRING, NULL((void*)0), true1);
3789
3790 prefs_register_bool_preference(gui_module, "io_graph_automatic_update",
3791 "Enables automatic updates for IO Graph",
3792 "Enables automatic updates for IO Graph",
3793 &prefs.gui_io_graph_automatic_update);
3794
3795 prefs_register_bool_preference(gui_module, "io_graph_enable_legend",
3796 "Enables the legend of IO Graph",
3797 "Enables the legend of IO Graph",
3798 &prefs.gui_io_graph_enable_legend);
3799
3800 prefs_register_bool_preference(gui_module, "plot_automatic_update",
3801 "Enables automatic updates for Plot",
3802 "Enables automatic updates for Plot",
3803 &prefs.gui_plot_automatic_update);
3804
3805 prefs_register_bool_preference(gui_module, "plot_enable_legend",
3806 "Enables the legend of Plot",
3807 "Enables the legend of Plot",
3808 &prefs.gui_plot_enable_legend);
3809
3810 prefs_register_bool_preference(gui_module, "plot_enable_auto_scroll",
3811 "Enables auto scroll of Plot",
3812 "Enables auto scroll of Plot",
3813 &prefs.gui_plot_enable_auto_scroll);
3814
3815 prefs_register_bool_preference(gui_module, "show_byteview_in_dialog",
3816 "Show the byte view in the packet details dialog",
3817 "Show the byte view in the packet details dialog",
3818 &prefs.gui_packet_details_show_byteview);
3819
3820 /* Console
3821 * These are preferences that can be read/written using the
3822 * preference module API. These preferences still use their own
3823 * configuration screens for access, but this cuts down on the
3824 * preference "string compare list" in set_pref()
3825 */
3826 console_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "console", "Console",
3827 "Console logging and debugging output", NULL((void*)0), NULL((void*)0), false0);
3828
3829 prefs_register_obsolete_preference(console_module, "log.level");
3830
3831 prefs_register_bool_preference(console_module, "incomplete_dissectors_check_debug",
3832 "Print debug line for incomplete dissectors",
3833 "Look for dissectors that left some bytes undecoded (debug)",
3834 &prefs.incomplete_dissectors_check_debug);
3835
3836 /* Display filter Expressions
3837 * This used to be an array of individual fields that has now been
3838 * converted to a UAT. Just make it part of the GUI category even
3839 * though the name of the preference will never be seen in preference
3840 * file
3841 */
3842 filter_expression_register_uat(gui_module);
3843
3844 /* Capture
3845 * These are preferences that can be read/written using the
3846 * preference module API. These preferences still use their own
3847 * configuration screens for access, but this cuts down on the
3848 * preference "string compare list" in set_pref()
3849 */
3850 capture_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "capture", "Capture",
3851 "Capture preferences", NULL((void*)0), apply_aggregation_prefs, false0);
3852 /* Capture preferences don't affect dissection */
3853 prefs_set_module_effect_flags(capture_module, PREF_EFFECT_CAPTURE(1u << 1));
3854
3855 register_string_like_preference(capture_module, "device", "Default capture device",
3856 "Default capture device",
3857 &prefs.capture_device, PREF_STRING, NULL((void*)0), false0);
3858
3859 register_string_like_preference(capture_module, "devices_linktypes", "Interface link-layer header type",
3860 "Interface link-layer header types (Ex: en0(1),en1(143),...)",
3861 &prefs.capture_devices_linktypes, PREF_STRING, NULL((void*)0), false0);
3862
3863 register_string_like_preference(capture_module, "devices_descr", "Interface descriptions",
3864 "Interface descriptions (Ex: eth0(eth0 descr),eth1(eth1 descr),...)",
3865 &prefs.capture_devices_descr, PREF_STRING, NULL((void*)0), false0);
3866
3867 register_string_like_preference(capture_module, "devices_hide", "Hide interface",
3868 "Hide interface? (Ex: eth0,eth3,...)",
3869 &prefs.capture_devices_hide, PREF_STRING, NULL((void*)0), false0);
3870
3871 register_string_like_preference(capture_module, "devices_monitor_mode", "Capture in monitor mode",
3872 "By default, capture in monitor mode on interface? (Ex: eth0,eth3,...)",
3873 &prefs.capture_devices_monitor_mode, PREF_STRING, NULL((void*)0), false0);
3874
3875 register_string_like_preference(capture_module, "devices_buffersize", "Interface buffer size",
3876 "Interface buffer size (Ex: en0(1),en1(143),...)",
3877 &prefs.capture_devices_buffersize, PREF_STRING, NULL((void*)0), false0);
3878
3879 register_string_like_preference(capture_module, "devices_snaplen", "Interface snap length",
3880 "Interface snap length (Ex: en0(65535),en1(1430),...)",
3881 &prefs.capture_devices_snaplen, PREF_STRING, NULL((void*)0), false0);
3882
3883 register_string_like_preference(capture_module, "devices_pmode", "Interface promiscuous mode",
3884 "Interface promiscuous mode (Ex: en0(0),en1(1),...)",
3885 &prefs.capture_devices_pmode, PREF_STRING, NULL((void*)0), false0);
3886
3887 prefs_register_bool_preference(capture_module, "prom_mode", "Capture in promiscuous mode",
3888 "Capture in promiscuous mode?", &prefs.capture_prom_mode);
3889
3890 prefs_register_bool_preference(capture_module, "monitor_mode", "Capture in monitor mode on 802.11 devices",
3891 "Capture in monitor mode on all 802.11 devices that support it?", &prefs.capture_monitor_mode);
3892
3893 register_string_like_preference(capture_module, "devices_filter", "Interface capture filter",
3894 "Interface capture filter (Ex: en0(tcp),en1(udp),...)",
3895 &prefs.capture_devices_filter, PREF_STRING, NULL((void*)0), false0);
3896
3897 prefs_register_bool_preference(capture_module, "pcap_ng", "Capture in pcapng format",
3898 "Capture in pcapng format?", &prefs.capture_pcap_ng);
3899
3900 prefs_register_bool_preference(capture_module, "real_time_update", "Update packet list in real time during capture",
3901 "Update packet list in real time during capture?", &prefs.capture_real_time);
3902
3903 prefs_register_uint_preference(capture_module, "update_interval",
3904 "Capture update interval",
3905 "Capture update interval in ms",
3906 10,
3907 &prefs.capture_update_interval);
3908
3909 prefs_register_bool_preference(capture_module, "enable_aggregation_view", "Enable aggregation view",
3910 "Enable Aggregation View for real-time capturing", &prefs.enable_aggregation);
3911
3912 prefs_register_bool_preference(capture_module, "no_interface_load", "Don't load interfaces on startup",
3913 "Don't automatically load capture interfaces on startup", &prefs.capture_no_interface_load);
3914
3915 prefs_register_bool_preference(capture_module, "no_extcap", "Disable external capture interfaces",
3916 "Disable external capture modules (extcap)", &prefs.capture_no_extcap);
3917
3918 prefs_register_obsolete_preference(capture_module, "auto_scroll");
3919
3920 prefs_register_bool_preference(capture_module, "show_info", "Show capture information dialog while capturing",
3921 "Show capture information dialog while capturing?", &prefs.capture_show_info);
3922
3923 prefs_register_obsolete_preference(capture_module, "syntax_check_filter");
3924
3925 custom_cbs.free_cb = capture_column_free_cb;
3926 custom_cbs.reset_cb = capture_column_reset_cb;
3927 custom_cbs.set_cb = capture_column_set_cb;
3928 custom_cbs.type_name_cb = capture_column_type_name_cb;
3929 custom_cbs.type_description_cb = capture_column_type_description_cb;
3930 custom_cbs.is_default_cb = capture_column_is_default_cb;
3931 custom_cbs.to_str_cb = capture_column_to_str_cb;
3932 prefs_register_list_custom_preference(capture_module, "columns", "Capture options dialog column list",
3933 "List of columns to be displayed", &custom_cbs, capture_column_init_cb, &prefs.capture_columns);
3934 aggregation_field_register_uat(capture_module);
3935
3936 /* Name Resolution */
3937 nameres_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "nameres", "Name Resolution",
3938 "Name Resolution", "ChCustPreferencesSection.html#ChCustPrefsNameSection", addr_resolve_pref_apply, true1);
3939 addr_resolve_pref_init(nameres_module);
3940 oid_pref_init(nameres_module);
3941 maxmind_db_pref_init(nameres_module);
3942
3943 /* Printing
3944 * None of these have any effect; we keep them as obsolete preferences
3945 * in order to avoid errors when reading older preference files.
3946 */
3947 printing = prefs_register_module(prefs_top_level_modules, prefs_modules, "print", "Printing",
3948 "Printing", NULL((void*)0), NULL((void*)0), false0);
3949 prefs_register_obsolete_preference(printing, "format");
3950 prefs_register_obsolete_preference(printing, "command");
3951 prefs_register_obsolete_preference(printing, "file");
3952
3953 /* Codecs */
3954 codecs_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "codecs", "Codecs",
3955 "Codecs", NULL((void*)0), NULL((void*)0), true1);
3956
3957 /* Statistics */
3958 stats_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "statistics", "Statistics",
3959 "Statistics", "ChCustPreferencesSection.html#_statistics", &stats_callback, true1);
3960
3961 prefs_register_uint_preference(stats_module, "update_interval",
3962 "Tap update interval in ms",
3963 "Determines time between tap updates",
3964 10,
3965 &prefs.tap_update_interval);
3966
3967 prefs_register_uint_preference(stats_module, "flow_graph_max_export_items",
3968 "Maximum Flow Graph items to export as image",
3969 "The maximum number of Flow Graph items (frames) "
3970 "to include when exporting the graph as an image. "
3971 "Note that some formats (e.g., JPEG) have inherent "
3972 "pixel limits and image viewers might be unable to "
3973 "handle very large images.",
3974 10,
3975 &prefs.flow_graph_max_export_items);
3976
3977 prefs_register_bool_preference(stats_module, "st_enable_burstinfo",
3978 "Enable the calculation of burst information",
3979 "If enabled burst rates will be calculated for statistics that use the stats_tree system. "
3980 "Burst rates are calculated over a much shorter time interval than the rate column.",
3981 &prefs.st_enable_burstinfo);
3982
3983 prefs_register_bool_preference(stats_module, "st_burst_showcount",
3984 "Show burst count for item rather than rate",
3985 "If selected the stats_tree statistics nodes will show the count of events "
3986 "within the burst window instead of a burst rate. Burst rate is calculated "
3987 "as number of events within burst window divided by the burst windown length.",
3988 &prefs.st_burst_showcount);
3989
3990 prefs_register_uint_preference(stats_module, "st_burst_resolution",
3991 "Burst rate resolution (ms)",
3992 "Sets the duration of the time interval into which events are grouped when calculating "
3993 "the burst rate. Higher resolution (smaller number) increases processing overhead.",
3994 10,&prefs.st_burst_resolution);
3995
3996 prefs_register_uint_preference(stats_module, "st_burst_windowlen",
3997 "Burst rate window size (ms)",
3998 "Sets the duration of the sliding window during which the burst rate is "
3999 "measured. Longer window relative to burst rate resolution increases "
4000 "processing overhead. Will be truncated to a multiple of burst resolution.",
4001 10,&prefs.st_burst_windowlen);
4002
4003 prefs_register_enum_preference(stats_module, "st_sort_defcolflag",
4004 "Default sort column for stats_tree stats",
4005 "Sets the default column by which stats based on the stats_tree "
4006 "system is sorted.",
4007 &prefs.st_sort_defcolflag, st_sort_col_vals, false0);
4008
4009 prefs_register_bool_preference(stats_module, "st_sort_defdescending",
4010 "Default stats_tree sort order is descending",
4011 "When selected, statistics based on the stats_tree system will by default "
4012 "be sorted in descending order.",
4013 &prefs.st_sort_defdescending);
4014
4015 prefs_register_bool_preference(stats_module, "st_sort_casesensitve",
4016 "Case sensitive sort of stats_tree item names",
4017 "When selected, the item/node names of statistics based on the stats_tree "
4018 "system will be sorted taking case into account. Else the case of the name "
4019 "will be ignored.",
4020 &prefs.st_sort_casesensitve);
4021
4022 prefs_register_bool_preference(stats_module, "st_sort_rng_nameonly",
4023 "Always sort 'range' nodes by name",
4024 "When selected, the stats_tree nodes representing a range of values "
4025 "(0-49, 50-100, etc.) will always be sorted by name (the range of the "
4026 "node). Else range nodes are sorted by the same column as the rest of "
4027 " the tree.",
4028 &prefs.st_sort_rng_nameonly);
4029
4030 prefs_register_bool_preference(stats_module, "st_sort_rng_fixorder",
4031 "Always sort 'range' nodes in ascending order",
4032 "When selected, the stats_tree nodes representing a range of values "
4033 "(0-49, 50-100, etc.) will always be sorted ascending; else it follows "
4034 "the sort direction of the tree. Only effective if \"Always sort "
4035 "'range' nodes by name\" is also selected.",
4036 &prefs.st_sort_rng_fixorder);
4037
4038 prefs_register_bool_preference(stats_module, "st_sort_showfullname",
4039 "Display the full stats_tree plug-in name",
4040 "When selected, the full name (including menu path) of the stats_tree "
4041 "plug-in is show in windows. If cleared the plug-in name is shown "
4042 "without menu path (only the part of the name after last '/' character.)",
4043 &prefs.st_sort_showfullname);
4044
4045 prefs_register_enum_preference(stats_module, "output_format",
4046 "Default output format",
4047 "Sets the default output format for statistical data. Only supported "
4048 "by taps using the stats_tree system currently; other taps may honor "
4049 "this preference in the future. ",
4050 &prefs.st_format, st_format_vals, false0);
4051
4052 module_t *conv_module;
4053 // avoid using prefs_register_stat to prevent lint complaint about recursion
4054 conv_module = prefs_register_submodule(stats_module, prefs_modules, "conv", "Conversations",
4055 "Conversations & Endpoints", NULL((void*)0), NULL((void*)0), true1);
4056 prefs_register_bool_preference(conv_module, "machine_readable",
4057 "Display exact (machine-readable) byte counts",
4058 "When enabled, exact machine-readable byte counts are displayed. "
4059 "When disabled, human readable numbers with SI prefixes are displayed.",
4060 &prefs.conv_machine_readable);
4061
4062 /* Protocols */
4063 protocols_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "protocols", "Protocols",
4064 "Protocols", "ChCustPreferencesSection.html#ChCustPrefsProtocolsSection", NULL((void*)0), true1);
4065
4066 prefs_register_bool_preference(protocols_module, "display_hidden_proto_items",
4067 "Display hidden protocol items",
4068 "Display all hidden protocol items in the packet list.",
4069 &prefs.display_hidden_proto_items);
4070
4071 prefs_register_bool_preference(protocols_module, "display_byte_fields_with_spaces",
4072 "Display byte fields with a space character between bytes",
4073 "Display all byte fields with a space character between each byte in the packet list.",
4074 &prefs.display_byte_fields_with_spaces);
4075
4076 /*
4077 * Note the -t / option only affects the display of the packet timestamp
4078 * in the default time column; this is for all other absolute times.
4079 */
4080 prefs_register_enum_preference(protocols_module, "display_abs_time_ascii",
4081 "Format absolute times like asctime",
4082 "When to format absolute times similar to asctime instead of ISO 8601, for backwards compatibility with older Wireshark.",
4083 (int*)&prefs.display_abs_time_ascii, abs_time_format_options, false0);
4084
4085 prefs_register_bool_preference(protocols_module, "enable_incomplete_dissectors_check",
4086 "Look for incomplete dissectors",
4087 "Look for dissectors that left some bytes undecoded.",
4088 &prefs.enable_incomplete_dissectors_check);
4089
4090 prefs_register_bool_preference(protocols_module, "strict_conversation_tracking_heuristics",
4091 "Enable stricter conversation tracking heuristics",
4092 "Protocols may use things like VLAN ID or interface ID to narrow the potential for duplicate conversations. "
4093 "Currently ICMP and ICMPv6 use this preference to add VLAN ID to conversation tracking, and IPv4 uses this preference to take VLAN ID into account during reassembly",
4094 &prefs.strict_conversation_tracking_heuristics);
4095
4096 prefs_register_bool_preference(protocols_module, "ignore_dup_frames",
4097 "Ignore duplicate frames",
4098 "Ignore frames that are exact duplicates of any previous frame.",
4099 &prefs.ignore_dup_frames);
4100
4101 prefs_register_enum_preference(protocols_module, "conversation_deinterlacing_key",
4102 "Deinterlacing conversations key",
4103 "Separate into different conversations frames that look like duplicates but have different Interface, MAC, or VLAN field values.",
4104 (int *)&prefs.conversation_deinterlacing_key, conv_deint_options, false0);
4105
4106 prefs_register_uint_preference(protocols_module, "ignore_dup_frames_cache_entries",
4107 "The max number of hashes to keep in memory for determining duplicates frames",
4108 "If \"Ignore duplicate frames\" is set, this setting sets the maximum number "
4109 "of cache entries to maintain. A 0 means no limit.",
4110 10, &prefs.ignore_dup_frames_cache_entries);
4111
4112
4113 /* Obsolete preferences
4114 * These "modules" were reorganized/renamed to correspond to their GUI
4115 * configuration screen within the preferences dialog
4116 */
4117
4118 /* taps is now part of the stats module */
4119 prefs_register_module(prefs_top_level_modules, prefs_modules, "taps", "TAPS", "TAPS", NULL((void*)0), NULL((void*)0), false0);
4120 /* packet_list is now part of the protocol (parent) module */
4121 prefs_register_module(prefs_top_level_modules, prefs_modules, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL((void*)0), NULL((void*)0), false0);
4122 /* stream is now part of the gui module */
4123 prefs_register_module(prefs_top_level_modules, prefs_modules, "stream", "STREAM", "STREAM", NULL((void*)0), NULL((void*)0), false0);
4124
4125}
4126
4127/* Parse through a list of comma-separated, possibly quoted strings.
4128 Return a list of the string data. */
4129GList *
4130prefs_get_string_list(const char *str)
4131{
4132 enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
4133
4134 int state = PRE_STRING, i = 0;
4135 bool_Bool backslash = false0;
4136 unsigned char cur_c;
4137 const size_t default_size = 64;
4138 GString *slstr = NULL((void*)0);
4139 GList *sl = NULL((void*)0);
4140
4141 /* Allocate a buffer for the first string. */
4142 slstr = g_string_sized_new(default_size);
4143
4144 for (;;) {
4145 cur_c = str[i];
4146 if (cur_c == '\0') {
4147 /* It's the end of the input, so it's the end of the string we
4148 were working on, and there's no more input. */
4149 if (state == IN_QUOT || backslash) {
4150 /* We were in the middle of a quoted string or backslash escape,
4151 and ran out of characters; that's an error. */
4152 g_string_free(slstr, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(slstr), ((!(0)))) : g_string_free_and_steal (slstr)) : (g_string_free
) ((slstr), ((!(0)))))
;
4153 prefs_clear_string_list(sl);
4154 return NULL((void*)0);
4155 }
4156 if (slstr->len > 0)
4157 sl = g_list_append(sl, g_string_free(slstr, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((slstr
), ((0))) : g_string_free_and_steal (slstr)) : (g_string_free
) ((slstr), ((0))))
);
4158 else
4159 g_string_free(slstr, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(slstr), ((!(0)))) : g_string_free_and_steal (slstr)) : (g_string_free
) ((slstr), ((!(0)))))
;
4160 break;
4161 }
4162 if (cur_c == '"' && !backslash) {
4163 switch (state) {
4164 case PRE_STRING:
4165 /* We hadn't yet started processing a string; this starts the
4166 string, and we're now quoting. */
4167 state = IN_QUOT;
4168 break;
4169 case IN_QUOT:
4170 /* We're in the middle of a quoted string, and we saw a quotation
4171 mark; we're no longer quoting. */
4172 state = NOT_IN_QUOT;
4173 break;
4174 case NOT_IN_QUOT:
4175 /* We're working on a string, but haven't seen a quote; we're
4176 now quoting. */
4177 state = IN_QUOT;
4178 break;
4179 default:
4180 break;
4181 }
4182 } else if (cur_c == '\\' && !backslash) {
4183 /* We saw a backslash, and the previous character wasn't a
4184 backslash; escape the next character.
4185
4186 This also means we've started a new string. */
4187 backslash = true1;
4188 if (state == PRE_STRING)
4189 state = NOT_IN_QUOT;
4190 } else if (cur_c == ',' && state != IN_QUOT && !backslash) {
4191 /* We saw a comma, and we're not in the middle of a quoted string
4192 and it wasn't preceded by a backslash; it's the end of
4193 the string we were working on... */
4194 if (slstr->len > 0) {
4195 sl = g_list_append(sl, g_string_free(slstr, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((slstr
), ((0))) : g_string_free_and_steal (slstr)) : (g_string_free
) ((slstr), ((0))))
);
4196 slstr = g_string_sized_new(default_size);
4197 }
4198
4199 /* ...and the beginning of a new string. */
4200 state = PRE_STRING;
4201 } else if (!g_ascii_isspace(cur_c)((g_ascii_table[(guchar) (cur_c)] & G_ASCII_SPACE) != 0) || state != PRE_STRING) {
4202 /* Either this isn't a white-space character, or we've started a
4203 string (i.e., already seen a non-white-space character for that
4204 string and put it into the string).
4205
4206 The character is to be put into the string; do so. */
4207 g_string_append_c(slstr, cur_c)g_string_append_c_inline (slstr, cur_c);
4208
4209 /* If it was backslash-escaped, we're done with the backslash escape. */
4210 backslash = false0;
4211 }
4212 i++;
4213 }
4214 return(sl);
4215}
4216
4217char *join_string_list(GList *sl)
4218{
4219 GString *joined_str = g_string_new("");
4220 GList *cur, *first;
4221 char *str;
4222 unsigned item_count = 0;
4223
4224 cur = first = g_list_first(sl);
4225 while (cur) {
4226 item_count++;
4227 str = (char *)cur->data;
4228
4229 if (cur != first)
4230 g_string_append_c(joined_str, ',')g_string_append_c_inline (joined_str, ',');
4231
4232 if (item_count % 2) {
4233 /* Wrap the line. */
4234 g_string_append(joined_str, "\n\t")(__builtin_constant_p ("\n\t") ? __extension__ ({ const char *
const __val = ("\n\t"); g_string_append_len_inline (joined_str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (joined_str
, "\n\t", (gssize) -1))
;
4235 } else
4236 g_string_append_c(joined_str, ' ')g_string_append_c_inline (joined_str, ' ');
4237
4238 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4239 while (*str) {
4240 gunichar uc = g_utf8_get_char (str);
4241
4242 if (uc == '"' || uc == '\\')
4243 g_string_append_c(joined_str, '\\')g_string_append_c_inline (joined_str, '\\');
4244
4245 if (g_unichar_isprint(uc))
4246 g_string_append_unichar (joined_str, uc);
4247
4248 str = g_utf8_next_char (str)(char *)((str) + g_utf8_skip[*(const guchar *)(str)]);
4249 }
4250
4251 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4252
4253 cur = cur->next;
4254 }
4255 return g_string_free(joined_str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((joined_str
), ((0))) : g_string_free_and_steal (joined_str)) : (g_string_free
) ((joined_str), ((0))))
;
4256}
4257
4258void
4259prefs_clear_string_list(GList *sl)
4260{
4261 g_list_free_full(sl, g_free);
4262}
4263
4264/*
4265 * Takes a string, a pointer to an array of "enum_val_t"s, and a default int
4266 * value.
4267 * The array must be terminated by an entry with a null "name" string.
4268 *
4269 * If the string matches a "name" string in an entry, the value from that
4270 * entry is returned.
4271 *
4272 * Otherwise, if a string matches a "description" string in an entry, the
4273 * value from that entry is returned; we do that for backwards compatibility,
4274 * as we used to have only a "name" string that was used both for command-line
4275 * and configuration-file values and in the GUI (which meant either that
4276 * the GUI had what might be somewhat cryptic values to select from or that
4277 * the "-o" flag took long strings, often with spaces in them).
4278 *
4279 * Otherwise, the default value that was passed as the third argument is
4280 * returned.
4281 */
4282static int
4283find_val_for_string(const char *needle, const enum_val_t *haystack,
4284 int default_value)
4285{
4286 int i;
4287
4288 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4289 if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
4290 return haystack[i].value;
4291 }
4292 }
4293 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4294 if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
4295 return haystack[i].value;
4296 }
4297 }
4298 return default_value;
4299}
4300
4301/* Preferences file format:
4302 * - Configuration directives start at the beginning of the line, and
4303 * are terminated with a colon.
4304 * - Directives can be continued on the next line by preceding them with
4305 * whitespace.
4306 *
4307 * Example:
4308
4309# This is a comment line
4310print.command: lpr
4311print.file: /a/very/long/path/
4312 to/wireshark-out.ps
4313 *
4314 */
4315
4316/*
4317 * Initialize non-dissector preferences used by the "register preference" API
4318 * to default values so the default values can be used when registered.
4319 *
4320 * String, filename, and directory preferences will be g_freed so they must
4321 * be g_mallocated.
4322 */
4323static void
4324prefs_set_global_defaults(wmem_allocator_t* pref_scope, const char** col_fmt, int num_cols)
4325{
4326 int i;
4327 char *col_name;
4328 fmt_data *cfmt;
4329
4330 prefs.restore_filter_after_following_stream = false0;
4331 prefs.gui_toolbar_main_style = TB_STYLE_ICONS0;
4332 /* We try to find the best font in the Qt code */
4333 wmem_free(pref_scope, prefs.gui_font_name);
4334 prefs.gui_font_name = wmem_strdup(pref_scope, "");
4335 prefs.gui_active_fg.red = 0;
4336 prefs.gui_active_fg.green = 0;
4337 prefs.gui_active_fg.blue = 0;
4338 prefs.gui_active_bg.red = 52223;
4339 prefs.gui_active_bg.green = 59647;
4340 prefs.gui_active_bg.blue = 65535;
4341 prefs.gui_active_style = COLOR_STYLE_DEFAULT0;
4342 prefs.gui_inactive_fg.red = 0;
4343 prefs.gui_inactive_fg.green = 0;
4344 prefs.gui_inactive_fg.blue = 0;
4345 prefs.gui_inactive_bg.red = 61439;
4346 prefs.gui_inactive_bg.green = 61439;
4347 prefs.gui_inactive_bg.blue = 61439;
4348 prefs.gui_inactive_style = COLOR_STYLE_DEFAULT0;
4349 prefs.gui_marked_fg.red = 65535;
4350 prefs.gui_marked_fg.green = 65535;
4351 prefs.gui_marked_fg.blue = 65535;
4352 prefs.gui_marked_bg.red = 0;
4353 prefs.gui_marked_bg.green = 8224;
4354 prefs.gui_marked_bg.blue = 10794;
4355 prefs.gui_ignored_fg.red = 32767;
4356 prefs.gui_ignored_fg.green = 32767;
4357 prefs.gui_ignored_fg.blue = 32767;
4358 prefs.gui_ignored_bg.red = 65535;
4359 prefs.gui_ignored_bg.green = 65535;
4360 prefs.gui_ignored_bg.blue = 65535;
4361 wmem_free(pref_scope, prefs.gui_colorized_fg);
4362 prefs.gui_colorized_fg = wmem_strdup(pref_scope, "000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
4363 wmem_free(pref_scope, prefs.gui_colorized_bg);
4364 prefs.gui_colorized_bg = wmem_strdup(pref_scope, "ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
4365 prefs.st_client_fg.red = 32767;
4366 prefs.st_client_fg.green = 0;
4367 prefs.st_client_fg.blue = 0;
4368 prefs.st_client_bg.red = 64507;
4369 prefs.st_client_bg.green = 60909;
4370 prefs.st_client_bg.blue = 60909;
4371 prefs.st_server_fg.red = 0;
4372 prefs.st_server_fg.green = 0;
4373 prefs.st_server_fg.blue = 32767;
4374 prefs.st_server_bg.red = 60909;
4375 prefs.st_server_bg.green = 60909;
4376 prefs.st_server_bg.blue = 64507;
4377
4378 if (gui_theme_is_dark) {
4379 // Green, red and yellow with HSV V = 84
4380 prefs.gui_filter_valid_bg.red = 0x0000; /* dark green */
4381 prefs.gui_filter_valid_bg.green = 0x66ff;
4382 prefs.gui_filter_valid_bg.blue = 0x0000;
4383 prefs.gui_filter_valid_fg.red = 0xFFFF;
4384 prefs.gui_filter_valid_fg.green = 0xFFFF;
4385 prefs.gui_filter_valid_fg.blue = 0xFFFF;
4386 prefs.gui_filter_invalid_bg.red = 0x66FF; /* dark red */
4387 prefs.gui_filter_invalid_bg.green = 0x0000;
4388 prefs.gui_filter_invalid_bg.blue = 0x0000;
4389 prefs.gui_filter_invalid_fg.red = 0xFFFF;
4390 prefs.gui_filter_invalid_fg.green = 0xFFFF;
4391 prefs.gui_filter_invalid_fg.blue = 0xFFFF;
4392 prefs.gui_filter_deprecated_bg.red = 0x66FF; /* dark yellow / olive */
4393 prefs.gui_filter_deprecated_bg.green = 0x66FF;
4394 prefs.gui_filter_deprecated_bg.blue = 0x0000;
4395 prefs.gui_filter_deprecated_fg.red = 0xFFFF;
4396 prefs.gui_filter_deprecated_fg.green = 0xFFFF;
4397 prefs.gui_filter_deprecated_fg.blue = 0xFFFF;
4398 } else {
4399 // Green, red and yellow with HSV V = 20
4400 prefs.gui_filter_valid_bg.red = 0xAFFF; /* light green */
4401 prefs.gui_filter_valid_bg.green = 0xFFFF;
4402 prefs.gui_filter_valid_bg.blue = 0xAFFF;
4403 prefs.gui_filter_valid_fg.red = 0x0000;
4404 prefs.gui_filter_valid_fg.green = 0x0000;
4405 prefs.gui_filter_valid_fg.blue = 0x0000;
4406 prefs.gui_filter_invalid_bg.red = 0xFFFF; /* light red */
4407 prefs.gui_filter_invalid_bg.green = 0xAFFF;
4408 prefs.gui_filter_invalid_bg.blue = 0xAFFF;
4409 prefs.gui_filter_invalid_fg.red = 0x0000;
4410 prefs.gui_filter_invalid_fg.green = 0x0000;
4411 prefs.gui_filter_invalid_fg.blue = 0x0000;
4412 prefs.gui_filter_deprecated_bg.red = 0xFFFF; /* light yellow */
4413 prefs.gui_filter_deprecated_bg.green = 0xFFFF;
4414 prefs.gui_filter_deprecated_bg.blue = 0xAFFF;
4415 prefs.gui_filter_deprecated_fg.red = 0x0000;
4416 prefs.gui_filter_deprecated_fg.green = 0x0000;
4417 prefs.gui_filter_deprecated_fg.blue = 0x0000;
4418 }
4419
4420 prefs.gui_geometry_save_position = true1;
4421 prefs.gui_geometry_save_size = true1;
4422 prefs.gui_geometry_save_maximized= true1;
4423 prefs.gui_fileopen_style = FO_STYLE_LAST_OPENED0;
4424 prefs.gui_recent_df_entries_max = 10;
4425 prefs.gui_recent_files_count_max = 10;
4426 wmem_free(pref_scope, prefs.gui_fileopen_dir);
4427 prefs.gui_fileopen_dir = wmem_strdup(pref_scope, get_persdatafile_dir());
4428 prefs.gui_fileopen_preview = 3;
4429 wmem_free(pref_scope, prefs.gui_tlskeylog_command);
4430 prefs.gui_tlskeylog_command = wmem_strdup(pref_scope, "");
4431 prefs.gui_ask_unsaved = true1;
4432 prefs.gui_autocomplete_filter = true1;
4433 prefs.gui_find_wrap = true1;
4434 prefs.gui_update_enabled = true1;
4435 prefs.gui_update_channel = UPDATE_CHANNEL_STABLE;
4436 prefs.gui_update_interval = 60*60*24; /* Seconds */
4437 prefs.gui_debounce_timer = 400; /* milliseconds */
4438 wmem_free(pref_scope, prefs.gui_window_title);
4439 prefs.gui_window_title = wmem_strdup(pref_scope, "");
4440 wmem_free(pref_scope, prefs.gui_prepend_window_title);
4441 prefs.gui_prepend_window_title = wmem_strdup(pref_scope, "");
4442 wmem_free(pref_scope, prefs.gui_start_title);
4443 prefs.gui_start_title = wmem_strdup(pref_scope, "The World's Most Popular Network Protocol Analyzer");
4444 prefs.gui_version_placement = version_both;
4445 prefs.gui_welcome_page_show_recent = true1;
4446 prefs.gui_layout_type = layout_type_2;
4447 prefs.gui_layout_content_1 = layout_pane_content_plist;
4448 prefs.gui_layout_content_2 = layout_pane_content_pdetails;
4449 prefs.gui_layout_content_3 = layout_pane_content_pbytes;
4450 prefs.gui_packet_list_elide_mode = ELIDE_RIGHT;
4451 prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut = COPY_FORMAT_TEXT;
4452 prefs.gui_packet_list_copy_text_with_aligned_columns = false0;
4453 prefs.gui_packet_list_show_related = true1;
4454 prefs.gui_packet_list_show_minimap = true1;
4455 prefs.gui_packet_list_sortable = true1;
4456 prefs.gui_packet_list_cached_rows_max = 10000;
4457 wmem_free(pref_scope, prefs.gui_interfaces_hide_types);
4458 prefs.gui_interfaces_hide_types = wmem_strdup(pref_scope, "");
4459 prefs.gui_interfaces_show_hidden = false0;
4460 prefs.gui_interfaces_remote_display = true1;
4461 prefs.gui_packet_list_separator = false0;
4462 prefs.gui_packet_header_column_definition = true1;
4463 prefs.gui_packet_list_hover_style = true1;
4464 prefs.gui_show_selected_packet = false0;
4465 prefs.gui_show_file_load_time = false0;
4466 prefs.gui_max_export_objects = 1000;
4467 prefs.gui_max_tree_items = 1 * 1000 * 1000;
4468 prefs.gui_max_tree_depth = 5 * 100;
4469 prefs.gui_decimal_places1 = DEF_GUI_DECIMAL_PLACES12;
4470 prefs.gui_decimal_places2 = DEF_GUI_DECIMAL_PLACES24;
4471 prefs.gui_decimal_places3 = DEF_GUI_DECIMAL_PLACES36;
4472
4473 if (prefs.col_list) {
4474 free_col_info(prefs.col_list);
4475 prefs.col_list = NULL((void*)0);
4476 }
4477 for (i = 0; i < num_cols; i++) {
4478 cfmt = g_new0(fmt_data,1)((fmt_data *) g_malloc0_n ((1), sizeof (fmt_data)));
4479 cfmt->title = g_strdup(col_fmt[i * 2])g_strdup_inline (col_fmt[i * 2]);
4480 cfmt->visible = true1;
4481 cfmt->display = COLUMN_DISPLAY_STRINGS'R';
4482 parse_column_format(cfmt, col_fmt[(i * 2) + 1]);
4483 prefs.col_list = g_list_append(prefs.col_list, cfmt);
4484 }
4485 prefs.num_cols = num_cols;
4486
4487/* set the default values for the capture dialog box */
4488 prefs.capture_prom_mode = true1;
4489 prefs.capture_monitor_mode = false0;
4490 prefs.capture_pcap_ng = true1;
4491 prefs.capture_real_time = true1;
4492 prefs.capture_update_interval = DEFAULT_UPDATE_INTERVAL100;
4493 prefs.capture_no_extcap = false0;
4494 prefs.capture_show_info = false0;
4495 prefs.enable_aggregation = false0;
4496
4497 if (!prefs.capture_columns) {
4498 /* First time through */
4499 for (i = 0; i < num_capture_cols; i++) {
4500 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
4501 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
4502 }
4503 }
4504
4505/* set the default values for the tap/statistics dialog box */
4506 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
4507 prefs.flow_graph_max_export_items = 1000;
4508 prefs.st_enable_burstinfo = true1;
4509 prefs.st_burst_showcount = false0;
4510 prefs.st_burst_resolution = ST_DEF_BURSTRES5;
4511 prefs.st_burst_windowlen = ST_DEF_BURSTLEN100;
4512 prefs.st_sort_casesensitve = true1;
4513 prefs.st_sort_rng_fixorder = true1;
4514 prefs.st_sort_rng_nameonly = true1;
4515 prefs.st_sort_defcolflag = ST_SORT_COL_COUNT2;
4516 prefs.st_sort_defdescending = true1;
4517 prefs.st_sort_showfullname = false0;
4518 prefs.conv_machine_readable = false0;
4519
4520 /* protocols */
4521 prefs.display_hidden_proto_items = false0;
4522 prefs.display_byte_fields_with_spaces = false0;
4523 prefs.display_abs_time_ascii = ABS_TIME_ASCII_TREE;
4524 prefs.ignore_dup_frames = false0;
4525 prefs.ignore_dup_frames_cache_entries = 10000;
4526
4527 /* set the default values for the io graph dialog */
4528 prefs.gui_io_graph_automatic_update = true1;
4529 prefs.gui_io_graph_enable_legend = true1;
4530
4531 /* set the default values for the plot dialog */
4532 prefs.gui_plot_automatic_update = true1;
4533 prefs.gui_plot_enable_legend = true1;
4534 prefs.gui_plot_enable_auto_scroll = false0;
4535
4536 /* set the default values for the packet dialog */
4537 prefs.gui_packet_dialog_layout = layout_vertical;
4538 prefs.gui_packet_details_show_byteview = true1;
4539}
4540
4541/*
4542 * Reset a single dissector preference.
4543 */
4544void
4545reset_pref(pref_t *pref)
4546{
4547 if (!pref) return;
4548
4549 /*
4550 * This preference is no longer supported; it's not a
4551 * real preference, so we don't reset it (i.e., we
4552 * treat it as if it weren't found in the list of
4553 * preferences, and we weren't called in the first place).
4554 */
4555 if (pref->obsolete)
4556 return;
4557
4558 switch (pref->type) {
4559
4560 case PREF_UINT:
4561 *pref->varp.uint = pref->default_val.uint;
4562 break;
4563
4564 case PREF_INT:
4565 *pref->varp.intp = pref->default_val.intval;
4566 break;
4567
4568 case PREF_FLOAT:
4569 *pref->varp.floatp = pref->default_val.floatval;
4570 break;
4571
4572 case PREF_BOOL:
4573 *pref->varp.boolp = pref->default_val.boolval;
4574 break;
4575
4576 case PREF_ENUM:
4577 case PREF_PROTO_TCP_SNDAMB_ENUM:
4578 *pref->varp.enump = pref->default_val.enumval;
4579 break;
4580
4581 case PREF_STRING:
4582 case PREF_SAVE_FILENAME:
4583 case PREF_OPEN_FILENAME:
4584 case PREF_DIRNAME:
4585 case PREF_PASSWORD:
4586 case PREF_DISSECTOR:
4587 reset_string_like_preference(pref);
4588 break;
4589
4590 case PREF_RANGE:
4591 case PREF_DECODE_AS_RANGE:
4592 wmem_free(pref->scope, *pref->varp.range);
4593 *pref->varp.range = range_copy(pref->scope, pref->default_val.range);
4594 break;
4595
4596 case PREF_STATIC_TEXT:
4597 case PREF_UAT:
4598 /* Nothing to do */
4599 break;
4600
4601 case PREF_COLOR:
4602 *pref->varp.colorp = pref->default_val.color;
4603 break;
4604
4605 case PREF_CUSTOM:
4606 pref->custom_cbs.reset_cb(pref);
4607 break;
4608 }
4609}
4610
4611static void
4612reset_pref_cb(void *data, void *user_data)
4613{
4614 pref_t *pref = (pref_t *) data;
4615 module_t *module = (module_t *)user_data;
4616
4617 if (pref && (pref->type == PREF_RANGE || pref->type == PREF_DECODE_AS_RANGE)) {
4618 /*
4619 * Some dissectors expect the range (returned via prefs_get_range_value)
4620 * to remain valid if it has not changed. If it did change, then we
4621 * should set "prefs_changed_flags" to ensure that the preference apply
4622 * callback is invoked. That callback will notify dissectors that it
4623 * should no longer assume the range to be valid.
4624 */
4625 if (ranges_are_equal(*pref->varp.range, pref->default_val.range)) {
4626 /* Optimization: do not invoke apply callback if nothing changed. */
4627 return;
4628 }
4629 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
4630 }
4631 reset_pref(pref);
4632}
4633
4634/*
4635 * Reset all preferences for a module.
4636 */
4637static bool_Bool
4638reset_module_prefs(const void *key _U___attribute__((unused)), void *value, void *data _U___attribute__((unused)))
4639{
4640 module_t *module = (module_t *)value;
4641 g_list_foreach(module->prefs, reset_pref_cb, module);
4642 return false0;
4643}
4644
4645/* Reset preferences */
4646void
4647prefs_reset(const char* app_env_var_prefix, const char** col_fmt, int num_cols)
4648{
4649 g_free(prefs.saved_at_version);
4650 prefs.saved_at_version = NULL((void*)0);
4651
4652 /*
4653 * Unload all UAT preferences.
4654 */
4655 uat_unload_all();
4656
4657 /*
4658 * Unload any loaded MIBs.
4659 */
4660 oids_cleanup();
4661
4662 /*
4663 * Reload all UAT preferences.
4664 */
4665 uat_load_all(app_env_var_prefix);
4666
4667 /*
4668 * Reset the non-dissector preferences.
4669 */
4670 prefs_set_global_defaults(wmem_epan_scope(), col_fmt, num_cols);
4671
4672 /*
4673 * Reset the non-UAT dissector preferences.
4674 */
4675 wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL((void*)0));
4676}
4677
4678#ifdef _WIN32
4679static void
4680read_registry(void)
4681{
4682 HKEY hTestKey;
4683 DWORD data;
4684 DWORD data_size = sizeof(DWORD);
4685 DWORD ret;
4686
4687 ret = RegOpenKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, KEY_READ, &hTestKey);
4688 if (ret != ERROR_SUCCESS && ret != ERROR_FILE_NOT_FOUND) {
4689 ws_noisy("Cannot open HKCU "REG_HKCU_WIRESHARK_KEY": 0x%lx", ret)do { if (1) { ws_log_full("Epan", LOG_LEVEL_NOISY, "epan/prefs.c"
, 4689, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
4690 return;
4691 }
4692
4693 ret = RegQueryValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", NULL((void*)0), NULL((void*)0), (LPBYTE)&data, &data_size);
4694 if (ret == ERROR_SUCCESS) {
4695 ws_log_console_open = (ws_log_console_open_pref)data;
4696 ws_noisy("Got "LOG_HKCU_CONSOLE_OPEN" from Windows registry: %d", ws_log_console_open)do { if (1) { ws_log_full("Epan", LOG_LEVEL_NOISY, "epan/prefs.c"
, 4696, __func__, "Got ""ConsoleOpen"" from Windows registry: %d"
, ws_log_console_open); } } while (0)
;
4697 }
4698 else if (ret != ERROR_FILE_NOT_FOUND) {
4699 ws_noisy("Error reading registry key "LOG_HKCU_CONSOLE_OPEN": 0x%lx", ret)do { if (1) { ws_log_full("Epan", LOG_LEVEL_NOISY, "epan/prefs.c"
, 4699, __func__, "Error reading registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
4700 }
4701
4702 RegCloseKey(hTestKey);
4703}
4704#endif
4705
4706void
4707prefs_read_module(const char *module, const char* app_env_var_prefix)
4708{
4709 int err;
4710 char *pf_path;
4711 FILE *pf;
4712
4713 module_t *target_module = prefs_find_module(module);
4714 if (!target_module) {
4715 return;
4716 }
4717
4718 /* Construct the pathname of the user's preferences file for the module. */
4719 char *pf_name = wmem_strdup_printf(NULL((void*)0), "%s.cfg", module);
4720 pf_path = get_persconffile_path(pf_name, true1, app_env_var_prefix);
4721 wmem_free(NULL((void*)0), pf_name);
4722
4723 /* Read the user's module preferences file, if it exists and is not a dir. */
4724 if (!test_for_regular_file(pf_path) || ((pf = ws_fopenfopen(pf_path, "r")) == NULL((void*)0))) {
4725 g_free(pf_path);
4726 /* Fall back to the user's generic preferences file. */
4727 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4728 pf = ws_fopenfopen(pf_path, "r");
4729 }
4730
4731 if (pf != NULL((void*)0)) {
4732 /* We succeeded in opening it; read it. */
4733 err = read_prefs_file(pf_path, pf, set_pref, target_module);
4734 if (err != 0) {
4735 /* We had an error reading the file; report it. */
4736 report_warning("Error reading your preferences file \"%s\": %s.",
4737 pf_path, g_strerror(err));
4738 } else
4739 g_free(pf_path);
4740 fclose(pf);
4741 } else {
4742 /* We failed to open it. If we failed for some reason other than
4743 "it doesn't exist", return the errno and the pathname, so our
4744 caller can report the error. */
4745 if (errno(*__errno_location ()) != ENOENT2) {
4746 report_warning("Can't open your preferences file \"%s\": %s.",
4747 pf_path, g_strerror(errno(*__errno_location ())));
4748 } else
4749 g_free(pf_path);
4750 }
4751
4752 return;
4753}
4754
4755/* Read the preferences file, fill in "prefs", and return a pointer to it.
4756
4757 If we got an error (other than "it doesn't exist") we report it through
4758 the UI. */
4759e_prefs *
4760read_prefs(const char* app_env_var_prefix)
4761{
4762 int err;
4763 char *pf_path;
4764 FILE *pf;
4765
4766 /* clean up libsmi structures before reading prefs */
4767 oids_cleanup();
4768
4769#ifdef _WIN32
4770 read_registry();
4771#endif
4772
4773 /*
4774 * If we don't already have the pathname of the global preferences
4775 * file, construct it. Then, in either case, try to open the file.
4776 */
4777 if (gpf_path == NULL((void*)0)) {
4778 /*
4779 * We don't have the path; try the new path first, and, if that
4780 * file doesn't exist, try the old path.
4781 */
4782 gpf_path = get_datafile_path(PF_NAME"preferences", app_env_var_prefix);
4783 if ((pf = ws_fopenfopen(gpf_path, "r")) == NULL((void*)0) && errno(*__errno_location ()) == ENOENT2) {
4784 /*
4785 * It doesn't exist by the new name; try the old name.
4786 */
4787 g_free(gpf_path);
4788 gpf_path = get_datafile_path(OLD_GPF_NAME"wireshark.conf", app_env_var_prefix);
4789 pf = ws_fopenfopen(gpf_path, "r");
4790 }
4791 } else {
4792 /*
4793 * We have the path; try it.
4794 */
4795 pf = ws_fopenfopen(gpf_path, "r");
4796 }
4797
4798 /*
4799 * If we were able to open the file, read it.
4800 * XXX - if it failed for a reason other than "it doesn't exist",
4801 * report the error.
4802 */
4803 if (pf != NULL((void*)0)) {
4804 /* We succeeded in opening it; read it. */
4805 err = read_prefs_file(gpf_path, pf, set_pref, NULL((void*)0));
4806 if (err != 0) {
4807 /* We had an error reading the file; report it. */
4808 report_warning("Error reading global preferences file \"%s\": %s.",
4809 gpf_path, g_strerror(err));
4810 }
4811 fclose(pf);
4812 } else {
4813 /* We failed to open it. If we failed for some reason other than
4814 "it doesn't exist", report the error. */
4815 if (errno(*__errno_location ()) != ENOENT2) {
4816 if (errno(*__errno_location ()) != 0) {
4817 report_warning("Can't open global preferences file \"%s\": %s.",
4818 gpf_path, g_strerror(errno(*__errno_location ())));
4819 }
4820 }
4821 }
4822
4823 /* Construct the pathname of the user's preferences file. */
4824 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4825
4826 /* Read the user's preferences file, if it exists. */
4827 if ((pf = ws_fopenfopen(pf_path, "r")) != NULL((void*)0)) {
4828
4829 /* We succeeded in opening it; read it. */
4830 err = read_prefs_file(pf_path, pf, set_pref, NULL((void*)0));
4831 if (err != 0) {
4832 /* We had an error reading the file; report it. */
4833 report_warning("Error reading your preferences file \"%s\": %s.",
4834 pf_path, g_strerror(err));
4835 } else
4836 g_free(pf_path);
4837 fclose(pf);
4838 } else {
4839 /* We failed to open it. If we failed for some reason other than
4840 "it doesn't exist", return the errno and the pathname, so our
4841 caller can report the error. */
4842 if (errno(*__errno_location ()) != ENOENT2) {
4843 report_warning("Can't open your preferences file \"%s\": %s.",
4844 pf_path, g_strerror(errno(*__errno_location ())));
4845 } else
4846 g_free(pf_path);
4847 }
4848
4849 /* load SMI modules if needed */
4850 oids_init(app_env_var_prefix);
4851
4852 return &prefs;
4853}
4854
4855/* read the preferences file (or similar) and call the callback
4856 * function to set each key/value pair found */
4857int
4858read_prefs_file(const char *pf_path, FILE *pf,
4859 pref_set_pair_cb pref_set_pair_fct, void *private_data)
4860{
4861 enum {
4862 START, /* beginning of a line */
4863 IN_VAR, /* processing key name */
4864 PRE_VAL, /* finished processing key name, skipping white space before value */
4865 IN_VAL, /* processing value */
4866 IN_SKIP /* skipping to the end of the line */
4867 } state = START;
4868 int got_c;
4869 GString *cur_val;
4870 GString *cur_var;
4871 bool_Bool got_val = false0;
4872 int fline = 1, pline = 1;
4873 char hint[] = "(save preferences to remove this warning)";
4874 char ver[128];
4875
4876 cur_val = g_string_new("");
4877 cur_var = g_string_new("");
4878
4879 /* Try to read in the profile name in the first line of the preferences file. */
4880 if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) {
1
Assuming the condition is false
2
Taking false branch
4881 /* Assume trailing period and remove it */
4882 g_free(prefs.saved_at_version);
4883 prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1);
4884 }
4885 rewind(pf);
3
After calling 'rewind' reading 'errno' is required to find out if the call has failed
4886
4887 while ((got_c = ws_getc_unlockedgetc_unlocked(pf)) != EOF(-1)) {
4
Value of 'errno' was not checked and may be overwritten by function 'getc_unlocked'
4888 if (got_c == '\r') {
4889 /* Treat CR-LF at the end of a line like LF, so that if we're reading
4890 * a Windows-format file on UN*X, we handle it the same way we'd handle
4891 * a UN*X-format file. */
4892 got_c = ws_getc_unlockedgetc_unlocked(pf);
4893 if (got_c == EOF(-1))
4894 break;
4895 if (got_c != '\n') {
4896 /* Put back the character after the CR, and process the CR normally. */
4897 ungetc(got_c, pf);
4898 got_c = '\r';
4899 }
4900 }
4901 if (got_c == '\n') {
4902 state = START;
4903 fline++;
4904 continue;
4905 }
4906
4907 switch (state) {
4908 case START:
4909 if (g_ascii_isalnum(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_ALNUM) != 0)) {
4910 if (cur_var->len > 0) {
4911 if (got_val) {
4912 if (cur_val->len > 0) {
4913 if (cur_val->str[cur_val->len-1] == ',') {
4914 /*
4915 * If the pref has a trailing comma, eliminate it.
4916 */
4917 cur_val->str[cur_val->len-1] = '\0';
4918 ws_warning("%s line %d: trailing comma in \"%s\" %s", pf_path, pline, cur_var->str, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4918, __func__, "%s line %d: trailing comma in \"%s\" %s", pf_path
, pline, cur_var->str, hint); } } while (0)
;
4919 }
4920 }
4921 /* Call the routine to set the preference; it will parse
4922 the value as appropriate.
4923
4924 Since we're reading a file, rather than processing
4925 explicit user input, for range preferences, silently
4926 lower values in excess of the range's maximum, rather
4927 than reporting errors and failing. */
4928 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
4929
4930 case PREFS_SET_OK:
4931 break;
4932
4933 case PREFS_SET_SYNTAX_ERR:
4934 report_warning("Syntax error in preference \"%s\" at line %d of\n%s %s",
4935 cur_var->str, pline, pf_path, hint);
4936 break;
4937
4938 case PREFS_SET_NO_SUCH_PREF:
4939 ws_warning("No such preference \"%s\" at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4940, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4940 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4940, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4941 break;
4942
4943 case PREFS_SET_OBSOLETE:
4944 /*
4945 * If an attempt is made to save the
4946 * preferences, a popup warning will be
4947 * displayed stating that obsolete prefs
4948 * have been detected and the user will
4949 * be given the opportunity to save these
4950 * prefs under a different profile name.
4951 * The prefs in question need to be listed
4952 * in the console window so that the
4953 * user can make an informed choice.
4954 */
4955 ws_warning("Obsolete preference \"%s\" at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4956, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4956 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4956, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4957 break;
4958 }
4959 } else {
4960 ws_warning("Incomplete preference at line %d: of\n%s %s", pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4960, __func__, "Incomplete preference at line %d: of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
4961 }
4962 }
4963 state = IN_VAR;
4964 got_val = false0;
4965 g_string_truncate(cur_var, 0)g_string_truncate_inline (cur_var, 0);
4966 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
4967 pline = fline;
4968 } else if (g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0) && cur_var->len > 0 && got_val) {
4969 state = PRE_VAL;
4970 } else if (got_c == '#') {
4971 state = IN_SKIP;
4972 } else {
4973 ws_warning("Malformed preference at line %d of\n%s %s", fline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4973, __func__, "Malformed preference at line %d of\n%s %s"
, fline, pf_path, hint); } } while (0)
;
4974 }
4975 break;
4976 case IN_VAR:
4977 if (got_c != ':') {
4978 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
4979 } else {
4980 /* This is a colon (':') */
4981 state = PRE_VAL;
4982 g_string_truncate(cur_val, 0)g_string_truncate_inline (cur_val, 0);
4983 /*
4984 * Set got_val to true to accommodate prefs such as
4985 * "gui.fileopen.dir" that do not require a value.
4986 */
4987 got_val = true1;
4988 }
4989 break;
4990 case PRE_VAL:
4991 if (!g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0)) {
4992 state = IN_VAL;
4993 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
4994 }
4995 break;
4996 case IN_VAL:
4997 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
4998 break;
4999 case IN_SKIP:
5000 break;
5001 }
5002 }
5003 if (cur_var->len > 0) {
5004 if (got_val) {
5005 /* Call the routine to set the preference; it will parse
5006 the value as appropriate.
5007
5008 Since we're reading a file, rather than processing
5009 explicit user input, for range preferences, silently
5010 lower values in excess of the range's maximum, rather
5011 than reporting errors and failing. */
5012 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
5013
5014 case PREFS_SET_OK:
5015 break;
5016
5017 case PREFS_SET_SYNTAX_ERR:
5018 ws_warning("Syntax error in preference %s at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5019, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5019 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5019, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5020 break;
5021
5022 case PREFS_SET_NO_SUCH_PREF:
5023 ws_warning("No such preference \"%s\" at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5024, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5024 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5024, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5025 break;
5026
5027 case PREFS_SET_OBSOLETE:
5028 ws_warning("Obsolete preference \"%s\" at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5029, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5029 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5029, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5030 break;
5031 }
5032 } else {
5033 ws_warning("Incomplete preference at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5034, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
5034 pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5034, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
5035 }
5036 }
5037
5038 g_string_free(cur_val, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(cur_val), ((!(0)))) : g_string_free_and_steal (cur_val)) : (
g_string_free) ((cur_val), ((!(0)))))
;
5039 g_string_free(cur_var, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(cur_var), ((!(0)))) : g_string_free_and_steal (cur_var)) : (
g_string_free) ((cur_var), ((!(0)))))
;
5040
5041 if (ferror(pf))
5042 return errno(*__errno_location ());
5043 else
5044 return 0;
5045}
5046
5047/*
5048 * If we were handed a preference starting with "uat:", try to turn it into
5049 * a valid uat entry.
5050 */
5051static bool_Bool
5052prefs_set_uat_pref(char *uat_entry, char **errmsg) {
5053 char *p, *colonp;
5054 uat_t *uat;
5055 bool_Bool ret;
5056
5057 colonp = strchr(uat_entry, ':');
5058 if (colonp == NULL((void*)0))
5059 return false0;
5060
5061 p = colonp;
5062 *p++ = '\0';
5063
5064 /*
5065 * Skip over any white space (there probably won't be any, but
5066 * as we allow it in the preferences file, we might as well
5067 * allow it here).
5068 */
5069 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
5070 p++;
5071 if (*p == '\0') {
5072 /*
5073 * Put the colon back, so if our caller uses, in an
5074 * error message, the string they passed us, the message
5075 * looks correct.
5076 */
5077 *colonp = ':';
5078 return false0;
5079 }
5080
5081 uat = uat_find(uat_entry);
5082 *colonp = ':';
5083 if (uat == NULL((void*)0)) {
5084 *errmsg = g_strdup("Unknown preference")g_strdup_inline ("Unknown preference");
5085 return false0;
5086 }
5087
5088 ret = uat_load_str(uat, p, errmsg);
5089 return ret;
5090}
5091
5092char *
5093prefs_sanitize_string(const char* str)
5094{
5095 char *sanitized;
5096 if (!prefs_regex) {
5097 prefs_regex = g_regex_new("\\s*\\R\\s*", (GRegexCompileFlags)G_REGEX_OPTIMIZE,
5098 (GRegexMatchFlags)G_REGEX_MATCH_BSR_ANYCRLF, NULL((void*)0));
5099 } else {
5100 g_regex_ref(prefs_regex);
5101 }
5102 sanitized = g_regex_replace(prefs_regex, str, -1, 0, " ", G_REGEX_MATCH_DEFAULT, NULL((void*)0));
5103 g_regex_unref(prefs_regex);
5104 return sanitized;
5105}
5106
5107/*
5108 * Given a string of the form "<pref name>:<pref value>", as might appear
5109 * as an argument to a "-o" option, parse it and set the preference in
5110 * question. Return an indication of whether it succeeded or failed
5111 * in some fashion.
5112 */
5113prefs_set_pref_e
5114prefs_set_pref(char *prefarg, char **errmsg)
5115{
5116 char *p, *colonp;
5117 prefs_set_pref_e ret;
5118
5119 *errmsg = NULL((void*)0);
5120
5121 colonp = strchr(prefarg, ':');
5122 if (colonp == NULL((void*)0)) {
5123 *errmsg = g_strdup("missing ':' (syntax is prefname:value).")g_strdup_inline ("missing ':' (syntax is prefname:value).");
5124 return PREFS_SET_SYNTAX_ERR;
5125 }
5126
5127 p = colonp;
5128 *p++ = '\0';
5129 /* XXX - Replace line terminators, or match and fail with errmsg, or ignore? */
5130
5131 /*
5132 * Skip over any white space (there probably won't be any, but
5133 * as we allow it in the preferences file, we might as well
5134 * allow it here).
5135 */
5136 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
5137 p++;
5138 /* The empty string is a legal value for range preferences (PREF_RANGE,
5139 * PREF_DECODE_AS_RANGE), and string-like preferences (PREF_STRING,
5140 * PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME), indeed often
5141 * not just useful but the default. A user might have a value saved
5142 * to their preference file but want to override it to default behavior.
5143 * Individual preference handlers of those types should be prepared to
5144 * deal with an empty string. For other types, it is up to set_pref() to
5145 * test for the empty string and set PREFS_SET_SYNTAX_ERROR there.
5146 */
5147 if (strcmp(prefarg, "uat")) {
5148 ret = set_pref(prefarg, p, NULL((void*)0), true1);
5149 } else {
5150 ret = prefs_set_uat_pref(p, errmsg) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR;
5151 }
5152 *colonp = ':'; /* put the colon back */
5153 return ret;
5154}
5155
5156unsigned prefs_get_uint_value(pref_t *pref, pref_source_t source)
5157{
5158 switch (source)
5159 {
5160 case pref_default:
5161 return pref->default_val.uint;
5162 case pref_stashed:
5163 return pref->stashed_val.uint;
5164 case pref_current:
5165 return *pref->varp.uint;
5166 default:
5167 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5167
, __func__, "assertion \"not reached\" failed")
;
5168 break;
5169 }
5170
5171 return 0;
5172}
5173
5174unsigned int prefs_set_int_value(pref_t* pref, int value, pref_source_t source)
5175{
5176 int changed = 0;
5177 switch (source)
5178 {
5179 case pref_default:
5180 if (pref->default_val.intval != value) {
5181 pref->default_val.intval = value;
5182 changed = prefs_get_effect_flags(pref);
5183 }
5184 break;
5185 case pref_stashed:
5186 if (pref->stashed_val.intval != value) {
5187 pref->stashed_val.intval = value;
5188 changed = prefs_get_effect_flags(pref);
5189 }
5190 break;
5191 case pref_current:
5192 if (*pref->varp.intp != value) {
5193 *pref->varp.intp = value;
5194 changed = prefs_get_effect_flags(pref);
5195 }
5196 break;
5197 default:
5198 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5198
, __func__, "assertion \"not reached\" failed")
;
5199 break;
5200 }
5201
5202 return changed;
5203}
5204
5205int prefs_get_int_value(pref_t* pref, pref_source_t source)
5206{
5207 switch (source)
5208 {
5209 case pref_default:
5210 return pref->default_val.intval;
5211 case pref_stashed:
5212 return pref->stashed_val.intval;
5213 case pref_current:
5214 return *pref->varp.intp;
5215 default:
5216 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5216
, __func__, "assertion \"not reached\" failed")
;
5217 break;
5218 }
5219
5220 return 0;
5221}
5222
5223unsigned int prefs_set_float_value(pref_t* pref, double value, pref_source_t source)
5224{
5225 int changed = 0;
5226 switch (source)
5227 {
5228 case pref_default:
5229 if (pref->default_val.floatval != value) {
5230 pref->default_val.floatval = value;
5231 changed = prefs_get_effect_flags(pref);
5232 }
5233 break;
5234 case pref_stashed:
5235 if (pref->stashed_val.floatval != value) {
5236 pref->stashed_val.floatval = value;
5237 changed = prefs_get_effect_flags(pref);
5238 }
5239 break;
5240 case pref_current:
5241 if (*pref->varp.floatp != value) {
5242 *pref->varp.floatp = value;
5243 changed = prefs_get_effect_flags(pref);
5244 }
5245 break;
5246 default:
5247 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5247
, __func__, "assertion \"not reached\" failed")
;
5248 break;
5249 }
5250
5251 return changed;
5252}
5253
5254double prefs_get_float_value(pref_t* pref, pref_source_t source)
5255{
5256 switch (source)
5257 {
5258 case pref_default:
5259 return pref->default_val.floatval;
5260 case pref_stashed:
5261 return pref->stashed_val.floatval;
5262 case pref_current:
5263 return *pref->varp.floatp;
5264 default:
5265 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5265
, __func__, "assertion \"not reached\" failed")
;
5266 break;
5267 }
5268
5269 return 0;
5270}
5271
5272
5273const char *prefs_get_password_value(pref_t *pref, pref_source_t source)
5274{
5275 return prefs_get_string_value(pref, source);
5276}
5277
5278
5279unsigned int prefs_set_uint_value(pref_t *pref, unsigned value, pref_source_t source)
5280{
5281 unsigned int changed = 0;
5282 switch (source)
5283 {
5284 case pref_default:
5285 if (pref->default_val.uint != value) {
5286 pref->default_val.uint = value;
5287 changed = prefs_get_effect_flags(pref);
5288 }
5289 break;
5290 case pref_stashed:
5291 if (pref->stashed_val.uint != value) {
5292 pref->stashed_val.uint = value;
5293 changed = prefs_get_effect_flags(pref);
5294 }
5295 break;
5296 case pref_current:
5297 if (*pref->varp.uint != value) {
5298 *pref->varp.uint = value;
5299 changed = prefs_get_effect_flags(pref);
5300 }
5301 break;
5302 default:
5303 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5303
, __func__, "assertion \"not reached\" failed")
;
5304 break;
5305 }
5306
5307 return changed;
5308}
5309
5310/*
5311 * For use by UI code that sets preferences.
5312 */
5313unsigned int
5314prefs_set_password_value(pref_t *pref, const char* value, pref_source_t source)
5315{
5316 return prefs_set_string_value(pref, value, source);
5317}
5318
5319
5320unsigned prefs_get_uint_base(pref_t *pref)
5321{
5322 return pref->info.base;
5323}
5324
5325/*
5326 * Returns true if the given device is hidden
5327 */
5328bool_Bool
5329prefs_is_capture_device_hidden(const char *name)
5330{
5331 char *tok, *devices;
5332 size_t len;
5333
5334 if (prefs.capture_devices_hide && name) {
5335 devices = g_strdup (prefs.capture_devices_hide)g_strdup_inline (prefs.capture_devices_hide);
5336 len = strlen (name);
5337 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5338 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5339 g_free (devices);
5340 return true1;
5341 }
5342 }
5343 g_free (devices);
5344 }
5345
5346 return false0;
5347}
5348
5349/*
5350 * Returns true if the given column is visible (not hidden)
5351 */
5352static bool_Bool
5353prefs_is_column_visible(const char *cols_hidden, int col)
5354{
5355 char *tok, *cols, *p;
5356 int cidx;
5357
5358 /*
5359 * Do we have a list of hidden columns?
5360 */
5361 if (cols_hidden) {
5362 /*
5363 * Yes - check the column against each of the ones in the
5364 * list.
5365 */
5366 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5367 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5368 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5369
5370 cidx = (int)strtol(tok, &p, 10);
5371 if (p == tok || *p != '\0') {
5372 continue;
5373 }
5374 if (cidx != col) {
5375 continue;
5376 }
5377 /*
5378 * OK, they match, so it's one of the hidden fields,
5379 * hence not visible.
5380 */
5381 g_free(cols);
5382 return false0;
5383 }
5384 g_free(cols);
5385 }
5386
5387 /*
5388 * No - either there are no hidden columns or this isn't one
5389 * of them - so it is visible.
5390 */
5391 return true1;
5392}
5393
5394/*
5395 * Returns true if the given column is visible (not hidden)
5396 */
5397static bool_Bool
5398prefs_is_column_fmt_visible(const char *cols_hidden, fmt_data *cfmt)
5399{
5400 char *tok, *cols;
5401 fmt_data cfmt_hidden;
5402
5403 /*
5404 * Do we have a list of hidden columns?
5405 */
5406 if (cols_hidden) {
5407 /*
5408 * Yes - check the column against each of the ones in the
5409 * list.
5410 */
5411 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5412 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5413 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5414
5415 /*
5416 * Parse this column format.
5417 */
5418 if (!parse_column_format(&cfmt_hidden, tok)) {
5419 /*
5420 * It's not valid; ignore it.
5421 */
5422 continue;
5423 }
5424
5425 /*
5426 * Does it match the column?
5427 */
5428 if (cfmt->fmt != cfmt_hidden.fmt) {
5429 /* No. */
5430 g_free(cfmt_hidden.custom_fields);
5431 cfmt_hidden.custom_fields = NULL((void*)0);
5432 continue;
5433 }
5434 if (cfmt->fmt == COL_CUSTOM) {
5435 /*
5436 * A custom column has to have the same custom field
5437 * and occurrence.
5438 */
5439 if (cfmt_hidden.custom_fields && cfmt->custom_fields) {
5440 if (strcmp(cfmt->custom_fields,
5441 cfmt_hidden.custom_fields) != 0) {
5442 /* Different fields. */
5443 g_free(cfmt_hidden.custom_fields);
5444 cfmt_hidden.custom_fields = NULL((void*)0);
5445 continue;
5446 }
5447 if (cfmt->custom_occurrence != cfmt_hidden.custom_occurrence) {
5448 /* Different occurrences settings. */
5449 g_free(cfmt_hidden.custom_fields);
5450 cfmt_hidden.custom_fields = NULL((void*)0);
5451 continue;
5452 }
5453 }
5454 }
5455
5456 /*
5457 * OK, they match, so it's one of the hidden fields,
5458 * hence not visible.
5459 */
5460 g_free(cfmt_hidden.custom_fields);
5461 g_free(cols);
5462 return false0;
5463 }
5464 g_free(cols);
5465 }
5466
5467 /*
5468 * No - either there are no hidden columns or this isn't one
5469 * of them - so it is visible.
5470 */
5471 return true1;
5472}
5473
5474/*
5475 * Returns true if the given device should capture in monitor mode by default
5476 */
5477bool_Bool
5478prefs_capture_device_monitor_mode(const char *name)
5479{
5480 char *tok, *devices;
5481 size_t len;
5482
5483 if (prefs.capture_devices_monitor_mode && name) {
5484 devices = g_strdup (prefs.capture_devices_monitor_mode)g_strdup_inline (prefs.capture_devices_monitor_mode);
5485 len = strlen (name);
5486 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5487 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5488 g_free (devices);
5489 return true1;
5490 }
5491 }
5492 g_free (devices);
5493 }
5494
5495 return false0;
5496}
5497
5498/*
5499 * Returns true if the user has marked this column as visible
5500 */
5501bool_Bool
5502prefs_capture_options_dialog_column_is_visible(const char *column)
5503{
5504 GList *curr;
5505 char *col;
5506
5507 for (curr = g_list_first(prefs.capture_columns); curr; curr = g_list_next(curr)((curr) ? (((GList *)(curr))->next) : ((void*)0))) {
5508 col = (char *)curr->data;
5509 if (col && (g_ascii_strcasecmp(col, column) == 0)) {
5510 return true1;
5511 }
5512 }
5513 return false0;
5514}
5515
5516bool_Bool
5517prefs_has_layout_pane_content (layout_pane_content_e layout_pane_content)
5518{
5519 return ((prefs.gui_layout_content_1 == layout_pane_content) ||
5520 (prefs.gui_layout_content_2 == layout_pane_content) ||
5521 (prefs.gui_layout_content_3 == layout_pane_content));
5522}
5523
5524char
5525string_to_name_resolve(const char *string, e_addr_resolve *name_resolve)
5526{
5527 char c;
5528
5529 memset(name_resolve, 0, sizeof(e_addr_resolve));
5530 while ((c = *string++) != '\0') {
5531 switch (c) {
5532 case 'g':
5533 name_resolve->maxmind_geoip = true1;
5534 break;
5535 case 'm':
5536 name_resolve->mac_name = true1;
5537 break;
5538 case 'n':
5539 name_resolve->network_name = true1;
5540 break;
5541 case 'N':
5542 name_resolve->use_external_net_name_resolver = true1;
5543 break;
5544 case 't':
5545 name_resolve->transport_name = true1;
5546 break;
5547 case 'd':
5548 name_resolve->dns_pkt_addr_resolution = true1;
5549 break;
5550 case 's':
5551 name_resolve->handshake_sni_addr_resolution = true1;
5552 break;
5553 case 'v':
5554 name_resolve->vlan_name = true1;
5555 break;
5556 default:
5557 /*
5558 * Unrecognized letter.
5559 */
5560 return c;
5561 }
5562 }
5563 return '\0';
5564}
5565
5566static bool_Bool
5567deprecated_heur_dissector_pref(char *pref_name, const char *value)
5568{
5569 struct heur_pref_name
5570 {
5571 const char* pref_name;
5572 const char* short_name;
5573 bool_Bool more_dissectors; /* For multiple dissectors controlled by the same preference */
5574 };
5575
5576 static const struct heur_pref_name heur_prefs[] = {
5577 {"acn.heuristic_acn", "acn_udp", 0},
5578 {"bfcp.enable", "bfcp_tcp", 1},
5579 {"bfcp.enable", "bfcp_udp", 0},
5580 {"bt-dht.enable", "bittorrent_dht_udp", 0},
5581 {"bt-utp.enable", "bt_utp_udp", 0},
5582 {"cattp.enable", "cattp_udp", 0},
5583 {"cfp.enable", "fp_eth", 0},
5584 {"dicom.heuristic", "dicom_tcp", 0},
5585 {"dnp3.heuristics", "dnp3_tcp", 1},
5586 {"dnp3.heuristics", "dnp3_udp", 0},
5587 {"dvb-s2_modeadapt.enable", "dvb_s2_udp", 0},
5588 {"esl.enable", "esl_eth", 0},
5589 {"fp.udp_heur", "fp_udp", 0},
5590 {"gvsp.enable_heuristic", "gvsp_udp", 0},
5591 {"hdcp2.enable", "hdcp2_tcp", 0},
5592 {"hislip.enable_heuristic", "hislip_tcp", 0},
5593 {"infiniband.dissect_eoib", "mellanox_eoib", 1},
5594 {"infiniband.identify_payload", "eth_over_ib", 0},
5595 {"jxta.udp.heuristic", "jxta_udp", 0},
5596 {"jxta.tcp.heuristic", "jxta_tcp", 0},
5597 {"jxta.sctp.heuristic", "jxta_sctp", 0},
5598 {"mac-lte.heuristic_mac_lte_over_udp", "mac_lte_udp", 0},
5599 {"mbim.bulk_heuristic", "mbim_usb_bulk", 0},
5600 {"norm.heuristic_norm", "rmt_norm_udp", 0},
5601 {"openflow.heuristic", "openflow_tcp", 0},
5602 {"pdcp-lte.heuristic_pdcp_lte_over_udp", "pdcp_lte_udp", 0},
5603 {"rlc.heuristic_rlc_over_udp", "rlc_udp", 0},
5604 {"rlc-lte.heuristic_rlc_lte_over_udp", "rlc_lte_udp", 0},
5605 {"rtcp.heuristic_rtcp", "rtcp_udp", 1},
5606 {"rtcp.heuristic_rtcp", "rtcp_stun", 0},
5607 {"rtp.heuristic_rtp", "rtp_udp", 1},
5608 {"rtp.heuristic_rtp", "rtp_stun", 0},
5609 {"teredo.heuristic_teredo", "teredo_udp", 0},
5610 {"vssmonitoring.use_heuristics", "vssmonitoring_eth", 0},
5611 {"xml.heuristic", "xml_http", 1},
5612 {"xml.heuristic", "xml_sip", 1},
5613 {"xml.heuristic", "xml_media", 0},
5614 {"xml.heuristic_tcp", "xml_tcp", 0},
5615 {"xml.heuristic_udp", "xml_udp", 0},
5616 };
5617
5618 unsigned int i;
5619 heur_dtbl_entry_t* heuristic;
5620
5621
5622 for (i = 0; i < array_length(heur_prefs)(sizeof (heur_prefs) / sizeof (heur_prefs)[0]); i++)
5623 {
5624 if (strcmp(pref_name, heur_prefs[i].pref_name) == 0)
5625 {
5626 heuristic = find_heur_dissector_by_unique_short_name(heur_prefs[i].short_name);
5627 if (heuristic != NULL((void*)0)) {
5628 heuristic->enabled = ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0);
5629 }
5630
5631 if (!heur_prefs[i].more_dissectors)
5632 return true1;
5633 }
5634 }
5635
5636
5637 return false0;
5638}
5639
5640static bool_Bool
5641deprecated_enable_dissector_pref(char *pref_name, const char *value)
5642{
5643 struct dissector_pref_name
5644 {
5645 const char* pref_name;
5646 const char* short_name;
5647 };
5648
5649 struct dissector_pref_name dissector_prefs[] = {
5650 {"transum.tsumenabled", "TRANSUM"},
5651 {"snort.enable_snort_dissector", "Snort"},
5652 {"prp.enable", "PRP"},
5653 };
5654
5655 unsigned int i;
5656 int proto_id;
5657
5658 for (i = 0; i < array_length(dissector_prefs)(sizeof (dissector_prefs) / sizeof (dissector_prefs)[0]); i++)
5659 {
5660 if (strcmp(pref_name, dissector_prefs[i].pref_name) == 0)
5661 {
5662 proto_id = proto_get_id_by_short_name(dissector_prefs[i].short_name);
5663 if (proto_id >= 0)
5664 proto_set_decoding(proto_id, ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0));
5665 return true1;
5666 }
5667 }
5668
5669 return false0;
5670}
5671
5672static bool_Bool
5673deprecated_port_pref(char *pref_name, const char *value)
5674{
5675 struct port_pref_name
5676 {
5677 const char* pref_name;
5678 const char* module_name; /* the protocol filter name */
5679 const char* table_name;
5680 unsigned base;
5681 };
5682
5683 struct obsolete_pref_name
5684 {
5685 const char* pref_name;
5686 };
5687
5688 /* For now this is only supporting TCP/UDP port and RTP payload
5689 * types dissector preferences, which are assumed to be decimal */
5690 /* module_name is the filter name of the destination port preference,
5691 * which is usually the same as the original module but not
5692 * necessarily (e.g., if the preference is for what is now a PINO.)
5693 * XXX: Most of these were changed pre-2.0. Can we end support
5694 * for migrating legacy preferences at some point?
5695 */
5696 static const struct port_pref_name port_prefs[] = {
5697 /* TCP */
5698 {"cmp.tcp_alternate_port", "cmp", "tcp.port", 10},
5699 {"h248.tcp_port", "h248", "tcp.port", 10},
5700 {"cops.tcp.cops_port", "cops", "tcp.port", 10},
5701 {"dhcpfo.tcp_port", "dhcpfo", "tcp.port", 10},
5702 {"enttec.tcp_port", "enttec", "tcp.port", 10},
5703 {"forces.tcp_alternate_port", "forces", "tcp.port", 10},
5704 {"ged125.tcp_port", "ged125", "tcp.port", 10},
5705 {"hpfeeds.dissector_port", "hpfeeds", "tcp.port", 10},
5706 {"lsc.port", "lsc", "tcp.port", 10},
5707 {"megaco.tcp.txt_port", "megaco", "tcp.port", 10},
5708 {"netsync.tcp_port", "netsync", "tcp.port", 10},
5709 {"osi.tpkt_port", "osi", "tcp.port", 10},
5710 {"rsync.tcp_port", "rsync", "tcp.port", 10},
5711 {"sametime.tcp_port", "sametime", "tcp.port", 10},
5712 {"sigcomp.tcp.port2", "sigcomp", "tcp.port", 10},
5713 {"synphasor.tcp_port", "synphasor", "tcp.port", 10},
5714 {"tipc.alternate_port", "tipc", "tcp.port", 10},
5715 {"vnc.alternate_port", "vnc", "tcp.port", 10},
5716 {"scop.port", "scop", "tcp.port", 10},
5717 {"scop.port_secure", "scop", "tcp.port", 10},
5718 {"tpncp.tcp.trunkpack_port", "tpncp", "tcp.port", 10},
5719 /* UDP */
5720 {"h248.udp_port", "h248", "udp.port", 10},
5721 {"actrace.udp_port", "actrace", "udp.port", 10},
5722 {"brp.port", "brp", "udp.port", 10},
5723 {"bvlc.additional_udp_port", "bvlc", "udp.port", 10},
5724 {"capwap.udp.port.control", "capwap", "udp.port", 10},
5725 {"capwap.udp.port.data", "capwap", "udp.port", 10},
5726 {"coap.udp_port", "coap", "udp.port", 10},
5727 {"enttec.udp_port", "enttec", "udp.port", 10},
5728 {"forces.udp_alternate_port", "forces", "udp.port", 10},
5729 {"ldss.udp_port", "ldss", "udp.port", 10},
5730 {"lmp.udp_port", "lmp", "udp.port", 10},
5731 {"ltp.port", "ltp", "udp.port", 10},
5732 {"lwres.udp.lwres_port", "lwres", "udp.port", 10},
5733 {"megaco.udp.txt_port", "megaco", "udp.port", 10},
5734 {"pfcp.port_pfcp", "pfcp", "udp.port", 10},
5735 {"pgm.udp.encap_ucast_port", "pgm", "udp.port", 10},
5736 {"pgm.udp.encap_mcast_port", "pgm", "udp.port", 10},
5737 {"quic.udp.quic.port", "quic", "udp.port", 10},
5738 {"quic.udp.quics.port", "quic", "udp.port", 10},
5739 {"radius.alternate_port", "radius", "udp.port", 10},
5740 {"rdt.default_udp_port", "rdt", "udp.port", 10},
5741 {"alc.default.udp_port", "alc", "udp.port", 10},
5742 {"sigcomp.udp.port2", "sigcomp", "udp.port", 10},
5743 {"synphasor.udp_port", "synphasor", "udp.port", 10},
5744 {"tdmop.udpport", "tdmop", "udp.port", 10},
5745 {"uaudp.port1", "uaudp", "udp.port", 10},
5746 {"uaudp.port2", "uaudp", "udp.port", 10},
5747 {"uaudp.port3", "uaudp", "udp.port", 10},
5748 {"uaudp.port4", "uaudp", "udp.port", 10},
5749 {"uhd.dissector_port", "uhd", "udp.port", 10},
5750 {"vrt.dissector_port", "vrt", "udp.port", 10},
5751 {"tpncp.udp.trunkpack_port", "tpncp", "udp.port", 10},
5752 /* SCTP */
5753 {"hnbap.port", "hnbap", "sctp.port", 10},
5754 {"m2pa.port", "m2pa", "sctp.port", 10},
5755 {"megaco.sctp.txt_port", "megaco", "sctp.port", 10},
5756 {"rua.port", "rua", "sctp.port", 10},
5757 /* SCTP PPI */
5758 {"lapd.sctp_payload_protocol_identifier", "lapd", "sctp.ppi", 10},
5759 /* SCCP SSN */
5760 {"ranap.sccp_ssn", "ranap", "sccp.ssn", 10},
5761 };
5762
5763 static const struct port_pref_name port_range_prefs[] = {
5764 /* TCP */
5765 {"couchbase.tcp.ports", "couchbase", "tcp.port", 10},
5766 {"gsm_ipa.tcp_ports", "gsm_ipa", "tcp.port", 10},
5767 {"kafka.tcp.ports", "kafka", "tcp.port", 10},
5768 {"kt.tcp.ports", "kt", "tcp.port", 10},
5769 {"memcache.tcp.ports", "memcache", "tcp.port", 10},
5770 {"mrcpv2.tcp.port_range", "mrcpv2", "tcp.port", 10},
5771 {"pdu_transport.ports.tcp", "pdu_transport", "tcp.port", 10},
5772 {"rtsp.tcp.port_range", "rtsp", "tcp.port", 10},
5773 {"sip.tcp.ports", "sip", "tcp.port", 10},
5774 {"someip.ports.tcp", "someip", "tcp.port", 10},
5775 {"tds.tcp_ports", "tds", "tcp.port", 10},
5776 {"tpkt.tcp.ports", "tpkt", "tcp.port", 10},
5777 {"uma.tcp.ports", "uma", "tcp.port", 10},
5778 /* UDP */
5779 {"aruba_erm.udp.ports", "arubs_erm", "udp.port", 10},
5780 {"diameter.udp.ports", "diameter", "udp.port", 10},
5781 {"dmp.udp_ports", "dmp", "udp.port", 10},
5782 {"dns.udp.ports", "dns", "udp.port", 10},
5783 {"gsm_ipa.udp_ports", "gsm_ipa", "udp.port", 10},
5784 {"hcrt.dissector_udp_port", "hcrt", "udp.port", 10},
5785 {"memcache.udp.ports", "memcache", "udp.port", 10},
5786 {"nb_rtpmux.udp_ports", "nb_rtpmux", "udp.port", 10},
5787 {"gprs-ns.udp.ports", "gprs-ns", "udp.port", 10},
5788 {"p_mul.udp_ports", "p_mul", "udp.port", 10},
5789 {"pdu_transport.ports.udp", "pdu_transport", "udp.port", 10},
5790 {"radius.ports", "radius", "udp.port", 10},
5791 {"sflow.ports", "sflow", "udp.port", 10},
5792 {"someip.ports.udp", "someip", "udp.port", 10},
5793 {"sscop.udp.ports", "sscop", "udp.port", 10},
5794 {"tftp.udp_ports", "tftp", "udp.port", 10},
5795 {"tipc.udp.ports", "tipc", "udp.port", 10},
5796 /* RTP */
5797 {"amr.dynamic.payload.type", "amr", "rtp.pt", 10},
5798 {"amr.wb.dynamic.payload.type", "amr_wb", "rtp.pt", 10},
5799 {"dvb-s2_modeadapt.dynamic.payload.type", "dvb-s2_modeadapt", "rtp.pt", 10},
5800 {"evs.dynamic.payload.type", "evs", "rtp.pt", 10},
5801 {"h263p.dynamic.payload.type", "h263p", "rtp.pt", 10},
5802 {"h264.dynamic.payload.type", "h264", "rtp.pt", 10},
5803 {"h265.dynamic.payload.type", "h265", "rtp.pt", 10},
5804 {"ismacryp.dynamic.payload.type", "ismacryp", "rtp.pt", 10},
5805 {"iuup.dynamic.payload.type", "iuup", "rtp.pt", 10},
5806 {"lapd.rtp_payload_type", "lapd", "rtp.pt", 10},
5807 {"mp4ves.dynamic.payload.type", "mp4ves", "rtp.pt", 10},
5808 {"mtp2.rtp_payload_type", "mtp2", "rtp.pt", 10},
5809 {"opus.dynamic.payload.type", "opus", "rtp.pt", 10},
5810 {"rtp.rfc2198_payload_type", "rtp_rfc2198", "rtp.pt", 10},
5811 {"rtpevent.event_payload_type_value", "rtpevent", "rtp.pt", 10},
5812 {"rtpevent.cisco_nse_payload_type_value", "rtpevent", "rtp.pt", 10},
5813 {"rtpmidi.midi_payload_type_value", "rtpmidi", "rtp.pt", 10},
5814 {"vp8.dynamic.payload.type", "vp8", "rtp.pt", 10},
5815 /* SCTP */
5816 {"diameter.sctp.ports", "diameter", "sctp.port", 10},
5817 {"sgsap.sctp_ports", "sgsap", "sctp.port", 10},
5818 /* SCCP SSN */
5819 {"pcap.ssn", "pcap", "sccp.ssn", 10},
5820 };
5821
5822 /* These are subdissectors of TPKT/OSITP that used to have a
5823 TCP port preference even though they were never
5824 directly on TCP. Convert them to use Decode As
5825 with the TPKT dissector handle */
5826 static const struct port_pref_name tpkt_subdissector_port_prefs[] = {
5827 {"dap.tcp.port", "dap", "tcp.port", 10},
5828 {"disp.tcp.port", "disp", "tcp.port", 10},
5829 {"dop.tcp.port", "dop", "tcp.port", 10},
5830 {"dsp.tcp.port", "dsp", "tcp.port", 10},
5831 {"p1.tcp.port", "p1", "tcp.port", 10},
5832 {"p7.tcp.port", "p7", "tcp.port", 10},
5833 {"rdp.tcp.port", "rdp", "tcp.port", 10},
5834 };
5835
5836 /* These are obsolete preferences from the dissectors' view,
5837 (typically because of a switch from a single value to a
5838 range value) but the name of the preference conflicts
5839 with the generated preference name from the dissector table.
5840 Don't allow the obsolete preference through to be handled */
5841 static const struct obsolete_pref_name obsolete_prefs[] = {
5842 {"diameter.tcp.port"},
5843 {"kafka.tcp.port"},
5844 {"mrcpv2.tcp.port"},
5845 {"rtsp.tcp.port"},
5846 {"sip.tcp.port"},
5847 {"t38.tcp.port"},
5848 };
5849
5850 unsigned int i;
5851 unsigned uval;
5852 dissector_table_t sub_dissectors;
5853 dissector_handle_t handle, tpkt_handle;
5854 module_t *module;
5855 pref_t *pref;
5856
5857 static bool_Bool sanity_checked;
5858 if (!sanity_checked) {
5859 sanity_checked = true1;
5860 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5861 module = prefs_find_module(port_prefs[i].module_name);
5862 if (!module) {
5863 ws_warning("Deprecated ports pref check - module '%s' not found", port_prefs[i].module_name)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5863, __func__, "Deprecated ports pref check - module '%s' not found"
, port_prefs[i].module_name); } } while (0)
;
5864 continue;
5865 }
5866 pref = prefs_find_preference(module, port_prefs[i].table_name);
5867 if (!pref) {
5868 ws_warning("Deprecated ports pref '%s.%s' not found", module->name, port_prefs[i].table_name)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5868, __func__, "Deprecated ports pref '%s.%s' not found", module
->name, port_prefs[i].table_name); } } while (0)
;
5869 continue;
5870 }
5871 if (pref->type != PREF_DECODE_AS_RANGE) {
5872 ws_warning("Deprecated ports pref '%s.%s' has wrong type: %#x (%s)", module->name, port_prefs[i].table_name, pref->type, prefs_pref_type_name(pref))do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5872, __func__, "Deprecated ports pref '%s.%s' has wrong type: %#x (%s)"
, module->name, port_prefs[i].table_name, pref->type, prefs_pref_type_name
(pref)); } } while (0)
;
5873 }
5874 }
5875 }
5876
5877 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5878 if (strcmp(pref_name, port_prefs[i].pref_name) == 0) {
5879 if (!ws_basestrtou32(value, NULL((void*)0), &uval, port_prefs[i].base))
5880 return false0; /* number was bad */
5881
5882 module = prefs_find_module(port_prefs[i].module_name);
5883 pref = prefs_find_preference(module, port_prefs[i].table_name);
5884 if (pref != NULL((void*)0)) {
5885 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5886 if (pref->type == PREF_DECODE_AS_RANGE) {
5887 // The legacy preference was a port number, but the new
5888 // preference is a port range. Add to existing range.
5889 if (uval) {
5890 prefs_range_add_value(pref, uval);
5891 }
5892 }
5893 }
5894
5895 /* If the value is zero, it wouldn't add to the Decode As tables */
5896 if (uval != 0)
5897 {
5898 sub_dissectors = find_dissector_table(port_prefs[i].table_name);
5899 if (sub_dissectors != NULL((void*)0)) {
5900 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5901 if (handle != NULL((void*)0)) {
5902 dissector_change_uint(port_prefs[i].table_name, uval, handle);
5903 decode_build_reset_list(port_prefs[i].table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(uval)((gpointer) (gulong) (uval)), NULL((void*)0), NULL((void*)0));
5904 }
5905 }
5906 }
5907
5908 return true1;
5909 }
5910 }
5911
5912 for (i = 0; i < array_length(port_range_prefs)(sizeof (port_range_prefs) / sizeof (port_range_prefs)[0]); i++)
5913 {
5914 if (strcmp(pref_name, port_range_prefs[i].pref_name) == 0)
5915 {
5916 uint32_t range_i, range_j;
5917
5918 sub_dissectors = find_dissector_table(port_range_prefs[i].table_name);
5919 if (sub_dissectors != NULL((void*)0)) {
5920 switch (dissector_table_get_type(sub_dissectors)) {
5921 case FT_UINT8:
5922 case FT_UINT16:
5923 case FT_UINT24:
5924 case FT_UINT32:
5925 break;
5926
5927 default:
5928 ws_error("The dissector table %s (%s) is not an integer type - are you using a buggy plugin?", port_range_prefs[i].table_name, get_dissector_table_ui_name(port_range_prefs[i].table_name))ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5928
, __func__, "The dissector table %s (%s) is not an integer type - are you using a buggy plugin?"
, port_range_prefs[i].table_name, get_dissector_table_ui_name
(port_range_prefs[i].table_name))
;
5929 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5929
, __func__, "assertion \"not reached\" failed")
;
5930 }
5931
5932 module = prefs_find_module(port_range_prefs[i].module_name);
5933 pref = prefs_find_preference(module, port_range_prefs[i].table_name);
5934 if (pref != NULL((void*)0))
5935 {
5936 if (!prefs_set_range_value_work(pref, value, true1, &module->prefs_changed_flags))
5937 {
5938 return false0; /* number was bad */
5939 }
5940
5941 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5942 if (handle != NULL((void*)0)) {
5943
5944 for (range_i = 0; range_i < (*pref->varp.range)->nranges; range_i++) {
5945 for (range_j = (*pref->varp.range)->ranges[range_i].low; range_j < (*pref->varp.range)->ranges[range_i].high; range_j++) {
5946 dissector_change_uint(port_range_prefs[i].table_name, range_j, handle);
5947 decode_build_reset_list(port_range_prefs[i].table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(range_j)((gpointer) (gulong) (range_j)), NULL((void*)0), NULL((void*)0));
5948 }
5949
5950 dissector_change_uint(port_range_prefs[i].table_name, (*pref->varp.range)->ranges[range_i].high, handle);
5951 decode_build_reset_list(port_range_prefs[i].table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[range_i].high)((gpointer) (gulong) ((*pref->varp.range)->ranges[range_i
].high))
, NULL((void*)0), NULL((void*)0));
5952 }
5953 }
5954 }
5955 }
5956
5957 return true1;
5958 }
5959 }
5960
5961 for (i = 0; i < array_length(tpkt_subdissector_port_prefs)(sizeof (tpkt_subdissector_port_prefs) / sizeof (tpkt_subdissector_port_prefs
)[0])
; i++)
5962 {
5963 if (strcmp(pref_name, tpkt_subdissector_port_prefs[i].pref_name) == 0)
5964 {
5965 /* XXX - give an error if it doesn't fit in a unsigned? */
5966 if (!ws_basestrtou32(value, NULL((void*)0), &uval, tpkt_subdissector_port_prefs[i].base))
5967 return false0; /* number was bad */
5968
5969 /* If the value is 0 or 102 (default TPKT port), don't add to the Decode As tables */
5970 if ((uval != 0) && (uval != 102))
5971 {
5972 tpkt_handle = find_dissector("tpkt");
5973 if (tpkt_handle != NULL((void*)0)) {
5974 dissector_change_uint(tpkt_subdissector_port_prefs[i].table_name, uval, tpkt_handle);
5975 }
5976 }
5977
5978 return true1;
5979 }
5980 }
5981
5982 for (i = 0; i < array_length(obsolete_prefs)(sizeof (obsolete_prefs) / sizeof (obsolete_prefs)[0]); i++)
5983 {
5984 if (strcmp(pref_name, obsolete_prefs[i].pref_name) == 0)
5985 {
5986 /* Just ignore the preference */
5987 return true1;
5988 }
5989 }
5990 return false0;
5991}
5992
5993static prefs_set_pref_e
5994set_pref(char *pref_name, const char *value, void *private_data,
5995 bool_Bool return_range_errors)
5996{
5997 unsigned cval;
5998 unsigned uval;
5999 bool_Bool bval;
6000 int enum_val, ival;
6001 double fval;
6002 char *dotp, *last_dotp;
6003 module_t *module, *containing_module, *target_module;
6004 pref_t *pref;
6005 bool_Bool converted_pref = false0;
6006
6007 target_module = (module_t*)private_data;
6008
6009 if (deprecated_heur_dissector_pref(pref_name, value)) {
6010 /* Handled within deprecated_heur_dissector_pref() if found */
6011 } else if (deprecated_enable_dissector_pref(pref_name, value)) {
6012 /* Handled within deprecated_enable_dissector_pref() if found */
6013 } else if (deprecated_port_pref(pref_name, value)) {
6014 /* Handled within deprecated_port_pref() if found */
6015 } else if (strcmp(pref_name, "console.log.level") == 0) {
6016 /* Handled on the command line within ws_log_parse_args() */
6017 return PREFS_SET_OK;
6018 } else {
6019 /* To which module does this preference belong? */
6020 module = NULL((void*)0);
6021 last_dotp = pref_name;
6022 while (!module) {
6023 dotp = strchr(last_dotp, '.');
6024 if (dotp == NULL((void*)0)) {
6025 /* Either there's no such module, or no module was specified.
6026 In either case, that means there's no such preference. */
6027 return PREFS_SET_NO_SUCH_PREF;
6028 }
6029 *dotp = '\0'; /* separate module and preference name */
6030 module = prefs_find_module(pref_name);
6031
6032 /*
6033 * XXX - "Diameter" rather than "diameter" was used in earlier
6034 * versions of Wireshark; if we didn't find the module, and its name
6035 * was "Diameter", look for "diameter" instead.
6036 *
6037 * In addition, the BEEP protocol used to be the BXXP protocol,
6038 * so if we didn't find the module, and its name was "bxxp",
6039 * look for "beep" instead.
6040 *
6041 * Also, the preferences for GTP v0 and v1 were combined under
6042 * a single "gtp" heading, and the preferences for SMPP were
6043 * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
6044 * However, SMPP now has its own preferences, so we just map
6045 * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
6046 *
6047 * We also renamed "dcp" to "dccp", "x.25" to "x25", "x411" to "p1"
6048 * and "nsip" to "gprs_ns".
6049 *
6050 * The SynOptics Network Management Protocol (SONMP) is now known by
6051 * its modern name, the Nortel Discovery Protocol (NDP).
6052 */
6053 if (module == NULL((void*)0)) {
6054 /*
6055 * See if there's a backwards-compatibility name
6056 * that maps to this module.
6057 */
6058 module = prefs_find_module_alias(pref_name);
6059 if (module == NULL((void*)0)) {
6060 /*
6061 * There's no alias for the module; see if the
6062 * module name matches any protocol aliases.
6063 */
6064 header_field_info *hfinfo = proto_registrar_get_byalias(pref_name);
6065 if (hfinfo) {
6066 module = (module_t *) wmem_tree_lookup_string(prefs_modules, hfinfo->abbrev, WMEM_TREE_STRING_NOCASE0x00000001);
6067 }
6068 }
6069 if (module) {
6070 converted_pref = true1;
6071 }
6072 }
6073 *dotp = '.'; /* put the preference string back */
6074 dotp++; /* skip past separator to preference name */
6075 last_dotp = dotp;
6076 }
6077
6078 /* The pref is located in the module or a submodule.
6079 * Assume module, then search for a submodule holding the pref. */
6080 containing_module = module;
6081 pref = prefs_find_preference_with_submodule(module, dotp, &containing_module);
6082
6083 if (pref == NULL((void*)0)) {
6084 /* "gui" prefix was added to column preferences for better organization
6085 * within the preferences file
6086 */
6087 if (module == gui_column_module) {
6088 /* While this has a subtree, there is no apply callback, so no
6089 * need to use prefs_find_preference_with_submodule to update
6090 * containing_module. It would not be useful. */
6091 pref = prefs_find_preference(module, pref_name);
6092 }
6093 else if (strcmp(module->name, "tcp") == 0) {
6094 /* Handle old names for TCP preferences. */
6095 if (strcmp(dotp, "dissect_experimental_options_with_magic") == 0)
6096 pref = prefs_find_preference(module, "dissect_experimental_options_rfc6994");
6097 } else if (strcmp(module->name, "extcap") == 0) {
6098 /* Handle the old "sshdump.remotesudo" preference; map it to the new
6099 "sshdump.remotepriv" preference, and map the boolean values to the
6100 appropriate strings of the new preference. */
6101 if (strcmp(dotp, "sshdump.remotesudo") == 0) {
6102 pref = prefs_find_preference(module, "sshdump.remotepriv");
6103 if (g_ascii_strcasecmp(value, "true") == 0)
6104 value = "sudo";
6105 else
6106 value = "none";
6107 }
6108 }
6109 if (pref) {
6110 converted_pref = true1;
6111 }
6112 }
6113 if (pref == NULL((void*)0) ) {
6114 if (strcmp(module->name, "extcap") == 0 && g_list_length(module->prefs) <= 1) {
6115 /*
6116 * Assume that we've skipped extcap preference registration
6117 * and that only extcap.gui_save_on_start is loaded.
6118 */
6119 return PREFS_SET_OK;
6120 }
6121 return PREFS_SET_NO_SUCH_PREF; /* no such preference */
6122 }
6123
6124 if (target_module && target_module != containing_module) {
6125 /* Ignore */
6126 return PREFS_SET_OK;
6127 }
6128
6129 if (pref->obsolete)
6130 return PREFS_SET_OBSOLETE; /* no such preference any more */
6131
6132 if (converted_pref) {
6133 ws_warning("Preference \"%s\" has been converted to \"%s.%s\"\n"do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6135, __func__, "Preference \"%s\" has been converted to \"%s.%s\"\n"
"Save your preferences to make this change permanent.", pref_name
, module->name ? module->name : module->parent->name
, prefs_get_name(pref)); } } while (0)
6134 "Save your preferences to make this change permanent.",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6135, __func__, "Preference \"%s\" has been converted to \"%s.%s\"\n"
"Save your preferences to make this change permanent.", pref_name
, module->name ? module->name : module->parent->name
, prefs_get_name(pref)); } } while (0)
6135 pref_name, module->name ? module->name : module->parent->name, prefs_get_name(pref))do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6135, __func__, "Preference \"%s\" has been converted to \"%s.%s\"\n"
"Save your preferences to make this change permanent.", pref_name
, module->name ? module->name : module->parent->name
, prefs_get_name(pref)); } } while (0)
;
6136 }
6137
6138 switch (pref->type) {
6139
6140 case PREF_UINT:
6141 if (!ws_basestrtou32(value, NULL((void*)0), &uval, pref->info.base))
6142 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6143 if (*pref->varp.uint != uval) {
6144 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6145 *pref->varp.uint = uval;
6146 }
6147 break;
6148
6149 case PREF_INT:
6150 if (!ws_strtoi32(value, NULL((void*)0), &ival))
6151 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6152 if (*pref->varp.intp != ival) {
6153 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6154 *pref->varp.intp = ival;
6155 }
6156 break;
6157
6158 case PREF_FLOAT:
6159 fval = g_ascii_strtod(value, NULL((void*)0));
6160 if (errno(*__errno_location ()) == ERANGE34)
6161 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6162
6163 if (*pref->varp.floatp != fval) {
6164 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6165 *pref->varp.floatp = fval;
6166 }
6167 break;
6168
6169 case PREF_BOOL:
6170 /* XXX - give an error if it's neither "true" nor "false"? */
6171 if (g_ascii_strcasecmp(value, "true") == 0)
6172 bval = true1;
6173 else
6174 bval = false0;
6175 if (*pref->varp.boolp != bval) {
6176 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6177 *pref->varp.boolp = bval;
6178 }
6179 break;
6180
6181 case PREF_ENUM:
6182 /* XXX - give an error if it doesn't match? */
6183 enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
6184 *pref->varp.enump);
6185 if (*pref->varp.enump != enum_val) {
6186 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6187 *pref->varp.enump = enum_val;
6188 }
6189 break;
6190
6191 case PREF_STRING:
6192 case PREF_SAVE_FILENAME:
6193 case PREF_OPEN_FILENAME:
6194 case PREF_DIRNAME:
6195 case PREF_DISSECTOR:
6196 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
6197 break;
6198
6199 case PREF_PASSWORD:
6200 /* Read value is every time empty */
6201 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, "", pref_current);
6202 break;
6203
6204 case PREF_RANGE:
6205 {
6206 if (!prefs_set_range_value_work(pref, value, return_range_errors,
6207 &containing_module->prefs_changed_flags))
6208 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6209 break;
6210 }
6211 case PREF_DECODE_AS_RANGE:
6212 {
6213 /* This is for backwards compatibility in case any of the preferences
6214 that shared the "Decode As" preference name and used to be PREF_RANGE
6215 are now applied directly to the Decode As functionality */
6216 range_t *newrange;
6217 dissector_table_t sub_dissectors;
6218 dissector_handle_t handle;
6219 uint32_t i, j;
6220
6221 if (range_convert_str_work(pref->scope, &newrange, value, pref->info.max_value,
6222 return_range_errors) != CVT_NO_ERROR) {
6223 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6224 }
6225
6226 if (!ranges_are_equal(*pref->varp.range, newrange)) {
6227 wmem_free(pref->scope, *pref->varp.range);
6228 *pref->varp.range = newrange;
6229 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6230
6231 const char* table_name = prefs_get_dissector_table(pref);
6232 sub_dissectors = find_dissector_table(table_name);
6233 if (sub_dissectors != NULL((void*)0)) {
6234 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
6235 if (handle != NULL((void*)0)) {
6236 /* Delete all of the old values from the dissector table */
6237 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
6238 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
6239 dissector_delete_uint(table_name, j, handle);
6240 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j)((gpointer) (gulong) (j)), NULL((void*)0), NULL((void*)0));
6241 }
6242
6243 dissector_delete_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
6244 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high)((gpointer) (gulong) ((*pref->varp.range)->ranges[i].high
))
, NULL((void*)0), NULL((void*)0));
6245 }
6246
6247 /* Add new values to the dissector table */
6248 for (i = 0; i < newrange->nranges; i++) {
6249 for (j = newrange->ranges[i].low; j < newrange->ranges[i].high; j++) {
6250 dissector_change_uint(table_name, j, handle);
6251 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j)((gpointer) (gulong) (j)), NULL((void*)0), NULL((void*)0));
6252 }
6253
6254 dissector_change_uint(table_name, newrange->ranges[i].high, handle);
6255 decode_build_reset_list(table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(newrange->ranges[i].high)((gpointer) (gulong) (newrange->ranges[i].high)), NULL((void*)0), NULL((void*)0));
6256 }
6257
6258 /* XXX - Do we save the decode_as_entries file here? */
6259 }
6260 }
6261 } else {
6262 wmem_free(pref->scope, newrange);
6263 }
6264 break;
6265 }
6266
6267 case PREF_COLOR:
6268 {
6269 if (!ws_hexstrtou32(value, NULL((void*)0), &cval))
6270 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6271 if ((pref->varp.colorp->red != RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
) ||
6272 (pref->varp.colorp->green != GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255))) ||
6273 (pref->varp.colorp->blue != BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255)))) {
6274 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6275 pref->varp.colorp->red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
6276 pref->varp.colorp->green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
6277 pref->varp.colorp->blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
6278 }
6279 break;
6280 }
6281
6282 case PREF_CUSTOM:
6283 return pref->custom_cbs.set_cb(pref, value, &containing_module->prefs_changed_flags);
6284
6285 case PREF_STATIC_TEXT:
6286 case PREF_UAT:
6287 break;
6288
6289 case PREF_PROTO_TCP_SNDAMB_ENUM:
6290 {
6291 /* There's no point in setting the TCP sequence override
6292 * value from the command line, because the pref is different
6293 * for each frame and reset to the default (0) for each new
6294 * file.
6295 */
6296 break;
6297 }
6298 }
6299 }
6300
6301 return PREFS_SET_OK;
6302}
6303
6304typedef struct {
6305 FILE *pf;
6306 bool_Bool is_gui_module;
6307} write_gui_pref_arg_t;
6308
6309const char *
6310prefs_pref_type_name(pref_t *pref)
6311{
6312 const char *type_name = "[Unknown]";
6313
6314 if (!pref) {
6315 return type_name; /* ...or maybe assert? */
6316 }
6317
6318 if (pref->obsolete) {
6319 type_name = "Obsolete";
6320 } else {
6321 switch (pref->type) {
6322
6323 case PREF_UINT:
6324 switch (pref->info.base) {
6325
6326 case 10:
6327 type_name = "Decimal";
6328 break;
6329
6330 case 8:
6331 type_name = "Octal";
6332 break;
6333
6334 case 16:
6335 type_name = "Hexadecimal";
6336 break;
6337 }
6338 break;
6339
6340 case PREF_INT:
6341 type_name = "Integer";
6342 break;
6343
6344 case PREF_FLOAT:
6345 type_name = "Float";
6346 break;
6347
6348 case PREF_BOOL:
6349 type_name = "Boolean";
6350 break;
6351
6352 case PREF_ENUM:
6353 case PREF_PROTO_TCP_SNDAMB_ENUM:
6354 type_name = "Choice";
6355 break;
6356
6357 case PREF_STRING:
6358 type_name = "String";
6359 break;
6360
6361 case PREF_SAVE_FILENAME:
6362 case PREF_OPEN_FILENAME:
6363 type_name = "Filename";
6364 break;
6365
6366 case PREF_DIRNAME:
6367 type_name = "Directory";
6368 break;
6369
6370 case PREF_RANGE:
6371 type_name = "Range";
6372 break;
6373
6374 case PREF_COLOR:
6375 type_name = "Color";
6376 break;
6377
6378 case PREF_CUSTOM:
6379 if (pref->custom_cbs.type_name_cb)
6380 return pref->custom_cbs.type_name_cb();
6381 type_name = "Custom";
6382 break;
6383
6384 case PREF_DECODE_AS_RANGE:
6385 type_name = "Range (for Decode As)";
6386 break;
6387
6388 case PREF_STATIC_TEXT:
6389 type_name = "Static text";
6390 break;
6391
6392 case PREF_UAT:
6393 type_name = "UAT";
6394 break;
6395
6396 case PREF_PASSWORD:
6397 type_name = "Password";
6398 break;
6399
6400 case PREF_DISSECTOR:
6401 type_name = "Dissector";
6402 break;
6403 }
6404 }
6405
6406 return type_name;
6407}
6408
6409unsigned int
6410prefs_get_effect_flags(pref_t *pref)
6411{
6412 if (pref == NULL((void*)0))
6413 return 0;
6414
6415 return pref->effect_flags;
6416}
6417
6418void
6419prefs_set_effect_flags(pref_t *pref, unsigned int flags)
6420{
6421 if (pref != NULL((void*)0)) {
6422 if (flags == 0) {
6423 ws_error("Setting \"%s\" preference effect flags to 0", pref->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6423
, __func__, "Setting \"%s\" preference effect flags to 0", pref
->name)
;
6424 }
6425 pref->effect_flags = flags;
6426 }
6427}
6428
6429void
6430prefs_set_effect_flags_by_name(module_t * module, const char *pref, unsigned int flags)
6431{
6432 prefs_set_effect_flags(prefs_find_preference(module, pref), flags);
6433}
6434
6435unsigned int
6436prefs_get_module_effect_flags(module_t * module)
6437{
6438 if (module == NULL((void*)0))
6439 return 0;
6440
6441 return module->effect_flags;
6442}
6443
6444void
6445prefs_set_module_effect_flags(module_t * module, unsigned int flags)
6446{
6447 if (module != NULL((void*)0)) {
6448 if (flags == 0) {
6449 ws_error("Setting module \"%s\" preference effect flags to 0", module->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6449
, __func__, "Setting module \"%s\" preference effect flags to 0"
, module->name)
;
6450 }
6451 module->effect_flags = flags;
6452 }
6453}
6454
6455char *
6456prefs_pref_type_description(pref_t *pref)
6457{
6458 const char *type_desc = "An unknown preference type";
6459
6460 if (!pref) {
6461 return ws_strdup_printf("%s.", type_desc)wmem_strdup_printf(((void*)0), "%s.", type_desc); /* ...or maybe assert? */
6462 }
6463
6464 if (pref->obsolete) {
6465 type_desc = "An obsolete preference";
6466 } else {
6467 switch (pref->type) {
6468
6469 case PREF_UINT:
6470 switch (pref->info.base) {
6471
6472 case 10:
6473 type_desc = "A decimal number";
6474 break;
6475
6476 case 8:
6477 type_desc = "An octal number";
6478 break;
6479
6480 case 16:
6481 type_desc = "A hexadecimal number";
6482 break;
6483 }
6484 break;
6485
6486 case PREF_INT:
6487 type_desc = "A decimal number";
6488 break;
6489
6490 case PREF_FLOAT:
6491 type_desc = "A floating point number";
6492 break;
6493
6494 case PREF_BOOL:
6495 type_desc = "true or false (case-insensitive)";
6496 break;
6497
6498 case PREF_ENUM:
6499 case PREF_PROTO_TCP_SNDAMB_ENUM:
6500 {
6501 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6502 GString *enum_str = g_string_new("One of: ");
6503 GString *desc_str = g_string_new("\nEquivalently, one of: ");
6504 bool_Bool distinct = false0;
6505 while (enum_valp->name != NULL((void*)0)) {
6506 g_string_append(enum_str, enum_valp->name)(__builtin_constant_p (enum_valp->name) ? __extension__ ({
const char * const __val = (enum_valp->name); g_string_append_len_inline
(enum_str, __val, (__val != ((void*)0)) ? (gssize) strlen ((
(__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(enum_str, enum_valp->name, (gssize) -1))
;
6507 g_string_append(desc_str, enum_valp->description)(__builtin_constant_p (enum_valp->description) ? __extension__
({ const char * const __val = (enum_valp->description); g_string_append_len_inline
(desc_str, __val, (__val != ((void*)0)) ? (gssize) strlen ((
(__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(desc_str, enum_valp->description, (gssize) -1))
;
6508 if (g_strcmp0(enum_valp->name, enum_valp->description) != 0) {
6509 distinct = true1;
6510 }
6511 enum_valp++;
6512 if (enum_valp->name != NULL((void*)0)) {
6513 g_string_append(enum_str, ", ")(__builtin_constant_p (", ") ? __extension__ ({ const char * const
__val = (", "); g_string_append_len_inline (enum_str, __val,
(__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)
)) : (gssize) -1); }) : g_string_append_len_inline (enum_str,
", ", (gssize) -1))
;
6514 g_string_append(desc_str, ", ")(__builtin_constant_p (", ") ? __extension__ ({ const char * const
__val = (", "); g_string_append_len_inline (desc_str, __val,
(__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)
)) : (gssize) -1); }) : g_string_append_len_inline (desc_str,
", ", (gssize) -1))
;
6515 }
6516 }
6517 if (distinct) {
6518 g_string_append(enum_str, desc_str->str)(__builtin_constant_p (desc_str->str) ? __extension__ ({ const
char * const __val = (desc_str->str); g_string_append_len_inline
(enum_str, __val, (__val != ((void*)0)) ? (gssize) strlen ((
(__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(enum_str, desc_str->str, (gssize) -1))
;
6519 }
6520 g_string_free(desc_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(desc_str), ((!(0)))) : g_string_free_and_steal (desc_str)) :
(g_string_free) ((desc_str), ((!(0)))))
;
6521 g_string_append(enum_str, "\n(case-insensitive).")(__builtin_constant_p ("\n(case-insensitive).") ? __extension__
({ const char * const __val = ("\n(case-insensitive)."); g_string_append_len_inline
(enum_str, __val, (__val != ((void*)0)) ? (gssize) strlen ((
(__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(enum_str, "\n(case-insensitive).", (gssize) -1))
;
6522 return g_string_free(enum_str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((enum_str
), ((0))) : g_string_free_and_steal (enum_str)) : (g_string_free
) ((enum_str), ((0))))
;
6523 }
6524
6525 case PREF_STRING:
6526 type_desc = "A string";
6527 break;
6528
6529 case PREF_SAVE_FILENAME:
6530 case PREF_OPEN_FILENAME:
6531 type_desc = "A path to a file";
6532 break;
6533
6534 case PREF_DIRNAME:
6535 type_desc = "A path to a directory";
6536 break;
6537
6538 case PREF_RANGE:
6539 {
6540 type_desc = "A string denoting an positive integer range (e.g., \"1-20,30-40\")";
6541 break;
6542 }
6543
6544 case PREF_COLOR:
6545 {
6546 type_desc = "A six-digit hexadecimal RGB color triplet (e.g. fce94f)";
6547 break;
6548 }
6549
6550 case PREF_CUSTOM:
6551 if (pref->custom_cbs.type_description_cb)
6552 return pref->custom_cbs.type_description_cb();
6553 type_desc = "A custom value";
6554 break;
6555
6556 case PREF_DECODE_AS_RANGE:
6557 type_desc = "A string denoting an positive integer range for Decode As";
6558 break;
6559
6560 case PREF_STATIC_TEXT:
6561 type_desc = "[Static text]";
6562 break;
6563
6564 case PREF_UAT:
6565 type_desc = "Configuration data stored in its own file";
6566 break;
6567
6568 case PREF_PASSWORD:
6569 type_desc = "Password (never stored on disk)";
6570 break;
6571
6572 case PREF_DISSECTOR:
6573 type_desc = "A dissector name";
6574 break;
6575
6576 default:
6577 break;
6578 }
6579 }
6580
6581 return g_strdup(type_desc)g_strdup_inline (type_desc);
6582}
6583
6584bool_Bool
6585prefs_pref_is_default(pref_t *pref)
6586{
6587 if (!pref) return false0;
6588
6589 if (pref->obsolete) {
6590 return false0;
6591 }
6592
6593 switch (pref->type) {
6594
6595 case PREF_UINT:
6596 if (pref->default_val.uint == *pref->varp.uint)
6597 return true1;
6598 break;
6599
6600 case PREF_INT:
6601 if (pref->default_val.intval == *pref->varp.intp)
6602 return true1;
6603 break;
6604
6605 case PREF_FLOAT:
6606 if (pref->default_val.floatval == *pref->varp.floatp)
6607 return true1;
6608 break;
6609
6610 case PREF_BOOL:
6611 if (pref->default_val.boolval == *pref->varp.boolp)
6612 return true1;
6613 break;
6614
6615 case PREF_ENUM:
6616 case PREF_PROTO_TCP_SNDAMB_ENUM:
6617 if (pref->default_val.enumval == *pref->varp.enump)
6618 return true1;
6619 break;
6620
6621 case PREF_STRING:
6622 case PREF_SAVE_FILENAME:
6623 case PREF_OPEN_FILENAME:
6624 case PREF_DIRNAME:
6625 case PREF_PASSWORD:
6626 case PREF_DISSECTOR:
6627 if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
6628 return true1;
6629 break;
6630
6631 case PREF_DECODE_AS_RANGE:
6632 case PREF_RANGE:
6633 {
6634 if ((ranges_are_equal(pref->default_val.range, *pref->varp.range)))
6635 return true1;
6636 break;
6637 }
6638
6639 case PREF_COLOR:
6640 {
6641 if ((pref->default_val.color.red == pref->varp.colorp->red) &&
6642 (pref->default_val.color.green == pref->varp.colorp->green) &&
6643 (pref->default_val.color.blue == pref->varp.colorp->blue))
6644 return true1;
6645 break;
6646 }
6647
6648 case PREF_CUSTOM:
6649 return pref->custom_cbs.is_default_cb(pref);
6650
6651 case PREF_STATIC_TEXT:
6652 case PREF_UAT:
6653 return false0;
6654 /* ws_assert_not_reached(); */
6655 break;
6656 }
6657
6658 return false0;
6659}
6660
6661char *
6662prefs_pref_to_str(pref_t *pref, pref_source_t source)
6663{
6664 const char *pref_text = "[Unknown]";
6665 void *valp; /* pointer to preference value */
6666 color_t *pref_color;
6667 char *tmp_value, *ret_value;
6668
6669 if (!pref) {
6670 return g_strdup(pref_text)g_strdup_inline (pref_text);
6671 }
6672
6673 switch (source) {
6674 case pref_default:
6675 valp = &pref->default_val;
6676 /* valp = &boolval, &enumval, etc. are implied by union property */
6677 pref_color = &pref->default_val.color;
6678 break;
6679 case pref_stashed:
6680 valp = &pref->stashed_val;
6681 /* valp = &boolval, &enumval, etc. are implied by union property */
6682 pref_color = &pref->stashed_val.color;
6683 break;
6684 case pref_current:
6685 valp = pref->varp.uint;
6686 /* valp = boolval, enumval, etc. are implied by union property */
6687 pref_color = pref->varp.colorp;
6688 break;
6689 default:
6690 return g_strdup(pref_text)g_strdup_inline (pref_text);
6691 }
6692
6693 if (pref->obsolete) {
6694 pref_text = "[Obsolete]";
6695 } else {
6696 switch (pref->type) {
6697
6698 case PREF_UINT:
6699 {
6700 unsigned pref_uint = *(unsigned *) valp;
6701 switch (pref->info.base) {
6702
6703 case 10:
6704 return ws_strdup_printf("%u", pref_uint)wmem_strdup_printf(((void*)0), "%u", pref_uint);
6705
6706 case 8:
6707 return ws_strdup_printf("%#o", pref_uint)wmem_strdup_printf(((void*)0), "%#o", pref_uint);
6708
6709 case 16:
6710 return ws_strdup_printf("%#x", pref_uint)wmem_strdup_printf(((void*)0), "%#x", pref_uint);
6711 }
6712 break;
6713 }
6714 case PREF_INT:
6715 return ws_strdup_printf("%d", *(int*)valp)wmem_strdup_printf(((void*)0), "%d", *(int*)valp);
6716
6717 case PREF_FLOAT:
6718 return ws_strdup_printf("%.*f", pref->info.base, *(double*)valp)wmem_strdup_printf(((void*)0), "%.*f", pref->info.base, *(
double*)valp)
;
6719
6720 case PREF_BOOL:
6721 return g_strdup((*(bool *) valp) ? "TRUE" : "FALSE")g_strdup_inline ((*(_Bool *) valp) ? "TRUE" : "FALSE");
6722
6723 case PREF_ENUM:
6724 case PREF_PROTO_TCP_SNDAMB_ENUM:
6725 {
6726 int pref_enumval = *(int *) valp;
6727 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6728 /*
6729 * TODO - We write the "description" value, because the "name" values
6730 * weren't validated to be command line friendly until 5.0, and a few
6731 * of them had to be changed. This allows older versions of Wireshark
6732 * to read preferences that they supported, as we supported either
6733 * the short name or the description when reading the preference files
6734 * or an "-o" option. Once 5.0 is the oldest supported version, switch
6735 * to writing the name below.
6736 */
6737 while (enum_valp->name != NULL((void*)0)) {
6738 if (enum_valp->value == pref_enumval)
6739 return g_strdup(enum_valp->description)g_strdup_inline (enum_valp->description);
6740 enum_valp++;
6741 }
6742 break;
6743 }
6744
6745 case PREF_STRING:
6746 case PREF_SAVE_FILENAME:
6747 case PREF_OPEN_FILENAME:
6748 case PREF_DIRNAME:
6749 case PREF_PASSWORD:
6750 case PREF_DISSECTOR:
6751 return prefs_sanitize_string(*(const char **) valp);
6752
6753 case PREF_DECODE_AS_RANGE:
6754 case PREF_RANGE:
6755 /* Convert wmem to g_alloc memory */
6756 tmp_value = range_convert_range(NULL((void*)0), *(range_t **) valp);
6757 ret_value = g_strdup(tmp_value)g_strdup_inline (tmp_value);
6758 wmem_free(NULL((void*)0), tmp_value);
6759 return ret_value;
6760
6761 case PREF_COLOR:
6762 return ws_strdup_printf("%02x%02x%02x",wmem_strdup_printf(((void*)0), "%02x%02x%02x", (pref_color->
red * 255 / 65535), (pref_color->green * 255 / 65535), (pref_color
->blue * 255 / 65535))
6763 (pref_color->red * 255 / 65535),wmem_strdup_printf(((void*)0), "%02x%02x%02x", (pref_color->
red * 255 / 65535), (pref_color->green * 255 / 65535), (pref_color
->blue * 255 / 65535))
6764 (pref_color->green * 255 / 65535),wmem_strdup_printf(((void*)0), "%02x%02x%02x", (pref_color->
red * 255 / 65535), (pref_color->green * 255 / 65535), (pref_color
->blue * 255 / 65535))
6765 (pref_color->blue * 255 / 65535))wmem_strdup_printf(((void*)0), "%02x%02x%02x", (pref_color->
red * 255 / 65535), (pref_color->green * 255 / 65535), (pref_color
->blue * 255 / 65535))
;
6766
6767 case PREF_CUSTOM:
6768 if (pref->custom_cbs.to_str_cb)
6769 return pref->custom_cbs.to_str_cb(pref, source == pref_default ? true1 : false0);
6770 pref_text = "[Custom]";
6771 break;
6772
6773 case PREF_STATIC_TEXT:
6774 pref_text = "[Static text]";
6775 break;
6776
6777 case PREF_UAT:
6778 {
6779 uat_t *uat = pref->varp.uat;
6780 if (uat && uat->filename)
6781 return ws_strdup_printf("[Managed in the file \"%s\"]", uat->filename)wmem_strdup_printf(((void*)0), "[Managed in the file \"%s\"]"
, uat->filename)
;
6782 else
6783 pref_text = "[Managed in an unknown file]";
6784 break;
6785 }
6786
6787 default:
6788 break;
6789 }
6790 }
6791
6792 return g_strdup(pref_text)g_strdup_inline (pref_text);
6793}
6794
6795/*
6796 * Write out a single dissector preference.
6797 */
6798void
6799pref_write_individual(void *data, void *user_data)
6800{
6801 pref_t *pref = (pref_t *)data;
6802 write_pref_arg_t *arg = (write_pref_arg_t *)user_data;
6803 char **desc_lines;
6804 int i;
6805
6806 if (!pref || pref->obsolete) {
6807 /*
6808 * This preference is no longer supported; it's not a
6809 * real preference, so we don't write it out (i.e., we
6810 * treat it as if it weren't found in the list of
6811 * preferences, and we weren't called in the first place).
6812 */
6813 return;
6814 }
6815
6816 switch (pref->type) {
6817
6818 case PREF_STATIC_TEXT:
6819 case PREF_UAT:
6820 /* Nothing to do; don't bother printing the description */
6821 return;
6822 case PREF_DECODE_AS_RANGE:
6823 /* Data is saved through Decode As mechanism and not part of preferences file */
6824 return;
6825 case PREF_PROTO_TCP_SNDAMB_ENUM:
6826 /* Not written to the preference file because the override is only
6827 * for the lifetime of the capture file and there is no single
6828 * value to write.
6829 */
6830 return;
6831 default:
6832 break;
6833 }
6834
6835 if (pref->type != PREF_CUSTOM || pref->custom_cbs.type_name_cb() != NULL((void*)0)) {
6836 /*
6837 * The prefix will either be the module name or the parent
6838 * name if it's a subtree
6839 */
6840 const char *name_prefix = (arg->module->name != NULL((void*)0)) ? arg->module->name : arg->module->parent->name;
6841 char *type_desc, *pref_text;
6842 const char * def_prefix = prefs_pref_is_default(pref) ? "#" : "";
6843
6844 if (pref->type == PREF_CUSTOM)
6845 fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
6846 fprintf(arg->pf, "\n");
6847 if (pref->description &&
6848 (g_ascii_strncasecmp(pref->description,"", 2) != 0)) {
6849 if (pref->type != PREF_CUSTOM) {
6850 /* We get duplicate lines otherwise. */
6851
6852 desc_lines = g_strsplit(pref->description, "\n", 0);
6853 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6854 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6855 }
6856 g_strfreev(desc_lines);
6857 }
6858 } else {
6859 fprintf(arg->pf, "# No description\n");
6860 }
6861
6862 type_desc = prefs_pref_type_description(pref);
6863 desc_lines = g_strsplit(type_desc, "\n", 0);
6864 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6865 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6866 }
6867 g_strfreev(desc_lines);
6868 g_free(type_desc);
6869
6870 pref_text = prefs_pref_to_str(pref, pref_current);
6871 fprintf(arg->pf, "%s%s.%s: ", def_prefix, name_prefix, pref->name);
6872 if (pref->type != PREF_PASSWORD)
6873 {
6874 desc_lines = g_strsplit(pref_text, "\n", 0);
6875 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6876 fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
6877 }
6878 if (i == 0)
6879 fprintf(arg->pf, "\n");
6880 g_strfreev(desc_lines);
6881 } else {
6882 /* We never store password value */
6883 fprintf(arg->pf, "\n");
6884 }
6885 g_free(pref_text);
6886 }
6887
6888}
6889
6890static void
6891count_non_uat_pref(void *data, void *user_data)
6892{
6893 pref_t *pref = (pref_t *)data;
6894 int *arg = (int *)user_data;
6895
6896 switch (pref->type)
6897 {
6898 case PREF_UAT:
6899 case PREF_DECODE_AS_RANGE:
6900 case PREF_PROTO_TCP_SNDAMB_ENUM:
6901 //These types are not written in preference file
6902 break;
6903 default:
6904 (*arg)++;
6905 break;
6906 }
6907}
6908
6909int
6910prefs_num_non_uat(module_t *module)
6911{
6912 int num = 0;
6913
6914 g_list_foreach(module->prefs, count_non_uat_pref, &num);
6915
6916 return num;
6917}
6918
6919/*
6920 * Write out all preferences for a module.
6921 */
6922static unsigned
6923write_module_prefs(module_t *module, void *user_data)
6924{
6925 write_gui_pref_arg_t *gui_pref_arg = (write_gui_pref_arg_t*)user_data;
6926 write_pref_arg_t arg;
6927
6928 /* The GUI module needs to be explicitly called out so it
6929 can be written out of order */
6930 if ((module == gui_module) && (gui_pref_arg->is_gui_module != true1))
6931 return 0;
6932
6933 /* Write a header for the main modules and GUI sub-modules */
6934 if (((module->parent == NULL((void*)0)) || (module->parent == gui_module)) &&
6935 ((prefs_module_has_submodules(module)) ||
6936 (prefs_num_non_uat(module) > 0) ||
6937 (module->name == NULL((void*)0)))) {
6938 if ((module->name == NULL((void*)0)) && (module->parent != NULL((void*)0))) {
6939 fprintf(gui_pref_arg->pf, "\n####### %s: %s ########\n", module->parent->title, module->title);
6940 } else {
6941 fprintf(gui_pref_arg->pf, "\n####### %s ########\n", module->title);
6942 }
6943 }
6944
6945 arg.module = module;
6946 arg.pf = gui_pref_arg->pf;
6947 g_list_foreach(arg.module->prefs, pref_write_individual, &arg);
6948
6949 if (prefs_module_has_submodules(module))
6950 return prefs_modules_foreach_submodules(module->submodules, write_module_prefs, user_data);
6951
6952 return 0;
6953}
6954
6955#ifdef _WIN32
6956static void
6957write_registry(void)
6958{
6959 HKEY hTestKey;
6960 DWORD data;
6961 DWORD data_size;
6962 DWORD ret;
6963
6964 ret = RegCreateKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, NULL((void*)0),
6965 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL((void*)0),
6966 &hTestKey, NULL((void*)0));
6967 if (ret != ERROR_SUCCESS) {
6968 ws_noisy("Cannot open HKCU "REG_HKCU_WIRESHARK_KEY": 0x%lx", ret)do { if (1) { ws_log_full("Epan", LOG_LEVEL_NOISY, "epan/prefs.c"
, 6968, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
6969 return;
6970 }
6971
6972 data = ws_log_console_open;
6973 data_size = sizeof(DWORD);
6974 ret = RegSetValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", 0, REG_DWORD, (const BYTE *)&data, data_size);
6975 if (ret == ERROR_SUCCESS) {
6976 ws_noisy("Wrote "LOG_HKCU_CONSOLE_OPEN" to Windows registry: 0x%lu", data)do { if (1) { ws_log_full("Epan", LOG_LEVEL_NOISY, "epan/prefs.c"
, 6976, __func__, "Wrote ""ConsoleOpen"" to Windows registry: 0x%lu"
, data); } } while (0)
;
6977 }
6978 else {
6979 ws_noisy("Error writing registry key "LOG_HKCU_CONSOLE_OPEN": 0x%lx", ret)do { if (1) { ws_log_full("Epan", LOG_LEVEL_NOISY, "epan/prefs.c"
, 6979, __func__, "Error writing registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
6980 }
6981
6982 RegCloseKey(hTestKey);
6983}
6984#endif
6985
6986/* Write out "prefs" to the user's preferences file, and return 0.
6987
6988 If the preferences file path is NULL, write to stdout.
6989
6990 If we got an error, stuff a pointer to the path of the preferences file
6991 into "*pf_path_return", and return the errno. */
6992int
6993write_prefs(const char* app_env_var_prefix, char **pf_path_return)
6994{
6995 char *pf_path;
6996 FILE *pf;
6997 write_gui_pref_arg_t write_gui_pref_info;
6998
6999#ifdef _WIN32
7000 write_registry();
7001#endif
7002
7003 /* To do:
7004 * - Split output lines longer than MAX_VAL_LEN
7005 * - Create a function for the preference directory check/creation
7006 * so that duplication can be avoided with filter.c
7007 */
7008
7009 if (pf_path_return != NULL((void*)0)) {
7010 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
7011 if ((pf = ws_fopenfopen(pf_path, "w")) == NULL((void*)0)) {
7012 *pf_path_return = pf_path;
7013 return errno(*__errno_location ());
7014 }
7015 g_free(pf_path);
7016 } else {
7017 pf = stdoutstdout;
7018 }
7019
7020 /*
7021 * If the preferences file is being written, be sure to write UAT files
7022 * first that were migrated from the preferences file.
7023 */
7024 if (pf_path_return != NULL((void*)0)) {
7025 if (prefs.filter_expressions_old) {
7026 char *err = NULL((void*)0);
7027 prefs.filter_expressions_old = false0;
7028 if (!uat_save(uat_get_table_by_name("Display expressions"), app_env_var_prefix, &err)) {
7029 ws_warning("Unable to save Display expressions: %s", err)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 7029, __func__, "Unable to save Display expressions: %s", err
); } } while (0)
;
7030 g_free(err);
7031 }
7032 }
7033
7034 module_t *extcap_module = prefs_find_module("extcap");
7035 if (extcap_module && !prefs.capture_no_extcap) {
7036 char *ext_path = get_persconffile_path("extcap.cfg", true1, app_env_var_prefix);
7037 FILE *extf;
7038 if ((extf = ws_fopenfopen(ext_path, "w")) == NULL((void*)0)) {
7039 if (errno(*__errno_location ()) != EISDIR21) {
7040 ws_warning("Unable to save extcap preferences \"%s\": %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 7041, __func__, "Unable to save extcap preferences \"%s\": %s"
, ext_path, g_strerror((*__errno_location ()))); } } while (0
)
7041 ext_path, g_strerror(errno))do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 7041, __func__, "Unable to save extcap preferences \"%s\": %s"
, ext_path, g_strerror((*__errno_location ()))); } } while (0
)
;
7042 }
7043 g_free(ext_path);
7044 } else {
7045 g_free(ext_path);
7046
7047 fputs("# Extcap configuration file for Wireshark " VERSION"4.7.0" ".\n"
7048 "#\n"
7049 "# This file is regenerated each time preferences are saved within\n"
7050 "# Wireshark. Making manual changes should be safe, however.\n"
7051 "# Preferences that have been commented out have not been\n"
7052 "# changed from their default value.\n", extf);
7053
7054 write_gui_pref_info.pf = extf;
7055 write_gui_pref_info.is_gui_module = false0;
7056
7057 write_module_prefs(extcap_module, &write_gui_pref_info);
7058
7059 fclose(extf);
7060 }
7061 }
7062 }
7063
7064 fputs("# Configuration file for Wireshark " VERSION"4.7.0" ".\n"
7065 "#\n"
7066 "# This file is regenerated each time preferences are saved within\n"
7067 "# Wireshark. Making manual changes should be safe, however.\n"
7068 "# Preferences that have been commented out have not been\n"
7069 "# changed from their default value.\n", pf);
7070
7071 /*
7072 * For "backwards compatibility" the GUI module is written first as it's
7073 * at the top of the file. This is followed by all modules that can't
7074 * fit into the preferences read/write API. Finally the remaining modules
7075 * are written in alphabetical order (including of course the protocol preferences)
7076 */
7077 write_gui_pref_info.pf = pf;
7078 write_gui_pref_info.is_gui_module = true1;
7079
7080 write_module_prefs(gui_module, &write_gui_pref_info);
7081
7082 write_gui_pref_info.is_gui_module = false0;
7083 prefs_module_list_foreach(prefs_top_level_modules, write_module_prefs, &write_gui_pref_info, true1);
7084
7085 fclose(pf);
7086
7087 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
7088 an error indication, or maybe write to a new preferences file and
7089 rename that file on top of the old one only if there are not I/O
7090 errors. */
7091 return 0;
7092}
7093
7094/** The col_list is only partly managed by the custom preference API
7095 * because its data is shared between multiple preferences, so
7096 * it's freed here
7097 */
7098static void
7099free_col_info(GList *list)
7100{
7101 fmt_data *cfmt;
7102 GList *list_head = list;
7103
7104 while (list != NULL((void*)0)) {
7105 cfmt = (fmt_data *)list->data;
7106
7107 g_free(cfmt->title);
7108 g_free(cfmt->custom_fields);
7109 g_free(cfmt);
7110 list = g_list_next(list)((list) ? (((GList *)(list))->next) : ((void*)0));
7111 }
7112 g_list_free(list_head);
7113}
7114
7115/*
7116 * Editor modelines
7117 *
7118 * Local Variables:
7119 * c-basic-offset: 4
7120 * tab-width: 8
7121 * indent-tabs-mode: nil
7122 * End:
7123 *
7124 * ex: set shiftwidth=4 tabstop=8 expandtab:
7125 * :indentSize=4:tabSize=8:noTabs=true:
7126 */