Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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