Bug Summary

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