2018-01-08 14:02:15 -08:00
|
|
|
/* preference_utils.c
|
2013-01-18 00:50:14 +00:00
|
|
|
* Routines for handling preferences
|
|
|
|
*
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
*
|
2018-02-07 12:26:45 +01:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2013-01-18 00:50:14 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
2013-01-23 19:04:36 +00:00
|
|
|
#include <epan/column.h>
|
2013-11-17 02:55:14 +00:00
|
|
|
#include <wsutil/filesystem.h>
|
2021-06-17 15:58:56 +01:00
|
|
|
#include <wsutil/wslog.h>
|
2013-01-18 00:50:14 +00:00
|
|
|
#include <epan/prefs.h>
|
|
|
|
#include <epan/prefs-int.h>
|
2016-10-07 16:25:01 -04:00
|
|
|
#include <epan/packet.h>
|
|
|
|
#include <epan/decode_as.h>
|
2018-09-08 11:49:22 +02:00
|
|
|
#include <epan/uat-int.h>
|
2019-12-10 22:01:16 -05:00
|
|
|
#include <ui/recent.h>
|
2013-01-18 00:50:14 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
#include "capture_opts.h"
|
|
|
|
#include "ui/capture_globals.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ui/preference_utils.h"
|
|
|
|
#include "ui/simple_dialog.h"
|
|
|
|
|
|
|
|
/* Fill in capture options with values from the preferences */
|
|
|
|
void
|
|
|
|
prefs_to_capture_opts(void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_LIBPCAP
|
2017-11-28 16:03:11 -08:00
|
|
|
/* Set promiscuous mode from the preferences setting. */
|
|
|
|
/* the same applies to other preferences settings as well. */
|
2013-01-18 00:50:14 +00:00
|
|
|
global_capture_opts.default_options.promisc_mode = prefs.capture_prom_mode;
|
2023-11-21 22:54:01 -05:00
|
|
|
global_capture_opts.default_options.monitor_mode = prefs.capture_monitor_mode;
|
2013-01-18 00:50:14 +00:00
|
|
|
global_capture_opts.use_pcapng = prefs.capture_pcap_ng;
|
2018-05-16 01:22:54 -07:00
|
|
|
global_capture_opts.show_info = prefs.capture_show_info;
|
2013-01-18 00:50:14 +00:00
|
|
|
global_capture_opts.real_time_mode = prefs.capture_real_time;
|
2023-03-08 22:15:21 -05:00
|
|
|
global_capture_opts.update_interval = prefs.capture_update_interval;
|
2013-01-18 00:50:14 +00:00
|
|
|
#endif /* HAVE_LIBPCAP */
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
prefs_main_write(void)
|
|
|
|
{
|
2017-11-28 16:03:11 -08:00
|
|
|
int err;
|
|
|
|
char *pf_dir_path;
|
|
|
|
char *pf_path;
|
|
|
|
|
|
|
|
/* Create the directory that holds personal configuration files, if
|
|
|
|
necessary. */
|
|
|
|
if (create_persconffile_dir(&pf_dir_path) == -1) {
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
|
|
|
"Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
|
|
|
|
g_strerror(errno));
|
|
|
|
g_free(pf_dir_path);
|
|
|
|
} else {
|
2019-12-10 22:01:16 -05:00
|
|
|
/* Write the preferences out. */
|
2017-11-28 16:03:11 -08:00
|
|
|
err = write_prefs(&pf_path);
|
|
|
|
if (err != 0) {
|
|
|
|
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
|
2013-01-18 00:50:14 +00:00
|
|
|
"Can't open preferences file\n\"%s\": %s.", pf_path,
|
|
|
|
g_strerror(err));
|
2017-11-28 16:03:11 -08:00
|
|
|
g_free(pf_path);
|
|
|
|
}
|
2019-12-10 22:01:16 -05:00
|
|
|
/* Write recent and recent_common files out to ensure sync with prefs. */
|
|
|
|
write_profile_recent();
|
|
|
|
write_recent();
|
2013-01-18 00:50:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-05 23:39:55 -05:00
|
|
|
static unsigned int
|
2016-01-21 13:41:42 +01:00
|
|
|
prefs_store_ext_helper(const char * module_name, const char *pref_name, const char *pref_value)
|
2015-06-05 11:19:37 +02:00
|
|
|
{
|
2017-11-28 16:03:11 -08:00
|
|
|
pref_t * pref = NULL;
|
2018-01-05 23:39:55 -05:00
|
|
|
unsigned int pref_changed = 0;
|
2015-06-05 11:19:37 +02:00
|
|
|
|
2021-12-30 16:03:15 +00:00
|
|
|
if ( !prefs_is_registered_protocol(module_name))
|
2018-01-05 23:39:55 -05:00
|
|
|
return 0;
|
2015-06-05 11:19:37 +02:00
|
|
|
|
2024-11-22 14:25:06 -08:00
|
|
|
pref = prefs_find_preference(prefs_find_module(module_name), pref_name);
|
2015-06-05 11:19:37 +02:00
|
|
|
|
2017-11-28 16:03:11 -08:00
|
|
|
if (!pref)
|
2018-01-05 23:39:55 -05:00
|
|
|
return 0;
|
2015-06-05 11:19:37 +02:00
|
|
|
|
2023-11-01 14:55:14 +01:00
|
|
|
if (prefs_get_type(pref) == PREF_STRING || prefs_get_type(pref) == PREF_DISSECTOR)
|
2017-11-28 16:03:11 -08:00
|
|
|
{
|
2018-01-05 23:39:55 -05:00
|
|
|
pref_changed |= prefs_set_string_value(pref, pref_value, pref_stashed);
|
2021-12-30 16:03:15 +00:00
|
|
|
if ( !pref_changed || prefs_get_string_value(pref, pref_stashed) != 0 )
|
2018-01-05 23:39:55 -05:00
|
|
|
pref_changed |= prefs_set_string_value(pref, pref_value, pref_current);
|
2021-12-30 16:03:15 +00:00
|
|
|
} else if (prefs_get_type(pref) == PREF_PASSWORD )
|
|
|
|
{
|
|
|
|
pref_changed |= prefs_set_password_value(pref, pref_value, pref_stashed);
|
|
|
|
if ( !pref_changed || prefs_get_password_value(pref, pref_stashed) != 0 )
|
|
|
|
pref_changed |= prefs_set_password_value(pref, pref_value, pref_current);
|
2017-11-28 16:03:11 -08:00
|
|
|
}
|
2015-06-05 11:19:37 +02:00
|
|
|
|
2017-11-28 16:03:11 -08:00
|
|
|
return pref_changed;
|
2016-01-21 13:41:42 +01:00
|
|
|
}
|
|
|
|
|
2018-01-05 23:39:55 -05:00
|
|
|
unsigned int
|
2016-01-21 13:41:42 +01:00
|
|
|
prefs_store_ext(const char * module_name, const char *pref_name, const char *pref_value)
|
|
|
|
{
|
2018-01-05 23:39:55 -05:00
|
|
|
unsigned int changed_flags = prefs_store_ext_helper(module_name, pref_name, pref_value);
|
|
|
|
if ( changed_flags )
|
2017-11-28 16:03:11 -08:00
|
|
|
{
|
|
|
|
prefs_main_write();
|
|
|
|
prefs_apply_all();
|
|
|
|
prefs_to_capture_opts();
|
2018-01-05 23:39:55 -05:00
|
|
|
return changed_flags;
|
2017-11-28 16:03:11 -08:00
|
|
|
}
|
2016-01-21 13:41:42 +01:00
|
|
|
|
2018-01-05 23:39:55 -05:00
|
|
|
return 0;
|
2016-01-21 13:41:42 +01:00
|
|
|
}
|
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
bool
|
2016-01-21 13:41:42 +01:00
|
|
|
prefs_store_ext_multiple(const char * module, GHashTable * pref_values)
|
|
|
|
{
|
2024-03-29 18:08:09 -07:00
|
|
|
bool pref_changed = false;
|
2017-11-28 16:03:11 -08:00
|
|
|
GList * keys = NULL;
|
2016-01-21 13:41:42 +01:00
|
|
|
|
2021-12-30 16:03:15 +00:00
|
|
|
if ( !prefs_is_registered_protocol(module))
|
2017-11-28 16:03:11 -08:00
|
|
|
return pref_changed;
|
2016-01-21 13:41:42 +01:00
|
|
|
|
2017-11-28 16:03:11 -08:00
|
|
|
keys = g_hash_table_get_keys(pref_values);
|
2021-12-30 16:03:15 +00:00
|
|
|
if ( !keys )
|
2017-11-28 16:03:11 -08:00
|
|
|
return pref_changed;
|
2016-01-21 13:41:42 +01:00
|
|
|
|
2019-05-20 19:33:12 +02:00
|
|
|
for ( GList * key = keys; key != NULL; key = g_list_next(key) )
|
2016-01-21 13:41:42 +01:00
|
|
|
{
|
2024-03-29 18:08:09 -07:00
|
|
|
char * pref_name = (char *)key->data;
|
|
|
|
char * pref_value = (char *) g_hash_table_lookup(pref_values, key->data);
|
2017-11-28 16:03:11 -08:00
|
|
|
|
|
|
|
if ( pref_name && pref_value )
|
|
|
|
{
|
|
|
|
if ( prefs_store_ext_helper(module, pref_name, pref_value) )
|
2024-03-29 18:08:09 -07:00
|
|
|
pref_changed = true;
|
2017-11-28 16:03:11 -08:00
|
|
|
}
|
2016-01-21 13:41:42 +01:00
|
|
|
}
|
2019-05-20 19:33:12 +02:00
|
|
|
g_list_free(keys);
|
2016-01-21 13:41:42 +01:00
|
|
|
|
2017-11-28 16:03:11 -08:00
|
|
|
if ( pref_changed )
|
|
|
|
{
|
|
|
|
prefs_main_write();
|
|
|
|
prefs_apply_all();
|
|
|
|
prefs_to_capture_opts();
|
|
|
|
}
|
2015-06-05 11:19:37 +02:00
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
return true;
|
2015-06-05 11:19:37 +02:00
|
|
|
}
|
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
int
|
|
|
|
column_prefs_add_custom(int fmt, const char *title, const char *custom_fields, int position)
|
2013-01-23 19:04:36 +00:00
|
|
|
{
|
|
|
|
GList *clp;
|
|
|
|
fmt_data *cfmt, *last_cfmt;
|
2024-03-29 18:08:09 -07:00
|
|
|
int colnr;
|
2013-01-23 19:04:36 +00:00
|
|
|
|
2020-12-20 21:30:28 -05:00
|
|
|
cfmt = g_new(fmt_data, 1);
|
2013-01-23 19:04:36 +00:00
|
|
|
/*
|
|
|
|
* Because a single underscore is interpreted as a signal that the next character
|
|
|
|
* is going to be marked as accelerator for this header (i.e. is going to be
|
|
|
|
* shown underlined), escape it be inserting a second consecutive underscore.
|
|
|
|
*/
|
|
|
|
cfmt->title = g_strdup(title);
|
|
|
|
cfmt->fmt = fmt;
|
2015-12-11 09:34:08 +01:00
|
|
|
cfmt->custom_fields = g_strdup(custom_fields);
|
2019-06-27 22:00:11 +02:00
|
|
|
cfmt->custom_occurrence = 0;
|
2024-09-11 14:26:14 +02:00
|
|
|
if (column_prefs_custom_display_strings(custom_fields)) {
|
|
|
|
cfmt->display = COLUMN_DISPLAY_STRINGS;
|
|
|
|
} else {
|
|
|
|
cfmt->display = COLUMN_DISPLAY_VALUES;
|
|
|
|
}
|
2013-01-23 19:04:36 +00:00
|
|
|
|
2015-03-09 08:11:13 +01:00
|
|
|
colnr = g_list_length(prefs.col_list);
|
|
|
|
|
2015-12-11 09:34:08 +01:00
|
|
|
if (custom_fields) {
|
2024-03-29 18:08:09 -07:00
|
|
|
cfmt->visible = true;
|
2013-01-23 19:04:36 +00:00
|
|
|
clp = g_list_last(prefs.col_list);
|
|
|
|
last_cfmt = (fmt_data *) clp->data;
|
2019-06-27 21:51:49 +02:00
|
|
|
if (position > 0 && position <= colnr) {
|
2019-06-12 16:35:29 -07:00
|
|
|
/* Custom fields may be added at any position, depending on the given argument */
|
2024-02-08 20:21:28 -05:00
|
|
|
colnr = position;
|
|
|
|
prefs.col_list = g_list_insert(prefs.col_list, cfmt, colnr);
|
2019-06-12 16:35:29 -07:00
|
|
|
} else if (last_cfmt->fmt == COL_INFO) {
|
2013-01-23 19:04:36 +00:00
|
|
|
/* Last column is COL_INFO, add custom column before this */
|
2015-03-09 08:11:13 +01:00
|
|
|
colnr -= 1;
|
|
|
|
prefs.col_list = g_list_insert(prefs.col_list, cfmt, colnr);
|
2013-01-23 19:04:36 +00:00
|
|
|
} else {
|
|
|
|
prefs.col_list = g_list_append(prefs.col_list, cfmt);
|
|
|
|
}
|
|
|
|
} else {
|
2024-03-29 18:08:09 -07:00
|
|
|
cfmt->visible = false; /* Will be set to true in visible_toggled() when added to list */
|
2013-01-23 19:04:36 +00:00
|
|
|
prefs.col_list = g_list_append(prefs.col_list, cfmt);
|
|
|
|
}
|
2024-02-08 20:21:28 -05:00
|
|
|
recent_insert_column(colnr);
|
2015-03-09 08:11:13 +01:00
|
|
|
|
|
|
|
return colnr;
|
2013-01-23 19:04:36 +00:00
|
|
|
}
|
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
int
|
|
|
|
column_prefs_has_custom(const char *custom_field)
|
2020-07-14 19:04:00 +02:00
|
|
|
{
|
|
|
|
GList *clp;
|
|
|
|
fmt_data *cfmt;
|
2024-03-29 18:08:09 -07:00
|
|
|
int colnr = -1;
|
2020-07-14 19:04:00 +02:00
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
for (int i = 0; i < prefs.num_cols; i++) {
|
2020-07-14 19:04:00 +02:00
|
|
|
clp = g_list_nth(prefs.col_list, i);
|
|
|
|
if (clp == NULL) /* Sanity check, invalid column requested */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cfmt = (fmt_data *) clp->data;
|
2023-01-16 12:34:30 +01:00
|
|
|
if (cfmt->fmt == COL_CUSTOM && cfmt->custom_occurrence == 0 && strcmp(custom_field, cfmt->custom_fields) == 0) {
|
2020-07-14 19:04:00 +02:00
|
|
|
colnr = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return colnr;
|
|
|
|
}
|
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
bool
|
2024-09-11 14:26:14 +02:00
|
|
|
column_prefs_custom_display_strings(const char* custom_field)
|
2022-06-28 00:36:39 -04:00
|
|
|
{
|
2024-03-29 18:08:09 -07:00
|
|
|
char **fields;
|
2022-06-28 00:36:39 -04:00
|
|
|
header_field_info *hfi;
|
|
|
|
bool resolve = false;
|
|
|
|
|
|
|
|
fields = g_regex_split_simple(COL_CUSTOM_PRIME_REGEX, custom_field,
|
column: Update custom column regex
When splitting a possibly multifield custom column expression
into components, don't match "or" unless it's a word by itself,
i.e. is surrounded by space. "||" by itself is fine as a token.
This is necessary if we allow more complicated filters to match
than just single fields separated by "||" or "or". Also split
at space at the beginning or end of a string (since we don't
always guarantee that whitespace is stripped.)
When spliting into components, only split on "||" and " or " that
are not inside parenthesis. Splitting on operators inside parentheses
results in components which are not fields or valid filter expressions
and has never worked, e.g. splitting "(tcp.srcport or tcp.dstport)"
into "(tcp.srcport" and "tcp.dstport)".
TEST_OR has the lowest possible operator precedence (see
commit 34ad6bb47887fab144c8e2547dce58152111abb0), so this works,
and also justifies using OR instead of AND for multifield custom
columns.
This means that, e.g., "tcp.srcport or tcp.dstport" will be treated
as a multifield custom column expression that returns the values
for both of the fields, whereas "(tcp.srcport or tcp.dstport)" will
be ultimately treated as a single logical test that returns true
if one of the fields exist and false if neither do. Until tests
and other non single-field expressions are supported, the latter
won't work, but it never has worked.
Related to #7752, #10154, #15990, #18588, and #16181.
2024-02-07 20:01:53 -05:00
|
|
|
(GRegexCompileFlags) (G_REGEX_RAW),
|
|
|
|
0);
|
2022-06-28 00:36:39 -04:00
|
|
|
|
2024-03-29 18:08:09 -07:00
|
|
|
for (unsigned i = 0; i < g_strv_length(fields); i++) {
|
2022-06-28 00:36:39 -04:00
|
|
|
if (fields[i] && *fields[i]) {
|
|
|
|
hfi = proto_registrar_get_byname(fields[i]);
|
2024-09-11 14:26:14 +02:00
|
|
|
if (hfi && ((hfi->type == FT_OID) || (hfi->type == FT_REL_OID) || (hfi->type == FT_ETHER) || (hfi->type == FT_BYTES) || (hfi->type == FT_IPv4) || (hfi->type == FT_IPv6) || (hfi->type == FT_FCWWN) || (hfi->type == FT_BOOLEAN) ||
|
2022-06-28 00:36:39 -04:00
|
|
|
((hfi->strings != NULL) &&
|
2023-06-19 17:20:02 +01:00
|
|
|
(FT_IS_INT(hfi->type) || FT_IS_UINT(hfi->type)))))
|
2022-06-28 00:36:39 -04:00
|
|
|
{
|
2024-03-29 18:08:09 -07:00
|
|
|
resolve = true;
|
2022-06-28 00:36:39 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev(fields);
|
|
|
|
|
|
|
|
return resolve;
|
|
|
|
}
|
|
|
|
|
2024-09-11 14:26:14 +02:00
|
|
|
bool
|
|
|
|
column_prefs_custom_display_details(const char* custom_field)
|
|
|
|
{
|
|
|
|
char **fields;
|
|
|
|
header_field_info *hfi;
|
|
|
|
bool resolve = false;
|
|
|
|
|
|
|
|
fields = g_regex_split_simple(COL_CUSTOM_PRIME_REGEX, custom_field,
|
|
|
|
(GRegexCompileFlags) (G_REGEX_RAW),
|
|
|
|
0);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < g_strv_length(fields); i++) {
|
|
|
|
if (fields[i] && *fields[i]) {
|
|
|
|
hfi = proto_registrar_get_byname(fields[i]);
|
|
|
|
if (hfi && !(hfi->display & BASE_NO_DISPLAY_VALUE)) {
|
|
|
|
resolve = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev(fields);
|
|
|
|
|
|
|
|
return resolve;
|
|
|
|
}
|
|
|
|
|
2013-01-23 19:04:36 +00:00
|
|
|
void
|
|
|
|
column_prefs_remove_link(GList *col_link)
|
|
|
|
{
|
|
|
|
fmt_data *cfmt;
|
|
|
|
|
|
|
|
if (!col_link || !col_link->data) return;
|
2014-02-25 15:42:35 -05:00
|
|
|
|
2013-01-23 19:04:36 +00:00
|
|
|
cfmt = (fmt_data *) col_link->data;
|
|
|
|
|
|
|
|
g_free(cfmt->title);
|
2015-12-11 09:34:08 +01:00
|
|
|
g_free(cfmt->custom_fields);
|
2013-01-23 19:04:36 +00:00
|
|
|
g_free(cfmt);
|
|
|
|
prefs.col_list = g_list_remove_link(prefs.col_list, col_link);
|
2023-04-24 23:08:45 -04:00
|
|
|
g_list_free_1(col_link);
|
2013-01-23 19:04:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2024-03-29 18:08:09 -07:00
|
|
|
column_prefs_remove_nth(int col)
|
2013-01-23 19:04:36 +00:00
|
|
|
{
|
|
|
|
column_prefs_remove_link(g_list_nth(prefs.col_list, col));
|
2024-02-08 20:21:28 -05:00
|
|
|
recent_remove_column(col);
|
2013-01-23 19:04:36 +00:00
|
|
|
}
|
|
|
|
|
2024-03-30 10:28:47 -07:00
|
|
|
void save_migrated_uat(const char *uat_name, bool *old_pref)
|
2018-09-08 11:49:22 +02:00
|
|
|
{
|
|
|
|
char *err = NULL;
|
|
|
|
|
|
|
|
if (!uat_save(uat_get_table_by_name(uat_name), &err)) {
|
2021-06-15 00:06:02 +01:00
|
|
|
ws_warning("Unable to save %s: %s", uat_name, err);
|
2018-09-08 11:49:22 +02:00
|
|
|
g_free(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that any old preferences are removed after successful migration.
|
|
|
|
if (*old_pref) {
|
2024-03-29 18:08:09 -07:00
|
|
|
*old_pref = false;
|
2018-09-08 11:49:22 +02:00
|
|
|
prefs_main_write();
|
|
|
|
}
|
|
|
|
}
|