Bug Summary

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