Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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