Bug Summary

File:builds/wireshark/wireshark/epan/prefs.c
Warning:line 4941, 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-15-100323-3641-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, "enable_aggregation_view", "Enable aggregation view",
3958 "Enable Aggregation View for real-time capturing", &prefs.enable_aggregation);
3959
3960 prefs_register_bool_preference(capture_module, "no_interface_load", "Don't load interfaces on startup",
3961 "Don't automatically load capture interfaces on startup", &prefs.capture_no_interface_load);
3962
3963 prefs_register_bool_preference(capture_module, "no_extcap", "Disable external capture interfaces",
3964 "Disable external capture modules (extcap)", &prefs.capture_no_extcap);
3965
3966 prefs_register_obsolete_preference(capture_module, "auto_scroll");
3967
3968 prefs_register_bool_preference(capture_module, "show_info", "Show capture information dialog while capturing",
3969 "Show capture information dialog while capturing?", &prefs.capture_show_info);
3970
3971 prefs_register_obsolete_preference(capture_module, "syntax_check_filter");
3972
3973 custom_cbs.free_cb = capture_column_free_cb;
3974 custom_cbs.reset_cb = capture_column_reset_cb;
3975 custom_cbs.set_cb = capture_column_set_cb;
3976 custom_cbs.type_name_cb = capture_column_type_name_cb;
3977 custom_cbs.type_description_cb = capture_column_type_description_cb;
3978 custom_cbs.is_default_cb = capture_column_is_default_cb;
3979 custom_cbs.to_str_cb = capture_column_to_str_cb;
3980 prefs_register_list_custom_preference(capture_module, "columns", "Capture options dialog column list",
3981 "List of columns to be displayed", &custom_cbs, capture_column_init_cb, &prefs.capture_columns);
3982 aggregation_field_register_uat(capture_module);
3983
3984 /* Name Resolution */
3985 nameres_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "nameres", "Name Resolution",
3986 "Name Resolution", "ChCustPreferencesSection.html#ChCustPrefsNameSection", addr_resolve_pref_apply, true1);
3987 addr_resolve_pref_init(nameres_module);
3988 oid_pref_init(nameres_module);
3989 maxmind_db_pref_init(nameres_module);
3990
3991 /* Printing
3992 * None of these have any effect; we keep them as obsolete preferences
3993 * in order to avoid errors when reading older preference files.
3994 */
3995 printing = prefs_register_module(prefs_top_level_modules, prefs_modules, "print", "Printing",
3996 "Printing", NULL((void*)0), NULL((void*)0), false0);
3997 prefs_register_obsolete_preference(printing, "format");
3998 prefs_register_obsolete_preference(printing, "command");
3999 prefs_register_obsolete_preference(printing, "file");
4000
4001 /* Codecs */
4002 codecs_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "codecs", "Codecs",
4003 "Codecs", NULL((void*)0), NULL((void*)0), true1);
4004
4005 /* Statistics */
4006 stats_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "statistics", "Statistics",
4007 "Statistics", "ChCustPreferencesSection.html#_statistics", &stats_callback, true1);
4008
4009 prefs_register_uint_preference(stats_module, "update_interval",
4010 "Tap update interval in ms",
4011 "Determines time between tap updates",
4012 10,
4013 &prefs.tap_update_interval);
4014
4015 prefs_register_uint_preference(stats_module, "flow_graph_max_export_items",
4016 "Maximum Flow Graph items to export as image",
4017 "The maximum number of Flow Graph items (frames) "
4018 "to include when exporting the graph as an image. "
4019 "Note that some formats (e.g., JPEG) have inherent "
4020 "pixel limits and image viewers might be unable to "
4021 "handle very large images.",
4022 10,
4023 &prefs.flow_graph_max_export_items);
4024
4025 prefs_register_bool_preference(stats_module, "st_enable_burstinfo",
4026 "Enable the calculation of burst information",
4027 "If enabled burst rates will be calculated for statistics that use the stats_tree system. "
4028 "Burst rates are calculated over a much shorter time interval than the rate column.",
4029 &prefs.st_enable_burstinfo);
4030
4031 prefs_register_bool_preference(stats_module, "st_burst_showcount",
4032 "Show burst count for item rather than rate",
4033 "If selected the stats_tree statistics nodes will show the count of events "
4034 "within the burst window instead of a burst rate. Burst rate is calculated "
4035 "as number of events within burst window divided by the burst windown length.",
4036 &prefs.st_burst_showcount);
4037
4038 prefs_register_uint_preference(stats_module, "st_burst_resolution",
4039 "Burst rate resolution (ms)",
4040 "Sets the duration of the time interval into which events are grouped when calculating "
4041 "the burst rate. Higher resolution (smaller number) increases processing overhead.",
4042 10,&prefs.st_burst_resolution);
4043
4044 prefs_register_uint_preference(stats_module, "st_burst_windowlen",
4045 "Burst rate window size (ms)",
4046 "Sets the duration of the sliding window during which the burst rate is "
4047 "measured. Longer window relative to burst rate resolution increases "
4048 "processing overhead. Will be truncated to a multiple of burst resolution.",
4049 10,&prefs.st_burst_windowlen);
4050
4051 prefs_register_enum_preference(stats_module, "st_sort_defcolflag",
4052 "Default sort column for stats_tree stats",
4053 "Sets the default column by which stats based on the stats_tree "
4054 "system is sorted.",
4055 &prefs.st_sort_defcolflag, st_sort_col_vals, false0);
4056
4057 prefs_register_bool_preference(stats_module, "st_sort_defdescending",
4058 "Default stats_tree sort order is descending",
4059 "When selected, statistics based on the stats_tree system will by default "
4060 "be sorted in descending order.",
4061 &prefs.st_sort_defdescending);
4062
4063 prefs_register_bool_preference(stats_module, "st_sort_casesensitve",
4064 "Case sensitive sort of stats_tree item names",
4065 "When selected, the item/node names of statistics based on the stats_tree "
4066 "system will be sorted taking case into account. Else the case of the name "
4067 "will be ignored.",
4068 &prefs.st_sort_casesensitve);
4069
4070 prefs_register_bool_preference(stats_module, "st_sort_rng_nameonly",
4071 "Always sort 'range' nodes by name",
4072 "When selected, the stats_tree nodes representing a range of values "
4073 "(0-49, 50-100, etc.) will always be sorted by name (the range of the "
4074 "node). Else range nodes are sorted by the same column as the rest of "
4075 " the tree.",
4076 &prefs.st_sort_rng_nameonly);
4077
4078 prefs_register_bool_preference(stats_module, "st_sort_rng_fixorder",
4079 "Always sort 'range' nodes in ascending order",
4080 "When selected, the stats_tree nodes representing a range of values "
4081 "(0-49, 50-100, etc.) will always be sorted ascending; else it follows "
4082 "the sort direction of the tree. Only effective if \"Always sort "
4083 "'range' nodes by name\" is also selected.",
4084 &prefs.st_sort_rng_fixorder);
4085
4086 prefs_register_bool_preference(stats_module, "st_sort_showfullname",
4087 "Display the full stats_tree plug-in name",
4088 "When selected, the full name (including menu path) of the stats_tree "
4089 "plug-in is show in windows. If cleared the plug-in name is shown "
4090 "without menu path (only the part of the name after last '/' character.)",
4091 &prefs.st_sort_showfullname);
4092
4093 prefs_register_enum_preference(stats_module, "output_format",
4094 "Default output format",
4095 "Sets the default output format for statistical data. Only supported "
4096 "by taps using the stats_tree system currently; other taps may honor "
4097 "this preference in the future. ",
4098 &prefs.st_format, st_format_vals, false0);
4099
4100 module_t *conv_module;
4101 // avoid using prefs_register_stat to prevent lint complaint about recursion
4102 conv_module = prefs_register_submodule(stats_module, prefs_modules, "conv", "Conversations",
4103 "Conversations & Endpoints", NULL((void*)0), NULL((void*)0), true1);
4104 prefs_register_bool_preference(conv_module, "machine_readable",
4105 "Display exact (machine-readable) byte counts",
4106 "When enabled, exact machine-readable byte counts are displayed. "
4107 "When disabled, human readable numbers with SI prefixes are displayed.",
4108 &prefs.conv_machine_readable);
4109
4110 /* Protocols */
4111 protocols_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "protocols", "Protocols",
4112 "Protocols", "ChCustPreferencesSection.html#ChCustPrefsProtocolsSection", NULL((void*)0), true1);
4113
4114 prefs_register_bool_preference(protocols_module, "display_hidden_proto_items",
4115 "Display hidden protocol items",
4116 "Display all hidden protocol items in the packet list.",
4117 &prefs.display_hidden_proto_items);
4118
4119 prefs_register_bool_preference(protocols_module, "display_byte_fields_with_spaces",
4120 "Display byte fields with a space character between bytes",
4121 "Display all byte fields with a space character between each byte in the packet list.",
4122 &prefs.display_byte_fields_with_spaces);
4123
4124 /*
4125 * Note the -t / option only affects the display of the packet timestamp
4126 * in the default time column; this is for all other absolute times.
4127 */
4128 prefs_register_enum_preference(protocols_module, "display_abs_time_ascii",
4129 "Format absolute times like asctime",
4130 "When to format absolute times similar to asctime instead of ISO 8601, for backwards compatibility with older Wireshark.",
4131 (int*)&prefs.display_abs_time_ascii, abs_time_format_options, false0);
4132
4133 prefs_register_bool_preference(protocols_module, "enable_incomplete_dissectors_check",
4134 "Look for incomplete dissectors",
4135 "Look for dissectors that left some bytes undecoded.",
4136 &prefs.enable_incomplete_dissectors_check);
4137
4138 prefs_register_bool_preference(protocols_module, "strict_conversation_tracking_heuristics",
4139 "Enable stricter conversation tracking heuristics",
4140 "Protocols may use things like VLAN ID or interface ID to narrow the potential for duplicate conversations. "
4141 "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",
4142 &prefs.strict_conversation_tracking_heuristics);
4143
4144 prefs_register_bool_preference(protocols_module, "ignore_dup_frames",
4145 "Ignore duplicate frames",
4146 "Ignore frames that are exact duplicates of any previous frame.",
4147 &prefs.ignore_dup_frames);
4148
4149 prefs_register_enum_preference(protocols_module, "conversation_deinterlacing_key",
4150 "Deinterlacing conversations key",
4151 "Separate into different conversations frames that look like duplicates but have different Interface, MAC, or VLAN field values.",
4152 (int *)&prefs.conversation_deinterlacing_key, conv_deint_options, false0);
4153
4154 prefs_register_uint_preference(protocols_module, "ignore_dup_frames_cache_entries",
4155 "The max number of hashes to keep in memory for determining duplicates frames",
4156 "If \"Ignore duplicate frames\" is set, this setting sets the maximum number "
4157 "of cache entries to maintain. A 0 means no limit.",
4158 10, &prefs.ignore_dup_frames_cache_entries);
4159
4160
4161 /* Obsolete preferences
4162 * These "modules" were reorganized/renamed to correspond to their GUI
4163 * configuration screen within the preferences dialog
4164 */
4165
4166 /* taps is now part of the stats module */
4167 prefs_register_module(prefs_top_level_modules, prefs_modules, "taps", "TAPS", "TAPS", NULL((void*)0), NULL((void*)0), false0);
4168 /* packet_list is now part of the protocol (parent) module */
4169 prefs_register_module(prefs_top_level_modules, prefs_modules, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL((void*)0), NULL((void*)0), false0);
4170 /* stream is now part of the gui module */
4171 prefs_register_module(prefs_top_level_modules, prefs_modules, "stream", "STREAM", "STREAM", NULL((void*)0), NULL((void*)0), false0);
4172
4173}
4174
4175/* Parse through a list of comma-separated, possibly quoted strings.
4176 Return a list of the string data. */
4177GList *
4178prefs_get_string_list(const char *str)
4179{
4180 enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
4181
4182 int state = PRE_STRING, i = 0;
4183 bool_Bool backslash = false0;
4184 unsigned char cur_c;
4185 const size_t default_size = 64;
4186 GString *slstr = NULL((void*)0);
4187 GList *sl = NULL((void*)0);
4188
4189 /* Allocate a buffer for the first string. */
4190 slstr = g_string_sized_new(default_size);
4191
4192 for (;;) {
4193 cur_c = str[i];
4194 if (cur_c == '\0') {
4195 /* It's the end of the input, so it's the end of the string we
4196 were working on, and there's no more input. */
4197 if (state == IN_QUOT || backslash) {
4198 /* We were in the middle of a quoted string or backslash escape,
4199 and ran out of characters; that's an error. */
4200 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)))))
;
4201 prefs_clear_string_list(sl);
4202 return NULL((void*)0);
4203 }
4204 if (slstr->len > 0)
4205 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))))
);
4206 else
4207 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)))))
;
4208 break;
4209 }
4210 if (cur_c == '"' && !backslash) {
4211 switch (state) {
4212 case PRE_STRING:
4213 /* We hadn't yet started processing a string; this starts the
4214 string, and we're now quoting. */
4215 state = IN_QUOT;
4216 break;
4217 case IN_QUOT:
4218 /* We're in the middle of a quoted string, and we saw a quotation
4219 mark; we're no longer quoting. */
4220 state = NOT_IN_QUOT;
4221 break;
4222 case NOT_IN_QUOT:
4223 /* We're working on a string, but haven't seen a quote; we're
4224 now quoting. */
4225 state = IN_QUOT;
4226 break;
4227 default:
4228 break;
4229 }
4230 } else if (cur_c == '\\' && !backslash) {
4231 /* We saw a backslash, and the previous character wasn't a
4232 backslash; escape the next character.
4233
4234 This also means we've started a new string. */
4235 backslash = true1;
4236 if (state == PRE_STRING)
4237 state = NOT_IN_QUOT;
4238 } else if (cur_c == ',' && state != IN_QUOT && !backslash) {
4239 /* We saw a comma, and we're not in the middle of a quoted string
4240 and it wasn't preceded by a backslash; it's the end of
4241 the string we were working on... */
4242 if (slstr->len > 0) {
4243 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))))
);
4244 slstr = g_string_sized_new(default_size);
4245 }
4246
4247 /* ...and the beginning of a new string. */
4248 state = PRE_STRING;
4249 } else if (!g_ascii_isspace(cur_c)((g_ascii_table[(guchar) (cur_c)] & G_ASCII_SPACE) != 0) || state != PRE_STRING) {
4250 /* Either this isn't a white-space character, or we've started a
4251 string (i.e., already seen a non-white-space character for that
4252 string and put it into the string).
4253
4254 The character is to be put into the string; do so. */
4255 g_string_append_c(slstr, cur_c)g_string_append_c_inline (slstr, cur_c);
4256
4257 /* If it was backslash-escaped, we're done with the backslash escape. */
4258 backslash = false0;
4259 }
4260 i++;
4261 }
4262 return(sl);
4263}
4264
4265char *join_string_list(GList *sl)
4266{
4267 GString *joined_str = g_string_new("");
4268 GList *cur, *first;
4269 char *str;
4270 unsigned item_count = 0;
4271
4272 cur = first = g_list_first(sl);
4273 while (cur) {
4274 item_count++;
4275 str = (char *)cur->data;
4276
4277 if (cur != first)
4278 g_string_append_c(joined_str, ',')g_string_append_c_inline (joined_str, ',');
4279
4280 if (item_count % 2) {
4281 /* Wrap the line. */
4282 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))
;
4283 } else
4284 g_string_append_c(joined_str, ' ')g_string_append_c_inline (joined_str, ' ');
4285
4286 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4287 while (*str) {
4288 gunichar uc = g_utf8_get_char (str);
4289
4290 if (uc == '"' || uc == '\\')
4291 g_string_append_c(joined_str, '\\')g_string_append_c_inline (joined_str, '\\');
4292
4293 if (g_unichar_isprint(uc))
4294 g_string_append_unichar (joined_str, uc);
4295
4296 str = g_utf8_next_char (str)(char *)((str) + g_utf8_skip[*(const guchar *)(str)]);
4297 }
4298
4299 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4300
4301 cur = cur->next;
4302 }
4303 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))))
;
4304}
4305
4306void
4307prefs_clear_string_list(GList *sl)
4308{
4309 g_list_free_full(sl, g_free);
4310}
4311
4312/*
4313 * Takes a string, a pointer to an array of "enum_val_t"s, and a default int
4314 * value.
4315 * The array must be terminated by an entry with a null "name" string.
4316 *
4317 * If the string matches a "name" string in an entry, the value from that
4318 * entry is returned.
4319 *
4320 * Otherwise, if a string matches a "description" string in an entry, the
4321 * value from that entry is returned; we do that for backwards compatibility,
4322 * as we used to have only a "name" string that was used both for command-line
4323 * and configuration-file values and in the GUI (which meant either that
4324 * the GUI had what might be somewhat cryptic values to select from or that
4325 * the "-o" flag took long strings, often with spaces in them).
4326 *
4327 * Otherwise, the default value that was passed as the third argument is
4328 * returned.
4329 */
4330static int
4331find_val_for_string(const char *needle, const enum_val_t *haystack,
4332 int default_value)
4333{
4334 int i;
4335
4336 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4337 if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
4338 return haystack[i].value;
4339 }
4340 }
4341 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4342 if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
4343 return haystack[i].value;
4344 }
4345 }
4346 return default_value;
4347}
4348
4349/* Preferences file format:
4350 * - Configuration directives start at the beginning of the line, and
4351 * are terminated with a colon.
4352 * - Directives can be continued on the next line by preceding them with
4353 * whitespace.
4354 *
4355 * Example:
4356
4357# This is a comment line
4358print.command: lpr
4359print.file: /a/very/long/path/
4360 to/wireshark-out.ps
4361 *
4362 */
4363
4364/*
4365 * Initialize non-dissector preferences used by the "register preference" API
4366 * to default values so the default values can be used when registered.
4367 *
4368 * String, filename, and directory preferences will be g_freed so they must
4369 * be g_mallocated.
4370 */
4371static void
4372prefs_set_global_defaults(wmem_allocator_t* pref_scope, const char** col_fmt, int num_cols)
4373{
4374 int i;
4375 char *col_name;
4376 fmt_data *cfmt;
4377
4378 prefs.restore_filter_after_following_stream = false0;
4379 prefs.gui_toolbar_main_style = TB_STYLE_ICONS0;
4380 /* We try to find the best font in the Qt code */
4381 wmem_free(pref_scope, prefs.gui_font_name);
4382 prefs.gui_font_name = wmem_strdup(pref_scope, "");
4383 prefs.gui_active_fg.red = 0;
4384 prefs.gui_active_fg.green = 0;
4385 prefs.gui_active_fg.blue = 0;
4386 prefs.gui_active_bg.red = 52223;
4387 prefs.gui_active_bg.green = 59647;
4388 prefs.gui_active_bg.blue = 65535;
4389 prefs.gui_active_style = COLOR_STYLE_DEFAULT0;
4390 prefs.gui_inactive_fg.red = 0;
4391 prefs.gui_inactive_fg.green = 0;
4392 prefs.gui_inactive_fg.blue = 0;
4393 prefs.gui_inactive_bg.red = 61439;
4394 prefs.gui_inactive_bg.green = 61439;
4395 prefs.gui_inactive_bg.blue = 61439;
4396 prefs.gui_inactive_style = COLOR_STYLE_DEFAULT0;
4397 prefs.gui_marked_fg.red = 65535;
4398 prefs.gui_marked_fg.green = 65535;
4399 prefs.gui_marked_fg.blue = 65535;
4400 prefs.gui_marked_bg.red = 0;
4401 prefs.gui_marked_bg.green = 8224;
4402 prefs.gui_marked_bg.blue = 10794;
4403 prefs.gui_ignored_fg.red = 32767;
4404 prefs.gui_ignored_fg.green = 32767;
4405 prefs.gui_ignored_fg.blue = 32767;
4406 prefs.gui_ignored_bg.red = 65535;
4407 prefs.gui_ignored_bg.green = 65535;
4408 prefs.gui_ignored_bg.blue = 65535;
4409 wmem_free(pref_scope, prefs.gui_colorized_fg);
4410 prefs.gui_colorized_fg = wmem_strdup(pref_scope, "000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
4411 wmem_free(pref_scope, prefs.gui_colorized_bg);
4412 prefs.gui_colorized_bg = wmem_strdup(pref_scope, "ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
4413 prefs.st_client_fg.red = 32767;
4414 prefs.st_client_fg.green = 0;
4415 prefs.st_client_fg.blue = 0;
4416 prefs.st_client_bg.red = 64507;
4417 prefs.st_client_bg.green = 60909;
4418 prefs.st_client_bg.blue = 60909;
4419 prefs.st_server_fg.red = 0;
4420 prefs.st_server_fg.green = 0;
4421 prefs.st_server_fg.blue = 32767;
4422 prefs.st_server_bg.red = 60909;
4423 prefs.st_server_bg.green = 60909;
4424 prefs.st_server_bg.blue = 64507;
4425
4426 if (gui_theme_is_dark) {
4427 // Green, red and yellow with HSV V = 84
4428 prefs.gui_filter_valid_bg.red = 0x0000; /* dark green */
4429 prefs.gui_filter_valid_bg.green = 0x66ff;
4430 prefs.gui_filter_valid_bg.blue = 0x0000;
4431 prefs.gui_filter_valid_fg.red = 0xFFFF;
4432 prefs.gui_filter_valid_fg.green = 0xFFFF;
4433 prefs.gui_filter_valid_fg.blue = 0xFFFF;
4434 prefs.gui_filter_invalid_bg.red = 0x66FF; /* dark red */
4435 prefs.gui_filter_invalid_bg.green = 0x0000;
4436 prefs.gui_filter_invalid_bg.blue = 0x0000;
4437 prefs.gui_filter_invalid_fg.red = 0xFFFF;
4438 prefs.gui_filter_invalid_fg.green = 0xFFFF;
4439 prefs.gui_filter_invalid_fg.blue = 0xFFFF;
4440 prefs.gui_filter_deprecated_bg.red = 0x66FF; /* dark yellow / olive */
4441 prefs.gui_filter_deprecated_bg.green = 0x66FF;
4442 prefs.gui_filter_deprecated_bg.blue = 0x0000;
4443 prefs.gui_filter_deprecated_fg.red = 0xFFFF;
4444 prefs.gui_filter_deprecated_fg.green = 0xFFFF;
4445 prefs.gui_filter_deprecated_fg.blue = 0xFFFF;
4446 } else {
4447 // Green, red and yellow with HSV V = 20
4448 prefs.gui_filter_valid_bg.red = 0xAFFF; /* light green */
4449 prefs.gui_filter_valid_bg.green = 0xFFFF;
4450 prefs.gui_filter_valid_bg.blue = 0xAFFF;
4451 prefs.gui_filter_valid_fg.red = 0x0000;
4452 prefs.gui_filter_valid_fg.green = 0x0000;
4453 prefs.gui_filter_valid_fg.blue = 0x0000;
4454 prefs.gui_filter_invalid_bg.red = 0xFFFF; /* light red */
4455 prefs.gui_filter_invalid_bg.green = 0xAFFF;
4456 prefs.gui_filter_invalid_bg.blue = 0xAFFF;
4457 prefs.gui_filter_invalid_fg.red = 0x0000;
4458 prefs.gui_filter_invalid_fg.green = 0x0000;
4459 prefs.gui_filter_invalid_fg.blue = 0x0000;
4460 prefs.gui_filter_deprecated_bg.red = 0xFFFF; /* light yellow */
4461 prefs.gui_filter_deprecated_bg.green = 0xFFFF;
4462 prefs.gui_filter_deprecated_bg.blue = 0xAFFF;
4463 prefs.gui_filter_deprecated_fg.red = 0x0000;
4464 prefs.gui_filter_deprecated_fg.green = 0x0000;
4465 prefs.gui_filter_deprecated_fg.blue = 0x0000;
4466 }
4467
4468 prefs.gui_geometry_save_position = true1;
4469 prefs.gui_geometry_save_size = true1;
4470 prefs.gui_geometry_save_maximized= true1;
4471 prefs.gui_fileopen_style = FO_STYLE_LAST_OPENED0;
4472 prefs.gui_recent_df_entries_max = 10;
4473 prefs.gui_recent_files_count_max = 10;
4474 wmem_free(pref_scope, prefs.gui_fileopen_dir);
4475 prefs.gui_fileopen_dir = wmem_strdup(pref_scope, get_persdatafile_dir());
4476 prefs.gui_fileopen_preview = 3;
4477 wmem_free(pref_scope, prefs.gui_tlskeylog_command);
4478 prefs.gui_tlskeylog_command = wmem_strdup(pref_scope, "");
4479 prefs.gui_ask_unsaved = true1;
4480 prefs.gui_autocomplete_filter = true1;
4481 prefs.gui_find_wrap = true1;
4482 prefs.gui_update_enabled = true1;
4483 prefs.gui_update_channel = UPDATE_CHANNEL_STABLE;
4484 prefs.gui_update_interval = 60*60*24; /* Seconds */
4485 prefs.gui_debounce_timer = 400; /* milliseconds */
4486 wmem_free(pref_scope, prefs.gui_window_title);
4487 prefs.gui_window_title = wmem_strdup(pref_scope, "");
4488 wmem_free(pref_scope, prefs.gui_prepend_window_title);
4489 prefs.gui_prepend_window_title = wmem_strdup(pref_scope, "");
4490 wmem_free(pref_scope, prefs.gui_start_title);
4491 prefs.gui_start_title = wmem_strdup(pref_scope, "The World's Most Popular Network Protocol Analyzer");
4492 prefs.gui_version_placement = version_both;
4493 prefs.gui_welcome_page_show_recent = true1;
4494 prefs.gui_layout_type = layout_type_2;
4495 prefs.gui_layout_content_1 = layout_pane_content_plist;
4496 prefs.gui_layout_content_2 = layout_pane_content_pdetails;
4497 prefs.gui_layout_content_3 = layout_pane_content_pbytes;
4498 prefs.gui_packet_list_elide_mode = ELIDE_RIGHT;
4499 prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut = COPY_FORMAT_TEXT;
4500 prefs.gui_packet_list_copy_text_with_aligned_columns = false0;
4501 prefs.gui_packet_list_show_related = true1;
4502 prefs.gui_packet_list_show_minimap = true1;
4503 prefs.gui_packet_list_sortable = true1;
4504 prefs.gui_packet_list_cached_rows_max = 10000;
4505 prefs.gui_packet_list_multi_color_mode = PACKET_LIST_MULTI_COLOR_MODE_OFF;
4506 prefs.gui_packet_list_multi_color_shift_percent = 85;
4507 prefs.gui_packet_list_multi_color_details = false0;
4508 prefs.gui_packet_list_multi_color_separator = PACKET_LIST_MULTI_COLOR_SEPARATOR_DIAGONAL;
4509 wmem_free(pref_scope, prefs.gui_interfaces_hide_types);
4510 prefs.gui_interfaces_hide_types = wmem_strdup(pref_scope, "");
4511 prefs.gui_interfaces_show_hidden = false0;
4512 prefs.gui_interfaces_remote_display = true1;
4513 prefs.gui_packet_list_separator = false0;
4514 prefs.gui_packet_header_column_definition = true1;
4515 prefs.gui_packet_list_hover_style = true1;
4516 prefs.gui_show_selected_packet = false0;
4517 prefs.gui_show_file_load_time = false0;
4518 prefs.gui_max_export_objects = 1000;
4519 prefs.gui_max_tree_items = 1 * 1000 * 1000;
4520 prefs.gui_max_tree_depth = 5 * 100;
4521 prefs.gui_decimal_places1 = DEF_GUI_DECIMAL_PLACES12;
4522 prefs.gui_decimal_places2 = DEF_GUI_DECIMAL_PLACES24;
4523 prefs.gui_decimal_places3 = DEF_GUI_DECIMAL_PLACES36;
4524
4525 if (prefs.col_list) {
4526 free_col_info(prefs.col_list);
4527 prefs.col_list = NULL((void*)0);
4528 }
4529 for (i = 0; i < num_cols; i++) {
4530 cfmt = g_new0(fmt_data,1)((fmt_data *) g_malloc0_n ((1), sizeof (fmt_data)));
4531 cfmt->title = g_strdup(col_fmt[i * 2])g_strdup_inline (col_fmt[i * 2]);
4532 cfmt->visible = true1;
4533 cfmt->display = COLUMN_DISPLAY_STRINGS'R';
4534 parse_column_format(cfmt, col_fmt[(i * 2) + 1]);
4535 prefs.col_list = g_list_append(prefs.col_list, cfmt);
4536 }
4537 prefs.num_cols = num_cols;
4538
4539/* set the default values for the capture dialog box */
4540 prefs.capture_prom_mode = true1;
4541 prefs.capture_monitor_mode = false0;
4542 prefs.capture_pcap_ng = true1;
4543 prefs.capture_real_time = true1;
4544 prefs.capture_update_interval = DEFAULT_UPDATE_INTERVAL100;
4545 prefs.capture_no_extcap = false0;
4546 prefs.capture_show_info = false0;
4547 prefs.enable_aggregation = false0;
4548
4549 if (!prefs.capture_columns) {
4550 /* First time through */
4551 for (i = 0; i < num_capture_cols; i++) {
4552 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
4553 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
4554 }
4555 }
4556
4557/* set the default values for the tap/statistics dialog box */
4558 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
4559 prefs.flow_graph_max_export_items = 1000;
4560 prefs.st_enable_burstinfo = true1;
4561 prefs.st_burst_showcount = false0;
4562 prefs.st_burst_resolution = ST_DEF_BURSTRES5;
4563 prefs.st_burst_windowlen = ST_DEF_BURSTLEN100;
4564 prefs.st_sort_casesensitve = true1;
4565 prefs.st_sort_rng_fixorder = true1;
4566 prefs.st_sort_rng_nameonly = true1;
4567 prefs.st_sort_defcolflag = ST_SORT_COL_COUNT2;
4568 prefs.st_sort_defdescending = true1;
4569 prefs.st_sort_showfullname = false0;
4570 prefs.conv_machine_readable = false0;
4571
4572 /* protocols */
4573 prefs.display_hidden_proto_items = false0;
4574 prefs.display_byte_fields_with_spaces = false0;
4575 prefs.display_abs_time_ascii = ABS_TIME_ASCII_TREE;
4576 prefs.ignore_dup_frames = false0;
4577 prefs.ignore_dup_frames_cache_entries = 10000;
4578
4579 /* set the default values for the io graph dialog */
4580 prefs.gui_io_graph_automatic_update = true1;
4581 prefs.gui_io_graph_enable_legend = true1;
4582
4583 /* set the default values for the plot dialog */
4584 prefs.gui_plot_automatic_update = true1;
4585 prefs.gui_plot_enable_legend = true1;
4586 prefs.gui_plot_enable_auto_scroll = false0;
4587
4588 /* set the default values for the packet dialog */
4589 prefs.gui_packet_dialog_layout = layout_vertical;
4590 prefs.gui_packet_details_show_byteview = true1;
4591}
4592
4593/*
4594 * Reset a single dissector preference.
4595 */
4596void
4597reset_pref(pref_t *pref)
4598{
4599 if (!pref) return;
4600
4601 /*
4602 * This preference is no longer supported; it's not a
4603 * real preference, so we don't reset it (i.e., we
4604 * treat it as if it weren't found in the list of
4605 * preferences, and we weren't called in the first place).
4606 */
4607 if (pref->obsolete)
4608 return;
4609
4610 switch (pref->type) {
4611
4612 case PREF_UINT:
4613 *pref->varp.uint = pref->default_val.uint;
4614 break;
4615
4616 case PREF_INT:
4617 *pref->varp.intp = pref->default_val.intval;
4618 break;
4619
4620 case PREF_FLOAT:
4621 *pref->varp.floatp = pref->default_val.floatval;
4622 break;
4623
4624 case PREF_BOOL:
4625 *pref->varp.boolp = pref->default_val.boolval;
4626 break;
4627
4628 case PREF_ENUM:
4629 case PREF_PROTO_TCP_SNDAMB_ENUM:
4630 *pref->varp.enump = pref->default_val.enumval;
4631 break;
4632
4633 case PREF_STRING:
4634 case PREF_SAVE_FILENAME:
4635 case PREF_OPEN_FILENAME:
4636 case PREF_DIRNAME:
4637 case PREF_PASSWORD:
4638 case PREF_DISSECTOR:
4639 reset_string_like_preference(pref);
4640 break;
4641
4642 case PREF_RANGE:
4643 case PREF_DECODE_AS_RANGE:
4644 wmem_free(pref->scope, *pref->varp.range);
4645 *pref->varp.range = range_copy(pref->scope, pref->default_val.range);
4646 break;
4647
4648 case PREF_STATIC_TEXT:
4649 case PREF_UAT:
4650 /* Nothing to do */
4651 break;
4652
4653 case PREF_COLOR:
4654 *pref->varp.colorp = pref->default_val.color;
4655 break;
4656
4657 case PREF_CUSTOM:
4658 pref->custom_cbs.reset_cb(pref);
4659 break;
4660 }
4661}
4662
4663static void
4664reset_pref_cb(void *data, void *user_data)
4665{
4666 pref_t *pref = (pref_t *) data;
4667 module_t *module = (module_t *)user_data;
4668
4669 if (pref && (pref->type == PREF_RANGE || pref->type == PREF_DECODE_AS_RANGE)) {
4670 /*
4671 * Some dissectors expect the range (returned via prefs_get_range_value)
4672 * to remain valid if it has not changed. If it did change, then we
4673 * should set "prefs_changed_flags" to ensure that the preference apply
4674 * callback is invoked. That callback will notify dissectors that it
4675 * should no longer assume the range to be valid.
4676 */
4677 if (ranges_are_equal(*pref->varp.range, pref->default_val.range)) {
4678 /* Optimization: do not invoke apply callback if nothing changed. */
4679 return;
4680 }
4681 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
4682 }
4683 reset_pref(pref);
4684}
4685
4686/*
4687 * Reset all preferences for a module.
4688 */
4689static bool_Bool
4690reset_module_prefs(const void *key _U___attribute__((unused)), void *value, void *data _U___attribute__((unused)))
4691{
4692 module_t *module = (module_t *)value;
4693 g_list_foreach(module->prefs, reset_pref_cb, module);
4694 return false0;
4695}
4696
4697/* Reset preferences */
4698void
4699prefs_reset(const char* app_env_var_prefix, const char** col_fmt, int num_cols)
4700{
4701 g_free(prefs.saved_at_version);
4702 prefs.saved_at_version = NULL((void*)0);
4703
4704 /*
4705 * Unload all UAT preferences.
4706 */
4707 uat_unload_all();
4708
4709 /*
4710 * Unload any loaded MIBs.
4711 */
4712 /* XXX - oids_cleanup not tested/supported at non-shutdown yet */
4713 //oids_cleanup();
4714
4715 /*
4716 * Reload all UAT preferences.
4717 */
4718 uat_load_all(app_env_var_prefix);
4719
4720 /*
4721 * Reset the non-dissector preferences.
4722 */
4723 prefs_set_global_defaults(wmem_epan_scope(), col_fmt, num_cols);
4724
4725 /*
4726 * Reset the non-UAT dissector preferences.
4727 */
4728 wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL((void*)0));
4729}
4730
4731#ifdef _WIN32
4732static void
4733read_registry(void)
4734{
4735 HKEY hTestKey;
4736 DWORD data;
4737 DWORD data_size = sizeof(DWORD);
4738 DWORD ret;
4739
4740 ret = RegOpenKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, KEY_READ, &hTestKey);
4741 if (ret != ERROR_SUCCESS && ret != ERROR_FILE_NOT_FOUND) {
4742 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"
, 4742, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
4743 return;
4744 }
4745
4746 ret = RegQueryValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", NULL((void*)0), NULL((void*)0), (LPBYTE)&data, &data_size);
4747 if (ret == ERROR_SUCCESS) {
4748 ws_log_console_open = (ws_log_console_open_pref)data;
4749 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"
, 4749, __func__, "Got ""ConsoleOpen"" from Windows registry: %d"
, ws_log_console_open); } } while (0)
;
4750 }
4751 else if (ret != ERROR_FILE_NOT_FOUND) {
4752 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"
, 4752, __func__, "Error reading registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
4753 }
4754
4755 RegCloseKey(hTestKey);
4756}
4757#endif
4758
4759void
4760prefs_read_module(const char *module, const char* app_env_var_prefix)
4761{
4762 int err;
4763 char *pf_path;
4764 FILE *pf;
4765
4766 module_t *target_module = prefs_find_module(module);
4767 if (!target_module) {
4768 return;
4769 }
4770
4771 /* Construct the pathname of the user's preferences file for the module. */
4772 char *pf_name = wmem_strdup_printf(NULL((void*)0), "%s.cfg", module);
4773 pf_path = get_persconffile_path(pf_name, true1, app_env_var_prefix);
4774 wmem_free(NULL((void*)0), pf_name);
4775
4776 /* Read the user's module preferences file, if it exists and is not a dir. */
4777 if (!test_for_regular_file(pf_path) || ((pf = ws_fopenfopen(pf_path, "r")) == NULL((void*)0))) {
4778 g_free(pf_path);
4779 /* Fall back to the user's generic preferences file. */
4780 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4781 pf = ws_fopenfopen(pf_path, "r");
4782 }
4783
4784 if (pf != NULL((void*)0)) {
4785 /* We succeeded in opening it; read it. */
4786 err = read_prefs_file(pf_path, pf, set_pref, target_module);
4787 if (err != 0) {
4788 /* We had an error reading the file; report it. */
4789 report_warning("Error reading your preferences file \"%s\": %s.",
4790 pf_path, g_strerror(err));
4791 } else
4792 g_free(pf_path);
4793 fclose(pf);
4794 } else {
4795 /* We failed to open it. If we failed for some reason other than
4796 "it doesn't exist", return the errno and the pathname, so our
4797 caller can report the error. */
4798 if (errno(*__errno_location ()) != ENOENT2) {
4799 report_warning("Can't open your preferences file \"%s\": %s.",
4800 pf_path, g_strerror(errno(*__errno_location ())));
4801 } else
4802 g_free(pf_path);
4803 }
4804
4805 return;
4806}
4807
4808/* Read the preferences file, fill in "prefs", and return a pointer to it.
4809
4810 If we got an error (other than "it doesn't exist") we report it through
4811 the UI. */
4812e_prefs *
4813read_prefs(const char* app_env_var_prefix)
4814{
4815 int err;
4816 char *pf_path;
4817 FILE *pf;
4818
4819 /* clean up libsmi structures before reading prefs */
4820 /* XXX - oids_cleanup not tested/supported at non-shutdown yet */
4821 // oids_cleanup();
4822
4823#ifdef _WIN32
4824 read_registry();
4825#endif
4826
4827 /*
4828 * If we don't already have the pathname of the global preferences
4829 * file, construct it. Then, in either case, try to open the file.
4830 */
4831 if (gpf_path == NULL((void*)0)) {
4832 /*
4833 * We don't have the path; try the new path first, and, if that
4834 * file doesn't exist, try the old path.
4835 */
4836 gpf_path = get_datafile_path(PF_NAME"preferences", app_env_var_prefix);
4837 if ((pf = ws_fopenfopen(gpf_path, "r")) == NULL((void*)0) && errno(*__errno_location ()) == ENOENT2) {
4838 /*
4839 * It doesn't exist by the new name; try the old name.
4840 */
4841 g_free(gpf_path);
4842 gpf_path = get_datafile_path(OLD_GPF_NAME"wireshark.conf", app_env_var_prefix);
4843 pf = ws_fopenfopen(gpf_path, "r");
4844 }
4845 } else {
4846 /*
4847 * We have the path; try it.
4848 */
4849 pf = ws_fopenfopen(gpf_path, "r");
4850 }
4851
4852 /*
4853 * If we were able to open the file, read it.
4854 * XXX - if it failed for a reason other than "it doesn't exist",
4855 * report the error.
4856 */
4857 if (pf != NULL((void*)0)) {
4858 /* We succeeded in opening it; read it. */
4859 err = read_prefs_file(gpf_path, pf, set_pref, NULL((void*)0));
4860 if (err != 0) {
4861 /* We had an error reading the file; report it. */
4862 report_warning("Error reading global preferences file \"%s\": %s.",
4863 gpf_path, g_strerror(err));
4864 }
4865 fclose(pf);
4866 } else {
4867 /* We failed to open it. If we failed for some reason other than
4868 "it doesn't exist", report the error. */
4869 if (errno(*__errno_location ()) != ENOENT2) {
4870 if (errno(*__errno_location ()) != 0) {
4871 report_warning("Can't open global preferences file \"%s\": %s.",
4872 gpf_path, g_strerror(errno(*__errno_location ())));
4873 }
4874 }
4875 }
4876
4877 /* Construct the pathname of the user's preferences file. */
4878 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4879
4880 /* Read the user's preferences file, if it exists. */
4881 if ((pf = ws_fopenfopen(pf_path, "r")) != NULL((void*)0)) {
4882
4883 /* We succeeded in opening it; read it. */
4884 err = read_prefs_file(pf_path, pf, set_pref, NULL((void*)0));
4885 if (err != 0) {
4886 /* We had an error reading the file; report it. */
4887 report_warning("Error reading your preferences file \"%s\": %s.",
4888 pf_path, g_strerror(err));
4889 } else
4890 g_free(pf_path);
4891 fclose(pf);
4892 } else {
4893 /* We failed to open it. If we failed for some reason other than
4894 "it doesn't exist", return the errno and the pathname, so our
4895 caller can report the error. */
4896 if (errno(*__errno_location ()) != ENOENT2) {
4897 report_warning("Can't open your preferences file \"%s\": %s.",
4898 pf_path, g_strerror(errno(*__errno_location ())));
4899 } else
4900 g_free(pf_path);
4901 }
4902
4903 /* load SMI modules if needed */
4904 oids_init(app_env_var_prefix);
4905
4906 return &prefs;
4907}
4908
4909/* read the preferences file (or similar) and call the callback
4910 * function to set each key/value pair found */
4911int
4912read_prefs_file(const char *pf_path, FILE *pf,
4913 pref_set_pair_cb pref_set_pair_fct, void *private_data)
4914{
4915 enum {
4916 START, /* beginning of a line */
4917 IN_VAR, /* processing key name */
4918 PRE_VAL, /* finished processing key name, skipping white space before value */
4919 IN_VAL, /* processing value */
4920 IN_SKIP /* skipping to the end of the line */
4921 } state = START;
4922 int got_c;
4923 GString *cur_val;
4924 GString *cur_var;
4925 bool_Bool got_val = false0;
4926 int fline = 1, pline = 1;
4927 char hint[] = "(save preferences to remove this warning)";
4928 char ver[128];
4929
4930 cur_val = g_string_new("");
4931 cur_var = g_string_new("");
4932
4933 /* Try to read in the profile name in the first line of the preferences file. */
4934 if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) {
1
Assuming the condition is false
2
Taking false branch
4935 /* Assume trailing period and remove it */
4936 g_free(prefs.saved_at_version);
4937 prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1);
4938 }
4939 rewind(pf);
3
After calling 'rewind' reading 'errno' is required to find out if the call has failed
4940
4941 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'
4942 if (got_c == '\r') {
4943 /* Treat CR-LF at the end of a line like LF, so that if we're reading
4944 * a Windows-format file on UN*X, we handle it the same way we'd handle
4945 * a UN*X-format file. */
4946 got_c = ws_getc_unlockedgetc_unlocked(pf);
4947 if (got_c == EOF(-1))
4948 break;
4949 if (got_c != '\n') {
4950 /* Put back the character after the CR, and process the CR normally. */
4951 ungetc(got_c, pf);
4952 got_c = '\r';
4953 }
4954 }
4955 if (got_c == '\n') {
4956 state = START;
4957 fline++;
4958 continue;
4959 }
4960
4961 switch (state) {
4962 case START:
4963 if (g_ascii_isalnum(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_ALNUM) != 0)) {
4964 if (cur_var->len > 0) {
4965 if (got_val) {
4966 if (cur_val->len > 0) {
4967 if (cur_val->str[cur_val->len-1] == ',') {
4968 /*
4969 * If the pref has a trailing comma, eliminate it.
4970 */
4971 cur_val->str[cur_val->len-1] = '\0';
4972 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"
, 4972, __func__, "%s line %d: trailing comma in \"%s\" %s", pf_path
, pline, cur_var->str, hint); } } while (0)
;
4973 }
4974 }
4975 /* Call the routine to set the preference; it will parse
4976 the value as appropriate.
4977
4978 Since we're reading a file, rather than processing
4979 explicit user input, for range preferences, silently
4980 lower values in excess of the range's maximum, rather
4981 than reporting errors and failing. */
4982 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
4983
4984 case PREFS_SET_OK:
4985 break;
4986
4987 case PREFS_SET_SYNTAX_ERR:
4988 report_warning("Syntax error in preference \"%s\" at line %d of\n%s %s",
4989 cur_var->str, pline, pf_path, hint);
4990 break;
4991
4992 case PREFS_SET_NO_SUCH_PREF:
4993 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"
, 4994, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4994 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4994, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4995 break;
4996
4997 case PREFS_SET_OBSOLETE:
4998 /*
4999 * If an attempt is made to save the
5000 * preferences, a popup warning will be
5001 * displayed stating that obsolete prefs
5002 * have been detected and the user will
5003 * be given the opportunity to save these
5004 * prefs under a different profile name.
5005 * The prefs in question need to be listed
5006 * in the console window so that the
5007 * user can make an informed choice.
5008 */
5009 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"
, 5010, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5010 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5010, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5011 break;
5012 }
5013 } else {
5014 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"
, 5014, __func__, "Incomplete preference at line %d: of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
5015 }
5016 }
5017 state = IN_VAR;
5018 got_val = false0;
5019 g_string_truncate(cur_var, 0)g_string_truncate_inline (cur_var, 0);
5020 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
5021 pline = fline;
5022 } else if (g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0) && cur_var->len > 0 && got_val) {
5023 state = PRE_VAL;
5024 } else if (got_c == '#') {
5025 state = IN_SKIP;
5026 } else {
5027 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"
, 5027, __func__, "Malformed preference at line %d of\n%s %s"
, fline, pf_path, hint); } } while (0)
;
5028 }
5029 break;
5030 case IN_VAR:
5031 if (got_c != ':') {
5032 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
5033 } else {
5034 /* This is a colon (':') */
5035 state = PRE_VAL;
5036 g_string_truncate(cur_val, 0)g_string_truncate_inline (cur_val, 0);
5037 /*
5038 * Set got_val to true to accommodate prefs such as
5039 * "gui.fileopen.dir" that do not require a value.
5040 */
5041 got_val = true1;
5042 }
5043 break;
5044 case PRE_VAL:
5045 if (!g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0)) {
5046 state = IN_VAL;
5047 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
5048 }
5049 break;
5050 case IN_VAL:
5051 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
5052 break;
5053 case IN_SKIP:
5054 break;
5055 }
5056 }
5057 if (cur_var->len > 0) {
5058 if (got_val) {
5059 /* Call the routine to set the preference; it will parse
5060 the value as appropriate.
5061
5062 Since we're reading a file, rather than processing
5063 explicit user input, for range preferences, silently
5064 lower values in excess of the range's maximum, rather
5065 than reporting errors and failing. */
5066 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
5067
5068 case PREFS_SET_OK:
5069 break;
5070
5071 case PREFS_SET_SYNTAX_ERR:
5072 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"
, 5073, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5073 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5073, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5074 break;
5075
5076 case PREFS_SET_NO_SUCH_PREF:
5077 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"
, 5078, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5078 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5078, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5079 break;
5080
5081 case PREFS_SET_OBSOLETE:
5082 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"
, 5083, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
5083 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5083, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
5084 break;
5085 }
5086 } else {
5087 ws_warning("Incomplete preference at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5088, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
5088 pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 5088, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
5089 }
5090 }
5091
5092 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)))))
;
5093 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)))))
;
5094
5095 if (ferror(pf))
5096 return errno(*__errno_location ());
5097 else
5098 return 0;
5099}
5100
5101/*
5102 * If we were handed a preference starting with "uat:", try to turn it into
5103 * a valid uat entry.
5104 */
5105static bool_Bool
5106prefs_set_uat_pref(char *uat_entry, char **errmsg) {
5107 char *p, *colonp;
5108 uat_t *uat;
5109 bool_Bool ret;
5110
5111 colonp = strchr(uat_entry, ':');
5112 if (colonp == NULL((void*)0))
5113 return false0;
5114
5115 p = colonp;
5116 *p++ = '\0';
5117
5118 /*
5119 * Skip over any white space (there probably won't be any, but
5120 * as we allow it in the preferences file, we might as well
5121 * allow it here).
5122 */
5123 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
5124 p++;
5125 if (*p == '\0') {
5126 /*
5127 * Put the colon back, so if our caller uses, in an
5128 * error message, the string they passed us, the message
5129 * looks correct.
5130 */
5131 *colonp = ':';
5132 return false0;
5133 }
5134
5135 uat = uat_find(uat_entry);
5136 *colonp = ':';
5137 if (uat == NULL((void*)0)) {
5138 *errmsg = g_strdup("Unknown preference")g_strdup_inline ("Unknown preference");
5139 return false0;
5140 }
5141
5142 ret = uat_load_str(uat, p, errmsg);
5143 return ret;
5144}
5145
5146char *
5147prefs_sanitize_string(const char* str)
5148{
5149 char *sanitized;
5150 if (!prefs_regex) {
5151 prefs_regex = g_regex_new("\\s*\\R\\s*", (GRegexCompileFlags)G_REGEX_OPTIMIZE,
5152 (GRegexMatchFlags)G_REGEX_MATCH_BSR_ANYCRLF, NULL((void*)0));
5153 } else {
5154 g_regex_ref(prefs_regex);
5155 }
5156 sanitized = g_regex_replace(prefs_regex, str, -1, 0, " ", G_REGEX_MATCH_DEFAULT, NULL((void*)0));
5157 g_regex_unref(prefs_regex);
5158 return sanitized;
5159}
5160
5161/*
5162 * Given a string of the form "<pref name>:<pref value>", as might appear
5163 * as an argument to a "-o" option, parse it and set the preference in
5164 * question. Return an indication of whether it succeeded or failed
5165 * in some fashion.
5166 */
5167prefs_set_pref_e
5168prefs_set_pref(char *prefarg, char **errmsg)
5169{
5170 char *p, *colonp;
5171 prefs_set_pref_e ret;
5172
5173 *errmsg = NULL((void*)0);
5174
5175 colonp = strchr(prefarg, ':');
5176 if (colonp == NULL((void*)0)) {
5177 *errmsg = g_strdup("missing ':' (syntax is prefname:value).")g_strdup_inline ("missing ':' (syntax is prefname:value).");
5178 return PREFS_SET_SYNTAX_ERR;
5179 }
5180
5181 p = colonp;
5182 *p++ = '\0';
5183 /* XXX - Replace line terminators, or match and fail with errmsg, or ignore? */
5184
5185 /*
5186 * Skip over any white space (there probably won't be any, but
5187 * as we allow it in the preferences file, we might as well
5188 * allow it here).
5189 */
5190 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
5191 p++;
5192 /* The empty string is a legal value for range preferences (PREF_RANGE,
5193 * PREF_DECODE_AS_RANGE), and string-like preferences (PREF_STRING,
5194 * PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME), indeed often
5195 * not just useful but the default. A user might have a value saved
5196 * to their preference file but want to override it to default behavior.
5197 * Individual preference handlers of those types should be prepared to
5198 * deal with an empty string. For other types, it is up to set_pref() to
5199 * test for the empty string and set PREFS_SET_SYNTAX_ERROR there.
5200 */
5201 if (strcmp(prefarg, "uat")) {
5202 ret = set_pref(prefarg, p, NULL((void*)0), true1);
5203 } else {
5204 ret = prefs_set_uat_pref(p, errmsg) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR;
5205 }
5206 *colonp = ':'; /* put the colon back */
5207 return ret;
5208}
5209
5210unsigned prefs_get_uint_value(pref_t *pref, pref_source_t source)
5211{
5212 switch (source)
5213 {
5214 case pref_default:
5215 return pref->default_val.uint;
5216 case pref_stashed:
5217 return pref->stashed_val.uint;
5218 case pref_current:
5219 return *pref->varp.uint;
5220 default:
5221 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5221
, __func__, "assertion \"not reached\" failed")
;
5222 break;
5223 }
5224
5225 return 0;
5226}
5227
5228unsigned int prefs_set_int_value(pref_t* pref, int value, pref_source_t source)
5229{
5230 int changed = 0;
5231 switch (source)
5232 {
5233 case pref_default:
5234 if (pref->default_val.intval != value) {
5235 pref->default_val.intval = value;
5236 changed = prefs_get_effect_flags(pref);
5237 }
5238 break;
5239 case pref_stashed:
5240 if (pref->stashed_val.intval != value) {
5241 pref->stashed_val.intval = value;
5242 changed = prefs_get_effect_flags(pref);
5243 }
5244 break;
5245 case pref_current:
5246 if (*pref->varp.intp != value) {
5247 *pref->varp.intp = value;
5248 changed = prefs_get_effect_flags(pref);
5249 }
5250 break;
5251 default:
5252 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5252
, __func__, "assertion \"not reached\" failed")
;
5253 break;
5254 }
5255
5256 return changed;
5257}
5258
5259int prefs_get_int_value(pref_t* pref, pref_source_t source)
5260{
5261 switch (source)
5262 {
5263 case pref_default:
5264 return pref->default_val.intval;
5265 case pref_stashed:
5266 return pref->stashed_val.intval;
5267 case pref_current:
5268 return *pref->varp.intp;
5269 default:
5270 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5270
, __func__, "assertion \"not reached\" failed")
;
5271 break;
5272 }
5273
5274 return 0;
5275}
5276
5277unsigned int prefs_set_float_value(pref_t* pref, double value, pref_source_t source)
5278{
5279 int changed = 0;
5280 switch (source)
5281 {
5282 case pref_default:
5283 if (pref->default_val.floatval != value) {
5284 pref->default_val.floatval = value;
5285 changed = prefs_get_effect_flags(pref);
5286 }
5287 break;
5288 case pref_stashed:
5289 if (pref->stashed_val.floatval != value) {
5290 pref->stashed_val.floatval = value;
5291 changed = prefs_get_effect_flags(pref);
5292 }
5293 break;
5294 case pref_current:
5295 if (*pref->varp.floatp != value) {
5296 *pref->varp.floatp = value;
5297 changed = prefs_get_effect_flags(pref);
5298 }
5299 break;
5300 default:
5301 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5301
, __func__, "assertion \"not reached\" failed")
;
5302 break;
5303 }
5304
5305 return changed;
5306}
5307
5308double prefs_get_float_value(pref_t* pref, pref_source_t source)
5309{
5310 switch (source)
5311 {
5312 case pref_default:
5313 return pref->default_val.floatval;
5314 case pref_stashed:
5315 return pref->stashed_val.floatval;
5316 case pref_current:
5317 return *pref->varp.floatp;
5318 default:
5319 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5319
, __func__, "assertion \"not reached\" failed")
;
5320 break;
5321 }
5322
5323 return 0;
5324}
5325
5326
5327const char *prefs_get_password_value(pref_t *pref, pref_source_t source)
5328{
5329 return prefs_get_string_value(pref, source);
5330}
5331
5332
5333unsigned int prefs_set_uint_value(pref_t *pref, unsigned value, pref_source_t source)
5334{
5335 unsigned int changed = 0;
5336 switch (source)
5337 {
5338 case pref_default:
5339 if (pref->default_val.uint != value) {
5340 pref->default_val.uint = value;
5341 changed = prefs_get_effect_flags(pref);
5342 }
5343 break;
5344 case pref_stashed:
5345 if (pref->stashed_val.uint != value) {
5346 pref->stashed_val.uint = value;
5347 changed = prefs_get_effect_flags(pref);
5348 }
5349 break;
5350 case pref_current:
5351 if (*pref->varp.uint != value) {
5352 *pref->varp.uint = value;
5353 changed = prefs_get_effect_flags(pref);
5354 }
5355 break;
5356 default:
5357 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5357
, __func__, "assertion \"not reached\" failed")
;
5358 break;
5359 }
5360
5361 return changed;
5362}
5363
5364/*
5365 * For use by UI code that sets preferences.
5366 */
5367unsigned int
5368prefs_set_password_value(pref_t *pref, const char* value, pref_source_t source)
5369{
5370 return prefs_set_string_value(pref, value, source);
5371}
5372
5373
5374unsigned prefs_get_uint_base(pref_t *pref)
5375{
5376 return pref->info.base;
5377}
5378
5379/*
5380 * Returns true if the given device is hidden
5381 */
5382bool_Bool
5383prefs_is_capture_device_hidden(const char *name)
5384{
5385 char *tok, *devices;
5386 size_t len;
5387
5388 if (prefs.capture_devices_hide && name) {
5389 devices = g_strdup (prefs.capture_devices_hide)g_strdup_inline (prefs.capture_devices_hide);
5390 len = strlen (name);
5391 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5392 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5393 g_free (devices);
5394 return true1;
5395 }
5396 }
5397 g_free (devices);
5398 }
5399
5400 return false0;
5401}
5402
5403/*
5404 * Returns true if the given column is visible (not hidden)
5405 */
5406static bool_Bool
5407prefs_is_column_visible(const char *cols_hidden, int col)
5408{
5409 char *tok, *cols, *p;
5410 int cidx;
5411
5412 /*
5413 * Do we have a list of hidden columns?
5414 */
5415 if (cols_hidden) {
5416 /*
5417 * Yes - check the column against each of the ones in the
5418 * list.
5419 */
5420 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5421 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5422 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5423
5424 cidx = (int)strtol(tok, &p, 10);
5425 if (p == tok || *p != '\0') {
5426 continue;
5427 }
5428 if (cidx != col) {
5429 continue;
5430 }
5431 /*
5432 * OK, they match, so it's one of the hidden fields,
5433 * hence not visible.
5434 */
5435 g_free(cols);
5436 return false0;
5437 }
5438 g_free(cols);
5439 }
5440
5441 /*
5442 * No - either there are no hidden columns or this isn't one
5443 * of them - so it is visible.
5444 */
5445 return true1;
5446}
5447
5448/*
5449 * Returns true if the given column is visible (not hidden)
5450 */
5451static bool_Bool
5452prefs_is_column_fmt_visible(const char *cols_hidden, fmt_data *cfmt)
5453{
5454 char *tok, *cols;
5455 fmt_data cfmt_hidden;
5456
5457 /*
5458 * Do we have a list of hidden columns?
5459 */
5460 if (cols_hidden) {
5461 /*
5462 * Yes - check the column against each of the ones in the
5463 * list.
5464 */
5465 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5466 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5467 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5468
5469 /*
5470 * Parse this column format.
5471 */
5472 if (!parse_column_format(&cfmt_hidden, tok)) {
5473 /*
5474 * It's not valid; ignore it.
5475 */
5476 continue;
5477 }
5478
5479 /*
5480 * Does it match the column?
5481 */
5482 if (cfmt->fmt != cfmt_hidden.fmt) {
5483 /* No. */
5484 g_free(cfmt_hidden.custom_fields);
5485 cfmt_hidden.custom_fields = NULL((void*)0);
5486 continue;
5487 }
5488 if (cfmt->fmt == COL_CUSTOM) {
5489 /*
5490 * A custom column has to have the same custom field
5491 * and occurrence.
5492 */
5493 if (cfmt_hidden.custom_fields && cfmt->custom_fields) {
5494 if (strcmp(cfmt->custom_fields,
5495 cfmt_hidden.custom_fields) != 0) {
5496 /* Different fields. */
5497 g_free(cfmt_hidden.custom_fields);
5498 cfmt_hidden.custom_fields = NULL((void*)0);
5499 continue;
5500 }
5501 if (cfmt->custom_occurrence != cfmt_hidden.custom_occurrence) {
5502 /* Different occurrences settings. */
5503 g_free(cfmt_hidden.custom_fields);
5504 cfmt_hidden.custom_fields = NULL((void*)0);
5505 continue;
5506 }
5507 }
5508 }
5509
5510 /*
5511 * OK, they match, so it's one of the hidden fields,
5512 * hence not visible.
5513 */
5514 g_free(cfmt_hidden.custom_fields);
5515 g_free(cols);
5516 return false0;
5517 }
5518 g_free(cols);
5519 }
5520
5521 /*
5522 * No - either there are no hidden columns or this isn't one
5523 * of them - so it is visible.
5524 */
5525 return true1;
5526}
5527
5528/*
5529 * Returns true if the given device should capture in monitor mode by default
5530 */
5531bool_Bool
5532prefs_capture_device_monitor_mode(const char *name)
5533{
5534 char *tok, *devices;
5535 size_t len;
5536
5537 if (prefs.capture_devices_monitor_mode && name) {
5538 devices = g_strdup (prefs.capture_devices_monitor_mode)g_strdup_inline (prefs.capture_devices_monitor_mode);
5539 len = strlen (name);
5540 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5541 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5542 g_free (devices);
5543 return true1;
5544 }
5545 }
5546 g_free (devices);
5547 }
5548
5549 return false0;
5550}
5551
5552/*
5553 * Returns true if the user has marked this column as visible
5554 */
5555bool_Bool
5556prefs_capture_options_dialog_column_is_visible(const char *column)
5557{
5558 GList *curr;
5559 char *col;
5560
5561 for (curr = g_list_first(prefs.capture_columns); curr; curr = g_list_next(curr)((curr) ? (((GList *)(curr))->next) : ((void*)0))) {
5562 col = (char *)curr->data;
5563 if (col && (g_ascii_strcasecmp(col, column) == 0)) {
5564 return true1;
5565 }
5566 }
5567 return false0;
5568}
5569
5570bool_Bool
5571prefs_has_layout_pane_content (layout_pane_content_e layout_pane_content)
5572{
5573 return ((prefs.gui_layout_content_1 == layout_pane_content) ||
5574 (prefs.gui_layout_content_2 == layout_pane_content) ||
5575 (prefs.gui_layout_content_3 == layout_pane_content));
5576}
5577
5578char
5579string_to_name_resolve(const char *string, e_addr_resolve *name_resolve)
5580{
5581 char c;
5582
5583 memset(name_resolve, 0, sizeof(e_addr_resolve));
5584 while ((c = *string++) != '\0') {
5585 switch (c) {
5586 case 'g':
5587 name_resolve->maxmind_geoip = true1;
5588 break;
5589 case 'm':
5590 name_resolve->mac_name = true1;
5591 break;
5592 case 'n':
5593 name_resolve->network_name = true1;
5594 break;
5595 case 'N':
5596 name_resolve->use_external_net_name_resolver = true1;
5597 break;
5598 case 't':
5599 name_resolve->transport_name = true1;
5600 break;
5601 case 'd':
5602 name_resolve->dns_pkt_addr_resolution = true1;
5603 break;
5604 case 's':
5605 name_resolve->handshake_sni_addr_resolution = true1;
5606 break;
5607 case 'v':
5608 name_resolve->vlan_name = true1;
5609 break;
5610 default:
5611 /*
5612 * Unrecognized letter.
5613 */
5614 return c;
5615 }
5616 }
5617 return '\0';
5618}
5619
5620static bool_Bool
5621deprecated_heur_dissector_pref(char *pref_name, const char *value)
5622{
5623 struct heur_pref_name
5624 {
5625 const char* pref_name;
5626 const char* short_name;
5627 bool_Bool more_dissectors; /* For multiple dissectors controlled by the same preference */
5628 };
5629
5630 static const struct heur_pref_name heur_prefs[] = {
5631 {"acn.heuristic_acn", "acn_udp", 0},
5632 {"bfcp.enable", "bfcp_tcp", 1},
5633 {"bfcp.enable", "bfcp_udp", 0},
5634 {"bt-dht.enable", "bittorrent_dht_udp", 0},
5635 {"bt-utp.enable", "bt_utp_udp", 0},
5636 {"cattp.enable", "cattp_udp", 0},
5637 {"cfp.enable", "fp_eth", 0},
5638 {"dicom.heuristic", "dicom_tcp", 0},
5639 {"dnp3.heuristics", "dnp3_tcp", 1},
5640 {"dnp3.heuristics", "dnp3_udp", 0},
5641 {"dvb-s2_modeadapt.enable", "dvb_s2_udp", 0},
5642 {"esl.enable", "esl_eth", 0},
5643 {"fp.udp_heur", "fp_udp", 0},
5644 {"gvsp.enable_heuristic", "gvsp_udp", 0},
5645 {"hdcp2.enable", "hdcp2_tcp", 0},
5646 {"hislip.enable_heuristic", "hislip_tcp", 0},
5647 {"infiniband.dissect_eoib", "mellanox_eoib", 1},
5648 {"infiniband.identify_payload", "eth_over_ib", 0},
5649 {"jxta.udp.heuristic", "jxta_udp", 0},
5650 {"jxta.tcp.heuristic", "jxta_tcp", 0},
5651 {"jxta.sctp.heuristic", "jxta_sctp", 0},
5652 {"mac-lte.heuristic_mac_lte_over_udp", "mac_lte_udp", 0},
5653 {"mbim.bulk_heuristic", "mbim_usb_bulk", 0},
5654 {"norm.heuristic_norm", "rmt_norm_udp", 0},
5655 {"openflow.heuristic", "openflow_tcp", 0},
5656 {"pdcp-lte.heuristic_pdcp_lte_over_udp", "pdcp_lte_udp", 0},
5657 {"rlc.heuristic_rlc_over_udp", "rlc_udp", 0},
5658 {"rlc-lte.heuristic_rlc_lte_over_udp", "rlc_lte_udp", 0},
5659 {"rtcp.heuristic_rtcp", "rtcp_udp", 1},
5660 {"rtcp.heuristic_rtcp", "rtcp_stun", 0},
5661 {"rtp.heuristic_rtp", "rtp_udp", 1},
5662 {"rtp.heuristic_rtp", "rtp_stun", 0},
5663 {"teredo.heuristic_teredo", "teredo_udp", 0},
5664 {"vssmonitoring.use_heuristics", "vssmonitoring_eth", 0},
5665 {"xml.heuristic", "xml_http", 1},
5666 {"xml.heuristic", "xml_sip", 1},
5667 {"xml.heuristic", "xml_media", 0},
5668 {"xml.heuristic_tcp", "xml_tcp", 0},
5669 {"xml.heuristic_udp", "xml_udp", 0},
5670 };
5671
5672 unsigned int i;
5673 heur_dtbl_entry_t* heuristic;
5674
5675
5676 for (i = 0; i < array_length(heur_prefs)(sizeof (heur_prefs) / sizeof (heur_prefs)[0]); i++)
5677 {
5678 if (strcmp(pref_name, heur_prefs[i].pref_name) == 0)
5679 {
5680 heuristic = find_heur_dissector_by_unique_short_name(heur_prefs[i].short_name);
5681 if (heuristic != NULL((void*)0)) {
5682 heuristic->enabled = ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0);
5683 }
5684
5685 if (!heur_prefs[i].more_dissectors)
5686 return true1;
5687 }
5688 }
5689
5690
5691 return false0;
5692}
5693
5694static bool_Bool
5695deprecated_enable_dissector_pref(char *pref_name, const char *value)
5696{
5697 struct dissector_pref_name
5698 {
5699 const char* pref_name;
5700 const char* short_name;
5701 };
5702
5703 struct dissector_pref_name dissector_prefs[] = {
5704 {"transum.tsumenabled", "TRANSUM"},
5705 {"snort.enable_snort_dissector", "Snort"},
5706 {"prp.enable", "PRP"},
5707 };
5708
5709 unsigned int i;
5710 int proto_id;
5711
5712 for (i = 0; i < array_length(dissector_prefs)(sizeof (dissector_prefs) / sizeof (dissector_prefs)[0]); i++)
5713 {
5714 if (strcmp(pref_name, dissector_prefs[i].pref_name) == 0)
5715 {
5716 proto_id = proto_get_id_by_short_name(dissector_prefs[i].short_name);
5717 if (proto_id >= 0)
5718 proto_set_decoding(proto_id, ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0));
5719 return true1;
5720 }
5721 }
5722
5723 return false0;
5724}
5725
5726static bool_Bool
5727deprecated_port_pref(char *pref_name, const char *value)
5728{
5729 struct port_pref_name
5730 {
5731 const char* pref_name;
5732 const char* module_name; /* the protocol filter name */
5733 const char* table_name;
5734 unsigned base;
5735 };
5736
5737 struct obsolete_pref_name
5738 {
5739 const char* pref_name;
5740 };
5741
5742 /* For now this is only supporting TCP/UDP port and RTP payload
5743 * types dissector preferences, which are assumed to be decimal */
5744 /* module_name is the filter name of the destination port preference,
5745 * which is usually the same as the original module but not
5746 * necessarily (e.g., if the preference is for what is now a PINO.)
5747 * XXX: Most of these were changed pre-2.0. Can we end support
5748 * for migrating legacy preferences at some point?
5749 */
5750 static const struct port_pref_name port_prefs[] = {
5751 /* TCP */
5752 {"cmp.tcp_alternate_port", "cmp", "tcp.port", 10},
5753 {"h248.tcp_port", "h248", "tcp.port", 10},
5754 {"cops.tcp.cops_port", "cops", "tcp.port", 10},
5755 {"dhcpfo.tcp_port", "dhcpfo", "tcp.port", 10},
5756 {"enttec.tcp_port", "enttec", "tcp.port", 10},
5757 {"forces.tcp_alternate_port", "forces", "tcp.port", 10},
5758 {"ged125.tcp_port", "ged125", "tcp.port", 10},
5759 {"hpfeeds.dissector_port", "hpfeeds", "tcp.port", 10},
5760 {"lsc.port", "lsc", "tcp.port", 10},
5761 {"megaco.tcp.txt_port", "megaco", "tcp.port", 10},
5762 {"netsync.tcp_port", "netsync", "tcp.port", 10},
5763 {"osi.tpkt_port", "osi", "tcp.port", 10},
5764 {"rsync.tcp_port", "rsync", "tcp.port", 10},
5765 {"sametime.tcp_port", "sametime", "tcp.port", 10},
5766 {"sigcomp.tcp.port2", "sigcomp", "tcp.port", 10},
5767 {"synphasor.tcp_port", "synphasor", "tcp.port", 10},
5768 {"tipc.alternate_port", "tipc", "tcp.port", 10},
5769 {"vnc.alternate_port", "vnc", "tcp.port", 10},
5770 {"scop.port", "scop", "tcp.port", 10},
5771 {"scop.port_secure", "scop", "tcp.port", 10},
5772 {"tpncp.tcp.trunkpack_port", "tpncp", "tcp.port", 10},
5773 /* UDP */
5774 {"h248.udp_port", "h248", "udp.port", 10},
5775 {"actrace.udp_port", "actrace", "udp.port", 10},
5776 {"brp.port", "brp", "udp.port", 10},
5777 {"bvlc.additional_udp_port", "bvlc", "udp.port", 10},
5778 {"capwap.udp.port.control", "capwap", "udp.port", 10},
5779 {"capwap.udp.port.data", "capwap", "udp.port", 10},
5780 {"coap.udp_port", "coap", "udp.port", 10},
5781 {"enttec.udp_port", "enttec", "udp.port", 10},
5782 {"forces.udp_alternate_port", "forces", "udp.port", 10},
5783 {"ldss.udp_port", "ldss", "udp.port", 10},
5784 {"lmp.udp_port", "lmp", "udp.port", 10},
5785 {"ltp.port", "ltp", "udp.port", 10},
5786 {"lwres.udp.lwres_port", "lwres", "udp.port", 10},
5787 {"megaco.udp.txt_port", "megaco", "udp.port", 10},
5788 {"pfcp.port_pfcp", "pfcp", "udp.port", 10},
5789 {"pgm.udp.encap_ucast_port", "pgm", "udp.port", 10},
5790 {"pgm.udp.encap_mcast_port", "pgm", "udp.port", 10},
5791 {"quic.udp.quic.port", "quic", "udp.port", 10},
5792 {"quic.udp.quics.port", "quic", "udp.port", 10},
5793 {"radius.alternate_port", "radius", "udp.port", 10},
5794 {"rdt.default_udp_port", "rdt", "udp.port", 10},
5795 {"alc.default.udp_port", "alc", "udp.port", 10},
5796 {"sigcomp.udp.port2", "sigcomp", "udp.port", 10},
5797 {"synphasor.udp_port", "synphasor", "udp.port", 10},
5798 {"tdmop.udpport", "tdmop", "udp.port", 10},
5799 {"uaudp.port1", "uaudp", "udp.port", 10},
5800 {"uaudp.port2", "uaudp", "udp.port", 10},
5801 {"uaudp.port3", "uaudp", "udp.port", 10},
5802 {"uaudp.port4", "uaudp", "udp.port", 10},
5803 {"uhd.dissector_port", "uhd", "udp.port", 10},
5804 {"vrt.dissector_port", "vrt", "udp.port", 10},
5805 {"tpncp.udp.trunkpack_port", "tpncp", "udp.port", 10},
5806 /* SCTP */
5807 {"hnbap.port", "hnbap", "sctp.port", 10},
5808 {"m2pa.port", "m2pa", "sctp.port", 10},
5809 {"megaco.sctp.txt_port", "megaco", "sctp.port", 10},
5810 {"rua.port", "rua", "sctp.port", 10},
5811 /* SCTP PPI */
5812 {"lapd.sctp_payload_protocol_identifier", "lapd", "sctp.ppi", 10},
5813 /* SCCP SSN */
5814 {"ranap.sccp_ssn", "ranap", "sccp.ssn", 10},
5815 };
5816
5817 static const struct port_pref_name port_range_prefs[] = {
5818 /* TCP */
5819 {"couchbase.tcp.ports", "couchbase", "tcp.port", 10},
5820 {"gsm_ipa.tcp_ports", "gsm_ipa", "tcp.port", 10},
5821 {"kafka.tcp.ports", "kafka", "tcp.port", 10},
5822 {"kt.tcp.ports", "kt", "tcp.port", 10},
5823 {"memcache.tcp.ports", "memcache", "tcp.port", 10},
5824 {"mrcpv2.tcp.port_range", "mrcpv2", "tcp.port", 10},
5825 {"pdu_transport.ports.tcp", "pdu_transport", "tcp.port", 10},
5826 {"rtsp.tcp.port_range", "rtsp", "tcp.port", 10},
5827 {"sip.tcp.ports", "sip", "tcp.port", 10},
5828 {"someip.ports.tcp", "someip", "tcp.port", 10},
5829 {"tds.tcp_ports", "tds", "tcp.port", 10},
5830 {"tpkt.tcp.ports", "tpkt", "tcp.port", 10},
5831 {"uma.tcp.ports", "uma", "tcp.port", 10},
5832 /* UDP */
5833 {"aruba_erm.udp.ports", "arubs_erm", "udp.port", 10},
5834 {"diameter.udp.ports", "diameter", "udp.port", 10},
5835 {"dmp.udp_ports", "dmp", "udp.port", 10},
5836 {"dns.udp.ports", "dns", "udp.port", 10},
5837 {"gsm_ipa.udp_ports", "gsm_ipa", "udp.port", 10},
5838 {"hcrt.dissector_udp_port", "hcrt", "udp.port", 10},
5839 {"memcache.udp.ports", "memcache", "udp.port", 10},
5840 {"nb_rtpmux.udp_ports", "nb_rtpmux", "udp.port", 10},
5841 {"gprs-ns.udp.ports", "gprs-ns", "udp.port", 10},
5842 {"p_mul.udp_ports", "p_mul", "udp.port", 10},
5843 {"pdu_transport.ports.udp", "pdu_transport", "udp.port", 10},
5844 {"radius.ports", "radius", "udp.port", 10},
5845 {"sflow.ports", "sflow", "udp.port", 10},
5846 {"someip.ports.udp", "someip", "udp.port", 10},
5847 {"sscop.udp.ports", "sscop", "udp.port", 10},
5848 {"tftp.udp_ports", "tftp", "udp.port", 10},
5849 {"tipc.udp.ports", "tipc", "udp.port", 10},
5850 /* RTP */
5851 {"amr.dynamic.payload.type", "amr", "rtp.pt", 10},
5852 {"amr.wb.dynamic.payload.type", "amr_wb", "rtp.pt", 10},
5853 {"dvb-s2_modeadapt.dynamic.payload.type", "dvb-s2_modeadapt", "rtp.pt", 10},
5854 {"evs.dynamic.payload.type", "evs", "rtp.pt", 10},
5855 {"h263p.dynamic.payload.type", "h263p", "rtp.pt", 10},
5856 {"h264.dynamic.payload.type", "h264", "rtp.pt", 10},
5857 {"h265.dynamic.payload.type", "h265", "rtp.pt", 10},
5858 {"ismacryp.dynamic.payload.type", "ismacryp", "rtp.pt", 10},
5859 {"iuup.dynamic.payload.type", "iuup", "rtp.pt", 10},
5860 {"lapd.rtp_payload_type", "lapd", "rtp.pt", 10},
5861 {"mp4ves.dynamic.payload.type", "mp4ves", "rtp.pt", 10},
5862 {"mtp2.rtp_payload_type", "mtp2", "rtp.pt", 10},
5863 {"opus.dynamic.payload.type", "opus", "rtp.pt", 10},
5864 {"rtp.rfc2198_payload_type", "rtp_rfc2198", "rtp.pt", 10},
5865 {"rtpevent.event_payload_type_value", "rtpevent", "rtp.pt", 10},
5866 {"rtpevent.cisco_nse_payload_type_value", "rtpevent", "rtp.pt", 10},
5867 {"rtpmidi.midi_payload_type_value", "rtpmidi", "rtp.pt", 10},
5868 {"vp8.dynamic.payload.type", "vp8", "rtp.pt", 10},
5869 /* SCTP */
5870 {"diameter.sctp.ports", "diameter", "sctp.port", 10},
5871 {"sgsap.sctp_ports", "sgsap", "sctp.port", 10},
5872 /* SCCP SSN */
5873 {"pcap.ssn", "pcap", "sccp.ssn", 10},
5874 };
5875
5876 /* These are subdissectors of TPKT/OSITP that used to have a
5877 TCP port preference even though they were never
5878 directly on TCP. Convert them to use Decode As
5879 with the TPKT dissector handle */
5880 static const struct port_pref_name tpkt_subdissector_port_prefs[] = {
5881 {"dap.tcp.port", "dap", "tcp.port", 10},
5882 {"disp.tcp.port", "disp", "tcp.port", 10},
5883 {"dop.tcp.port", "dop", "tcp.port", 10},
5884 {"dsp.tcp.port", "dsp", "tcp.port", 10},
5885 {"p1.tcp.port", "p1", "tcp.port", 10},
5886 {"p7.tcp.port", "p7", "tcp.port", 10},
5887 {"rdp.tcp.port", "rdp", "tcp.port", 10},
5888 };
5889
5890 /* These are obsolete preferences from the dissectors' view,
5891 (typically because of a switch from a single value to a
5892 range value) but the name of the preference conflicts
5893 with the generated preference name from the dissector table.
5894 Don't allow the obsolete preference through to be handled */
5895 static const struct obsolete_pref_name obsolete_prefs[] = {
5896 {"diameter.tcp.port"},
5897 {"kafka.tcp.port"},
5898 {"mrcpv2.tcp.port"},
5899 {"rtsp.tcp.port"},
5900 {"sip.tcp.port"},
5901 {"t38.tcp.port"},
5902 };
5903
5904 unsigned int i;
5905 unsigned uval;
5906 dissector_table_t sub_dissectors;
5907 dissector_handle_t handle, tpkt_handle;
5908 module_t *module;
5909 pref_t *pref;
5910
5911 static bool_Bool sanity_checked;
5912 if (!sanity_checked) {
5913 sanity_checked = true1;
5914 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5915 module = prefs_find_module(port_prefs[i].module_name);
5916 if (!module) {
5917 // We might not be Wireshark, and therefore might not have deprecated port prefs.
5918 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"
, 5918, __func__, "Deprecated ports pref check - module '%s' not found"
, port_prefs[i].module_name); } } while (0)
;
5919 continue;
5920 }
5921 pref = prefs_find_preference(module, port_prefs[i].table_name);
5922 if (!pref) {
5923 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"
, 5923, __func__, "Deprecated ports pref '%s.%s' not found", module
->name, port_prefs[i].table_name); } } while (0)
;
5924 continue;
5925 }
5926 if (pref->type != PREF_DECODE_AS_RANGE) {
5927 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"
, 5927, __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)
;
5928 }
5929 }
5930 }
5931
5932 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5933 if (strcmp(pref_name, port_prefs[i].pref_name) == 0) {
5934 if (!ws_basestrtou32(value, NULL((void*)0), &uval, port_prefs[i].base))
5935 return false0; /* number was bad */
5936
5937 module = prefs_find_module(port_prefs[i].module_name);
5938 pref = prefs_find_preference(module, port_prefs[i].table_name);
5939 if (pref != NULL((void*)0)) {
5940 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5941 if (pref->type == PREF_DECODE_AS_RANGE) {
5942 // The legacy preference was a port number, but the new
5943 // preference is a port range. Add to existing range.
5944 if (uval) {
5945 prefs_range_add_value(pref, uval);
5946 }
5947 }
5948 }
5949
5950 /* If the value is zero, it wouldn't add to the Decode As tables */
5951 if (uval != 0)
5952 {
5953 sub_dissectors = find_dissector_table(port_prefs[i].table_name);
5954 if (sub_dissectors != NULL((void*)0)) {
5955 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5956 if (handle != NULL((void*)0)) {
5957 dissector_change_uint(port_prefs[i].table_name, uval, handle);
5958 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));
5959 }
5960 }
5961 }
5962
5963 return true1;
5964 }
5965 }
5966
5967 for (i = 0; i < array_length(port_range_prefs)(sizeof (port_range_prefs) / sizeof (port_range_prefs)[0]); i++)
5968 {
5969 if (strcmp(pref_name, port_range_prefs[i].pref_name) == 0)
5970 {
5971 uint32_t range_i, range_j;
5972
5973 sub_dissectors = find_dissector_table(port_range_prefs[i].table_name);
5974 if (sub_dissectors != NULL((void*)0)) {
5975 switch (dissector_table_get_type(sub_dissectors)) {
5976 case FT_UINT8:
5977 case FT_UINT16:
5978 case FT_UINT24:
5979 case FT_UINT32:
5980 break;
5981
5982 default:
5983 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", 5983
, __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))
;
5984 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5984
, __func__, "assertion \"not reached\" failed")
;
5985 }
5986
5987 module = prefs_find_module(port_range_prefs[i].module_name);
5988 pref = prefs_find_preference(module, port_range_prefs[i].table_name);
5989 if (pref != NULL((void*)0))
5990 {
5991 if (!prefs_set_range_value_work(pref, value, true1, &module->prefs_changed_flags))
5992 {
5993 return false0; /* number was bad */
5994 }
5995
5996 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5997 if (handle != NULL((void*)0)) {
5998
5999 for (range_i = 0; range_i < (*pref->varp.range)->nranges; range_i++) {
6000 for (range_j = (*pref->varp.range)->ranges[range_i].low; range_j < (*pref->varp.range)->ranges[range_i].high; range_j++) {
6001 dissector_change_uint(port_range_prefs[i].table_name, range_j, handle);
6002 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));
6003 }
6004
6005 dissector_change_uint(port_range_prefs[i].table_name, (*pref->varp.range)->ranges[range_i].high, handle);
6006 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));
6007 }
6008 }
6009 }
6010 }
6011
6012 return true1;
6013 }
6014 }
6015
6016 for (i = 0; i < array_length(tpkt_subdissector_port_prefs)(sizeof (tpkt_subdissector_port_prefs) / sizeof (tpkt_subdissector_port_prefs
)[0])
; i++)
6017 {
6018 if (strcmp(pref_name, tpkt_subdissector_port_prefs[i].pref_name) == 0)
6019 {
6020 /* XXX - give an error if it doesn't fit in a unsigned? */
6021 if (!ws_basestrtou32(value, NULL((void*)0), &uval, tpkt_subdissector_port_prefs[i].base))
6022 return false0; /* number was bad */
6023
6024 /* If the value is 0 or 102 (default TPKT port), don't add to the Decode As tables */
6025 if ((uval != 0) && (uval != 102))
6026 {
6027 tpkt_handle = find_dissector("tpkt");
6028 if (tpkt_handle != NULL((void*)0)) {
6029 dissector_change_uint(tpkt_subdissector_port_prefs[i].table_name, uval, tpkt_handle);
6030 }
6031 }
6032
6033 return true1;
6034 }
6035 }
6036
6037 for (i = 0; i < array_length(obsolete_prefs)(sizeof (obsolete_prefs) / sizeof (obsolete_prefs)[0]); i++)
6038 {
6039 if (strcmp(pref_name, obsolete_prefs[i].pref_name) == 0)
6040 {
6041 /* Just ignore the preference */
6042 return true1;
6043 }
6044 }
6045 return false0;
6046}
6047
6048static prefs_set_pref_e
6049set_pref(char *pref_name, const char *value, void *private_data,
6050 bool_Bool return_range_errors)
6051{
6052 unsigned cval;
6053 unsigned uval;
6054 bool_Bool bval;
6055 int enum_val, ival;
6056 double fval;
6057 char *dotp, *last_dotp;
6058 module_t *module, *containing_module, *target_module;
6059 pref_t *pref;
6060 bool_Bool converted_pref = false0;
6061
6062 target_module = (module_t*)private_data;
6063
6064 if (deprecated_heur_dissector_pref(pref_name, value)) {
6065 /* Handled within deprecated_heur_dissector_pref() if found */
6066 } else if (deprecated_enable_dissector_pref(pref_name, value)) {
6067 /* Handled within deprecated_enable_dissector_pref() if found */
6068 } else if (deprecated_port_pref(pref_name, value)) {
6069 /* Handled within deprecated_port_pref() if found */
6070 } else if (strcmp(pref_name, "console.log.level") == 0) {
6071 /* Handled on the command line within ws_log_parse_args() */
6072 return PREFS_SET_OK;
6073 } else {
6074 /* To which module does this preference belong? */
6075 module = NULL((void*)0);
6076 last_dotp = pref_name;
6077 while (!module) {
6078 dotp = strchr(last_dotp, '.');
6079 if (dotp == NULL((void*)0)) {
6080 /* Either there's no such module, or no module was specified.
6081 In either case, that means there's no such preference. */
6082 return PREFS_SET_NO_SUCH_PREF;
6083 }
6084 *dotp = '\0'; /* separate module and preference name */
6085 module = prefs_find_module(pref_name);
6086
6087 /*
6088 * XXX - "Diameter" rather than "diameter" was used in earlier
6089 * versions of Wireshark; if we didn't find the module, and its name
6090 * was "Diameter", look for "diameter" instead.
6091 *
6092 * In addition, the BEEP protocol used to be the BXXP protocol,
6093 * so if we didn't find the module, and its name was "bxxp",
6094 * look for "beep" instead.
6095 *
6096 * Also, the preferences for GTP v0 and v1 were combined under
6097 * a single "gtp" heading, and the preferences for SMPP were
6098 * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
6099 * However, SMPP now has its own preferences, so we just map
6100 * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
6101 *
6102 * We also renamed "dcp" to "dccp", "x.25" to "x25", "x411" to "p1"
6103 * and "nsip" to "gprs_ns".
6104 *
6105 * The SynOptics Network Management Protocol (SONMP) is now known by
6106 * its modern name, the Nortel Discovery Protocol (NDP).
6107 */
6108 if (module == NULL((void*)0)) {
6109 /*
6110 * See if there's a backwards-compatibility name
6111 * that maps to this module.
6112 */
6113 module = prefs_find_module_alias(pref_name);
6114 if (module == NULL((void*)0)) {
6115 /*
6116 * There's no alias for the module; see if the
6117 * module name matches any protocol aliases.
6118 */
6119 header_field_info *hfinfo = proto_registrar_get_byalias(pref_name);
6120 if (hfinfo) {
6121 module = (module_t *) wmem_tree_lookup_string(prefs_modules, hfinfo->abbrev, WMEM_TREE_STRING_NOCASE0x00000001);
6122 }
6123 }
6124 if (module) {
6125 converted_pref = true1;
6126 }
6127 }
6128 *dotp = '.'; /* put the preference string back */
6129 dotp++; /* skip past separator to preference name */
6130 last_dotp = dotp;
6131 }
6132
6133 /* The pref is located in the module or a submodule.
6134 * Assume module, then search for a submodule holding the pref. */
6135 containing_module = module;
6136 pref = prefs_find_preference_with_submodule(module, dotp, &containing_module);
6137
6138 if (pref == NULL((void*)0)) {
6139 /* "gui" prefix was added to column preferences for better organization
6140 * within the preferences file
6141 */
6142 if (module == gui_column_module) {
6143 /* While this has a subtree, there is no apply callback, so no
6144 * need to use prefs_find_preference_with_submodule to update
6145 * containing_module. It would not be useful. */
6146 pref = prefs_find_preference(module, pref_name);
6147 }
6148 else if (strcmp(module->name, "tcp") == 0) {
6149 /* Handle old names for TCP preferences. */
6150 if (strcmp(dotp, "dissect_experimental_options_with_magic") == 0)
6151 pref = prefs_find_preference(module, "dissect_experimental_options_rfc6994");
6152 } else if (strcmp(module->name, "extcap") == 0) {
6153 /* Handle the old "sshdump.remotesudo" preference; map it to the new
6154 "sshdump.remotepriv" preference, and map the boolean values to the
6155 appropriate strings of the new preference. */
6156 if (strcmp(dotp, "sshdump.remotesudo") == 0) {
6157 pref = prefs_find_preference(module, "sshdump.remotepriv");
6158 if (g_ascii_strcasecmp(value, "true") == 0)
6159 value = "sudo";
6160 else
6161 value = "none";
6162 }
6163 }
6164 if (pref) {
6165 converted_pref = true1;
6166 }
6167 }
6168 if (pref == NULL((void*)0) ) {
6169 if (strcmp(module->name, "extcap") == 0 && g_list_length(module->prefs) <= 1) {
6170 /*
6171 * Assume that we've skipped extcap preference registration
6172 * and that only extcap.gui_save_on_start is loaded.
6173 */
6174 return PREFS_SET_OK;
6175 }
6176 return PREFS_SET_NO_SUCH_PREF; /* no such preference */
6177 }
6178
6179 if (target_module && target_module != containing_module) {
6180 /* Ignore */
6181 return PREFS_SET_OK;
6182 }
6183
6184 if (pref->obsolete)
6185 return PREFS_SET_OBSOLETE; /* no such preference any more */
6186
6187 if (converted_pref) {
6188 ws_warning("Preference \"%s\" has been converted to \"%s.%s\"\n"do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6190, __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)
6189 "Save your preferences to make this change permanent.",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6190, __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)
6190 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"
, 6190, __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)
;
6191 }
6192
6193 switch (pref->type) {
6194
6195 case PREF_UINT:
6196 if (!ws_basestrtou32(value, NULL((void*)0), &uval, pref->info.base))
6197 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6198 if (*pref->varp.uint != uval) {
6199 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6200 *pref->varp.uint = uval;
6201 }
6202 break;
6203
6204 case PREF_INT:
6205 if (!ws_strtoi32(value, NULL((void*)0), &ival))
6206 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6207 if (*pref->varp.intp != ival) {
6208 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6209 *pref->varp.intp = ival;
6210 }
6211 break;
6212
6213 case PREF_FLOAT:
6214 fval = g_ascii_strtod(value, NULL((void*)0));
6215 if (errno(*__errno_location ()) == ERANGE34)
6216 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6217
6218 if (*pref->varp.floatp != fval) {
6219 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6220 *pref->varp.floatp = fval;
6221 }
6222 break;
6223
6224 case PREF_BOOL:
6225 /* XXX - give an error if it's neither "true" nor "false"? */
6226 if (g_ascii_strcasecmp(value, "true") == 0)
6227 bval = true1;
6228 else
6229 bval = false0;
6230 if (*pref->varp.boolp != bval) {
6231 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6232 *pref->varp.boolp = bval;
6233 }
6234 break;
6235
6236 case PREF_ENUM:
6237 /* XXX - give an error if it doesn't match? */
6238 enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
6239 *pref->varp.enump);
6240 if (*pref->varp.enump != enum_val) {
6241 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6242 *pref->varp.enump = enum_val;
6243 }
6244 break;
6245
6246 case PREF_STRING:
6247 case PREF_SAVE_FILENAME:
6248 case PREF_OPEN_FILENAME:
6249 case PREF_DIRNAME:
6250 case PREF_DISSECTOR:
6251 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
6252 break;
6253
6254 case PREF_PASSWORD:
6255 /* Read value is every time empty */
6256 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, "", pref_current);
6257 break;
6258
6259 case PREF_RANGE:
6260 {
6261 if (!prefs_set_range_value_work(pref, value, return_range_errors,
6262 &containing_module->prefs_changed_flags))
6263 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6264 break;
6265 }
6266 case PREF_DECODE_AS_RANGE:
6267 {
6268 /* This is for backwards compatibility in case any of the preferences
6269 that shared the "Decode As" preference name and used to be PREF_RANGE
6270 are now applied directly to the Decode As functionality */
6271 range_t *newrange;
6272 dissector_table_t sub_dissectors;
6273 dissector_handle_t handle;
6274 uint32_t i, j;
6275
6276 if (range_convert_str_work(pref->scope, &newrange, value, pref->info.max_value,
6277 return_range_errors) != CVT_NO_ERROR) {
6278 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6279 }
6280
6281 if (!ranges_are_equal(*pref->varp.range, newrange)) {
6282 wmem_free(pref->scope, *pref->varp.range);
6283 *pref->varp.range = newrange;
6284 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6285
6286 const char* table_name = prefs_get_dissector_table(pref);
6287 sub_dissectors = find_dissector_table(table_name);
6288 if (sub_dissectors != NULL((void*)0)) {
6289 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
6290 if (handle != NULL((void*)0)) {
6291 /* Delete all of the old values from the dissector table */
6292 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
6293 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
6294 dissector_delete_uint(table_name, j, handle);
6295 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));
6296 }
6297
6298 dissector_delete_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
6299 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));
6300 }
6301
6302 /* Add new values to the dissector table */
6303 for (i = 0; i < newrange->nranges; i++) {
6304 for (j = newrange->ranges[i].low; j < newrange->ranges[i].high; j++) {
6305 dissector_change_uint(table_name, j, handle);
6306 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));
6307 }
6308
6309 dissector_change_uint(table_name, newrange->ranges[i].high, handle);
6310 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));
6311 }
6312
6313 /* XXX - Do we save the decode_as_entries file here? */
6314 }
6315 }
6316 } else {
6317 wmem_free(pref->scope, newrange);
6318 }
6319 break;
6320 }
6321
6322 case PREF_COLOR:
6323 {
6324 if (!ws_hexstrtou32(value, NULL((void*)0), &cval))
6325 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6326 if ((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 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6330 pref->varp.colorp->red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
6331 pref->varp.colorp->green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
6332 pref->varp.colorp->blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
6333 }
6334 break;
6335 }
6336
6337 case PREF_CUSTOM:
6338 return pref->custom_cbs.set_cb(pref, value, &containing_module->prefs_changed_flags);
6339
6340 case PREF_STATIC_TEXT:
6341 case PREF_UAT:
6342 break;
6343
6344 case PREF_PROTO_TCP_SNDAMB_ENUM:
6345 {
6346 /* There's no point in setting the TCP sequence override
6347 * value from the command line, because the pref is different
6348 * for each frame and reset to the default (0) for each new
6349 * file.
6350 */
6351 break;
6352 }
6353 }
6354 }
6355
6356 return PREFS_SET_OK;
6357}
6358
6359typedef struct {
6360 FILE *pf;
6361 bool_Bool is_gui_module;
6362} write_gui_pref_arg_t;
6363
6364const char *
6365prefs_pref_type_name(pref_t *pref)
6366{
6367 const char *type_name = "[Unknown]";
6368
6369 if (!pref) {
6370 return type_name; /* ...or maybe assert? */
6371 }
6372
6373 if (pref->obsolete) {
6374 type_name = "Obsolete";
6375 } else {
6376 switch (pref->type) {
6377
6378 case PREF_UINT:
6379 switch (pref->info.base) {
6380
6381 case 10:
6382 type_name = "Decimal";
6383 break;
6384
6385 case 8:
6386 type_name = "Octal";
6387 break;
6388
6389 case 16:
6390 type_name = "Hexadecimal";
6391 break;
6392 }
6393 break;
6394
6395 case PREF_INT:
6396 type_name = "Integer";
6397 break;
6398
6399 case PREF_FLOAT:
6400 type_name = "Float";
6401 break;
6402
6403 case PREF_BOOL:
6404 type_name = "Boolean";
6405 break;
6406
6407 case PREF_ENUM:
6408 case PREF_PROTO_TCP_SNDAMB_ENUM:
6409 type_name = "Choice";
6410 break;
6411
6412 case PREF_STRING:
6413 type_name = "String";
6414 break;
6415
6416 case PREF_SAVE_FILENAME:
6417 case PREF_OPEN_FILENAME:
6418 type_name = "Filename";
6419 break;
6420
6421 case PREF_DIRNAME:
6422 type_name = "Directory";
6423 break;
6424
6425 case PREF_RANGE:
6426 type_name = "Range";
6427 break;
6428
6429 case PREF_COLOR:
6430 type_name = "Color";
6431 break;
6432
6433 case PREF_CUSTOM:
6434 if (pref->custom_cbs.type_name_cb)
6435 return pref->custom_cbs.type_name_cb();
6436 type_name = "Custom";
6437 break;
6438
6439 case PREF_DECODE_AS_RANGE:
6440 type_name = "Range (for Decode As)";
6441 break;
6442
6443 case PREF_STATIC_TEXT:
6444 type_name = "Static text";
6445 break;
6446
6447 case PREF_UAT:
6448 type_name = "UAT";
6449 break;
6450
6451 case PREF_PASSWORD:
6452 type_name = "Password";
6453 break;
6454
6455 case PREF_DISSECTOR:
6456 type_name = "Dissector";
6457 break;
6458 }
6459 }
6460
6461 return type_name;
6462}
6463
6464unsigned int
6465prefs_get_effect_flags(pref_t *pref)
6466{
6467 if (pref == NULL((void*)0))
6468 return 0;
6469
6470 return pref->effect_flags;
6471}
6472
6473void
6474prefs_set_effect_flags(pref_t *pref, unsigned int flags)
6475{
6476 if (pref != NULL((void*)0)) {
6477 if (flags == 0) {
6478 ws_error("Setting \"%s\" preference effect flags to 0", pref->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6478
, __func__, "Setting \"%s\" preference effect flags to 0", pref
->name)
;
6479 }
6480 pref->effect_flags = flags;
6481 }
6482}
6483
6484void
6485prefs_set_effect_flags_by_name(module_t * module, const char *pref, unsigned int flags)
6486{
6487 prefs_set_effect_flags(prefs_find_preference(module, pref), flags);
6488}
6489
6490unsigned int
6491prefs_get_module_effect_flags(module_t * module)
6492{
6493 if (module == NULL((void*)0))
6494 return 0;
6495
6496 return module->effect_flags;
6497}
6498
6499void
6500prefs_set_module_effect_flags(module_t * module, unsigned int flags)
6501{
6502 if (module != NULL((void*)0)) {
6503 if (flags == 0) {
6504 ws_error("Setting module \"%s\" preference effect flags to 0", module->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6504
, __func__, "Setting module \"%s\" preference effect flags to 0"
, module->name)
;
6505 }
6506 module->effect_flags = flags;
6507 }
6508}
6509
6510char *
6511prefs_pref_type_description(pref_t *pref)
6512{
6513 const char *type_desc = "An unknown preference type";
6514
6515 if (!pref) {
6516 return ws_strdup_printf("%s.", type_desc)wmem_strdup_printf(((void*)0), "%s.", type_desc); /* ...or maybe assert? */
6517 }
6518
6519 if (pref->obsolete) {
6520 type_desc = "An obsolete preference";
6521 } else {
6522 switch (pref->type) {
6523
6524 case PREF_UINT:
6525 switch (pref->info.base) {
6526
6527 case 10:
6528 type_desc = "A decimal number";
6529 break;
6530
6531 case 8:
6532 type_desc = "An octal number";
6533 break;
6534
6535 case 16:
6536 type_desc = "A hexadecimal number";
6537 break;
6538 }
6539 break;
6540
6541 case PREF_INT:
6542 type_desc = "A decimal number";
6543 break;
6544
6545 case PREF_FLOAT:
6546 type_desc = "A floating point number";
6547 break;
6548
6549 case PREF_BOOL:
6550 type_desc = "true or false (case-insensitive)";
6551 break;
6552
6553 case PREF_ENUM:
6554 case PREF_PROTO_TCP_SNDAMB_ENUM:
6555 {
6556 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6557 GString *enum_str = g_string_new("One of: ");
6558 GString *desc_str = g_string_new("\nEquivalently, one of: ");
6559 bool_Bool distinct = false0;
6560 while (enum_valp->name != NULL((void*)0)) {
6561 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))
;
6562 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))
;
6563 if (g_strcmp0(enum_valp->name, enum_valp->description) != 0) {
6564 distinct = true1;
6565 }
6566 enum_valp++;
6567 if (enum_valp->name != NULL((void*)0)) {
6568 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))
;
6569 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))
;
6570 }
6571 }
6572 if (distinct) {
6573 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))
;
6574 }
6575 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)))))
;
6576 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))
;
6577 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))))
;
6578 }
6579
6580 case PREF_STRING:
6581 type_desc = "A string";
6582 break;
6583
6584 case PREF_SAVE_FILENAME:
6585 case PREF_OPEN_FILENAME:
6586 type_desc = "A path to a file";
6587 break;
6588
6589 case PREF_DIRNAME:
6590 type_desc = "A path to a directory";
6591 break;
6592
6593 case PREF_RANGE:
6594 {
6595 type_desc = "A string denoting an positive integer range (e.g., \"1-20,30-40\")";
6596 break;
6597 }
6598
6599 case PREF_COLOR:
6600 {
6601 type_desc = "A six-digit hexadecimal RGB color triplet (e.g. fce94f)";
6602 break;
6603 }
6604
6605 case PREF_CUSTOM:
6606 if (pref->custom_cbs.type_description_cb)
6607 return pref->custom_cbs.type_description_cb();
6608 type_desc = "A custom value";
6609 break;
6610
6611 case PREF_DECODE_AS_RANGE:
6612 type_desc = "A string denoting an positive integer range for Decode As";
6613 break;
6614
6615 case PREF_STATIC_TEXT:
6616 type_desc = "[Static text]";
6617 break;
6618
6619 case PREF_UAT:
6620 type_desc = "Configuration data stored in its own file";
6621 break;
6622
6623 case PREF_PASSWORD:
6624 type_desc = "Password (never stored on disk)";
6625 break;
6626
6627 case PREF_DISSECTOR:
6628 type_desc = "A dissector name";
6629 break;
6630
6631 default:
6632 break;
6633 }
6634 }
6635
6636 return g_strdup(type_desc)g_strdup_inline (type_desc);
6637}
6638
6639bool_Bool
6640prefs_pref_is_default(pref_t *pref)
6641{
6642 if (!pref) return false0;
6643
6644 if (pref->obsolete) {
6645 return false0;
6646 }
6647
6648 switch (pref->type) {
6649
6650 case PREF_UINT:
6651 if (pref->default_val.uint == *pref->varp.uint)
6652 return true1;
6653 break;
6654
6655 case PREF_INT:
6656 if (pref->default_val.intval == *pref->varp.intp)
6657 return true1;
6658 break;
6659
6660 case PREF_FLOAT:
6661 if (pref->default_val.floatval == *pref->varp.floatp)
6662 return true1;
6663 break;
6664
6665 case PREF_BOOL:
6666 if (pref->default_val.boolval == *pref->varp.boolp)
6667 return true1;
6668 break;
6669
6670 case PREF_ENUM:
6671 case PREF_PROTO_TCP_SNDAMB_ENUM:
6672 if (pref->default_val.enumval == *pref->varp.enump)
6673 return true1;
6674 break;
6675
6676 case PREF_STRING:
6677 case PREF_SAVE_FILENAME:
6678 case PREF_OPEN_FILENAME:
6679 case PREF_DIRNAME:
6680 case PREF_PASSWORD:
6681 case PREF_DISSECTOR:
6682 if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
6683 return true1;
6684 break;
6685
6686 case PREF_DECODE_AS_RANGE:
6687 case PREF_RANGE:
6688 {
6689 if ((ranges_are_equal(pref->default_val.range, *pref->varp.range)))
6690 return true1;
6691 break;
6692 }
6693
6694 case PREF_COLOR:
6695 {
6696 if ((pref->default_val.color.red == pref->varp.colorp->red) &&
6697 (pref->default_val.color.green == pref->varp.colorp->green) &&
6698 (pref->default_val.color.blue == pref->varp.colorp->blue))
6699 return true1;
6700 break;
6701 }
6702
6703 case PREF_CUSTOM:
6704 return pref->custom_cbs.is_default_cb(pref);
6705
6706 case PREF_STATIC_TEXT:
6707 case PREF_UAT:
6708 return false0;
6709 /* ws_assert_not_reached(); */
6710 break;
6711 }
6712
6713 return false0;
6714}
6715
6716char *
6717prefs_pref_to_str(pref_t *pref, pref_source_t source)
6718{
6719 const char *pref_text = "[Unknown]";
6720 void *valp; /* pointer to preference value */
6721 color_t *pref_color;
6722 char *tmp_value, *ret_value;
6723
6724 if (!pref) {
6725 return g_strdup(pref_text)g_strdup_inline (pref_text);
6726 }
6727
6728 switch (source) {
6729 case pref_default:
6730 valp = &pref->default_val;
6731 /* valp = &boolval, &enumval, etc. are implied by union property */
6732 pref_color = &pref->default_val.color;
6733 break;
6734 case pref_stashed:
6735 valp = &pref->stashed_val;
6736 /* valp = &boolval, &enumval, etc. are implied by union property */
6737 pref_color = &pref->stashed_val.color;
6738 break;
6739 case pref_current:
6740 valp = pref->varp.uint;
6741 /* valp = boolval, enumval, etc. are implied by union property */
6742 pref_color = pref->varp.colorp;
6743 break;
6744 default:
6745 return g_strdup(pref_text)g_strdup_inline (pref_text);
6746 }
6747
6748 if (pref->obsolete) {
6749 pref_text = "[Obsolete]";
6750 } else {
6751 switch (pref->type) {
6752
6753 case PREF_UINT:
6754 {
6755 unsigned pref_uint = *(unsigned *) valp;
6756 switch (pref->info.base) {
6757
6758 case 10:
6759 return ws_strdup_printf("%u", pref_uint)wmem_strdup_printf(((void*)0), "%u", pref_uint);
6760
6761 case 8:
6762 return ws_strdup_printf("%#o", pref_uint)wmem_strdup_printf(((void*)0), "%#o", pref_uint);
6763
6764 case 16:
6765 return ws_strdup_printf("%#x", pref_uint)wmem_strdup_printf(((void*)0), "%#x", pref_uint);
6766 }
6767 break;
6768 }
6769 case PREF_INT:
6770 return ws_strdup_printf("%d", *(int*)valp)wmem_strdup_printf(((void*)0), "%d", *(int*)valp);
6771
6772 case PREF_FLOAT:
6773 return ws_strdup_printf("%.*f", pref->info.base, *(double*)valp)wmem_strdup_printf(((void*)0), "%.*f", pref->info.base, *(
double*)valp)
;
6774
6775 case PREF_BOOL:
6776 return g_strdup((*(bool *) valp) ? "TRUE" : "FALSE")g_strdup_inline ((*(_Bool *) valp) ? "TRUE" : "FALSE");
6777
6778 case PREF_ENUM:
6779 case PREF_PROTO_TCP_SNDAMB_ENUM:
6780 {
6781 int pref_enumval = *(int *) valp;
6782 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6783 /*
6784 * TODO - We write the "description" value, because the "name" values
6785 * weren't validated to be command line friendly until 5.0, and a few
6786 * of them had to be changed. This allows older versions of Wireshark
6787 * to read preferences that they supported, as we supported either
6788 * the short name or the description when reading the preference files
6789 * or an "-o" option. Once 5.0 is the oldest supported version, switch
6790 * to writing the name below.
6791 */
6792 while (enum_valp->name != NULL((void*)0)) {
6793 if (enum_valp->value == pref_enumval)
6794 return g_strdup(enum_valp->description)g_strdup_inline (enum_valp->description);
6795 enum_valp++;
6796 }
6797 break;
6798 }
6799
6800 case PREF_STRING:
6801 case PREF_SAVE_FILENAME:
6802 case PREF_OPEN_FILENAME:
6803 case PREF_DIRNAME:
6804 case PREF_PASSWORD:
6805 case PREF_DISSECTOR:
6806 return prefs_sanitize_string(*(const char **) valp);
6807
6808 case PREF_DECODE_AS_RANGE:
6809 case PREF_RANGE:
6810 /* Convert wmem to g_alloc memory */
6811 tmp_value = range_convert_range(NULL((void*)0), *(range_t **) valp);
6812 ret_value = g_strdup(tmp_value)g_strdup_inline (tmp_value);
6813 wmem_free(NULL((void*)0), tmp_value);
6814 return ret_value;
6815
6816 case PREF_COLOR:
6817 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))
6818 (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))
6819 (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))
6820 (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))
;
6821
6822 case PREF_CUSTOM:
6823 if (pref->custom_cbs.to_str_cb)
6824 return pref->custom_cbs.to_str_cb(pref, source == pref_default ? true1 : false0);
6825 pref_text = "[Custom]";
6826 break;
6827
6828 case PREF_STATIC_TEXT:
6829 pref_text = "[Static text]";
6830 break;
6831
6832 case PREF_UAT:
6833 {
6834 uat_t *uat = pref->varp.uat;
6835 if (uat && uat->filename)
6836 return ws_strdup_printf("[Managed in the file \"%s\"]", uat->filename)wmem_strdup_printf(((void*)0), "[Managed in the file \"%s\"]"
, uat->filename)
;
6837 else
6838 pref_text = "[Managed in an unknown file]";
6839 break;
6840 }
6841
6842 default:
6843 break;
6844 }
6845 }
6846
6847 return g_strdup(pref_text)g_strdup_inline (pref_text);
6848}
6849
6850/*
6851 * Write out a single dissector preference.
6852 */
6853void
6854pref_write_individual(void *data, void *user_data)
6855{
6856 pref_t *pref = (pref_t *)data;
6857 write_pref_arg_t *arg = (write_pref_arg_t *)user_data;
6858 char **desc_lines;
6859 int i;
6860
6861 if (!pref || pref->obsolete) {
6862 /*
6863 * This preference is no longer supported; it's not a
6864 * real preference, so we don't write it out (i.e., we
6865 * treat it as if it weren't found in the list of
6866 * preferences, and we weren't called in the first place).
6867 */
6868 return;
6869 }
6870
6871 switch (pref->type) {
6872
6873 case PREF_STATIC_TEXT:
6874 case PREF_UAT:
6875 /* Nothing to do; don't bother printing the description */
6876 return;
6877 case PREF_DECODE_AS_RANGE:
6878 /* Data is saved through Decode As mechanism and not part of preferences file */
6879 return;
6880 case PREF_PROTO_TCP_SNDAMB_ENUM:
6881 /* Not written to the preference file because the override is only
6882 * for the lifetime of the capture file and there is no single
6883 * value to write.
6884 */
6885 return;
6886 default:
6887 break;
6888 }
6889
6890 if (pref->type != PREF_CUSTOM || pref->custom_cbs.type_name_cb() != NULL((void*)0)) {
6891 /*
6892 * The prefix will either be the module name or the parent
6893 * name if it's a subtree
6894 */
6895 const char *name_prefix = (arg->module->name != NULL((void*)0)) ? arg->module->name : arg->module->parent->name;
6896 char *type_desc, *pref_text;
6897 const char * def_prefix = prefs_pref_is_default(pref) ? "#" : "";
6898
6899 if (pref->type == PREF_CUSTOM)
6900 fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
6901 fprintf(arg->pf, "\n");
6902 if (pref->description &&
6903 (g_ascii_strncasecmp(pref->description,"", 2) != 0)) {
6904 if (pref->type != PREF_CUSTOM) {
6905 /* We get duplicate lines otherwise. */
6906
6907 desc_lines = g_strsplit(pref->description, "\n", 0);
6908 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6909 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6910 }
6911 g_strfreev(desc_lines);
6912 }
6913 } else {
6914 fprintf(arg->pf, "# No description\n");
6915 }
6916
6917 type_desc = prefs_pref_type_description(pref);
6918 desc_lines = g_strsplit(type_desc, "\n", 0);
6919 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6920 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6921 }
6922 g_strfreev(desc_lines);
6923 g_free(type_desc);
6924
6925 pref_text = prefs_pref_to_str(pref, pref_current);
6926 fprintf(arg->pf, "%s%s.%s: ", def_prefix, name_prefix, pref->name);
6927 if (pref->type != PREF_PASSWORD)
6928 {
6929 desc_lines = g_strsplit(pref_text, "\n", 0);
6930 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6931 fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
6932 }
6933 if (i == 0)
6934 fprintf(arg->pf, "\n");
6935 g_strfreev(desc_lines);
6936 } else {
6937 /* We never store password value */
6938 fprintf(arg->pf, "\n");
6939 }
6940 g_free(pref_text);
6941 }
6942
6943}
6944
6945static void
6946count_non_uat_pref(void *data, void *user_data)
6947{
6948 pref_t *pref = (pref_t *)data;
6949 int *arg = (int *)user_data;
6950
6951 switch (pref->type)
6952 {
6953 case PREF_UAT:
6954 case PREF_DECODE_AS_RANGE:
6955 case PREF_PROTO_TCP_SNDAMB_ENUM:
6956 //These types are not written in preference file
6957 break;
6958 default:
6959 (*arg)++;
6960 break;
6961 }
6962}
6963
6964int
6965prefs_num_non_uat(module_t *module)
6966{
6967 int num = 0;
6968
6969 g_list_foreach(module->prefs, count_non_uat_pref, &num);
6970
6971 return num;
6972}
6973
6974/*
6975 * Write out all preferences for a module.
6976 */
6977static unsigned
6978write_module_prefs(module_t *module, void *user_data)
6979{
6980 write_gui_pref_arg_t *gui_pref_arg = (write_gui_pref_arg_t*)user_data;
6981 write_pref_arg_t arg;
6982
6983 /* The GUI module needs to be explicitly called out so it
6984 can be written out of order */
6985 if ((module == gui_module) && (gui_pref_arg->is_gui_module != true1))
6986 return 0;
6987
6988 /* Write a header for the main modules and GUI sub-modules */
6989 if (((module->parent == NULL((void*)0)) || (module->parent == gui_module)) &&
6990 ((prefs_module_has_submodules(module)) ||
6991 (prefs_num_non_uat(module) > 0) ||
6992 (module->name == NULL((void*)0)))) {
6993 if ((module->name == NULL((void*)0)) && (module->parent != NULL((void*)0))) {
6994 fprintf(gui_pref_arg->pf, "\n####### %s: %s ########\n", module->parent->title, module->title);
6995 } else {
6996 fprintf(gui_pref_arg->pf, "\n####### %s ########\n", module->title);
6997 }
6998 }
6999
7000 arg.module = module;
7001 arg.pf = gui_pref_arg->pf;
7002 g_list_foreach(arg.module->prefs, pref_write_individual, &arg);
7003
7004 if (prefs_module_has_submodules(module))
7005 return prefs_modules_foreach_submodules(module->submodules, write_module_prefs, user_data);
7006
7007 return 0;
7008}
7009
7010#ifdef _WIN32
7011static void
7012write_registry(void)
7013{
7014 HKEY hTestKey;
7015 DWORD data;
7016 DWORD data_size;
7017 DWORD ret;
7018
7019 ret = RegCreateKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, NULL((void*)0),
7020 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL((void*)0),
7021 &hTestKey, NULL((void*)0));
7022 if (ret != ERROR_SUCCESS) {
7023 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"
, 7023, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
7024 return;
7025 }
7026
7027 data = ws_log_console_open;
7028 data_size = sizeof(DWORD);
7029 ret = RegSetValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", 0, REG_DWORD, (const BYTE *)&data, data_size);
7030 if (ret == ERROR_SUCCESS) {
7031 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"
, 7031, __func__, "Wrote ""ConsoleOpen"" to Windows registry: 0x%lu"
, data); } } while (0)
;
7032 }
7033 else {
7034 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"
, 7034, __func__, "Error writing registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
7035 }
7036
7037 RegCloseKey(hTestKey);
7038}
7039#endif
7040
7041/* Write out "prefs" to the user's preferences file, and return 0.
7042
7043 If the preferences file path is NULL, write to stdout.
7044
7045 If we got an error, stuff a pointer to the path of the preferences file
7046 into "*pf_path_return", and return the errno. */
7047int
7048write_prefs(const char* app_env_var_prefix, char **pf_path_return)
7049{
7050 char *pf_path;
7051 FILE *pf;
7052 write_gui_pref_arg_t write_gui_pref_info;
7053
7054#ifdef _WIN32
7055 write_registry();
7056#endif
7057
7058 /* To do:
7059 * - Split output lines longer than MAX_VAL_LEN
7060 * - Create a function for the preference directory check/creation
7061 * so that duplication can be avoided with filter.c
7062 */
7063
7064 if (pf_path_return != NULL((void*)0)) {
7065 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
7066 if ((pf = ws_fopenfopen(pf_path, "w")) == NULL((void*)0)) {
7067 *pf_path_return = pf_path;
7068 return errno(*__errno_location ());
7069 }
7070 g_free(pf_path);
7071 } else {
7072 pf = stdoutstdout;
7073 }
7074
7075 /*
7076 * If the preferences file is being written, be sure to write UAT files
7077 * first that were migrated from the preferences file.
7078 */
7079 if (pf_path_return != NULL((void*)0)) {
7080 if (prefs.filter_expressions_old) {
7081 char *err = NULL((void*)0);
7082 prefs.filter_expressions_old = false0;
7083 if (!uat_save(uat_get_table_by_name("Display expressions"), app_env_var_prefix, &err)) {
7084 ws_warning("Unable to save Display expressions: %s", err)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 7084, __func__, "Unable to save Display expressions: %s", err
); } } while (0)
;
7085 g_free(err);
7086 }
7087 }
7088
7089 module_t *extcap_module = prefs_find_module("extcap");
7090 if (extcap_module && !prefs.capture_no_extcap) {
7091 char *ext_path = get_persconffile_path("extcap.cfg", true1, app_env_var_prefix);
7092 FILE *extf;
7093 if ((extf = ws_fopenfopen(ext_path, "w")) == NULL((void*)0)) {
7094 if (errno(*__errno_location ()) != EISDIR21) {
7095 ws_warning("Unable to save extcap preferences \"%s\": %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 7096, __func__, "Unable to save extcap preferences \"%s\": %s"
, ext_path, g_strerror((*__errno_location ()))); } } while (0
)
7096 ext_path, g_strerror(errno))do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 7096, __func__, "Unable to save extcap preferences \"%s\": %s"
, ext_path, g_strerror((*__errno_location ()))); } } while (0
)
;
7097 }
7098 g_free(ext_path);
7099 } else {
7100 g_free(ext_path);
7101
7102 fputs("# Extcap configuration file for Wireshark " VERSION"4.7.0" ".\n"
7103 "#\n"
7104 "# This file is regenerated each time preferences are saved within\n"
7105 "# Wireshark. Making manual changes should be safe, however.\n"
7106 "# Preferences that have been commented out have not been\n"
7107 "# changed from their default value.\n", extf);
7108
7109 write_gui_pref_info.pf = extf;
7110 write_gui_pref_info.is_gui_module = false0;
7111
7112 write_module_prefs(extcap_module, &write_gui_pref_info);
7113
7114 fclose(extf);
7115 }
7116 }
7117 }
7118
7119 fputs("# Configuration file for Wireshark " VERSION"4.7.0" ".\n"
7120 "#\n"
7121 "# This file is regenerated each time preferences are saved within\n"
7122 "# Wireshark. Making manual changes should be safe, however.\n"
7123 "# Preferences that have been commented out have not been\n"
7124 "# changed from their default value.\n", pf);
7125
7126 /*
7127 * For "backwards compatibility" the GUI module is written first as it's
7128 * at the top of the file. This is followed by all modules that can't
7129 * fit into the preferences read/write API. Finally the remaining modules
7130 * are written in alphabetical order (including of course the protocol preferences)
7131 */
7132 write_gui_pref_info.pf = pf;
7133 write_gui_pref_info.is_gui_module = true1;
7134
7135 write_module_prefs(gui_module, &write_gui_pref_info);
7136
7137 write_gui_pref_info.is_gui_module = false0;
7138 prefs_module_list_foreach(prefs_top_level_modules, write_module_prefs, &write_gui_pref_info, true1);
7139
7140 fclose(pf);
7141
7142 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
7143 an error indication, or maybe write to a new preferences file and
7144 rename that file on top of the old one only if there are not I/O
7145 errors. */
7146 return 0;
7147}
7148
7149/** The col_list is only partly managed by the custom preference API
7150 * because its data is shared between multiple preferences, so
7151 * it's freed here
7152 */
7153static void
7154free_col_info(GList *list)
7155{
7156 fmt_data *cfmt;
7157 GList *list_head = list;
7158
7159 while (list != NULL((void*)0)) {
7160 cfmt = (fmt_data *)list->data;
7161
7162 g_free(cfmt->title);
7163 g_free(cfmt->custom_fields);
7164 g_free(cfmt);
7165 list = g_list_next(list)((list) ? (((GList *)(list))->next) : ((void*)0));
7166 }
7167 g_list_free(list_head);
7168}
7169
7170/*
7171 * Editor modelines
7172 *
7173 * Local Variables:
7174 * c-basic-offset: 4
7175 * tab-width: 8
7176 * indent-tabs-mode: nil
7177 * End:
7178 *
7179 * ex: set shiftwidth=4 tabstop=8 expandtab:
7180 * :indentSize=4:tabSize=8:noTabs=true:
7181 */