Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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