Bug Summary

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