Bug Summary

File:builds/wireshark/wireshark/epan/prefs.c
Warning:line 4720, 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-10-24-100333-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 <[email protected]>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11#include "config.h"
12#define WS_LOG_DOMAIN"Epan" LOG_DOMAIN_EPAN"Epan"
13
14#include "ws_diag_control.h"
15
16#include <stdlib.h>
17#include <string.h>
18#include <errno(*__errno_location ()).h>
19#ifdef _WIN32
20#include <windows.h>
21#endif
22
23#include <glib.h>
24
25#include <stdio.h>
26#include <wsutil/filesystem.h>
27#include <epan/addr_resolv.h>
28#include <epan/oids.h>
29#include <epan/maxmind_db.h>
30#include <epan/packet.h>
31#include <epan/prefs.h>
32#include <epan/proto.h>
33#include <epan/strutil.h>
34#include <epan/column.h>
35#include <epan/decode_as.h>
36#include <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 (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2225 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2226 }
2227 break;
2228
2229 case PREF_COLOR:
2230 if ((pref->varp.colorp->blue != pref->stashed_val.color.blue) ||
2231 (pref->varp.colorp->red != pref->stashed_val.color.red) ||
2232 (pref->varp.colorp->green != pref->stashed_val.color.green)) {
2233 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2234 }
2235 break;
2236
2237 case PREF_UAT:
2238 if (pref->varp.uat && pref->varp.uat->changed) {
2239 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2240 }
2241 break;
2242
2243 case PREF_STATIC_TEXT:
2244 case PREF_CUSTOM:
2245 break;
2246
2247 default:
2248 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2248
, __func__, "assertion \"not reached\" failed")
;
2249 break;
2250 }
2251 return 0;
2252}
2253
2254unsigned
2255pref_unstash(pref_t *pref, void *unstash_data_p)
2256{
2257 pref_unstash_data_t *unstash_data = (pref_unstash_data_t *)unstash_data_p;
2258 dissector_table_t sub_dissectors = NULL((void*)0);
2259 dissector_handle_t handle = NULL((void*)0);
2260
2261 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2261, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2262
2263 /* Revert the preference to its saved value. */
2264 switch (pref->type) {
2265
2266 case PREF_UINT:
2267 if (*pref->varp.uint != pref->stashed_val.uint) {
2268 *pref->varp.uint = pref->stashed_val.uint;
2269 }
2270 break;
2271
2272 case PREF_INT:
2273 if (*pref->varp.intp != pref->stashed_val.intval) {
2274 *pref->varp.intp = pref->stashed_val.intval;
2275 }
2276 break;
2277
2278 case PREF_FLOAT:
2279 if (*pref->varp.floatp != pref->stashed_val.floatval) {
2280 *pref->varp.floatp = pref->stashed_val.floatval;
2281 }
2282 break;
2283
2284 case PREF_BOOL:
2285 if (*pref->varp.boolp != pref->stashed_val.boolval) {
2286 *pref->varp.boolp = pref->stashed_val.boolval;
2287 }
2288 break;
2289
2290 case PREF_ENUM:
2291 if (*pref->varp.enump != pref->stashed_val.enumval) {
2292 *pref->varp.enump = pref->stashed_val.enumval;
2293 }
2294 break;
2295
2296 case PREF_PROTO_TCP_SNDAMB_ENUM:
2297 {
2298 /* The preference dialogs are modal so the frame_data pointers should
2299 * still be valid; otherwise we could store the frame numbers to
2300 * change.
2301 */
2302 frame_data *fdata;
2303 for (GList* elem = pref->stashed_val.list; elem != NULL((void*)0); elem = elem->next) {
2304 fdata = (frame_data*)elem->data;
2305 if (fdata->tcp_snd_manual_analysis != *pref->varp.enump) {
2306 fdata->tcp_snd_manual_analysis = *pref->varp.enump;
2307 }
2308 }
2309 break;
2310 }
2311
2312 case PREF_STRING:
2313 case PREF_SAVE_FILENAME:
2314 case PREF_OPEN_FILENAME:
2315 case PREF_DIRNAME:
2316 case PREF_PASSWORD:
2317 case PREF_DISSECTOR:
2318 if (pref->stashed_val.string == NULL((void*)0)) {
2319 /* XXX - This shouldn't happen, but there's an issue with how the
2320 * Preferences Dialog handles newly registered extcap prefs. */
2321 ws_debug("stashed pref %s is NULL", prefs_get_name(pref))do { if (1) { ws_log_full("Epan", LOG_LEVEL_DEBUG, "epan/prefs.c"
, 2321, __func__, "stashed pref %s is NULL", prefs_get_name(pref
)); } } while (0)
;
2322 break;
2323 }
2324 if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0) {
2325 wmem_free(pref->scope, *pref->varp.string);
2326 *pref->varp.string = wmem_strdup(pref->scope, pref->stashed_val.string);
2327 }
2328 break;
2329
2330 case PREF_DECODE_AS_RANGE:
2331 {
2332 const char* table_name = prefs_get_dissector_table(pref);
2333 if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2334 uint32_t i, j;
2335
2336 if (unstash_data->handle_decode_as) {
2337 sub_dissectors = find_dissector_table(table_name);
2338 if (sub_dissectors != NULL((void*)0)) {
2339 const char *handle_desc = prefs_get_dissector_description(pref);
2340 // It should perhaps be possible to get this via dissector name.
2341 handle = dissector_table_get_dissector_handle(sub_dissectors, handle_desc);
2342 if (handle != NULL((void*)0)) {
2343 /* Set the current handle to NULL for all the old values
2344 * in the dissector table. If there isn't an initial
2345 * handle, this actually deletes the entry. (If there
2346 * is an initial entry, keep it around so that the
2347 * user can see the original value.)
2348 *
2349 * XXX - If there's an initial handle which is not this,
2350 * reset it instead? At least this leaves the initial
2351 * handle visible in the Decode As table.
2352 */
2353 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2354 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2355 dissector_change_uint(table_name, j, NULL((void*)0));
2356 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));
2357 }
2358
2359 dissector_change_uint(table_name, (*pref->varp.range)->ranges[i].high, NULL((void*)0));
2360 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));
2361 }
2362 }
2363 }
2364 }
2365
2366 wmem_free(pref->scope, *pref->varp.range);
2367 *pref->varp.range = range_copy(pref->scope, pref->stashed_val.range);
2368
2369 if (unstash_data->handle_decode_as) {
2370 if ((sub_dissectors != NULL((void*)0)) && (handle != NULL((void*)0))) {
2371
2372 /* Add new values to the dissector table */
2373 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2374
2375 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2376 dissector_change_uint(table_name, j, handle);
2377 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));
2378 }
2379
2380 dissector_change_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
2381 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));
2382 }
2383 }
2384 }
2385 }
2386 break;
2387 }
2388
2389 case PREF_RANGE:
2390 if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2391 wmem_free(pref->scope, *pref->varp.range);
2392 *pref->varp.range = range_copy(pref->scope, pref->stashed_val.range);
2393 }
2394 break;
2395
2396 case PREF_COLOR:
2397 if ((pref->varp.colorp->blue != pref->stashed_val.color.blue) ||
2398 (pref->varp.colorp->red != pref->stashed_val.color.red) ||
2399 (pref->varp.colorp->green != pref->stashed_val.color.green)) {
2400 *pref->varp.colorp = pref->stashed_val.color;
2401 }
2402 break;
2403
2404 case PREF_UAT:
2405 case PREF_STATIC_TEXT:
2406 case PREF_CUSTOM:
2407 break;
2408
2409 default:
2410 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2410
, __func__, "assertion \"not reached\" failed")
;
2411 break;
2412 }
2413 return 0;
2414}
2415
2416void
2417reset_stashed_pref(pref_t *pref) {
2418
2419 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2419, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2420
2421 switch (pref->type) {
2422
2423 case PREF_UINT:
2424 pref->stashed_val.uint = pref->default_val.uint;
2425 break;
2426
2427 case PREF_INT:
2428 pref->stashed_val.intval = pref->default_val.intval;
2429 break;
2430
2431 case PREF_FLOAT:
2432 pref->stashed_val.floatval = pref->default_val.floatval;
2433 break;
2434
2435 case PREF_BOOL:
2436 pref->stashed_val.boolval = pref->default_val.boolval;
2437 break;
2438
2439 case PREF_ENUM:
2440 pref->stashed_val.enumval = pref->default_val.enumval;
2441 break;
2442
2443 case PREF_STRING:
2444 case PREF_SAVE_FILENAME:
2445 case PREF_OPEN_FILENAME:
2446 case PREF_DIRNAME:
2447 case PREF_PASSWORD:
2448 case PREF_DISSECTOR:
2449 wmem_free(pref->scope, pref->stashed_val.string);
2450 pref->stashed_val.string = wmem_strdup(pref->scope, pref->default_val.string);
2451 break;
2452
2453 case PREF_DECODE_AS_RANGE:
2454 case PREF_RANGE:
2455 wmem_free(pref->scope, pref->stashed_val.range);
2456 pref->stashed_val.range = range_copy(pref->scope, pref->default_val.range);
2457 break;
2458
2459 case PREF_PROTO_TCP_SNDAMB_ENUM:
2460 if (pref->stashed_val.list != NULL((void*)0)) {
2461 g_list_free(pref->stashed_val.list);
2462 pref->stashed_val.list = NULL((void*)0);
2463 }
2464 break;
2465
2466 case PREF_COLOR:
2467 memcpy(&pref->stashed_val.color, &pref->default_val.color, sizeof(color_t));
2468 break;
2469
2470 case PREF_STATIC_TEXT:
2471 case PREF_UAT:
2472 case PREF_CUSTOM:
2473 break;
2474
2475 default:
2476 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2476
, __func__, "assertion \"not reached\" failed")
;
2477 break;
2478 }
2479}
2480
2481unsigned
2482pref_clean_stash(pref_t *pref, void *unused _U___attribute__((unused)))
2483{
2484 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2484, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2485
2486 switch (pref->type) {
2487
2488 case PREF_UINT:
2489 case PREF_INT:
2490 case PREF_FLOAT:
2491 case PREF_BOOL:
2492 case PREF_ENUM:
2493 break;
2494
2495 case PREF_STRING:
2496 case PREF_SAVE_FILENAME:
2497 case PREF_OPEN_FILENAME:
2498 case PREF_DIRNAME:
2499 case PREF_PASSWORD:
2500 case PREF_DISSECTOR:
2501 if (pref->stashed_val.string != NULL((void*)0)) {
2502 wmem_free(pref->scope, pref->stashed_val.string);
2503 pref->stashed_val.string = NULL((void*)0);
2504 }
2505 break;
2506
2507 case PREF_DECODE_AS_RANGE:
2508 case PREF_RANGE:
2509 if (pref->stashed_val.range != NULL((void*)0)) {
2510 wmem_free(pref->scope, pref->stashed_val.range);
2511 pref->stashed_val.range = NULL((void*)0);
2512 }
2513 break;
2514
2515 case PREF_STATIC_TEXT:
2516 case PREF_UAT:
2517 case PREF_COLOR:
2518 case PREF_CUSTOM:
2519 break;
2520
2521 case PREF_PROTO_TCP_SNDAMB_ENUM:
2522 if (pref->stashed_val.list != NULL((void*)0)) {
2523 g_list_free(pref->stashed_val.list);
2524 pref->stashed_val.list = NULL((void*)0);
2525 }
2526 break;
2527
2528 default:
2529 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2529
, __func__, "assertion \"not reached\" failed")
;
2530 break;
2531 }
2532 return 0;
2533}
2534
2535/*
2536 * Call a callback function, with a specified argument, for each preference
2537 * in a given module.
2538 *
2539 * If any of the callbacks return a non-zero value, stop and return that
2540 * value, otherwise return 0.
2541 */
2542unsigned
2543prefs_pref_foreach(module_t *module, pref_cb callback, void *user_data)
2544{
2545 GList *elem;
2546 pref_t *pref;
2547 unsigned ret;
2548
2549 for (elem = g_list_first(module->prefs); elem != NULL((void*)0); elem = g_list_next(elem)((elem) ? (((GList *)(elem))->next) : ((void*)0))) {
2550 pref = (pref_t *)elem->data;
2551 if (!pref || pref->obsolete) {
2552 /*
2553 * This preference is no longer supported; it's
2554 * not a real preference, so we don't call the
2555 * callback for it (i.e., we treat it as if it
2556 * weren't found in the list of preferences,
2557 * and we weren't called in the first place).
2558 */
2559 continue;
2560 }
2561
2562 ret = (*callback)(pref, user_data);
2563 if (ret != 0)
2564 return ret;
2565 }
2566 return 0;
2567}
2568
2569static const enum_val_t st_sort_col_vals[] = {
2570 { "name", "Node name (topic/item)", ST_SORT_COL_NAME1 },
2571 { "count", "Item count", ST_SORT_COL_COUNT2 },
2572 { "average", "Average value of the node", ST_SORT_COL_AVG3 },
2573 { "min", "Minimum value of the node", ST_SORT_COL_MIN4 },
2574 { "max", "Maximum value of the node", ST_SORT_COL_MAX5 },
2575 { "burst", "Burst rate of the node", ST_SORT_COL_BURSTRATE6 },
2576 { NULL((void*)0), NULL((void*)0), 0 }
2577};
2578
2579static const enum_val_t st_format_vals[] = {
2580 { "text", "Plain text", ST_FORMAT_PLAIN },
2581 { "csv", "Comma separated values", ST_FORMAT_CSV },
2582 { "xml", "XML document", ST_FORMAT_XML },
2583 { "yaml", "YAML document", ST_FORMAT_YAML },
2584 { NULL((void*)0), NULL((void*)0), 0 }
2585};
2586
2587static void
2588stats_callback(void)
2589{
2590 /* Test for a sane tap update interval */
2591 if (prefs.tap_update_interval < 100 || prefs.tap_update_interval > 10000)
2592 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
2593
2594 /* burst resolution can't be less than 1 (ms) */
2595 if (prefs.st_burst_resolution < 1) {
2596 prefs.st_burst_resolution = 1;
2597 }
2598 else if (prefs.st_burst_resolution > ST_MAX_BURSTRES600000) {
2599 prefs.st_burst_resolution = ST_MAX_BURSTRES600000;
2600 }
2601 /* make sure burst window value makes sense */
2602 if (prefs.st_burst_windowlen < prefs.st_burst_resolution) {
2603 prefs.st_burst_windowlen = prefs.st_burst_resolution;
2604 }
2605 /* round burst window down to multiple of resolution */
2606 prefs.st_burst_windowlen -= prefs.st_burst_windowlen%prefs.st_burst_resolution;
2607 if ((prefs.st_burst_windowlen/prefs.st_burst_resolution) > ST_MAX_BURSTBUCKETS100) {
2608 prefs.st_burst_windowlen = prefs.st_burst_resolution*ST_MAX_BURSTBUCKETS100;
2609 }
2610}
2611
2612static void
2613gui_callback(void)
2614{
2615 /* Ensure there is at least one file count */
2616 if (prefs.gui_recent_files_count_max == 0)
2617 prefs.gui_recent_files_count_max = 10;
2618
2619 /* Ensure there is at least one display filter entry */
2620 if (prefs.gui_recent_df_entries_max == 0)
2621 prefs.gui_recent_df_entries_max = 10;
2622
2623 /* number of decimal places should be between 2 and 10 */
2624 if (prefs.gui_decimal_places1 < 2) {
2625 prefs.gui_decimal_places1 = 2;
2626 } else if (prefs.gui_decimal_places1 > 10) {
2627 prefs.gui_decimal_places1 = 10;
2628 }
2629 /* number of decimal places should be between 2 and 10 */
2630 if (prefs.gui_decimal_places2 < 2) {
2631 prefs.gui_decimal_places2 = 2;
2632 } else if (prefs.gui_decimal_places2 > 10) {
2633 prefs.gui_decimal_places2 = 10;
2634 }
2635 /* number of decimal places should be between 2 and 10 */
2636 if (prefs.gui_decimal_places3 < 2) {
2637 prefs.gui_decimal_places3 = 2;
2638 } else if (prefs.gui_decimal_places3 > 10) {
2639 prefs.gui_decimal_places3 = 10;
2640 }
2641}
2642
2643static void
2644gui_layout_callback(void)
2645{
2646 if (prefs.gui_layout_type == layout_unused ||
2647 prefs.gui_layout_type >= layout_type_max) {
2648 /* XXX - report an error? It's not a syntax error - we'd need to
2649 add a way of reporting a *semantic* error. */
2650 prefs.gui_layout_type = layout_type_2;
2651 }
2652}
2653
2654/******************************************************
2655 * All custom preference function callbacks
2656 ******************************************************/
2657static void custom_pref_no_cb(pref_t* pref _U___attribute__((unused))) {}
2658
2659/*
2660 * Column preference functions
2661 */
2662#define PRS_COL_HIDDEN_FMT"column.hidden" "column.hidden"
2663#define PRS_COL_HIDDEN"column.hide" "column.hide"
2664#define PRS_COL_FMT"column.format" "column.format"
2665#define PRS_COL_NUM"column.number" "column.number"
2666static module_t *gui_column_module;
2667
2668static prefs_set_pref_e
2669column_hidden_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
2670{
2671 GList *clp;
2672 fmt_data *cfmt;
2673 pref_t *format_pref;
2674
2675 /*
2676 * Prefer the new preference to the old format-based preference if we've
2677 * read it. (We probably could just compare the string to NULL and "".)
2678 */
2679 prefs.cols_hide_new = true1;
2680
2681 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2682
2683 /*
2684 * Set the "visible" flag for the existing columns; we need to
2685 * do this if we set PRS_COL_HIDDEN but don't set PRS_COL_FMT
2686 * after setting it (which might be the case if, for example, we
2687 * set PRS_COL_HIDDEN on the command line).
2688 */
2689 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2690 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2691 int cidx = 1;
2692 while (clp) {
2693 cfmt = (fmt_data *)clp->data;
2694 cfmt->visible = prefs_is_column_visible(*pref->varp.string, cidx);
2695 cidx++;
2696 clp = clp->next;
2697 }
2698
2699 return PREFS_SET_OK;
2700}
2701
2702static const char *
2703column_hidden_type_name_cb(void)
2704{
2705 return "Packet list hidden columns";
2706}
2707
2708static char *
2709column_hidden_type_description_cb(void)
2710{
2711 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."
)
;
2712}
2713
2714static char *
2715column_hidden_to_str_cb(pref_t* pref, bool_Bool default_val)
2716{
2717 GString *cols_hidden;
2718 GList *clp;
2719 fmt_data *cfmt;
2720 pref_t *format_pref;
2721 int cidx = 1;
2722
2723 if (default_val)
2724 return g_strdup(pref->default_val.string)g_strdup_inline (pref->default_val.string);
2725
2726 cols_hidden = g_string_new("");
2727 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2728 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2729 while (clp) {
2730 cfmt = (fmt_data *) clp->data;
2731 if (!cfmt->visible) {
2732 if (cols_hidden->len)
2733 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))
;
2734 g_string_append_printf (cols_hidden, "%i", cidx);
2735 }
2736 clp = clp->next;
2737 cidx++;
2738 }
2739
2740 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))))
;
2741}
2742
2743static bool_Bool
2744column_hidden_is_default_cb(pref_t* pref)
2745{
2746 char *cur_hidden_str = column_hidden_to_str_cb(pref, false0);
2747 bool_Bool is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2748
2749 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)
;
2750 return is_default;
2751}
2752
2753static prefs_set_pref_e
2754column_hidden_fmt_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
2755{
2756 GList *clp;
2757 fmt_data *cfmt;
2758 pref_t *format_pref;
2759
2760 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2761
2762 /*
2763 * Set the "visible" flag for the existing columns; we need to
2764 * do this if we set PRS_COL_HIDDEN_FMT but don't set PRS_COL_FMT
2765 * after setting it (which might be the case if, for example, we
2766 * set PRS_COL_HIDDEN_FMT on the command line; it shouldn't happen
2767 * when reading the configuration file because we write (both of)
2768 * the hidden column prefs before the column format prefs.)
2769 */
2770 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2771 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2772 while (clp) {
2773 cfmt = (fmt_data *)clp->data;
2774 cfmt->visible = prefs_is_column_fmt_visible(*pref->varp.string, cfmt);
2775 clp = clp->next;
2776 }
2777
2778 return PREFS_SET_OK;
2779}
2780
2781static const char *
2782column_hidden_fmt_type_name_cb(void)
2783{
2784 return "Packet list hidden column formats (deprecated)";
2785}
2786
2787static char *
2788column_hidden_fmt_type_description_cb(void)
2789{
2790 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."
)
;
2791}
2792
2793static char *
2794column_hidden_fmt_to_str_cb(pref_t* pref, bool_Bool default_val)
2795{
2796 GString *cols_hidden;
2797 GList *clp;
2798 fmt_data *cfmt;
2799 pref_t *format_pref;
2800
2801 if (default_val)
2802 return g_strdup(pref->default_val.string)g_strdup_inline (pref->default_val.string);
2803
2804 cols_hidden = g_string_new("");
2805 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2806 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2807 while (clp) {
2808 char *prefs_fmt;
2809 cfmt = (fmt_data *) clp->data;
2810 if (!cfmt->visible) {
2811 if (cols_hidden->len)
2812 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))
;
2813 prefs_fmt = column_fmt_data_to_str(cfmt);
2814 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))
;
2815 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)
;
2816 }
2817 clp = clp->next;
2818 }
2819
2820 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))))
;
2821}
2822
2823static bool_Bool
2824column_hidden_fmt_is_default_cb(pref_t* pref)
2825{
2826 char *cur_hidden_str = column_hidden_fmt_to_str_cb(pref, false0);
2827 bool_Bool is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2828
2829 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)
;
2830 return is_default;
2831}
2832
2833/* Number of columns "preference". This is only used internally and is not written to the
2834 * preference file
2835 */
2836static void
2837column_num_reset_cb(pref_t* pref)
2838{
2839 *pref->varp.uint = pref->default_val.uint;
2840}
2841
2842static prefs_set_pref_e
2843column_num_set_cb(pref_t* pref _U___attribute__((unused)), const char* value _U___attribute__((unused)), unsigned int* changed_flags _U___attribute__((unused)))
2844{
2845 /* Don't write this to the preferences file */
2846 return PREFS_SET_OK;
2847}
2848
2849static const char *
2850column_num_type_name_cb(void)
2851{
2852 return NULL((void*)0);
2853}
2854
2855static char *
2856column_num_type_description_cb(void)
2857{
2858 return g_strdup("")g_strdup_inline ("");
2859}
2860
2861static bool_Bool
2862column_num_is_default_cb(pref_t* pref _U___attribute__((unused)))
2863{
2864 return true1;
2865}
2866
2867static char *
2868column_num_to_str_cb(pref_t* pref _U___attribute__((unused)), bool_Bool default_val _U___attribute__((unused)))
2869{
2870 return g_strdup("")g_strdup_inline ("");
2871}
2872
2873/*
2874 * Column format custom preference functions
2875 */
2876static void
2877column_format_init_cb(pref_t* pref, GList** value)
2878{
2879 fmt_data *src_cfmt, *dest_cfmt;
2880 GList *entry;
2881
2882 pref->varp.list = value;
2883
2884 pref->default_val.list = NULL((void*)0);
2885 for (entry = *pref->varp.list; entry != NULL((void*)0); entry = g_list_next(entry)((entry) ? (((GList *)(entry))->next) : ((void*)0))) {
2886 src_cfmt = (fmt_data *)entry->data;
2887 dest_cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2888 dest_cfmt->title = g_strdup(src_cfmt->title)g_strdup_inline (src_cfmt->title);
2889 dest_cfmt->fmt = src_cfmt->fmt;
2890 if (src_cfmt->custom_fields) {
2891 dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields)g_strdup_inline (src_cfmt->custom_fields);
2892 dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2893 } else {
2894 dest_cfmt->custom_fields = NULL((void*)0);
2895 dest_cfmt->custom_occurrence = 0;
2896 }
2897 dest_cfmt->visible = src_cfmt->visible;
2898 dest_cfmt->display = src_cfmt->display;
2899 pref->default_val.list = g_list_append(pref->default_val.list, dest_cfmt);
2900 }
2901
2902 column_register_fields();
2903}
2904
2905static void
2906column_format_free_cb(pref_t* pref)
2907{
2908 free_col_info(*pref->varp.list);
2909 free_col_info(pref->default_val.list);
2910}
2911
2912static void
2913column_format_reset_cb(pref_t* pref)
2914{
2915 fmt_data *src_cfmt, *dest_cfmt;
2916 GList *entry;
2917 pref_t *col_num_pref;
2918
2919 free_col_info(*pref->varp.list);
2920 *pref->varp.list = NULL((void*)0);
2921
2922 for (entry = pref->default_val.list; entry != NULL((void*)0); entry = g_list_next(entry)((entry) ? (((GList *)(entry))->next) : ((void*)0))) {
2923 src_cfmt = (fmt_data *)entry->data;
2924 dest_cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2925 dest_cfmt->title = g_strdup(src_cfmt->title)g_strdup_inline (src_cfmt->title);
2926 dest_cfmt->fmt = src_cfmt->fmt;
2927 if (src_cfmt->custom_fields) {
2928 dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields)g_strdup_inline (src_cfmt->custom_fields);
2929 dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2930 } else {
2931 dest_cfmt->custom_fields = NULL((void*)0);
2932 dest_cfmt->custom_occurrence = 0;
2933 }
2934 dest_cfmt->visible = src_cfmt->visible;
2935 dest_cfmt->display = src_cfmt->display;
2936 *pref->varp.list = g_list_append(*pref->varp.list, dest_cfmt);
2937 }
2938
2939 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2940 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", 2940, __func__, "assertion failed: %s"
, "col_num_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2941 column_num_reset_cb(col_num_pref);
2942}
2943
2944static prefs_set_pref_e
2945column_format_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags _U___attribute__((unused)))
2946{
2947 GList *col_l, *col_l_elt;
2948 fmt_data *cfmt;
2949 int llen;
2950 pref_t *hidden_pref, *col_num_pref;
2951
2952 col_l = prefs_get_string_list(value);
2953 if (col_l == NULL((void*)0))
2954 return PREFS_SET_SYNTAX_ERR;
2955 if ((g_list_length(col_l) % 2) != 0) {
2956 /* A title didn't have a matching format. */
2957 prefs_clear_string_list(col_l);
2958 return PREFS_SET_SYNTAX_ERR;
2959 }
2960 /* Check to make sure all column formats are valid. */
2961 col_l_elt = g_list_first(col_l);
2962 while (col_l_elt) {
2963 fmt_data cfmt_check;
2964
2965 /* Go past the title. */
2966 col_l_elt = col_l_elt->next;
2967
2968 /* Some predefined columns have been migrated to use custom columns.
2969 * We'll convert these silently here */
2970 try_convert_to_custom_column((char **)&col_l_elt->data);
2971
2972 /* Parse the format to see if it's valid. */
2973 if (!parse_column_format(&cfmt_check, (char *)col_l_elt->data)) {
2974 /* It's not a valid column format. */
2975 prefs_clear_string_list(col_l);
2976 return PREFS_SET_SYNTAX_ERR;
2977 }
2978 if (cfmt_check.fmt == COL_CUSTOM) {
2979 /* We don't need the custom column field on this pass. */
2980 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
)
;
2981 }
2982
2983 /* Go past the format. */
2984 col_l_elt = col_l_elt->next;
2985 }
2986
2987 /* They're all valid; process them. */
2988 free_col_info(*pref->varp.list);
2989 *pref->varp.list = NULL((void*)0);
2990 if (prefs.cols_hide_new) {
2991 hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN"column.hide");
2992 } else {
2993 hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN_FMT"column.hidden");
2994 }
2995 ws_assert(hidden_pref != NULL)do { if ((1) && !(hidden_pref != ((void*)0))) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2995, __func__, "assertion failed: %s"
, "hidden_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2996 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2997 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", 2997, __func__, "assertion failed: %s"
, "col_num_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2998 llen = g_list_length(col_l);
2999 *col_num_pref->varp.uint = llen / 2;
3000 col_l_elt = g_list_first(col_l);
3001 int cidx = 1;
3002 while (col_l_elt) {
3003 cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
3004 cfmt->title = g_strdup((char *)col_l_elt->data)g_strdup_inline ((char *)col_l_elt->data);
3005 col_l_elt = col_l_elt->next;
3006 parse_column_format(cfmt, (char *)col_l_elt->data);
3007 if (prefs.cols_hide_new) {
3008 cfmt->visible = prefs_is_column_visible(*hidden_pref->varp.string, cidx);
3009 } else {
3010 cfmt->visible = prefs_is_column_fmt_visible(*hidden_pref->varp.string, cfmt);
3011 }
3012 col_l_elt = col_l_elt->next;
3013 *pref->varp.list = g_list_append(*pref->varp.list, cfmt);
3014 cidx++;
3015 }
3016
3017 prefs_clear_string_list(col_l);
3018 free_string_like_preference(hidden_pref);
3019 column_register_fields();
3020 return PREFS_SET_OK;
3021}
3022
3023
3024static const char *
3025column_format_type_name_cb(void)
3026{
3027 return "Packet list column format";
3028}
3029
3030static char *
3031column_format_type_description_cb(void)
3032{
3033 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"
)
;
3034}
3035
3036static bool_Bool
3037column_format_is_default_cb(pref_t* pref)
3038{
3039 GList *clp = *pref->varp.list,
3040 *pref_col = g_list_first(clp),
3041 *def_col = g_list_first(pref->default_val.list);
3042 fmt_data *cfmt, *def_cfmt;
3043 bool_Bool is_default = true1;
3044 pref_t *col_num_pref;
3045
3046 /* See if the column data has changed from the default */
3047 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
3048 if (col_num_pref && *col_num_pref->varp.uint != col_num_pref->default_val.uint) {
3049 is_default = false0;
3050 } else {
3051 while (pref_col && def_col) {
3052 cfmt = (fmt_data *) pref_col->data;
3053 def_cfmt = (fmt_data *) def_col->data;
3054 if ((g_strcmp0(cfmt->title, def_cfmt->title) != 0) ||
3055 (cfmt->fmt != def_cfmt->fmt) ||
3056 (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) &&
3057 ((g_strcmp0(cfmt->custom_fields, def_cfmt->custom_fields) != 0) ||
3058 (cfmt->display != def_cfmt->display)))) {
3059 is_default = false0;
3060 break;
3061 }
3062
3063 pref_col = pref_col->next;
3064 def_col = def_col->next;
3065 }
3066 }
3067
3068 return is_default;
3069}
3070
3071static char *
3072column_format_to_str_cb(pref_t* pref, bool_Bool default_val)
3073{
3074 GList *pref_l = default_val ? pref->default_val.list : *pref->varp.list;
3075 GList *clp = g_list_first(pref_l);
3076 GList *col_l;
3077 fmt_data *cfmt;
3078 char *column_format_str;
3079
3080 col_l = NULL((void*)0);
3081 while (clp) {
3082 cfmt = (fmt_data *) clp->data;
3083 col_l = g_list_append(col_l, g_strdup(cfmt->title)g_strdup_inline (cfmt->title));
3084 col_l = g_list_append(col_l, column_fmt_data_to_str(cfmt));
3085 clp = clp->next;
3086 }
3087
3088 column_format_str = join_string_list(col_l);
3089 prefs_clear_string_list(col_l);
3090 return column_format_str;
3091}
3092
3093static prefs_set_pref_e
3094colorized_frame_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
3095{
3096 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
3097 return PREFS_SET_OK;
3098}
3099
3100static const char *
3101colorized_frame_type_name_cb(void)
3102{
3103 /* Don't write the colors of the 10 easy-access-colorfilters to the preferences
3104 * file until the colors can be changed in the GUI. Currently this is not really
3105 * possible since the STOCK-icons for these colors are hardcoded.
3106 *
3107 * XXX Find a way to change the colors of the STOCK-icons on the fly and then
3108 * add these 10 colors to the list of colors that can be changed through
3109 * the preferences.
3110 *
3111 */
3112 return NULL((void*)0);
3113}
3114
3115static char *
3116colorized_frame_type_description_cb(void)
3117{
3118 return g_strdup("")g_strdup_inline ("");
3119}
3120
3121static bool_Bool
3122colorized_frame_is_default_cb(pref_t* pref _U___attribute__((unused)))
3123{
3124 return true1;
3125}
3126
3127static char *
3128colorized_frame_to_str_cb(pref_t* pref _U___attribute__((unused)), bool_Bool default_val _U___attribute__((unused)))
3129{
3130 return g_strdup("")g_strdup_inline ("");
3131}
3132
3133/*
3134 * Register all non-dissector modules' preferences.
3135 */
3136static module_t *gui_module;
3137static module_t *gui_color_module;
3138static module_t *nameres_module;
3139static module_t *extcap_module;
3140
3141static void
3142prefs_register_modules(void)
3143{
3144 module_t *printing, *capture_module, *console_module,
3145 *gui_layout_module, *gui_font_module;
3146 unsigned int layout_gui_flags;
3147 struct pref_custom_cbs custom_cbs;
3148
3149 if (protocols_module != NULL((void*)0)) {
3150 /* Already setup preferences */
3151 return;
3152 }
3153
3154 /* Extcap
3155 * The extcap preferences used to be in the main preference file, but are
3156 * now (since 4.4.0) written separately to "extcap.cfg". It occasionally
3157 * seems to cause issues that this is registered as a top level module.
3158 */
3159 extcap_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "extcap", "Extcap Utilities",
3160 "Extcap Utilities", NULL((void*)0), NULL((void*)0), false0);
3161 /* Extcap preferences don't affect dissection */
3162 prefs_set_module_effect_flags(extcap_module, PREF_EFFECT_CAPTURE(1u << 1));
3163
3164 /* Setting default value to true */
3165 prefs.extcap_save_on_start = true1;
3166 prefs_register_bool_preference(extcap_module, "gui_save_on_start",
3167 "Save arguments on start of capture",
3168 "Save arguments on start of capture",
3169 &prefs.extcap_save_on_start);
3170
3171 /* GUI
3172 * These are "simple" GUI preferences that can be read/written using the
3173 * preference module API. These preferences still use their own
3174 * configuration screens for access, but this cuts down on the
3175 * preference "string compare list" in set_pref()
3176 */
3177 gui_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "gui", "User Interface",
3178 "User Interface", NULL((void*)0), &gui_callback, false0);
3179 /*
3180 * The GUI preferences don't affect dissection in general.
3181 * Any changes are signaled in other ways, so PREF_EFFECT_GUI doesn't
3182 * explicitly do anything, but wslua_set_preference expects *some*
3183 * effect flag to be set if the preference was changed.
3184 * We have to do this again for all the submodules, which don't inherit
3185 * the flags from their parent. The layout submodule and color submodule
3186 * have their own effect flags, though note that not all preferences in
3187 * those submodules need the specific flag; some are just grouped in the
3188 * submodule to present to the user in the same dialog page as the others.
3189 */
3190 unsigned gui_effect_flags = prefs_get_module_effect_flags(gui_module);
3191 gui_effect_flags |= PREF_EFFECT_GUI(1u << 4);
3192 gui_effect_flags &= (~PREF_EFFECT_DISSECTION(1u << 0));
3193 prefs_set_module_effect_flags(gui_module, gui_effect_flags);
3194
3195 /*
3196 * gui.console_open is stored in the registry in addition to the
3197 * preferences file. It is also read independently by ws_log_init()
3198 * for early log initialization of the console.
3199 */
3200 prefs_register_enum_preference(gui_module, "console_open",
3201 "Open a console window",
3202 "Open a console window (Windows only)",
3203 (int *)&ws_log_console_open, gui_console_open_type, false0);
3204
3205 prefs_register_obsolete_preference(gui_module, "scrollbar_on_right");
3206 prefs_register_obsolete_preference(gui_module, "packet_list_sel_browse");
3207 prefs_register_obsolete_preference(gui_module, "protocol_tree_sel_browse");
3208 prefs_register_obsolete_preference(gui_module, "tree_view_altern_colors");
3209 prefs_register_obsolete_preference(gui_module, "expert_composite_eyecandy");
3210 prefs_register_obsolete_preference(gui_module, "filter_toolbar_show_in_statusbar");
3211 prefs_register_obsolete_preference(gui_module, "restore_filter_after_following_stream");
3212
3213 prefs_register_obsolete_preference(gui_module, "protocol_tree_line_style");
3214
3215 prefs_register_obsolete_preference(gui_module, "protocol_tree_expander_style");
3216
3217 prefs_register_obsolete_preference(gui_module, "hex_dump_highlight_style");
3218
3219 prefs_register_obsolete_preference(gui_module, "packet_editor.enabled");
3220
3221 gui_column_module = prefs_register_subtree(gui_module, prefs_modules, "Columns", "Columns", NULL((void*)0));
3222 prefs_set_module_effect_flags(gui_column_module, gui_effect_flags);
3223 /* For reading older preference files with "column." preferences */
3224 prefs_register_module_alias("column", gui_column_module);
3225
3226
3227 custom_cbs.free_cb = free_string_like_preference;
3228 custom_cbs.reset_cb = reset_string_like_preference;
3229 custom_cbs.set_cb = column_hidden_set_cb;
3230 custom_cbs.type_name_cb = column_hidden_type_name_cb;
3231 custom_cbs.type_description_cb = column_hidden_type_description_cb;
3232 custom_cbs.is_default_cb = column_hidden_is_default_cb;
3233 custom_cbs.to_str_cb = column_hidden_to_str_cb;
3234 register_string_like_preference(gui_column_module, PRS_COL_HIDDEN"column.hide", "Packet list hidden columns",
3235 "List all column indices (1-indexed) to hide in the packet list",
3236 &cols_hidden_list, PREF_CUSTOM, &custom_cbs, false0);
3237
3238 custom_cbs.set_cb = column_hidden_fmt_set_cb;
3239 custom_cbs.type_name_cb = column_hidden_fmt_type_name_cb;
3240 custom_cbs.type_description_cb = column_hidden_fmt_type_description_cb;
3241 custom_cbs.is_default_cb = column_hidden_fmt_is_default_cb;
3242 custom_cbs.to_str_cb = column_hidden_fmt_to_str_cb;
3243
3244 register_string_like_preference(gui_column_module, PRS_COL_HIDDEN_FMT"column.hidden", "Packet list hidden column formats (deprecated)",
3245 "List all column formats to hide in the packet list; deprecated in favor of the index-based preference",
3246 &cols_hidden_fmt_list, PREF_CUSTOM, &custom_cbs, false0);
3247
3248 custom_cbs.free_cb = column_format_free_cb;
3249 custom_cbs.reset_cb = column_format_reset_cb;
3250 custom_cbs.set_cb = column_format_set_cb;
3251 custom_cbs.type_name_cb = column_format_type_name_cb;
3252 custom_cbs.type_description_cb = column_format_type_description_cb;
3253 custom_cbs.is_default_cb = column_format_is_default_cb;
3254 custom_cbs.to_str_cb = column_format_to_str_cb;
3255
3256 prefs_register_list_custom_preference(gui_column_module, PRS_COL_FMT"column.format", "Packet list column format",
3257 "Each pair of strings consists of a column title and its format", &custom_cbs,
3258 column_format_init_cb, &prefs.col_list);
3259
3260 /* Number of columns. This is only used internally and is not written to the
3261 * preference file
3262 */
3263 custom_cbs.free_cb = custom_pref_no_cb;
3264 custom_cbs.reset_cb = column_num_reset_cb;
3265 custom_cbs.set_cb = column_num_set_cb;
3266 custom_cbs.type_name_cb = column_num_type_name_cb;
3267 custom_cbs.type_description_cb = column_num_type_description_cb;
3268 custom_cbs.is_default_cb = column_num_is_default_cb;
3269 custom_cbs.to_str_cb = column_num_to_str_cb;
3270 prefs_register_uint_custom_preference(gui_column_module, PRS_COL_NUM"column.number", "Number of columns",
3271 "Number of columns in col_list", &custom_cbs, &prefs.num_cols);
3272
3273 /* User Interface : Font */
3274 gui_font_module = prefs_register_subtree(gui_module, prefs_modules, "Font", "Font", NULL((void*)0));
3275 prefs_set_module_effect_flags(gui_font_module, gui_effect_flags);
3276
3277 prefs_register_obsolete_preference(gui_font_module, "font_name");
3278
3279 prefs_register_obsolete_preference(gui_font_module, "gtk2.font_name");
3280
3281 register_string_like_preference(gui_font_module, "qt.font_name", "Font name",
3282 "Font name for packet list, protocol tree, and hex dump panes. (Qt)",
3283 &prefs.gui_font_name, PREF_STRING, NULL((void*)0), true1);
3284
3285 /* User Interface : Colors */
3286 gui_color_module = prefs_register_subtree(gui_module, prefs_modules, "Colors", "Colors", NULL((void*)0));
3287 unsigned gui_color_effect_flags = gui_effect_flags | PREF_EFFECT_GUI_COLOR(1u << 5);
3288 prefs_set_module_effect_flags(gui_color_module, gui_color_effect_flags);
3289
3290 /* The appearance mode moved to global recent_common storage
3291 (recent.gui_color_scheme) so it no longer flips when switching
3292 profiles. Keep the old per-profile key registered as obsolete so
3293 existing preferences files load without an "unknown preference"
3294 warning. */
3295 prefs_register_obsolete_preference(gui_color_module, "color_scheme");
3296
3297 custom_cbs.free_cb = free_string_like_preference;
3298 custom_cbs.reset_cb = reset_string_like_preference;
3299 custom_cbs.set_cb = colorized_frame_set_cb;
3300 custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3301 custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3302 custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3303 custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3304 register_string_like_preference(gui_column_module, "colorized_frame.fg", "Colorized Foreground",
3305 "Filter Colorized Foreground",
3306 &prefs.gui_colorized_fg, PREF_CUSTOM, &custom_cbs, true1);
3307
3308 custom_cbs.free_cb = free_string_like_preference;
3309 custom_cbs.reset_cb = reset_string_like_preference;
3310 custom_cbs.set_cb = colorized_frame_set_cb;
3311 custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3312 custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3313 custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3314 custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3315 register_string_like_preference(gui_column_module, "colorized_frame.bg", "Colorized Background",
3316 "Filter Colorized Background",
3317 &prefs.gui_colorized_bg, PREF_CUSTOM, &custom_cbs, true1);
3318
3319 prefs_register_enum_preference(gui_module, "fileopen.style",
3320 "Where to start the File Open dialog box",
3321 "Where to start the File Open dialog box",
3322 (int*)&prefs.gui_fileopen_style, gui_fileopen_style, false0);
3323
3324 prefs_register_uint_preference(gui_module, "recent_files_count.max",
3325 "The max. number of items in the open recent files list",
3326 "The max. number of items in the open recent files list",
3327 10,
3328 &prefs.gui_recent_files_count_max);
3329
3330 prefs_register_uint_preference(gui_module, "recent_display_filter_entries.max",
3331 "The max. number of entries in the display filter list",
3332 "The max. number of entries in the display filter list",
3333 10,
3334 &prefs.gui_recent_df_entries_max);
3335
3336 register_string_like_preference(gui_module, "fileopen.dir", "Start Directory",
3337 "Directory to start in when opening File Open dialog.",
3338 &prefs.gui_fileopen_dir, PREF_DIRNAME, NULL((void*)0), true1);
3339
3340 prefs_register_obsolete_preference(gui_module, "fileopen.remembered_dir");
3341
3342 prefs_register_uint_preference(gui_module, "fileopen.preview",
3343 "The preview timeout in the File Open dialog",
3344 "The preview timeout in the File Open dialog",
3345 10,
3346 &prefs.gui_fileopen_preview);
3347
3348 register_string_like_preference(gui_module, "tlskeylog_command", "Program to launch with TLS Keylog",
3349 "Program path or command line to launch with SSLKEYLOGFILE",
3350 &prefs.gui_tlskeylog_command, PREF_STRING, NULL((void*)0), true1);
3351
3352 prefs_register_bool_preference(gui_module, "ask_unsaved",
3353 "Ask to save unsaved capture files",
3354 "Ask to save unsaved capture files?",
3355 &prefs.gui_ask_unsaved);
3356
3357 prefs_register_bool_preference(gui_module, "autocomplete_filter",
3358 "Display autocompletion for filter text",
3359 "Display an autocomplete suggestion for display and capture filter controls",
3360 &prefs.gui_autocomplete_filter);
3361
3362 prefs_register_bool_preference(gui_module, "find_wrap",
3363 "Wrap to beginning/end of file during search",
3364 "Wrap to beginning/end of file during search?",
3365 &prefs.gui_find_wrap);
3366
3367 prefs_register_obsolete_preference(gui_module, "use_pref_save");
3368
3369 prefs_register_bool_preference(gui_module, "geometry.save.position",
3370 "Save window position at exit",
3371 "Save window position at exit?",
3372 &prefs.gui_geometry_save_position);
3373
3374 prefs_register_bool_preference(gui_module, "geometry.save.size",
3375 "Save window size at exit",
3376 "Save window size at exit?",
3377 &prefs.gui_geometry_save_size);
3378
3379 prefs_register_bool_preference(gui_module, "geometry.save.maximized",
3380 "Save window maximized state at exit",
3381 "Save window maximized state at exit?",
3382 &prefs.gui_geometry_save_maximized);
3383
3384 prefs_register_obsolete_preference(gui_module, "macosx_style");
3385
3386 prefs_register_obsolete_preference(gui_module, "geometry.main.x");
3387 prefs_register_obsolete_preference(gui_module, "geometry.main.y");
3388 prefs_register_obsolete_preference(gui_module, "geometry.main.width");
3389 prefs_register_obsolete_preference(gui_module, "geometry.main.height");
3390 prefs_register_obsolete_preference(gui_module, "toolbar_main_show");
3391
3392 prefs_register_enum_preference(gui_module, "toolbar_main_style",
3393 "Main Toolbar style",
3394 "Main Toolbar style",
3395 &prefs.gui_toolbar_main_style, gui_toolbar_style, false0);
3396
3397 prefs_register_obsolete_preference(gui_module, "toolbar_filter_style");
3398 prefs_register_obsolete_preference(gui_module, "webbrowser");
3399
3400 prefs_register_bool_preference(gui_module, "update.enabled",
3401 "Check for updates",
3402 "Check for updates (Windows and macOS only)",
3403 &prefs.gui_update_enabled);
3404
3405 prefs_register_enum_preference(gui_module, "update.channel",
3406 "Update channel",
3407 "The type of update to fetch. You should probably leave this set to STABLE.",
3408 (int*)(void*)(&prefs.gui_update_channel), gui_update_channel, false0);
3409
3410 prefs_register_uint_preference(gui_module, "update.interval",
3411 "How often to check for software updates",
3412 "How often to check for software updates in seconds",
3413 10,
3414 &prefs.gui_update_interval);
3415
3416 prefs_register_uint_preference(gui_module, "debounce.timer",
3417 "How long to wait before processing computationally intensive user input",
3418 "How long to wait (in milliseconds) before processing "
3419 "computationally intensive user input. "
3420 "If you type quickly, consider lowering the value for a 'snappier' "
3421 "experience. "
3422 "If you type slowly, consider increasing the value to avoid performance issues. "
3423 "This is currently used to delay searches in View -> Internals -> Supported Protocols "
3424 "and Preferences -> Advanced menu.",
3425 10,
3426 &prefs.gui_debounce_timer);
3427
3428 register_string_like_preference(gui_module, "window_title", "Custom window title",
3429 "Custom window title to be appended to the existing title\n"
3430 "%C = capture comment from command line\n"
3431 "%F = file path of the capture file\n"
3432 "%P = profile name\n"
3433 "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3434 "%V = version info",
3435 &prefs.gui_window_title, PREF_STRING, NULL((void*)0), true1);
3436
3437 register_string_like_preference(gui_module, "prepend_window_title", "Custom window title prefix",
3438 "Custom window title to be prepended to the existing title\n"
3439 "%C = capture comment from command line\n"
3440 "%F = file path of the capture file\n"
3441 "%P = profile name\n"
3442 "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3443 "%V = version info",
3444 &prefs.gui_prepend_window_title, PREF_STRING, NULL((void*)0), true1);
3445
3446 register_string_like_preference(gui_module, "start_title", "Custom start page title",
3447 "Custom start page title",
3448 &prefs.gui_start_title, PREF_STRING, NULL((void*)0), true1);
3449
3450 prefs_register_enum_preference(gui_module, "version_placement",
3451 "Show version in the start page and/or main screen's title bar",
3452 "Show version in the start page and/or main screen's title bar",
3453 (int*)(void*)(&prefs.gui_version_placement), gui_version_placement_type, false0);
3454
3455 prefs_register_obsolete_preference(gui_module, "auto_scroll_on_expand");
3456 prefs_register_obsolete_preference(gui_module, "auto_scroll_percentage");
3457
3458 prefs_register_uint_preference(gui_module, "max_export_objects",
3459 "Maximum number of exported objects",
3460 "The maximum number of objects that can be exported",
3461 10,
3462 &prefs.gui_max_export_objects);
3463 prefs_register_uint_preference(gui_module, "max_tree_items",
3464 "Maximum number of tree items",
3465 "The maximum number of items that can be added to the dissection tree (Increase with caution)",
3466 10,
3467 &prefs.gui_max_tree_items);
3468 /*
3469 * Used independently by proto_tree_add_node, call_dissector*, dissector_try_heuristic,
3470 * and increment_dissection_depth.
3471 */
3472 prefs_register_uint_preference(gui_module, "max_tree_depth",
3473 "Maximum dissection depth",
3474 "The maximum depth for dissection tree and protocol layer checks. (Increase with caution)",
3475 10,
3476 &prefs.gui_max_tree_depth);
3477
3478 prefs_register_bool_preference(gui_module, "welcome_page.show_recent",
3479 "Show recent files on the welcome page",
3480 "This will enable or disable the 'Open' list on the welcome page.",
3481 &prefs.gui_welcome_page_show_recent);
3482
3483 /* User Interface : Layout */
3484 gui_layout_module = prefs_register_subtree(gui_module, prefs_modules, "Layout", "Layout", gui_layout_callback);
3485 /* Most of the preferences in Layout aren't actually "Layout" preferences,
3486 * from the point of view of triggering a re-layout of the splitter, etc.
3487 * So most get the default GUI effect flags. */
3488 prefs_set_module_effect_flags(gui_layout_module, gui_effect_flags);
3489 /* Adjust the preference effects of layout GUI for better handling of preferences at Wireshark (GUI) level */
3490 layout_gui_flags = gui_effect_flags | PREF_EFFECT_GUI_LAYOUT(1u << 2);
3491
3492 prefs_register_uint_preference(gui_layout_module, "layout_type",
3493 "Layout type",
3494 "Layout type (1-6)",
3495 10,
3496 (unsigned*)(void*)(&prefs.gui_layout_type));
3497 prefs_set_effect_flags_by_name(gui_layout_module, "layout_type", layout_gui_flags);
3498
3499 prefs_register_enum_preference(gui_layout_module, "layout_content_1",
3500 "Layout content of the pane 1",
3501 "Layout content of the pane 1",
3502 (int*)(void*)(&prefs.gui_layout_content_1), gui_layout_content, false0);
3503 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_1", layout_gui_flags);
3504
3505 prefs_register_enum_preference(gui_layout_module, "layout_content_2",
3506 "Layout content of the pane 2",
3507 "Layout content of the pane 2",
3508 (int*)(void*)(&prefs.gui_layout_content_2), gui_layout_content, false0);
3509 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_2", layout_gui_flags);
3510
3511 prefs_register_enum_preference(gui_layout_module, "layout_content_3",
3512 "Layout content of the pane 3",
3513 "Layout content of the pane 3",
3514 (int*)(void*)(&prefs.gui_layout_content_3), gui_layout_content, false0);
3515 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_3", layout_gui_flags);
3516
3517 prefs_register_bool_preference(gui_layout_module, "packet_list_separator.enabled",
3518 "Enable Packet List Separator",
3519 "Enable Packet List Separator",
3520 &prefs.gui_packet_list_separator);
3521
3522 prefs_register_bool_preference(gui_layout_module, "packet_header_column_definition.enabled",
3523 "Show column definition in packet list header",
3524 "Show column definition in packet list header",
3525 &prefs.gui_packet_header_column_definition);
3526
3527 /* packet_list_hover_style affects the colors, not the layout.
3528 * It's in the layout module to group it with the other packet list
3529 * preferences for the user's benefit with the dialog.
3530 */
3531 prefs_register_bool_preference(gui_layout_module, "packet_list_hover_style.enabled",
3532 "Enable Packet List mouse-over colorization",
3533 "Enable Packet List mouse-over colorization",
3534 &prefs.gui_packet_list_hover_style);
3535 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_hover_style.enabled", gui_color_effect_flags);
3536
3537 prefs_register_bool_preference(gui_layout_module, "show_selected_packet.enabled",
3538 "Show selected packet in the Status Bar",
3539 "Show selected packet in the Status Bar",
3540 &prefs.gui_show_selected_packet);
3541
3542 prefs_register_bool_preference(gui_layout_module, "show_file_load_time.enabled",
3543 "Show file load time in the Status Bar",
3544 "Show file load time in the Status Bar",
3545 &prefs.gui_show_file_load_time);
3546
3547 prefs_register_enum_preference(gui_layout_module, "packet_dialog_layout",
3548 "Packet Dialog layout",
3549 "Packet Dialog layout",
3550 (int*)(&prefs.gui_packet_dialog_layout), gui_packet_dialog_layout, false0);
3551
3552 prefs_register_enum_preference(gui_module, "packet_list_elide_mode",
3553 "Elide mode",
3554 "The position of \"...\" (ellipsis) in packet list text.",
3555 (int*)(void*)(&prefs.gui_packet_list_elide_mode), gui_packet_list_elide_mode, false0);
3556 prefs_register_uint_preference(gui_module, "decimal_places1",
3557 "Count of decimal places for values of type 1",
3558 "Sets the count of decimal places for values of type 1."
3559 "Type 1 values are defined by authors."
3560 "Value can be in range 2 to 10.",
3561 10,&prefs.gui_decimal_places1);
3562
3563 prefs_register_uint_preference(gui_module, "decimal_places2",
3564 "Count of decimal places for values of type 2",
3565 "Sets the count of decimal places for values of type 2."
3566 "Type 2 values are defined by authors."
3567 "Value can be in range 2 to 10.",
3568 10,&prefs.gui_decimal_places2);
3569
3570 prefs_register_uint_preference(gui_module, "decimal_places3",
3571 "Count of decimal places for values of type 3",
3572 "Sets the count of decimal places for values of type 3."
3573 "Type 3 values are defined by authors."
3574 "Value can be in range 2 to 10.",
3575 10,&prefs.gui_decimal_places3);
3576
3577 prefs_register_bool_preference(gui_module, "rtp_player_use_disk1",
3578 "RTP Player saves temporary data to disk",
3579 "If set to true, RTP Player saves temporary data to "
3580 "temp files on disk. If not set, it uses memory."
3581 "Every stream uses one file therefore you might touch "
3582 "OS limit for count of opened files."
3583 "When ui.rtp_player_use_disk2 is set to true too, it uses "
3584 " two files per RTP stream together."
3585 ,&prefs.gui_rtp_player_use_disk1);
3586
3587 prefs_register_bool_preference(gui_module, "rtp_player_use_disk2",
3588 "RTP Player saves temporary dictionary for data to disk",
3589 "If set to true, RTP Player saves temporary dictionary to "
3590 "temp files on disk. If not set, it uses memory."
3591 "Every stream uses one file therefore you might touch "
3592 "OS limit for count of opened files."
3593 "When ui.rtp_player_use_disk1 is set to true too, it uses "
3594 " two files per RTP stream."
3595 ,&prefs.gui_rtp_player_use_disk2);
3596
3597 prefs_register_enum_preference(gui_layout_module, "gui_packet_list_copy_format_options_for_keyboard_shortcut",
3598 "Allows text to be copied with selected format",
3599 "Allows text to be copied with selected format when copied via keyboard",
3600 (int*)(void*)(&prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut),
3601 gui_packet_list_copy_format_options_for_keyboard_shortcut, false0);
3602
3603 prefs_register_bool_preference(gui_layout_module, "gui_packet_list_copy_text_with_aligned_columns",
3604 "Allows text to be copied with aligned columns",
3605 "Allows text to be copied with aligned columns when copied via menu or keyboard",
3606 &prefs.gui_packet_list_copy_text_with_aligned_columns);
3607
3608 prefs_register_bool_preference(gui_layout_module, "packet_list_show_related",
3609 "Show Related Packets",
3610 "Show related packet indicators in the first column",
3611 &prefs.gui_packet_list_show_related);
3612
3613 prefs_register_bool_preference(gui_layout_module, "packet_list_show_minimap",
3614 "Enable Intelligent Scroll Bar",
3615 "Show the intelligent scroll bar (a minimap of packet list colors in the scrollbar)",
3616 &prefs.gui_packet_list_show_minimap);
3617 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_show_minimap", gui_color_effect_flags);
3618
3619 prefs_register_enum_preference(gui_layout_module, "packet_list_multi_color_mode",
3620 "Multi-Color Display Mode",
3621 "How to display multiple colors: Equal Stripes (entire row) or Shift Right (configurable primary color percentage)",
3622 (int*)(void*)(&prefs.gui_packet_list_multi_color_mode), gui_packet_list_multi_color_modes, false0);
3623 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_multi_color_mode", gui_color_effect_flags);
3624
3625 prefs_register_uint_preference(gui_layout_module, "packet_list_multi_color_shift_percent",
3626 "Shift Right percentage",
3627 "Primary color percentage in Shift Right mode (75, 80, 85, 90, or 95)",
3628 10,
3629 &prefs.gui_packet_list_multi_color_shift_percent);
3630 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_multi_color_shift_percent", gui_color_effect_flags);
3631
3632 prefs_register_bool_preference(gui_module, "packet_list_multi_color_details",
3633 "Display Multiple Colors in Packet Details",
3634 "Show all matching color filter names in packet details pane and TShark output when multiple color filters match",
3635 &prefs.gui_packet_list_multi_color_details);
3636 /* This preference affects what is shown in the packet detail proto tree,
3637 * so changing it requires re-dissection to take effect immediately. */
3638 prefs_set_preference_effect(gui_module, "packet_list_multi_color_details",
3639 PREF_EFFECT_DISSECTION(1u << 0));
3640
3641 prefs_register_bool_preference(gui_module, "coloring_rules_include_disabled",
3642 "Show disabled coloring rules",
3643 "Also match disabled coloring rules and list them in the packet details, marked as disabled. Disabled rules never color packets.",
3644 &prefs.gui_coloring_rules_include_disabled);
3645 /* Matching disabled rules are added to the packet details tree,
3646 * so changing it requires re-dissection to take effect immediately. */
3647 prefs_set_preference_effect(gui_module, "coloring_rules_include_disabled",
3648 PREF_EFFECT_DISSECTION(1u << 0));
3649
3650 prefs_register_enum_preference(gui_layout_module, "packet_list_multi_color_separator",
3651 "Color Stripe Separator Style",
3652 "Shape of the boundary between color stripes: Vertical, Diagonal (candy-cane), or Bubble (half-moon)",
3653 (int*)(void*)(&prefs.gui_packet_list_multi_color_separator), gui_packet_list_multi_color_separators, false0);
3654 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_multi_color_separator", gui_color_effect_flags);
3655
3656 prefs_register_bool_preference(gui_module, "packet_list_is_sortable",
3657 "Allow packet list to be sortable",
3658 "To prevent sorting by mistake (which can take some time to calculate), it can be disabled",
3659 &prefs.gui_packet_list_sortable);
3660
3661 prefs_register_uint_preference(gui_module, "packet_list_cached_rows_max",
3662 "Maximum cached rows",
3663 "Maximum number of rows that can be sorted by columns that require dissection. Increasing this increases memory consumption by caching column text",
3664 10,
3665 &prefs.gui_packet_list_cached_rows_max);
3666
3667 prefs_register_bool_preference(gui_module, "interfaces_show_hidden",
3668 "Show hidden interfaces",
3669 "Show all interfaces, including interfaces marked as hidden",
3670 &prefs.gui_interfaces_show_hidden);
3671
3672 prefs_register_bool_preference(gui_module, "interfaces_remote_display",
3673 "Show Remote interfaces",
3674 "Show remote interfaces in the interface selection",
3675 &prefs.gui_interfaces_remote_display);
3676
3677 register_string_like_preference(gui_module, "interfaces_hidden_types", "Hide interface types in list",
3678 "Hide the given interface types in the startup list.\n"
3679 "A comma-separated string of interface type values (e.g. 5,9).\n"
3680 "0 = Wired,\n"
3681 "1 = AirPCAP,\n"
3682 "2 = Pipe,\n"
3683 "3 = STDIN,\n"
3684 "4 = Bluetooth,\n"
3685 "5 = Wireless,\n"
3686 "6 = Dial-Up,\n"
3687 "7 = USB,\n"
3688 "8 = External Capture,\n"
3689 "9 = Virtual",
3690 &prefs.gui_interfaces_hide_types, PREF_STRING, NULL((void*)0), true1);
3691
3692 prefs_register_bool_preference(gui_module, "io_graph_automatic_update",
3693 "Enables automatic updates for IO Graph",
3694 "Enables automatic updates for IO Graph",
3695 &prefs.gui_io_graph_automatic_update);
3696
3697 prefs_register_bool_preference(gui_module, "io_graph_enable_legend",
3698 "Enables the legend of IO Graph",
3699 "Enables the legend of IO Graph",
3700 &prefs.gui_io_graph_enable_legend);
3701
3702 prefs_register_bool_preference(gui_module, "plot_automatic_update",
3703 "Enables automatic updates for Plot",
3704 "Enables automatic updates for Plot",
3705 &prefs.gui_plot_automatic_update);
3706
3707 prefs_register_bool_preference(gui_module, "plot_enable_legend",
3708 "Enables the legend of Plot",
3709 "Enables the legend of Plot",
3710 &prefs.gui_plot_enable_legend);
3711
3712 prefs_register_bool_preference(gui_module, "plot_enable_auto_scroll",
3713 "Enables auto scroll of Plot",
3714 "Enables auto scroll of Plot",
3715 &prefs.gui_plot_enable_auto_scroll);
3716
3717 prefs_register_bool_preference(gui_module, "show_byteview_in_dialog",
3718 "Show the byte view in the packet details dialog",
3719 "Show the byte view in the packet details dialog",
3720 &prefs.gui_packet_details_show_byteview);
3721
3722 /* Console
3723 * These are preferences that can be read/written using the
3724 * preference module API. These preferences still use their own
3725 * configuration screens for access, but this cuts down on the
3726 * preference "string compare list" in set_pref()
3727 */
3728 console_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "console", "Console",
3729 "Console logging and debugging output", NULL((void*)0), NULL((void*)0), false0);
3730
3731 prefs_register_obsolete_preference(console_module, "log.level");
3732
3733 prefs_register_bool_preference(console_module, "incomplete_dissectors_check_debug",
3734 "Print debug line for incomplete dissectors",
3735 "Look for dissectors that left some bytes undecoded (debug)",
3736 &prefs.incomplete_dissectors_check_debug);
3737
3738 /* Display filter Expressions
3739 * This used to be an array of individual fields that has now been
3740 * converted to a UAT. Just make it part of the GUI category even
3741 * though the name of the preference will never be seen in preference
3742 * file
3743 */
3744 filter_expression_register_uat(gui_module);
3745
3746 /* Capture
3747 * These are preferences that can be read/written using the
3748 * preference module API. These preferences still use their own
3749 * configuration screens for access, but this cuts down on the
3750 * preference "string compare list" in set_pref()
3751 */
3752 capture_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "capture", "Capture",
3753 "Capture preferences", NULL((void*)0), apply_aggregation_prefs, false0);
3754 /* Capture preferences don't affect dissection */
3755 prefs_set_module_effect_flags(capture_module, PREF_EFFECT_CAPTURE(1u << 1));
3756
3757 register_string_like_preference(capture_module, "device", "Default capture device",
3758 "Default capture device",
3759 &prefs.capture_device, PREF_STRING, NULL((void*)0), false0);
3760
3761 register_string_like_preference(capture_module, "devices_linktypes", "Interface link-layer header type",
3762 "Interface link-layer header types (Ex: en0(1),en1(143),...)",
3763 &prefs.capture_devices_linktypes, PREF_STRING, NULL((void*)0), false0);
3764
3765 register_string_like_preference(capture_module, "devices_descr", "Interface descriptions",
3766 "Interface descriptions (Ex: eth0(eth0 descr),eth1(eth1 descr),...)",
3767 &prefs.capture_devices_descr, PREF_STRING, NULL((void*)0), false0);
3768
3769 register_string_like_preference(capture_module, "devices_hide", "Hide interface",
3770 "Hide interface? (Ex: eth0,eth3,...)",
3771 &prefs.capture_devices_hide, PREF_STRING, NULL((void*)0), false0);
3772
3773 register_string_like_preference(capture_module, "devices_monitor_mode", "Capture in monitor mode",
3774 "By default, capture in monitor mode on interface? (Ex: eth0,eth3,...)",
3775 &prefs.capture_devices_monitor_mode, PREF_STRING, NULL((void*)0), false0);
3776
3777 register_string_like_preference(capture_module, "devices_buffersize", "Interface buffer size",
3778 "Interface buffer size (Ex: en0(1),en1(143),...)",
3779 &prefs.capture_devices_buffersize, PREF_STRING, NULL((void*)0), false0);
3780
3781 register_string_like_preference(capture_module, "devices_snaplen", "Interface snap length",
3782 "Interface snap length (Ex: en0(65535),en1(1430),...)",
3783 &prefs.capture_devices_snaplen, PREF_STRING, NULL((void*)0), false0);
3784
3785 register_string_like_preference(capture_module, "devices_pmode", "Interface promiscuous mode",
3786 "Interface promiscuous mode (Ex: en0(0),en1(1),...)",
3787 &prefs.capture_devices_pmode, PREF_STRING, NULL((void*)0), false0);
3788
3789 prefs_register_bool_preference(capture_module, "prom_mode", "Capture in promiscuous mode",
3790 "Capture in promiscuous mode?", &prefs.capture_prom_mode);
3791
3792 prefs_register_bool_preference(capture_module, "monitor_mode", "Capture in monitor mode on 802.11 devices",
3793 "Capture in monitor mode on all 802.11 devices that support it?", &prefs.capture_monitor_mode);
3794
3795 register_string_like_preference(capture_module, "devices_filter", "Interface capture filter",
3796 "Interface capture filter (Ex: en0(tcp),en1(udp),...)",
3797 &prefs.capture_devices_filter, PREF_STRING, NULL((void*)0), false0);
3798
3799 prefs_register_bool_preference(capture_module, "pcap_ng", "Capture in pcapng format",
3800 "Capture in pcapng format?", &prefs.capture_pcap_ng);
3801
3802#ifdef HAVE_ZSTD1
3803 prefs_register_int_preference(capture_module, "zstd_compression_level",
3804 "Zstandard compression level",
3805 "Compression level for saving and exporting Zstandard captures. "
3806 "Higher levels use more CPU and memory to produce smaller files. "
3807 "Use 1 to 22, or 0 for the library default (3). "
3808 "With Zstandard 1.4.0 or newer, negative levels select fast compression; "
3809 "more negative levels favor speed over compression ratio. "
3810 "Also applies to TShark when rewriting captures with -r and -w.",
3811 &prefs.capture_zstd_compression_level);
3812#endif
3813
3814 prefs_register_enum_preference(capture_module, "process_info", "Record the processes that packets belong to",
3815 "What to record, in pcapng files, of the processes on this host that sent or received each packet."
3816 " Paths, command lines and user names can be sensitive.",
3817 (int*)(void*)(&prefs.capture_process_info), capture_process_info_vals, false0);
3818
3819 prefs_register_bool_preference(capture_module, "real_time_update", "Update packet list in real time during capture",
3820 "Update packet list in real time during capture?", &prefs.capture_real_time);
3821
3822 prefs_register_uint_preference(capture_module, "update_interval",
3823 "Capture update interval",
3824 "Capture update interval in ms",
3825 10,
3826 &prefs.capture_update_interval);
3827
3828 prefs_register_directory_preference(capture_module, "temp_dir", "Temporary directory",
3829 "Directory in which to write temporary capture files. Leave empty to use the "
3830 "system default (the TMPDIR environment variable, or /tmp). A directory chosen in "
3831 "the Capture Options dialog is saved here. Overridden by the --temp-dir option.",
3832 (const char **)&prefs.capture_temp_dir);
3833
3834 prefs_register_bool_preference(capture_module, "no_interface_load", "Don't load interfaces on startup",
3835 "Don't automatically load capture interfaces on startup", &prefs.capture_no_interface_load);
3836
3837 prefs_register_bool_preference(capture_module, "no_extcap", "Disable external capture interfaces",
3838 "Disable external capture modules (extcap)", &prefs.capture_no_extcap);
3839
3840 prefs_register_obsolete_preference(capture_module, "auto_scroll");
3841
3842 prefs_register_bool_preference(capture_module, "show_info", "Show capture information dialog while capturing",
3843 "Show capture information dialog while capturing?", &prefs.capture_show_info);
3844
3845 prefs_register_obsolete_preference(capture_module, "syntax_check_filter");
3846
3847 prefs_register_obsolete_preference(capture_module, "columns");
3848
3849 aggregation_field_register_uat(capture_module);
3850
3851 /* Name Resolution */
3852 nameres_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "nameres", "Name Resolution",
3853 "Name Resolution", "ChCustPreferencesSection.html#ChCustPrefsNameSection", addr_resolve_pref_apply, true1);
3854 addr_resolve_pref_init(nameres_module);
3855 oid_pref_init(nameres_module);
3856 maxmind_db_pref_init(nameres_module);
3857
3858 /* Printing
3859 * None of these have any effect; we keep them as obsolete preferences
3860 * in order to avoid errors when reading older preference files.
3861 */
3862 printing = prefs_register_module(prefs_top_level_modules, prefs_modules, "print", "Printing",
3863 "Printing", NULL((void*)0), NULL((void*)0), false0);
3864 prefs_register_obsolete_preference(printing, "format");
3865 prefs_register_obsolete_preference(printing, "command");
3866 prefs_register_obsolete_preference(printing, "file");
3867
3868 /* Codecs */
3869 codecs_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "codecs", "Codecs",
3870 "Codecs", NULL((void*)0), NULL((void*)0), true1);
3871
3872 /* Statistics */
3873 stats_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "statistics", "Statistics",
3874 "Statistics", "ChCustPreferencesSection.html#_statistics", &stats_callback, true1);
3875
3876 prefs_register_uint_preference(stats_module, "update_interval",
3877 "Tap update interval in ms",
3878 "Determines time between tap updates",
3879 10,
3880 &prefs.tap_update_interval);
3881
3882 prefs_register_uint_preference(stats_module, "flow_graph_max_export_items",
3883 "Maximum Flow Graph items to export as image",
3884 "The maximum number of Flow Graph items (frames) "
3885 "to include when exporting the graph as an image. "
3886 "Note that some formats (e.g., JPEG) have inherent "
3887 "pixel limits and image viewers might be unable to "
3888 "handle very large images.",
3889 10,
3890 &prefs.flow_graph_max_export_items);
3891
3892 prefs_register_bool_preference(stats_module, "st_enable_burstinfo",
3893 "Enable the calculation of burst information",
3894 "If enabled burst rates will be calculated for statistics that use the stats_tree system. "
3895 "Burst rates are calculated over a much shorter time interval than the rate column.",
3896 &prefs.st_enable_burstinfo);
3897
3898 prefs_register_bool_preference(stats_module, "st_burst_showcount",
3899 "Show burst count for item rather than rate",
3900 "If selected the stats_tree statistics nodes will show the count of events "
3901 "within the burst window instead of a burst rate. Burst rate is calculated "
3902 "as number of events within burst window divided by the burst windown length.",
3903 &prefs.st_burst_showcount);
3904
3905 prefs_register_uint_preference(stats_module, "st_burst_resolution",
3906 "Burst rate resolution (ms)",
3907 "Sets the duration of the time interval into which events are grouped when calculating "
3908 "the burst rate. Higher resolution (smaller number) increases processing overhead.",
3909 10,&prefs.st_burst_resolution);
3910
3911 prefs_register_uint_preference(stats_module, "st_burst_windowlen",
3912 "Burst rate window size (ms)",
3913 "Sets the duration of the sliding window during which the burst rate is "
3914 "measured. Longer window relative to burst rate resolution increases "
3915 "processing overhead. Will be truncated to a multiple of burst resolution.",
3916 10,&prefs.st_burst_windowlen);
3917
3918 prefs_register_enum_preference(stats_module, "st_sort_defcolflag",
3919 "Default sort column for stats_tree stats",
3920 "Sets the default column by which stats based on the stats_tree "
3921 "system is sorted.",
3922 &prefs.st_sort_defcolflag, st_sort_col_vals, false0);
3923
3924 prefs_register_bool_preference(stats_module, "st_sort_defdescending",
3925 "Default stats_tree sort order is descending",
3926 "When selected, statistics based on the stats_tree system will by default "
3927 "be sorted in descending order.",
3928 &prefs.st_sort_defdescending);
3929
3930 prefs_register_bool_preference(stats_module, "st_sort_casesensitve",
3931 "Case sensitive sort of stats_tree item names",
3932 "When selected, the item/node names of statistics based on the stats_tree "
3933 "system will be sorted taking case into account. Else the case of the name "
3934 "will be ignored.",
3935 &prefs.st_sort_casesensitve);
3936
3937 prefs_register_bool_preference(stats_module, "st_sort_rng_nameonly",
3938 "Always sort 'range' nodes by name",
3939 "When selected, the stats_tree nodes representing a range of values "
3940 "(0-49, 50-100, etc.) will always be sorted by name (the range of the "
3941 "node). Else range nodes are sorted by the same column as the rest of "
3942 " the tree.",
3943 &prefs.st_sort_rng_nameonly);
3944
3945 prefs_register_bool_preference(stats_module, "st_sort_rng_fixorder",
3946 "Always sort 'range' nodes in ascending order",
3947 "When selected, the stats_tree nodes representing a range of values "
3948 "(0-49, 50-100, etc.) will always be sorted ascending; else it follows "
3949 "the sort direction of the tree. Only effective if \"Always sort "
3950 "'range' nodes by name\" is also selected.",
3951 &prefs.st_sort_rng_fixorder);
3952
3953 prefs_register_bool_preference(stats_module, "st_sort_showfullname",
3954 "Display the full stats_tree plug-in name",
3955 "When selected, the full name (including menu path) of the stats_tree "
3956 "plug-in is show in windows. If cleared the plug-in name is shown "
3957 "without menu path (only the part of the name after last '/' character.)",
3958 &prefs.st_sort_showfullname);
3959
3960 prefs_register_enum_preference(stats_module, "output_format",
3961 "Default output format",
3962 "Sets the default output format for statistical data. Only supported "
3963 "by taps using the stats_tree system currently; other taps may honor "
3964 "this preference in the future. ",
3965 &prefs.st_format, st_format_vals, false0);
3966
3967 module_t *conv_module;
3968 // avoid using prefs_register_stat to prevent lint complaint about recursion
3969 conv_module = prefs_register_submodule(stats_module, prefs_modules, "conv", "Conversations",
3970 "Conversations & Endpoints", NULL((void*)0), NULL((void*)0), true1);
3971 prefs_register_bool_preference(conv_module, "machine_readable",
3972 "Display exact (machine-readable) byte counts",
3973 "When enabled, exact machine-readable byte counts are displayed. "
3974 "When disabled, human readable numbers with SI prefixes are displayed.",
3975 &prefs.conv_machine_readable);
3976
3977 /* Protocols */
3978 protocols_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "protocols", "Protocols",
3979 "Protocols", "ChCustPreferencesSection.html#ChCustPrefsProtocolsSection", NULL((void*)0), true1);
3980
3981 prefs_register_bool_preference(protocols_module, "display_hidden_proto_items",
3982 "Display hidden protocol items",
3983 "Display all hidden protocol items in the packet list.",
3984 &prefs.display_hidden_proto_items);
3985
3986 prefs_register_bool_preference(protocols_module, "display_byte_fields_with_spaces",
3987 "Display byte fields with a space character between bytes",
3988 "Display all byte fields with a space character between each byte in the packet list.",
3989 &prefs.display_byte_fields_with_spaces);
3990
3991 /*
3992 * Note the -t / option only affects the display of the packet timestamp
3993 * in the default time column; this is for all other absolute times.
3994 */
3995 prefs_register_enum_preference(protocols_module, "display_abs_time_ascii",
3996 "Format absolute times like asctime",
3997 "When to format absolute times similar to asctime instead of ISO 8601, for backwards compatibility with older Wireshark.",
3998 (int*)&prefs.display_abs_time_ascii, abs_time_format_options, false0);
3999
4000 prefs_register_bool_preference(protocols_module, "enable_incomplete_dissectors_check",
4001 "Look for incomplete dissectors",
4002 "Look for dissectors that left some bytes undecoded.",
4003 &prefs.enable_incomplete_dissectors_check);
4004
4005 prefs_register_bool_preference(protocols_module, "strict_conversation_tracking_heuristics",
4006 "Enable stricter conversation tracking heuristics",
4007 "Protocols may use things like VLAN ID or interface ID to narrow the potential for duplicate conversations. "
4008 "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",
4009 &prefs.strict_conversation_tracking_heuristics);
4010
4011 prefs_register_bool_preference(protocols_module, "ignore_dup_frames",
4012 "Ignore duplicate frames",
4013 "Ignore frames that are exact duplicates of any previous frame.",
4014 &prefs.ignore_dup_frames);
4015
4016 prefs_register_enum_preference(protocols_module, "conversation_deinterlacing_key",
4017 "Deinterlacing conversations key",
4018 "Separate into different conversations frames that look like duplicates but have different Interface, MAC, or VLAN field values.",
4019 (int *)&prefs.conversation_deinterlacing_key, conv_deint_options, false0);
4020
4021 prefs_register_uint_preference(protocols_module, "ignore_dup_frames_cache_entries",
4022 "The max number of hashes to keep in memory for determining duplicates frames",
4023 "If \"Ignore duplicate frames\" is set, this setting sets the maximum number "
4024 "of cache entries to maintain. A 0 means no limit.",
4025 10, &prefs.ignore_dup_frames_cache_entries);
4026
4027
4028 /* Obsolete preferences
4029 * These "modules" were reorganized/renamed to correspond to their GUI
4030 * configuration screen within the preferences dialog
4031 */
4032
4033 /* taps is now part of the stats module */
4034 prefs_register_module(prefs_top_level_modules, prefs_modules, "taps", "TAPS", "TAPS", NULL((void*)0), NULL((void*)0), false0);
4035 /* packet_list is now part of the protocol (parent) module */
4036 prefs_register_module(prefs_top_level_modules, prefs_modules, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL((void*)0), NULL((void*)0), false0);
4037 /* stream is now part of the gui module */
4038 prefs_register_module(prefs_top_level_modules, prefs_modules, "stream", "STREAM", "STREAM", NULL((void*)0), NULL((void*)0), false0);
4039
4040}
4041
4042/* Parse through a list of comma-separated, possibly quoted strings.
4043 Return a list of the string data. */
4044GList *
4045prefs_get_string_list(const char *str)
4046{
4047 enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
4048
4049 int state = PRE_STRING, i = 0;
4050 bool_Bool backslash = false0;
4051 unsigned char cur_c;
4052 const size_t default_size = 64;
4053 GString *slstr = NULL((void*)0);
4054 GList *sl = NULL((void*)0);
4055
4056 /* Allocate a buffer for the first string. */
4057 slstr = g_string_sized_new(default_size);
4058
4059 for (;;) {
4060 cur_c = str[i];
4061 if (cur_c == '\0') {
4062 /* It's the end of the input, so it's the end of the string we
4063 were working on, and there's no more input. */
4064 if (state == IN_QUOT || backslash) {
4065 /* We were in the middle of a quoted string or backslash escape,
4066 and ran out of characters; that's an error. */
4067 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)))))
;
4068 prefs_clear_string_list(sl);
4069 return NULL((void*)0);
4070 }
4071 if (slstr->len > 0)
4072 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))))
);
4073 else
4074 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)))))
;
4075 break;
4076 }
4077 if (cur_c == '"' && !backslash) {
4078 switch (state) {
4079 case PRE_STRING:
4080 /* We hadn't yet started processing a string; this starts the
4081 string, and we're now quoting. */
4082 state = IN_QUOT;
4083 break;
4084 case IN_QUOT:
4085 /* We're in the middle of a quoted string, and we saw a quotation
4086 mark; we're no longer quoting. */
4087 state = NOT_IN_QUOT;
4088 break;
4089 case NOT_IN_QUOT:
4090 /* We're working on a string, but haven't seen a quote; we're
4091 now quoting. */
4092 state = IN_QUOT;
4093 break;
4094 default:
4095 break;
4096 }
4097 } else if (cur_c == '\\' && !backslash) {
4098 /* We saw a backslash, and the previous character wasn't a
4099 backslash; escape the next character.
4100
4101 This also means we've started a new string. */
4102 backslash = true1;
4103 if (state == PRE_STRING)
4104 state = NOT_IN_QUOT;
4105 } else if (cur_c == ',' && state != IN_QUOT && !backslash) {
4106 /* We saw a comma, and we're not in the middle of a quoted string
4107 and it wasn't preceded by a backslash; it's the end of
4108 the string we were working on... */
4109 if (slstr->len > 0) {
4110 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))))
);
4111 slstr = g_string_sized_new(default_size);
4112 }
4113
4114 /* ...and the beginning of a new string. */
4115 state = PRE_STRING;
4116 } else if (!g_ascii_isspace(cur_c)((g_ascii_table[(guchar) (cur_c)] & G_ASCII_SPACE) != 0) || state != PRE_STRING) {
4117 /* Either this isn't a white-space character, or we've started a
4118 string (i.e., already seen a non-white-space character for that
4119 string and put it into the string).
4120
4121 The character is to be put into the string; do so. */
4122 g_string_append_c(slstr, cur_c)g_string_append_c_inline (slstr, cur_c);
4123
4124 /* If it was backslash-escaped, we're done with the backslash escape. */
4125 backslash = false0;
4126 }
4127 i++;
4128 }
4129 return(sl);
4130}
4131
4132char *join_string_list(GList *sl)
4133{
4134 GString *joined_str = g_string_new("");
4135 GList *cur, *first;
4136 char *str;
4137 unsigned item_count = 0;
4138
4139 cur = first = g_list_first(sl);
4140 while (cur) {
4141 item_count++;
4142 str = (char *)cur->data;
4143
4144 if (cur != first)
4145 g_string_append_c(joined_str, ',')g_string_append_c_inline (joined_str, ',');
4146
4147 if (item_count % 2) {
4148 /* Wrap the line. */
4149 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))
;
4150 } else
4151 g_string_append_c(joined_str, ' ')g_string_append_c_inline (joined_str, ' ');
4152
4153 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4154 while (*str) {
4155 gunichar uc = g_utf8_get_char (str);
4156
4157 if (uc == '"' || uc == '\\')
4158 g_string_append_c(joined_str, '\\')g_string_append_c_inline (joined_str, '\\');
4159
4160 if (g_unichar_isprint(uc))
4161 g_string_append_unichar (joined_str, uc);
4162
4163 str = g_utf8_next_char (str)((str) + g_utf8_skip[*(const guchar *)(str)]);
4164 }
4165
4166 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4167
4168 cur = cur->next;
4169 }
4170 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))))
;
4171}
4172
4173void
4174prefs_clear_string_list(GList *sl)
4175{
4176 g_list_free_full(sl, g_free);
4177}
4178
4179/*
4180 * Takes a string, a pointer to an array of "enum_val_t"s, and a default int
4181 * value.
4182 * The array must be terminated by an entry with a null "name" string.
4183 *
4184 * If the string matches a "name" string in an entry, the value from that
4185 * entry is returned.
4186 *
4187 * Otherwise, if a string matches a "description" string in an entry, the
4188 * value from that entry is returned; we do that for backwards compatibility,
4189 * as we used to have only a "name" string that was used both for command-line
4190 * and configuration-file values and in the GUI (which meant either that
4191 * the GUI had what might be somewhat cryptic values to select from or that
4192 * the "-o" flag took long strings, often with spaces in them).
4193 *
4194 * Otherwise, the default value that was passed as the third argument is
4195 * returned.
4196 */
4197static int
4198find_val_for_string(const char *needle, const enum_val_t *haystack,
4199 int default_value)
4200{
4201 int i;
4202
4203 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4204 if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
4205 return haystack[i].value;
4206 }
4207 }
4208 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4209 if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
4210 return haystack[i].value;
4211 }
4212 }
4213 return default_value;
4214}
4215
4216/* Preferences file format:
4217 * - Configuration directives start at the beginning of the line, and
4218 * are terminated with a colon.
4219 * - Directives can be continued on the next line by preceding them with
4220 * whitespace.
4221 *
4222 * Example:
4223
4224# This is a comment line
4225print.command: lpr
4226print.file: /a/very/long/path/
4227 to/wireshark-out.ps
4228 *
4229 */
4230
4231/*
4232 * Initialize non-dissector preferences used by the "register preference" API
4233 * to default values so the default values can be used when registered.
4234 *
4235 * String, filename, and directory preferences will be g_freed so they must
4236 * be g_mallocated.
4237 */
4238static void
4239prefs_set_global_defaults(wmem_allocator_t* pref_scope, const char** col_fmt, int num_cols)
4240{
4241 int i;
4242 fmt_data *cfmt;
4243
4244 prefs.gui_toolbar_main_style = TB_STYLE_ICONS0;
4245 /* We try to find the best font in the Qt code */
4246 wmem_free(pref_scope, prefs.gui_font_name);
4247 prefs.gui_font_name = wmem_strdup(pref_scope, "");
4248 wmem_free(pref_scope, prefs.gui_colorized_fg);
4249 prefs.gui_colorized_fg = wmem_strdup(pref_scope, "000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
4250 wmem_free(pref_scope, prefs.gui_colorized_bg);
4251 prefs.gui_colorized_bg = wmem_strdup(pref_scope, "ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
4252
4253 prefs.gui_geometry_save_position = true1;
4254 prefs.gui_geometry_save_size = true1;
4255 prefs.gui_geometry_save_maximized= true1;
4256 prefs.gui_fileopen_style = FO_STYLE_LAST_OPENED0;
4257 prefs.gui_recent_df_entries_max = 10;
4258 prefs.gui_recent_files_count_max = 10;
4259 wmem_free(pref_scope, prefs.gui_fileopen_dir);
4260 prefs.gui_fileopen_dir = wmem_strdup(pref_scope, get_persdatafile_dir());
4261 prefs.gui_fileopen_preview = 3;
4262 wmem_free(pref_scope, prefs.gui_tlskeylog_command);
4263 prefs.gui_tlskeylog_command = wmem_strdup(pref_scope, "");
4264 prefs.gui_ask_unsaved = true1;
4265 prefs.gui_autocomplete_filter = true1;
4266 prefs.gui_find_wrap = true1;
4267 prefs.gui_update_enabled = true1;
4268 prefs.gui_update_channel = UPDATE_CHANNEL_STABLE;
4269 prefs.gui_update_interval = 60*60*24; /* Seconds */
4270 prefs.gui_debounce_timer = 400; /* milliseconds */
4271 wmem_free(pref_scope, prefs.gui_window_title);
4272 prefs.gui_window_title = wmem_strdup(pref_scope, "");
4273 wmem_free(pref_scope, prefs.gui_prepend_window_title);
4274 prefs.gui_prepend_window_title = wmem_strdup(pref_scope, "");
4275 wmem_free(pref_scope, prefs.gui_start_title);
4276 prefs.gui_start_title = wmem_strdup(pref_scope, "The World's Most Popular Network Protocol Analyzer");
4277 prefs.gui_version_placement = version_both;
4278 prefs.gui_welcome_page_show_recent = true1;
4279 prefs.gui_layout_type = layout_type_2;
4280 prefs.gui_layout_content_1 = layout_pane_content_plist;
4281 prefs.gui_layout_content_2 = layout_pane_content_pdetails;
4282 prefs.gui_layout_content_3 = layout_pane_content_pbytes;
4283 prefs.gui_packet_list_elide_mode = ELIDE_RIGHT;
4284 prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut = COPY_FORMAT_TEXT;
4285 prefs.gui_packet_list_copy_text_with_aligned_columns = false0;
4286 prefs.gui_packet_list_show_related = true1;
4287 prefs.gui_packet_list_show_minimap = true1;
4288 prefs.gui_packet_list_sortable = true1;
4289 prefs.gui_packet_list_cached_rows_max = 10000;
4290 prefs.gui_packet_list_multi_color_mode = PACKET_LIST_MULTI_COLOR_MODE_OFF;
4291 prefs.gui_packet_list_multi_color_shift_percent = 85;
4292 prefs.gui_packet_list_multi_color_details = false0;
4293 prefs.gui_coloring_rules_include_disabled = false0;
4294 prefs.gui_packet_list_multi_color_separator = PACKET_LIST_MULTI_COLOR_SEPARATOR_DIAGONAL;
4295 wmem_free(pref_scope, prefs.gui_interfaces_hide_types);
4296 prefs.gui_interfaces_hide_types = wmem_strdup(pref_scope, "");
4297 prefs.gui_interfaces_show_hidden = false0;
4298 prefs.gui_interfaces_remote_display = true1;
4299 prefs.gui_packet_list_separator = false0;
4300 prefs.gui_packet_header_column_definition = true1;
4301 prefs.gui_packet_list_hover_style = true1;
4302 prefs.gui_show_selected_packet = false0;
4303 prefs.gui_show_file_load_time = false0;
4304 prefs.gui_max_export_objects = 1000;
4305 prefs.gui_max_tree_items = 1 * 1000 * 1000;
4306 prefs.gui_max_tree_depth = 5 * 100;
4307 prefs.gui_decimal_places1 = DEF_GUI_DECIMAL_PLACES12;
4308 prefs.gui_decimal_places2 = DEF_GUI_DECIMAL_PLACES24;
4309 prefs.gui_decimal_places3 = DEF_GUI_DECIMAL_PLACES36;
4310
4311 if (prefs.col_list) {
4312 free_col_info(prefs.col_list);
4313 prefs.col_list = NULL((void*)0);
4314 }
4315 for (i = 0; i < num_cols; i++) {
4316 cfmt = g_new0(fmt_data,1)((fmt_data *) g_malloc0_n ((1), sizeof (fmt_data)));
4317 cfmt->title = g_strdup(col_fmt[i * 2])g_strdup_inline (col_fmt[i * 2]);
4318 cfmt->visible = true1;
4319 cfmt->display = COLUMN_DISPLAY_STRINGS'R';
4320 parse_column_format(cfmt, col_fmt[(i * 2) + 1]);
4321 prefs.col_list = g_list_append(prefs.col_list, cfmt);
4322 }
4323 prefs.num_cols = num_cols;
4324
4325/* set the default values for the capture dialog box */
4326 prefs.capture_prom_mode = true1;
4327 prefs.capture_monitor_mode = false0;
4328 prefs.capture_pcap_ng = true1;
4329 prefs.capture_zstd_compression_level = 3;
4330 prefs.capture_process_info = CAPTURE_PROCESS_INFO_BASIC;
4331 prefs.capture_real_time = true1;
4332 prefs.capture_update_interval = DEFAULT_UPDATE_INTERVAL100;
4333 prefs.capture_no_extcap = false0;
4334 prefs.capture_show_info = false0;
4335
4336/* set the default values for the tap/statistics dialog box */
4337 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
4338 prefs.flow_graph_max_export_items = 1000;
4339 prefs.st_enable_burstinfo = true1;
4340 prefs.st_burst_showcount = false0;
4341 prefs.st_burst_resolution = ST_DEF_BURSTRES5;
4342 prefs.st_burst_windowlen = ST_DEF_BURSTLEN100;
4343 prefs.st_sort_casesensitve = true1;
4344 prefs.st_sort_rng_fixorder = true1;
4345 prefs.st_sort_rng_nameonly = true1;
4346 prefs.st_sort_defcolflag = ST_SORT_COL_COUNT2;
4347 prefs.st_sort_defdescending = true1;
4348 prefs.st_sort_showfullname = false0;
4349 prefs.conv_machine_readable = false0;
4350
4351 /* protocols */
4352 prefs.display_hidden_proto_items = false0;
4353 prefs.display_byte_fields_with_spaces = false0;
4354 prefs.display_abs_time_ascii = ABS_TIME_ASCII_TREE;
4355 prefs.ignore_dup_frames = false0;
4356 prefs.ignore_dup_frames_cache_entries = 10000;
4357
4358 /* set the default values for the io graph dialog */
4359 prefs.gui_io_graph_automatic_update = true1;
4360 prefs.gui_io_graph_enable_legend = true1;
4361
4362 /* set the default values for the plot dialog */
4363 prefs.gui_plot_automatic_update = true1;
4364 prefs.gui_plot_enable_legend = true1;
4365 prefs.gui_plot_enable_auto_scroll = false0;
4366
4367 /* set the default values for the packet dialog */
4368 prefs.gui_packet_dialog_layout = layout_vertical;
4369 prefs.gui_packet_details_show_byteview = true1;
4370}
4371
4372/*
4373 * Reset a single dissector preference.
4374 */
4375void
4376reset_pref(pref_t *pref)
4377{
4378 if (!pref) return;
4379
4380 /*
4381 * This preference is no longer supported; it's not a
4382 * real preference, so we don't reset it (i.e., we
4383 * treat it as if it weren't found in the list of
4384 * preferences, and we weren't called in the first place).
4385 */
4386 if (pref->obsolete)
4387 return;
4388
4389 switch (pref->type) {
4390
4391 case PREF_UINT:
4392 *pref->varp.uint = pref->default_val.uint;
4393 break;
4394
4395 case PREF_INT:
4396 *pref->varp.intp = pref->default_val.intval;
4397 break;
4398
4399 case PREF_FLOAT:
4400 *pref->varp.floatp = pref->default_val.floatval;
4401 break;
4402
4403 case PREF_BOOL:
4404 *pref->varp.boolp = pref->default_val.boolval;
4405 break;
4406
4407 case PREF_ENUM:
4408 case PREF_PROTO_TCP_SNDAMB_ENUM:
4409 *pref->varp.enump = pref->default_val.enumval;
4410 break;
4411
4412 case PREF_STRING:
4413 case PREF_SAVE_FILENAME:
4414 case PREF_OPEN_FILENAME:
4415 case PREF_DIRNAME:
4416 case PREF_PASSWORD:
4417 case PREF_DISSECTOR:
4418 reset_string_like_preference(pref);
4419 break;
4420
4421 case PREF_RANGE:
4422 case PREF_DECODE_AS_RANGE:
4423 wmem_free(pref->scope, *pref->varp.range);
4424 *pref->varp.range = range_copy(pref->scope, pref->default_val.range);
4425 break;
4426
4427 case PREF_STATIC_TEXT:
4428 case PREF_UAT:
4429 /* Nothing to do */
4430 break;
4431
4432 case PREF_COLOR:
4433 *pref->varp.colorp = pref->default_val.color;
4434 break;
4435
4436 case PREF_CUSTOM:
4437 pref->custom_cbs.reset_cb(pref);
4438 break;
4439 }
4440}
4441
4442static void
4443reset_pref_cb(void *data, void *user_data)
4444{
4445 pref_t *pref = (pref_t *) data;
4446 module_t *module = (module_t *)user_data;
4447
4448 if (pref && (pref->type == PREF_RANGE || pref->type == PREF_DECODE_AS_RANGE)) {
4449 /*
4450 * Some dissectors expect the range (returned via prefs_get_range_value)
4451 * to remain valid if it has not changed. If it did change, then we
4452 * should set "prefs_changed_flags" to ensure that the preference apply
4453 * callback is invoked. That callback will notify dissectors that it
4454 * should no longer assume the range to be valid.
4455 */
4456 if (ranges_are_equal(*pref->varp.range, pref->default_val.range)) {
4457 /* Optimization: do not invoke apply callback if nothing changed. */
4458 return;
4459 }
4460 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
4461 }
4462 reset_pref(pref);
4463}
4464
4465/*
4466 * Reset all preferences for a module.
4467 */
4468static bool_Bool
4469reset_module_prefs(const void *key _U___attribute__((unused)), void *value, void *data _U___attribute__((unused)))
4470{
4471 module_t *module = (module_t *)value;
4472 g_list_foreach(module->prefs, reset_pref_cb, module);
4473 return false0;
4474}
4475
4476/* Reset preferences */
4477void
4478prefs_reset(const char* app_env_var_prefix, const char** col_fmt, int num_cols)
4479{
4480 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
)
;
4481 prefs.saved_at_version = NULL((void*)0);
4482
4483 /*
4484 * Unload all UAT preferences.
4485 */
4486 uat_unload_all();
4487
4488 /*
4489 * Unload any loaded MIBs.
4490 */
4491 /* XXX - oids_cleanup not tested/supported at non-shutdown yet */
4492 //oids_cleanup();
4493
4494 /*
4495 * Reload all UAT preferences.
4496 */
4497 uat_load_all(app_env_var_prefix);
4498
4499 /*
4500 * Reset the non-dissector preferences.
4501 */
4502 prefs_set_global_defaults(wmem_epan_scope(), col_fmt, num_cols);
4503
4504 /*
4505 * Reset the non-UAT dissector preferences.
4506 */
4507 wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL((void*)0));
4508}
4509
4510#ifdef _WIN32
4511static void
4512read_registry(void)
4513{
4514 HKEY hTestKey;
4515 DWORD data;
4516 DWORD data_size = sizeof(DWORD);
4517 DWORD ret;
4518
4519 ret = RegOpenKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, KEY_READ, &hTestKey);
4520 if (ret != ERROR_SUCCESS && ret != ERROR_FILE_NOT_FOUND) {
4521 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"
, 4521, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
4522 return;
4523 }
4524
4525 ret = RegQueryValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", NULL((void*)0), NULL((void*)0), (LPBYTE)&data, &data_size);
4526 if (ret == ERROR_SUCCESS) {
4527 ws_log_console_open = (ws_log_console_open_pref)data;
4528 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"
, 4528, __func__, "Got ""ConsoleOpen"" from Windows registry: %d"
, ws_log_console_open); } } while (0)
;
4529 }
4530 else if (ret != ERROR_FILE_NOT_FOUND) {
4531 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"
, 4531, __func__, "Error reading registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
4532 }
4533
4534 RegCloseKey(hTestKey);
4535}
4536#endif
4537
4538void
4539prefs_read_module(const char *module, bool_Bool from_profile, const char* app_env_var_prefix)
4540{
4541 int err;
4542 char *pf_path;
4543 FILE *pf;
4544
4545 module_t *target_module = prefs_find_module(module);
4546 if (!target_module) {
4547 return;
4548 }
4549
4550 /* Construct the pathname of the user's preferences file for the module. */
4551 char *pf_name = g_strdup_printf("%s.cfg", module);
4552 pf_path = get_persconffile_path(pf_name, from_profile, app_env_var_prefix);
4553 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)
;
4554
4555 /* Read the user's module preferences file, if it exists and is not a dir. */
4556 if (!test_for_regular_file(pf_path) || ((pf = ws_fopenfopen(pf_path, "r")) == NULL((void*)0))) {
4557 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)
;
4558 /* Fall back to the user's generic preferences file. */
4559 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4560 pf = ws_fopenfopen(pf_path, "r");
4561 }
4562
4563 if (pf != NULL((void*)0)) {
4564 /* We succeeded in opening it; read it. */
4565 err = read_prefs_file(pf_path, pf, set_pref, target_module);
4566 if (err != 0) {
4567 /* We had an error reading the file; report it. */
4568 report_warning("Error reading your preferences file \"%s\": %s.",
4569 pf_path, g_strerror(err));
4570 } else
4571 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)
;
4572 fclose(pf);
4573 } else {
4574 /* We failed to open it. If we failed for some reason other than
4575 "it doesn't exist", return the errno and the pathname, so our
4576 caller can report the error. */
4577 if (errno(*__errno_location ()) != ENOENT2) {
4578 report_warning("Can't open your preferences file \"%s\": %s.",
4579 pf_path, g_strerror(errno(*__errno_location ())));
4580 } else
4581 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)
;
4582 }
4583
4584 return;
4585}
4586
4587/* Read the preferences file, fill in "prefs", and return a pointer to it.
4588
4589 If we got an error (other than "it doesn't exist") we report it through
4590 the UI. */
4591e_prefs *
4592read_prefs(const char* app_env_var_prefix)
4593{
4594 int err;
4595 char *pf_path;
4596 FILE *pf;
4597
4598 /* clean up libsmi structures before reading prefs */
4599 /* XXX - oids_cleanup not tested/supported at non-shutdown yet */
4600 // oids_cleanup();
4601
4602#ifdef _WIN32
4603 read_registry();
4604#endif
4605
4606 /*
4607 * If we don't already have the pathname of the global preferences
4608 * file, construct it. Then, in either case, try to open the file.
4609 */
4610 if (gpf_path == NULL((void*)0)) {
4611 /*
4612 * We don't have the path; try the new path first, and, if that
4613 * file doesn't exist, try the old path.
4614 */
4615 gpf_path = get_datafile_path(PF_NAME"preferences", app_env_var_prefix);
4616 if ((pf = ws_fopenfopen(gpf_path, "r")) == NULL((void*)0) && errno(*__errno_location ()) == ENOENT2) {
4617 /*
4618 * It doesn't exist by the new name; try the old name.
4619 */
4620 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)
;
4621 gpf_path = get_datafile_path(OLD_GPF_NAME"wireshark.conf", app_env_var_prefix);
4622 pf = ws_fopenfopen(gpf_path, "r");
4623 }
4624 } else {
4625 /*
4626 * We have the path; try it.
4627 */
4628 pf = ws_fopenfopen(gpf_path, "r");
4629 }
4630
4631 /*
4632 * If we were able to open the file, read it.
4633 * XXX - if it failed for a reason other than "it doesn't exist",
4634 * report the error.
4635 */
4636 if (pf != NULL((void*)0)) {
4637 /* We succeeded in opening it; read it. */
4638 err = read_prefs_file(gpf_path, pf, set_pref, NULL((void*)0));
4639 if (err != 0) {
4640 /* We had an error reading the file; report it. */
4641 report_warning("Error reading global preferences file \"%s\": %s.",
4642 gpf_path, g_strerror(err));
4643 }
4644 fclose(pf);
4645 } else {
4646 /* We failed to open it. If we failed for some reason other than
4647 "it doesn't exist", report the error. */
4648 if (errno(*__errno_location ()) != ENOENT2) {
4649 if (errno(*__errno_location ()) != 0) {
4650 report_warning("Can't open global preferences file \"%s\": %s.",
4651 gpf_path, g_strerror(errno(*__errno_location ())));
4652 }
4653 }
4654 }
4655
4656 /* Construct the pathname of the user's preferences file. */
4657 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4658
4659 /* Read the user's preferences file, if it exists. */
4660 if ((pf = ws_fopenfopen(pf_path, "r")) != NULL((void*)0)) {
4661
4662 /* We succeeded in opening it; read it. */
4663 err = read_prefs_file(pf_path, pf, set_pref, NULL((void*)0));
4664 if (err != 0) {
4665 /* We had an error reading the file; report it. */
4666 report_warning("Error reading your preferences file \"%s\": %s.",
4667 pf_path, g_strerror(err));
4668 } else
4669 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)
;
4670 fclose(pf);
4671 } else {
4672 /* We failed to open it. If we failed for some reason other than
4673 "it doesn't exist", return the errno and the pathname, so our
4674 caller can report the error. */
4675 if (errno(*__errno_location ()) != ENOENT2) {
4676 report_warning("Can't open your preferences file \"%s\": %s.",
4677 pf_path, g_strerror(errno(*__errno_location ())));
4678 } else
4679 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)
;
4680 }
4681
4682 /* load SMI modules if needed */
4683 oids_init(app_env_var_prefix);
4684
4685 return &prefs;
4686}
4687
4688/* read the preferences file (or similar) and call the callback
4689 * function to set each key/value pair found */
4690int
4691read_prefs_file(const char *pf_path, FILE *pf,
4692 pref_set_pair_cb pref_set_pair_fct, void *private_data)
4693{
4694 enum {
4695 START, /* beginning of a line */
4696 IN_VAR, /* processing key name */
4697 PRE_VAL, /* finished processing key name, skipping white space before value */
4698 IN_VAL, /* processing value */
4699 IN_SKIP /* skipping to the end of the line */
4700 } state = START;
4701 int got_c;
4702 GString *cur_val;
4703 GString *cur_var;
4704 bool_Bool got_val = false0;
4705 int fline = 1, pline = 1;
4706 char hint[] = "(save preferences to remove this warning)";
4707 char ver[128];
4708
4709 cur_val = g_string_new("");
4710 cur_var = g_string_new("");
4711
4712 /* Try to read in the profile name in the first line of the preferences file. */
4713 if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) {
1
Assuming the condition is false
2
Taking false branch
4714 /* Assume trailing period and remove it */
4715 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
)
;
4716 prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1);
4717 }
4718 rewind(pf);
3
After calling 'rewind' reading 'errno' is required to find out if the call has failed
4719
4720 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'
4721 if (got_c == '\r') {
4722 /* Treat CR-LF at the end of a line like LF, so that if we're reading
4723 * a Windows-format file on UN*X, we handle it the same way we'd handle
4724 * a UN*X-format file. */
4725 got_c = ws_getc_unlockedgetc_unlocked(pf);
4726 if (got_c == EOF(-1))
4727 break;
4728 if (got_c != '\n') {
4729 /* Put back the character after the CR, and process the CR normally. */
4730 ungetc(got_c, pf);
4731 got_c = '\r';
4732 }
4733 }
4734 if (got_c == '\n') {
4735 state = START;
4736 fline++;
4737 continue;
4738 }
4739
4740 switch (state) {
4741 case START:
4742 if (g_ascii_isalnum(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_ALNUM) != 0)) {
4743 if (cur_var->len > 0) {
4744 if (got_val) {
4745 if (cur_val->len > 0) {
4746 if (cur_val->str[cur_val->len-1] == ',') {
4747 /*
4748 * If the pref has a trailing comma, eliminate it.
4749 */
4750 cur_val->str[cur_val->len-1] = '\0';
4751 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"
, 4751, __func__, "%s line %d: trailing comma in \"%s\" %s", pf_path
, pline, cur_var->str, hint); } } while (0)
;
4752 }
4753 }
4754 /* Call the routine to set the preference; it will parse
4755 the value as appropriate.
4756
4757 Since we're reading a file, rather than processing
4758 explicit user input, for range preferences, silently
4759 lower values in excess of the range's maximum, rather
4760 than reporting errors and failing. */
4761 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
4762
4763 case PREFS_SET_OK:
4764 break;
4765
4766 case PREFS_SET_SYNTAX_ERR:
4767 report_warning("Syntax error in preference \"%s\" at line %d of\n%s %s",
4768 cur_var->str, pline, pf_path, hint);
4769 break;
4770
4771 case PREFS_SET_NO_SUCH_PREF:
4772 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"
, 4773, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4773 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4773, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4774 break;
4775
4776 case PREFS_SET_OBSOLETE:
4777 /*
4778 * If an attempt is made to save the
4779 * preferences, a popup warning will be
4780 * displayed stating that obsolete prefs
4781 * have been detected and the user will
4782 * be given the opportunity to save these
4783 * prefs under a different profile name.
4784 * The prefs in question need to be listed
4785 * in the console window so that the
4786 * user can make an informed choice.
4787 */
4788 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"
, 4789, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4789 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4789, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4790 break;
4791 }
4792 } else {
4793 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"
, 4793, __func__, "Incomplete preference at line %d: of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
4794 }
4795 }
4796 state = IN_VAR;
4797 got_val = false0;
4798 g_string_truncate(cur_var, 0)g_string_truncate_inline (cur_var, 0);
4799 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
4800 pline = fline;
4801 } else if (g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0) && cur_var->len > 0 && got_val) {
4802 state = PRE_VAL;
4803 } else if (got_c == '#') {
4804 state = IN_SKIP;
4805 } else {
4806 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"
, 4806, __func__, "Malformed preference at line %d of\n%s %s"
, fline, pf_path, hint); } } while (0)
;
4807 }
4808 break;
4809 case IN_VAR:
4810 if (got_c != ':') {
4811 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
4812 } else {
4813 /* This is a colon (':') */
4814 state = PRE_VAL;
4815 g_string_truncate(cur_val, 0)g_string_truncate_inline (cur_val, 0);
4816 /*
4817 * Set got_val to true to accommodate prefs such as
4818 * "gui.fileopen.dir" that do not require a value.
4819 */
4820 got_val = true1;
4821 }
4822 break;
4823 case PRE_VAL:
4824 if (!g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0)) {
4825 state = IN_VAL;
4826 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
4827 }
4828 break;
4829 case IN_VAL:
4830 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
4831 break;
4832 case IN_SKIP:
4833 break;
4834 }
4835 }
4836 if (cur_var->len > 0) {
4837 if (got_val) {
4838 /* Call the routine to set the preference; it will parse
4839 the value as appropriate.
4840
4841 Since we're reading a file, rather than processing
4842 explicit user input, for range preferences, silently
4843 lower values in excess of the range's maximum, rather
4844 than reporting errors and failing. */
4845 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
4846
4847 case PREFS_SET_OK:
4848 break;
4849
4850 case PREFS_SET_SYNTAX_ERR:
4851 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"
, 4852, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4852 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4852, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4853 break;
4854
4855 case PREFS_SET_NO_SUCH_PREF:
4856 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"
, 4857, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4857 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4857, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4858 break;
4859
4860 case PREFS_SET_OBSOLETE:
4861 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"
, 4862, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4862 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4862, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4863 break;
4864 }
4865 } else {
4866 ws_warning("Incomplete preference at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4867, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
4867 pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4867, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
4868 }
4869 }
4870
4871 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)))))
;
4872 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)))))
;
4873
4874 if (ferror(pf))
4875 return errno(*__errno_location ());
4876 else
4877 return 0;
4878}
4879
4880/*
4881 * If we were handed a preference starting with "uat:", try to turn it into
4882 * a valid uat entry.
4883 */
4884static bool_Bool
4885prefs_set_uat_pref(char *uat_entry, char **errmsg) {
4886 char *p, *colonp;
4887 uat_t *uat;
4888 bool_Bool ret;
4889
4890 colonp = strchr(uat_entry, ':');
4891 if (colonp == NULL((void*)0))
4892 return false0;
4893
4894 p = colonp;
4895 *p++ = '\0';
4896
4897 /*
4898 * Skip over any white space (there probably won't be any, but
4899 * as we allow it in the preferences file, we might as well
4900 * allow it here).
4901 */
4902 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
4903 p++;
4904 if (*p == '\0') {
4905 /*
4906 * Put the colon back, so if our caller uses, in an
4907 * error message, the string they passed us, the message
4908 * looks correct.
4909 */
4910 *colonp = ':';
4911 return false0;
4912 }
4913
4914 uat = uat_find(uat_entry);
4915 *colonp = ':';
4916 if (uat == NULL((void*)0)) {
4917 *errmsg = g_strdup("Unknown preference")g_strdup_inline ("Unknown preference");
4918 return false0;
4919 }
4920
4921 ret = uat_load_str(uat, p, errmsg);
4922 return ret;
4923}
4924
4925char *
4926prefs_sanitize_string(const char* str)
4927{
4928 char *sanitized;
4929 if (!prefs_regex) {
4930 prefs_regex = g_regex_new("\\s*\\R\\s*", (GRegexCompileFlags)G_REGEX_OPTIMIZE,
4931 (GRegexMatchFlags)G_REGEX_MATCH_BSR_ANYCRLF, NULL((void*)0));
4932 } else {
4933 g_regex_ref(prefs_regex);
4934 }
4935 sanitized = g_regex_replace(prefs_regex, str, -1, 0, " ", G_REGEX_MATCH_DEFAULT, NULL((void*)0));
4936 g_regex_unref(prefs_regex);
4937 return sanitized;
4938}
4939
4940/*
4941 * Given a string of the form "<pref name>:<pref value>", as might appear
4942 * as an argument to a "-o" option, parse it and set the preference in
4943 * question. Return an indication of whether it succeeded or failed
4944 * in some fashion.
4945 */
4946prefs_set_pref_e
4947prefs_set_pref(char *prefarg, char **errmsg)
4948{
4949 char *p, *colonp;
4950 prefs_set_pref_e ret;
4951
4952 *errmsg = NULL((void*)0);
4953
4954 colonp = strchr(prefarg, ':');
4955 if (colonp == NULL((void*)0)) {
4956 *errmsg = g_strdup("missing ':' (syntax is prefname:value).")g_strdup_inline ("missing ':' (syntax is prefname:value).");
4957 return PREFS_SET_SYNTAX_ERR;
4958 }
4959
4960 p = colonp;
4961 *p++ = '\0';
4962 /* XXX - Replace line terminators, or match and fail with errmsg, or ignore? */
4963
4964 /*
4965 * Skip over any white space (there probably won't be any, but
4966 * as we allow it in the preferences file, we might as well
4967 * allow it here).
4968 */
4969 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
4970 p++;
4971 /* The empty string is a legal value for range preferences (PREF_RANGE,
4972 * PREF_DECODE_AS_RANGE), and string-like preferences (PREF_STRING,
4973 * PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME), indeed often
4974 * not just useful but the default. A user might have a value saved
4975 * to their preference file but want to override it to default behavior.
4976 * Individual preference handlers of those types should be prepared to
4977 * deal with an empty string. For other types, it is up to set_pref() to
4978 * test for the empty string and set PREFS_SET_SYNTAX_ERROR there.
4979 */
4980 if (strcmp(prefarg, "uat")) {
4981 ret = set_pref(prefarg, p, NULL((void*)0), true1);
4982 } else {
4983 ret = prefs_set_uat_pref(p, errmsg) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR;
4984 }
4985 *colonp = ':'; /* put the colon back */
4986 return ret;
4987}
4988
4989unsigned prefs_get_uint_value(pref_t *pref, pref_source_t source)
4990{
4991 switch (source)
4992 {
4993 case pref_default:
4994 return pref->default_val.uint;
4995 case pref_stashed:
4996 return pref->stashed_val.uint;
4997 case pref_current:
4998 return *pref->varp.uint;
4999 default:
5000 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5000
, __func__, "assertion \"not reached\" failed")
;
5001 break;
5002 }
5003
5004 return 0;
5005}
5006
5007unsigned int prefs_set_int_value(pref_t* pref, int value, pref_source_t source)
5008{
5009 int changed = 0;
5010 switch (source)
5011 {
5012 case pref_default:
5013 if (pref->default_val.intval != value) {
5014 pref->default_val.intval = value;
5015 changed = prefs_get_effect_flags(pref);
5016 }
5017 break;
5018 case pref_stashed:
5019 if (pref->stashed_val.intval != value) {
5020 pref->stashed_val.intval = value;
5021 changed = prefs_get_effect_flags(pref);
5022 }
5023 break;
5024 case pref_current:
5025 if (*pref->varp.intp != value) {
5026 *pref->varp.intp = value;
5027 changed = prefs_get_effect_flags(pref);
5028 }
5029 break;
5030 default:
5031 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5031
, __func__, "assertion \"not reached\" failed")
;
5032 break;
5033 }
5034
5035 return changed;
5036}
5037
5038int prefs_get_int_value(pref_t* pref, pref_source_t source)
5039{
5040 switch (source)
5041 {
5042 case pref_default:
5043 return pref->default_val.intval;
5044 case pref_stashed:
5045 return pref->stashed_val.intval;
5046 case pref_current:
5047 return *pref->varp.intp;
5048 default:
5049 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5049
, __func__, "assertion \"not reached\" failed")
;
5050 break;
5051 }
5052
5053 return 0;
5054}
5055
5056unsigned int prefs_set_float_value(pref_t* pref, double value, pref_source_t source)
5057{
5058 int changed = 0;
5059 switch (source)
5060 {
5061 case pref_default:
5062 if (pref->default_val.floatval != value) {
5063 pref->default_val.floatval = value;
5064 changed = prefs_get_effect_flags(pref);
5065 }
5066 break;
5067 case pref_stashed:
5068 if (pref->stashed_val.floatval != value) {
5069 pref->stashed_val.floatval = value;
5070 changed = prefs_get_effect_flags(pref);
5071 }
5072 break;
5073 case pref_current:
5074 if (*pref->varp.floatp != value) {
5075 *pref->varp.floatp = value;
5076 changed = prefs_get_effect_flags(pref);
5077 }
5078 break;
5079 default:
5080 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5080
, __func__, "assertion \"not reached\" failed")
;
5081 break;
5082 }
5083
5084 return changed;
5085}
5086
5087double prefs_get_float_value(pref_t* pref, pref_source_t source)
5088{
5089 switch (source)
5090 {
5091 case pref_default:
5092 return pref->default_val.floatval;
5093 case pref_stashed:
5094 return pref->stashed_val.floatval;
5095 case pref_current:
5096 return *pref->varp.floatp;
5097 default:
5098 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5098
, __func__, "assertion \"not reached\" failed")
;
5099 break;
5100 }
5101
5102 return 0;
5103}
5104
5105
5106const char *prefs_get_password_value(pref_t *pref, pref_source_t source)
5107{
5108 return prefs_get_string_value(pref, source);
5109}
5110
5111
5112unsigned int prefs_set_uint_value(pref_t *pref, unsigned value, pref_source_t source)
5113{
5114 unsigned int changed = 0;
5115 switch (source)
5116 {
5117 case pref_default:
5118 if (pref->default_val.uint != value) {
5119 pref->default_val.uint = value;
5120 changed = prefs_get_effect_flags(pref);
5121 }
5122 break;
5123 case pref_stashed:
5124 if (pref->stashed_val.uint != value) {
5125 pref->stashed_val.uint = value;
5126 changed = prefs_get_effect_flags(pref);
5127 }
5128 break;
5129 case pref_current:
5130 if (*pref->varp.uint != value) {
5131 *pref->varp.uint = value;
5132 changed = prefs_get_effect_flags(pref);
5133 }
5134 break;
5135 default:
5136 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5136
, __func__, "assertion \"not reached\" failed")
;
5137 break;
5138 }
5139
5140 return changed;
5141}
5142
5143/*
5144 * For use by UI code that sets preferences.
5145 */
5146unsigned int
5147prefs_set_password_value(pref_t *pref, const char* value, pref_source_t source)
5148{
5149 return prefs_set_string_value(pref, value, source);
5150}
5151
5152
5153unsigned prefs_get_uint_base(pref_t *pref)
5154{
5155 return pref->info.base;
5156}
5157
5158/*
5159 * Returns true if the given device is hidden
5160 */
5161bool_Bool
5162prefs_is_capture_device_hidden(const char *name)
5163{
5164 char *tok, *devices;
5165 size_t len;
5166
5167 if (prefs.capture_devices_hide && name) {
5168 devices = g_strdup (prefs.capture_devices_hide)g_strdup_inline (prefs.capture_devices_hide);
5169 len = strlen (name);
5170 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5171 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5172 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5173 return true1;
5174 }
5175 }
5176 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5177 }
5178
5179 return false0;
5180}
5181
5182/*
5183 * Returns true if the given column is visible (not hidden)
5184 */
5185static bool_Bool
5186prefs_is_column_visible(const char *cols_hidden, int col)
5187{
5188 char *tok, *cols, *p;
5189 int cidx;
5190
5191 /*
5192 * Do we have a list of hidden columns?
5193 */
5194 if (cols_hidden) {
5195 /*
5196 * Yes - check the column against each of the ones in the
5197 * list.
5198 */
5199 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5200 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5201 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5202
5203 cidx = (int)strtol(tok, &p, 10);
5204 if (p == tok || *p != '\0') {
5205 continue;
5206 }
5207 if (cidx != col) {
5208 continue;
5209 }
5210 /*
5211 * OK, they match, so it's one of the hidden fields,
5212 * hence not visible.
5213 */
5214 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5215 return false0;
5216 }
5217 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5218 }
5219
5220 /*
5221 * No - either there are no hidden columns or this isn't one
5222 * of them - so it is visible.
5223 */
5224 return true1;
5225}
5226
5227/*
5228 * Returns true if the given column is visible (not hidden)
5229 */
5230static bool_Bool
5231prefs_is_column_fmt_visible(const char *cols_hidden, fmt_data *cfmt)
5232{
5233 char *tok, *cols;
5234 fmt_data cfmt_hidden;
5235
5236 /*
5237 * Do we have a list of hidden columns?
5238 */
5239 if (cols_hidden) {
5240 /*
5241 * Yes - check the column against each of the ones in the
5242 * list.
5243 */
5244 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5245 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5246 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5247
5248 /*
5249 * Parse this column format.
5250 */
5251 if (!parse_column_format(&cfmt_hidden, tok)) {
5252 /*
5253 * It's not valid; ignore it.
5254 */
5255 continue;
5256 }
5257
5258 /*
5259 * Does it match the column?
5260 */
5261 if (cfmt->fmt != cfmt_hidden.fmt) {
5262 /* No. */
5263 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
)
;
5264 cfmt_hidden.custom_fields = NULL((void*)0);
5265 continue;
5266 }
5267 if (cfmt->fmt == COL_CUSTOM) {
5268 /*
5269 * A custom column has to have the same custom field
5270 * and occurrence.
5271 */
5272 if (cfmt_hidden.custom_fields && cfmt->custom_fields) {
5273 if (strcmp(cfmt->custom_fields,
5274 cfmt_hidden.custom_fields) != 0) {
5275 /* Different fields. */
5276 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
)
;
5277 cfmt_hidden.custom_fields = NULL((void*)0);
5278 continue;
5279 }
5280 if (cfmt->custom_occurrence != cfmt_hidden.custom_occurrence) {
5281 /* Different occurrences settings. */
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 }
5287 }
5288
5289 /*
5290 * OK, they match, so it's one of the hidden fields,
5291 * hence not visible.
5292 */
5293 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
)
;
5294 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5295 return false0;
5296 }
5297 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5298 }
5299
5300 /*
5301 * No - either there are no hidden columns or this isn't one
5302 * of them - so it is visible.
5303 */
5304 return true1;
5305}
5306
5307/*
5308 * Returns true if the given device should capture in monitor mode by default
5309 */
5310bool_Bool
5311prefs_capture_device_monitor_mode(const char *name)
5312{
5313 char *tok, *devices;
5314 size_t len;
5315
5316 if (prefs.capture_devices_monitor_mode && name) {
5317 devices = g_strdup (prefs.capture_devices_monitor_mode)g_strdup_inline (prefs.capture_devices_monitor_mode);
5318 len = strlen (name);
5319 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5320 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5321 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5322 return true1;
5323 }
5324 }
5325 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5326 }
5327
5328 return false0;
5329}
5330
5331bool_Bool
5332prefs_has_layout_pane_content (layout_pane_content_e layout_pane_content)
5333{
5334 return ((prefs.gui_layout_content_1 == layout_pane_content) ||
5335 (prefs.gui_layout_content_2 == layout_pane_content) ||
5336 (prefs.gui_layout_content_3 == layout_pane_content));
5337}
5338
5339char
5340string_to_name_resolve(const char *string, e_addr_resolve *name_resolve)
5341{
5342 char c;
5343
5344 memset(name_resolve, 0, sizeof(e_addr_resolve));
5345 while ((c = *string++) != '\0') {
5346 switch (c) {
5347 case 'g':
5348 name_resolve->maxmind_geoip = true1;
5349 break;
5350 case 'm':
5351 name_resolve->mac_name = true1;
5352 break;
5353 case 'n':
5354 name_resolve->network_name = true1;
5355 break;
5356 case 'N':
5357 name_resolve->use_external_net_name_resolver = true1;
5358 break;
5359 case 't':
5360 name_resolve->transport_name = true1;
5361 break;
5362 case 'd':
5363 name_resolve->dns_pkt_addr_resolution = true1;
5364 break;
5365 case 's':
5366 name_resolve->handshake_sni_addr_resolution = true1;
5367 break;
5368 case 'v':
5369 name_resolve->vlan_name = true1;
5370 break;
5371 default:
5372 /*
5373 * Unrecognized letter.
5374 */
5375 return c;
5376 }
5377 }
5378 return '\0';
5379}
5380
5381static bool_Bool
5382deprecated_heur_dissector_pref(char *pref_name, const char *value)
5383{
5384 struct heur_pref_name
5385 {
5386 const char* pref_name;
5387 const char* short_name;
5388 bool_Bool more_dissectors; /* For multiple dissectors controlled by the same preference */
5389 };
5390
5391 static const struct heur_pref_name heur_prefs[] = {
5392 {"acn.heuristic_acn", "acn_udp", 0},
5393 {"bfcp.enable", "bfcp_tcp", 1},
5394 {"bfcp.enable", "bfcp_udp", 0},
5395 {"bt-dht.enable", "bittorrent_dht_udp", 0},
5396 {"bt-utp.enable", "bt_utp_udp", 0},
5397 {"cattp.enable", "cattp_udp", 0},
5398 {"cfp.enable", "fp_eth", 0},
5399 {"dicom.heuristic", "dicom_tcp", 0},
5400 {"dnp3.heuristics", "dnp3_tcp", 1},
5401 {"dnp3.heuristics", "dnp3_udp", 0},
5402 {"dvb-s2_modeadapt.enable", "dvb_s2_udp", 0},
5403 {"esl.enable", "esl_eth", 0},
5404 {"fp.udp_heur", "fp_udp", 0},
5405 {"gvsp.enable_heuristic", "gvsp_udp", 0},
5406 {"hdcp2.enable", "hdcp2_tcp", 0},
5407 {"hislip.enable_heuristic", "hislip_tcp", 0},
5408 {"infiniband.dissect_eoib", "mellanox_eoib", 1},
5409 {"infiniband.identify_payload", "eth_over_ib", 0},
5410 {"jxta.udp.heuristic", "jxta_udp", 0},
5411 {"jxta.tcp.heuristic", "jxta_tcp", 0},
5412 {"jxta.sctp.heuristic", "jxta_sctp", 0},
5413 {"mac-lte.heuristic_mac_lte_over_udp", "mac_lte_udp", 0},
5414 {"mbim.bulk_heuristic", "mbim_usb_bulk", 0},
5415 {"norm.heuristic_norm", "rmt_norm_udp", 0},
5416 {"openflow.heuristic", "openflow_tcp", 0},
5417 {"pdcp-lte.heuristic_pdcp_lte_over_udp", "pdcp_lte_udp", 0},
5418 {"rlc.heuristic_rlc_over_udp", "rlc_udp", 0},
5419 {"rlc-lte.heuristic_rlc_lte_over_udp", "rlc_lte_udp", 0},
5420 {"rtcp.heuristic_rtcp", "rtcp_udp", 1},
5421 {"rtcp.heuristic_rtcp", "rtcp_stun", 0},
5422 {"rtp.heuristic_rtp", "rtp_udp", 1},
5423 {"rtp.heuristic_rtp", "rtp_stun", 0},
5424 {"teredo.heuristic_teredo", "teredo_udp", 0},
5425 {"vssmonitoring.use_heuristics", "vssmonitoring_eth", 0},
5426 {"xml.heuristic", "xml_http", 1},
5427 {"xml.heuristic", "xml_sip", 1},
5428 {"xml.heuristic", "xml_media", 0},
5429 {"xml.heuristic_tcp", "xml_tcp", 0},
5430 {"xml.heuristic_udp", "xml_udp", 0},
5431 };
5432
5433 unsigned int i;
5434 heur_dtbl_entry_t* heuristic;
5435
5436
5437 for (i = 0; i < array_length(heur_prefs)(sizeof (heur_prefs) / sizeof (heur_prefs)[0]); i++)
5438 {
5439 if (strcmp(pref_name, heur_prefs[i].pref_name) == 0)
5440 {
5441 heuristic = find_heur_dissector_by_unique_short_name(heur_prefs[i].short_name);
5442 if (heuristic != NULL((void*)0)) {
5443 heuristic->enabled = ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0);
5444 }
5445
5446 if (!heur_prefs[i].more_dissectors)
5447 return true1;
5448 }
5449 }
5450
5451
5452 return false0;
5453}
5454
5455static bool_Bool
5456deprecated_enable_dissector_pref(char *pref_name, const char *value)
5457{
5458 struct dissector_pref_name
5459 {
5460 const char* pref_name;
5461 const char* short_name;
5462 };
5463
5464 struct dissector_pref_name dissector_prefs[] = {
5465 {"transum.tsumenabled", "TRANSUM"},
5466 {"snort.enable_snort_dissector", "Snort"},
5467 {"prp.enable", "PRP"},
5468 };
5469
5470 unsigned int i;
5471 int proto_id;
5472
5473 for (i = 0; i < array_length(dissector_prefs)(sizeof (dissector_prefs) / sizeof (dissector_prefs)[0]); i++)
5474 {
5475 if (strcmp(pref_name, dissector_prefs[i].pref_name) == 0)
5476 {
5477 proto_id = proto_get_id_by_short_name(dissector_prefs[i].short_name);
5478 if (proto_id >= 0)
5479 proto_set_decoding(proto_id, ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0));
5480 return true1;
5481 }
5482 }
5483
5484 return false0;
5485}
5486
5487static bool_Bool
5488deprecated_port_pref(char *pref_name, const char *value)
5489{
5490 struct port_pref_name
5491 {
5492 const char* pref_name;
5493 const char* module_name; /* the protocol filter name */
5494 const char* table_name;
5495 unsigned base;
5496 };
5497
5498 struct obsolete_pref_name
5499 {
5500 const char* pref_name;
5501 };
5502
5503 /* For now this is only supporting TCP/UDP port and RTP payload
5504 * types dissector preferences, which are assumed to be decimal */
5505 /* module_name is the filter name of the destination port preference,
5506 * which is usually the same as the original module but not
5507 * necessarily (e.g., if the preference is for what is now a PINO.)
5508 * XXX: Most of these were changed pre-2.0. Can we end support
5509 * for migrating legacy preferences at some point?
5510 */
5511 static const struct port_pref_name port_prefs[] = {
5512 /* TCP */
5513 {"cmp.tcp_alternate_port", "cmp", "tcp.port", 10},
5514 {"h248.tcp_port", "h248", "tcp.port", 10},
5515 {"cops.tcp.cops_port", "cops", "tcp.port", 10},
5516 {"dhcpfo.tcp_port", "dhcpfo", "tcp.port", 10},
5517 {"enttec.tcp_port", "enttec", "tcp.port", 10},
5518 {"forces.tcp_alternate_port", "forces", "tcp.port", 10},
5519 {"ged125.tcp_port", "ged125", "tcp.port", 10},
5520 {"hpfeeds.dissector_port", "hpfeeds", "tcp.port", 10},
5521 {"lsc.port", "lsc", "tcp.port", 10},
5522 {"megaco.tcp.txt_port", "megaco", "tcp.port", 10},
5523 {"netsync.tcp_port", "netsync", "tcp.port", 10},
5524 {"osi.tpkt_port", "osi", "tcp.port", 10},
5525 {"rsync.tcp_port", "rsync", "tcp.port", 10},
5526 {"sametime.tcp_port", "sametime", "tcp.port", 10},
5527 {"sigcomp.tcp.port2", "sigcomp", "tcp.port", 10},
5528 {"synphasor.tcp_port", "synphasor", "tcp.port", 10},
5529 {"tipc.alternate_port", "tipc", "tcp.port", 10},
5530 {"vnc.alternate_port", "vnc", "tcp.port", 10},
5531 {"scop.port", "scop", "tcp.port", 10},
5532 {"scop.port_secure", "scop", "tcp.port", 10},
5533 {"tpncp.tcp.trunkpack_port", "tpncp", "tcp.port", 10},
5534 /* UDP */
5535 {"h248.udp_port", "h248", "udp.port", 10},
5536 {"actrace.udp_port", "actrace", "udp.port", 10},
5537 {"brp.port", "brp", "udp.port", 10},
5538 {"bvlc.additional_udp_port", "bvlc", "udp.port", 10},
5539 {"capwap.udp.port.control", "capwap", "udp.port", 10},
5540 {"capwap.udp.port.data", "capwap", "udp.port", 10},
5541 {"coap.udp_port", "coap", "udp.port", 10},
5542 {"enttec.udp_port", "enttec", "udp.port", 10},
5543 {"forces.udp_alternate_port", "forces", "udp.port", 10},
5544 {"ldss.udp_port", "ldss", "udp.port", 10},
5545 {"lmp.udp_port", "lmp", "udp.port", 10},
5546 {"ltp.port", "ltp", "udp.port", 10},
5547 {"lwres.udp.lwres_port", "lwres", "udp.port", 10},
5548 {"megaco.udp.txt_port", "megaco", "udp.port", 10},
5549 {"pfcp.port_pfcp", "pfcp", "udp.port", 10},
5550 {"pgm.udp.encap_ucast_port", "pgm", "udp.port", 10},
5551 {"pgm.udp.encap_mcast_port", "pgm", "udp.port", 10},
5552 {"quic.udp.quic.port", "quic", "udp.port", 10},
5553 {"quic.udp.quics.port", "quic", "udp.port", 10},
5554 {"radius.alternate_port", "radius", "udp.port", 10},
5555 {"rdt.default_udp_port", "rdt", "udp.port", 10},
5556 {"alc.default.udp_port", "alc", "udp.port", 10},
5557 {"sigcomp.udp.port2", "sigcomp", "udp.port", 10},
5558 {"synphasor.udp_port", "synphasor", "udp.port", 10},
5559 {"tdmop.udpport", "tdmop", "udp.port", 10},
5560 {"uaudp.port1", "uaudp", "udp.port", 10},
5561 {"uaudp.port2", "uaudp", "udp.port", 10},
5562 {"uaudp.port3", "uaudp", "udp.port", 10},
5563 {"uaudp.port4", "uaudp", "udp.port", 10},
5564 {"uhd.dissector_port", "uhd", "udp.port", 10},
5565 {"vrt.dissector_port", "vrt", "udp.port", 10},
5566 {"tpncp.udp.trunkpack_port", "tpncp", "udp.port", 10},
5567 /* SCTP */
5568 {"hnbap.port", "hnbap", "sctp.port", 10},
5569 {"m2pa.port", "m2pa", "sctp.port", 10},
5570 {"megaco.sctp.txt_port", "megaco", "sctp.port", 10},
5571 {"rua.port", "rua", "sctp.port", 10},
5572 /* SCTP PPI */
5573 {"lapd.sctp_payload_protocol_identifier", "lapd", "sctp.ppi", 10},
5574 /* SCCP SSN */
5575 {"ranap.sccp_ssn", "ranap", "sccp.ssn", 10},
5576 };
5577
5578 static const struct port_pref_name port_range_prefs[] = {
5579 /* TCP */
5580 {"couchbase.tcp.ports", "couchbase", "tcp.port", 10},
5581 {"gsm_ipa.tcp_ports", "gsm_ipa", "tcp.port", 10},
5582 {"kafka.tcp.ports", "kafka", "tcp.port", 10},
5583 {"kt.tcp.ports", "kt", "tcp.port", 10},
5584 {"memcache.tcp.ports", "memcache", "tcp.port", 10},
5585 {"mrcpv2.tcp.port_range", "mrcpv2", "tcp.port", 10},
5586 {"pdu_transport.ports.tcp", "pdu_transport", "tcp.port", 10},
5587 {"rtsp.tcp.port_range", "rtsp", "tcp.port", 10},
5588 {"sip.tcp.ports", "sip", "tcp.port", 10},
5589 {"someip.ports.tcp", "someip", "tcp.port", 10},
5590 {"tds.tcp_ports", "tds", "tcp.port", 10},
5591 {"tpkt.tcp.ports", "tpkt", "tcp.port", 10},
5592 {"uma.tcp.ports", "uma", "tcp.port", 10},
5593 /* UDP */
5594 {"aruba_erm.udp.ports", "arubs_erm", "udp.port", 10},
5595 {"diameter.udp.ports", "diameter", "udp.port", 10},
5596 {"dmp.udp_ports", "dmp", "udp.port", 10},
5597 {"dns.udp.ports", "dns", "udp.port", 10},
5598 {"gsm_ipa.udp_ports", "gsm_ipa", "udp.port", 10},
5599 {"hcrt.dissector_udp_port", "hcrt", "udp.port", 10},
5600 {"memcache.udp.ports", "memcache", "udp.port", 10},
5601 {"nb_rtpmux.udp_ports", "nb_rtpmux", "udp.port", 10},
5602 {"gprs-ns.udp.ports", "gprs-ns", "udp.port", 10},
5603 {"p_mul.udp_ports", "p_mul", "udp.port", 10},
5604 {"pdu_transport.ports.udp", "pdu_transport", "udp.port", 10},
5605 {"radius.ports", "radius", "udp.port", 10},
5606 {"sflow.ports", "sflow", "udp.port", 10},
5607 {"someip.ports.udp", "someip", "udp.port", 10},
5608 {"sscop.udp.ports", "sscop", "udp.port", 10},
5609 {"tftp.udp_ports", "tftp", "udp.port", 10},
5610 {"tipc.udp.ports", "tipc", "udp.port", 10},
5611 /* RTP */
5612 {"amr.dynamic.payload.type", "amr", "rtp.pt", 10},
5613 {"amr.wb.dynamic.payload.type", "amr_wb", "rtp.pt", 10},
5614 {"dvb-s2_modeadapt.dynamic.payload.type", "dvb-s2_modeadapt", "rtp.pt", 10},
5615 {"evs.dynamic.payload.type", "evs", "rtp.pt", 10},
5616 {"h263p.dynamic.payload.type", "h263p", "rtp.pt", 10},
5617 {"h264.dynamic.payload.type", "h264", "rtp.pt", 10},
5618 {"h265.dynamic.payload.type", "h265", "rtp.pt", 10},
5619 {"ismacryp.dynamic.payload.type", "ismacryp", "rtp.pt", 10},
5620 {"iuup.dynamic.payload.type", "iuup", "rtp.pt", 10},
5621 {"lapd.rtp_payload_type", "lapd", "rtp.pt", 10},
5622 {"mp4ves.dynamic.payload.type", "mp4ves", "rtp.pt", 10},
5623 {"mtp2.rtp_payload_type", "mtp2", "rtp.pt", 10},
5624 {"opus.dynamic.payload.type", "opus", "rtp.pt", 10},
5625 {"rtp.rfc2198_payload_type", "rtp_rfc2198", "rtp.pt", 10},
5626 {"rtpevent.event_payload_type_value", "rtpevent", "rtp.pt", 10},
5627 {"rtpevent.cisco_nse_payload_type_value", "rtpevent", "rtp.pt", 10},
5628 {"rtpmidi.midi_payload_type_value", "rtpmidi", "rtp.pt", 10},
5629 {"vp8.dynamic.payload.type", "vp8", "rtp.pt", 10},
5630 /* SCTP */
5631 {"diameter.sctp.ports", "diameter", "sctp.port", 10},
5632 {"sgsap.sctp_ports", "sgsap", "sctp.port", 10},
5633 /* SCCP SSN */
5634 {"pcap.ssn", "pcap", "sccp.ssn", 10},
5635 };
5636
5637 /* These are subdissectors of TPKT/OSITP that used to have a
5638 TCP port preference even though they were never
5639 directly on TCP. Convert them to use Decode As
5640 with the TPKT dissector handle */
5641 static const struct port_pref_name tpkt_subdissector_port_prefs[] = {
5642 {"dap.tcp.port", "dap", "tcp.port", 10},
5643 {"disp.tcp.port", "disp", "tcp.port", 10},
5644 {"dop.tcp.port", "dop", "tcp.port", 10},
5645 {"dsp.tcp.port", "dsp", "tcp.port", 10},
5646 {"p1.tcp.port", "p1", "tcp.port", 10},
5647 {"p7.tcp.port", "p7", "tcp.port", 10},
5648 {"rdp.tcp.port", "rdp", "tcp.port", 10},
5649 };
5650
5651 /* These are obsolete preferences from the dissectors' view,
5652 (typically because of a switch from a single value to a
5653 range value) but the name of the preference conflicts
5654 with the generated preference name from the dissector table.
5655 Don't allow the obsolete preference through to be handled */
5656 static const struct obsolete_pref_name obsolete_prefs[] = {
5657 {"diameter.tcp.port"},
5658 {"kafka.tcp.port"},
5659 {"mrcpv2.tcp.port"},
5660 {"rtsp.tcp.port"},
5661 {"sip.tcp.port"},
5662 {"t38.tcp.port"},
5663 };
5664
5665 unsigned int i;
5666 unsigned uval;
5667 dissector_table_t sub_dissectors;
5668 dissector_handle_t handle, tpkt_handle;
5669 module_t *module;
5670 pref_t *pref;
5671
5672 static bool_Bool sanity_checked;
5673 if (!sanity_checked) {
5674 sanity_checked = true1;
5675 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5676 module = prefs_find_module(port_prefs[i].module_name);
5677 if (!module) {
5678 // We might not be Wireshark, and therefore might not have deprecated port prefs.
5679 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"
, 5679, __func__, "Deprecated ports pref check - module '%s' not found"
, port_prefs[i].module_name); } } while (0)
;
5680 continue;
5681 }
5682 pref = prefs_find_preference(module, port_prefs[i].table_name);
5683 if (!pref) {
5684 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"
, 5684, __func__, "Deprecated ports pref '%s.%s' not found", module
->name, port_prefs[i].table_name); } } while (0)
;
5685 continue;
5686 }
5687 if (pref->type != PREF_DECODE_AS_RANGE) {
5688 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"
, 5688, __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)
;
5689 }
5690 }
5691 }
5692
5693 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5694 if (strcmp(pref_name, port_prefs[i].pref_name) == 0) {
5695 if (!ws_basestrtou32(value, NULL((void*)0), &uval, port_prefs[i].base))
5696 return false0; /* number was bad */
5697
5698 module = prefs_find_module(port_prefs[i].module_name);
5699 pref = prefs_find_preference(module, port_prefs[i].table_name);
5700 if (pref != NULL((void*)0)) {
5701 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5702 if (pref->type == PREF_DECODE_AS_RANGE) {
5703 // The legacy preference was a port number, but the new
5704 // preference is a port range. Add to existing range.
5705 if (uval) {
5706 prefs_range_add_value(pref, uval);
5707 }
5708 }
5709 }
5710
5711 /* If the value is zero, it wouldn't add to the Decode As tables */
5712 if (uval != 0)
5713 {
5714 sub_dissectors = find_dissector_table(port_prefs[i].table_name);
5715 if (sub_dissectors != NULL((void*)0)) {
5716 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5717 if (handle != NULL((void*)0)) {
5718 dissector_change_uint(port_prefs[i].table_name, uval, handle);
5719 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));
5720 }
5721 }
5722 }
5723
5724 return true1;
5725 }
5726 }
5727
5728 for (i = 0; i < array_length(port_range_prefs)(sizeof (port_range_prefs) / sizeof (port_range_prefs)[0]); i++)
5729 {
5730 if (strcmp(pref_name, port_range_prefs[i].pref_name) == 0)
5731 {
5732 uint32_t range_i, range_j;
5733
5734 sub_dissectors = find_dissector_table(port_range_prefs[i].table_name);
5735 if (sub_dissectors != NULL((void*)0)) {
5736 switch (dissector_table_get_type(sub_dissectors)) {
5737 case FT_UINT8:
5738 case FT_UINT16:
5739 case FT_UINT24:
5740 case FT_UINT32:
5741 break;
5742
5743 default:
5744 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", 5744
, __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))
;
5745 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5745
, __func__, "assertion \"not reached\" failed")
;
5746 }
5747
5748 module = prefs_find_module(port_range_prefs[i].module_name);
5749 pref = prefs_find_preference(module, port_range_prefs[i].table_name);
5750 if (pref != NULL((void*)0))
5751 {
5752 if (!prefs_set_range_value_work(pref, value, true1, &module->prefs_changed_flags))
5753 {
5754 return false0; /* number was bad */
5755 }
5756
5757 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5758 if (handle != NULL((void*)0)) {
5759
5760 for (range_i = 0; range_i < (*pref->varp.range)->nranges; range_i++) {
5761 for (range_j = (*pref->varp.range)->ranges[range_i].low; range_j < (*pref->varp.range)->ranges[range_i].high; range_j++) {
5762 dissector_change_uint(port_range_prefs[i].table_name, range_j, handle);
5763 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));
5764 }
5765
5766 dissector_change_uint(port_range_prefs[i].table_name, (*pref->varp.range)->ranges[range_i].high, handle);
5767 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));
5768 }
5769 }
5770 }
5771 }
5772
5773 return true1;
5774 }
5775 }
5776
5777 for (i = 0; i < array_length(tpkt_subdissector_port_prefs)(sizeof (tpkt_subdissector_port_prefs) / sizeof (tpkt_subdissector_port_prefs
)[0])
; i++)
5778 {
5779 if (strcmp(pref_name, tpkt_subdissector_port_prefs[i].pref_name) == 0)
5780 {
5781 /* XXX - give an error if it doesn't fit in a unsigned? */
5782 if (!ws_basestrtou32(value, NULL((void*)0), &uval, tpkt_subdissector_port_prefs[i].base))
5783 return false0; /* number was bad */
5784
5785 /* If the value is 0 or 102 (default TPKT port), don't add to the Decode As tables */
5786 if ((uval != 0) && (uval != 102))
5787 {
5788 tpkt_handle = find_dissector("tpkt");
5789 if (tpkt_handle != NULL((void*)0)) {
5790 dissector_change_uint(tpkt_subdissector_port_prefs[i].table_name, uval, tpkt_handle);
5791 }
5792 }
5793
5794 return true1;
5795 }
5796 }
5797
5798 for (i = 0; i < array_length(obsolete_prefs)(sizeof (obsolete_prefs) / sizeof (obsolete_prefs)[0]); i++)
5799 {
5800 if (strcmp(pref_name, obsolete_prefs[i].pref_name) == 0)
5801 {
5802 /* Just ignore the preference */
5803 return true1;
5804 }
5805 }
5806 return false0;
5807}
5808
5809static prefs_set_pref_e
5810set_pref(char *pref_name, const char *value, void *private_data,
5811 bool_Bool return_range_errors)
5812{
5813 unsigned cval;
5814 unsigned uval;
5815 bool_Bool bval;
5816 int enum_val, ival;
5817 double fval;
5818 char *dotp, *last_dotp;
5819 module_t *module, *containing_module, *target_module;
5820 pref_t *pref;
5821 bool_Bool converted_pref = false0;
5822
5823 target_module = (module_t*)private_data;
5824
5825 if (deprecated_heur_dissector_pref(pref_name, value)) {
5826 /* Handled within deprecated_heur_dissector_pref() if found */
5827 } else if (deprecated_enable_dissector_pref(pref_name, value)) {
5828 /* Handled within deprecated_enable_dissector_pref() if found */
5829 } else if (deprecated_port_pref(pref_name, value)) {
5830 /* Handled within deprecated_port_pref() if found */
5831 } else if (strcmp(pref_name, "console.log.level") == 0) {
5832 /* Handled on the command line within ws_log_parse_args() */
5833 return PREFS_SET_OK;
5834 } else {
5835 /* To which module does this preference belong? */
5836 module = NULL((void*)0);
5837 last_dotp = pref_name;
5838 while (!module) {
5839 dotp = strchr(last_dotp, '.');
5840 if (dotp == NULL((void*)0)) {
5841 /* Either there's no such module, or no module was specified.
5842 In either case, that means there's no such preference. */
5843 return PREFS_SET_NO_SUCH_PREF;
5844 }
5845 *dotp = '\0'; /* separate module and preference name */
5846 module = prefs_find_module(pref_name);
5847
5848 /*
5849 * XXX - "Diameter" rather than "diameter" was used in earlier
5850 * versions of Wireshark; if we didn't find the module, and its name
5851 * was "Diameter", look for "diameter" instead.
5852 *
5853 * In addition, the BEEP protocol used to be the BXXP protocol,
5854 * so if we didn't find the module, and its name was "bxxp",
5855 * look for "beep" instead.
5856 *
5857 * Also, the preferences for GTP v0 and v1 were combined under
5858 * a single "gtp" heading, and the preferences for SMPP were
5859 * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
5860 * However, SMPP now has its own preferences, so we just map
5861 * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
5862 *
5863 * We also renamed "dcp" to "dccp", "x.25" to "x25", "x411" to "p1"
5864 * and "nsip" to "gprs_ns".
5865 *
5866 * The SynOptics Network Management Protocol (SONMP) is now known by
5867 * its modern name, the Nortel Discovery Protocol (NDP).
5868 */
5869 if (module == NULL((void*)0)) {
5870 /*
5871 * See if there's a backwards-compatibility name
5872 * that maps to this module.
5873 */
5874 module = prefs_find_module_alias(pref_name);
5875 if (module == NULL((void*)0)) {
5876 /*
5877 * There's no alias for the module; see if the
5878 * module name matches any protocol aliases.
5879 */
5880 header_field_info *hfinfo = proto_registrar_get_byalias(pref_name);
5881 if (hfinfo) {
5882 module = (module_t *) wmem_tree_lookup_string(prefs_modules, hfinfo->abbrev, WMEM_TREE_STRING_NOCASE0x00000001);
5883 }
5884 }
5885 if (module) {
5886 converted_pref = true1;
5887 }
5888 }
5889 *dotp = '.'; /* put the preference string back */
5890 dotp++; /* skip past separator to preference name */
5891 last_dotp = dotp;
5892 }
5893
5894 /* The pref is located in the module or a submodule.
5895 * Assume module, then search for a submodule holding the pref. */
5896 containing_module = module;
5897 pref = prefs_find_preference_with_submodule(module, dotp, &containing_module);
5898
5899 if (pref == NULL((void*)0)) {
5900 /* "gui" prefix was added to column preferences for better organization
5901 * within the preferences file
5902 */
5903 if (module == gui_column_module) {
5904 /* While this has a subtree, there is no apply callback, so no
5905 * need to use prefs_find_preference_with_submodule to update
5906 * containing_module. It would not be useful. */
5907 pref = prefs_find_preference(module, pref_name);
5908 }
5909 else if (strcmp(module->name, "tcp") == 0) {
5910 /* Handle old names for TCP preferences. */
5911 if (strcmp(dotp, "dissect_experimental_options_with_magic") == 0)
5912 pref = prefs_find_preference(module, "dissect_experimental_options_rfc6994");
5913 } else if (strcmp(module->name, "extcap") == 0) {
5914 /* Handle the old "sshdump.remotesudo" preference; map it to the new
5915 "sshdump.remotepriv" preference, and map the boolean values to the
5916 appropriate strings of the new preference. */
5917 if (strcmp(dotp, "sshdump.remotesudo") == 0) {
5918 pref = prefs_find_preference(module, "sshdump.remotepriv");
5919 if (g_ascii_strcasecmp(value, "true") == 0)
5920 value = "sudo";
5921 else
5922 value = "none";
5923 }
5924 }
5925 if (pref) {
5926 converted_pref = true1;
5927 }
5928 }
5929 if (pref == NULL((void*)0) ) {
5930 if (strcmp(module->name, "extcap") == 0 && g_list_length(module->prefs) <= 1) {
5931 /*
5932 * Assume that we've skipped extcap preference registration
5933 * and that only extcap.gui_save_on_start is loaded.
5934 */
5935 return PREFS_SET_OK;
5936 }
5937 return PREFS_SET_NO_SUCH_PREF; /* no such preference */
5938 }
5939
5940 if (target_module && target_module != containing_module) {
5941 /* Ignore */
5942 return PREFS_SET_OK;
5943 }
5944
5945 if (pref->obsolete)
5946 return PREFS_SET_OBSOLETE; /* no such preference any more */
5947
5948 if (converted_pref) {
5949 ws_warning("Preference \"%s\" has been converted to \"%s.%s\"\n"do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5951, __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)
5950 "Save your preferences to make this change permanent.",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5951, __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)
5951 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"
, 5951, __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)
;
5952 }
5953
5954 switch (pref->type) {
5955
5956 case PREF_UINT:
5957 if (!ws_basestrtou32(value, NULL((void*)0), &uval, pref->info.base))
5958 return PREFS_SET_SYNTAX_ERR; /* number was bad */
5959 if (*pref->varp.uint != uval) {
5960 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5961 *pref->varp.uint = uval;
5962 }
5963 break;
5964
5965 case PREF_INT:
5966 if (!ws_strtoi32(value, NULL((void*)0), &ival))
5967 return PREFS_SET_SYNTAX_ERR; /* number was bad */
5968 if (*pref->varp.intp != ival) {
5969 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5970 *pref->varp.intp = ival;
5971 }
5972 break;
5973
5974 case PREF_FLOAT:
5975 fval = g_ascii_strtod(value, NULL((void*)0));
5976 if (errno(*__errno_location ()) == ERANGE34)
5977 return PREFS_SET_SYNTAX_ERR; /* number was bad */
5978
5979 if (*pref->varp.floatp != fval) {
5980 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5981 *pref->varp.floatp = fval;
5982 }
5983 break;
5984
5985 case PREF_BOOL:
5986 /* XXX - give an error if it's neither "true" nor "false"? */
5987 if (g_ascii_strcasecmp(value, "true") == 0)
5988 bval = true1;
5989 else
5990 bval = false0;
5991 if (*pref->varp.boolp != bval) {
5992 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5993 *pref->varp.boolp = bval;
5994 }
5995 break;
5996
5997 case PREF_ENUM:
5998 /* XXX - give an error if it doesn't match? */
5999 enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
6000 *pref->varp.enump);
6001 if (*pref->varp.enump != enum_val) {
6002 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6003 *pref->varp.enump = enum_val;
6004 }
6005 break;
6006
6007 case PREF_STRING:
6008 case PREF_SAVE_FILENAME:
6009 case PREF_OPEN_FILENAME:
6010 case PREF_DIRNAME:
6011 case PREF_DISSECTOR:
6012 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
6013 break;
6014
6015 case PREF_PASSWORD:
6016 /* Read value is every time empty */
6017 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, "", pref_current);
6018 break;
6019
6020 case PREF_RANGE:
6021 {
6022 if (!prefs_set_range_value_work(pref, value, return_range_errors,
6023 &containing_module->prefs_changed_flags))
6024 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6025 break;
6026 }
6027 case PREF_DECODE_AS_RANGE:
6028 {
6029 /* This is for backwards compatibility in case any of the preferences
6030 that shared the "Decode As" preference name and used to be PREF_RANGE
6031 are now applied directly to the Decode As functionality */
6032 range_t *newrange;
6033 dissector_table_t sub_dissectors;
6034 dissector_handle_t handle;
6035 uint32_t i, j;
6036
6037 if (range_convert_str_work(pref->scope, &newrange, value, pref->info.max_value,
6038 return_range_errors) != CVT_NO_ERROR) {
6039 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6040 }
6041
6042 if (!ranges_are_equal(*pref->varp.range, newrange)) {
6043 wmem_free(pref->scope, *pref->varp.range);
6044 *pref->varp.range = newrange;
6045 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6046
6047 const char* table_name = prefs_get_dissector_table(pref);
6048 sub_dissectors = find_dissector_table(table_name);
6049 if (sub_dissectors != NULL((void*)0)) {
6050 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
6051 if (handle != NULL((void*)0)) {
6052 /* Delete all of the old values from the dissector table */
6053 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
6054 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
6055 dissector_delete_uint(table_name, j, handle);
6056 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));
6057 }
6058
6059 dissector_delete_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
6060 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));
6061 }
6062
6063 /* Add new values to the dissector table */
6064 for (i = 0; i < newrange->nranges; i++) {
6065 for (j = newrange->ranges[i].low; j < newrange->ranges[i].high; j++) {
6066 dissector_change_uint(table_name, j, handle);
6067 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));
6068 }
6069
6070 dissector_change_uint(table_name, newrange->ranges[i].high, handle);
6071 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));
6072 }
6073
6074 /* XXX - Do we save the decode_as_entries file here? */
6075 }
6076 }
6077 } else {
6078 wmem_free(pref->scope, newrange);
6079 }
6080 break;
6081 }
6082
6083 case PREF_COLOR:
6084 {
6085 if (!ws_hexstrtou32(value, NULL((void*)0), &cval))
6086 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6087 if ((pref->varp.colorp->red != RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
) ||
6088 (pref->varp.colorp->green != GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255))) ||
6089 (pref->varp.colorp->blue != BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255)))) {
6090 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6091 pref->varp.colorp->red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
6092 pref->varp.colorp->green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
6093 pref->varp.colorp->blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
6094 }
6095 break;
6096 }
6097
6098 case PREF_CUSTOM:
6099 return pref->custom_cbs.set_cb(pref, value, &containing_module->prefs_changed_flags);
6100
6101 case PREF_STATIC_TEXT:
6102 case PREF_UAT:
6103 break;
6104
6105 case PREF_PROTO_TCP_SNDAMB_ENUM:
6106 {
6107 /* There's no point in setting the TCP sequence override
6108 * value from the command line, because the pref is different
6109 * for each frame and reset to the default (0) for each new
6110 * file.
6111 */
6112 break;
6113 }
6114 }
6115 }
6116
6117 return PREFS_SET_OK;
6118}
6119
6120typedef struct {
6121 FILE *pf;
6122 bool_Bool is_gui_module;
6123 bool_Bool is_extcap_module;
6124} write_gui_pref_arg_t;
6125
6126const char *
6127prefs_pref_type_name(pref_t *pref)
6128{
6129 const char *type_name = "[Unknown]";
6130
6131 if (!pref) {
6132 return type_name; /* ...or maybe assert? */
6133 }
6134
6135 if (pref->obsolete) {
6136 type_name = "Obsolete";
6137 } else {
6138 switch (pref->type) {
6139
6140 case PREF_UINT:
6141 switch (pref->info.base) {
6142
6143 case 10:
6144 type_name = "Decimal";
6145 break;
6146
6147 case 8:
6148 type_name = "Octal";
6149 break;
6150
6151 case 16:
6152 type_name = "Hexadecimal";
6153 break;
6154 }
6155 break;
6156
6157 case PREF_INT:
6158 type_name = "Integer";
6159 break;
6160
6161 case PREF_FLOAT:
6162 type_name = "Float";
6163 break;
6164
6165 case PREF_BOOL:
6166 type_name = "Boolean";
6167 break;
6168
6169 case PREF_ENUM:
6170 case PREF_PROTO_TCP_SNDAMB_ENUM:
6171 type_name = "Choice";
6172 break;
6173
6174 case PREF_STRING:
6175 type_name = "String";
6176 break;
6177
6178 case PREF_SAVE_FILENAME:
6179 case PREF_OPEN_FILENAME:
6180 type_name = "Filename";
6181 break;
6182
6183 case PREF_DIRNAME:
6184 type_name = "Directory";
6185 break;
6186
6187 case PREF_RANGE:
6188 type_name = "Range";
6189 break;
6190
6191 case PREF_COLOR:
6192 type_name = "Color";
6193 break;
6194
6195 case PREF_CUSTOM:
6196 if (pref->custom_cbs.type_name_cb)
6197 return pref->custom_cbs.type_name_cb();
6198 type_name = "Custom";
6199 break;
6200
6201 case PREF_DECODE_AS_RANGE:
6202 type_name = "Range (for Decode As)";
6203 break;
6204
6205 case PREF_STATIC_TEXT:
6206 type_name = "Static text";
6207 break;
6208
6209 case PREF_UAT:
6210 type_name = "UAT";
6211 break;
6212
6213 case PREF_PASSWORD:
6214 type_name = "Password";
6215 break;
6216
6217 case PREF_DISSECTOR:
6218 type_name = "Dissector";
6219 break;
6220 }
6221 }
6222
6223 return type_name;
6224}
6225
6226unsigned int
6227prefs_get_effect_flags(pref_t *pref)
6228{
6229 if (pref == NULL((void*)0))
6230 return 0;
6231
6232 return pref->effect_flags;
6233}
6234
6235void
6236prefs_set_effect_flags(pref_t *pref, unsigned int flags)
6237{
6238 if (pref != NULL((void*)0)) {
6239 if (flags == 0) {
6240 ws_error("Setting \"%s\" preference effect flags to 0", pref->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6240
, __func__, "Setting \"%s\" preference effect flags to 0", pref
->name)
;
6241 }
6242 pref->effect_flags = flags;
6243 }
6244}
6245
6246void
6247prefs_set_effect_flags_by_name(module_t * module, const char *pref, unsigned int flags)
6248{
6249 prefs_set_effect_flags(prefs_find_preference(module, pref), flags);
6250}
6251
6252unsigned int
6253prefs_get_module_effect_flags(module_t * module)
6254{
6255 if (module == NULL((void*)0))
6256 return 0;
6257
6258 return module->effect_flags;
6259}
6260
6261void
6262prefs_set_module_effect_flags(module_t * module, unsigned int flags)
6263{
6264 if (module != NULL((void*)0)) {
6265 if (flags == 0) {
6266 ws_error("Setting module \"%s\" preference effect flags to 0", module->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6266
, __func__, "Setting module \"%s\" preference effect flags to 0"
, module->name)
;
6267 }
6268 module->effect_flags = flags;
6269 }
6270}
6271
6272char *
6273prefs_pref_type_description(pref_t *pref)
6274{
6275 const char *type_desc = "An unknown preference type";
6276
6277 if (!pref) {
6278 return ws_strdup_printf("%s.", type_desc)wmem_strdup_printf(((void*)0), "%s.", type_desc); /* ...or maybe assert? */
6279 }
6280
6281 if (pref->obsolete) {
6282 type_desc = "An obsolete preference";
6283 } else {
6284 switch (pref->type) {
6285
6286 case PREF_UINT:
6287 switch (pref->info.base) {
6288
6289 case 10:
6290 type_desc = "A decimal number";
6291 break;
6292
6293 case 8:
6294 type_desc = "An octal number";
6295 break;
6296
6297 case 16:
6298 type_desc = "A hexadecimal number";
6299 break;
6300 }
6301 break;
6302
6303 case PREF_INT:
6304 type_desc = "A decimal number";
6305 break;
6306
6307 case PREF_FLOAT:
6308 type_desc = "A floating point number";
6309 break;
6310
6311 case PREF_BOOL:
6312 type_desc = "true or false (case-insensitive)";
6313 break;
6314
6315 case PREF_ENUM:
6316 case PREF_PROTO_TCP_SNDAMB_ENUM:
6317 {
6318 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6319 GString *enum_str = g_string_new("One of: ");
6320 GString *desc_str = g_string_new("\nEquivalently, one of: ");
6321 bool_Bool distinct = false0;
6322 while (enum_valp->name != NULL((void*)0)) {
6323 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))
;
6324 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))
;
6325 if (g_strcmp0(enum_valp->name, enum_valp->description) != 0) {
6326 distinct = true1;
6327 }
6328 enum_valp++;
6329 if (enum_valp->name != NULL((void*)0)) {
6330 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))
;
6331 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))
;
6332 }
6333 }
6334 if (distinct) {
6335 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))
;
6336 }
6337 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)))))
;
6338 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))
;
6339 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))))
;
6340 }
6341
6342 case PREF_STRING:
6343 type_desc = "A string";
6344 break;
6345
6346 case PREF_SAVE_FILENAME:
6347 case PREF_OPEN_FILENAME:
6348 type_desc = "A path to a file";
6349 break;
6350
6351 case PREF_DIRNAME:
6352 type_desc = "A path to a directory";
6353 break;
6354
6355 case PREF_RANGE:
6356 {
6357 type_desc = "A string denoting an positive integer range (e.g., \"1-20,30-40\")";
6358 break;
6359 }
6360
6361 case PREF_COLOR:
6362 {
6363 type_desc = "A six-digit hexadecimal RGB color triplet (e.g. fce94f)";
6364 break;
6365 }
6366
6367 case PREF_CUSTOM:
6368 if (pref->custom_cbs.type_description_cb)
6369 return pref->custom_cbs.type_description_cb();
6370 type_desc = "A custom value";
6371 break;
6372
6373 case PREF_DECODE_AS_RANGE:
6374 type_desc = "A string denoting an positive integer range for Decode As";
6375 break;
6376
6377 case PREF_STATIC_TEXT:
6378 type_desc = "[Static text]";
6379 break;
6380
6381 case PREF_UAT:
6382 type_desc = "Configuration data stored in its own file";
6383 break;
6384
6385 case PREF_PASSWORD:
6386 type_desc = "Password (never stored on disk)";
6387 break;
6388
6389 case PREF_DISSECTOR:
6390 type_desc = "A dissector name";
6391 break;
6392
6393 default:
6394 break;
6395 }
6396 }
6397
6398 return g_strdup(type_desc)g_strdup_inline (type_desc);
6399}
6400
6401bool_Bool
6402prefs_pref_is_default(pref_t *pref)
6403{
6404 if (!pref) return false0;
6405
6406 if (pref->obsolete) {
6407 return false0;
6408 }
6409
6410 switch (pref->type) {
6411
6412 case PREF_UINT:
6413 if (pref->default_val.uint == *pref->varp.uint)
6414 return true1;
6415 break;
6416
6417 case PREF_INT:
6418 if (pref->default_val.intval == *pref->varp.intp)
6419 return true1;
6420 break;
6421
6422 case PREF_FLOAT:
6423 if (pref->default_val.floatval == *pref->varp.floatp)
6424 return true1;
6425 break;
6426
6427 case PREF_BOOL:
6428 if (pref->default_val.boolval == *pref->varp.boolp)
6429 return true1;
6430 break;
6431
6432 case PREF_ENUM:
6433 case PREF_PROTO_TCP_SNDAMB_ENUM:
6434 if (pref->default_val.enumval == *pref->varp.enump)
6435 return true1;
6436 break;
6437
6438 case PREF_STRING:
6439 case PREF_SAVE_FILENAME:
6440 case PREF_OPEN_FILENAME:
6441 case PREF_DIRNAME:
6442 case PREF_PASSWORD:
6443 case PREF_DISSECTOR:
6444 if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
6445 return true1;
6446 break;
6447
6448 case PREF_DECODE_AS_RANGE:
6449 case PREF_RANGE:
6450 {
6451 if ((ranges_are_equal(pref->default_val.range, *pref->varp.range)))
6452 return true1;
6453 break;
6454 }
6455
6456 case PREF_COLOR:
6457 {
6458 if ((pref->default_val.color.red == pref->varp.colorp->red) &&
6459 (pref->default_val.color.green == pref->varp.colorp->green) &&
6460 (pref->default_val.color.blue == pref->varp.colorp->blue))
6461 return true1;
6462 break;
6463 }
6464
6465 case PREF_CUSTOM:
6466 return pref->custom_cbs.is_default_cb(pref);
6467
6468 case PREF_STATIC_TEXT:
6469 case PREF_UAT:
6470 return false0;
6471 /* ws_assert_not_reached(); */
6472 break;
6473 }
6474
6475 return false0;
6476}
6477
6478char *
6479prefs_pref_to_str(pref_t *pref, pref_source_t source)
6480{
6481 const char *pref_text = "[Unknown]";
6482 void *valp; /* pointer to preference value */
6483 color_t *pref_color;
6484 char *tmp_value, *ret_value;
6485
6486 if (!pref) {
6487 return g_strdup(pref_text)g_strdup_inline (pref_text);
6488 }
6489
6490 switch (source) {
6491 case pref_default:
6492 valp = &pref->default_val;
6493 /* valp = &boolval, &enumval, etc. are implied by union property */
6494 pref_color = &pref->default_val.color;
6495 break;
6496 case pref_stashed:
6497 valp = &pref->stashed_val;
6498 /* valp = &boolval, &enumval, etc. are implied by union property */
6499 pref_color = &pref->stashed_val.color;
6500 break;
6501 case pref_current:
6502 valp = pref->varp.uint;
6503 /* valp = boolval, enumval, etc. are implied by union property */
6504 pref_color = pref->varp.colorp;
6505 break;
6506 default:
6507 return g_strdup(pref_text)g_strdup_inline (pref_text);
6508 }
6509
6510 if (pref->obsolete) {
6511 pref_text = "[Obsolete]";
6512 } else {
6513 switch (pref->type) {
6514
6515 case PREF_UINT:
6516 {
6517 unsigned pref_uint = *(unsigned *) valp;
6518 switch (pref->info.base) {
6519
6520 case 10:
6521 return ws_strdup_printf("%u", pref_uint)wmem_strdup_printf(((void*)0), "%u", pref_uint);
6522
6523 case 8:
6524 return ws_strdup_printf("%#o", pref_uint)wmem_strdup_printf(((void*)0), "%#o", pref_uint);
6525
6526 case 16:
6527 return ws_strdup_printf("%#x", pref_uint)wmem_strdup_printf(((void*)0), "%#x", pref_uint);
6528 }
6529 break;
6530 }
6531 case PREF_INT:
6532 return ws_strdup_printf("%d", *(int*)valp)wmem_strdup_printf(((void*)0), "%d", *(int*)valp);
6533
6534 case PREF_FLOAT:
6535 return ws_strdup_printf("%.*f", pref->info.base, *(double*)valp)wmem_strdup_printf(((void*)0), "%.*f", pref->info.base, *(
double*)valp)
;
6536
6537 case PREF_BOOL:
6538 return g_strdup((*(bool *) valp) ? "TRUE" : "FALSE")g_strdup_inline ((*(_Bool *) valp) ? "TRUE" : "FALSE");
6539
6540 case PREF_ENUM:
6541 case PREF_PROTO_TCP_SNDAMB_ENUM:
6542 {
6543 int pref_enumval = *(int *) valp;
6544 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6545 /*
6546 * TODO - We write the "description" value, because the "name" values
6547 * weren't validated to be command line friendly until 5.0, and a few
6548 * of them had to be changed. This allows older versions of Wireshark
6549 * to read preferences that they supported, as we supported either
6550 * the short name or the description when reading the preference files
6551 * or an "-o" option. Once 5.0 is the oldest supported version, switch
6552 * to writing the name below.
6553 */
6554 while (enum_valp->name != NULL((void*)0)) {
6555 if (enum_valp->value == pref_enumval)
6556 return g_strdup(enum_valp->description)g_strdup_inline (enum_valp->description);
6557 enum_valp++;
6558 }
6559 break;
6560 }
6561
6562 case PREF_STRING:
6563 case PREF_SAVE_FILENAME:
6564 case PREF_OPEN_FILENAME:
6565 case PREF_DIRNAME:
6566 case PREF_PASSWORD:
6567 case PREF_DISSECTOR:
6568 return prefs_sanitize_string(*(const char **) valp);
6569
6570 case PREF_DECODE_AS_RANGE:
6571 case PREF_RANGE:
6572 /* Convert wmem to g_alloc memory */
6573 tmp_value = range_convert_range(NULL((void*)0), *(range_t **) valp);
6574 ret_value = g_strdup(tmp_value)g_strdup_inline (tmp_value);
6575 wmem_free(NULL((void*)0), tmp_value);
6576 return ret_value;
6577
6578 case PREF_COLOR:
6579 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))
6580 (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))
6581 (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))
6582 (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))
;
6583
6584 case PREF_CUSTOM:
6585 if (pref->custom_cbs.to_str_cb)
6586 return pref->custom_cbs.to_str_cb(pref, source == pref_default ? true1 : false0);
6587 pref_text = "[Custom]";
6588 break;
6589
6590 case PREF_STATIC_TEXT:
6591 pref_text = "[Static text]";
6592 break;
6593
6594 case PREF_UAT:
6595 {
6596 uat_t *uat = pref->varp.uat;
6597 if (uat && uat->filename)
6598 return ws_strdup_printf("[Managed in the file \"%s\"]", uat->filename)wmem_strdup_printf(((void*)0), "[Managed in the file \"%s\"]"
, uat->filename)
;
6599 else
6600 pref_text = "[Managed in an unknown file]";
6601 break;
6602 }
6603
6604 default:
6605 break;
6606 }
6607 }
6608
6609 return g_strdup(pref_text)g_strdup_inline (pref_text);
6610}
6611
6612/*
6613 * Write out a single dissector preference.
6614 */
6615void
6616pref_write_individual(void *data, void *user_data)
6617{
6618 pref_t *pref = (pref_t *)data;
6619 write_pref_arg_t *arg = (write_pref_arg_t *)user_data;
6620 char **desc_lines;
6621 int i;
6622
6623 if (!pref || pref->obsolete) {
6624 /*
6625 * This preference is no longer supported; it's not a
6626 * real preference, so we don't write it out (i.e., we
6627 * treat it as if it weren't found in the list of
6628 * preferences, and we weren't called in the first place).
6629 */
6630 return;
6631 }
6632
6633 switch (pref->type) {
6634
6635 case PREF_STATIC_TEXT:
6636 case PREF_UAT:
6637 /* Nothing to do; don't bother printing the description */
6638 return;
6639 case PREF_DECODE_AS_RANGE:
6640 /* Data is saved through Decode As mechanism and not part of preferences file */
6641 return;
6642 case PREF_PROTO_TCP_SNDAMB_ENUM:
6643 /* Not written to the preference file because the override is only
6644 * for the lifetime of the capture file and there is no single
6645 * value to write.
6646 */
6647 return;
6648 default:
6649 break;
6650 }
6651
6652 if (pref->type != PREF_CUSTOM || pref->custom_cbs.type_name_cb() != NULL((void*)0)) {
6653 /*
6654 * The prefix will either be the module name or the parent
6655 * name if it's a subtree
6656 */
6657 const char *name_prefix = (arg->module->name != NULL((void*)0)) ? arg->module->name : arg->module->parent->name;
6658 char *type_desc, *pref_text;
6659 const char * def_prefix = prefs_pref_is_default(pref) ? "#" : "";
6660
6661 if (pref->type == PREF_CUSTOM)
6662 fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
6663 fprintf(arg->pf, "\n");
6664 if (pref->description &&
6665 (g_ascii_strncasecmp(pref->description,"", 2) != 0)) {
6666 if (pref->type != PREF_CUSTOM) {
6667 /* We get duplicate lines otherwise. */
6668
6669 desc_lines = g_strsplit(pref->description, "\n", 0);
6670 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6671 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6672 }
6673 g_strfreev(desc_lines);
6674 }
6675 } else {
6676 fprintf(arg->pf, "# No description\n");
6677 }
6678
6679 type_desc = prefs_pref_type_description(pref);
6680 desc_lines = g_strsplit(type_desc, "\n", 0);
6681 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6682 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6683 }
6684 g_strfreev(desc_lines);
6685 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)
;
6686
6687 pref_text = prefs_pref_to_str(pref, pref_current);
6688 fprintf(arg->pf, "%s%s.%s: ", def_prefix, name_prefix, pref->name);
6689 if (pref->type != PREF_PASSWORD)
6690 {
6691 desc_lines = g_strsplit(pref_text, "\n", 0);
6692 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6693 fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
6694 }
6695 if (i == 0)
6696 fprintf(arg->pf, "\n");
6697 g_strfreev(desc_lines);
6698 } else {
6699 /* We never store password value */
6700 fprintf(arg->pf, "\n");
6701 }
6702 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)
;
6703 }
6704
6705}
6706
6707static void
6708count_non_uat_pref(void *data, void *user_data)
6709{
6710 pref_t *pref = (pref_t *)data;
6711 int *arg = (int *)user_data;
6712
6713 switch (pref->type)
6714 {
6715 case PREF_UAT:
6716 case PREF_DECODE_AS_RANGE:
6717 case PREF_PROTO_TCP_SNDAMB_ENUM:
6718 //These types are not written in preference file
6719 break;
6720 default:
6721 (*arg)++;
6722 break;
6723 }
6724}
6725
6726int
6727prefs_num_non_uat(module_t *module)
6728{
6729 int num = 0;
6730
6731 g_list_foreach(module->prefs, count_non_uat_pref, &num);
6732
6733 return num;
6734}
6735
6736/*
6737 * Write out all preferences for a module.
6738 */
6739static unsigned
6740write_module_prefs(module_t *module, void *user_data)
6741{
6742 write_gui_pref_arg_t *gui_pref_arg = (write_gui_pref_arg_t*)user_data;
6743 write_pref_arg_t arg;
6744
6745 /* The GUI module needs to be explicitly called out so it
6746 can be written out of order */
6747 if ((module == gui_module) && (gui_pref_arg->is_gui_module != true1))
6748 return 0;
6749
6750 if ((module == extcap_module) && (gui_pref_arg->is_extcap_module != true1))
6751 return 0;
6752
6753 /* Write a header for the main modules and GUI sub-modules */
6754 if (((module->parent == NULL((void*)0)) || (module->parent == gui_module)) &&
6755 ((prefs_module_has_submodules(module)) ||
6756 (prefs_num_non_uat(module) > 0) ||
6757 (module->name == NULL((void*)0)))) {
6758 if ((module->name == NULL((void*)0)) && (module->parent != NULL((void*)0))) {
6759 fprintf(gui_pref_arg->pf, "\n####### %s: %s ########\n", module->parent->title, module->title);
6760 } else {
6761 fprintf(gui_pref_arg->pf, "\n####### %s ########\n", module->title);
6762 }
6763 }
6764
6765 arg.module = module;
6766 arg.pf = gui_pref_arg->pf;
6767 g_list_foreach(arg.module->prefs, pref_write_individual, &arg);
6768
6769 if (prefs_module_has_submodules(module))
6770 return prefs_modules_foreach_submodules(module->submodules, write_module_prefs, user_data);
6771
6772 return 0;
6773}
6774
6775#ifdef _WIN32
6776static void
6777write_registry(void)
6778{
6779 HKEY hTestKey;
6780 DWORD data;
6781 DWORD data_size;
6782 DWORD ret;
6783
6784 ret = RegCreateKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, NULL((void*)0),
6785 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL((void*)0),
6786 &hTestKey, NULL((void*)0));
6787 if (ret != ERROR_SUCCESS) {
6788 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"
, 6788, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
6789 return;
6790 }
6791
6792 data = ws_log_console_open;
6793 data_size = sizeof(DWORD);
6794 ret = RegSetValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", 0, REG_DWORD, (const BYTE *)&data, data_size);
6795 if (ret == ERROR_SUCCESS) {
6796 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"
, 6796, __func__, "Wrote ""ConsoleOpen"" to Windows registry: 0x%lu"
, data); } } while (0)
;
6797 }
6798 else {
6799 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"
, 6799, __func__, "Error writing registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
6800 }
6801
6802 RegCloseKey(hTestKey);
6803}
6804#endif
6805
6806int
6807prefs_write_module(const char *module, bool_Bool from_profile, const char* app_env_var_prefix)
6808{
6809 write_gui_pref_arg_t write_pref_info;
6810
6811 module_t *target_module = prefs_find_module(module);
6812 if (!target_module) {
6813 return ENOENT2;
6814 }
6815
6816 char *pf_name = g_strdup_printf("%s.cfg", module);
6817 char *pf_path = get_persconffile_path(pf_name, from_profile, app_env_var_prefix);
6818 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)
;
6819
6820 FILE *pf;
6821 if ((pf = ws_fopenfopen(pf_path, "w")) == NULL((void*)0)) {
6822 int err = errno(*__errno_location ());
6823 if (err != EISDIR21) {
6824 ws_warning("Unable to save %s preferences \"%s\": %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6825, __func__, "Unable to save %s preferences \"%s\": %s",
module, pf_path, g_strerror(err)); } } while (0)
6825 module, pf_path, g_strerror(err))do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6825, __func__, "Unable to save %s preferences \"%s\": %s",
module, pf_path, g_strerror(err)); } } while (0)
;
6826 }
6827 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)
;
6828 return err;
6829 }
6830 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)
;
6831
6832 fprintf(pf, "# %s configuration file for Wireshark " VERSION"5.1.0" ".\n"
6833 "#\n"
6834 "# This file is regenerated each time preferences are saved within\n"
6835 "# Wireshark. Making manual changes should be safe, however.\n"
6836 "# Preferences that have been commented out have not been\n"
6837 "# changed from their default value.\n", target_module->title);
6838
6839 write_pref_info.pf = pf;
6840 write_pref_info.is_gui_module = (target_module == gui_module);
6841 write_pref_info.is_extcap_module = (target_module == extcap_module);
6842
6843 write_module_prefs(target_module, &write_pref_info);
6844
6845 fclose(pf);
6846
6847 return 0;
6848}
6849
6850/* Write out "prefs" to the user's preferences file, and return 0.
6851
6852 If the preferences file path is NULL, write to stdout.
6853
6854 If we got an error, stuff a pointer to the path of the preferences
6855 file into "*pf_path_return", and return the errno.
6856
6857 Note that we don't write extcap.cfg here; that's done by
6858 extcap_write_preferences().
6859*/
6860 int
6861 write_prefs(const char *app_env_var_prefix, char **pf_path_return)
6862{
6863 char *pf_path;
6864 FILE *pf;
6865 write_gui_pref_arg_t write_gui_pref_info;
6866
6867#ifdef _WIN32
6868 write_registry();
6869#endif
6870
6871 /* To do:
6872 * - Split output lines longer than MAX_VAL_LEN
6873 * - Create a function for the preference directory check/creation
6874 * so that duplication can be avoided with filter.c
6875 */
6876
6877 if (pf_path_return != NULL((void*)0)) {
6878 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
6879 if ((pf = ws_fopenfopen(pf_path, "w")) == NULL((void*)0)) {
6880 *pf_path_return = pf_path;
6881 return errno(*__errno_location ());
6882 }
6883 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)
;
6884 } else {
6885 pf = stdoutstdout;
6886 }
6887
6888 /*
6889 * If the preferences file is being written, be sure to write UAT files
6890 * first that were migrated from the preferences file.
6891 */
6892 if (pf_path_return != NULL((void*)0)) {
6893 if (prefs.filter_expressions_old) {
6894 char *err = NULL((void*)0);
6895 prefs.filter_expressions_old = false0;
6896 if (!uat_save(uat_get_table_by_name("Display expressions"), app_env_var_prefix, &err)) {
6897 ws_warning("Unable to save Display expressions: %s", err)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6897, __func__, "Unable to save Display expressions: %s", err
); } } while (0)
;
6898 g_free(err)(__builtin_object_size ((err), 0) != ((size_t) - 1)) ? g_free_sized
(err, __builtin_object_size ((err), 0)) : (g_free) (err)
;
6899 }
6900 }
6901 }
6902
6903 fputs("# Configuration file for Wireshark " VERSION"5.1.0" ".\n"
6904 "#\n"
6905 "# This file is regenerated each time preferences are saved within\n"
6906 "# Wireshark. Making manual changes should be safe, however.\n"
6907 "# Preferences that have been commented out have not been\n"
6908 "# changed from their default value.\n", pf);
6909
6910 /*
6911 * For "backwards compatibility" the GUI module is written first as it's
6912 * at the top of the file. This is followed by all modules that can't
6913 * fit into the preferences read/write API. Finally the remaining modules
6914 * are written in alphabetical order (including of course the protocol preferences)
6915 */
6916 write_gui_pref_info.pf = pf;
6917 write_gui_pref_info.is_gui_module = true1;
6918 write_gui_pref_info.is_extcap_module = false0;
6919
6920 write_module_prefs(gui_module, &write_gui_pref_info);
6921
6922 write_gui_pref_info.is_gui_module = false0;
6923 if (pf_path_return == NULL((void*)0)) {
6924 /* If we're writing the prefs to stdout, write the extcap prefs. */
6925 write_gui_pref_info.is_extcap_module = true1;
6926 }
6927 prefs_module_list_foreach(prefs_top_level_modules, write_module_prefs, &write_gui_pref_info, true1);
6928
6929 fclose(pf);
6930
6931 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
6932 an error indication, or maybe write to a new preferences file and
6933 rename that file on top of the old one only if there are not I/O
6934 errors. */
6935 return 0;
6936}
6937
6938/** The col_list is only partly managed by the custom preference API
6939 * because its data is shared between multiple preferences, so
6940 * it's freed here
6941 */
6942static void
6943free_col_info(GList *list)
6944{
6945 fmt_data *cfmt;
6946 GList *list_head = list;
6947
6948 while (list != NULL((void*)0)) {
6949 cfmt = (fmt_data *)list->data;
6950
6951 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)
;
6952 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
)
;
6953 g_free(cfmt)(__builtin_object_size ((cfmt), 0) != ((size_t) - 1)) ? g_free_sized
(cfmt, __builtin_object_size ((cfmt), 0)) : (g_free) (cfmt)
;
6954 list = g_list_next(list)((list) ? (((GList *)(list))->next) : ((void*)0));
6955 }
6956 g_list_free(list_head);
6957}
6958
6959/*
6960 * Editor modelines
6961 *
6962 * Local Variables:
6963 * c-basic-offset: 4
6964 * tab-width: 8
6965 * indent-tabs-mode: nil
6966 * End:
6967 *
6968 * ex: set shiftwidth=4 tabstop=8 expandtab:
6969 * :indentSize=4:tabSize=8:noTabs=true:
6970 */