Bug Summary

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