Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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