1 /* preference_utils.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 
13 #include <errno.h>
14 
15 #include <epan/column.h>
16 #include <wsutil/filesystem.h>
17 #include <wsutil/wslog.h>
18 #include <epan/prefs.h>
19 #include <epan/prefs-int.h>
20 #include <epan/packet.h>
21 #include <epan/decode_as.h>
22 #include <epan/uat-int.h>
23 #include <ui/recent.h>
24 
25 #ifdef HAVE_LIBPCAP
26 #include "capture_opts.h"
27 #include "ui/capture_globals.h"
28 #endif
29 
30 #include "ui/preference_utils.h"
31 #include "ui/simple_dialog.h"
32 
33 #ifdef HAVE_LIBPCAP
34 gboolean auto_scroll_live;
35 #endif
36 
37 /* Fill in capture options with values from the preferences */
38 void
prefs_to_capture_opts(void)39 prefs_to_capture_opts(void)
40 {
41 #ifdef HAVE_LIBPCAP
42     /* Set promiscuous mode from the preferences setting. */
43     /* the same applies to other preferences settings as well. */
44     global_capture_opts.default_options.promisc_mode = prefs.capture_prom_mode;
45     global_capture_opts.use_pcapng                   = prefs.capture_pcap_ng;
46     global_capture_opts.show_info                    = prefs.capture_show_info;
47     global_capture_opts.real_time_mode               = prefs.capture_real_time;
48     auto_scroll_live                                 = prefs.capture_auto_scroll;
49 #endif /* HAVE_LIBPCAP */
50 }
51 
52 void
prefs_main_write(void)53 prefs_main_write(void)
54 {
55     int   err;
56     char *pf_dir_path;
57     char *pf_path;
58 
59     /* Create the directory that holds personal configuration files, if
60        necessary.  */
61     if (create_persconffile_dir(&pf_dir_path) == -1) {
62         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
63                 "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
64                 g_strerror(errno));
65         g_free(pf_dir_path);
66     } else {
67         /* Write the preferences out. */
68         err = write_prefs(&pf_path);
69         if (err != 0) {
70             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
71                     "Can't open preferences file\n\"%s\": %s.", pf_path,
72                     g_strerror(err));
73             g_free(pf_path);
74         }
75         /* Write recent and recent_common files out to ensure sync with prefs. */
76         write_profile_recent();
77         write_recent();
78     }
79 }
80 
81 static unsigned int
prefs_store_ext_helper(const char * module_name,const char * pref_name,const char * pref_value)82 prefs_store_ext_helper(const char * module_name, const char *pref_name, const char *pref_value)
83 {
84     module_t * module = NULL;
85     pref_t * pref = NULL;
86     unsigned int pref_changed = 0;
87 
88     if ( ! prefs_is_registered_protocol(module_name))
89         return 0;
90 
91     module = prefs_find_module(module_name);
92     if ( ! module )
93         return 0;
94 
95     pref = prefs_find_preference(module, pref_name);
96 
97     if (!pref)
98         return 0;
99 
100     if (prefs_get_type(pref) == PREF_STRING )
101     {
102         pref_changed |= prefs_set_string_value(pref, pref_value, pref_stashed);
103         if ( ! pref_changed || prefs_get_string_value(pref, pref_stashed) != 0 )
104             pref_changed |= prefs_set_string_value(pref, pref_value, pref_current);
105     }
106 
107     return pref_changed;
108 }
109 
110 unsigned int
prefs_store_ext(const char * module_name,const char * pref_name,const char * pref_value)111 prefs_store_ext(const char * module_name, const char *pref_name, const char *pref_value)
112 {
113     unsigned int changed_flags = prefs_store_ext_helper(module_name, pref_name, pref_value);
114     if ( changed_flags )
115     {
116         prefs_main_write();
117         prefs_apply_all();
118         prefs_to_capture_opts();
119         return changed_flags;
120     }
121 
122     return 0;
123 }
124 
125 gboolean
prefs_store_ext_multiple(const char * module,GHashTable * pref_values)126 prefs_store_ext_multiple(const char * module, GHashTable * pref_values)
127 {
128     gboolean pref_changed = FALSE;
129     GList * keys = NULL;
130 
131     if ( ! prefs_is_registered_protocol(module))
132         return pref_changed;
133 
134     keys = g_hash_table_get_keys(pref_values);
135     if ( ! keys )
136         return pref_changed;
137 
138     for ( GList * key = keys; key != NULL; key = g_list_next(key) )
139     {
140         gchar * pref_name = (gchar *)key->data;
141         gchar * pref_value = (gchar *) g_hash_table_lookup(pref_values, key->data);
142 
143         if ( pref_name && pref_value )
144         {
145             if ( prefs_store_ext_helper(module, pref_name, pref_value) )
146                 pref_changed = TRUE;
147         }
148     }
149     g_list_free(keys);
150 
151     if ( pref_changed )
152     {
153         prefs_main_write();
154         prefs_apply_all();
155         prefs_to_capture_opts();
156     }
157 
158     return TRUE;
159 }
160 
161 gint
column_prefs_add_custom(gint fmt,const gchar * title,const gchar * custom_fields,gint position)162 column_prefs_add_custom(gint fmt, const gchar *title, const gchar *custom_fields, gint position)
163 {
164     GList *clp;
165     fmt_data *cfmt, *last_cfmt;
166     gint colnr;
167 
168     cfmt = g_new(fmt_data, 1);
169     /*
170      * Because a single underscore is interpreted as a signal that the next character
171      * is going to be marked as accelerator for this header (i.e. is going to be
172      * shown underlined), escape it be inserting a second consecutive underscore.
173      */
174     cfmt->title = g_strdup(title);
175     cfmt->fmt = fmt;
176     cfmt->custom_fields = g_strdup(custom_fields);
177     cfmt->custom_occurrence = 0;
178     cfmt->resolved = TRUE;
179 
180     colnr = g_list_length(prefs.col_list);
181 
182     if (custom_fields) {
183         cfmt->visible = TRUE;
184         clp = g_list_last(prefs.col_list);
185         last_cfmt = (fmt_data *) clp->data;
186         if (position > 0 && position <= colnr) {
187             /* Custom fields may be added at any position, depending on the given argument */
188             prefs.col_list = g_list_insert(prefs.col_list, cfmt, position);
189         } else if (last_cfmt->fmt == COL_INFO) {
190             /* Last column is COL_INFO, add custom column before this */
191             colnr -= 1;
192             prefs.col_list = g_list_insert(prefs.col_list, cfmt, colnr);
193         } else {
194             prefs.col_list = g_list_append(prefs.col_list, cfmt);
195         }
196     } else {
197         cfmt->visible = FALSE;  /* Will be set to TRUE in visible_toggled() when added to list */
198         prefs.col_list = g_list_append(prefs.col_list, cfmt);
199     }
200 
201     return colnr;
202 }
203 
204 gint
column_prefs_has_custom(const gchar * custom_field)205 column_prefs_has_custom(const gchar *custom_field)
206 {
207     GList *clp;
208     fmt_data *cfmt;
209     gint colnr = -1;
210 
211     for (gint i = 0; i < prefs.num_cols; i++) {
212         clp = g_list_nth(prefs.col_list, i);
213         if (clp == NULL) /* Sanity check, invalid column requested */
214             continue;
215 
216         cfmt = (fmt_data *) clp->data;
217         if (cfmt->fmt == COL_CUSTOM && strcmp(custom_field, cfmt->custom_fields) == 0) {
218             colnr = i;
219             break;
220         }
221     }
222 
223     return colnr;
224 }
225 
226 void
column_prefs_remove_link(GList * col_link)227 column_prefs_remove_link(GList *col_link)
228 {
229     fmt_data *cfmt;
230 
231     if (!col_link || !col_link->data) return;
232 
233     cfmt = (fmt_data *) col_link->data;
234 
235     g_free(cfmt->title);
236     g_free(cfmt->custom_fields);
237     g_free(cfmt);
238     prefs.col_list = g_list_remove_link(prefs.col_list, col_link);
239 }
240 
241 void
column_prefs_remove_nth(gint col)242 column_prefs_remove_nth(gint col)
243 {
244     column_prefs_remove_link(g_list_nth(prefs.col_list, col));
245 }
246 
save_migrated_uat(const char * uat_name,gboolean * old_pref)247 void save_migrated_uat(const char *uat_name, gboolean *old_pref)
248 {
249     char *err = NULL;
250 
251     if (!uat_save(uat_get_table_by_name(uat_name), &err)) {
252         ws_warning("Unable to save %s: %s", uat_name, err);
253         g_free(err);
254         return;
255     }
256 
257     // Ensure that any old preferences are removed after successful migration.
258     if (*old_pref) {
259         *old_pref = FALSE;
260         prefs_main_write();
261     }
262 }
263