Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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