Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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