Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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