Bug Summary

File:builds/wireshark/wireshark/epan/prefs.c
Warning:line 4784, 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-06-07-100346-3530-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 <gerald@wireshark.org>
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
2158pref_unstash(pref_t *pref, void *unstash_data_p)
2159{
2160 pref_unstash_data_t *unstash_data = (pref_unstash_data_t *)unstash_data_p;
2161 dissector_table_t sub_dissectors = NULL((void*)0);
2162 dissector_handle_t handle = NULL((void*)0);
2163
2164 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2164, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2165
2166 /* Revert the preference to its saved value. */
2167 switch (pref->type) {
2168
2169 case PREF_UINT:
2170 if (*pref->varp.uint != pref->stashed_val.uint) {
2171 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2172 *pref->varp.uint = pref->stashed_val.uint;
2173 }
2174 break;
2175
2176 case PREF_INT:
2177 if (*pref->varp.intp != pref->stashed_val.intval) {
2178 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2179 *pref->varp.intp = pref->stashed_val.intval;
2180 }
2181 break;
2182
2183 case PREF_FLOAT:
2184 if (*pref->varp.floatp != pref->stashed_val.floatval) {
2185 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2186 *pref->varp.floatp = pref->stashed_val.floatval;
2187 }
2188 break;
2189
2190 case PREF_BOOL:
2191 if (*pref->varp.boolp != pref->stashed_val.boolval) {
2192 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2193 *pref->varp.boolp = pref->stashed_val.boolval;
2194 }
2195 break;
2196
2197 case PREF_ENUM:
2198 if (*pref->varp.enump != pref->stashed_val.enumval) {
2199 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2200 *pref->varp.enump = pref->stashed_val.enumval;
2201 }
2202 break;
2203
2204 case PREF_PROTO_TCP_SNDAMB_ENUM:
2205 {
2206 /* The preference dialogs are modal so the frame_data pointers should
2207 * still be valid; otherwise we could store the frame numbers to
2208 * change.
2209 */
2210 frame_data *fdata;
2211 for (GList* elem = pref->stashed_val.list; elem != NULL((void*)0); elem = elem->next) {
2212 fdata = (frame_data*)elem->data;
2213 if (fdata->tcp_snd_manual_analysis != *pref->varp.enump) {
2214 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2215 fdata->tcp_snd_manual_analysis = *pref->varp.enump;
2216 }
2217 }
2218 break;
2219 }
2220 case PREF_STRING:
2221 case PREF_SAVE_FILENAME:
2222 case PREF_OPEN_FILENAME:
2223 case PREF_DIRNAME:
2224 case PREF_PASSWORD:
2225 case PREF_DISSECTOR:
2226 if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0) {
2227 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2228 wmem_free(pref->scope, *pref->varp.string);
2229 *pref->varp.string = wmem_strdup(pref->scope, pref->stashed_val.string);
2230 }
2231 break;
2232
2233 case PREF_DECODE_AS_RANGE:
2234 {
2235 const char* table_name = prefs_get_dissector_table(pref);
2236 if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2237 uint32_t i, j;
2238 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2239
2240 if (unstash_data->handle_decode_as) {
2241 sub_dissectors = find_dissector_table(table_name);
2242 if (sub_dissectors != NULL((void*)0)) {
2243 const char *handle_desc = prefs_get_dissector_description(pref);
2244 // It should perhaps be possible to get this via dissector name.
2245 handle = dissector_table_get_dissector_handle(sub_dissectors, handle_desc);
2246 if (handle != NULL((void*)0)) {
2247 /* Set the current handle to NULL for all the old values
2248 * in the dissector table. If there isn't an initial
2249 * handle, this actually deletes the entry. (If there
2250 * is an initial entry, keep it around so that the
2251 * user can see the original value.)
2252 *
2253 * XXX - If there's an initial handle which is not this,
2254 * reset it instead? At least this leaves the initial
2255 * handle visible in the Decode As table.
2256 */
2257 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2258 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2259 dissector_change_uint(table_name, j, NULL((void*)0));
2260 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));
2261 }
2262
2263 dissector_change_uint(table_name, (*pref->varp.range)->ranges[i].high, NULL((void*)0));
2264 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));
2265 }
2266 }
2267 }
2268 }
2269
2270 wmem_free(pref->scope, *pref->varp.range);
2271 *pref->varp.range = range_copy(pref->scope, pref->stashed_val.range);
2272
2273 if (unstash_data->handle_decode_as) {
2274 if ((sub_dissectors != NULL((void*)0)) && (handle != NULL((void*)0))) {
2275
2276 /* Add new values to the dissector table */
2277 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2278
2279 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2280 dissector_change_uint(table_name, j, handle);
2281 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));
2282 }
2283
2284 dissector_change_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
2285 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));
2286 }
2287 }
2288 }
2289 }
2290 break;
2291 }
2292 case PREF_RANGE:
2293 if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2294 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2295 wmem_free(pref->scope, *pref->varp.range);
2296 *pref->varp.range = range_copy(pref->scope, pref->stashed_val.range);
2297 }
2298 break;
2299
2300 case PREF_COLOR:
2301 if ((pref->varp.colorp->blue != pref->stashed_val.color.blue) ||
2302 (pref->varp.colorp->red != pref->stashed_val.color.red) ||
2303 (pref->varp.colorp->green != pref->stashed_val.color.green)) {
2304 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2305 *pref->varp.colorp = pref->stashed_val.color;
2306 }
2307 break;
2308 case PREF_UAT:
2309 if (pref->varp.uat && pref->varp.uat->changed) {
2310 unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2311 }
2312 break;
2313 case PREF_STATIC_TEXT:
2314 case PREF_CUSTOM:
2315 break;
2316
2317 default:
2318 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2318
, __func__, "assertion \"not reached\" failed")
;
2319 break;
2320 }
2321 return 0;
2322}
2323
2324void
2325reset_stashed_pref(pref_t *pref) {
2326
2327 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2327, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2328
2329 switch (pref->type) {
2330
2331 case PREF_UINT:
2332 pref->stashed_val.uint = pref->default_val.uint;
2333 break;
2334
2335 case PREF_INT:
2336 pref->stashed_val.intval = pref->default_val.intval;
2337 break;
2338
2339 case PREF_FLOAT:
2340 pref->stashed_val.floatval = pref->default_val.floatval;
2341 break;
2342
2343 case PREF_BOOL:
2344 pref->stashed_val.boolval = pref->default_val.boolval;
2345 break;
2346
2347 case PREF_ENUM:
2348 pref->stashed_val.enumval = pref->default_val.enumval;
2349 break;
2350
2351 case PREF_STRING:
2352 case PREF_SAVE_FILENAME:
2353 case PREF_OPEN_FILENAME:
2354 case PREF_DIRNAME:
2355 case PREF_PASSWORD:
2356 case PREF_DISSECTOR:
2357 wmem_free(pref->scope, pref->stashed_val.string);
2358 pref->stashed_val.string = wmem_strdup(pref->scope, pref->default_val.string);
2359 break;
2360
2361 case PREF_DECODE_AS_RANGE:
2362 case PREF_RANGE:
2363 wmem_free(pref->scope, pref->stashed_val.range);
2364 pref->stashed_val.range = range_copy(pref->scope, pref->default_val.range);
2365 break;
2366
2367 case PREF_PROTO_TCP_SNDAMB_ENUM:
2368 if (pref->stashed_val.list != NULL((void*)0)) {
2369 g_list_free(pref->stashed_val.list);
2370 pref->stashed_val.list = NULL((void*)0);
2371 }
2372 break;
2373
2374 case PREF_COLOR:
2375 memcpy(&pref->stashed_val.color, &pref->default_val.color, sizeof(color_t));
2376 break;
2377
2378 case PREF_STATIC_TEXT:
2379 case PREF_UAT:
2380 case PREF_CUSTOM:
2381 break;
2382
2383 default:
2384 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2384
, __func__, "assertion \"not reached\" failed")
;
2385 break;
2386 }
2387}
2388
2389unsigned
2390pref_clean_stash(pref_t *pref, void *unused _U___attribute__((unused)))
2391{
2392 ws_assert(!pref->obsolete)do { if ((1) && !(!pref->obsolete)) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2392, __func__, "assertion failed: %s"
, "!pref->obsolete"); } while (0)
;
2393
2394 switch (pref->type) {
2395
2396 case PREF_UINT:
2397 case PREF_INT:
2398 case PREF_FLOAT:
2399 case PREF_BOOL:
2400 case PREF_ENUM:
2401 break;
2402
2403 case PREF_STRING:
2404 case PREF_SAVE_FILENAME:
2405 case PREF_OPEN_FILENAME:
2406 case PREF_DIRNAME:
2407 case PREF_PASSWORD:
2408 case PREF_DISSECTOR:
2409 if (pref->stashed_val.string != NULL((void*)0)) {
2410 wmem_free(pref->scope, pref->stashed_val.string);
2411 pref->stashed_val.string = NULL((void*)0);
2412 }
2413 break;
2414
2415 case PREF_DECODE_AS_RANGE:
2416 case PREF_RANGE:
2417 if (pref->stashed_val.range != NULL((void*)0)) {
2418 wmem_free(pref->scope, pref->stashed_val.range);
2419 pref->stashed_val.range = NULL((void*)0);
2420 }
2421 break;
2422
2423 case PREF_STATIC_TEXT:
2424 case PREF_UAT:
2425 case PREF_COLOR:
2426 case PREF_CUSTOM:
2427 break;
2428
2429 case PREF_PROTO_TCP_SNDAMB_ENUM:
2430 if (pref->stashed_val.list != NULL((void*)0)) {
2431 g_list_free(pref->stashed_val.list);
2432 pref->stashed_val.list = NULL((void*)0);
2433 }
2434 break;
2435
2436 default:
2437 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2437
, __func__, "assertion \"not reached\" failed")
;
2438 break;
2439 }
2440 return 0;
2441}
2442
2443/*
2444 * Call a callback function, with a specified argument, for each preference
2445 * in a given module.
2446 *
2447 * If any of the callbacks return a non-zero value, stop and return that
2448 * value, otherwise return 0.
2449 */
2450unsigned
2451prefs_pref_foreach(module_t *module, pref_cb callback, void *user_data)
2452{
2453 GList *elem;
2454 pref_t *pref;
2455 unsigned ret;
2456
2457 for (elem = g_list_first(module->prefs); elem != NULL((void*)0); elem = g_list_next(elem)((elem) ? (((GList *)(elem))->next) : ((void*)0))) {
2458 pref = (pref_t *)elem->data;
2459 if (!pref || pref->obsolete) {
2460 /*
2461 * This preference is no longer supported; it's
2462 * not a real preference, so we don't call the
2463 * callback for it (i.e., we treat it as if it
2464 * weren't found in the list of preferences,
2465 * and we weren't called in the first place).
2466 */
2467 continue;
2468 }
2469
2470 ret = (*callback)(pref, user_data);
2471 if (ret != 0)
2472 return ret;
2473 }
2474 return 0;
2475}
2476
2477static const enum_val_t st_sort_col_vals[] = {
2478 { "name", "Node name (topic/item)", ST_SORT_COL_NAME1 },
2479 { "count", "Item count", ST_SORT_COL_COUNT2 },
2480 { "average", "Average value of the node", ST_SORT_COL_AVG3 },
2481 { "min", "Minimum value of the node", ST_SORT_COL_MIN4 },
2482 { "max", "Maximum value of the node", ST_SORT_COL_MAX5 },
2483 { "burst", "Burst rate of the node", ST_SORT_COL_BURSTRATE6 },
2484 { NULL((void*)0), NULL((void*)0), 0 }
2485};
2486
2487static const enum_val_t st_format_vals[] = {
2488 { "text", "Plain text", ST_FORMAT_PLAIN },
2489 { "csv", "Comma separated values", ST_FORMAT_CSV },
2490 { "xml", "XML document", ST_FORMAT_XML },
2491 { "yaml", "YAML document", ST_FORMAT_YAML },
2492 { NULL((void*)0), NULL((void*)0), 0 }
2493};
2494
2495static void
2496stats_callback(void)
2497{
2498 /* Test for a sane tap update interval */
2499 if (prefs.tap_update_interval < 100 || prefs.tap_update_interval > 10000)
2500 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
2501
2502 /* burst resolution can't be less than 1 (ms) */
2503 if (prefs.st_burst_resolution < 1) {
2504 prefs.st_burst_resolution = 1;
2505 }
2506 else if (prefs.st_burst_resolution > ST_MAX_BURSTRES600000) {
2507 prefs.st_burst_resolution = ST_MAX_BURSTRES600000;
2508 }
2509 /* make sure burst window value makes sense */
2510 if (prefs.st_burst_windowlen < prefs.st_burst_resolution) {
2511 prefs.st_burst_windowlen = prefs.st_burst_resolution;
2512 }
2513 /* round burst window down to multiple of resolution */
2514 prefs.st_burst_windowlen -= prefs.st_burst_windowlen%prefs.st_burst_resolution;
2515 if ((prefs.st_burst_windowlen/prefs.st_burst_resolution) > ST_MAX_BURSTBUCKETS100) {
2516 prefs.st_burst_windowlen = prefs.st_burst_resolution*ST_MAX_BURSTBUCKETS100;
2517 }
2518}
2519
2520static void
2521gui_callback(void)
2522{
2523 /* Ensure there is at least one file count */
2524 if (prefs.gui_recent_files_count_max == 0)
2525 prefs.gui_recent_files_count_max = 10;
2526
2527 /* Ensure there is at least one display filter entry */
2528 if (prefs.gui_recent_df_entries_max == 0)
2529 prefs.gui_recent_df_entries_max = 10;
2530
2531 /* number of decimal places should be between 2 and 10 */
2532 if (prefs.gui_decimal_places1 < 2) {
2533 prefs.gui_decimal_places1 = 2;
2534 } else if (prefs.gui_decimal_places1 > 10) {
2535 prefs.gui_decimal_places1 = 10;
2536 }
2537 /* number of decimal places should be between 2 and 10 */
2538 if (prefs.gui_decimal_places2 < 2) {
2539 prefs.gui_decimal_places2 = 2;
2540 } else if (prefs.gui_decimal_places2 > 10) {
2541 prefs.gui_decimal_places2 = 10;
2542 }
2543 /* number of decimal places should be between 2 and 10 */
2544 if (prefs.gui_decimal_places3 < 2) {
2545 prefs.gui_decimal_places3 = 2;
2546 } else if (prefs.gui_decimal_places3 > 10) {
2547 prefs.gui_decimal_places3 = 10;
2548 }
2549}
2550
2551static void
2552gui_layout_callback(void)
2553{
2554 if (prefs.gui_layout_type == layout_unused ||
2555 prefs.gui_layout_type >= layout_type_max) {
2556 /* XXX - report an error? It's not a syntax error - we'd need to
2557 add a way of reporting a *semantic* error. */
2558 prefs.gui_layout_type = layout_type_2;
2559 }
2560}
2561
2562/******************************************************
2563 * All custom preference function callbacks
2564 ******************************************************/
2565static void custom_pref_no_cb(pref_t* pref _U___attribute__((unused))) {}
2566
2567/*
2568 * Column preference functions
2569 */
2570#define PRS_COL_HIDDEN_FMT"column.hidden" "column.hidden"
2571#define PRS_COL_HIDDEN"column.hide" "column.hide"
2572#define PRS_COL_FMT"column.format" "column.format"
2573#define PRS_COL_NUM"column.number" "column.number"
2574static module_t *gui_column_module;
2575
2576static prefs_set_pref_e
2577column_hidden_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
2578{
2579 GList *clp;
2580 fmt_data *cfmt;
2581 pref_t *format_pref;
2582
2583 /*
2584 * Prefer the new preference to the old format-based preference if we've
2585 * read it. (We probably could just compare the string to NULL and "".)
2586 */
2587 prefs.cols_hide_new = true1;
2588
2589 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2590
2591 /*
2592 * Set the "visible" flag for the existing columns; we need to
2593 * do this if we set PRS_COL_HIDDEN but don't set PRS_COL_FMT
2594 * after setting it (which might be the case if, for example, we
2595 * set PRS_COL_HIDDEN on the command line).
2596 */
2597 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2598 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2599 int cidx = 1;
2600 while (clp) {
2601 cfmt = (fmt_data *)clp->data;
2602 cfmt->visible = prefs_is_column_visible(*pref->varp.string, cidx);
2603 cidx++;
2604 clp = clp->next;
2605 }
2606
2607 return PREFS_SET_OK;
2608}
2609
2610static const char *
2611column_hidden_type_name_cb(void)
2612{
2613 return "Packet list hidden columns";
2614}
2615
2616static char *
2617column_hidden_type_description_cb(void)
2618{
2619 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."
)
;
2620}
2621
2622static char *
2623column_hidden_to_str_cb(pref_t* pref, bool_Bool default_val)
2624{
2625 GString *cols_hidden;
2626 GList *clp;
2627 fmt_data *cfmt;
2628 pref_t *format_pref;
2629 int cidx = 1;
2630
2631 if (default_val)
2632 return g_strdup(pref->default_val.string)g_strdup_inline (pref->default_val.string);
2633
2634 cols_hidden = g_string_new("");
2635 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2636 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2637 while (clp) {
2638 cfmt = (fmt_data *) clp->data;
2639 if (!cfmt->visible) {
2640 if (cols_hidden->len)
2641 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))
;
2642 g_string_append_printf (cols_hidden, "%i", cidx);
2643 }
2644 clp = clp->next;
2645 cidx++;
2646 }
2647
2648 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))))
;
2649}
2650
2651static bool_Bool
2652column_hidden_is_default_cb(pref_t* pref)
2653{
2654 char *cur_hidden_str = column_hidden_to_str_cb(pref, false0);
2655 bool_Bool is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2656
2657 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)
;
2658 return is_default;
2659}
2660
2661static prefs_set_pref_e
2662column_hidden_fmt_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
2663{
2664 GList *clp;
2665 fmt_data *cfmt;
2666 pref_t *format_pref;
2667
2668 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2669
2670 /*
2671 * Set the "visible" flag for the existing columns; we need to
2672 * do this if we set PRS_COL_HIDDEN_FMT but don't set PRS_COL_FMT
2673 * after setting it (which might be the case if, for example, we
2674 * set PRS_COL_HIDDEN_FMT on the command line; it shouldn't happen
2675 * when reading the configuration file because we write (both of)
2676 * the hidden column prefs before the column format prefs.)
2677 */
2678 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2679 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2680 while (clp) {
2681 cfmt = (fmt_data *)clp->data;
2682 cfmt->visible = prefs_is_column_fmt_visible(*pref->varp.string, cfmt);
2683 clp = clp->next;
2684 }
2685
2686 return PREFS_SET_OK;
2687}
2688
2689static const char *
2690column_hidden_fmt_type_name_cb(void)
2691{
2692 return "Packet list hidden column formats (deprecated)";
2693}
2694
2695static char *
2696column_hidden_fmt_type_description_cb(void)
2697{
2698 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."
)
;
2699}
2700
2701static char *
2702column_hidden_fmt_to_str_cb(pref_t* pref, bool_Bool default_val)
2703{
2704 GString *cols_hidden;
2705 GList *clp;
2706 fmt_data *cfmt;
2707 pref_t *format_pref;
2708
2709 if (default_val)
2710 return g_strdup(pref->default_val.string)g_strdup_inline (pref->default_val.string);
2711
2712 cols_hidden = g_string_new("");
2713 format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT"column.format");
2714 clp = (format_pref) ? *format_pref->varp.list : NULL((void*)0);
2715 while (clp) {
2716 char *prefs_fmt;
2717 cfmt = (fmt_data *) clp->data;
2718 if (!cfmt->visible) {
2719 if (cols_hidden->len)
2720 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))
;
2721 prefs_fmt = column_fmt_data_to_str(cfmt);
2722 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))
;
2723 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)
;
2724 }
2725 clp = clp->next;
2726 }
2727
2728 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))))
;
2729}
2730
2731static bool_Bool
2732column_hidden_fmt_is_default_cb(pref_t* pref)
2733{
2734 char *cur_hidden_str = column_hidden_fmt_to_str_cb(pref, false0);
2735 bool_Bool is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2736
2737 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)
;
2738 return is_default;
2739}
2740
2741/* Number of columns "preference". This is only used internally and is not written to the
2742 * preference file
2743 */
2744static void
2745column_num_reset_cb(pref_t* pref)
2746{
2747 *pref->varp.uint = pref->default_val.uint;
2748}
2749
2750static prefs_set_pref_e
2751column_num_set_cb(pref_t* pref _U___attribute__((unused)), const char* value _U___attribute__((unused)), unsigned int* changed_flags _U___attribute__((unused)))
2752{
2753 /* Don't write this to the preferences file */
2754 return PREFS_SET_OK;
2755}
2756
2757static const char *
2758column_num_type_name_cb(void)
2759{
2760 return NULL((void*)0);
2761}
2762
2763static char *
2764column_num_type_description_cb(void)
2765{
2766 return g_strdup("")g_strdup_inline ("");
2767}
2768
2769static bool_Bool
2770column_num_is_default_cb(pref_t* pref _U___attribute__((unused)))
2771{
2772 return true1;
2773}
2774
2775static char *
2776column_num_to_str_cb(pref_t* pref _U___attribute__((unused)), bool_Bool default_val _U___attribute__((unused)))
2777{
2778 return g_strdup("")g_strdup_inline ("");
2779}
2780
2781/*
2782 * Column format custom preference functions
2783 */
2784static void
2785column_format_init_cb(pref_t* pref, GList** value)
2786{
2787 fmt_data *src_cfmt, *dest_cfmt;
2788 GList *entry;
2789
2790 pref->varp.list = value;
2791
2792 pref->default_val.list = NULL((void*)0);
2793 for (entry = *pref->varp.list; entry != NULL((void*)0); entry = g_list_next(entry)((entry) ? (((GList *)(entry))->next) : ((void*)0))) {
2794 src_cfmt = (fmt_data *)entry->data;
2795 dest_cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2796 dest_cfmt->title = g_strdup(src_cfmt->title)g_strdup_inline (src_cfmt->title);
2797 dest_cfmt->fmt = src_cfmt->fmt;
2798 if (src_cfmt->custom_fields) {
2799 dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields)g_strdup_inline (src_cfmt->custom_fields);
2800 dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2801 } else {
2802 dest_cfmt->custom_fields = NULL((void*)0);
2803 dest_cfmt->custom_occurrence = 0;
2804 }
2805 dest_cfmt->visible = src_cfmt->visible;
2806 dest_cfmt->display = src_cfmt->display;
2807 pref->default_val.list = g_list_append(pref->default_val.list, dest_cfmt);
2808 }
2809
2810 column_register_fields();
2811}
2812
2813static void
2814column_format_free_cb(pref_t* pref)
2815{
2816 free_col_info(*pref->varp.list);
2817 free_col_info(pref->default_val.list);
2818}
2819
2820static void
2821column_format_reset_cb(pref_t* pref)
2822{
2823 fmt_data *src_cfmt, *dest_cfmt;
2824 GList *entry;
2825 pref_t *col_num_pref;
2826
2827 free_col_info(*pref->varp.list);
2828 *pref->varp.list = NULL((void*)0);
2829
2830 for (entry = pref->default_val.list; entry != NULL((void*)0); entry = g_list_next(entry)((entry) ? (((GList *)(entry))->next) : ((void*)0))) {
2831 src_cfmt = (fmt_data *)entry->data;
2832 dest_cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2833 dest_cfmt->title = g_strdup(src_cfmt->title)g_strdup_inline (src_cfmt->title);
2834 dest_cfmt->fmt = src_cfmt->fmt;
2835 if (src_cfmt->custom_fields) {
2836 dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields)g_strdup_inline (src_cfmt->custom_fields);
2837 dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2838 } else {
2839 dest_cfmt->custom_fields = NULL((void*)0);
2840 dest_cfmt->custom_occurrence = 0;
2841 }
2842 dest_cfmt->visible = src_cfmt->visible;
2843 dest_cfmt->display = src_cfmt->display;
2844 *pref->varp.list = g_list_append(*pref->varp.list, dest_cfmt);
2845 }
2846
2847 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2848 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", 2848, __func__, "assertion failed: %s"
, "col_num_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2849 column_num_reset_cb(col_num_pref);
2850}
2851
2852static prefs_set_pref_e
2853column_format_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags _U___attribute__((unused)))
2854{
2855 GList *col_l, *col_l_elt;
2856 fmt_data *cfmt;
2857 int llen;
2858 pref_t *hidden_pref, *col_num_pref;
2859
2860 col_l = prefs_get_string_list(value);
2861 if (col_l == NULL((void*)0))
2862 return PREFS_SET_SYNTAX_ERR;
2863 if ((g_list_length(col_l) % 2) != 0) {
2864 /* A title didn't have a matching format. */
2865 prefs_clear_string_list(col_l);
2866 return PREFS_SET_SYNTAX_ERR;
2867 }
2868 /* Check to make sure all column formats are valid. */
2869 col_l_elt = g_list_first(col_l);
2870 while (col_l_elt) {
2871 fmt_data cfmt_check;
2872
2873 /* Go past the title. */
2874 col_l_elt = col_l_elt->next;
2875
2876 /* Some predefined columns have been migrated to use custom columns.
2877 * We'll convert these silently here */
2878 try_convert_to_custom_column((char **)&col_l_elt->data);
2879
2880 /* Parse the format to see if it's valid. */
2881 if (!parse_column_format(&cfmt_check, (char *)col_l_elt->data)) {
2882 /* It's not a valid column format. */
2883 prefs_clear_string_list(col_l);
2884 return PREFS_SET_SYNTAX_ERR;
2885 }
2886 if (cfmt_check.fmt == COL_CUSTOM) {
2887 /* We don't need the custom column field on this pass. */
2888 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
)
;
2889 }
2890
2891 /* Go past the format. */
2892 col_l_elt = col_l_elt->next;
2893 }
2894
2895 /* They're all valid; process them. */
2896 free_col_info(*pref->varp.list);
2897 *pref->varp.list = NULL((void*)0);
2898 if (prefs.cols_hide_new) {
2899 hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN"column.hide");
2900 } else {
2901 hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN_FMT"column.hidden");
2902 }
2903 ws_assert(hidden_pref != NULL)do { if ((1) && !(hidden_pref != ((void*)0))) ws_log_fatal_full
("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 2903, __func__, "assertion failed: %s"
, "hidden_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2904 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2905 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", 2905, __func__, "assertion failed: %s"
, "col_num_pref != ((void*)0)"); } while (0)
; /* Should never happen */
2906 llen = g_list_length(col_l);
2907 *col_num_pref->varp.uint = llen / 2;
2908 col_l_elt = g_list_first(col_l);
2909 int cidx = 1;
2910 while (col_l_elt) {
2911 cfmt = g_new(fmt_data,1)((fmt_data *) g_malloc_n ((1), sizeof (fmt_data)));
2912 cfmt->title = g_strdup((char *)col_l_elt->data)g_strdup_inline ((char *)col_l_elt->data);
2913 col_l_elt = col_l_elt->next;
2914 parse_column_format(cfmt, (char *)col_l_elt->data);
2915 if (prefs.cols_hide_new) {
2916 cfmt->visible = prefs_is_column_visible(*hidden_pref->varp.string, cidx);
2917 } else {
2918 cfmt->visible = prefs_is_column_fmt_visible(*hidden_pref->varp.string, cfmt);
2919 }
2920 col_l_elt = col_l_elt->next;
2921 *pref->varp.list = g_list_append(*pref->varp.list, cfmt);
2922 cidx++;
2923 }
2924
2925 prefs_clear_string_list(col_l);
2926 free_string_like_preference(hidden_pref);
2927 column_register_fields();
2928 return PREFS_SET_OK;
2929}
2930
2931
2932static const char *
2933column_format_type_name_cb(void)
2934{
2935 return "Packet list column format";
2936}
2937
2938static char *
2939column_format_type_description_cb(void)
2940{
2941 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"
)
;
2942}
2943
2944static bool_Bool
2945column_format_is_default_cb(pref_t* pref)
2946{
2947 GList *clp = *pref->varp.list,
2948 *pref_col = g_list_first(clp),
2949 *def_col = g_list_first(pref->default_val.list);
2950 fmt_data *cfmt, *def_cfmt;
2951 bool_Bool is_default = true1;
2952 pref_t *col_num_pref;
2953
2954 /* See if the column data has changed from the default */
2955 col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM"column.number");
2956 if (col_num_pref && *col_num_pref->varp.uint != col_num_pref->default_val.uint) {
2957 is_default = false0;
2958 } else {
2959 while (pref_col && def_col) {
2960 cfmt = (fmt_data *) pref_col->data;
2961 def_cfmt = (fmt_data *) def_col->data;
2962 if ((g_strcmp0(cfmt->title, def_cfmt->title) != 0) ||
2963 (cfmt->fmt != def_cfmt->fmt) ||
2964 (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) &&
2965 ((g_strcmp0(cfmt->custom_fields, def_cfmt->custom_fields) != 0) ||
2966 (cfmt->display != def_cfmt->display)))) {
2967 is_default = false0;
2968 break;
2969 }
2970
2971 pref_col = pref_col->next;
2972 def_col = def_col->next;
2973 }
2974 }
2975
2976 return is_default;
2977}
2978
2979static char *
2980column_format_to_str_cb(pref_t* pref, bool_Bool default_val)
2981{
2982 GList *pref_l = default_val ? pref->default_val.list : *pref->varp.list;
2983 GList *clp = g_list_first(pref_l);
2984 GList *col_l;
2985 fmt_data *cfmt;
2986 char *column_format_str;
2987
2988 col_l = NULL((void*)0);
2989 while (clp) {
2990 cfmt = (fmt_data *) clp->data;
2991 col_l = g_list_append(col_l, g_strdup(cfmt->title)g_strdup_inline (cfmt->title));
2992 col_l = g_list_append(col_l, column_fmt_data_to_str(cfmt));
2993 clp = clp->next;
2994 }
2995
2996 column_format_str = join_string_list(col_l);
2997 prefs_clear_string_list(col_l);
2998 return column_format_str;
2999}
3000
3001
3002/****** Capture column custom preference functions ******/
3003
3004/* This routine is only called when Wireshark is started, NOT when another profile is selected.
3005 Copy the pref->capture_columns list (just loaded with the capture_cols[] struct values)
3006 to prefs->default_val.list.
3007*/
3008static void
3009capture_column_init_cb(pref_t* pref, GList** capture_cols_values)
3010{
3011 GList *ccv_list = *capture_cols_values,
3012 *dlist = NULL((void*)0);
3013
3014 /* */
3015 while (ccv_list) {
3016 dlist = g_list_append(dlist, g_strdup((char *)ccv_list->data)g_strdup_inline ((char *)ccv_list->data));
3017 ccv_list = ccv_list->next;
3018 }
3019
3020 pref->default_val.list = dlist;
3021 pref->varp.list = &prefs.capture_columns;
3022 pref->stashed_val.boolval = false0;
3023}
3024
3025/* Free the prefs->capture_columns list strings and remove the list entries.
3026 Note that since pref->varp.list points to &prefs.capture_columns, it is
3027 also freed.
3028*/
3029static void
3030capture_column_free_cb(pref_t* pref)
3031{
3032 prefs_clear_string_list(prefs.capture_columns);
3033 prefs.capture_columns = NULL((void*)0);
3034
3035 if (pref->stashed_val.boolval == true1) {
3036 prefs_clear_string_list(pref->default_val.list);
3037 pref->default_val.list = NULL((void*)0);
3038 }
3039}
3040
3041/* Copy pref->default_val.list to *pref->varp.list.
3042*/
3043static void
3044capture_column_reset_cb(pref_t* pref)
3045{
3046 GList *vlist = NULL((void*)0), *dlist;
3047
3048 /* Free the column name strings and remove the links from *pref->varp.list */
3049 prefs_clear_string_list(*pref->varp.list);
3050
3051 for (dlist = pref->default_val.list; dlist != NULL((void*)0); dlist = g_list_next(dlist)((dlist) ? (((GList *)(dlist))->next) : ((void*)0))) {
3052 vlist = g_list_append(vlist, g_strdup((char *)dlist->data)g_strdup_inline ((char *)dlist->data));
3053 }
3054 *pref->varp.list = vlist;
3055}
3056
3057static prefs_set_pref_e
3058capture_column_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags _U___attribute__((unused)))
3059{
3060 GList *col_l = prefs_get_string_list(value);
3061 GList *col_l_elt;
3062 char *col_name;
3063 int i;
3064
3065 if (col_l == NULL((void*)0))
3066 return PREFS_SET_SYNTAX_ERR;
3067
3068 capture_column_free_cb(pref);
3069
3070 /* If value (the list of capture.columns read from preferences) is empty, set capture.columns
3071 to the full list of valid capture column names. */
3072 col_l_elt = g_list_first(col_l);
3073 if (!(*(char *)col_l_elt->data)) {
3074 for (i = 0; i < num_capture_cols; i++) {
3075 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
3076 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
3077 }
3078 }
3079
3080 /* Verify that all the column names are valid. If not, use the entire list of valid columns.
3081 */
3082 while (col_l_elt) {
3083 bool_Bool found_match = false0;
3084 col_name = (char *)col_l_elt->data;
3085
3086 for (i = 0; i < num_capture_cols; i++) {
3087 if (strcmp(col_name, capture_cols[i])==0) {
3088 found_match = true1;
3089 break;
3090 }
3091 }
3092 if (!found_match) {
3093 /* One or more cols are invalid so use the entire list of valid cols. */
3094 for (i = 0; i < num_capture_cols; i++) {
3095 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
3096 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
3097 }
3098 pref->varp.list = &prefs.capture_columns;
3099 prefs_clear_string_list(col_l);
3100 return PREFS_SET_SYNTAX_ERR;
3101 }
3102 col_l_elt = col_l_elt->next;
3103 }
3104
3105 col_l_elt = g_list_first(col_l);
3106 while (col_l_elt) {
3107 col_name = (char *)col_l_elt->data;
3108 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
3109 col_l_elt = col_l_elt->next;
3110 }
3111 pref->varp.list = &prefs.capture_columns;
3112 g_list_free(col_l);
3113 return PREFS_SET_OK;
3114}
3115
3116
3117static const char *
3118capture_column_type_name_cb(void)
3119{
3120 return "Column list";
3121}
3122
3123static char *
3124capture_column_type_description_cb(void)
3125{
3126 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"
)
3127 "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"
)
3128 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"
)
;
3129}
3130
3131static bool_Bool
3132capture_column_is_default_cb(pref_t* pref)
3133{
3134 GList *pref_col = g_list_first(prefs.capture_columns),
3135 *def_col = g_list_first(pref->default_val.list);
3136 bool_Bool is_default = true1;
3137
3138 /* See if the column data has changed from the default */
3139 while (pref_col && def_col) {
3140 if (strcmp((char *)pref_col->data, (char *)def_col->data) != 0) {
3141 is_default = false0;
3142 break;
3143 }
3144 pref_col = pref_col->next;
3145 def_col = def_col->next;
3146 }
3147
3148 /* Ensure the same column count */
3149 if (((pref_col == NULL((void*)0)) && (def_col != NULL((void*)0))) ||
3150 ((pref_col != NULL((void*)0)) && (def_col == NULL((void*)0))))
3151 is_default = false0;
3152
3153 return is_default;
3154}
3155
3156static char *
3157capture_column_to_str_cb(pref_t* pref, bool_Bool default_val)
3158{
3159
3160 GList *pref_l = default_val ? pref->default_val.list : prefs.capture_columns;
3161 GList *clp = g_list_first(pref_l);
3162 GList *col_l = NULL((void*)0);
3163 char *col;
3164 char *capture_column_str;
3165
3166 while (clp) {
3167 col = (char *) clp->data;
3168 col_l = g_list_append(col_l, g_strdup(col)g_strdup_inline (col));
3169 clp = clp->next;
3170 }
3171
3172 capture_column_str = join_string_list(col_l);
3173 prefs_clear_string_list(col_l);
3174 return capture_column_str;
3175}
3176
3177static prefs_set_pref_e
3178colorized_frame_set_cb(pref_t* pref, const char* value, unsigned int* changed_flags)
3179{
3180 (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
3181 return PREFS_SET_OK;
3182}
3183
3184static const char *
3185colorized_frame_type_name_cb(void)
3186{
3187 /* Don't write the colors of the 10 easy-access-colorfilters to the preferences
3188 * file until the colors can be changed in the GUI. Currently this is not really
3189 * possible since the STOCK-icons for these colors are hardcoded.
3190 *
3191 * XXX Find a way to change the colors of the STOCK-icons on the fly and then
3192 * add these 10 colors to the list of colors that can be changed through
3193 * the preferences.
3194 *
3195 */
3196 return NULL((void*)0);
3197}
3198
3199static char *
3200colorized_frame_type_description_cb(void)
3201{
3202 return g_strdup("")g_strdup_inline ("");
3203}
3204
3205static bool_Bool
3206colorized_frame_is_default_cb(pref_t* pref _U___attribute__((unused)))
3207{
3208 return true1;
3209}
3210
3211static char *
3212colorized_frame_to_str_cb(pref_t* pref _U___attribute__((unused)), bool_Bool default_val _U___attribute__((unused)))
3213{
3214 return g_strdup("")g_strdup_inline ("");
3215}
3216
3217/*
3218 * Register all non-dissector modules' preferences.
3219 */
3220static module_t *gui_module;
3221static module_t *gui_color_module;
3222static module_t *nameres_module;
3223
3224static void
3225prefs_register_modules(void)
3226{
3227 module_t *printing, *capture_module, *console_module,
3228 *gui_layout_module, *gui_font_module;
3229 module_t *extcap_module;
3230 unsigned int layout_gui_flags;
3231 struct pref_custom_cbs custom_cbs;
3232
3233 if (protocols_module != NULL((void*)0)) {
3234 /* Already setup preferences */
3235 return;
3236 }
3237
3238 /* GUI
3239 * These are "simple" GUI preferences that can be read/written using the
3240 * preference module API. These preferences still use their own
3241 * configuration screens for access, but this cuts down on the
3242 * preference "string compare list" in set_pref()
3243 */
3244 extcap_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "extcap", "Extcap Utilities",
3245 "Extcap Utilities", NULL((void*)0), NULL((void*)0), false0);
3246
3247 /* Setting default value to true */
3248 prefs.extcap_save_on_start = true1;
3249 prefs_register_bool_preference(extcap_module, "gui_save_on_start",
3250 "Save arguments on start of capture",
3251 "Save arguments on start of capture",
3252 &prefs.extcap_save_on_start);
3253
3254 /* GUI
3255 * These are "simple" GUI preferences that can be read/written using the
3256 * preference module API. These preferences still use their own
3257 * configuration screens for access, but this cuts down on the
3258 * preference "string compare list" in set_pref()
3259 */
3260 gui_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "gui", "User Interface",
3261 "User Interface", NULL((void*)0), &gui_callback, false0);
3262 /*
3263 * The GUI preferences don't affect dissection in general.
3264 * Any changes are signaled in other ways, so PREF_EFFECT_GUI doesn't
3265 * explicitly do anything, but wslua_set_preference expects *some*
3266 * effect flag to be set if the preference was changed.
3267 * We have to do this again for all the submodules (except for the
3268 * layout submodule, which has its own effect flag).
3269 */
3270 unsigned gui_effect_flags = prefs_get_module_effect_flags(gui_module);
3271 gui_effect_flags |= PREF_EFFECT_GUI(1u << 4);
3272 gui_effect_flags &= (~PREF_EFFECT_DISSECTION(1u << 0));
3273 prefs_set_module_effect_flags(gui_module, gui_effect_flags);
3274
3275 /*
3276 * gui.console_open is stored in the registry in addition to the
3277 * preferences file. It is also read independently by ws_log_init()
3278 * for early log initialization of the console.
3279 */
3280 prefs_register_enum_preference(gui_module, "console_open",
3281 "Open a console window",
3282 "Open a console window (Windows only)",
3283 (int *)&ws_log_console_open, gui_console_open_type, false0);
3284
3285 prefs_register_obsolete_preference(gui_module, "scrollbar_on_right");
3286 prefs_register_obsolete_preference(gui_module, "packet_list_sel_browse");
3287 prefs_register_obsolete_preference(gui_module, "protocol_tree_sel_browse");
3288 prefs_register_obsolete_preference(gui_module, "tree_view_altern_colors");
3289 prefs_register_obsolete_preference(gui_module, "expert_composite_eyecandy");
3290 prefs_register_obsolete_preference(gui_module, "filter_toolbar_show_in_statusbar");
3291
3292 prefs_register_bool_preference(gui_module, "restore_filter_after_following_stream",
3293 "Restore current display filter after following a stream",
3294 "Restore current display filter after following a stream?",
3295 &prefs.restore_filter_after_following_stream);
3296
3297 prefs_register_obsolete_preference(gui_module, "protocol_tree_line_style");
3298
3299 prefs_register_obsolete_preference(gui_module, "protocol_tree_expander_style");
3300
3301 prefs_register_obsolete_preference(gui_module, "hex_dump_highlight_style");
3302
3303 prefs_register_obsolete_preference(gui_module, "packet_editor.enabled");
3304
3305 gui_column_module = prefs_register_subtree(gui_module, prefs_modules, "Columns", "Columns", NULL((void*)0));
3306 prefs_set_module_effect_flags(gui_column_module, gui_effect_flags);
3307 /* For reading older preference files with "column." preferences */
3308 prefs_register_module_alias("column", gui_column_module);
3309
3310
3311 custom_cbs.free_cb = free_string_like_preference;
3312 custom_cbs.reset_cb = reset_string_like_preference;
3313 custom_cbs.set_cb = column_hidden_set_cb;
3314 custom_cbs.type_name_cb = column_hidden_type_name_cb;
3315 custom_cbs.type_description_cb = column_hidden_type_description_cb;
3316 custom_cbs.is_default_cb = column_hidden_is_default_cb;
3317 custom_cbs.to_str_cb = column_hidden_to_str_cb;
3318 register_string_like_preference(gui_column_module, PRS_COL_HIDDEN"column.hide", "Packet list hidden columns",
3319 "List all column indices (1-indexed) to hide in the packet list",
3320 &cols_hidden_list, PREF_CUSTOM, &custom_cbs, false0);
3321
3322 custom_cbs.set_cb = column_hidden_fmt_set_cb;
3323 custom_cbs.type_name_cb = column_hidden_fmt_type_name_cb;
3324 custom_cbs.type_description_cb = column_hidden_fmt_type_description_cb;
3325 custom_cbs.is_default_cb = column_hidden_fmt_is_default_cb;
3326 custom_cbs.to_str_cb = column_hidden_fmt_to_str_cb;
3327
3328 register_string_like_preference(gui_column_module, PRS_COL_HIDDEN_FMT"column.hidden", "Packet list hidden column formats (deprecated)",
3329 "List all column formats to hide in the packet list; deprecated in favor of the index-based preference",
3330 &cols_hidden_fmt_list, PREF_CUSTOM, &custom_cbs, false0);
3331
3332 custom_cbs.free_cb = column_format_free_cb;
3333 custom_cbs.reset_cb = column_format_reset_cb;
3334 custom_cbs.set_cb = column_format_set_cb;
3335 custom_cbs.type_name_cb = column_format_type_name_cb;
3336 custom_cbs.type_description_cb = column_format_type_description_cb;
3337 custom_cbs.is_default_cb = column_format_is_default_cb;
3338 custom_cbs.to_str_cb = column_format_to_str_cb;
3339
3340 prefs_register_list_custom_preference(gui_column_module, PRS_COL_FMT"column.format", "Packet list column format",
3341 "Each pair of strings consists of a column title and its format", &custom_cbs,
3342 column_format_init_cb, &prefs.col_list);
3343
3344 /* Number of columns. This is only used internally and is not written to the
3345 * preference file
3346 */
3347 custom_cbs.free_cb = custom_pref_no_cb;
3348 custom_cbs.reset_cb = column_num_reset_cb;
3349 custom_cbs.set_cb = column_num_set_cb;
3350 custom_cbs.type_name_cb = column_num_type_name_cb;
3351 custom_cbs.type_description_cb = column_num_type_description_cb;
3352 custom_cbs.is_default_cb = column_num_is_default_cb;
3353 custom_cbs.to_str_cb = column_num_to_str_cb;
3354 prefs_register_uint_custom_preference(gui_column_module, PRS_COL_NUM"column.number", "Number of columns",
3355 "Number of columns in col_list", &custom_cbs, &prefs.num_cols);
3356
3357 /* User Interface : Font */
3358 gui_font_module = prefs_register_subtree(gui_module, prefs_modules, "Font", "Font", NULL((void*)0));
3359 prefs_set_module_effect_flags(gui_font_module, gui_effect_flags);
3360
3361 prefs_register_obsolete_preference(gui_font_module, "font_name");
3362
3363 prefs_register_obsolete_preference(gui_font_module, "gtk2.font_name");
3364
3365 register_string_like_preference(gui_font_module, "qt.font_name", "Font name",
3366 "Font name for packet list, protocol tree, and hex dump panes. (Qt)",
3367 &prefs.gui_font_name, PREF_STRING, NULL((void*)0), true1);
3368
3369 /* User Interface : Colors */
3370 gui_color_module = prefs_register_subtree(gui_module, prefs_modules, "Colors", "Colors", NULL((void*)0));
3371 unsigned gui_color_effect_flags = gui_effect_flags | PREF_EFFECT_GUI_COLOR(1u << 5);
3372 prefs_set_module_effect_flags(gui_color_module, gui_color_effect_flags);
3373
3374 /* The appearance mode moved to global recent_common storage
3375 (recent.gui_color_scheme) so it no longer flips when switching
3376 profiles. Keep the old per-profile key registered as obsolete so
3377 existing preferences files load without an "unknown preference"
3378 warning. */
3379 prefs_register_obsolete_preference(gui_color_module, "color_scheme");
3380
3381 custom_cbs.free_cb = free_string_like_preference;
3382 custom_cbs.reset_cb = reset_string_like_preference;
3383 custom_cbs.set_cb = colorized_frame_set_cb;
3384 custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3385 custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3386 custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3387 custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3388 register_string_like_preference(gui_column_module, "colorized_frame.fg", "Colorized Foreground",
3389 "Filter Colorized Foreground",
3390 &prefs.gui_colorized_fg, PREF_CUSTOM, &custom_cbs, true1);
3391
3392 custom_cbs.free_cb = free_string_like_preference;
3393 custom_cbs.reset_cb = reset_string_like_preference;
3394 custom_cbs.set_cb = colorized_frame_set_cb;
3395 custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3396 custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3397 custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3398 custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3399 register_string_like_preference(gui_column_module, "colorized_frame.bg", "Colorized Background",
3400 "Filter Colorized Background",
3401 &prefs.gui_colorized_bg, PREF_CUSTOM, &custom_cbs, true1);
3402
3403 prefs_register_enum_preference(gui_module, "fileopen.style",
3404 "Where to start the File Open dialog box",
3405 "Where to start the File Open dialog box",
3406 (int*)&prefs.gui_fileopen_style, gui_fileopen_style, false0);
3407
3408 prefs_register_uint_preference(gui_module, "recent_files_count.max",
3409 "The max. number of items in the open recent files list",
3410 "The max. number of items in the open recent files list",
3411 10,
3412 &prefs.gui_recent_files_count_max);
3413
3414 prefs_register_uint_preference(gui_module, "recent_display_filter_entries.max",
3415 "The max. number of entries in the display filter list",
3416 "The max. number of entries in the display filter list",
3417 10,
3418 &prefs.gui_recent_df_entries_max);
3419
3420 register_string_like_preference(gui_module, "fileopen.dir", "Start Directory",
3421 "Directory to start in when opening File Open dialog.",
3422 &prefs.gui_fileopen_dir, PREF_DIRNAME, NULL((void*)0), true1);
3423
3424 prefs_register_obsolete_preference(gui_module, "fileopen.remembered_dir");
3425
3426 prefs_register_uint_preference(gui_module, "fileopen.preview",
3427 "The preview timeout in the File Open dialog",
3428 "The preview timeout in the File Open dialog",
3429 10,
3430 &prefs.gui_fileopen_preview);
3431
3432 register_string_like_preference(gui_module, "tlskeylog_command", "Program to launch with TLS Keylog",
3433 "Program path or command line to launch with SSLKEYLOGFILE",
3434 &prefs.gui_tlskeylog_command, PREF_STRING, NULL((void*)0), true1);
3435
3436 prefs_register_bool_preference(gui_module, "ask_unsaved",
3437 "Ask to save unsaved capture files",
3438 "Ask to save unsaved capture files?",
3439 &prefs.gui_ask_unsaved);
3440
3441 prefs_register_bool_preference(gui_module, "autocomplete_filter",
3442 "Display autocompletion for filter text",
3443 "Display an autocomplete suggestion for display and capture filter controls",
3444 &prefs.gui_autocomplete_filter);
3445
3446 prefs_register_bool_preference(gui_module, "find_wrap",
3447 "Wrap to beginning/end of file during search",
3448 "Wrap to beginning/end of file during search?",
3449 &prefs.gui_find_wrap);
3450
3451 prefs_register_obsolete_preference(gui_module, "use_pref_save");
3452
3453 prefs_register_bool_preference(gui_module, "geometry.save.position",
3454 "Save window position at exit",
3455 "Save window position at exit?",
3456 &prefs.gui_geometry_save_position);
3457
3458 prefs_register_bool_preference(gui_module, "geometry.save.size",
3459 "Save window size at exit",
3460 "Save window size at exit?",
3461 &prefs.gui_geometry_save_size);
3462
3463 prefs_register_bool_preference(gui_module, "geometry.save.maximized",
3464 "Save window maximized state at exit",
3465 "Save window maximized state at exit?",
3466 &prefs.gui_geometry_save_maximized);
3467
3468 prefs_register_obsolete_preference(gui_module, "macosx_style");
3469
3470 prefs_register_obsolete_preference(gui_module, "geometry.main.x");
3471 prefs_register_obsolete_preference(gui_module, "geometry.main.y");
3472 prefs_register_obsolete_preference(gui_module, "geometry.main.width");
3473 prefs_register_obsolete_preference(gui_module, "geometry.main.height");
3474 prefs_register_obsolete_preference(gui_module, "toolbar_main_show");
3475
3476 prefs_register_enum_preference(gui_module, "toolbar_main_style",
3477 "Main Toolbar style",
3478 "Main Toolbar style",
3479 &prefs.gui_toolbar_main_style, gui_toolbar_style, false0);
3480
3481 prefs_register_obsolete_preference(gui_module, "toolbar_filter_style");
3482 prefs_register_obsolete_preference(gui_module, "webbrowser");
3483
3484 prefs_register_bool_preference(gui_module, "update.enabled",
3485 "Check for updates",
3486 "Check for updates (Windows and macOS only)",
3487 &prefs.gui_update_enabled);
3488
3489 prefs_register_enum_preference(gui_module, "update.channel",
3490 "Update channel",
3491 "The type of update to fetch. You should probably leave this set to STABLE.",
3492 (int*)(void*)(&prefs.gui_update_channel), gui_update_channel, false0);
3493
3494 prefs_register_uint_preference(gui_module, "update.interval",
3495 "How often to check for software updates",
3496 "How often to check for software updates in seconds",
3497 10,
3498 &prefs.gui_update_interval);
3499
3500 prefs_register_uint_preference(gui_module, "debounce.timer",
3501 "How long to wait before processing computationally intensive user input",
3502 "How long to wait (in milliseconds) before processing "
3503 "computationally intensive user input. "
3504 "If you type quickly, consider lowering the value for a 'snappier' "
3505 "experience. "
3506 "If you type slowly, consider increasing the value to avoid performance issues. "
3507 "This is currently used to delay searches in View -> Internals -> Supported Protocols "
3508 "and Preferences -> Advanced menu.",
3509 10,
3510 &prefs.gui_debounce_timer);
3511
3512 register_string_like_preference(gui_module, "window_title", "Custom window title",
3513 "Custom window title to be appended to the existing title\n"
3514 "%C = capture comment from command line\n"
3515 "%F = file path of the capture file\n"
3516 "%P = profile name\n"
3517 "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3518 "%V = version info",
3519 &prefs.gui_window_title, PREF_STRING, NULL((void*)0), true1);
3520
3521 register_string_like_preference(gui_module, "prepend_window_title", "Custom window title prefix",
3522 "Custom window title to be prepended to the existing title\n"
3523 "%C = capture comment from command line\n"
3524 "%F = file path of the capture file\n"
3525 "%P = profile name\n"
3526 "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3527 "%V = version info",
3528 &prefs.gui_prepend_window_title, PREF_STRING, NULL((void*)0), true1);
3529
3530 register_string_like_preference(gui_module, "start_title", "Custom start page title",
3531 "Custom start page title",
3532 &prefs.gui_start_title, PREF_STRING, NULL((void*)0), true1);
3533
3534 prefs_register_enum_preference(gui_module, "version_placement",
3535 "Show version in the start page and/or main screen's title bar",
3536 "Show version in the start page and/or main screen's title bar",
3537 (int*)(void*)(&prefs.gui_version_placement), gui_version_placement_type, false0);
3538
3539 prefs_register_obsolete_preference(gui_module, "auto_scroll_on_expand");
3540 prefs_register_obsolete_preference(gui_module, "auto_scroll_percentage");
3541
3542 prefs_register_uint_preference(gui_module, "max_export_objects",
3543 "Maximum number of exported objects",
3544 "The maximum number of objects that can be exported",
3545 10,
3546 &prefs.gui_max_export_objects);
3547 prefs_register_uint_preference(gui_module, "max_tree_items",
3548 "Maximum number of tree items",
3549 "The maximum number of items that can be added to the dissection tree (Increase with caution)",
3550 10,
3551 &prefs.gui_max_tree_items);
3552 /*
3553 * Used independently by proto_tree_add_node, call_dissector*, dissector_try_heuristic,
3554 * and increment_dissection_depth.
3555 */
3556 prefs_register_uint_preference(gui_module, "max_tree_depth",
3557 "Maximum dissection depth",
3558 "The maximum depth for dissection tree and protocol layer checks. (Increase with caution)",
3559 10,
3560 &prefs.gui_max_tree_depth);
3561
3562 prefs_register_bool_preference(gui_module, "welcome_page.show_recent",
3563 "Show recent files on the welcome page",
3564 "This will enable or disable the 'Open' list on the welcome page.",
3565 &prefs.gui_welcome_page_show_recent);
3566
3567 /* User Interface : Layout */
3568 gui_layout_module = prefs_register_subtree(gui_module, prefs_modules, "Layout", "Layout", gui_layout_callback);
3569 /* Adjust the preference effects of layout GUI for better handling of preferences at Wireshark (GUI) level */
3570 layout_gui_flags = prefs_get_module_effect_flags(gui_layout_module);
3571 layout_gui_flags |= PREF_EFFECT_GUI_LAYOUT(1u << 2);
3572 layout_gui_flags &= (~PREF_EFFECT_DISSECTION(1u << 0));
3573
3574 prefs_register_uint_preference(gui_layout_module, "layout_type",
3575 "Layout type",
3576 "Layout type (1-6)",
3577 10,
3578 (unsigned*)(void*)(&prefs.gui_layout_type));
3579 prefs_set_effect_flags_by_name(gui_layout_module, "layout_type", layout_gui_flags);
3580
3581 prefs_register_enum_preference(gui_layout_module, "layout_content_1",
3582 "Layout content of the pane 1",
3583 "Layout content of the pane 1",
3584 (int*)(void*)(&prefs.gui_layout_content_1), gui_layout_content, false0);
3585 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_1", layout_gui_flags);
3586
3587 prefs_register_enum_preference(gui_layout_module, "layout_content_2",
3588 "Layout content of the pane 2",
3589 "Layout content of the pane 2",
3590 (int*)(void*)(&prefs.gui_layout_content_2), gui_layout_content, false0);
3591 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_2", layout_gui_flags);
3592
3593 prefs_register_enum_preference(gui_layout_module, "layout_content_3",
3594 "Layout content of the pane 3",
3595 "Layout content of the pane 3",
3596 (int*)(void*)(&prefs.gui_layout_content_3), gui_layout_content, false0);
3597 prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_3", layout_gui_flags);
3598
3599 prefs_register_bool_preference(gui_layout_module, "packet_list_separator.enabled",
3600 "Enable Packet List Separator",
3601 "Enable Packet List Separator",
3602 &prefs.gui_packet_list_separator);
3603
3604 prefs_register_bool_preference(gui_layout_module, "packet_header_column_definition.enabled",
3605 "Show column definition in packet list header",
3606 "Show column definition in packet list header",
3607 &prefs.gui_packet_header_column_definition);
3608
3609 /* packet_list_hover_style affects the colors, not the layout.
3610 * It's in the layout module to group it with the other packet list
3611 * preferences for the user's benefit with the dialog.
3612 */
3613 prefs_register_bool_preference(gui_layout_module, "packet_list_hover_style.enabled",
3614 "Enable Packet List mouse-over colorization",
3615 "Enable Packet List mouse-over colorization",
3616 &prefs.gui_packet_list_hover_style);
3617 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_hover_style.enabled", gui_color_effect_flags);
3618
3619 prefs_register_bool_preference(gui_layout_module, "show_selected_packet.enabled",
3620 "Show selected packet in the Status Bar",
3621 "Show selected packet in the Status Bar",
3622 &prefs.gui_show_selected_packet);
3623
3624 prefs_register_bool_preference(gui_layout_module, "show_file_load_time.enabled",
3625 "Show file load time in the Status Bar",
3626 "Show file load time in the Status Bar",
3627 &prefs.gui_show_file_load_time);
3628
3629 prefs_register_enum_preference(gui_layout_module, "packet_dialog_layout",
3630 "Packet Dialog layout",
3631 "Packet Dialog layout",
3632 (int*)(&prefs.gui_packet_dialog_layout), gui_packet_dialog_layout, false0);
3633
3634 prefs_register_enum_preference(gui_module, "packet_list_elide_mode",
3635 "Elide mode",
3636 "The position of \"...\" (ellipsis) in packet list text.",
3637 (int*)(void*)(&prefs.gui_packet_list_elide_mode), gui_packet_list_elide_mode, false0);
3638 prefs_register_uint_preference(gui_module, "decimal_places1",
3639 "Count of decimal places for values of type 1",
3640 "Sets the count of decimal places for values of type 1."
3641 "Type 1 values are defined by authors."
3642 "Value can be in range 2 to 10.",
3643 10,&prefs.gui_decimal_places1);
3644
3645 prefs_register_uint_preference(gui_module, "decimal_places2",
3646 "Count of decimal places for values of type 2",
3647 "Sets the count of decimal places for values of type 2."
3648 "Type 2 values are defined by authors."
3649 "Value can be in range 2 to 10.",
3650 10,&prefs.gui_decimal_places2);
3651
3652 prefs_register_uint_preference(gui_module, "decimal_places3",
3653 "Count of decimal places for values of type 3",
3654 "Sets the count of decimal places for values of type 3."
3655 "Type 3 values are defined by authors."
3656 "Value can be in range 2 to 10.",
3657 10,&prefs.gui_decimal_places3);
3658
3659 prefs_register_bool_preference(gui_module, "rtp_player_use_disk1",
3660 "RTP Player saves temporary data to disk",
3661 "If set to true, RTP Player saves temporary data to "
3662 "temp files on disk. If not set, it uses memory."
3663 "Every stream uses one file therefore you might touch "
3664 "OS limit for count of opened files."
3665 "When ui.rtp_player_use_disk2 is set to true too, it uses "
3666 " two files per RTP stream together."
3667 ,&prefs.gui_rtp_player_use_disk1);
3668
3669 prefs_register_bool_preference(gui_module, "rtp_player_use_disk2",
3670 "RTP Player saves temporary dictionary for data to disk",
3671 "If set to true, RTP Player saves temporary dictionary to "
3672 "temp files on disk. If not set, it uses memory."
3673 "Every stream uses one file therefore you might touch "
3674 "OS limit for count of opened files."
3675 "When ui.rtp_player_use_disk1 is set to true too, it uses "
3676 " two files per RTP stream."
3677 ,&prefs.gui_rtp_player_use_disk2);
3678
3679 prefs_register_enum_preference(gui_layout_module, "gui_packet_list_copy_format_options_for_keyboard_shortcut",
3680 "Allows text to be copied with selected format",
3681 "Allows text to be copied with selected format when copied via keyboard",
3682 (int*)(void*)(&prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut),
3683 gui_packet_list_copy_format_options_for_keyboard_shortcut, false0);
3684
3685 prefs_register_bool_preference(gui_layout_module, "gui_packet_list_copy_text_with_aligned_columns",
3686 "Allows text to be copied with aligned columns",
3687 "Allows text to be copied with aligned columns when copied via menu or keyboard",
3688 &prefs.gui_packet_list_copy_text_with_aligned_columns);
3689
3690 prefs_register_bool_preference(gui_layout_module, "packet_list_show_related",
3691 "Show Related Packets",
3692 "Show related packet indicators in the first column",
3693 &prefs.gui_packet_list_show_related);
3694
3695 prefs_register_bool_preference(gui_layout_module, "packet_list_show_minimap",
3696 "Enable Intelligent Scroll Bar",
3697 "Show the intelligent scroll bar (a minimap of packet list colors in the scrollbar)",
3698 &prefs.gui_packet_list_show_minimap);
3699 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_show_minimap", gui_color_effect_flags);
3700
3701 prefs_register_enum_preference(gui_layout_module, "packet_list_multi_color_mode",
3702 "Multi-Color Display Mode",
3703 "How to display multiple colors: Equal Stripes (entire row) or Shift Right (configurable primary color percentage)",
3704 (int*)(void*)(&prefs.gui_packet_list_multi_color_mode), gui_packet_list_multi_color_modes, false0);
3705 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_multi_color_mode", gui_color_effect_flags);
3706
3707 prefs_register_uint_preference(gui_layout_module, "packet_list_multi_color_shift_percent",
3708 "Shift Right percentage",
3709 "Primary color percentage in Shift Right mode (75, 80, 85, 90, or 95)",
3710 10,
3711 &prefs.gui_packet_list_multi_color_shift_percent);
3712 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_multi_color_shift_percent", gui_color_effect_flags);
3713
3714 prefs_register_bool_preference(gui_module, "packet_list_multi_color_details",
3715 "Display Multiple Colors in Packet Details",
3716 "Show all matching color filter names in packet details pane and TShark output when multiple color filters match",
3717 &prefs.gui_packet_list_multi_color_details);
3718 /* This preference affects what is shown in the packet detail proto tree,
3719 * so changing it requires re-dissection to take effect immediately. */
3720 prefs_set_preference_effect(gui_module, "packet_list_multi_color_details",
3721 PREF_EFFECT_DISSECTION(1u << 0));
3722
3723 prefs_register_enum_preference(gui_layout_module, "packet_list_multi_color_separator",
3724 "Color Stripe Separator Style",
3725 "Shape of the boundary between color stripes: Vertical, Diagonal (candy-cane), or Bubble (half-moon)",
3726 (int*)(void*)(&prefs.gui_packet_list_multi_color_separator), gui_packet_list_multi_color_separators, false0);
3727 prefs_set_effect_flags_by_name(gui_layout_module, "packet_list_multi_color_separator", gui_color_effect_flags);
3728
3729 prefs_register_bool_preference(gui_module, "packet_list_is_sortable",
3730 "Allow packet list to be sortable",
3731 "To prevent sorting by mistake (which can take some time to calculate), it can be disabled",
3732 &prefs.gui_packet_list_sortable);
3733
3734 prefs_register_uint_preference(gui_module, "packet_list_cached_rows_max",
3735 "Maximum cached rows",
3736 "Maximum number of rows that can be sorted by columns that require dissection. Increasing this increases memory consumption by caching column text",
3737 10,
3738 &prefs.gui_packet_list_cached_rows_max);
3739
3740 prefs_register_bool_preference(gui_module, "interfaces_show_hidden",
3741 "Show hidden interfaces",
3742 "Show all interfaces, including interfaces marked as hidden",
3743 &prefs.gui_interfaces_show_hidden);
3744
3745 prefs_register_bool_preference(gui_module, "interfaces_remote_display",
3746 "Show Remote interfaces",
3747 "Show remote interfaces in the interface selection",
3748 &prefs.gui_interfaces_remote_display);
3749
3750 register_string_like_preference(gui_module, "interfaces_hidden_types", "Hide interface types in list",
3751 "Hide the given interface types in the startup list.\n"
3752 "A comma-separated string of interface type values (e.g. 5,9).\n"
3753 "0 = Wired,\n"
3754 "1 = AirPCAP,\n"
3755 "2 = Pipe,\n"
3756 "3 = STDIN,\n"
3757 "4 = Bluetooth,\n"
3758 "5 = Wireless,\n"
3759 "6 = Dial-Up,\n"
3760 "7 = USB,\n"
3761 "8 = External Capture,\n"
3762 "9 = Virtual",
3763 &prefs.gui_interfaces_hide_types, PREF_STRING, NULL((void*)0), true1);
3764
3765 prefs_register_bool_preference(gui_module, "io_graph_automatic_update",
3766 "Enables automatic updates for IO Graph",
3767 "Enables automatic updates for IO Graph",
3768 &prefs.gui_io_graph_automatic_update);
3769
3770 prefs_register_bool_preference(gui_module, "io_graph_enable_legend",
3771 "Enables the legend of IO Graph",
3772 "Enables the legend of IO Graph",
3773 &prefs.gui_io_graph_enable_legend);
3774
3775 prefs_register_bool_preference(gui_module, "plot_automatic_update",
3776 "Enables automatic updates for Plot",
3777 "Enables automatic updates for Plot",
3778 &prefs.gui_plot_automatic_update);
3779
3780 prefs_register_bool_preference(gui_module, "plot_enable_legend",
3781 "Enables the legend of Plot",
3782 "Enables the legend of Plot",
3783 &prefs.gui_plot_enable_legend);
3784
3785 prefs_register_bool_preference(gui_module, "plot_enable_auto_scroll",
3786 "Enables auto scroll of Plot",
3787 "Enables auto scroll of Plot",
3788 &prefs.gui_plot_enable_auto_scroll);
3789
3790 prefs_register_bool_preference(gui_module, "show_byteview_in_dialog",
3791 "Show the byte view in the packet details dialog",
3792 "Show the byte view in the packet details dialog",
3793 &prefs.gui_packet_details_show_byteview);
3794
3795 /* Console
3796 * These are preferences that can be read/written using the
3797 * preference module API. These preferences still use their own
3798 * configuration screens for access, but this cuts down on the
3799 * preference "string compare list" in set_pref()
3800 */
3801 console_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "console", "Console",
3802 "Console logging and debugging output", NULL((void*)0), NULL((void*)0), false0);
3803
3804 prefs_register_obsolete_preference(console_module, "log.level");
3805
3806 prefs_register_bool_preference(console_module, "incomplete_dissectors_check_debug",
3807 "Print debug line for incomplete dissectors",
3808 "Look for dissectors that left some bytes undecoded (debug)",
3809 &prefs.incomplete_dissectors_check_debug);
3810
3811 /* Display filter Expressions
3812 * This used to be an array of individual fields that has now been
3813 * converted to a UAT. Just make it part of the GUI category even
3814 * though the name of the preference will never be seen in preference
3815 * file
3816 */
3817 filter_expression_register_uat(gui_module);
3818
3819 /* Capture
3820 * These are preferences that can be read/written using the
3821 * preference module API. These preferences still use their own
3822 * configuration screens for access, but this cuts down on the
3823 * preference "string compare list" in set_pref()
3824 */
3825 capture_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "capture", "Capture",
3826 "Capture preferences", NULL((void*)0), apply_aggregation_prefs, false0);
3827 /* Capture preferences don't affect dissection */
3828 prefs_set_module_effect_flags(capture_module, PREF_EFFECT_CAPTURE(1u << 1));
3829
3830 register_string_like_preference(capture_module, "device", "Default capture device",
3831 "Default capture device",
3832 &prefs.capture_device, PREF_STRING, NULL((void*)0), false0);
3833
3834 register_string_like_preference(capture_module, "devices_linktypes", "Interface link-layer header type",
3835 "Interface link-layer header types (Ex: en0(1),en1(143),...)",
3836 &prefs.capture_devices_linktypes, PREF_STRING, NULL((void*)0), false0);
3837
3838 register_string_like_preference(capture_module, "devices_descr", "Interface descriptions",
3839 "Interface descriptions (Ex: eth0(eth0 descr),eth1(eth1 descr),...)",
3840 &prefs.capture_devices_descr, PREF_STRING, NULL((void*)0), false0);
3841
3842 register_string_like_preference(capture_module, "devices_hide", "Hide interface",
3843 "Hide interface? (Ex: eth0,eth3,...)",
3844 &prefs.capture_devices_hide, PREF_STRING, NULL((void*)0), false0);
3845
3846 register_string_like_preference(capture_module, "devices_monitor_mode", "Capture in monitor mode",
3847 "By default, capture in monitor mode on interface? (Ex: eth0,eth3,...)",
3848 &prefs.capture_devices_monitor_mode, PREF_STRING, NULL((void*)0), false0);
3849
3850 register_string_like_preference(capture_module, "devices_buffersize", "Interface buffer size",
3851 "Interface buffer size (Ex: en0(1),en1(143),...)",
3852 &prefs.capture_devices_buffersize, PREF_STRING, NULL((void*)0), false0);
3853
3854 register_string_like_preference(capture_module, "devices_snaplen", "Interface snap length",
3855 "Interface snap length (Ex: en0(65535),en1(1430),...)",
3856 &prefs.capture_devices_snaplen, PREF_STRING, NULL((void*)0), false0);
3857
3858 register_string_like_preference(capture_module, "devices_pmode", "Interface promiscuous mode",
3859 "Interface promiscuous mode (Ex: en0(0),en1(1),...)",
3860 &prefs.capture_devices_pmode, PREF_STRING, NULL((void*)0), false0);
3861
3862 prefs_register_bool_preference(capture_module, "prom_mode", "Capture in promiscuous mode",
3863 "Capture in promiscuous mode?", &prefs.capture_prom_mode);
3864
3865 prefs_register_bool_preference(capture_module, "monitor_mode", "Capture in monitor mode on 802.11 devices",
3866 "Capture in monitor mode on all 802.11 devices that support it?", &prefs.capture_monitor_mode);
3867
3868 register_string_like_preference(capture_module, "devices_filter", "Interface capture filter",
3869 "Interface capture filter (Ex: en0(tcp),en1(udp),...)",
3870 &prefs.capture_devices_filter, PREF_STRING, NULL((void*)0), false0);
3871
3872 prefs_register_bool_preference(capture_module, "pcap_ng", "Capture in pcapng format",
3873 "Capture in pcapng format?", &prefs.capture_pcap_ng);
3874
3875 prefs_register_bool_preference(capture_module, "real_time_update", "Update packet list in real time during capture",
3876 "Update packet list in real time during capture?", &prefs.capture_real_time);
3877
3878 prefs_register_uint_preference(capture_module, "update_interval",
3879 "Capture update interval",
3880 "Capture update interval in ms",
3881 10,
3882 &prefs.capture_update_interval);
3883
3884 prefs_register_bool_preference(capture_module, "no_interface_load", "Don't load interfaces on startup",
3885 "Don't automatically load capture interfaces on startup", &prefs.capture_no_interface_load);
3886
3887 prefs_register_bool_preference(capture_module, "no_extcap", "Disable external capture interfaces",
3888 "Disable external capture modules (extcap)", &prefs.capture_no_extcap);
3889
3890 prefs_register_obsolete_preference(capture_module, "auto_scroll");
3891
3892 prefs_register_bool_preference(capture_module, "show_info", "Show capture information dialog while capturing",
3893 "Show capture information dialog while capturing?", &prefs.capture_show_info);
3894
3895 prefs_register_obsolete_preference(capture_module, "syntax_check_filter");
3896
3897 custom_cbs.free_cb = capture_column_free_cb;
3898 custom_cbs.reset_cb = capture_column_reset_cb;
3899 custom_cbs.set_cb = capture_column_set_cb;
3900 custom_cbs.type_name_cb = capture_column_type_name_cb;
3901 custom_cbs.type_description_cb = capture_column_type_description_cb;
3902 custom_cbs.is_default_cb = capture_column_is_default_cb;
3903 custom_cbs.to_str_cb = capture_column_to_str_cb;
3904 prefs_register_list_custom_preference(capture_module, "columns", "Capture options dialog column list",
3905 "List of columns to be displayed", &custom_cbs, capture_column_init_cb, &prefs.capture_columns);
3906 aggregation_field_register_uat(capture_module);
3907
3908 /* Name Resolution */
3909 nameres_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "nameres", "Name Resolution",
3910 "Name Resolution", "ChCustPreferencesSection.html#ChCustPrefsNameSection", addr_resolve_pref_apply, true1);
3911 addr_resolve_pref_init(nameres_module);
3912 oid_pref_init(nameres_module);
3913 maxmind_db_pref_init(nameres_module);
3914
3915 /* Printing
3916 * None of these have any effect; we keep them as obsolete preferences
3917 * in order to avoid errors when reading older preference files.
3918 */
3919 printing = prefs_register_module(prefs_top_level_modules, prefs_modules, "print", "Printing",
3920 "Printing", NULL((void*)0), NULL((void*)0), false0);
3921 prefs_register_obsolete_preference(printing, "format");
3922 prefs_register_obsolete_preference(printing, "command");
3923 prefs_register_obsolete_preference(printing, "file");
3924
3925 /* Codecs */
3926 codecs_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "codecs", "Codecs",
3927 "Codecs", NULL((void*)0), NULL((void*)0), true1);
3928
3929 /* Statistics */
3930 stats_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "statistics", "Statistics",
3931 "Statistics", "ChCustPreferencesSection.html#_statistics", &stats_callback, true1);
3932
3933 prefs_register_uint_preference(stats_module, "update_interval",
3934 "Tap update interval in ms",
3935 "Determines time between tap updates",
3936 10,
3937 &prefs.tap_update_interval);
3938
3939 prefs_register_uint_preference(stats_module, "flow_graph_max_export_items",
3940 "Maximum Flow Graph items to export as image",
3941 "The maximum number of Flow Graph items (frames) "
3942 "to include when exporting the graph as an image. "
3943 "Note that some formats (e.g., JPEG) have inherent "
3944 "pixel limits and image viewers might be unable to "
3945 "handle very large images.",
3946 10,
3947 &prefs.flow_graph_max_export_items);
3948
3949 prefs_register_bool_preference(stats_module, "st_enable_burstinfo",
3950 "Enable the calculation of burst information",
3951 "If enabled burst rates will be calculated for statistics that use the stats_tree system. "
3952 "Burst rates are calculated over a much shorter time interval than the rate column.",
3953 &prefs.st_enable_burstinfo);
3954
3955 prefs_register_bool_preference(stats_module, "st_burst_showcount",
3956 "Show burst count for item rather than rate",
3957 "If selected the stats_tree statistics nodes will show the count of events "
3958 "within the burst window instead of a burst rate. Burst rate is calculated "
3959 "as number of events within burst window divided by the burst windown length.",
3960 &prefs.st_burst_showcount);
3961
3962 prefs_register_uint_preference(stats_module, "st_burst_resolution",
3963 "Burst rate resolution (ms)",
3964 "Sets the duration of the time interval into which events are grouped when calculating "
3965 "the burst rate. Higher resolution (smaller number) increases processing overhead.",
3966 10,&prefs.st_burst_resolution);
3967
3968 prefs_register_uint_preference(stats_module, "st_burst_windowlen",
3969 "Burst rate window size (ms)",
3970 "Sets the duration of the sliding window during which the burst rate is "
3971 "measured. Longer window relative to burst rate resolution increases "
3972 "processing overhead. Will be truncated to a multiple of burst resolution.",
3973 10,&prefs.st_burst_windowlen);
3974
3975 prefs_register_enum_preference(stats_module, "st_sort_defcolflag",
3976 "Default sort column for stats_tree stats",
3977 "Sets the default column by which stats based on the stats_tree "
3978 "system is sorted.",
3979 &prefs.st_sort_defcolflag, st_sort_col_vals, false0);
3980
3981 prefs_register_bool_preference(stats_module, "st_sort_defdescending",
3982 "Default stats_tree sort order is descending",
3983 "When selected, statistics based on the stats_tree system will by default "
3984 "be sorted in descending order.",
3985 &prefs.st_sort_defdescending);
3986
3987 prefs_register_bool_preference(stats_module, "st_sort_casesensitve",
3988 "Case sensitive sort of stats_tree item names",
3989 "When selected, the item/node names of statistics based on the stats_tree "
3990 "system will be sorted taking case into account. Else the case of the name "
3991 "will be ignored.",
3992 &prefs.st_sort_casesensitve);
3993
3994 prefs_register_bool_preference(stats_module, "st_sort_rng_nameonly",
3995 "Always sort 'range' nodes by name",
3996 "When selected, the stats_tree nodes representing a range of values "
3997 "(0-49, 50-100, etc.) will always be sorted by name (the range of the "
3998 "node). Else range nodes are sorted by the same column as the rest of "
3999 " the tree.",
4000 &prefs.st_sort_rng_nameonly);
4001
4002 prefs_register_bool_preference(stats_module, "st_sort_rng_fixorder",
4003 "Always sort 'range' nodes in ascending order",
4004 "When selected, the stats_tree nodes representing a range of values "
4005 "(0-49, 50-100, etc.) will always be sorted ascending; else it follows "
4006 "the sort direction of the tree. Only effective if \"Always sort "
4007 "'range' nodes by name\" is also selected.",
4008 &prefs.st_sort_rng_fixorder);
4009
4010 prefs_register_bool_preference(stats_module, "st_sort_showfullname",
4011 "Display the full stats_tree plug-in name",
4012 "When selected, the full name (including menu path) of the stats_tree "
4013 "plug-in is show in windows. If cleared the plug-in name is shown "
4014 "without menu path (only the part of the name after last '/' character.)",
4015 &prefs.st_sort_showfullname);
4016
4017 prefs_register_enum_preference(stats_module, "output_format",
4018 "Default output format",
4019 "Sets the default output format for statistical data. Only supported "
4020 "by taps using the stats_tree system currently; other taps may honor "
4021 "this preference in the future. ",
4022 &prefs.st_format, st_format_vals, false0);
4023
4024 module_t *conv_module;
4025 // avoid using prefs_register_stat to prevent lint complaint about recursion
4026 conv_module = prefs_register_submodule(stats_module, prefs_modules, "conv", "Conversations",
4027 "Conversations & Endpoints", NULL((void*)0), NULL((void*)0), true1);
4028 prefs_register_bool_preference(conv_module, "machine_readable",
4029 "Display exact (machine-readable) byte counts",
4030 "When enabled, exact machine-readable byte counts are displayed. "
4031 "When disabled, human readable numbers with SI prefixes are displayed.",
4032 &prefs.conv_machine_readable);
4033
4034 /* Protocols */
4035 protocols_module = prefs_register_module(prefs_top_level_modules, prefs_modules, "protocols", "Protocols",
4036 "Protocols", "ChCustPreferencesSection.html#ChCustPrefsProtocolsSection", NULL((void*)0), true1);
4037
4038 prefs_register_bool_preference(protocols_module, "display_hidden_proto_items",
4039 "Display hidden protocol items",
4040 "Display all hidden protocol items in the packet list.",
4041 &prefs.display_hidden_proto_items);
4042
4043 prefs_register_bool_preference(protocols_module, "display_byte_fields_with_spaces",
4044 "Display byte fields with a space character between bytes",
4045 "Display all byte fields with a space character between each byte in the packet list.",
4046 &prefs.display_byte_fields_with_spaces);
4047
4048 /*
4049 * Note the -t / option only affects the display of the packet timestamp
4050 * in the default time column; this is for all other absolute times.
4051 */
4052 prefs_register_enum_preference(protocols_module, "display_abs_time_ascii",
4053 "Format absolute times like asctime",
4054 "When to format absolute times similar to asctime instead of ISO 8601, for backwards compatibility with older Wireshark.",
4055 (int*)&prefs.display_abs_time_ascii, abs_time_format_options, false0);
4056
4057 prefs_register_bool_preference(protocols_module, "enable_incomplete_dissectors_check",
4058 "Look for incomplete dissectors",
4059 "Look for dissectors that left some bytes undecoded.",
4060 &prefs.enable_incomplete_dissectors_check);
4061
4062 prefs_register_bool_preference(protocols_module, "strict_conversation_tracking_heuristics",
4063 "Enable stricter conversation tracking heuristics",
4064 "Protocols may use things like VLAN ID or interface ID to narrow the potential for duplicate conversations. "
4065 "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",
4066 &prefs.strict_conversation_tracking_heuristics);
4067
4068 prefs_register_bool_preference(protocols_module, "ignore_dup_frames",
4069 "Ignore duplicate frames",
4070 "Ignore frames that are exact duplicates of any previous frame.",
4071 &prefs.ignore_dup_frames);
4072
4073 prefs_register_enum_preference(protocols_module, "conversation_deinterlacing_key",
4074 "Deinterlacing conversations key",
4075 "Separate into different conversations frames that look like duplicates but have different Interface, MAC, or VLAN field values.",
4076 (int *)&prefs.conversation_deinterlacing_key, conv_deint_options, false0);
4077
4078 prefs_register_uint_preference(protocols_module, "ignore_dup_frames_cache_entries",
4079 "The max number of hashes to keep in memory for determining duplicates frames",
4080 "If \"Ignore duplicate frames\" is set, this setting sets the maximum number "
4081 "of cache entries to maintain. A 0 means no limit.",
4082 10, &prefs.ignore_dup_frames_cache_entries);
4083
4084
4085 /* Obsolete preferences
4086 * These "modules" were reorganized/renamed to correspond to their GUI
4087 * configuration screen within the preferences dialog
4088 */
4089
4090 /* taps is now part of the stats module */
4091 prefs_register_module(prefs_top_level_modules, prefs_modules, "taps", "TAPS", "TAPS", NULL((void*)0), NULL((void*)0), false0);
4092 /* packet_list is now part of the protocol (parent) module */
4093 prefs_register_module(prefs_top_level_modules, prefs_modules, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL((void*)0), NULL((void*)0), false0);
4094 /* stream is now part of the gui module */
4095 prefs_register_module(prefs_top_level_modules, prefs_modules, "stream", "STREAM", "STREAM", NULL((void*)0), NULL((void*)0), false0);
4096
4097}
4098
4099/* Parse through a list of comma-separated, possibly quoted strings.
4100 Return a list of the string data. */
4101GList *
4102prefs_get_string_list(const char *str)
4103{
4104 enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
4105
4106 int state = PRE_STRING, i = 0;
4107 bool_Bool backslash = false0;
4108 unsigned char cur_c;
4109 const size_t default_size = 64;
4110 GString *slstr = NULL((void*)0);
4111 GList *sl = NULL((void*)0);
4112
4113 /* Allocate a buffer for the first string. */
4114 slstr = g_string_sized_new(default_size);
4115
4116 for (;;) {
4117 cur_c = str[i];
4118 if (cur_c == '\0') {
4119 /* It's the end of the input, so it's the end of the string we
4120 were working on, and there's no more input. */
4121 if (state == IN_QUOT || backslash) {
4122 /* We were in the middle of a quoted string or backslash escape,
4123 and ran out of characters; that's an error. */
4124 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)))))
;
4125 prefs_clear_string_list(sl);
4126 return NULL((void*)0);
4127 }
4128 if (slstr->len > 0)
4129 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))))
);
4130 else
4131 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)))))
;
4132 break;
4133 }
4134 if (cur_c == '"' && !backslash) {
4135 switch (state) {
4136 case PRE_STRING:
4137 /* We hadn't yet started processing a string; this starts the
4138 string, and we're now quoting. */
4139 state = IN_QUOT;
4140 break;
4141 case IN_QUOT:
4142 /* We're in the middle of a quoted string, and we saw a quotation
4143 mark; we're no longer quoting. */
4144 state = NOT_IN_QUOT;
4145 break;
4146 case NOT_IN_QUOT:
4147 /* We're working on a string, but haven't seen a quote; we're
4148 now quoting. */
4149 state = IN_QUOT;
4150 break;
4151 default:
4152 break;
4153 }
4154 } else if (cur_c == '\\' && !backslash) {
4155 /* We saw a backslash, and the previous character wasn't a
4156 backslash; escape the next character.
4157
4158 This also means we've started a new string. */
4159 backslash = true1;
4160 if (state == PRE_STRING)
4161 state = NOT_IN_QUOT;
4162 } else if (cur_c == ',' && state != IN_QUOT && !backslash) {
4163 /* We saw a comma, and we're not in the middle of a quoted string
4164 and it wasn't preceded by a backslash; it's the end of
4165 the string we were working on... */
4166 if (slstr->len > 0) {
4167 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))))
);
4168 slstr = g_string_sized_new(default_size);
4169 }
4170
4171 /* ...and the beginning of a new string. */
4172 state = PRE_STRING;
4173 } else if (!g_ascii_isspace(cur_c)((g_ascii_table[(guchar) (cur_c)] & G_ASCII_SPACE) != 0) || state != PRE_STRING) {
4174 /* Either this isn't a white-space character, or we've started a
4175 string (i.e., already seen a non-white-space character for that
4176 string and put it into the string).
4177
4178 The character is to be put into the string; do so. */
4179 g_string_append_c(slstr, cur_c)g_string_append_c_inline (slstr, cur_c);
4180
4181 /* If it was backslash-escaped, we're done with the backslash escape. */
4182 backslash = false0;
4183 }
4184 i++;
4185 }
4186 return(sl);
4187}
4188
4189char *join_string_list(GList *sl)
4190{
4191 GString *joined_str = g_string_new("");
4192 GList *cur, *first;
4193 char *str;
4194 unsigned item_count = 0;
4195
4196 cur = first = g_list_first(sl);
4197 while (cur) {
4198 item_count++;
4199 str = (char *)cur->data;
4200
4201 if (cur != first)
4202 g_string_append_c(joined_str, ',')g_string_append_c_inline (joined_str, ',');
4203
4204 if (item_count % 2) {
4205 /* Wrap the line. */
4206 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))
;
4207 } else
4208 g_string_append_c(joined_str, ' ')g_string_append_c_inline (joined_str, ' ');
4209
4210 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4211 while (*str) {
4212 gunichar uc = g_utf8_get_char (str);
4213
4214 if (uc == '"' || uc == '\\')
4215 g_string_append_c(joined_str, '\\')g_string_append_c_inline (joined_str, '\\');
4216
4217 if (g_unichar_isprint(uc))
4218 g_string_append_unichar (joined_str, uc);
4219
4220 str = g_utf8_next_char (str)((str) + g_utf8_skip[*(const guchar *)(str)]);
4221 }
4222
4223 g_string_append_c(joined_str, '"')g_string_append_c_inline (joined_str, '"');
4224
4225 cur = cur->next;
4226 }
4227 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))))
;
4228}
4229
4230void
4231prefs_clear_string_list(GList *sl)
4232{
4233 g_list_free_full(sl, g_free);
4234}
4235
4236/*
4237 * Takes a string, a pointer to an array of "enum_val_t"s, and a default int
4238 * value.
4239 * The array must be terminated by an entry with a null "name" string.
4240 *
4241 * If the string matches a "name" string in an entry, the value from that
4242 * entry is returned.
4243 *
4244 * Otherwise, if a string matches a "description" string in an entry, the
4245 * value from that entry is returned; we do that for backwards compatibility,
4246 * as we used to have only a "name" string that was used both for command-line
4247 * and configuration-file values and in the GUI (which meant either that
4248 * the GUI had what might be somewhat cryptic values to select from or that
4249 * the "-o" flag took long strings, often with spaces in them).
4250 *
4251 * Otherwise, the default value that was passed as the third argument is
4252 * returned.
4253 */
4254static int
4255find_val_for_string(const char *needle, const enum_val_t *haystack,
4256 int default_value)
4257{
4258 int i;
4259
4260 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4261 if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
4262 return haystack[i].value;
4263 }
4264 }
4265 for (i = 0; haystack[i].name != NULL((void*)0); i++) {
4266 if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
4267 return haystack[i].value;
4268 }
4269 }
4270 return default_value;
4271}
4272
4273/* Preferences file format:
4274 * - Configuration directives start at the beginning of the line, and
4275 * are terminated with a colon.
4276 * - Directives can be continued on the next line by preceding them with
4277 * whitespace.
4278 *
4279 * Example:
4280
4281# This is a comment line
4282print.command: lpr
4283print.file: /a/very/long/path/
4284 to/wireshark-out.ps
4285 *
4286 */
4287
4288/*
4289 * Initialize non-dissector preferences used by the "register preference" API
4290 * to default values so the default values can be used when registered.
4291 *
4292 * String, filename, and directory preferences will be g_freed so they must
4293 * be g_mallocated.
4294 */
4295static void
4296prefs_set_global_defaults(wmem_allocator_t* pref_scope, const char** col_fmt, int num_cols)
4297{
4298 int i;
4299 char *col_name;
4300 fmt_data *cfmt;
4301
4302 prefs.restore_filter_after_following_stream = false0;
4303 prefs.gui_toolbar_main_style = TB_STYLE_ICONS0;
4304 /* We try to find the best font in the Qt code */
4305 wmem_free(pref_scope, prefs.gui_font_name);
4306 prefs.gui_font_name = wmem_strdup(pref_scope, "");
4307 wmem_free(pref_scope, prefs.gui_colorized_fg);
4308 prefs.gui_colorized_fg = wmem_strdup(pref_scope, "000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
4309 wmem_free(pref_scope, prefs.gui_colorized_bg);
4310 prefs.gui_colorized_bg = wmem_strdup(pref_scope, "ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
4311
4312 prefs.gui_geometry_save_position = true1;
4313 prefs.gui_geometry_save_size = true1;
4314 prefs.gui_geometry_save_maximized= true1;
4315 prefs.gui_fileopen_style = FO_STYLE_LAST_OPENED0;
4316 prefs.gui_recent_df_entries_max = 10;
4317 prefs.gui_recent_files_count_max = 10;
4318 wmem_free(pref_scope, prefs.gui_fileopen_dir);
4319 prefs.gui_fileopen_dir = wmem_strdup(pref_scope, get_persdatafile_dir());
4320 prefs.gui_fileopen_preview = 3;
4321 wmem_free(pref_scope, prefs.gui_tlskeylog_command);
4322 prefs.gui_tlskeylog_command = wmem_strdup(pref_scope, "");
4323 prefs.gui_ask_unsaved = true1;
4324 prefs.gui_autocomplete_filter = true1;
4325 prefs.gui_find_wrap = true1;
4326 prefs.gui_update_enabled = true1;
4327 prefs.gui_update_channel = UPDATE_CHANNEL_STABLE;
4328 prefs.gui_update_interval = 60*60*24; /* Seconds */
4329 prefs.gui_debounce_timer = 400; /* milliseconds */
4330 wmem_free(pref_scope, prefs.gui_window_title);
4331 prefs.gui_window_title = wmem_strdup(pref_scope, "");
4332 wmem_free(pref_scope, prefs.gui_prepend_window_title);
4333 prefs.gui_prepend_window_title = wmem_strdup(pref_scope, "");
4334 wmem_free(pref_scope, prefs.gui_start_title);
4335 prefs.gui_start_title = wmem_strdup(pref_scope, "The World's Most Popular Network Protocol Analyzer");
4336 prefs.gui_version_placement = version_both;
4337 prefs.gui_welcome_page_show_recent = true1;
4338 prefs.gui_layout_type = layout_type_2;
4339 prefs.gui_layout_content_1 = layout_pane_content_plist;
4340 prefs.gui_layout_content_2 = layout_pane_content_pdetails;
4341 prefs.gui_layout_content_3 = layout_pane_content_pbytes;
4342 prefs.gui_packet_list_elide_mode = ELIDE_RIGHT;
4343 prefs.gui_packet_list_copy_format_options_for_keyboard_shortcut = COPY_FORMAT_TEXT;
4344 prefs.gui_packet_list_copy_text_with_aligned_columns = false0;
4345 prefs.gui_packet_list_show_related = true1;
4346 prefs.gui_packet_list_show_minimap = true1;
4347 prefs.gui_packet_list_sortable = true1;
4348 prefs.gui_packet_list_cached_rows_max = 10000;
4349 prefs.gui_packet_list_multi_color_mode = PACKET_LIST_MULTI_COLOR_MODE_OFF;
4350 prefs.gui_packet_list_multi_color_shift_percent = 85;
4351 prefs.gui_packet_list_multi_color_details = false0;
4352 prefs.gui_packet_list_multi_color_separator = PACKET_LIST_MULTI_COLOR_SEPARATOR_DIAGONAL;
4353 wmem_free(pref_scope, prefs.gui_interfaces_hide_types);
4354 prefs.gui_interfaces_hide_types = wmem_strdup(pref_scope, "");
4355 prefs.gui_interfaces_show_hidden = false0;
4356 prefs.gui_interfaces_remote_display = true1;
4357 prefs.gui_packet_list_separator = false0;
4358 prefs.gui_packet_header_column_definition = true1;
4359 prefs.gui_packet_list_hover_style = true1;
4360 prefs.gui_show_selected_packet = false0;
4361 prefs.gui_show_file_load_time = false0;
4362 prefs.gui_max_export_objects = 1000;
4363 prefs.gui_max_tree_items = 1 * 1000 * 1000;
4364 prefs.gui_max_tree_depth = 5 * 100;
4365 prefs.gui_decimal_places1 = DEF_GUI_DECIMAL_PLACES12;
4366 prefs.gui_decimal_places2 = DEF_GUI_DECIMAL_PLACES24;
4367 prefs.gui_decimal_places3 = DEF_GUI_DECIMAL_PLACES36;
4368
4369 if (prefs.col_list) {
4370 free_col_info(prefs.col_list);
4371 prefs.col_list = NULL((void*)0);
4372 }
4373 for (i = 0; i < num_cols; i++) {
4374 cfmt = g_new0(fmt_data,1)((fmt_data *) g_malloc0_n ((1), sizeof (fmt_data)));
4375 cfmt->title = g_strdup(col_fmt[i * 2])g_strdup_inline (col_fmt[i * 2]);
4376 cfmt->visible = true1;
4377 cfmt->display = COLUMN_DISPLAY_STRINGS'R';
4378 parse_column_format(cfmt, col_fmt[(i * 2) + 1]);
4379 prefs.col_list = g_list_append(prefs.col_list, cfmt);
4380 }
4381 prefs.num_cols = num_cols;
4382
4383/* set the default values for the capture dialog box */
4384 prefs.capture_prom_mode = true1;
4385 prefs.capture_monitor_mode = false0;
4386 prefs.capture_pcap_ng = true1;
4387 prefs.capture_real_time = true1;
4388 prefs.capture_update_interval = DEFAULT_UPDATE_INTERVAL100;
4389 prefs.capture_no_extcap = false0;
4390 prefs.capture_show_info = false0;
4391
4392 if (!prefs.capture_columns) {
4393 /* First time through */
4394 for (i = 0; i < num_capture_cols; i++) {
4395 col_name = g_strdup(capture_cols[i])g_strdup_inline (capture_cols[i]);
4396 prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
4397 }
4398 }
4399
4400/* set the default values for the tap/statistics dialog box */
4401 prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL3000;
4402 prefs.flow_graph_max_export_items = 1000;
4403 prefs.st_enable_burstinfo = true1;
4404 prefs.st_burst_showcount = false0;
4405 prefs.st_burst_resolution = ST_DEF_BURSTRES5;
4406 prefs.st_burst_windowlen = ST_DEF_BURSTLEN100;
4407 prefs.st_sort_casesensitve = true1;
4408 prefs.st_sort_rng_fixorder = true1;
4409 prefs.st_sort_rng_nameonly = true1;
4410 prefs.st_sort_defcolflag = ST_SORT_COL_COUNT2;
4411 prefs.st_sort_defdescending = true1;
4412 prefs.st_sort_showfullname = false0;
4413 prefs.conv_machine_readable = false0;
4414
4415 /* protocols */
4416 prefs.display_hidden_proto_items = false0;
4417 prefs.display_byte_fields_with_spaces = false0;
4418 prefs.display_abs_time_ascii = ABS_TIME_ASCII_TREE;
4419 prefs.ignore_dup_frames = false0;
4420 prefs.ignore_dup_frames_cache_entries = 10000;
4421
4422 /* set the default values for the io graph dialog */
4423 prefs.gui_io_graph_automatic_update = true1;
4424 prefs.gui_io_graph_enable_legend = true1;
4425
4426 /* set the default values for the plot dialog */
4427 prefs.gui_plot_automatic_update = true1;
4428 prefs.gui_plot_enable_legend = true1;
4429 prefs.gui_plot_enable_auto_scroll = false0;
4430
4431 /* set the default values for the packet dialog */
4432 prefs.gui_packet_dialog_layout = layout_vertical;
4433 prefs.gui_packet_details_show_byteview = true1;
4434}
4435
4436/*
4437 * Reset a single dissector preference.
4438 */
4439void
4440reset_pref(pref_t *pref)
4441{
4442 if (!pref) return;
4443
4444 /*
4445 * This preference is no longer supported; it's not a
4446 * real preference, so we don't reset it (i.e., we
4447 * treat it as if it weren't found in the list of
4448 * preferences, and we weren't called in the first place).
4449 */
4450 if (pref->obsolete)
4451 return;
4452
4453 switch (pref->type) {
4454
4455 case PREF_UINT:
4456 *pref->varp.uint = pref->default_val.uint;
4457 break;
4458
4459 case PREF_INT:
4460 *pref->varp.intp = pref->default_val.intval;
4461 break;
4462
4463 case PREF_FLOAT:
4464 *pref->varp.floatp = pref->default_val.floatval;
4465 break;
4466
4467 case PREF_BOOL:
4468 *pref->varp.boolp = pref->default_val.boolval;
4469 break;
4470
4471 case PREF_ENUM:
4472 case PREF_PROTO_TCP_SNDAMB_ENUM:
4473 *pref->varp.enump = pref->default_val.enumval;
4474 break;
4475
4476 case PREF_STRING:
4477 case PREF_SAVE_FILENAME:
4478 case PREF_OPEN_FILENAME:
4479 case PREF_DIRNAME:
4480 case PREF_PASSWORD:
4481 case PREF_DISSECTOR:
4482 reset_string_like_preference(pref);
4483 break;
4484
4485 case PREF_RANGE:
4486 case PREF_DECODE_AS_RANGE:
4487 wmem_free(pref->scope, *pref->varp.range);
4488 *pref->varp.range = range_copy(pref->scope, pref->default_val.range);
4489 break;
4490
4491 case PREF_STATIC_TEXT:
4492 case PREF_UAT:
4493 /* Nothing to do */
4494 break;
4495
4496 case PREF_COLOR:
4497 *pref->varp.colorp = pref->default_val.color;
4498 break;
4499
4500 case PREF_CUSTOM:
4501 pref->custom_cbs.reset_cb(pref);
4502 break;
4503 }
4504}
4505
4506static void
4507reset_pref_cb(void *data, void *user_data)
4508{
4509 pref_t *pref = (pref_t *) data;
4510 module_t *module = (module_t *)user_data;
4511
4512 if (pref && (pref->type == PREF_RANGE || pref->type == PREF_DECODE_AS_RANGE)) {
4513 /*
4514 * Some dissectors expect the range (returned via prefs_get_range_value)
4515 * to remain valid if it has not changed. If it did change, then we
4516 * should set "prefs_changed_flags" to ensure that the preference apply
4517 * callback is invoked. That callback will notify dissectors that it
4518 * should no longer assume the range to be valid.
4519 */
4520 if (ranges_are_equal(*pref->varp.range, pref->default_val.range)) {
4521 /* Optimization: do not invoke apply callback if nothing changed. */
4522 return;
4523 }
4524 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
4525 }
4526 reset_pref(pref);
4527}
4528
4529/*
4530 * Reset all preferences for a module.
4531 */
4532static bool_Bool
4533reset_module_prefs(const void *key _U___attribute__((unused)), void *value, void *data _U___attribute__((unused)))
4534{
4535 module_t *module = (module_t *)value;
4536 g_list_foreach(module->prefs, reset_pref_cb, module);
4537 return false0;
4538}
4539
4540/* Reset preferences */
4541void
4542prefs_reset(const char* app_env_var_prefix, const char** col_fmt, int num_cols)
4543{
4544 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
)
;
4545 prefs.saved_at_version = NULL((void*)0);
4546
4547 /*
4548 * Unload all UAT preferences.
4549 */
4550 uat_unload_all();
4551
4552 /*
4553 * Unload any loaded MIBs.
4554 */
4555 /* XXX - oids_cleanup not tested/supported at non-shutdown yet */
4556 //oids_cleanup();
4557
4558 /*
4559 * Reload all UAT preferences.
4560 */
4561 uat_load_all(app_env_var_prefix);
4562
4563 /*
4564 * Reset the non-dissector preferences.
4565 */
4566 prefs_set_global_defaults(wmem_epan_scope(), col_fmt, num_cols);
4567
4568 /*
4569 * Reset the non-UAT dissector preferences.
4570 */
4571 wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL((void*)0));
4572}
4573
4574#ifdef _WIN32
4575static void
4576read_registry(void)
4577{
4578 HKEY hTestKey;
4579 DWORD data;
4580 DWORD data_size = sizeof(DWORD);
4581 DWORD ret;
4582
4583 ret = RegOpenKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, KEY_READ, &hTestKey);
4584 if (ret != ERROR_SUCCESS && ret != ERROR_FILE_NOT_FOUND) {
4585 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"
, 4585, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
4586 return;
4587 }
4588
4589 ret = RegQueryValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", NULL((void*)0), NULL((void*)0), (LPBYTE)&data, &data_size);
4590 if (ret == ERROR_SUCCESS) {
4591 ws_log_console_open = (ws_log_console_open_pref)data;
4592 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"
, 4592, __func__, "Got ""ConsoleOpen"" from Windows registry: %d"
, ws_log_console_open); } } while (0)
;
4593 }
4594 else if (ret != ERROR_FILE_NOT_FOUND) {
4595 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"
, 4595, __func__, "Error reading registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
4596 }
4597
4598 RegCloseKey(hTestKey);
4599}
4600#endif
4601
4602void
4603prefs_read_module(const char *module, const char* app_env_var_prefix)
4604{
4605 int err;
4606 char *pf_path;
4607 FILE *pf;
4608
4609 module_t *target_module = prefs_find_module(module);
4610 if (!target_module) {
4611 return;
4612 }
4613
4614 /* Construct the pathname of the user's preferences file for the module. */
4615 char *pf_name = wmem_strdup_printf(NULL((void*)0), "%s.cfg", module);
4616 pf_path = get_persconffile_path(pf_name, true1, app_env_var_prefix);
4617 wmem_free(NULL((void*)0), pf_name);
4618
4619 /* Read the user's module preferences file, if it exists and is not a dir. */
4620 if (!test_for_regular_file(pf_path) || ((pf = ws_fopenfopen(pf_path, "r")) == NULL((void*)0))) {
4621 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)
;
4622 /* Fall back to the user's generic preferences file. */
4623 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4624 pf = ws_fopenfopen(pf_path, "r");
4625 }
4626
4627 if (pf != NULL((void*)0)) {
4628 /* We succeeded in opening it; read it. */
4629 err = read_prefs_file(pf_path, pf, set_pref, target_module);
4630 if (err != 0) {
4631 /* We had an error reading the file; report it. */
4632 report_warning("Error reading your preferences file \"%s\": %s.",
4633 pf_path, g_strerror(err));
4634 } else
4635 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)
;
4636 fclose(pf);
4637 } else {
4638 /* We failed to open it. If we failed for some reason other than
4639 "it doesn't exist", return the errno and the pathname, so our
4640 caller can report the error. */
4641 if (errno(*__errno_location ()) != ENOENT2) {
4642 report_warning("Can't open your preferences file \"%s\": %s.",
4643 pf_path, g_strerror(errno(*__errno_location ())));
4644 } else
4645 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)
;
4646 }
4647
4648 return;
4649}
4650
4651/* Read the preferences file, fill in "prefs", and return a pointer to it.
4652
4653 If we got an error (other than "it doesn't exist") we report it through
4654 the UI. */
4655e_prefs *
4656read_prefs(const char* app_env_var_prefix)
4657{
4658 int err;
4659 char *pf_path;
4660 FILE *pf;
4661
4662 /* clean up libsmi structures before reading prefs */
4663 /* XXX - oids_cleanup not tested/supported at non-shutdown yet */
4664 // oids_cleanup();
4665
4666#ifdef _WIN32
4667 read_registry();
4668#endif
4669
4670 /*
4671 * If we don't already have the pathname of the global preferences
4672 * file, construct it. Then, in either case, try to open the file.
4673 */
4674 if (gpf_path == NULL((void*)0)) {
4675 /*
4676 * We don't have the path; try the new path first, and, if that
4677 * file doesn't exist, try the old path.
4678 */
4679 gpf_path = get_datafile_path(PF_NAME"preferences", app_env_var_prefix);
4680 if ((pf = ws_fopenfopen(gpf_path, "r")) == NULL((void*)0) && errno(*__errno_location ()) == ENOENT2) {
4681 /*
4682 * It doesn't exist by the new name; try the old name.
4683 */
4684 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)
;
4685 gpf_path = get_datafile_path(OLD_GPF_NAME"wireshark.conf", app_env_var_prefix);
4686 pf = ws_fopenfopen(gpf_path, "r");
4687 }
4688 } else {
4689 /*
4690 * We have the path; try it.
4691 */
4692 pf = ws_fopenfopen(gpf_path, "r");
4693 }
4694
4695 /*
4696 * If we were able to open the file, read it.
4697 * XXX - if it failed for a reason other than "it doesn't exist",
4698 * report the error.
4699 */
4700 if (pf != NULL((void*)0)) {
4701 /* We succeeded in opening it; read it. */
4702 err = read_prefs_file(gpf_path, pf, set_pref, NULL((void*)0));
4703 if (err != 0) {
4704 /* We had an error reading the file; report it. */
4705 report_warning("Error reading global preferences file \"%s\": %s.",
4706 gpf_path, g_strerror(err));
4707 }
4708 fclose(pf);
4709 } else {
4710 /* We failed to open it. If we failed for some reason other than
4711 "it doesn't exist", report the error. */
4712 if (errno(*__errno_location ()) != ENOENT2) {
4713 if (errno(*__errno_location ()) != 0) {
4714 report_warning("Can't open global preferences file \"%s\": %s.",
4715 gpf_path, g_strerror(errno(*__errno_location ())));
4716 }
4717 }
4718 }
4719
4720 /* Construct the pathname of the user's preferences file. */
4721 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
4722
4723 /* Read the user's preferences file, if it exists. */
4724 if ((pf = ws_fopenfopen(pf_path, "r")) != NULL((void*)0)) {
4725
4726 /* We succeeded in opening it; read it. */
4727 err = read_prefs_file(pf_path, pf, set_pref, NULL((void*)0));
4728 if (err != 0) {
4729 /* We had an error reading the file; report it. */
4730 report_warning("Error reading your preferences file \"%s\": %s.",
4731 pf_path, g_strerror(err));
4732 } else
4733 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)
;
4734 fclose(pf);
4735 } else {
4736 /* We failed to open it. If we failed for some reason other than
4737 "it doesn't exist", return the errno and the pathname, so our
4738 caller can report the error. */
4739 if (errno(*__errno_location ()) != ENOENT2) {
4740 report_warning("Can't open your preferences file \"%s\": %s.",
4741 pf_path, g_strerror(errno(*__errno_location ())));
4742 } else
4743 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)
;
4744 }
4745
4746 /* load SMI modules if needed */
4747 oids_init(app_env_var_prefix);
4748
4749 return &prefs;
4750}
4751
4752/* read the preferences file (or similar) and call the callback
4753 * function to set each key/value pair found */
4754int
4755read_prefs_file(const char *pf_path, FILE *pf,
4756 pref_set_pair_cb pref_set_pair_fct, void *private_data)
4757{
4758 enum {
4759 START, /* beginning of a line */
4760 IN_VAR, /* processing key name */
4761 PRE_VAL, /* finished processing key name, skipping white space before value */
4762 IN_VAL, /* processing value */
4763 IN_SKIP /* skipping to the end of the line */
4764 } state = START;
4765 int got_c;
4766 GString *cur_val;
4767 GString *cur_var;
4768 bool_Bool got_val = false0;
4769 int fline = 1, pline = 1;
4770 char hint[] = "(save preferences to remove this warning)";
4771 char ver[128];
4772
4773 cur_val = g_string_new("");
4774 cur_var = g_string_new("");
4775
4776 /* Try to read in the profile name in the first line of the preferences file. */
4777 if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) {
1
Assuming the condition is false
2
Taking false branch
4778 /* Assume trailing period and remove it */
4779 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
)
;
4780 prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1);
4781 }
4782 rewind(pf);
3
After calling 'rewind' reading 'errno' is required to find out if the call has failed
4783
4784 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'
4785 if (got_c == '\r') {
4786 /* Treat CR-LF at the end of a line like LF, so that if we're reading
4787 * a Windows-format file on UN*X, we handle it the same way we'd handle
4788 * a UN*X-format file. */
4789 got_c = ws_getc_unlockedgetc_unlocked(pf);
4790 if (got_c == EOF(-1))
4791 break;
4792 if (got_c != '\n') {
4793 /* Put back the character after the CR, and process the CR normally. */
4794 ungetc(got_c, pf);
4795 got_c = '\r';
4796 }
4797 }
4798 if (got_c == '\n') {
4799 state = START;
4800 fline++;
4801 continue;
4802 }
4803
4804 switch (state) {
4805 case START:
4806 if (g_ascii_isalnum(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_ALNUM) != 0)) {
4807 if (cur_var->len > 0) {
4808 if (got_val) {
4809 if (cur_val->len > 0) {
4810 if (cur_val->str[cur_val->len-1] == ',') {
4811 /*
4812 * If the pref has a trailing comma, eliminate it.
4813 */
4814 cur_val->str[cur_val->len-1] = '\0';
4815 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"
, 4815, __func__, "%s line %d: trailing comma in \"%s\" %s", pf_path
, pline, cur_var->str, hint); } } while (0)
;
4816 }
4817 }
4818 /* Call the routine to set the preference; it will parse
4819 the value as appropriate.
4820
4821 Since we're reading a file, rather than processing
4822 explicit user input, for range preferences, silently
4823 lower values in excess of the range's maximum, rather
4824 than reporting errors and failing. */
4825 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
4826
4827 case PREFS_SET_OK:
4828 break;
4829
4830 case PREFS_SET_SYNTAX_ERR:
4831 report_warning("Syntax error in preference \"%s\" at line %d of\n%s %s",
4832 cur_var->str, pline, pf_path, hint);
4833 break;
4834
4835 case PREFS_SET_NO_SUCH_PREF:
4836 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"
, 4837, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4837 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4837, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4838 break;
4839
4840 case PREFS_SET_OBSOLETE:
4841 /*
4842 * If an attempt is made to save the
4843 * preferences, a popup warning will be
4844 * displayed stating that obsolete prefs
4845 * have been detected and the user will
4846 * be given the opportunity to save these
4847 * prefs under a different profile name.
4848 * The prefs in question need to be listed
4849 * in the console window so that the
4850 * user can make an informed choice.
4851 */
4852 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"
, 4853, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4853 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4853, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4854 break;
4855 }
4856 } else {
4857 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"
, 4857, __func__, "Incomplete preference at line %d: of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
4858 }
4859 }
4860 state = IN_VAR;
4861 got_val = false0;
4862 g_string_truncate(cur_var, 0)g_string_truncate_inline (cur_var, 0);
4863 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
4864 pline = fline;
4865 } else if (g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0) && cur_var->len > 0 && got_val) {
4866 state = PRE_VAL;
4867 } else if (got_c == '#') {
4868 state = IN_SKIP;
4869 } else {
4870 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"
, 4870, __func__, "Malformed preference at line %d of\n%s %s"
, fline, pf_path, hint); } } while (0)
;
4871 }
4872 break;
4873 case IN_VAR:
4874 if (got_c != ':') {
4875 g_string_append_c(cur_var, (char) got_c)g_string_append_c_inline (cur_var, (char) got_c);
4876 } else {
4877 /* This is a colon (':') */
4878 state = PRE_VAL;
4879 g_string_truncate(cur_val, 0)g_string_truncate_inline (cur_val, 0);
4880 /*
4881 * Set got_val to true to accommodate prefs such as
4882 * "gui.fileopen.dir" that do not require a value.
4883 */
4884 got_val = true1;
4885 }
4886 break;
4887 case PRE_VAL:
4888 if (!g_ascii_isspace(got_c)((g_ascii_table[(guchar) (got_c)] & G_ASCII_SPACE) != 0)) {
4889 state = IN_VAL;
4890 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
4891 }
4892 break;
4893 case IN_VAL:
4894 g_string_append_c(cur_val, (char) got_c)g_string_append_c_inline (cur_val, (char) got_c);
4895 break;
4896 case IN_SKIP:
4897 break;
4898 }
4899 }
4900 if (cur_var->len > 0) {
4901 if (got_val) {
4902 /* Call the routine to set the preference; it will parse
4903 the value as appropriate.
4904
4905 Since we're reading a file, rather than processing
4906 explicit user input, for range preferences, silently
4907 lower values in excess of the range's maximum, rather
4908 than reporting errors and failing. */
4909 switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, false0)) {
4910
4911 case PREFS_SET_OK:
4912 break;
4913
4914 case PREFS_SET_SYNTAX_ERR:
4915 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"
, 4916, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4916 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4916, __func__, "Syntax error in preference %s at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4917 break;
4918
4919 case PREFS_SET_NO_SUCH_PREF:
4920 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"
, 4921, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4921 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4921, __func__, "No such preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4922 break;
4923
4924 case PREFS_SET_OBSOLETE:
4925 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"
, 4926, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
4926 cur_var->str, pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4926, __func__, "Obsolete preference \"%s\" at line %d of\n%s %s"
, cur_var->str, pline, pf_path, hint); } } while (0)
;
4927 break;
4928 }
4929 } else {
4930 ws_warning("Incomplete preference at line %d of\n%s %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4931, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
4931 pline, pf_path, hint)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 4931, __func__, "Incomplete preference at line %d of\n%s %s"
, pline, pf_path, hint); } } while (0)
;
4932 }
4933 }
4934
4935 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)))))
;
4936 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)))))
;
4937
4938 if (ferror(pf))
4939 return errno(*__errno_location ());
4940 else
4941 return 0;
4942}
4943
4944/*
4945 * If we were handed a preference starting with "uat:", try to turn it into
4946 * a valid uat entry.
4947 */
4948static bool_Bool
4949prefs_set_uat_pref(char *uat_entry, char **errmsg) {
4950 char *p, *colonp;
4951 uat_t *uat;
4952 bool_Bool ret;
4953
4954 colonp = strchr(uat_entry, ':');
4955 if (colonp == NULL((void*)0))
4956 return false0;
4957
4958 p = colonp;
4959 *p++ = '\0';
4960
4961 /*
4962 * Skip over any white space (there probably won't be any, but
4963 * as we allow it in the preferences file, we might as well
4964 * allow it here).
4965 */
4966 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
4967 p++;
4968 if (*p == '\0') {
4969 /*
4970 * Put the colon back, so if our caller uses, in an
4971 * error message, the string they passed us, the message
4972 * looks correct.
4973 */
4974 *colonp = ':';
4975 return false0;
4976 }
4977
4978 uat = uat_find(uat_entry);
4979 *colonp = ':';
4980 if (uat == NULL((void*)0)) {
4981 *errmsg = g_strdup("Unknown preference")g_strdup_inline ("Unknown preference");
4982 return false0;
4983 }
4984
4985 ret = uat_load_str(uat, p, errmsg);
4986 return ret;
4987}
4988
4989char *
4990prefs_sanitize_string(const char* str)
4991{
4992 char *sanitized;
4993 if (!prefs_regex) {
4994 prefs_regex = g_regex_new("\\s*\\R\\s*", (GRegexCompileFlags)G_REGEX_OPTIMIZE,
4995 (GRegexMatchFlags)G_REGEX_MATCH_BSR_ANYCRLF, NULL((void*)0));
4996 } else {
4997 g_regex_ref(prefs_regex);
4998 }
4999 sanitized = g_regex_replace(prefs_regex, str, -1, 0, " ", G_REGEX_MATCH_DEFAULT, NULL((void*)0));
5000 g_regex_unref(prefs_regex);
5001 return sanitized;
5002}
5003
5004/*
5005 * Given a string of the form "<pref name>:<pref value>", as might appear
5006 * as an argument to a "-o" option, parse it and set the preference in
5007 * question. Return an indication of whether it succeeded or failed
5008 * in some fashion.
5009 */
5010prefs_set_pref_e
5011prefs_set_pref(char *prefarg, char **errmsg)
5012{
5013 char *p, *colonp;
5014 prefs_set_pref_e ret;
5015
5016 *errmsg = NULL((void*)0);
5017
5018 colonp = strchr(prefarg, ':');
5019 if (colonp == NULL((void*)0)) {
5020 *errmsg = g_strdup("missing ':' (syntax is prefname:value).")g_strdup_inline ("missing ':' (syntax is prefname:value).");
5021 return PREFS_SET_SYNTAX_ERR;
5022 }
5023
5024 p = colonp;
5025 *p++ = '\0';
5026 /* XXX - Replace line terminators, or match and fail with errmsg, or ignore? */
5027
5028 /*
5029 * Skip over any white space (there probably won't be any, but
5030 * as we allow it in the preferences file, we might as well
5031 * allow it here).
5032 */
5033 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
5034 p++;
5035 /* The empty string is a legal value for range preferences (PREF_RANGE,
5036 * PREF_DECODE_AS_RANGE), and string-like preferences (PREF_STRING,
5037 * PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME), indeed often
5038 * not just useful but the default. A user might have a value saved
5039 * to their preference file but want to override it to default behavior.
5040 * Individual preference handlers of those types should be prepared to
5041 * deal with an empty string. For other types, it is up to set_pref() to
5042 * test for the empty string and set PREFS_SET_SYNTAX_ERROR there.
5043 */
5044 if (strcmp(prefarg, "uat")) {
5045 ret = set_pref(prefarg, p, NULL((void*)0), true1);
5046 } else {
5047 ret = prefs_set_uat_pref(p, errmsg) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR;
5048 }
5049 *colonp = ':'; /* put the colon back */
5050 return ret;
5051}
5052
5053unsigned prefs_get_uint_value(pref_t *pref, pref_source_t source)
5054{
5055 switch (source)
5056 {
5057 case pref_default:
5058 return pref->default_val.uint;
5059 case pref_stashed:
5060 return pref->stashed_val.uint;
5061 case pref_current:
5062 return *pref->varp.uint;
5063 default:
5064 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5064
, __func__, "assertion \"not reached\" failed")
;
5065 break;
5066 }
5067
5068 return 0;
5069}
5070
5071unsigned int prefs_set_int_value(pref_t* pref, int value, pref_source_t source)
5072{
5073 int changed = 0;
5074 switch (source)
5075 {
5076 case pref_default:
5077 if (pref->default_val.intval != value) {
5078 pref->default_val.intval = value;
5079 changed = prefs_get_effect_flags(pref);
5080 }
5081 break;
5082 case pref_stashed:
5083 if (pref->stashed_val.intval != value) {
5084 pref->stashed_val.intval = value;
5085 changed = prefs_get_effect_flags(pref);
5086 }
5087 break;
5088 case pref_current:
5089 if (*pref->varp.intp != value) {
5090 *pref->varp.intp = value;
5091 changed = prefs_get_effect_flags(pref);
5092 }
5093 break;
5094 default:
5095 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5095
, __func__, "assertion \"not reached\" failed")
;
5096 break;
5097 }
5098
5099 return changed;
5100}
5101
5102int prefs_get_int_value(pref_t* pref, pref_source_t source)
5103{
5104 switch (source)
5105 {
5106 case pref_default:
5107 return pref->default_val.intval;
5108 case pref_stashed:
5109 return pref->stashed_val.intval;
5110 case pref_current:
5111 return *pref->varp.intp;
5112 default:
5113 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5113
, __func__, "assertion \"not reached\" failed")
;
5114 break;
5115 }
5116
5117 return 0;
5118}
5119
5120unsigned int prefs_set_float_value(pref_t* pref, double value, pref_source_t source)
5121{
5122 int changed = 0;
5123 switch (source)
5124 {
5125 case pref_default:
5126 if (pref->default_val.floatval != value) {
5127 pref->default_val.floatval = value;
5128 changed = prefs_get_effect_flags(pref);
5129 }
5130 break;
5131 case pref_stashed:
5132 if (pref->stashed_val.floatval != value) {
5133 pref->stashed_val.floatval = value;
5134 changed = prefs_get_effect_flags(pref);
5135 }
5136 break;
5137 case pref_current:
5138 if (*pref->varp.floatp != value) {
5139 *pref->varp.floatp = value;
5140 changed = prefs_get_effect_flags(pref);
5141 }
5142 break;
5143 default:
5144 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5144
, __func__, "assertion \"not reached\" failed")
;
5145 break;
5146 }
5147
5148 return changed;
5149}
5150
5151double prefs_get_float_value(pref_t* pref, pref_source_t source)
5152{
5153 switch (source)
5154 {
5155 case pref_default:
5156 return pref->default_val.floatval;
5157 case pref_stashed:
5158 return pref->stashed_val.floatval;
5159 case pref_current:
5160 return *pref->varp.floatp;
5161 default:
5162 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5162
, __func__, "assertion \"not reached\" failed")
;
5163 break;
5164 }
5165
5166 return 0;
5167}
5168
5169
5170const char *prefs_get_password_value(pref_t *pref, pref_source_t source)
5171{
5172 return prefs_get_string_value(pref, source);
5173}
5174
5175
5176unsigned int prefs_set_uint_value(pref_t *pref, unsigned value, pref_source_t source)
5177{
5178 unsigned int changed = 0;
5179 switch (source)
5180 {
5181 case pref_default:
5182 if (pref->default_val.uint != value) {
5183 pref->default_val.uint = value;
5184 changed = prefs_get_effect_flags(pref);
5185 }
5186 break;
5187 case pref_stashed:
5188 if (pref->stashed_val.uint != value) {
5189 pref->stashed_val.uint = value;
5190 changed = prefs_get_effect_flags(pref);
5191 }
5192 break;
5193 case pref_current:
5194 if (*pref->varp.uint != value) {
5195 *pref->varp.uint = value;
5196 changed = prefs_get_effect_flags(pref);
5197 }
5198 break;
5199 default:
5200 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5200
, __func__, "assertion \"not reached\" failed")
;
5201 break;
5202 }
5203
5204 return changed;
5205}
5206
5207/*
5208 * For use by UI code that sets preferences.
5209 */
5210unsigned int
5211prefs_set_password_value(pref_t *pref, const char* value, pref_source_t source)
5212{
5213 return prefs_set_string_value(pref, value, source);
5214}
5215
5216
5217unsigned prefs_get_uint_base(pref_t *pref)
5218{
5219 return pref->info.base;
5220}
5221
5222/*
5223 * Returns true if the given device is hidden
5224 */
5225bool_Bool
5226prefs_is_capture_device_hidden(const char *name)
5227{
5228 char *tok, *devices;
5229 size_t len;
5230
5231 if (prefs.capture_devices_hide && name) {
5232 devices = g_strdup (prefs.capture_devices_hide)g_strdup_inline (prefs.capture_devices_hide);
5233 len = strlen (name);
5234 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5235 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5236 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5237 return true1;
5238 }
5239 }
5240 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5241 }
5242
5243 return false0;
5244}
5245
5246/*
5247 * Returns true if the given column is visible (not hidden)
5248 */
5249static bool_Bool
5250prefs_is_column_visible(const char *cols_hidden, int col)
5251{
5252 char *tok, *cols, *p;
5253 int cidx;
5254
5255 /*
5256 * Do we have a list of hidden columns?
5257 */
5258 if (cols_hidden) {
5259 /*
5260 * Yes - check the column against each of the ones in the
5261 * list.
5262 */
5263 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5264 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5265 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5266
5267 cidx = (int)strtol(tok, &p, 10);
5268 if (p == tok || *p != '\0') {
5269 continue;
5270 }
5271 if (cidx != col) {
5272 continue;
5273 }
5274 /*
5275 * OK, they match, so it's one of the hidden fields,
5276 * hence not visible.
5277 */
5278 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5279 return false0;
5280 }
5281 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5282 }
5283
5284 /*
5285 * No - either there are no hidden columns or this isn't one
5286 * of them - so it is visible.
5287 */
5288 return true1;
5289}
5290
5291/*
5292 * Returns true if the given column is visible (not hidden)
5293 */
5294static bool_Bool
5295prefs_is_column_fmt_visible(const char *cols_hidden, fmt_data *cfmt)
5296{
5297 char *tok, *cols;
5298 fmt_data cfmt_hidden;
5299
5300 /*
5301 * Do we have a list of hidden columns?
5302 */
5303 if (cols_hidden) {
5304 /*
5305 * Yes - check the column against each of the ones in the
5306 * list.
5307 */
5308 cols = g_strdup(cols_hidden)g_strdup_inline (cols_hidden);
5309 for (tok = strtok(cols, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5310 tok = g_strstrip(tok)g_strchomp (g_strchug (tok));
5311
5312 /*
5313 * Parse this column format.
5314 */
5315 if (!parse_column_format(&cfmt_hidden, tok)) {
5316 /*
5317 * It's not valid; ignore it.
5318 */
5319 continue;
5320 }
5321
5322 /*
5323 * Does it match the column?
5324 */
5325 if (cfmt->fmt != cfmt_hidden.fmt) {
5326 /* No. */
5327 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
)
;
5328 cfmt_hidden.custom_fields = NULL((void*)0);
5329 continue;
5330 }
5331 if (cfmt->fmt == COL_CUSTOM) {
5332 /*
5333 * A custom column has to have the same custom field
5334 * and occurrence.
5335 */
5336 if (cfmt_hidden.custom_fields && cfmt->custom_fields) {
5337 if (strcmp(cfmt->custom_fields,
5338 cfmt_hidden.custom_fields) != 0) {
5339 /* Different fields. */
5340 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
)
;
5341 cfmt_hidden.custom_fields = NULL((void*)0);
5342 continue;
5343 }
5344 if (cfmt->custom_occurrence != cfmt_hidden.custom_occurrence) {
5345 /* Different occurrences settings. */
5346 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
)
;
5347 cfmt_hidden.custom_fields = NULL((void*)0);
5348 continue;
5349 }
5350 }
5351 }
5352
5353 /*
5354 * OK, they match, so it's one of the hidden fields,
5355 * hence not visible.
5356 */
5357 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
)
;
5358 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5359 return false0;
5360 }
5361 g_free(cols)(__builtin_object_size ((cols), 0) != ((size_t) - 1)) ? g_free_sized
(cols, __builtin_object_size ((cols), 0)) : (g_free) (cols)
;
5362 }
5363
5364 /*
5365 * No - either there are no hidden columns or this isn't one
5366 * of them - so it is visible.
5367 */
5368 return true1;
5369}
5370
5371/*
5372 * Returns true if the given device should capture in monitor mode by default
5373 */
5374bool_Bool
5375prefs_capture_device_monitor_mode(const char *name)
5376{
5377 char *tok, *devices;
5378 size_t len;
5379
5380 if (prefs.capture_devices_monitor_mode && name) {
5381 devices = g_strdup (prefs.capture_devices_monitor_mode)g_strdup_inline (prefs.capture_devices_monitor_mode);
5382 len = strlen (name);
5383 for (tok = strtok (devices, ","); tok; tok = strtok(NULL((void*)0), ",")) {
5384 if (strlen (tok) == len && strcmp (name, tok) == 0) {
5385 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5386 return true1;
5387 }
5388 }
5389 g_free (devices)(__builtin_object_size ((devices), 0) != ((size_t) - 1)) ? g_free_sized
(devices, __builtin_object_size ((devices), 0)) : (g_free) (
devices)
;
5390 }
5391
5392 return false0;
5393}
5394
5395/*
5396 * Returns true if the user has marked this column as visible
5397 */
5398bool_Bool
5399prefs_capture_options_dialog_column_is_visible(const char *column)
5400{
5401 GList *curr;
5402 char *col;
5403
5404 for (curr = g_list_first(prefs.capture_columns); curr; curr = g_list_next(curr)((curr) ? (((GList *)(curr))->next) : ((void*)0))) {
5405 col = (char *)curr->data;
5406 if (col && (g_ascii_strcasecmp(col, column) == 0)) {
5407 return true1;
5408 }
5409 }
5410 return false0;
5411}
5412
5413bool_Bool
5414prefs_has_layout_pane_content (layout_pane_content_e layout_pane_content)
5415{
5416 return ((prefs.gui_layout_content_1 == layout_pane_content) ||
5417 (prefs.gui_layout_content_2 == layout_pane_content) ||
5418 (prefs.gui_layout_content_3 == layout_pane_content));
5419}
5420
5421char
5422string_to_name_resolve(const char *string, e_addr_resolve *name_resolve)
5423{
5424 char c;
5425
5426 memset(name_resolve, 0, sizeof(e_addr_resolve));
5427 while ((c = *string++) != '\0') {
5428 switch (c) {
5429 case 'g':
5430 name_resolve->maxmind_geoip = true1;
5431 break;
5432 case 'm':
5433 name_resolve->mac_name = true1;
5434 break;
5435 case 'n':
5436 name_resolve->network_name = true1;
5437 break;
5438 case 'N':
5439 name_resolve->use_external_net_name_resolver = true1;
5440 break;
5441 case 't':
5442 name_resolve->transport_name = true1;
5443 break;
5444 case 'd':
5445 name_resolve->dns_pkt_addr_resolution = true1;
5446 break;
5447 case 's':
5448 name_resolve->handshake_sni_addr_resolution = true1;
5449 break;
5450 case 'v':
5451 name_resolve->vlan_name = true1;
5452 break;
5453 default:
5454 /*
5455 * Unrecognized letter.
5456 */
5457 return c;
5458 }
5459 }
5460 return '\0';
5461}
5462
5463static bool_Bool
5464deprecated_heur_dissector_pref(char *pref_name, const char *value)
5465{
5466 struct heur_pref_name
5467 {
5468 const char* pref_name;
5469 const char* short_name;
5470 bool_Bool more_dissectors; /* For multiple dissectors controlled by the same preference */
5471 };
5472
5473 static const struct heur_pref_name heur_prefs[] = {
5474 {"acn.heuristic_acn", "acn_udp", 0},
5475 {"bfcp.enable", "bfcp_tcp", 1},
5476 {"bfcp.enable", "bfcp_udp", 0},
5477 {"bt-dht.enable", "bittorrent_dht_udp", 0},
5478 {"bt-utp.enable", "bt_utp_udp", 0},
5479 {"cattp.enable", "cattp_udp", 0},
5480 {"cfp.enable", "fp_eth", 0},
5481 {"dicom.heuristic", "dicom_tcp", 0},
5482 {"dnp3.heuristics", "dnp3_tcp", 1},
5483 {"dnp3.heuristics", "dnp3_udp", 0},
5484 {"dvb-s2_modeadapt.enable", "dvb_s2_udp", 0},
5485 {"esl.enable", "esl_eth", 0},
5486 {"fp.udp_heur", "fp_udp", 0},
5487 {"gvsp.enable_heuristic", "gvsp_udp", 0},
5488 {"hdcp2.enable", "hdcp2_tcp", 0},
5489 {"hislip.enable_heuristic", "hislip_tcp", 0},
5490 {"infiniband.dissect_eoib", "mellanox_eoib", 1},
5491 {"infiniband.identify_payload", "eth_over_ib", 0},
5492 {"jxta.udp.heuristic", "jxta_udp", 0},
5493 {"jxta.tcp.heuristic", "jxta_tcp", 0},
5494 {"jxta.sctp.heuristic", "jxta_sctp", 0},
5495 {"mac-lte.heuristic_mac_lte_over_udp", "mac_lte_udp", 0},
5496 {"mbim.bulk_heuristic", "mbim_usb_bulk", 0},
5497 {"norm.heuristic_norm", "rmt_norm_udp", 0},
5498 {"openflow.heuristic", "openflow_tcp", 0},
5499 {"pdcp-lte.heuristic_pdcp_lte_over_udp", "pdcp_lte_udp", 0},
5500 {"rlc.heuristic_rlc_over_udp", "rlc_udp", 0},
5501 {"rlc-lte.heuristic_rlc_lte_over_udp", "rlc_lte_udp", 0},
5502 {"rtcp.heuristic_rtcp", "rtcp_udp", 1},
5503 {"rtcp.heuristic_rtcp", "rtcp_stun", 0},
5504 {"rtp.heuristic_rtp", "rtp_udp", 1},
5505 {"rtp.heuristic_rtp", "rtp_stun", 0},
5506 {"teredo.heuristic_teredo", "teredo_udp", 0},
5507 {"vssmonitoring.use_heuristics", "vssmonitoring_eth", 0},
5508 {"xml.heuristic", "xml_http", 1},
5509 {"xml.heuristic", "xml_sip", 1},
5510 {"xml.heuristic", "xml_media", 0},
5511 {"xml.heuristic_tcp", "xml_tcp", 0},
5512 {"xml.heuristic_udp", "xml_udp", 0},
5513 };
5514
5515 unsigned int i;
5516 heur_dtbl_entry_t* heuristic;
5517
5518
5519 for (i = 0; i < array_length(heur_prefs)(sizeof (heur_prefs) / sizeof (heur_prefs)[0]); i++)
5520 {
5521 if (strcmp(pref_name, heur_prefs[i].pref_name) == 0)
5522 {
5523 heuristic = find_heur_dissector_by_unique_short_name(heur_prefs[i].short_name);
5524 if (heuristic != NULL((void*)0)) {
5525 heuristic->enabled = ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0);
5526 }
5527
5528 if (!heur_prefs[i].more_dissectors)
5529 return true1;
5530 }
5531 }
5532
5533
5534 return false0;
5535}
5536
5537static bool_Bool
5538deprecated_enable_dissector_pref(char *pref_name, const char *value)
5539{
5540 struct dissector_pref_name
5541 {
5542 const char* pref_name;
5543 const char* short_name;
5544 };
5545
5546 struct dissector_pref_name dissector_prefs[] = {
5547 {"transum.tsumenabled", "TRANSUM"},
5548 {"snort.enable_snort_dissector", "Snort"},
5549 {"prp.enable", "PRP"},
5550 };
5551
5552 unsigned int i;
5553 int proto_id;
5554
5555 for (i = 0; i < array_length(dissector_prefs)(sizeof (dissector_prefs) / sizeof (dissector_prefs)[0]); i++)
5556 {
5557 if (strcmp(pref_name, dissector_prefs[i].pref_name) == 0)
5558 {
5559 proto_id = proto_get_id_by_short_name(dissector_prefs[i].short_name);
5560 if (proto_id >= 0)
5561 proto_set_decoding(proto_id, ((g_ascii_strcasecmp(value, "true") == 0) ? true1 : false0));
5562 return true1;
5563 }
5564 }
5565
5566 return false0;
5567}
5568
5569static bool_Bool
5570deprecated_port_pref(char *pref_name, const char *value)
5571{
5572 struct port_pref_name
5573 {
5574 const char* pref_name;
5575 const char* module_name; /* the protocol filter name */
5576 const char* table_name;
5577 unsigned base;
5578 };
5579
5580 struct obsolete_pref_name
5581 {
5582 const char* pref_name;
5583 };
5584
5585 /* For now this is only supporting TCP/UDP port and RTP payload
5586 * types dissector preferences, which are assumed to be decimal */
5587 /* module_name is the filter name of the destination port preference,
5588 * which is usually the same as the original module but not
5589 * necessarily (e.g., if the preference is for what is now a PINO.)
5590 * XXX: Most of these were changed pre-2.0. Can we end support
5591 * for migrating legacy preferences at some point?
5592 */
5593 static const struct port_pref_name port_prefs[] = {
5594 /* TCP */
5595 {"cmp.tcp_alternate_port", "cmp", "tcp.port", 10},
5596 {"h248.tcp_port", "h248", "tcp.port", 10},
5597 {"cops.tcp.cops_port", "cops", "tcp.port", 10},
5598 {"dhcpfo.tcp_port", "dhcpfo", "tcp.port", 10},
5599 {"enttec.tcp_port", "enttec", "tcp.port", 10},
5600 {"forces.tcp_alternate_port", "forces", "tcp.port", 10},
5601 {"ged125.tcp_port", "ged125", "tcp.port", 10},
5602 {"hpfeeds.dissector_port", "hpfeeds", "tcp.port", 10},
5603 {"lsc.port", "lsc", "tcp.port", 10},
5604 {"megaco.tcp.txt_port", "megaco", "tcp.port", 10},
5605 {"netsync.tcp_port", "netsync", "tcp.port", 10},
5606 {"osi.tpkt_port", "osi", "tcp.port", 10},
5607 {"rsync.tcp_port", "rsync", "tcp.port", 10},
5608 {"sametime.tcp_port", "sametime", "tcp.port", 10},
5609 {"sigcomp.tcp.port2", "sigcomp", "tcp.port", 10},
5610 {"synphasor.tcp_port", "synphasor", "tcp.port", 10},
5611 {"tipc.alternate_port", "tipc", "tcp.port", 10},
5612 {"vnc.alternate_port", "vnc", "tcp.port", 10},
5613 {"scop.port", "scop", "tcp.port", 10},
5614 {"scop.port_secure", "scop", "tcp.port", 10},
5615 {"tpncp.tcp.trunkpack_port", "tpncp", "tcp.port", 10},
5616 /* UDP */
5617 {"h248.udp_port", "h248", "udp.port", 10},
5618 {"actrace.udp_port", "actrace", "udp.port", 10},
5619 {"brp.port", "brp", "udp.port", 10},
5620 {"bvlc.additional_udp_port", "bvlc", "udp.port", 10},
5621 {"capwap.udp.port.control", "capwap", "udp.port", 10},
5622 {"capwap.udp.port.data", "capwap", "udp.port", 10},
5623 {"coap.udp_port", "coap", "udp.port", 10},
5624 {"enttec.udp_port", "enttec", "udp.port", 10},
5625 {"forces.udp_alternate_port", "forces", "udp.port", 10},
5626 {"ldss.udp_port", "ldss", "udp.port", 10},
5627 {"lmp.udp_port", "lmp", "udp.port", 10},
5628 {"ltp.port", "ltp", "udp.port", 10},
5629 {"lwres.udp.lwres_port", "lwres", "udp.port", 10},
5630 {"megaco.udp.txt_port", "megaco", "udp.port", 10},
5631 {"pfcp.port_pfcp", "pfcp", "udp.port", 10},
5632 {"pgm.udp.encap_ucast_port", "pgm", "udp.port", 10},
5633 {"pgm.udp.encap_mcast_port", "pgm", "udp.port", 10},
5634 {"quic.udp.quic.port", "quic", "udp.port", 10},
5635 {"quic.udp.quics.port", "quic", "udp.port", 10},
5636 {"radius.alternate_port", "radius", "udp.port", 10},
5637 {"rdt.default_udp_port", "rdt", "udp.port", 10},
5638 {"alc.default.udp_port", "alc", "udp.port", 10},
5639 {"sigcomp.udp.port2", "sigcomp", "udp.port", 10},
5640 {"synphasor.udp_port", "synphasor", "udp.port", 10},
5641 {"tdmop.udpport", "tdmop", "udp.port", 10},
5642 {"uaudp.port1", "uaudp", "udp.port", 10},
5643 {"uaudp.port2", "uaudp", "udp.port", 10},
5644 {"uaudp.port3", "uaudp", "udp.port", 10},
5645 {"uaudp.port4", "uaudp", "udp.port", 10},
5646 {"uhd.dissector_port", "uhd", "udp.port", 10},
5647 {"vrt.dissector_port", "vrt", "udp.port", 10},
5648 {"tpncp.udp.trunkpack_port", "tpncp", "udp.port", 10},
5649 /* SCTP */
5650 {"hnbap.port", "hnbap", "sctp.port", 10},
5651 {"m2pa.port", "m2pa", "sctp.port", 10},
5652 {"megaco.sctp.txt_port", "megaco", "sctp.port", 10},
5653 {"rua.port", "rua", "sctp.port", 10},
5654 /* SCTP PPI */
5655 {"lapd.sctp_payload_protocol_identifier", "lapd", "sctp.ppi", 10},
5656 /* SCCP SSN */
5657 {"ranap.sccp_ssn", "ranap", "sccp.ssn", 10},
5658 };
5659
5660 static const struct port_pref_name port_range_prefs[] = {
5661 /* TCP */
5662 {"couchbase.tcp.ports", "couchbase", "tcp.port", 10},
5663 {"gsm_ipa.tcp_ports", "gsm_ipa", "tcp.port", 10},
5664 {"kafka.tcp.ports", "kafka", "tcp.port", 10},
5665 {"kt.tcp.ports", "kt", "tcp.port", 10},
5666 {"memcache.tcp.ports", "memcache", "tcp.port", 10},
5667 {"mrcpv2.tcp.port_range", "mrcpv2", "tcp.port", 10},
5668 {"pdu_transport.ports.tcp", "pdu_transport", "tcp.port", 10},
5669 {"rtsp.tcp.port_range", "rtsp", "tcp.port", 10},
5670 {"sip.tcp.ports", "sip", "tcp.port", 10},
5671 {"someip.ports.tcp", "someip", "tcp.port", 10},
5672 {"tds.tcp_ports", "tds", "tcp.port", 10},
5673 {"tpkt.tcp.ports", "tpkt", "tcp.port", 10},
5674 {"uma.tcp.ports", "uma", "tcp.port", 10},
5675 /* UDP */
5676 {"aruba_erm.udp.ports", "arubs_erm", "udp.port", 10},
5677 {"diameter.udp.ports", "diameter", "udp.port", 10},
5678 {"dmp.udp_ports", "dmp", "udp.port", 10},
5679 {"dns.udp.ports", "dns", "udp.port", 10},
5680 {"gsm_ipa.udp_ports", "gsm_ipa", "udp.port", 10},
5681 {"hcrt.dissector_udp_port", "hcrt", "udp.port", 10},
5682 {"memcache.udp.ports", "memcache", "udp.port", 10},
5683 {"nb_rtpmux.udp_ports", "nb_rtpmux", "udp.port", 10},
5684 {"gprs-ns.udp.ports", "gprs-ns", "udp.port", 10},
5685 {"p_mul.udp_ports", "p_mul", "udp.port", 10},
5686 {"pdu_transport.ports.udp", "pdu_transport", "udp.port", 10},
5687 {"radius.ports", "radius", "udp.port", 10},
5688 {"sflow.ports", "sflow", "udp.port", 10},
5689 {"someip.ports.udp", "someip", "udp.port", 10},
5690 {"sscop.udp.ports", "sscop", "udp.port", 10},
5691 {"tftp.udp_ports", "tftp", "udp.port", 10},
5692 {"tipc.udp.ports", "tipc", "udp.port", 10},
5693 /* RTP */
5694 {"amr.dynamic.payload.type", "amr", "rtp.pt", 10},
5695 {"amr.wb.dynamic.payload.type", "amr_wb", "rtp.pt", 10},
5696 {"dvb-s2_modeadapt.dynamic.payload.type", "dvb-s2_modeadapt", "rtp.pt", 10},
5697 {"evs.dynamic.payload.type", "evs", "rtp.pt", 10},
5698 {"h263p.dynamic.payload.type", "h263p", "rtp.pt", 10},
5699 {"h264.dynamic.payload.type", "h264", "rtp.pt", 10},
5700 {"h265.dynamic.payload.type", "h265", "rtp.pt", 10},
5701 {"ismacryp.dynamic.payload.type", "ismacryp", "rtp.pt", 10},
5702 {"iuup.dynamic.payload.type", "iuup", "rtp.pt", 10},
5703 {"lapd.rtp_payload_type", "lapd", "rtp.pt", 10},
5704 {"mp4ves.dynamic.payload.type", "mp4ves", "rtp.pt", 10},
5705 {"mtp2.rtp_payload_type", "mtp2", "rtp.pt", 10},
5706 {"opus.dynamic.payload.type", "opus", "rtp.pt", 10},
5707 {"rtp.rfc2198_payload_type", "rtp_rfc2198", "rtp.pt", 10},
5708 {"rtpevent.event_payload_type_value", "rtpevent", "rtp.pt", 10},
5709 {"rtpevent.cisco_nse_payload_type_value", "rtpevent", "rtp.pt", 10},
5710 {"rtpmidi.midi_payload_type_value", "rtpmidi", "rtp.pt", 10},
5711 {"vp8.dynamic.payload.type", "vp8", "rtp.pt", 10},
5712 /* SCTP */
5713 {"diameter.sctp.ports", "diameter", "sctp.port", 10},
5714 {"sgsap.sctp_ports", "sgsap", "sctp.port", 10},
5715 /* SCCP SSN */
5716 {"pcap.ssn", "pcap", "sccp.ssn", 10},
5717 };
5718
5719 /* These are subdissectors of TPKT/OSITP that used to have a
5720 TCP port preference even though they were never
5721 directly on TCP. Convert them to use Decode As
5722 with the TPKT dissector handle */
5723 static const struct port_pref_name tpkt_subdissector_port_prefs[] = {
5724 {"dap.tcp.port", "dap", "tcp.port", 10},
5725 {"disp.tcp.port", "disp", "tcp.port", 10},
5726 {"dop.tcp.port", "dop", "tcp.port", 10},
5727 {"dsp.tcp.port", "dsp", "tcp.port", 10},
5728 {"p1.tcp.port", "p1", "tcp.port", 10},
5729 {"p7.tcp.port", "p7", "tcp.port", 10},
5730 {"rdp.tcp.port", "rdp", "tcp.port", 10},
5731 };
5732
5733 /* These are obsolete preferences from the dissectors' view,
5734 (typically because of a switch from a single value to a
5735 range value) but the name of the preference conflicts
5736 with the generated preference name from the dissector table.
5737 Don't allow the obsolete preference through to be handled */
5738 static const struct obsolete_pref_name obsolete_prefs[] = {
5739 {"diameter.tcp.port"},
5740 {"kafka.tcp.port"},
5741 {"mrcpv2.tcp.port"},
5742 {"rtsp.tcp.port"},
5743 {"sip.tcp.port"},
5744 {"t38.tcp.port"},
5745 };
5746
5747 unsigned int i;
5748 unsigned uval;
5749 dissector_table_t sub_dissectors;
5750 dissector_handle_t handle, tpkt_handle;
5751 module_t *module;
5752 pref_t *pref;
5753
5754 static bool_Bool sanity_checked;
5755 if (!sanity_checked) {
5756 sanity_checked = true1;
5757 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5758 module = prefs_find_module(port_prefs[i].module_name);
5759 if (!module) {
5760 // We might not be Wireshark, and therefore might not have deprecated port prefs.
5761 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"
, 5761, __func__, "Deprecated ports pref check - module '%s' not found"
, port_prefs[i].module_name); } } while (0)
;
5762 continue;
5763 }
5764 pref = prefs_find_preference(module, port_prefs[i].table_name);
5765 if (!pref) {
5766 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"
, 5766, __func__, "Deprecated ports pref '%s.%s' not found", module
->name, port_prefs[i].table_name); } } while (0)
;
5767 continue;
5768 }
5769 if (pref->type != PREF_DECODE_AS_RANGE) {
5770 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"
, 5770, __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)
;
5771 }
5772 }
5773 }
5774
5775 for (i = 0; i < G_N_ELEMENTS(port_prefs)(sizeof (port_prefs) / sizeof ((port_prefs)[0])); i++) {
5776 if (strcmp(pref_name, port_prefs[i].pref_name) == 0) {
5777 if (!ws_basestrtou32(value, NULL((void*)0), &uval, port_prefs[i].base))
5778 return false0; /* number was bad */
5779
5780 module = prefs_find_module(port_prefs[i].module_name);
5781 pref = prefs_find_preference(module, port_prefs[i].table_name);
5782 if (pref != NULL((void*)0)) {
5783 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5784 if (pref->type == PREF_DECODE_AS_RANGE) {
5785 // The legacy preference was a port number, but the new
5786 // preference is a port range. Add to existing range.
5787 if (uval) {
5788 prefs_range_add_value(pref, uval);
5789 }
5790 }
5791 }
5792
5793 /* If the value is zero, it wouldn't add to the Decode As tables */
5794 if (uval != 0)
5795 {
5796 sub_dissectors = find_dissector_table(port_prefs[i].table_name);
5797 if (sub_dissectors != NULL((void*)0)) {
5798 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5799 if (handle != NULL((void*)0)) {
5800 dissector_change_uint(port_prefs[i].table_name, uval, handle);
5801 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));
5802 }
5803 }
5804 }
5805
5806 return true1;
5807 }
5808 }
5809
5810 for (i = 0; i < array_length(port_range_prefs)(sizeof (port_range_prefs) / sizeof (port_range_prefs)[0]); i++)
5811 {
5812 if (strcmp(pref_name, port_range_prefs[i].pref_name) == 0)
5813 {
5814 uint32_t range_i, range_j;
5815
5816 sub_dissectors = find_dissector_table(port_range_prefs[i].table_name);
5817 if (sub_dissectors != NULL((void*)0)) {
5818 switch (dissector_table_get_type(sub_dissectors)) {
5819 case FT_UINT8:
5820 case FT_UINT16:
5821 case FT_UINT24:
5822 case FT_UINT32:
5823 break;
5824
5825 default:
5826 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", 5826
, __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))
;
5827 ws_assert_not_reached()ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 5827
, __func__, "assertion \"not reached\" failed")
;
5828 }
5829
5830 module = prefs_find_module(port_range_prefs[i].module_name);
5831 pref = prefs_find_preference(module, port_range_prefs[i].table_name);
5832 if (pref != NULL((void*)0))
5833 {
5834 if (!prefs_set_range_value_work(pref, value, true1, &module->prefs_changed_flags))
5835 {
5836 return false0; /* number was bad */
5837 }
5838
5839 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5840 if (handle != NULL((void*)0)) {
5841
5842 for (range_i = 0; range_i < (*pref->varp.range)->nranges; range_i++) {
5843 for (range_j = (*pref->varp.range)->ranges[range_i].low; range_j < (*pref->varp.range)->ranges[range_i].high; range_j++) {
5844 dissector_change_uint(port_range_prefs[i].table_name, range_j, handle);
5845 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));
5846 }
5847
5848 dissector_change_uint(port_range_prefs[i].table_name, (*pref->varp.range)->ranges[range_i].high, handle);
5849 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));
5850 }
5851 }
5852 }
5853 }
5854
5855 return true1;
5856 }
5857 }
5858
5859 for (i = 0; i < array_length(tpkt_subdissector_port_prefs)(sizeof (tpkt_subdissector_port_prefs) / sizeof (tpkt_subdissector_port_prefs
)[0])
; i++)
5860 {
5861 if (strcmp(pref_name, tpkt_subdissector_port_prefs[i].pref_name) == 0)
5862 {
5863 /* XXX - give an error if it doesn't fit in a unsigned? */
5864 if (!ws_basestrtou32(value, NULL((void*)0), &uval, tpkt_subdissector_port_prefs[i].base))
5865 return false0; /* number was bad */
5866
5867 /* If the value is 0 or 102 (default TPKT port), don't add to the Decode As tables */
5868 if ((uval != 0) && (uval != 102))
5869 {
5870 tpkt_handle = find_dissector("tpkt");
5871 if (tpkt_handle != NULL((void*)0)) {
5872 dissector_change_uint(tpkt_subdissector_port_prefs[i].table_name, uval, tpkt_handle);
5873 }
5874 }
5875
5876 return true1;
5877 }
5878 }
5879
5880 for (i = 0; i < array_length(obsolete_prefs)(sizeof (obsolete_prefs) / sizeof (obsolete_prefs)[0]); i++)
5881 {
5882 if (strcmp(pref_name, obsolete_prefs[i].pref_name) == 0)
5883 {
5884 /* Just ignore the preference */
5885 return true1;
5886 }
5887 }
5888 return false0;
5889}
5890
5891static prefs_set_pref_e
5892set_pref(char *pref_name, const char *value, void *private_data,
5893 bool_Bool return_range_errors)
5894{
5895 unsigned cval;
5896 unsigned uval;
5897 bool_Bool bval;
5898 int enum_val, ival;
5899 double fval;
5900 char *dotp, *last_dotp;
5901 module_t *module, *containing_module, *target_module;
5902 pref_t *pref;
5903 bool_Bool converted_pref = false0;
5904
5905 target_module = (module_t*)private_data;
5906
5907 if (deprecated_heur_dissector_pref(pref_name, value)) {
5908 /* Handled within deprecated_heur_dissector_pref() if found */
5909 } else if (deprecated_enable_dissector_pref(pref_name, value)) {
5910 /* Handled within deprecated_enable_dissector_pref() if found */
5911 } else if (deprecated_port_pref(pref_name, value)) {
5912 /* Handled within deprecated_port_pref() if found */
5913 } else if (strcmp(pref_name, "console.log.level") == 0) {
5914 /* Handled on the command line within ws_log_parse_args() */
5915 return PREFS_SET_OK;
5916 } else {
5917 /* To which module does this preference belong? */
5918 module = NULL((void*)0);
5919 last_dotp = pref_name;
5920 while (!module) {
5921 dotp = strchr(last_dotp, '.');
5922 if (dotp == NULL((void*)0)) {
5923 /* Either there's no such module, or no module was specified.
5924 In either case, that means there's no such preference. */
5925 return PREFS_SET_NO_SUCH_PREF;
5926 }
5927 *dotp = '\0'; /* separate module and preference name */
5928 module = prefs_find_module(pref_name);
5929
5930 /*
5931 * XXX - "Diameter" rather than "diameter" was used in earlier
5932 * versions of Wireshark; if we didn't find the module, and its name
5933 * was "Diameter", look for "diameter" instead.
5934 *
5935 * In addition, the BEEP protocol used to be the BXXP protocol,
5936 * so if we didn't find the module, and its name was "bxxp",
5937 * look for "beep" instead.
5938 *
5939 * Also, the preferences for GTP v0 and v1 were combined under
5940 * a single "gtp" heading, and the preferences for SMPP were
5941 * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
5942 * However, SMPP now has its own preferences, so we just map
5943 * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
5944 *
5945 * We also renamed "dcp" to "dccp", "x.25" to "x25", "x411" to "p1"
5946 * and "nsip" to "gprs_ns".
5947 *
5948 * The SynOptics Network Management Protocol (SONMP) is now known by
5949 * its modern name, the Nortel Discovery Protocol (NDP).
5950 */
5951 if (module == NULL((void*)0)) {
5952 /*
5953 * See if there's a backwards-compatibility name
5954 * that maps to this module.
5955 */
5956 module = prefs_find_module_alias(pref_name);
5957 if (module == NULL((void*)0)) {
5958 /*
5959 * There's no alias for the module; see if the
5960 * module name matches any protocol aliases.
5961 */
5962 header_field_info *hfinfo = proto_registrar_get_byalias(pref_name);
5963 if (hfinfo) {
5964 module = (module_t *) wmem_tree_lookup_string(prefs_modules, hfinfo->abbrev, WMEM_TREE_STRING_NOCASE0x00000001);
5965 }
5966 }
5967 if (module) {
5968 converted_pref = true1;
5969 }
5970 }
5971 *dotp = '.'; /* put the preference string back */
5972 dotp++; /* skip past separator to preference name */
5973 last_dotp = dotp;
5974 }
5975
5976 /* The pref is located in the module or a submodule.
5977 * Assume module, then search for a submodule holding the pref. */
5978 containing_module = module;
5979 pref = prefs_find_preference_with_submodule(module, dotp, &containing_module);
5980
5981 if (pref == NULL((void*)0)) {
5982 /* "gui" prefix was added to column preferences for better organization
5983 * within the preferences file
5984 */
5985 if (module == gui_column_module) {
5986 /* While this has a subtree, there is no apply callback, so no
5987 * need to use prefs_find_preference_with_submodule to update
5988 * containing_module. It would not be useful. */
5989 pref = prefs_find_preference(module, pref_name);
5990 }
5991 else if (strcmp(module->name, "tcp") == 0) {
5992 /* Handle old names for TCP preferences. */
5993 if (strcmp(dotp, "dissect_experimental_options_with_magic") == 0)
5994 pref = prefs_find_preference(module, "dissect_experimental_options_rfc6994");
5995 } else if (strcmp(module->name, "extcap") == 0) {
5996 /* Handle the old "sshdump.remotesudo" preference; map it to the new
5997 "sshdump.remotepriv" preference, and map the boolean values to the
5998 appropriate strings of the new preference. */
5999 if (strcmp(dotp, "sshdump.remotesudo") == 0) {
6000 pref = prefs_find_preference(module, "sshdump.remotepriv");
6001 if (g_ascii_strcasecmp(value, "true") == 0)
6002 value = "sudo";
6003 else
6004 value = "none";
6005 }
6006 }
6007 if (pref) {
6008 converted_pref = true1;
6009 }
6010 }
6011 if (pref == NULL((void*)0) ) {
6012 if (strcmp(module->name, "extcap") == 0 && g_list_length(module->prefs) <= 1) {
6013 /*
6014 * Assume that we've skipped extcap preference registration
6015 * and that only extcap.gui_save_on_start is loaded.
6016 */
6017 return PREFS_SET_OK;
6018 }
6019 return PREFS_SET_NO_SUCH_PREF; /* no such preference */
6020 }
6021
6022 if (target_module && target_module != containing_module) {
6023 /* Ignore */
6024 return PREFS_SET_OK;
6025 }
6026
6027 if (pref->obsolete)
6028 return PREFS_SET_OBSOLETE; /* no such preference any more */
6029
6030 if (converted_pref) {
6031 ws_warning("Preference \"%s\" has been converted to \"%s.%s\"\n"do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6033, __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)
6032 "Save your preferences to make this change permanent.",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6033, __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)
6033 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"
, 6033, __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)
;
6034 }
6035
6036 switch (pref->type) {
6037
6038 case PREF_UINT:
6039 if (!ws_basestrtou32(value, NULL((void*)0), &uval, pref->info.base))
6040 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6041 if (*pref->varp.uint != uval) {
6042 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6043 *pref->varp.uint = uval;
6044 }
6045 break;
6046
6047 case PREF_INT:
6048 if (!ws_strtoi32(value, NULL((void*)0), &ival))
6049 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6050 if (*pref->varp.intp != ival) {
6051 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6052 *pref->varp.intp = ival;
6053 }
6054 break;
6055
6056 case PREF_FLOAT:
6057 fval = g_ascii_strtod(value, NULL((void*)0));
6058 if (errno(*__errno_location ()) == ERANGE34)
6059 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6060
6061 if (*pref->varp.floatp != fval) {
6062 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6063 *pref->varp.floatp = fval;
6064 }
6065 break;
6066
6067 case PREF_BOOL:
6068 /* XXX - give an error if it's neither "true" nor "false"? */
6069 if (g_ascii_strcasecmp(value, "true") == 0)
6070 bval = true1;
6071 else
6072 bval = false0;
6073 if (*pref->varp.boolp != bval) {
6074 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6075 *pref->varp.boolp = bval;
6076 }
6077 break;
6078
6079 case PREF_ENUM:
6080 /* XXX - give an error if it doesn't match? */
6081 enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
6082 *pref->varp.enump);
6083 if (*pref->varp.enump != enum_val) {
6084 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6085 *pref->varp.enump = enum_val;
6086 }
6087 break;
6088
6089 case PREF_STRING:
6090 case PREF_SAVE_FILENAME:
6091 case PREF_OPEN_FILENAME:
6092 case PREF_DIRNAME:
6093 case PREF_DISSECTOR:
6094 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
6095 break;
6096
6097 case PREF_PASSWORD:
6098 /* Read value is every time empty */
6099 containing_module->prefs_changed_flags |= prefs_set_string_value(pref, "", pref_current);
6100 break;
6101
6102 case PREF_RANGE:
6103 {
6104 if (!prefs_set_range_value_work(pref, value, return_range_errors,
6105 &containing_module->prefs_changed_flags))
6106 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6107 break;
6108 }
6109 case PREF_DECODE_AS_RANGE:
6110 {
6111 /* This is for backwards compatibility in case any of the preferences
6112 that shared the "Decode As" preference name and used to be PREF_RANGE
6113 are now applied directly to the Decode As functionality */
6114 range_t *newrange;
6115 dissector_table_t sub_dissectors;
6116 dissector_handle_t handle;
6117 uint32_t i, j;
6118
6119 if (range_convert_str_work(pref->scope, &newrange, value, pref->info.max_value,
6120 return_range_errors) != CVT_NO_ERROR) {
6121 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6122 }
6123
6124 if (!ranges_are_equal(*pref->varp.range, newrange)) {
6125 wmem_free(pref->scope, *pref->varp.range);
6126 *pref->varp.range = newrange;
6127 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6128
6129 const char* table_name = prefs_get_dissector_table(pref);
6130 sub_dissectors = find_dissector_table(table_name);
6131 if (sub_dissectors != NULL((void*)0)) {
6132 handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
6133 if (handle != NULL((void*)0)) {
6134 /* Delete all of the old values from the dissector table */
6135 for (i = 0; i < (*pref->varp.range)->nranges; i++) {
6136 for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
6137 dissector_delete_uint(table_name, j, handle);
6138 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));
6139 }
6140
6141 dissector_delete_uint(table_name, (*pref->varp.range)->ranges[i].high, handle);
6142 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));
6143 }
6144
6145 /* Add new values to the dissector table */
6146 for (i = 0; i < newrange->nranges; i++) {
6147 for (j = newrange->ranges[i].low; j < newrange->ranges[i].high; j++) {
6148 dissector_change_uint(table_name, j, handle);
6149 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));
6150 }
6151
6152 dissector_change_uint(table_name, newrange->ranges[i].high, handle);
6153 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));
6154 }
6155
6156 /* XXX - Do we save the decode_as_entries file here? */
6157 }
6158 }
6159 } else {
6160 wmem_free(pref->scope, newrange);
6161 }
6162 break;
6163 }
6164
6165 case PREF_COLOR:
6166 {
6167 if (!ws_hexstrtou32(value, NULL((void*)0), &cval))
6168 return PREFS_SET_SYNTAX_ERR; /* number was bad */
6169 if ((pref->varp.colorp->red != RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
) ||
6170 (pref->varp.colorp->green != GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255))) ||
6171 (pref->varp.colorp->blue != BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255)))) {
6172 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
6173 pref->varp.colorp->red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
6174 pref->varp.colorp->green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
6175 pref->varp.colorp->blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
6176 }
6177 break;
6178 }
6179
6180 case PREF_CUSTOM:
6181 return pref->custom_cbs.set_cb(pref, value, &containing_module->prefs_changed_flags);
6182
6183 case PREF_STATIC_TEXT:
6184 case PREF_UAT:
6185 break;
6186
6187 case PREF_PROTO_TCP_SNDAMB_ENUM:
6188 {
6189 /* There's no point in setting the TCP sequence override
6190 * value from the command line, because the pref is different
6191 * for each frame and reset to the default (0) for each new
6192 * file.
6193 */
6194 break;
6195 }
6196 }
6197 }
6198
6199 return PREFS_SET_OK;
6200}
6201
6202typedef struct {
6203 FILE *pf;
6204 bool_Bool is_gui_module;
6205} write_gui_pref_arg_t;
6206
6207const char *
6208prefs_pref_type_name(pref_t *pref)
6209{
6210 const char *type_name = "[Unknown]";
6211
6212 if (!pref) {
6213 return type_name; /* ...or maybe assert? */
6214 }
6215
6216 if (pref->obsolete) {
6217 type_name = "Obsolete";
6218 } else {
6219 switch (pref->type) {
6220
6221 case PREF_UINT:
6222 switch (pref->info.base) {
6223
6224 case 10:
6225 type_name = "Decimal";
6226 break;
6227
6228 case 8:
6229 type_name = "Octal";
6230 break;
6231
6232 case 16:
6233 type_name = "Hexadecimal";
6234 break;
6235 }
6236 break;
6237
6238 case PREF_INT:
6239 type_name = "Integer";
6240 break;
6241
6242 case PREF_FLOAT:
6243 type_name = "Float";
6244 break;
6245
6246 case PREF_BOOL:
6247 type_name = "Boolean";
6248 break;
6249
6250 case PREF_ENUM:
6251 case PREF_PROTO_TCP_SNDAMB_ENUM:
6252 type_name = "Choice";
6253 break;
6254
6255 case PREF_STRING:
6256 type_name = "String";
6257 break;
6258
6259 case PREF_SAVE_FILENAME:
6260 case PREF_OPEN_FILENAME:
6261 type_name = "Filename";
6262 break;
6263
6264 case PREF_DIRNAME:
6265 type_name = "Directory";
6266 break;
6267
6268 case PREF_RANGE:
6269 type_name = "Range";
6270 break;
6271
6272 case PREF_COLOR:
6273 type_name = "Color";
6274 break;
6275
6276 case PREF_CUSTOM:
6277 if (pref->custom_cbs.type_name_cb)
6278 return pref->custom_cbs.type_name_cb();
6279 type_name = "Custom";
6280 break;
6281
6282 case PREF_DECODE_AS_RANGE:
6283 type_name = "Range (for Decode As)";
6284 break;
6285
6286 case PREF_STATIC_TEXT:
6287 type_name = "Static text";
6288 break;
6289
6290 case PREF_UAT:
6291 type_name = "UAT";
6292 break;
6293
6294 case PREF_PASSWORD:
6295 type_name = "Password";
6296 break;
6297
6298 case PREF_DISSECTOR:
6299 type_name = "Dissector";
6300 break;
6301 }
6302 }
6303
6304 return type_name;
6305}
6306
6307unsigned int
6308prefs_get_effect_flags(pref_t *pref)
6309{
6310 if (pref == NULL((void*)0))
6311 return 0;
6312
6313 return pref->effect_flags;
6314}
6315
6316void
6317prefs_set_effect_flags(pref_t *pref, unsigned int flags)
6318{
6319 if (pref != NULL((void*)0)) {
6320 if (flags == 0) {
6321 ws_error("Setting \"%s\" preference effect flags to 0", pref->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6321
, __func__, "Setting \"%s\" preference effect flags to 0", pref
->name)
;
6322 }
6323 pref->effect_flags = flags;
6324 }
6325}
6326
6327void
6328prefs_set_effect_flags_by_name(module_t * module, const char *pref, unsigned int flags)
6329{
6330 prefs_set_effect_flags(prefs_find_preference(module, pref), flags);
6331}
6332
6333unsigned int
6334prefs_get_module_effect_flags(module_t * module)
6335{
6336 if (module == NULL((void*)0))
6337 return 0;
6338
6339 return module->effect_flags;
6340}
6341
6342void
6343prefs_set_module_effect_flags(module_t * module, unsigned int flags)
6344{
6345 if (module != NULL((void*)0)) {
6346 if (flags == 0) {
6347 ws_error("Setting module \"%s\" preference effect flags to 0", module->name)ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/prefs.c", 6347
, __func__, "Setting module \"%s\" preference effect flags to 0"
, module->name)
;
6348 }
6349 module->effect_flags = flags;
6350 }
6351}
6352
6353char *
6354prefs_pref_type_description(pref_t *pref)
6355{
6356 const char *type_desc = "An unknown preference type";
6357
6358 if (!pref) {
6359 return ws_strdup_printf("%s.", type_desc)wmem_strdup_printf(((void*)0), "%s.", type_desc); /* ...or maybe assert? */
6360 }
6361
6362 if (pref->obsolete) {
6363 type_desc = "An obsolete preference";
6364 } else {
6365 switch (pref->type) {
6366
6367 case PREF_UINT:
6368 switch (pref->info.base) {
6369
6370 case 10:
6371 type_desc = "A decimal number";
6372 break;
6373
6374 case 8:
6375 type_desc = "An octal number";
6376 break;
6377
6378 case 16:
6379 type_desc = "A hexadecimal number";
6380 break;
6381 }
6382 break;
6383
6384 case PREF_INT:
6385 type_desc = "A decimal number";
6386 break;
6387
6388 case PREF_FLOAT:
6389 type_desc = "A floating point number";
6390 break;
6391
6392 case PREF_BOOL:
6393 type_desc = "true or false (case-insensitive)";
6394 break;
6395
6396 case PREF_ENUM:
6397 case PREF_PROTO_TCP_SNDAMB_ENUM:
6398 {
6399 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6400 GString *enum_str = g_string_new("One of: ");
6401 GString *desc_str = g_string_new("\nEquivalently, one of: ");
6402 bool_Bool distinct = false0;
6403 while (enum_valp->name != NULL((void*)0)) {
6404 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))
;
6405 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))
;
6406 if (g_strcmp0(enum_valp->name, enum_valp->description) != 0) {
6407 distinct = true1;
6408 }
6409 enum_valp++;
6410 if (enum_valp->name != NULL((void*)0)) {
6411 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))
;
6412 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))
;
6413 }
6414 }
6415 if (distinct) {
6416 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))
;
6417 }
6418 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)))))
;
6419 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))
;
6420 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))))
;
6421 }
6422
6423 case PREF_STRING:
6424 type_desc = "A string";
6425 break;
6426
6427 case PREF_SAVE_FILENAME:
6428 case PREF_OPEN_FILENAME:
6429 type_desc = "A path to a file";
6430 break;
6431
6432 case PREF_DIRNAME:
6433 type_desc = "A path to a directory";
6434 break;
6435
6436 case PREF_RANGE:
6437 {
6438 type_desc = "A string denoting an positive integer range (e.g., \"1-20,30-40\")";
6439 break;
6440 }
6441
6442 case PREF_COLOR:
6443 {
6444 type_desc = "A six-digit hexadecimal RGB color triplet (e.g. fce94f)";
6445 break;
6446 }
6447
6448 case PREF_CUSTOM:
6449 if (pref->custom_cbs.type_description_cb)
6450 return pref->custom_cbs.type_description_cb();
6451 type_desc = "A custom value";
6452 break;
6453
6454 case PREF_DECODE_AS_RANGE:
6455 type_desc = "A string denoting an positive integer range for Decode As";
6456 break;
6457
6458 case PREF_STATIC_TEXT:
6459 type_desc = "[Static text]";
6460 break;
6461
6462 case PREF_UAT:
6463 type_desc = "Configuration data stored in its own file";
6464 break;
6465
6466 case PREF_PASSWORD:
6467 type_desc = "Password (never stored on disk)";
6468 break;
6469
6470 case PREF_DISSECTOR:
6471 type_desc = "A dissector name";
6472 break;
6473
6474 default:
6475 break;
6476 }
6477 }
6478
6479 return g_strdup(type_desc)g_strdup_inline (type_desc);
6480}
6481
6482bool_Bool
6483prefs_pref_is_default(pref_t *pref)
6484{
6485 if (!pref) return false0;
6486
6487 if (pref->obsolete) {
6488 return false0;
6489 }
6490
6491 switch (pref->type) {
6492
6493 case PREF_UINT:
6494 if (pref->default_val.uint == *pref->varp.uint)
6495 return true1;
6496 break;
6497
6498 case PREF_INT:
6499 if (pref->default_val.intval == *pref->varp.intp)
6500 return true1;
6501 break;
6502
6503 case PREF_FLOAT:
6504 if (pref->default_val.floatval == *pref->varp.floatp)
6505 return true1;
6506 break;
6507
6508 case PREF_BOOL:
6509 if (pref->default_val.boolval == *pref->varp.boolp)
6510 return true1;
6511 break;
6512
6513 case PREF_ENUM:
6514 case PREF_PROTO_TCP_SNDAMB_ENUM:
6515 if (pref->default_val.enumval == *pref->varp.enump)
6516 return true1;
6517 break;
6518
6519 case PREF_STRING:
6520 case PREF_SAVE_FILENAME:
6521 case PREF_OPEN_FILENAME:
6522 case PREF_DIRNAME:
6523 case PREF_PASSWORD:
6524 case PREF_DISSECTOR:
6525 if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
6526 return true1;
6527 break;
6528
6529 case PREF_DECODE_AS_RANGE:
6530 case PREF_RANGE:
6531 {
6532 if ((ranges_are_equal(pref->default_val.range, *pref->varp.range)))
6533 return true1;
6534 break;
6535 }
6536
6537 case PREF_COLOR:
6538 {
6539 if ((pref->default_val.color.red == pref->varp.colorp->red) &&
6540 (pref->default_val.color.green == pref->varp.colorp->green) &&
6541 (pref->default_val.color.blue == pref->varp.colorp->blue))
6542 return true1;
6543 break;
6544 }
6545
6546 case PREF_CUSTOM:
6547 return pref->custom_cbs.is_default_cb(pref);
6548
6549 case PREF_STATIC_TEXT:
6550 case PREF_UAT:
6551 return false0;
6552 /* ws_assert_not_reached(); */
6553 break;
6554 }
6555
6556 return false0;
6557}
6558
6559char *
6560prefs_pref_to_str(pref_t *pref, pref_source_t source)
6561{
6562 const char *pref_text = "[Unknown]";
6563 void *valp; /* pointer to preference value */
6564 color_t *pref_color;
6565 char *tmp_value, *ret_value;
6566
6567 if (!pref) {
6568 return g_strdup(pref_text)g_strdup_inline (pref_text);
6569 }
6570
6571 switch (source) {
6572 case pref_default:
6573 valp = &pref->default_val;
6574 /* valp = &boolval, &enumval, etc. are implied by union property */
6575 pref_color = &pref->default_val.color;
6576 break;
6577 case pref_stashed:
6578 valp = &pref->stashed_val;
6579 /* valp = &boolval, &enumval, etc. are implied by union property */
6580 pref_color = &pref->stashed_val.color;
6581 break;
6582 case pref_current:
6583 valp = pref->varp.uint;
6584 /* valp = boolval, enumval, etc. are implied by union property */
6585 pref_color = pref->varp.colorp;
6586 break;
6587 default:
6588 return g_strdup(pref_text)g_strdup_inline (pref_text);
6589 }
6590
6591 if (pref->obsolete) {
6592 pref_text = "[Obsolete]";
6593 } else {
6594 switch (pref->type) {
6595
6596 case PREF_UINT:
6597 {
6598 unsigned pref_uint = *(unsigned *) valp;
6599 switch (pref->info.base) {
6600
6601 case 10:
6602 return ws_strdup_printf("%u", pref_uint)wmem_strdup_printf(((void*)0), "%u", pref_uint);
6603
6604 case 8:
6605 return ws_strdup_printf("%#o", pref_uint)wmem_strdup_printf(((void*)0), "%#o", pref_uint);
6606
6607 case 16:
6608 return ws_strdup_printf("%#x", pref_uint)wmem_strdup_printf(((void*)0), "%#x", pref_uint);
6609 }
6610 break;
6611 }
6612 case PREF_INT:
6613 return ws_strdup_printf("%d", *(int*)valp)wmem_strdup_printf(((void*)0), "%d", *(int*)valp);
6614
6615 case PREF_FLOAT:
6616 return ws_strdup_printf("%.*f", pref->info.base, *(double*)valp)wmem_strdup_printf(((void*)0), "%.*f", pref->info.base, *(
double*)valp)
;
6617
6618 case PREF_BOOL:
6619 return g_strdup((*(bool *) valp) ? "TRUE" : "FALSE")g_strdup_inline ((*(_Bool *) valp) ? "TRUE" : "FALSE");
6620
6621 case PREF_ENUM:
6622 case PREF_PROTO_TCP_SNDAMB_ENUM:
6623 {
6624 int pref_enumval = *(int *) valp;
6625 const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6626 /*
6627 * TODO - We write the "description" value, because the "name" values
6628 * weren't validated to be command line friendly until 5.0, and a few
6629 * of them had to be changed. This allows older versions of Wireshark
6630 * to read preferences that they supported, as we supported either
6631 * the short name or the description when reading the preference files
6632 * or an "-o" option. Once 5.0 is the oldest supported version, switch
6633 * to writing the name below.
6634 */
6635 while (enum_valp->name != NULL((void*)0)) {
6636 if (enum_valp->value == pref_enumval)
6637 return g_strdup(enum_valp->description)g_strdup_inline (enum_valp->description);
6638 enum_valp++;
6639 }
6640 break;
6641 }
6642
6643 case PREF_STRING:
6644 case PREF_SAVE_FILENAME:
6645 case PREF_OPEN_FILENAME:
6646 case PREF_DIRNAME:
6647 case PREF_PASSWORD:
6648 case PREF_DISSECTOR:
6649 return prefs_sanitize_string(*(const char **) valp);
6650
6651 case PREF_DECODE_AS_RANGE:
6652 case PREF_RANGE:
6653 /* Convert wmem to g_alloc memory */
6654 tmp_value = range_convert_range(NULL((void*)0), *(range_t **) valp);
6655 ret_value = g_strdup(tmp_value)g_strdup_inline (tmp_value);
6656 wmem_free(NULL((void*)0), tmp_value);
6657 return ret_value;
6658
6659 case PREF_COLOR:
6660 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))
6661 (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))
6662 (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))
6663 (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))
;
6664
6665 case PREF_CUSTOM:
6666 if (pref->custom_cbs.to_str_cb)
6667 return pref->custom_cbs.to_str_cb(pref, source == pref_default ? true1 : false0);
6668 pref_text = "[Custom]";
6669 break;
6670
6671 case PREF_STATIC_TEXT:
6672 pref_text = "[Static text]";
6673 break;
6674
6675 case PREF_UAT:
6676 {
6677 uat_t *uat = pref->varp.uat;
6678 if (uat && uat->filename)
6679 return ws_strdup_printf("[Managed in the file \"%s\"]", uat->filename)wmem_strdup_printf(((void*)0), "[Managed in the file \"%s\"]"
, uat->filename)
;
6680 else
6681 pref_text = "[Managed in an unknown file]";
6682 break;
6683 }
6684
6685 default:
6686 break;
6687 }
6688 }
6689
6690 return g_strdup(pref_text)g_strdup_inline (pref_text);
6691}
6692
6693/*
6694 * Write out a single dissector preference.
6695 */
6696void
6697pref_write_individual(void *data, void *user_data)
6698{
6699 pref_t *pref = (pref_t *)data;
6700 write_pref_arg_t *arg = (write_pref_arg_t *)user_data;
6701 char **desc_lines;
6702 int i;
6703
6704 if (!pref || pref->obsolete) {
6705 /*
6706 * This preference is no longer supported; it's not a
6707 * real preference, so we don't write it out (i.e., we
6708 * treat it as if it weren't found in the list of
6709 * preferences, and we weren't called in the first place).
6710 */
6711 return;
6712 }
6713
6714 switch (pref->type) {
6715
6716 case PREF_STATIC_TEXT:
6717 case PREF_UAT:
6718 /* Nothing to do; don't bother printing the description */
6719 return;
6720 case PREF_DECODE_AS_RANGE:
6721 /* Data is saved through Decode As mechanism and not part of preferences file */
6722 return;
6723 case PREF_PROTO_TCP_SNDAMB_ENUM:
6724 /* Not written to the preference file because the override is only
6725 * for the lifetime of the capture file and there is no single
6726 * value to write.
6727 */
6728 return;
6729 default:
6730 break;
6731 }
6732
6733 if (pref->type != PREF_CUSTOM || pref->custom_cbs.type_name_cb() != NULL((void*)0)) {
6734 /*
6735 * The prefix will either be the module name or the parent
6736 * name if it's a subtree
6737 */
6738 const char *name_prefix = (arg->module->name != NULL((void*)0)) ? arg->module->name : arg->module->parent->name;
6739 char *type_desc, *pref_text;
6740 const char * def_prefix = prefs_pref_is_default(pref) ? "#" : "";
6741
6742 if (pref->type == PREF_CUSTOM)
6743 fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
6744 fprintf(arg->pf, "\n");
6745 if (pref->description &&
6746 (g_ascii_strncasecmp(pref->description,"", 2) != 0)) {
6747 if (pref->type != PREF_CUSTOM) {
6748 /* We get duplicate lines otherwise. */
6749
6750 desc_lines = g_strsplit(pref->description, "\n", 0);
6751 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6752 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6753 }
6754 g_strfreev(desc_lines);
6755 }
6756 } else {
6757 fprintf(arg->pf, "# No description\n");
6758 }
6759
6760 type_desc = prefs_pref_type_description(pref);
6761 desc_lines = g_strsplit(type_desc, "\n", 0);
6762 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6763 fprintf(arg->pf, "# %s\n", desc_lines[i]);
6764 }
6765 g_strfreev(desc_lines);
6766 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)
;
6767
6768 pref_text = prefs_pref_to_str(pref, pref_current);
6769 fprintf(arg->pf, "%s%s.%s: ", def_prefix, name_prefix, pref->name);
6770 if (pref->type != PREF_PASSWORD)
6771 {
6772 desc_lines = g_strsplit(pref_text, "\n", 0);
6773 for (i = 0; desc_lines[i] != NULL((void*)0); ++i) {
6774 fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
6775 }
6776 if (i == 0)
6777 fprintf(arg->pf, "\n");
6778 g_strfreev(desc_lines);
6779 } else {
6780 /* We never store password value */
6781 fprintf(arg->pf, "\n");
6782 }
6783 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)
;
6784 }
6785
6786}
6787
6788static void
6789count_non_uat_pref(void *data, void *user_data)
6790{
6791 pref_t *pref = (pref_t *)data;
6792 int *arg = (int *)user_data;
6793
6794 switch (pref->type)
6795 {
6796 case PREF_UAT:
6797 case PREF_DECODE_AS_RANGE:
6798 case PREF_PROTO_TCP_SNDAMB_ENUM:
6799 //These types are not written in preference file
6800 break;
6801 default:
6802 (*arg)++;
6803 break;
6804 }
6805}
6806
6807int
6808prefs_num_non_uat(module_t *module)
6809{
6810 int num = 0;
6811
6812 g_list_foreach(module->prefs, count_non_uat_pref, &num);
6813
6814 return num;
6815}
6816
6817/*
6818 * Write out all preferences for a module.
6819 */
6820static unsigned
6821write_module_prefs(module_t *module, void *user_data)
6822{
6823 write_gui_pref_arg_t *gui_pref_arg = (write_gui_pref_arg_t*)user_data;
6824 write_pref_arg_t arg;
6825
6826 /* The GUI module needs to be explicitly called out so it
6827 can be written out of order */
6828 if ((module == gui_module) && (gui_pref_arg->is_gui_module != true1))
6829 return 0;
6830
6831 /* Write a header for the main modules and GUI sub-modules */
6832 if (((module->parent == NULL((void*)0)) || (module->parent == gui_module)) &&
6833 ((prefs_module_has_submodules(module)) ||
6834 (prefs_num_non_uat(module) > 0) ||
6835 (module->name == NULL((void*)0)))) {
6836 if ((module->name == NULL((void*)0)) && (module->parent != NULL((void*)0))) {
6837 fprintf(gui_pref_arg->pf, "\n####### %s: %s ########\n", module->parent->title, module->title);
6838 } else {
6839 fprintf(gui_pref_arg->pf, "\n####### %s ########\n", module->title);
6840 }
6841 }
6842
6843 arg.module = module;
6844 arg.pf = gui_pref_arg->pf;
6845 g_list_foreach(arg.module->prefs, pref_write_individual, &arg);
6846
6847 if (prefs_module_has_submodules(module))
6848 return prefs_modules_foreach_submodules(module->submodules, write_module_prefs, user_data);
6849
6850 return 0;
6851}
6852
6853#ifdef _WIN32
6854static void
6855write_registry(void)
6856{
6857 HKEY hTestKey;
6858 DWORD data;
6859 DWORD data_size;
6860 DWORD ret;
6861
6862 ret = RegCreateKeyExA(HKEY_CURRENT_USER, REG_HKCU_WIRESHARK_KEY"Software\\Wireshark", 0, NULL((void*)0),
6863 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL((void*)0),
6864 &hTestKey, NULL((void*)0));
6865 if (ret != ERROR_SUCCESS) {
6866 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"
, 6866, __func__, "Cannot open HKCU ""Software\\Wireshark"": 0x%lx"
, ret); } } while (0)
;
6867 return;
6868 }
6869
6870 data = ws_log_console_open;
6871 data_size = sizeof(DWORD);
6872 ret = RegSetValueExA(hTestKey, LOG_HKCU_CONSOLE_OPEN"ConsoleOpen", 0, REG_DWORD, (const BYTE *)&data, data_size);
6873 if (ret == ERROR_SUCCESS) {
6874 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"
, 6874, __func__, "Wrote ""ConsoleOpen"" to Windows registry: 0x%lu"
, data); } } while (0)
;
6875 }
6876 else {
6877 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"
, 6877, __func__, "Error writing registry key ""ConsoleOpen"": 0x%lx"
, ret); } } while (0)
;
6878 }
6879
6880 RegCloseKey(hTestKey);
6881}
6882#endif
6883
6884/* Write out "prefs" to the user's preferences file, and return 0.
6885
6886 If the preferences file path is NULL, write to stdout.
6887
6888 If we got an error, stuff a pointer to the path of the preferences file
6889 into "*pf_path_return", and return the errno. */
6890int
6891write_prefs(const char* app_env_var_prefix, char **pf_path_return)
6892{
6893 char *pf_path;
6894 FILE *pf;
6895 write_gui_pref_arg_t write_gui_pref_info;
6896
6897#ifdef _WIN32
6898 write_registry();
6899#endif
6900
6901 /* To do:
6902 * - Split output lines longer than MAX_VAL_LEN
6903 * - Create a function for the preference directory check/creation
6904 * so that duplication can be avoided with filter.c
6905 */
6906
6907 if (pf_path_return != NULL((void*)0)) {
6908 pf_path = get_persconffile_path(PF_NAME"preferences", true1, app_env_var_prefix);
6909 if ((pf = ws_fopenfopen(pf_path, "w")) == NULL((void*)0)) {
6910 *pf_path_return = pf_path;
6911 return errno(*__errno_location ());
6912 }
6913 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)
;
6914 } else {
6915 pf = stdoutstdout;
6916 }
6917
6918 /*
6919 * If the preferences file is being written, be sure to write UAT files
6920 * first that were migrated from the preferences file.
6921 */
6922 if (pf_path_return != NULL((void*)0)) {
6923 if (prefs.filter_expressions_old) {
6924 char *err = NULL((void*)0);
6925 prefs.filter_expressions_old = false0;
6926 if (!uat_save(uat_get_table_by_name("Display expressions"), app_env_var_prefix, &err)) {
6927 ws_warning("Unable to save Display expressions: %s", err)do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6927, __func__, "Unable to save Display expressions: %s", err
); } } while (0)
;
6928 g_free(err)(__builtin_object_size ((err), 0) != ((size_t) - 1)) ? g_free_sized
(err, __builtin_object_size ((err), 0)) : (g_free) (err)
;
6929 }
6930 }
6931
6932 module_t *extcap_module = prefs_find_module("extcap");
6933 if (extcap_module && !prefs.capture_no_extcap) {
6934 char *ext_path = get_persconffile_path("extcap.cfg", true1, app_env_var_prefix);
6935 FILE *extf;
6936 if ((extf = ws_fopenfopen(ext_path, "w")) == NULL((void*)0)) {
6937 if (errno(*__errno_location ()) != EISDIR21) {
6938 ws_warning("Unable to save extcap preferences \"%s\": %s",do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6939, __func__, "Unable to save extcap preferences \"%s\": %s"
, ext_path, g_strerror((*__errno_location ()))); } } while (0
)
6939 ext_path, g_strerror(errno))do { if (1) { ws_log_full("Epan", LOG_LEVEL_WARNING, "epan/prefs.c"
, 6939, __func__, "Unable to save extcap preferences \"%s\": %s"
, ext_path, g_strerror((*__errno_location ()))); } } while (0
)
;
6940 }
6941 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)
;
6942 } else {
6943 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)
;
6944
6945 fputs("# Extcap configuration file for Wireshark " VERSION"4.7.1" ".\n"
6946 "#\n"
6947 "# This file is regenerated each time preferences are saved within\n"
6948 "# Wireshark. Making manual changes should be safe, however.\n"
6949 "# Preferences that have been commented out have not been\n"
6950 "# changed from their default value.\n", extf);
6951
6952 write_gui_pref_info.pf = extf;
6953 write_gui_pref_info.is_gui_module = false0;
6954
6955 write_module_prefs(extcap_module, &write_gui_pref_info);
6956
6957 fclose(extf);
6958 }
6959 }
6960 }
6961
6962 fputs("# Configuration file for Wireshark " VERSION"4.7.1" ".\n"
6963 "#\n"
6964 "# This file is regenerated each time preferences are saved within\n"
6965 "# Wireshark. Making manual changes should be safe, however.\n"
6966 "# Preferences that have been commented out have not been\n"
6967 "# changed from their default value.\n", pf);
6968
6969 /*
6970 * For "backwards compatibility" the GUI module is written first as it's
6971 * at the top of the file. This is followed by all modules that can't
6972 * fit into the preferences read/write API. Finally the remaining modules
6973 * are written in alphabetical order (including of course the protocol preferences)
6974 */
6975 write_gui_pref_info.pf = pf;
6976 write_gui_pref_info.is_gui_module = true1;
6977
6978 write_module_prefs(gui_module, &write_gui_pref_info);
6979
6980 write_gui_pref_info.is_gui_module = false0;
6981 prefs_module_list_foreach(prefs_top_level_modules, write_module_prefs, &write_gui_pref_info, true1);
6982
6983 fclose(pf);
6984
6985 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
6986 an error indication, or maybe write to a new preferences file and
6987 rename that file on top of the old one only if there are not I/O
6988 errors. */
6989 return 0;
6990}
6991
6992/** The col_list is only partly managed by the custom preference API
6993 * because its data is shared between multiple preferences, so
6994 * it's freed here
6995 */
6996static void
6997free_col_info(GList *list)
6998{
6999 fmt_data *cfmt;
7000 GList *list_head = list;
7001
7002 while (list != NULL((void*)0)) {
7003 cfmt = (fmt_data *)list->data;
7004
7005 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)
;
7006 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
)
;
7007 g_free(cfmt)(__builtin_object_size ((cfmt), 0) != ((size_t) - 1)) ? g_free_sized
(cfmt, __builtin_object_size ((cfmt), 0)) : (g_free) (cfmt)
;
7008 list = g_list_next(list)((list) ? (((GList *)(list))->next) : ((void*)0));
7009 }
7010 g_list_free(list_head);
7011}
7012
7013/*
7014 * Editor modelines
7015 *
7016 * Local Variables:
7017 * c-basic-offset: 4
7018 * tab-width: 8
7019 * indent-tabs-mode: nil
7020 * End:
7021 *
7022 * ex: set shiftwidth=4 tabstop=8 expandtab:
7023 * :indentSize=4:tabSize=8:noTabs=true:
7024 */