Bug Summary

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