Bug Summary

File:ui/recent.c
Warning:line 1748, column 13
Null pointer passed to 1st parameter expecting 'nonnull'

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 recent.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-19/lib/clang/19 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/ui -I /builds/wireshark/wireshark/build/ui -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-19/lib/clang/19/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-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -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/2025-07-07-100249-3847-1 -x c /builds/wireshark/wireshark/ui/recent.c
1/* recent.c
2 * Recent "preference" handling routines
3 * Copyright 2004, Ulf Lamping <ulf.lamping@web.de>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include "config.h"
13
14#include <wireshark.h>
15
16#include <stdlib.h>
17#include <errno(*__errno_location ()).h>
18
19#include <wsutil/application_flavor.h>
20#include <wsutil/filesystem.h>
21#include <epan/prefs.h>
22#include <epan/prefs-int.h>
23#include <epan/column.h>
24#include <epan/value_string.h>
25
26#ifdef HAVE_PCAP_REMOTE
27#include "ui/capture_opts.h"
28#endif
29#include "ui/util.h"
30#include "ui/recent.h"
31#include "ui/recent_utils.h"
32#include "ui/packet_list_utils.h"
33#include "ui/simple_dialog.h"
34
35#include <wsutil/file_util.h>
36#include <wsutil/strtoi.h>
37
38#define RECENT_KEY_MAIN_TOOLBAR_SHOW"gui.toolbar_main_show" "gui.toolbar_main_show"
39#define RECENT_KEY_FILTER_TOOLBAR_SHOW"gui.filter_toolbar_show" "gui.filter_toolbar_show"
40#define RECENT_KEY_WIRELESS_TOOLBAR_SHOW"gui.wireless_toolbar_show" "gui.wireless_toolbar_show"
41#define RECENT_KEY_PACKET_LIST_SHOW"gui.packet_list_show" "gui.packet_list_show"
42#define RECENT_KEY_TREE_VIEW_SHOW"gui.tree_view_show" "gui.tree_view_show"
43#define RECENT_KEY_BYTE_VIEW_SHOW"gui.byte_view_show" "gui.byte_view_show"
44#define RECENT_KEY_PACKET_DIAGRAM_SHOW"gui.packet_diagram_show" "gui.packet_diagram_show"
45#define RECENT_KEY_STATUSBAR_SHOW"gui.statusbar_show" "gui.statusbar_show"
46#define RECENT_KEY_PACKET_LIST_COLORIZE"gui.packet_list_colorize" "gui.packet_list_colorize"
47#define RECENT_KEY_CAPTURE_AUTO_SCROLL"capture.auto_scroll" "capture.auto_scroll"
48#define RECENT_GUI_TIME_FORMAT"gui.time_format" "gui.time_format"
49#define RECENT_GUI_TIME_PRECISION"gui.time_precision" "gui.time_precision"
50#define RECENT_GUI_SECONDS_FORMAT"gui.seconds_format" "gui.seconds_format"
51#define RECENT_GUI_ZOOM_LEVEL"gui.zoom_level" "gui.zoom_level"
52#define RECENT_GUI_BYTES_VIEW"gui.bytes_view" "gui.bytes_view"
53#define RECENT_GUI_BYTES_ENCODING"gui.bytes_encoding" "gui.bytes_encoding"
54#define RECENT_GUI_ALLOW_HOVER_SELECTION"gui.allow_hover_selection" "gui.allow_hover_selection"
55#define RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES"gui.packet_diagram_field_values" "gui.packet_diagram_field_values"
56#define RECENT_GUI_GEOMETRY_MAIN_X"gui.geometry_main_x" "gui.geometry_main_x"
57#define RECENT_GUI_GEOMETRY_MAIN_Y"gui.geometry_main_y" "gui.geometry_main_y"
58#define RECENT_GUI_GEOMETRY_MAIN_WIDTH"gui.geometry_main_width" "gui.geometry_main_width"
59#define RECENT_GUI_GEOMETRY_MAIN_HEIGHT"gui.geometry_main_height" "gui.geometry_main_height"
60#define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED"gui.geometry_main_maximized" "gui.geometry_main_maximized"
61#define RECENT_GUI_GEOMETRY_MAIN"gui.geometry_main" "gui.geometry_main"
62#define RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS"gui.geometry_leftalign_actions" "gui.geometry_leftalign_actions"
63#define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE"gui.geometry_main_upper_pane" "gui.geometry_main_upper_pane"
64#define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE"gui.geometry_main_lower_pane" "gui.geometry_main_lower_pane"
65#define RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT"gui.geometry_main_master_split" "gui.geometry_main_master_split"
66#define RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT"gui.geometry_main_extra_split" "gui.geometry_main_extra_split"
67#define RECENT_LAST_USED_PROFILE"gui.last_used_profile" "gui.last_used_profile"
68#define RECENT_PROFILE_SWITCH_CHECK_COUNT"gui.profile_switch_check_count" "gui.profile_switch_check_count"
69#define RECENT_GUI_FILEOPEN_REMEMBERED_DIR"gui.fileopen_remembered_dir" "gui.fileopen_remembered_dir"
70#define RECENT_GUI_CONVERSATION_TABS"gui.conversation_tabs" "gui.conversation_tabs"
71#define RECENT_GUI_CONVERSATION_TABS_COLUMNS"gui.conversation_tabs_columns" "gui.conversation_tabs_columns"
72#define RECENT_GUI_ENDPOINT_TABS"gui.endpoint_tabs" "gui.endpoint_tabs"
73#define RECENT_GUI_ENDPOINT_TABS_COLUMNS"gui.endpoint_tabs_columns" "gui.endpoint_tabs_columns"
74#define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES"gui.rlc_pdus_from_mac_frames" "gui.rlc_pdus_from_mac_frames"
75#define RECENT_GUI_CUSTOM_COLORS"gui.custom_colors" "gui.custom_colors"
76#define RECENT_GUI_TOOLBAR_SHOW"gui.additional_toolbar_show" "gui.additional_toolbar_show"
77#define RECENT_GUI_INTERFACE_TOOLBAR_SHOW"gui.interface_toolbar_show" "gui.interface_toolbar_show"
78#define RECENT_GUI_SEARCH_IN"gui.search_in" "gui.search_in"
79#define RECENT_GUI_SEARCH_CHAR_SET"gui.search_char_set" "gui.search_char_set"
80#define RECENT_GUI_SEARCH_CASE_SENSITIVE"gui.search_case_sensitive" "gui.search_case_sensitive"
81#define RECENT_GUI_SEARCH_REVERSE_DIR"gui.search_reverse_dir" "gui.search_reverse_dir"
82#define RECENT_GUI_SEARCH_MULTIPLE_OCCURS"gui.search_multiple_occurs" "gui.search_multiple_occurs"
83#define RECENT_GUI_SEARCH_TYPE"gui.search_type" "gui.search_type"
84#define RECENT_GUI_FOLLOW_SHOW"gui.follow_show" "gui.follow_show"
85#define RECENT_GUI_FOLLOW_DELTA"gui.follow_delta" "gui.follow_delta"
86#define RECENT_GUI_SHOW_BYTES_DECODE"gui.show_bytes_decode" "gui.show_bytes_decode"
87#define RECENT_GUI_SHOW_BYTES_SHOW"gui.show_bytes_show" "gui.show_bytes_show"
88#define RECENT_GUI_TSD_MA_WINDOW_SIZE"gui.tsd_ma_window_size" "gui.tsd_ma_window_size"
89#define RECENT_GUI_TSD_THROUGHPUT_SHOW"gui.tsd_throughput_show" "gui.tsd_throughput_show"
90#define RECENT_GUI_TSD_GOODPUT_SHOW"gui.tsd_goodput_show" "gui.tsd_goodput_show"
91
92#define RECENT_GUI_GEOMETRY"gui.geom." "gui.geom."
93
94#define RECENT_KEY_PRIVS_WARN_IF_ELEVATED"privs.warn_if_elevated" "privs.warn_if_elevated"
95#define RECENT_KEY_SYS_WARN_IF_NO_CAPTURE"sys.warn_if_no_capture" "sys.warn_if_no_capture"
96
97#define RECENT_FILE_NAME"recent" "recent"
98#define RECENT_COMMON_FILE_NAME"recent_common" "recent_common"
99
100recent_settings_t recent;
101
102static const value_string ts_type_values[] = {
103 { TS_RELATIVE, "RELATIVE" },
104 { TS_ABSOLUTE, "ABSOLUTE" },
105 { TS_ABSOLUTE_WITH_YMD, "ABSOLUTE_WITH_YMD" },
106 { TS_ABSOLUTE_WITH_YDOY, "ABSOLUTE_WITH_YDOY" },
107 { TS_ABSOLUTE_WITH_YMD, "ABSOLUTE_WITH_DATE" }, /* Backward compatibility */
108 { TS_DELTA, "DELTA" },
109 { TS_DELTA_DIS, "DELTA_DIS" },
110 { TS_EPOCH, "EPOCH" },
111 { TS_UTC, "UTC" },
112 { TS_UTC_WITH_YMD, "UTC_WITH_YMD" },
113 { TS_UTC_WITH_YDOY, "UTC_WITH_YDOY" },
114 { TS_UTC_WITH_YMD, "UTC_WITH_DATE" }, /* Backward compatibility */
115 { 0, NULL((void*)0) }
116};
117
118/*
119 * NOTE: all values other than TS_PREC_AUTO are the number of digits
120 * of precision.
121 *
122 * We continue to use the old names for values where they may have
123 * been written to the recent file by previous releases. For other
124 * values, we just write it out numerically.
125 */
126static const value_string ts_precision_values[] = {
127 { TS_PREC_AUTO, "AUTO" },
128 { TS_PREC_FIXED_SEC, "SEC" },
129 { TS_PREC_FIXED_100_MSEC, "DSEC" },
130 { TS_PREC_FIXED_10_MSEC, "CSEC" },
131 { TS_PREC_FIXED_MSEC, "MSEC" },
132 { TS_PREC_FIXED_USEC, "USEC" },
133 { TS_PREC_FIXED_NSEC, "NSEC" },
134 { 0, NULL((void*)0) }
135};
136
137static const value_string ts_seconds_values[] = {
138 { TS_SECONDS_DEFAULT, "SECONDS" },
139 { TS_SECONDS_HOUR_MIN_SEC, "HOUR_MIN_SEC" },
140 { 0, NULL((void*)0) }
141};
142
143static const value_string bytes_view_type_values[] = {
144 { BYTES_HEX, "HEX" },
145 { BYTES_BITS, "BITS" },
146 { BYTES_DEC, "DEC" },
147 { BYTES_OCT, "OCT" },
148 { 0, NULL((void*)0) }
149};
150
151static const value_string bytes_encoding_type_values[] = {
152 { BYTES_ENC_FROM_PACKET, "FROM_PACKET" },
153 { BYTES_ENC_ASCII, "ASCII" },
154 { BYTES_ENC_EBCDIC, "EBCDIC" },
155 { 0, NULL((void*)0) }
156};
157
158static const value_string search_in_values[] = {
159 { SEARCH_IN_PACKET_LIST, "PACKET_LIST" },
160 { SEARCH_IN_PACKET_DETAILS, "PACKET_DETAILS" },
161 { SEARCH_IN_PACKET_BYTES, "PACKET_BYTES" },
162 { 0, NULL((void*)0) }
163};
164
165static const value_string search_char_set_values[] = {
166 { SEARCH_CHAR_SET_NARROW_AND_WIDE, "NARROW_AND_WIDE" },
167 { SEARCH_CHAR_SET_NARROW, "NARROW" },
168 { SEARCH_CHAR_SET_WIDE, "WIDE" },
169 { 0, NULL((void*)0) }
170};
171
172static const value_string search_type_values[] = {
173 { SEARCH_TYPE_DISPLAY_FILTER, "DISPLAY_FILTER" },
174 { SEARCH_TYPE_HEX_VALUE, "HEX_VALUE" },
175 { SEARCH_TYPE_STRING, "STRING" },
176 { SEARCH_TYPE_REGEX, "REGEX" },
177 { 0, NULL((void*)0) }
178};
179
180static const value_string bytes_show_values[] = {
181 { SHOW_ASCII, "ASCII" },
182 { SHOW_ASCII_CONTROL, "ASCII_CONTROL" },
183 { SHOW_CARRAY, "C_ARRAYS" },
184 { SHOW_EBCDIC, "EBCDIC" },
185 { SHOW_HEXDUMP, "HEX_DUMP" },
186 { SHOW_HTML, "HTML" },
187 { SHOW_IMAGE, "IMAGE" },
188 { SHOW_JSON, "JSON" },
189 { SHOW_RAW, "RAW" },
190 { SHOW_RUSTARRAY, "RUST_ARRAY" },
191 { SHOW_CODEC, "UTF-8" },
192 // Other codecs are generated at runtime
193 { SHOW_YAML, "YAML"},
194 { 0, NULL((void*)0) }
195};
196
197static const value_string follow_delta_values[] = {
198 { FOLLOW_DELTA_NONE, "NONE" },
199 { FOLLOW_DELTA_TURN, "TURN" },
200 { FOLLOW_DELTA_ALL, "ALL" },
201 { 0, NULL((void*)0) }
202};
203
204static const value_string show_bytes_decode_values[] = {
205 { DecodeAsNone, "NONE" },
206 { DecodeAsBASE64, "BASE64" },
207 { DecodeAsCompressed, "COMPRESSED" },
208 { DecodeAsHexDigits, "HEX_DIGITS" },
209 { DecodeAsPercentEncoding, "PERCENT_ENCODING" },
210 { DecodeAsQuotedPrintable, "QUOTED_PRINTABLE" },
211 { DecodeAsROT13, "ROT13"},
212 { 0, NULL((void*)0) }
213};
214
215static void
216free_col_width_data(void *data)
217{
218 col_width_data *cfmt = (col_width_data *)data;
219 g_free(cfmt);
220}
221
222void
223recent_free_column_width_info(recent_settings_t *rs)
224{
225 g_list_free_full(rs->col_width_list, free_col_width_data);
226 rs->col_width_list = NULL((void*)0);
227}
228
229/** Write the geometry values of a single window to the recent file.
230 *
231 * @param key unused
232 * @param value the geometry values
233 * @param rfh recent file handle (FILE)
234 */
235static void
236write_recent_geom(void *key _U___attribute__((unused)), void *value, void *rfh)
237{
238 window_geometry_t *geom = (window_geometry_t *)value;
239 FILE *rf = (FILE *)rfh;
240
241 fprintf(rf, "\n# Geometry and maximized state of %s window.\n", geom->key);
242 fprintf(rf, "# Decimal integers.\n");
243 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.x: %d\n", geom->key, geom->x);
244 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.y: %d\n", geom->key, geom->y);
245 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.width: %d\n", geom->key,
246 geom->width);
247 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.height: %d\n", geom->key,
248 geom->height);
249
250 fprintf(rf, "# true or false (case-insensitive).\n");
251 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.maximized: %s\n", geom->key,
252 geom->maximized == true1 ? "true" : "false");
253
254 fprintf(rf, "# Qt Geometry State (hex byte string).\n");
255 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.qt_geometry: %s\n", geom->key,
256 geom->qt_geom);
257}
258
259/* the geometry hashtable for all known window classes,
260 * the window name is the key, and the geometry struct is the value */
261static GHashTable *window_geom_hash;
262
263static GHashTable *window_splitter_hash;
264
265void
266window_geom_free(void *data)
267{
268 window_geometry_t *geom = (window_geometry_t*)data;
269 g_free(geom->key);
270 g_free(geom->qt_geom);
271 g_free(geom);
272}
273
274/* save the window and its current geometry into the geometry hashtable */
275void
276window_geom_save(const char *name, window_geometry_t *geom)
277{
278 char *key;
279 window_geometry_t *work;
280
281 /* init hashtable, if not already done */
282 if (!window_geom_hash) {
283 window_geom_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL((void*)0), window_geom_free);
284 }
285
286 /* g_malloc and insert the new one */
287 work = g_new(window_geometry_t, 1)((window_geometry_t *) g_malloc_n ((1), sizeof (window_geometry_t
)))
;
288 *work = *geom;
289 key = g_strdup(name)g_strdup_inline (name);
290 work->key = key;
291 g_hash_table_replace(window_geom_hash, key, work);
292}
293
294/* load the desired geometry for this window from the geometry hashtable */
295bool_Bool
296window_geom_load(const char *name,
297 window_geometry_t *geom)
298{
299 window_geometry_t *p;
300
301 /* init hashtable, if not already done */
302 if (!window_geom_hash) {
303 window_geom_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL((void*)0), window_geom_free);
304 }
305
306 p = (window_geometry_t *)g_hash_table_lookup(window_geom_hash, name);
307 if (p) {
308 *geom = *p;
309 return true1;
310 } else {
311 return false0;
312 }
313}
314
315/* save the window and its splitter state into the splitter hashtable */
316void
317window_splitter_save(const char *name, const char *splitter_state)
318{
319 /* init hashtable, if not already done */
320 if (!window_splitter_hash) {
321 window_splitter_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
322 }
323
324 g_hash_table_replace(window_splitter_hash, g_strdup(name)g_strdup_inline (name), g_strdup(splitter_state)g_strdup_inline (splitter_state));
325}
326
327/* save the window and its splitter state into the geometry hashtable */
328const char*
329window_splitter_load(const char *name)
330{
331 /* init hashtable, if not already done */
332 if (!window_splitter_hash) {
333 return NULL((void*)0);
334 }
335
336 return g_hash_table_lookup(window_splitter_hash, name);
337}
338
339
340/* parse values of particular types */
341static void
342parse_recent_boolean(const char *val_str, bool_Bool *valuep)
343{
344 if (g_ascii_strcasecmp(val_str, "true") == 0) {
345 *valuep = true1;
346 }
347 else {
348 *valuep = false0;
349 }
350}
351
352/** Read in a single geometry key value pair from the recent file.
353 *
354 * @param name the geom_name of the window
355 * @param key the subkey of this pair (e.g. "x")
356 * @param value the new value (e.g. "123")
357 */
358static void
359window_geom_recent_read_pair(const char *name,
360 const char *key,
361 const char *value)
362{
363 window_geometry_t geom;
364
365 if (strcmp(key, "splitter") == 0) {
366 window_splitter_save(name, value);
367 return;
368 }
369
370 /* find window geometry maybe already in hashtable */
371 if (!window_geom_load(name, &geom)) {
372 /* not in table, init geom with "basic" values */
373 geom.key = NULL((void*)0); /* Will be set in window_geom_save() */
374 geom.set_pos = false0;
375 geom.x = -1;
376 geom.y = -1;
377 geom.set_size = false0;
378 geom.width = -1;
379 geom.height = -1;
380 geom.qt_geom = NULL((void*)0);
381 }
382
383 if (strcmp(key, "x") == 0) {
384 geom.x = (int)strtol(value, NULL((void*)0), 10);
385 geom.set_pos = true1;
386 } else if (strcmp(key, "y") == 0) {
387 geom.y = (int)strtol(value, NULL((void*)0), 10);
388 geom.set_pos = true1;
389 } else if (strcmp(key, "width") == 0) {
390 geom.width = (int)strtol(value, NULL((void*)0), 10);
391 geom.set_size = true1;
392 } else if (strcmp(key, "height") == 0) {
393 geom.height = (int)strtol(value, NULL((void*)0), 10);
394 geom.set_size = true1;
395 } else if (strcmp(key, "maximized") == 0) {
396 parse_recent_boolean(value, &geom.maximized);
397 geom.set_maximized = true1;
398 } else if (strcmp(key, "qt_geometry") == 0) {
399 geom.qt_geom = g_strdup(value)g_strdup_inline (value);
400 } else {
401 /*
402 * Silently ignore the bogus key. We shouldn't abort here,
403 * as this could be due to a corrupt recent file.
404 *
405 * XXX - should we print a message about this?
406 */
407 return;
408 }
409
410 /* save / replace geometry in hashtable */
411 window_geom_save(name, &geom);
412}
413
414/** Write all geometry values of all windows to the recent file.
415 * Will call write_recent_geom() for every existing window type.
416 *
417 * @param rf recent file handle from caller
418 */
419static void
420window_geom_recent_write_all(FILE *rf)
421{
422 /* init hashtable, if not already done */
423 if (!window_geom_hash) {
424 window_geom_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL((void*)0), window_geom_free);
425 }
426
427 g_hash_table_foreach(window_geom_hash, write_recent_geom, rf);
428}
429
430/** Write all known window splitter states to the recent file.
431 *
432 * @param rf recent file handle from caller
433 */
434static void
435window_splitter_recent_write_all(FILE *rf)
436{
437 /* init hashtable, if not already done */
438 if (!window_splitter_hash) {
439 return;
440 }
441
442 GHashTableIter iter;
443 void *key, *value;
444 g_hash_table_iter_init(&iter, window_splitter_hash);
445 while (g_hash_table_iter_next(&iter, &key, &value)) {
446 fprintf(rf, "\n# Splitter state of %s window.\n", (char*)key);
447 fprintf(rf, "# Qt Splitter state (hex byte string).\n");
448 fprintf(rf, RECENT_GUI_GEOMETRY"gui.geom." "%s.splitter: %s\n", (char*)key,
449 (char*)value);
450 }
451}
452
453/* Global list of recent capture filters. */
454static GList *recent_cfilter_list;
455
456/*
457 * Per-interface lists of recent capture filters; stored in a hash
458 * table indexed by interface name.
459 */
460static GHashTable *per_interface_cfilter_lists_hash;
461
462/* XXX: use a preference for this setting! */
463/* N.B.: If we use a pref, we will read the recent_common file
464 * before the pref, so don't truncate the list when reading
465 * (see the similar #16782 for the recent files.)
466 */
467static unsigned cfilter_combo_max_recent = 20;
468
469/**
470 * Returns a list of recent capture filters.
471 *
472 * @param ifname interface name; NULL refers to the global list.
473 */
474GList *
475recent_get_cfilter_list(const char *ifname)
476{
477 if (ifname == NULL((void*)0))
478 return recent_cfilter_list;
479 if (per_interface_cfilter_lists_hash == NULL((void*)0)) {
480 /* No such lists exist. */
481 return NULL((void*)0);
482 }
483 return (GList *)g_hash_table_lookup(per_interface_cfilter_lists_hash, ifname);
484}
485
486/**
487 * Add a capture filter to the global recent capture filter list or
488 * the recent capture filter list for an interface.
489 *
490 * @param ifname interface name; NULL refers to the global list.
491 * @param s text of capture filter
492 */
493void
494recent_add_cfilter(const char *ifname, const char *s)
495{
496 GList *cfilter_list;
497 GList *li;
498 char *li_filter, *newfilter = NULL((void*)0);
499
500 /* Don't add empty filters to the list. */
501 if (s[0] == '\0')
502 return;
503
504 if (ifname == NULL((void*)0))
505 cfilter_list = recent_cfilter_list;
506 else {
507 /* If we don't yet have a hash table for per-interface recent
508 capture filter lists, create one. Have it free the new key
509 if we're updating an entry rather than creating it below. */
510 if (per_interface_cfilter_lists_hash == NULL((void*)0))
511 per_interface_cfilter_lists_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL((void*)0));
512 cfilter_list = (GList *)g_hash_table_lookup(per_interface_cfilter_lists_hash, ifname);
513 }
514
515 li = g_list_first(cfilter_list);
516 while (li) {
517 /* If the filter is already in the list, remove the old one and
518 * append the new one at the latest position (at g_list_append() below) */
519 li_filter = (char *)li->data;
520 if (strcmp(s, li_filter) == 0) {
521 /* No need to copy the string, we're just moving it. */
522 newfilter = li_filter;
523 cfilter_list = g_list_remove(cfilter_list, li->data);
524 break;
525 }
526 li = li->next;
527 }
528 if (newfilter == NULL((void*)0)) {
529 /* The filter wasn't already in the list; make a copy to add. */
530 newfilter = g_strdup(s)g_strdup_inline (s);
531 }
532 cfilter_list = g_list_prepend(cfilter_list, newfilter);
533
534 if (ifname == NULL((void*)0))
535 recent_cfilter_list = cfilter_list;
536 else
537 g_hash_table_insert(per_interface_cfilter_lists_hash, g_strdup(ifname)g_strdup_inline (ifname), cfilter_list);
538}
539
540#ifdef HAVE_PCAP_REMOTE
541/* XXX: use a preference for this setting! */
542/* N.B.: If we use a pref, we will read the recent_common file
543 * before the pref, so don't truncate the list when reading
544 * (see the similar #16782 for the recent files.)
545 */
546static unsigned remote_host_max_recent = 20;
547static GList *remote_host_list;
548
549int recent_get_remote_host_list_size(void)
550{
551 if (remote_host_list == NULL((void*)0)) {
552 /* No entries exist. */
553 return 0;
554 }
555 return g_list_length(remote_host_list);
556}
557
558static void
559free_remote_host(void *value)
560{
561 struct remote_host* rh = (struct remote_host*)value;
562
563 g_free(rh->r_host);
564 g_free(rh->remote_port);
565 g_free(rh->auth_username);
566 g_free(rh->auth_password);
567
568}
569
570static int
571remote_host_compare(const void *a, const void *b)
572{
573 const struct remote_host* rh_a = (const struct remote_host*)a;
574 const struct remote_host* rh_b = (const struct remote_host*)b;
575
576 /* We assume only one entry per host (the GUI assumes that too.) */
577 return g_strcmp0(rh_a->r_host, rh_b->r_host);
578}
579
580static void
581remote_host_reverse(void)
582{
583 if (remote_host_list) {
584 remote_host_list = g_list_reverse(remote_host_list);
585 }
586}
587
588void recent_add_remote_host(char *host _U___attribute__((unused)), struct remote_host *rh)
589{
590 GList* li = NULL((void*)0);
591 if (remote_host_list) {
592 li = g_list_find_custom(remote_host_list, rh, remote_host_compare);
593 if (li != NULL((void*)0)) {
594 free_remote_host(li->data);
595 remote_host_list = g_list_delete_link(remote_host_list, li);
596 }
597 }
598 remote_host_list = g_list_prepend(remote_host_list, rh);
599}
600
601void
602recent_remote_host_list_foreach(GFunc func, void *user_data)
603{
604 if (remote_host_list != NULL((void*)0)) {
605 g_list_foreach(remote_host_list, func, user_data);
606 }
607}
608
609static void
610recent_print_remote_host(void *value, void *user)
611{
612 FILE *rf = (FILE *)user;
613 struct remote_host_info *ri = (struct remote_host_info *)value;
614
615 fprintf (rf, RECENT_KEY_REMOTE_HOST"recent.remote_host" ": %s,%s,%d\n", ri->remote_host, ri->remote_port, ri->auth_type);
616}
617
618/**
619 * Write the contents of the remote_host_list to the 'recent' file.
620 *
621 * @param rf File to write to.
622 */
623static void
624capture_remote_combo_recent_write_all(FILE *rf)
625{
626 unsigned max_count = 0;
627 GList *li = g_list_first(remote_host_list);
628
629 /* write all non empty remote capture hosts to the recent file (until max count) */
630 while (li && (max_count++ <= remote_host_max_recent)) {
631 recent_print_remote_host(li->data, rf);
632 li = li->next;
633 }
634}
635
636
637void recent_free_remote_host_list(void)
638{
639 g_list_free_full(remote_host_list, free_remote_host);
640 remote_host_list = NULL((void*)0);
641}
642
643struct remote_host *
644recent_get_remote_host(const char *host)
645{
646 if (host == NULL((void*)0))
647 return NULL((void*)0);
648 for (GList* li = g_list_first(remote_host_list); li != NULL((void*)0); li = li->next) {
649 struct remote_host *rh = (struct remote_host*)li->data;
650 if (g_strcmp0(host, rh->r_host) == 0) {
651 return rh;
652 }
653 }
654 return NULL((void*)0);
655}
656
657/**
658 * Fill the remote_host_list with the entries stored in the 'recent' file.
659 *
660 * @param s String to be filled from the 'recent' file.
661 * @return True, if the list was written successfully, False otherwise.
662 */
663static bool_Bool
664capture_remote_combo_add_recent(const char *s)
665{
666 GList *vals = prefs_get_string_list (s);
667 GList *valp = vals;
668 capture_auth auth_type;
669 char *p;
670 struct remote_host *rh;
671
672 if (valp == NULL((void*)0))
673 return false0;
674
675 /* First value is the host */
676 if (recent_get_remote_host(valp->data)) {
677 /* Don't add it, it's already in the list (shouldn't happen). */
678 return false0; // Should this be true or false?
679 }
680 rh = (struct remote_host *) g_malloc (sizeof (*rh));
681
682 /* First value is the host */
683 rh->r_host = (char *)g_strdup ((const char *)valp->data)g_strdup_inline ((const char *)valp->data);
684 if (strlen(rh->r_host) == 0) {
685 /* Empty remote host */
686 g_free(rh->r_host);
687 g_free(rh);
688 return false0;
689 }
690 rh->auth_type = CAPTURE_AUTH_NULL;
691 valp = valp->next;
692
693 if (valp) {
694 /* Found value 2, this is the port number */
695 if (!strcmp((const char*)valp->data, "0")) {
696 /* Port 0 isn't valid, so leave port blank */
697 rh->remote_port = (char *)g_strdup ("")g_strdup_inline ("");
698 } else {
699 rh->remote_port = (char *)g_strdup ((const char *)valp->data)g_strdup_inline ((const char *)valp->data);
700 }
701 valp = valp->next;
702 } else {
703 /* Did not find a port number */
704 rh->remote_port = g_strdup ("")g_strdup_inline ("");
705 }
706
707 if (valp) {
708 /* Found value 3, this is the authentication type */
709 auth_type = (capture_auth)strtol((const char *)valp->data, &p, 0);
710 if (p != valp->data && *p == '\0') {
711 rh->auth_type = auth_type;
712 }
713 }
714
715 /* Do not store username and password */
716 rh->auth_username = g_strdup ("")g_strdup_inline ("");
717 rh->auth_password = g_strdup ("")g_strdup_inline ("");
718
719 prefs_clear_string_list(vals);
720
721 remote_host_list = g_list_prepend(remote_host_list, rh);
722 return true1;
723}
724#endif
725
726static void
727cfilter_recent_write_all_list(FILE *rf, const char *ifname, GList *cfilter_list)
728{
729 unsigned max_count = 0;
730 GList *li;
731
732 /* write all non empty capture filter strings to the recent file (until max count) */
733 li = g_list_first(cfilter_list);
734 while (li && (max_count++ <= cfilter_combo_max_recent) ) {
735 if (li->data && strlen((const char *)li->data)) {
736 if (ifname == NULL((void*)0))
737 fprintf (rf, RECENT_KEY_CAPTURE_FILTER"recent.capture_filter" ": %s\n", (char *)li->data);
738 else
739 fprintf (rf, RECENT_KEY_CAPTURE_FILTER"recent.capture_filter" ".%s: %s\n", ifname, (char *)li->data);
740 }
741 li = li->next;
742 }
743}
744
745static void
746cfilter_recent_write_all_hash_callback(void *key, void *value, void *user_data)
747{
748 cfilter_recent_write_all_list((FILE *)user_data, (const char *)key, (GList *)value);
749}
750
751/** Write all capture filter values to the recent file.
752 *
753 * @param rf recent file handle from caller
754 */
755static void
756cfilter_recent_write_all(FILE *rf)
757{
758 /* Write out the global list. */
759 cfilter_recent_write_all_list(rf, NULL((void*)0), recent_cfilter_list);
760
761 /* Write out all the per-interface lists. */
762 if (per_interface_cfilter_lists_hash != NULL((void*)0)) {
763 g_hash_table_foreach(per_interface_cfilter_lists_hash, cfilter_recent_write_all_hash_callback, (void *)rf);
764 }
765}
766
767/** Reverse the order of all the capture filter lists after
768 * reading recent_common (we want the latest first).
769 * Note this is O(N), whereas appendng N items to a GList is O(N^2),
770 * since it doesn't have a pointer to the end like a GQueue.
771 */
772static void
773cfilter_recent_reverse_all(void)
774{
775 recent_cfilter_list = g_list_reverse(recent_cfilter_list);
776
777 /* Reverse all the per-interface lists. */
778 if (per_interface_cfilter_lists_hash != NULL((void*)0)) {
779 GHashTableIter iter;
780 void *key, *value;
781 g_hash_table_iter_init(&iter, per_interface_cfilter_lists_hash);
782 GList *li;
783 while (g_hash_table_iter_next(&iter, &key, &value)) {
784 li = (GList *)value;
785 li = g_list_reverse(li);
786 /* per_interface_cfilter_lists_hash was created without a
787 * value_destroy_func, so this is fine.
788 */
789 g_hash_table_iter_replace(&iter, li);
790 }
791 }
792}
793
794/* Write out recent settings of particular types. */
795static void
796write_recent_boolean(FILE *rf, const char *description, const char *name,
797 bool_Bool value)
798{
799 fprintf(rf, "\n# %s.\n", description);
800 fprintf(rf, "# true or false (case-insensitive).\n");
801 fprintf(rf, "%s: %s\n", name, value == true1 ? "true" : "false");
802}
803
804static void
805write_recent_double(FILE *rf, const char *description, const char *name,
806 double value)
807{
808 fprintf(rf, "\n# %s.\n", description);
809 char buf[G_ASCII_DTOSTR_BUF_SIZE(29 + 10)];
810 fprintf(rf, "%s: %s\n", name, g_ascii_dtostr(buf, sizeof(buf), value));
811}
812
813static void
814write_recent_enum(FILE *rf, const char *description, const char *name,
815 const value_string *values, unsigned value)
816{
817 const char *if_invalid = NULL((void*)0);
818 const value_string *valp;
819 const char *str_value;
820
821 fprintf(rf, "\n# %s.\n", description);
822 fprintf(rf, "# One of: ");
823 valp = values;
824 while (valp->strptr != NULL((void*)0)) {
825 if (if_invalid == NULL((void*)0))
826 if_invalid = valp->strptr;
827 fprintf(rf, "%s", valp->strptr);
828 valp++;
829 if (valp->strptr != NULL((void*)0))
830 fprintf(rf, ", ");
831 }
832 fprintf(rf, "\n");
833 str_value = try_val_to_str(value, values);
834 if (str_value != NULL((void*)0))
835 fprintf(rf, "%s: %s\n", name, str_value);
836 else
837 fprintf(rf, "%s: %s\n", name, if_invalid != NULL((void*)0) ? if_invalid : "Unknown");
838}
839
840/* Attempt to write out "recent common" to the user's recent_common file.
841 If we got an error report it with a dialog box and return false,
842 otherwise return true. */
843bool_Bool
844write_recent(void)
845{
846 char *pf_dir_path;
847 char *rf_path;
848 FILE *rf;
849 char *string_list;
850
851 /* To do:
852 * - Split output lines longer than MAX_VAL_LEN
853 * - Create a function for the preference directory check/creation
854 * so that duplication can be avoided with filter.c
855 */
856
857 /* Create the directory that holds personal configuration files, if
858 necessary. */
859 if (create_persconffile_dir(&pf_dir_path) == -1) {
860 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK0x01,
861 "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
862 g_strerror(errno(*__errno_location ())));
863 g_free(pf_dir_path);
864 return false0;
865 }
866
867 rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME"recent_common", false0);
868 if ((rf = ws_fopenfopen(rf_path, "w")) == NULL((void*)0)) {
869 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK0x01,
870 "Can't open recent file\n\"%s\": %s.", rf_path,
871 g_strerror(errno(*__errno_location ())));
872 g_free(rf_path);
873 return false0;
874 }
875 g_free(rf_path);
876
877 fprintf(rf, "# Common recent settings file for %s " VERSION"4.5.0" ".\n"
878 "#\n"
879 "# This file is regenerated each time %s is quit\n"
880 "# and when changing configuration profile.\n"
881 "# So be careful, if you want to make manual changes here.\n"
882 "\n"
883 "######## Recent capture files (latest last), cannot be altered through command line ########\n"
884 "\n",
885 application_flavor_name_proper(), application_flavor_name_proper());
886
887
888 menu_recent_file_write_all(rf);
889
890 fputs("\n"
891 "######## Recent capture filters (latest first), cannot be altered through command line ########\n"
892 "\n", rf);
893
894 cfilter_recent_write_all(rf);
895
896 fputs("\n"
897 "######## Recent display filters (latest last), cannot be altered through command line ########\n"
898 "\n", rf);
899
900 dfilter_recent_combo_write_all(rf);
901
902#ifdef HAVE_PCAP_REMOTE
903 fputs("\n"
904 "######## Recent remote hosts (latest first), cannot be altered through command line ########\n"
905 "\n", rf);
906
907 capture_remote_combo_recent_write_all(rf);
908#endif
909
910 fprintf(rf, "\n# Main window geometry.\n");
911 fprintf(rf, "# Decimal numbers.\n");
912 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X"gui.geometry_main_x" ": %d\n", recent.gui_geometry_main_x);
913 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y"gui.geometry_main_y" ": %d\n", recent.gui_geometry_main_y);
914 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH"gui.geometry_main_width" ": %d\n",
915 recent.gui_geometry_main_width);
916 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT"gui.geometry_main_height" ": %d\n",
917 recent.gui_geometry_main_height);
918
919 write_recent_boolean(rf, "Main window maximized",
920 RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED"gui.geometry_main_maximized",
921 recent.gui_geometry_main_maximized);
922
923 if (recent.gui_geometry_main != NULL((void*)0)) {
924 fprintf(rf, "\n# Main window geometry state.\n");
925 fprintf(rf, "# Hex byte string.\n");
926 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN"gui.geometry_main" ": %s\n",
927 recent.gui_geometry_main);
928 }
929
930 write_recent_boolean(rf, "Leftalign Action Buttons",
931 RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS"gui.geometry_leftalign_actions",
932 recent.gui_geometry_leftalign_actions);
933
934 fprintf(rf, "\n# Last used Configuration Profile.\n");
935 fprintf(rf, RECENT_LAST_USED_PROFILE"gui.last_used_profile" ": %s\n", get_profile_name());
936
937 fprintf(rf, "\n# Number of packets or events to check for automatic profile switching.\n");
938 fprintf(rf, "# Decimal number. Zero disables switching.\n");
939 const char * def_prefix = recent.gui_profile_switch_check_count == 1000 ? "#" : "";
940 fprintf(rf, "%s" RECENT_PROFILE_SWITCH_CHECK_COUNT"gui.profile_switch_check_count" ": %d\n", def_prefix,
941 recent.gui_profile_switch_check_count);
942
943 write_recent_boolean(rf, "Warn if running with elevated permissions (e.g. as root)",
944 RECENT_KEY_PRIVS_WARN_IF_ELEVATED"privs.warn_if_elevated",
945 recent.privs_warn_if_elevated);
946
947 write_recent_boolean(rf, "Warn if Wireshark is unable to capture",
948 RECENT_KEY_SYS_WARN_IF_NO_CAPTURE"sys.warn_if_no_capture",
949 recent.sys_warn_if_no_capture);
950
951 write_recent_enum(rf, "Find packet search in", RECENT_GUI_SEARCH_IN"gui.search_in", search_in_values,
952 recent.gui_search_in);
953 write_recent_enum(rf, "Find packet character set", RECENT_GUI_SEARCH_CHAR_SET"gui.search_char_set", search_char_set_values,
954 recent.gui_search_char_set);
955 write_recent_boolean(rf, "Find packet case sensitive search",
956 RECENT_GUI_SEARCH_CASE_SENSITIVE"gui.search_case_sensitive",
957 recent.gui_search_case_sensitive);
958 write_recent_boolean(rf, "Find packet search reverse direction",
959 RECENT_GUI_SEARCH_REVERSE_DIR"gui.search_reverse_dir",
960 recent.gui_search_reverse_dir);
961 write_recent_boolean(rf, "Find packet search multiple occurrences",
962 RECENT_GUI_SEARCH_MULTIPLE_OCCURS"gui.search_multiple_occurs",
963 recent.gui_search_multiple_occurs);
964 write_recent_enum(rf, "Find packet search type", RECENT_GUI_SEARCH_TYPE"gui.search_type", search_type_values,
965 recent.gui_search_type);
966
967 window_geom_recent_write_all(rf);
968
969 fprintf(rf, "\n# Custom colors.\n");
970 fprintf(rf, "# List of custom colors selected in Qt color picker.\n");
971 string_list = join_string_list(recent.custom_colors);
972 fprintf(rf, RECENT_GUI_CUSTOM_COLORS"gui.custom_colors" ": %s\n", string_list);
973 g_free(string_list);
974
975 fclose(rf);
976
977 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
978 an error indication, or maybe write to a new recent file and
979 rename that file on top of the old one only if there are not I/O
980 errors. */
981 return true1;
982}
983
984
985/* Attempt to Write out profile "recent" to the user's profile recent file.
986 If we got an error report it with a dialog box and return false,
987 otherwise return true. */
988bool_Bool
989write_profile_recent(void)
990{
991 char *pf_dir_path;
992 char *rf_path;
993 char *string_list;
994 FILE *rf;
995
996 /* To do:
997 * - Split output lines longer than MAX_VAL_LEN
998 * - Create a function for the preference directory check/creation
999 * so that duplication can be avoided with filter.c
1000 */
1001
1002 /* Create the directory that holds personal configuration files, if
1003 necessary. */
1004 if (create_persconffile_dir(&pf_dir_path) == -1) {
1005 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK0x01,
1006 "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
1007 g_strerror(errno(*__errno_location ())));
1008 g_free(pf_dir_path);
1009 return false0;
1010 }
1011
1012 rf_path = get_persconffile_path(RECENT_FILE_NAME"recent", true1);
1013 if ((rf = ws_fopenfopen(rf_path, "w")) == NULL((void*)0)) {
1014 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK0x01,
1015 "Can't open recent file\n\"%s\": %s.", rf_path,
1016 g_strerror(errno(*__errno_location ())));
1017 g_free(rf_path);
1018 return false0;
1019 }
1020 g_free(rf_path);
1021
1022 fprintf(rf, "# Recent settings file for %s " VERSION"4.5.0" ".\n"
1023 "#\n"
1024 "# This file is regenerated each time %s is quit\n"
1025 "# and when changing configuration profile.\n"
1026 "# So be careful, if you want to make manual changes here.\n"
1027 "\n",
1028 application_flavor_name_proper(), application_flavor_name_proper());
1029
1030 write_recent_boolean(rf, "Main Toolbar show (hide)",
1031 RECENT_KEY_MAIN_TOOLBAR_SHOW"gui.toolbar_main_show",
1032 recent.main_toolbar_show);
1033
1034 write_recent_boolean(rf, "Filter Toolbar show (hide)",
1035 RECENT_KEY_FILTER_TOOLBAR_SHOW"gui.filter_toolbar_show",
1036 recent.filter_toolbar_show);
1037
1038 write_recent_boolean(rf, "Wireless Settings Toolbar show (hide)",
1039 RECENT_KEY_WIRELESS_TOOLBAR_SHOW"gui.wireless_toolbar_show",
1040 recent.wireless_toolbar_show);
1041
1042 write_recent_boolean(rf, "Packet list show (hide)",
1043 RECENT_KEY_PACKET_LIST_SHOW"gui.packet_list_show",
1044 recent.packet_list_show);
1045
1046 write_recent_boolean(rf, "Tree view show (hide)",
1047 RECENT_KEY_TREE_VIEW_SHOW"gui.tree_view_show",
1048 recent.tree_view_show);
1049
1050 write_recent_boolean(rf, "Byte view show (hide)",
1051 RECENT_KEY_BYTE_VIEW_SHOW"gui.byte_view_show",
1052 recent.byte_view_show);
1053
1054 write_recent_boolean(rf, "Packet diagram show (hide)",
1055 RECENT_KEY_PACKET_DIAGRAM_SHOW"gui.packet_diagram_show",
1056 recent.packet_diagram_show);
1057
1058 write_recent_boolean(rf, "Statusbar show (hide)",
1059 RECENT_KEY_STATUSBAR_SHOW"gui.statusbar_show",
1060 recent.statusbar_show);
1061
1062 write_recent_boolean(rf, "Packet list colorize (hide)",
1063 RECENT_KEY_PACKET_LIST_COLORIZE"gui.packet_list_colorize",
1064 recent.packet_list_colorize);
1065
1066 write_recent_boolean(rf, "Auto scroll packet list when capturing",
1067 RECENT_KEY_CAPTURE_AUTO_SCROLL"capture.auto_scroll",
1068 recent.capture_auto_scroll);
1069
1070 write_recent_enum(rf, "Timestamp display format",
1071 RECENT_GUI_TIME_FORMAT"gui.time_format", ts_type_values,
1072 recent.gui_time_format);
1073
1074 /*
1075 * The value of this item is either TS_PREC_AUTO, which is a
1076 * negative number meaning "pick the display precision based
1077 * on the time stamp precision of the packet", or is a numerical
1078 * value giving the number of decimal places to display, from 0
1079 * to WS_TSPREC_MAX.
1080 *
1081 * It used to be that not all values between 0 and 9 (the maximum
1082 * precision back then) were supported, and that names were
1083 * written out to the recent file.
1084 *
1085 * For backwards compatibility with those older versions of
1086 * Wireshark, write out the names for those values, and the
1087 * raw number for other values.
1088 */
1089 {
1090 const char *if_invalid = NULL((void*)0);
1091 const value_string *valp;
1092 const char *str_value;
1093
1094 fprintf(rf, "\n# %s.\n", "Timestamp display precision");
1095 fprintf(rf, "# One of: ");
1096 valp = ts_precision_values;
1097 while (valp->strptr != NULL((void*)0)) {
1098 if (if_invalid == NULL((void*)0))
1099 if_invalid = valp->strptr;
1100 fprintf(rf, "%s", valp->strptr);
1101 valp++;
1102 if (valp->strptr != NULL((void*)0))
1103 fprintf(rf, ", ");
1104 }
1105 fprintf(rf, ", or a number between 0 and %d\n", WS_TSPREC_MAX9);
1106
1107 str_value = try_val_to_str(recent.gui_time_precision, ts_precision_values);
1108 if (str_value != NULL((void*)0))
1109 fprintf(rf, "%s: %s\n", RECENT_GUI_TIME_PRECISION"gui.time_precision", str_value);
1110 else {
1111 if (recent.gui_time_precision >= 0 && recent.gui_time_precision < WS_TSPREC_MAX9)
1112 fprintf(rf, "%s: %d\n", RECENT_GUI_TIME_PRECISION"gui.time_precision", recent.gui_time_precision);
1113 else
1114 fprintf(rf, "%s: %s\n", RECENT_GUI_TIME_PRECISION"gui.time_precision", if_invalid != NULL((void*)0) ? if_invalid : "Unknown");
1115 }
1116 }
1117
1118 write_recent_enum(rf, "Seconds display format",
1119 RECENT_GUI_SECONDS_FORMAT"gui.seconds_format", ts_seconds_values,
1120 recent.gui_seconds_format);
1121
1122 fprintf(rf, "\n# Zoom level.\n");
1123 fprintf(rf, "# A decimal number.\n");
1124 fprintf(rf, RECENT_GUI_ZOOM_LEVEL"gui.zoom_level" ": %d\n",
1125 recent.gui_zoom_level);
1126
1127 write_recent_enum(rf, "Bytes view display type",
1128 RECENT_GUI_BYTES_VIEW"gui.bytes_view", bytes_view_type_values,
1129 recent.gui_bytes_view);
1130
1131 write_recent_enum(rf, "Bytes view text encoding",
1132 RECENT_GUI_BYTES_ENCODING"gui.bytes_encoding", bytes_encoding_type_values,
1133 recent.gui_bytes_encoding);
1134
1135 write_recent_boolean(rf, "Packet diagram field values show (hide)",
1136 RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES"gui.packet_diagram_field_values",
1137 recent.gui_packet_diagram_field_values);
1138
1139 write_recent_boolean(rf, "Allow hover selection in byte view",
1140 RECENT_GUI_ALLOW_HOVER_SELECTION"gui.allow_hover_selection",
1141 recent.gui_allow_hover_selection);
1142
1143 write_recent_enum(rf, "Follow stream show as",
1144 RECENT_GUI_FOLLOW_SHOW"gui.follow_show", bytes_show_values,
1145 recent.gui_follow_show);
1146
1147 write_recent_enum(rf, "Follow stream delta times",
1148 RECENT_GUI_FOLLOW_DELTA"gui.follow_delta", follow_delta_values,
1149 recent.gui_follow_delta);
1150
1151 write_recent_enum(rf, "Show packet bytes decode as",
1152 RECENT_GUI_SHOW_BYTES_DECODE"gui.show_bytes_decode", show_bytes_decode_values,
1153 recent.gui_show_bytes_decode);
1154
1155 write_recent_enum(rf, "Show packet bytes show as",
1156 RECENT_GUI_SHOW_BYTES_SHOW"gui.show_bytes_show", bytes_show_values,
1157 recent.gui_show_bytes_show);
1158
1159 fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
1160 fprintf(rf, "# Decimal number.\n");
1161 if (recent.gui_geometry_main_upper_pane != 0) {
1162 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE"gui.geometry_main_upper_pane" ": %d\n",
1163 recent.gui_geometry_main_upper_pane);
1164 }
1165 fprintf(rf, "\n# Main window middle pane size.\n");
1166 fprintf(rf, "# Decimal number.\n");
1167 if (recent.gui_geometry_main_lower_pane != 0) {
1168 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE"gui.geometry_main_lower_pane" ": %d\n",
1169 recent.gui_geometry_main_lower_pane);
1170 }
1171
1172 if (recent.gui_geometry_main_master_split != NULL((void*)0)) {
1173 fprintf(rf, "\n# Main window master splitter state.\n");
1174 fprintf(rf, "# Hex byte string.\n");
1175 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT"gui.geometry_main_master_split" ": %s\n",
1176 recent.gui_geometry_main_master_split);
1177 }
1178
1179 if (recent.gui_geometry_main_extra_split != NULL((void*)0)) {
1180 fprintf(rf, "\n# Main window extra splitter state.\n");
1181 fprintf(rf, "# Hex byte string.\n");
1182 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT"gui.geometry_main_extra_split" ": %s\n",
1183 recent.gui_geometry_main_extra_split);
1184 }
1185
1186 window_splitter_recent_write_all(rf);
1187
1188 fprintf(rf, "\n# Packet list column pixel widths.\n");
1189 fprintf(rf, "# Each pair of strings consists of a column format and its pixel width.\n");
1190 packet_list_recent_write_all(rf);
1191
1192 fprintf(rf, "\n# Open conversation dialog tabs.\n");
1193 fprintf(rf, "# List of conversation names, e.g. \"TCP\", \"IPv6\".\n");
1194 string_list = join_string_list(recent.conversation_tabs);
1195 fprintf(rf, RECENT_GUI_CONVERSATION_TABS"gui.conversation_tabs" ": %s\n", string_list);
1196 g_free(string_list);
1197
1198 fprintf(rf, "\n# Conversation dialog tabs columns.\n");
1199 fprintf(rf, "# List of conversation columns numbers.\n");
1200 string_list = join_string_list(recent.conversation_tabs_columns);
1201 fprintf(rf, RECENT_GUI_CONVERSATION_TABS_COLUMNS"gui.conversation_tabs_columns" ": %s\n", string_list);
1202 g_free(string_list);
1203
1204 fprintf(rf, "\n# Open endpoint dialog tabs.\n");
1205 fprintf(rf, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
1206 string_list = join_string_list(recent.endpoint_tabs);
1207 fprintf(rf, RECENT_GUI_ENDPOINT_TABS"gui.endpoint_tabs" ": %s\n", string_list);
1208 g_free(string_list);
1209
1210 fprintf(rf, "\n# Endpoint dialog tabs columns.\n");
1211 fprintf(rf, "# List of endpoint columns numbers.\n");
1212 string_list = join_string_list(recent.endpoint_tabs_columns);
1213 fprintf(rf, RECENT_GUI_ENDPOINT_TABS_COLUMNS"gui.endpoint_tabs_columns" ": %s\n", string_list);
1214 g_free(string_list);
1215
1216 write_recent_boolean(rf, "For RLC stats, whether to use RLC PDUs found inside MAC frames",
1217 RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES"gui.rlc_pdus_from_mac_frames",
1218 recent.gui_rlc_use_pdus_from_mac);
1219
1220 if (get_last_open_dir() != NULL((void*)0)) {
1221 fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
1222 fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR"gui.fileopen_remembered_dir" ": %s\n", get_last_open_dir());
1223 }
1224
1225 fprintf(rf, "\n# Additional Toolbars shown\n");
1226 fprintf(rf, "# List of additional toolbars to show.\n");
1227 string_list = join_string_list(recent.gui_additional_toolbars);
1228 fprintf(rf, RECENT_GUI_TOOLBAR_SHOW"gui.additional_toolbar_show" ": %s\n", string_list);
1229 g_free(string_list);
1230
1231 fprintf(rf, "\n# Interface Toolbars show.\n");
1232 fprintf(rf, "# List of interface toolbars to show.\n");
1233 string_list = join_string_list(recent.interface_toolbars);
1234 fprintf(rf, RECENT_GUI_INTERFACE_TOOLBAR_SHOW"gui.interface_toolbar_show" ": %s\n", string_list);
1235 g_free(string_list);
1236
1237 write_recent_double(rf, "TCP Stream Graphs Moving Average Window Size",
1238 RECENT_GUI_TSD_MA_WINDOW_SIZE"gui.tsd_ma_window_size",
1239 recent.gui_tsgd_ma_window_size);
1240 write_recent_boolean(rf, "TCP Stream Graphs Dialog Throughput show (hide)",
1241 RECENT_GUI_TSD_THROUGHPUT_SHOW"gui.tsd_throughput_show",
1242 recent.gui_tsgd_throughput_show);
1243 write_recent_boolean(rf, "TCP Stream Graphs Dialog Goodput show (hide)",
1244 RECENT_GUI_TSD_GOODPUT_SHOW"gui.tsd_goodput_show",
1245 recent.gui_tsgd_goodput_show);
1246
1247 fclose(rf);
1248
1249 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
1250 an error indication, or maybe write to a new recent file and
1251 rename that file on top of the old one only if there are not I/O
1252 errors. */
1253 return true1;
1254}
1255
1256/* set one user's recent common file key/value pair */
1257static prefs_set_pref_e
1258read_set_recent_common_pair_static(char *key, const char *value,
1259 void *private_data _U___attribute__((unused)),
1260 bool_Bool return_range_errors _U___attribute__((unused)))
1261{
1262 long num;
1263 char *p;
1264
1265 if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED"gui.geometry_main_maximized") == 0) {
1266 parse_recent_boolean(value, &recent.gui_geometry_main_maximized);
1267 } else if (strcmp(key, RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS"gui.geometry_leftalign_actions") == 0) {
1268 parse_recent_boolean(value, &recent.gui_geometry_leftalign_actions);
1269 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X"gui.geometry_main_x") == 0) {
1270 num = strtol(value, &p, 0);
1271 if (p == value || *p != '\0')
1272 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1273 recent.gui_geometry_main_x = (int)num;
1274 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y"gui.geometry_main_y") == 0) {
1275 num = strtol(value, &p, 0);
1276 if (p == value || *p != '\0')
1277 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1278 recent.gui_geometry_main_y = (int)num;
1279 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH"gui.geometry_main_width") == 0) {
1280 num = strtol(value, &p, 0);
1281 if (p == value || *p != '\0')
1282 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1283 if (num <= 0)
1284 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1285 recent.gui_geometry_main_width = (int)num;
1286 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT"gui.geometry_main_height") == 0) {
1287 num = strtol(value, &p, 0);
1288 if (p == value || *p != '\0')
1289 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1290 if (num <= 0)
1291 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1292 recent.gui_geometry_main_height = (int)num;
1293 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN"gui.geometry_main") == 0) {
1294 g_free(recent.gui_geometry_main);
1295 recent.gui_geometry_main = g_strdup(value)g_strdup_inline (value);
1296 } else if (strcmp(key, RECENT_LAST_USED_PROFILE"gui.last_used_profile") == 0) {
1297 if ((strcmp(value, DEFAULT_PROFILE"Default") != 0) && profile_exists (value, false0)) {
1298 set_profile_name (value);
1299 }
1300 } else if (strcmp(key, RECENT_PROFILE_SWITCH_CHECK_COUNT"gui.profile_switch_check_count") == 0) {
1301 num = strtol(value, &p, 0);
1302 if (p == value || *p != '\0')
1303 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1304 if (num <= 0)
1305 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1306 recent.gui_profile_switch_check_count = (int)num;
1307 } else if (strncmp(key, RECENT_GUI_GEOMETRY"gui.geom.", sizeof(RECENT_GUI_GEOMETRY"gui.geom.")-1) == 0) {
1308 /* now have something like "gui.geom.main.x", split it into win and sub_key */
1309 char *win = &key[sizeof(RECENT_GUI_GEOMETRY"gui.geom.")-1];
1310 char *sub_key = strchr(win, '.');
1311 if (sub_key) {
1312 *sub_key = '\0';
1313 sub_key++;
1314 window_geom_recent_read_pair(win, sub_key, value);
1315 }
1316 } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_ELEVATED"privs.warn_if_elevated") == 0) {
1317 parse_recent_boolean(value, &recent.privs_warn_if_elevated);
1318 } else if (strcmp(key, RECENT_KEY_SYS_WARN_IF_NO_CAPTURE"sys.warn_if_no_capture") == 0) {
1319 parse_recent_boolean(value, &recent.sys_warn_if_no_capture);
1320 } else if (strcmp(key, RECENT_GUI_SEARCH_IN"gui.search_in") == 0) {
1321 recent.gui_search_in = (search_in_type)str_to_val(value, search_in_values, SEARCH_IN_PACKET_LIST);
1322 } else if (strcmp(key, RECENT_GUI_SEARCH_CHAR_SET"gui.search_char_set") == 0) {
1323 recent.gui_search_char_set = (search_char_set_type)str_to_val(value, search_char_set_values, SEARCH_CHAR_SET_NARROW_AND_WIDE);
1324 } else if (strcmp(key, RECENT_GUI_SEARCH_CASE_SENSITIVE"gui.search_case_sensitive") == 0) {
1325 parse_recent_boolean(value, &recent.gui_search_case_sensitive);
1326 } else if (strcmp(key, RECENT_GUI_SEARCH_REVERSE_DIR"gui.search_reverse_dir") == 0) {
1327 parse_recent_boolean(value, &recent.gui_search_reverse_dir);
1328 } else if (strcmp(key, RECENT_GUI_SEARCH_MULTIPLE_OCCURS"gui.search_multiple_occurs") == 0) {
1329 parse_recent_boolean(value, &recent.gui_search_multiple_occurs);
1330 } else if (strcmp(key, RECENT_GUI_SEARCH_TYPE"gui.search_type") == 0) {
1331 recent.gui_search_type = (search_type_type)str_to_val(value, search_type_values, SEARCH_TYPE_DISPLAY_FILTER);
1332 } else if (strcmp(key, RECENT_GUI_CUSTOM_COLORS"gui.custom_colors") == 0) {
1333 recent.custom_colors = prefs_get_string_list(value);
1334 }
1335
1336 return PREFS_SET_OK;
1337}
1338
1339/* set one user's recent file key/value pair */
1340static prefs_set_pref_e
1341read_set_recent_pair_static(char *key, const char *value,
1342 void *private_data _U___attribute__((unused)),
1343 bool_Bool return_range_errors _U___attribute__((unused)))
1344{
1345 long num;
1346 int32_t num_int32;
1347 double val_as_dbl;
1348 char *p;
1349 GList *col_l, *col_l_elt;
1350 col_width_data *cfmt;
1351
1352 if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW"gui.toolbar_main_show") == 0) {
1353 parse_recent_boolean(value, &recent.main_toolbar_show);
1354 } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW"gui.filter_toolbar_show") == 0) {
1355 parse_recent_boolean(value, &recent.filter_toolbar_show);
1356 /* check both the old and the new keyword */
1357 } else if (strcmp(key, RECENT_KEY_WIRELESS_TOOLBAR_SHOW"gui.wireless_toolbar_show") == 0 || (strcmp(key, "gui.airpcap_toolbar_show") == 0)) {
1358 parse_recent_boolean(value, &recent.wireless_toolbar_show);
1359 } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW"gui.packet_list_show") == 0) {
1360 parse_recent_boolean(value, &recent.packet_list_show);
1361 } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW"gui.tree_view_show") == 0) {
1362 parse_recent_boolean(value, &recent.tree_view_show);
1363 } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW"gui.byte_view_show") == 0) {
1364 parse_recent_boolean(value, &recent.byte_view_show);
1365 } else if (strcmp(key, RECENT_KEY_PACKET_DIAGRAM_SHOW"gui.packet_diagram_show") == 0) {
1366 parse_recent_boolean(value, &recent.packet_diagram_show);
1367 } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW"gui.statusbar_show") == 0) {
1368 parse_recent_boolean(value, &recent.statusbar_show);
1369 } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE"gui.packet_list_colorize") == 0) {
1370 parse_recent_boolean(value, &recent.packet_list_colorize);
1371 } else if (strcmp(key, RECENT_KEY_CAPTURE_AUTO_SCROLL"capture.auto_scroll") == 0) {
1372 parse_recent_boolean(value, &recent.capture_auto_scroll);
1373 } else if (strcmp(key, RECENT_GUI_TIME_FORMAT"gui.time_format") == 0) {
1374 recent.gui_time_format = (ts_type)str_to_val(value, ts_type_values,
1375 application_flavor_is_wireshark() ? TS_RELATIVE : TS_ABSOLUTE);
1376 } else if (strcmp(key, RECENT_GUI_TIME_PRECISION"gui.time_precision") == 0) {
1377 /*
1378 * The value of this item is either TS_PREC_AUTO, which is a
1379 * negative number meaning "pick the display precision based
1380 * on the time stamp precision of the packet", or is a numerical
1381 * value giving the number of decimal places to display, from 0
1382 * to WS_TSPREC_MAX.
1383 *
1384 * It used to be that not all values between 0 and 9 (the maximum
1385 * precision back then) were supported, and that names were
1386 * written out to the recent file.
1387 *
1388 * If the string value is a valid number in that range, use
1389 * that number, otherwise look it up in the table of names,
1390 * and, if that fails, set it to TS_PREC_AUTO.
1391 */
1392 if (ws_strtoi32(value, NULL((void*)0), &num_int32) && num_int32 >= 0 &&
1393 num_int32 <= WS_TSPREC_MAX9) {
1394 recent.gui_time_precision = num_int32;
1395 } else {
1396 recent.gui_time_precision =
1397 (ts_precision)str_to_val(value, ts_precision_values, TS_PREC_AUTO);
1398 }
1399 } else if (strcmp(key, RECENT_GUI_SECONDS_FORMAT"gui.seconds_format") == 0) {
1400 recent.gui_seconds_format =
1401 (ts_seconds_type)str_to_val(value, ts_seconds_values, TS_SECONDS_DEFAULT);
1402 } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL"gui.zoom_level") == 0) {
1403 num = strtol(value, &p, 0);
1404 if (p == value || *p != '\0')
1405 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1406 recent.gui_zoom_level = (int)num;
1407 } else if (strcmp(key, RECENT_GUI_BYTES_VIEW"gui.bytes_view") == 0) {
1408 recent.gui_bytes_view =
1409 (bytes_view_type)str_to_val(value, bytes_view_type_values, BYTES_HEX);
1410 } else if (strcmp(key, RECENT_GUI_BYTES_ENCODING"gui.bytes_encoding") == 0) {
1411 recent.gui_bytes_encoding =
1412 (bytes_encoding_type)str_to_val(value, bytes_encoding_type_values, BYTES_ENC_FROM_PACKET);
1413 } else if (strcmp(key, RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES"gui.packet_diagram_field_values") == 0) {
1414 parse_recent_boolean(value, &recent.gui_packet_diagram_field_values);
1415 } else if (strcmp(key, RECENT_GUI_ALLOW_HOVER_SELECTION"gui.allow_hover_selection") == 0) {
1416 parse_recent_boolean(value, &recent.gui_allow_hover_selection);
1417 } else if (strcmp(key, RECENT_GUI_FOLLOW_SHOW"gui.follow_show") == 0) {
1418 recent.gui_follow_show = (bytes_show_type)str_to_val(value, bytes_show_values, SHOW_ASCII);
1419 } else if (strcmp(key, RECENT_GUI_FOLLOW_DELTA"gui.follow_delta") == 0) {
1420 recent.gui_follow_delta = (follow_delta_type)str_to_val(value, follow_delta_values, FOLLOW_DELTA_NONE);
1421 } else if (strcmp(key, RECENT_GUI_SHOW_BYTES_DECODE"gui.show_bytes_decode") == 0) {
1422 recent.gui_show_bytes_decode = (bytes_decode_type)str_to_val(value, show_bytes_decode_values, DecodeAsNone);
1423 } else if (strcmp(key, RECENT_GUI_SHOW_BYTES_SHOW"gui.show_bytes_show") == 0) {
1424 recent.gui_show_bytes_show = (bytes_show_type)str_to_val(value, bytes_show_values, SHOW_ASCII);
1425 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE"gui.geometry_main_upper_pane") == 0) {
1426 num = strtol(value, &p, 0);
1427 if (p == value || *p != '\0')
1428 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1429 if (num <= 0)
1430 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1431 recent.gui_geometry_main_upper_pane = (int)num;
1432 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE"gui.geometry_main_lower_pane") == 0) {
1433 num = strtol(value, &p, 0);
1434 if (p == value || *p != '\0')
1435 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1436 if (num <= 0)
1437 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1438 recent.gui_geometry_main_lower_pane = (int)num;
1439 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT"gui.geometry_main_master_split") == 0) {
1440 g_free(recent.gui_geometry_main_master_split);
1441 recent.gui_geometry_main_master_split = g_strdup(value)g_strdup_inline (value);
1442 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT"gui.geometry_main_extra_split") == 0) {
1443 g_free(recent.gui_geometry_main_extra_split);
1444 recent.gui_geometry_main_extra_split = g_strdup(value)g_strdup_inline (value);
1445 } else if (strncmp(key, RECENT_GUI_GEOMETRY"gui.geom.", sizeof(RECENT_GUI_GEOMETRY"gui.geom.")-1) == 0) {
1446 /* now have something like "gui.geom.win.sub_key", split it into win and sub_key */
1447 char *win = &key[sizeof(RECENT_GUI_GEOMETRY"gui.geom.")-1];
1448 char *sub_key = strchr(win, '.');
1449 if (sub_key) {
1450 *sub_key = '\0';
1451 sub_key++;
1452 window_geom_recent_read_pair(win, sub_key, value);
1453 }
1454 } else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS"gui.conversation_tabs") == 0) {
1455 g_list_free_full(recent.conversation_tabs, g_free);
1456 recent.conversation_tabs = prefs_get_string_list(value);
1457 } else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS_COLUMNS"gui.conversation_tabs_columns") == 0) {
1458 g_list_free_full(recent.conversation_tabs_columns, g_free);
1459 recent.conversation_tabs_columns = prefs_get_string_list(value);
1460 } else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS"gui.endpoint_tabs") == 0) {
1461 g_list_free_full(recent.endpoint_tabs, g_free);
1462 recent.endpoint_tabs = prefs_get_string_list(value);
1463 } else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS_COLUMNS"gui.endpoint_tabs_columns") == 0) {
1464 g_list_free_full(recent.endpoint_tabs_columns, g_free);
1465 recent.endpoint_tabs_columns = prefs_get_string_list(value);
1466 } else if (strcmp(key, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES"gui.rlc_pdus_from_mac_frames") == 0) {
1467 parse_recent_boolean(value, &recent.gui_rlc_use_pdus_from_mac);
1468 } else if (strcmp(key, RECENT_KEY_COL_WIDTH"column.width") == 0) {
1469 col_l = prefs_get_string_list(value);
1470 if (col_l == NULL((void*)0))
1471 return PREFS_SET_SYNTAX_ERR;
1472 if ((g_list_length(col_l) % 2) != 0) {
1473 /* A title didn't have a matching width. */
1474 prefs_clear_string_list(col_l);
1475 return PREFS_SET_SYNTAX_ERR;
1476 }
1477 recent_free_column_width_info(&recent);
1478 recent.col_width_list = NULL((void*)0);
1479 col_l_elt = g_list_first(col_l);
1480 while (col_l_elt) {
1481 cfmt = g_new(col_width_data, 1)((col_width_data *) g_malloc_n ((1), sizeof (col_width_data))
)
;
1482 /* Skip the column format, we don't use it anymore because the
1483 * column indices are in sync and the key since 4.4. Format is
1484 * still written for backwards compatibility.
1485 */
1486 col_l_elt = col_l_elt->next;
1487 cfmt->width = (int)strtol((const char *)col_l_elt->data, &p, 0);
1488 if (p == col_l_elt->data || (*p != '\0' && *p != ':')) {
1489 g_free(cfmt);
1490 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1491 }
1492
1493 if (*p == ':') {
1494 cfmt->xalign = *(++p);
1495 } else {
1496 cfmt->xalign = COLUMN_XALIGN_DEFAULT0;
1497 }
1498
1499 col_l_elt = col_l_elt->next;
1500 recent.col_width_list = g_list_append(recent.col_width_list, cfmt);
1501 }
1502 prefs_clear_string_list(col_l);
1503 } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR"gui.fileopen_remembered_dir") == 0) {
1504 g_free(recent.gui_fileopen_remembered_dir);
1505 recent.gui_fileopen_remembered_dir = g_strdup(value)g_strdup_inline (value);
1506 } else if (strcmp(key, RECENT_GUI_TOOLBAR_SHOW"gui.additional_toolbar_show") == 0) {
1507 recent.gui_additional_toolbars = prefs_get_string_list(value);
1508 } else if (strcmp(key, RECENT_GUI_INTERFACE_TOOLBAR_SHOW"gui.interface_toolbar_show") == 0) {
1509 recent.interface_toolbars = prefs_get_string_list(value);
1510 } else if (strcmp(key, RECENT_GUI_TSD_THROUGHPUT_SHOW"gui.tsd_throughput_show") == 0) {
1511 parse_recent_boolean(value, &recent.gui_tsgd_throughput_show);
1512 } else if (strcmp(key, RECENT_GUI_TSD_GOODPUT_SHOW"gui.tsd_goodput_show") == 0) {
1513 parse_recent_boolean(value, &recent.gui_tsgd_goodput_show);
1514 } else if (strcmp(key, RECENT_GUI_TSD_MA_WINDOW_SIZE"gui.tsd_ma_window_size") == 0) {
1515 val_as_dbl = g_ascii_strtod(value, &p);
1516 if (p == value || *p != '\0') {
1517 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1518 }
1519 if (val_as_dbl <= 0) {
1520 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1521 }
1522 recent.gui_tsgd_ma_window_size = val_as_dbl;
1523 } else {
1524 return PREFS_SET_NO_SUCH_PREF;
1525 }
1526
1527 return PREFS_SET_OK;
1528}
1529
1530
1531/* set one user's recent file key/value pair */
1532static prefs_set_pref_e
1533read_set_recent_pair_dynamic(char *key, const char *value,
1534 void *private_data _U___attribute__((unused)),
1535 bool_Bool return_range_errors _U___attribute__((unused)))
1536{
1537 if (!g_utf8_validate(value, -1, NULL((void*)0))) {
1538 return PREFS_SET_SYNTAX_ERR;
1539 }
1540 if (strcmp(key, RECENT_KEY_CAPTURE_FILE"recent.capture_file") == 0) {
1541 add_menu_recent_capture_file(value, true1);
1542 } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER"recent.display_filter") == 0) {
1543 dfilter_combo_add_recent(value);
1544 } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER"recent.capture_filter") == 0) {
1545 recent_add_cfilter(NULL((void*)0), value);
1546 } else if (g_str_has_prefix(key, RECENT_KEY_CAPTURE_FILTER ".")(__builtin_constant_p ("recent.capture_filter" ".")? __extension__
({ const char * const __str = (key); const char * const __prefix
= ("recent.capture_filter" "."); gboolean __result = (0); if
(__str == ((void*)0) || __prefix == ((void*)0)) __result = (
g_str_has_prefix) (__str, __prefix); else { const size_t __str_len
= strlen (((__str) + !(__str))); const size_t __prefix_len =
strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len
) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix
)), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) (
key, "recent.capture_filter" ".") )
) {
1547 /* strrchr() can't fail - string has a prefix that ends with a "." */
1548 recent_add_cfilter(strrchr(key, '.') + 1, value);
1549#ifdef HAVE_PCAP_REMOTE
1550 } else if (strcmp(key, RECENT_KEY_REMOTE_HOST"recent.remote_host") == 0) {
1551 capture_remote_combo_add_recent(value);
1552#endif
1553 }
1554
1555 return PREFS_SET_OK;
1556}
1557
1558
1559/*
1560 * Given a string of the form "<recent name>:<recent value>", as might appear
1561 * as an argument to a "-o" option, parse it and set the recent value in
1562 * question. Return an indication of whether it succeeded or failed
1563 * in some fashion.
1564 */
1565int
1566recent_set_arg(char *prefarg)
1567{
1568 char *p, *colonp;
1569 int ret;
1570
1571 colonp = strchr(prefarg, ':');
1572 if (colonp == NULL((void*)0))
1573 return PREFS_SET_SYNTAX_ERR;
1574
1575 p = colonp;
1576 *p++ = '\0';
1577
1578 /*
1579 * Skip over any white space (there probably won't be any, but
1580 * as we allow it in the preferences file, we might as well
1581 * allow it here).
1582 */
1583 while (g_ascii_isspace(*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0))
1584 p++;
1585 if (*p == '\0') {
1586 /*
1587 * Put the colon back, so if our caller uses, in an
1588 * error message, the string they passed us, the message
1589 * looks correct.
1590 */
1591 *colonp = ':';
1592 return PREFS_SET_SYNTAX_ERR;
1593 }
1594
1595 ret = read_set_recent_pair_static(prefarg, p, NULL((void*)0), true1);
1596 *colonp = ':'; /* put the colon back */
1597 return ret;
1598}
1599
1600
1601/* opens the user's recent common file and read the first part */
1602bool_Bool
1603recent_read_static(char **rf_path_return, int *rf_errno_return)
1604{
1605 char *rf_path;
1606 FILE *rf;
1607
1608 /* set defaults */
1609 recent.gui_geometry_main_x = 20;
1610 recent.gui_geometry_main_y = 20;
1611 recent.gui_geometry_main_width = DEF_WIDTH750;
1612 recent.gui_geometry_main_height = DEF_HEIGHT550;
1613 recent.gui_geometry_main_maximized= false0;
1614
1615 recent.gui_geometry_leftalign_actions = false0;
1616
1617 recent.privs_warn_if_elevated = true1;
1618 recent.sys_warn_if_no_capture = true1;
1619
1620 recent.col_width_list = NULL((void*)0);
1621 recent.gui_geometry_main = NULL((void*)0);
1622 recent.gui_geometry_main_master_split = NULL((void*)0);
1623 recent.gui_geometry_main_extra_split = NULL((void*)0);
1624 recent.gui_profile_switch_check_count = 1000;
1625 recent.gui_fileopen_remembered_dir = NULL((void*)0);
1626
1627 /* Construct the pathname of the user's recent common file. */
1628 rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME"recent_common", false0);
1629
1630 /* Read the user's recent common file, if it exists. */
1631 *rf_path_return = NULL((void*)0);
1632 if ((rf = ws_fopenfopen(rf_path, "r")) != NULL((void*)0)) {
1633 /* We succeeded in opening it; read it. */
1634 read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL((void*)0));
1635
1636 fclose(rf);
1637 } else {
1638 /* We failed to open it. If we failed for some reason other than
1639 "it doesn't exist", return the errno and the pathname, so our
1640 caller can report the error. */
1641 if (errno(*__errno_location ()) != ENOENT2) {
1642 *rf_errno_return = errno(*__errno_location ());
1643 *rf_path_return = rf_path;
1644 return false0;
1645 }
1646 }
1647 g_free(rf_path);
1648 return true1;
1649}
1650
1651
1652
1653/* opens the user's recent file and read the first part */
1654bool_Bool
1655recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
1656{
1657 char *rf_path, *rf_common_path;
1658 FILE *rf;
1659
1660 /* set defaults */
1661 recent.main_toolbar_show = true1;
1662 recent.filter_toolbar_show = true1;
1663 recent.wireless_toolbar_show = false0;
1664 recent.packet_list_show = true1;
1665 recent.tree_view_show = true1;
1666 recent.byte_view_show = true1;
1667 recent.packet_diagram_show = true1;
1668 recent.statusbar_show = true1;
1669 recent.packet_list_colorize = true1;
1670 recent.capture_auto_scroll = true1;
1671 recent.gui_time_format = TS_RELATIVE;
1672 recent.gui_time_precision = TS_PREC_AUTO;
1673 recent.gui_seconds_format = TS_SECONDS_DEFAULT;
1674 recent.gui_zoom_level = 0;
1675 recent.gui_bytes_view = BYTES_HEX;
1676 recent.gui_bytes_encoding = BYTES_ENC_FROM_PACKET;
1677 recent.gui_allow_hover_selection = true1;
1678 recent.gui_follow_show = SHOW_ASCII;
1679 recent.gui_follow_delta = FOLLOW_DELTA_NONE;
1680 recent.gui_show_bytes_decode = DecodeAsNone;
1681 recent.gui_show_bytes_show = SHOW_ASCII;
1682
1683 /* defaults for the TCP Stream Graph Dialog */
1684 recent.gui_tsgd_ma_window_size = 1.0;
1685 recent.gui_tsgd_throughput_show = true1;
1686 recent.gui_tsgd_goodput_show = false0;
1687
1688 /* pane size of zero will autodetect */
1689 recent.gui_geometry_main_upper_pane = 0;
1690 recent.gui_geometry_main_lower_pane = 0;
1691
1692 if (recent.gui_geometry_main) {
1
Assuming field 'gui_geometry_main' is null
2
Taking false branch
1693 g_free(recent.gui_geometry_main);
1694 recent.gui_geometry_main = NULL((void*)0);
1695 }
1696
1697 if (recent.gui_geometry_main_master_split) {
3
Assuming field 'gui_geometry_main_master_split' is null
4
Taking false branch
1698 g_free(recent.gui_geometry_main_master_split);
1699 recent.gui_geometry_main_master_split = NULL((void*)0);
1700 }
1701 if (recent.gui_geometry_main_extra_split) {
5
Assuming field 'gui_geometry_main_extra_split' is null
6
Taking false branch
1702 g_free(recent.gui_geometry_main_extra_split);
1703 recent.gui_geometry_main_extra_split = NULL((void*)0);
1704 }
1705
1706 if (recent.col_width_list) {
7
Assuming field 'col_width_list' is null
8
Taking false branch
1707 recent_free_column_width_info(&recent);
1708 }
1709
1710 if (recent.gui_fileopen_remembered_dir) {
9
Assuming field 'gui_fileopen_remembered_dir' is null
10
Taking false branch
1711 g_free (recent.gui_fileopen_remembered_dir);
1712 recent.gui_fileopen_remembered_dir = NULL((void*)0);
1713 }
1714
1715 if (recent.gui_additional_toolbars) {
11
Assuming field 'gui_additional_toolbars' is null
12
Taking false branch
1716 g_list_free_full (recent.gui_additional_toolbars, g_free);
1717 recent.gui_additional_toolbars = NULL((void*)0);
1718 }
1719
1720 if (recent.interface_toolbars) {
13
Assuming field 'interface_toolbars' is null
14
Taking false branch
1721 g_list_free_full (recent.interface_toolbars, g_free);
1722 recent.interface_toolbars = NULL((void*)0);
1723 }
1724
1725 /* Construct the pathname of the user's profile recent file. */
1726 rf_path = get_persconffile_path(RECENT_FILE_NAME"recent", true1);
1727
1728 /* Read the user's recent file, if it exists. */
1729 *rf_path_return = NULL((void*)0);
1730 if ((rf = ws_fopenfopen(rf_path, "r")) != NULL((void*)0)) {
15
Taking true branch
1731 /* We succeeded in opening it; read it. */
1732 read_prefs_file(rf_path, rf, read_set_recent_pair_static, NULL((void*)0));
1733 fclose(rf);
1734
1735 /* XXX: The following code doesn't actually do anything since
1736 * the "recent common file" always exists. Presumably the
1737 * "if (!file_exists())" should actually be "if (file_exists())".
1738 * However, I've left the code as is because this
1739 * behaviour has existed for quite some time and I don't
1740 * know what's supposed to happen at this point.
1741 * ToDo: Determine if the "recent common file" should be read at this point
1742 */
1743 rf_common_path = get_persconffile_path(RECENT_COMMON_FILE_NAME"recent_common", false0);
1744 if (!file_exists(rf_common_path)) {
16
Assuming the condition is true
17
Taking true branch
1745 /* Read older common settings from recent file */
1746 rf = ws_fopenfopen(rf_path, "r");
18
Assuming pointer value is null
19
Assuming that 'fopen' fails
20
Value assigned to 'rf'
1747 read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL((void*)0));
1748 fclose(rf);
21
Null pointer passed to 1st parameter expecting 'nonnull'
1749 }
1750 g_free(rf_common_path);
1751 } else {
1752 /* We failed to open it. If we failed for some reason other than
1753 "it doesn't exist", return the errno and the pathname, so our
1754 caller can report the error. */
1755 if (errno(*__errno_location ()) != ENOENT2) {
1756 *rf_errno_return = errno(*__errno_location ());
1757 *rf_path_return = rf_path;
1758 return false0;
1759 }
1760 }
1761 g_free(rf_path);
1762 return true1;
1763}
1764
1765/* opens the user's recent file and read it out */
1766bool_Bool
1767recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
1768{
1769 char *rf_path;
1770 FILE *rf;
1771
1772
1773 /* Construct the pathname of the user's recent common file. */
1774 rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME"recent_common", false0);
1775 if (!file_exists (rf_path)) {
1776 /* Recent common file does not exist, read from default recent */
1777 g_free (rf_path);
1778 rf_path = get_persconffile_path(RECENT_FILE_NAME"recent", false0);
1779 }
1780
1781 /* Read the user's recent file, if it exists. */
1782 *rf_path_return = NULL((void*)0);
1783 if ((rf = ws_fopenfopen(rf_path, "r")) != NULL((void*)0)) {
1784 /* We succeeded in opening it; read it. */
1785 read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic, NULL((void*)0));
1786#if 0
1787 /* set dfilter combobox to have an empty line */
1788 dfilter_combo_add_empty();
1789#endif
1790 /* We prepend new capture filters, so reverse them after adding
1791 * all to keep the latest first.
1792 */
1793 cfilter_recent_reverse_all();
1794#ifdef HAVE_PCAP_REMOTE
1795 remote_host_reverse();
1796#endif
1797 fclose(rf);
1798 } else {
1799 /* We failed to open it. If we failed for some reason other than
1800 "it doesn't exist", return the errno and the pathname, so our
1801 caller can report the error. */
1802 if (errno(*__errno_location ()) != ENOENT2) {
1803 *rf_errno_return = errno(*__errno_location ());
1804 *rf_path_return = rf_path;
1805 return false0;
1806 }
1807 }
1808 g_free(rf_path);
1809 return true1;
1810}
1811
1812void
1813recent_insert_column(int col)
1814{
1815 col_width_data *col_w;
1816
1817 col_w = g_new(col_width_data, 1)((col_width_data *) g_malloc_n ((1), sizeof (col_width_data))
)
;
1818 col_w->width = -1;
1819 col_w->xalign = COLUMN_XALIGN_DEFAULT0;
1820 recent.col_width_list = g_list_insert(recent.col_width_list, col_w, col);
1821}
1822
1823void
1824recent_remove_column(int col)
1825{
1826 GList *col_l = g_list_nth(recent.col_width_list, col);
1827 col_width_data *col_w;
1828
1829 if (!col_l) return;
1830
1831 col_w = (col_width_data*)col_l->data;
1832
1833 if (col_w) {
1834 free_col_width_data(col_w);
1835 }
1836
1837 recent.col_width_list = g_list_delete_link(recent.col_width_list, col_l);
1838}
1839
1840int
1841recent_get_column_width(int col)
1842{
1843 col_width_data *col_w;
1844
1845 col_w = g_list_nth_data(recent.col_width_list, col);
1846 if (col_w) {
1847 return col_w->width;
1848 } else {
1849 /* Make sure the recent column list isn't out of sync with the
1850 * number of columns (e.g., for a brand new profile.)
1851 */
1852 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1853 recent_insert_column(colnr);
1854 }
1855 }
1856
1857 return -1;
1858}
1859
1860void
1861recent_set_column_width(int col, int width)
1862{
1863 col_width_data *col_w;
1864
1865 col_w = g_list_nth_data(recent.col_width_list, col);
1866 if (col_w) {
1867 col_w->width = width;
1868 } else {
1869 /* Make sure the recent column list isn't out of sync with the
1870 * number of columns (e.g., for a brand new profile.)
1871 */
1872 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1873 recent_insert_column(colnr);
1874 }
1875 col_w = g_list_nth_data(recent.col_width_list, col);
1876 if (col_w) {
1877 col_w->width = width;
1878 }
1879 }
1880}
1881
1882char
1883recent_get_column_xalign(int col)
1884{
1885 col_width_data *col_w;
1886
1887 col_w = g_list_nth_data(recent.col_width_list, col);
1888 if (col_w) {
1889 return col_w->xalign;
1890 } else {
1891 /* Make sure the recent column list isn't out of sync with the
1892 * number of columns (e.g., for a brand new profile.)
1893 */
1894 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1895 recent_insert_column(colnr);
1896 }
1897 }
1898
1899 return COLUMN_XALIGN_DEFAULT0;
1900}
1901
1902void
1903recent_set_column_xalign(int col, char xalign)
1904{
1905 col_width_data *col_w;
1906
1907 col_w = g_list_nth_data(recent.col_width_list, col);
1908 if (col_w) {
1909 col_w->xalign = xalign;
1910 } else {
1911 /* Make sure the recent column list isn't out of sync with the
1912 * number of columns (e.g., for a brand new profile.)
1913 */
1914 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1915 recent_insert_column(colnr);
1916 }
1917 col_w = g_list_nth_data(recent.col_width_list, col);
1918 if (col_w) {
1919 col_w->xalign = xalign;
1920 }
1921 }
1922}
1923
1924void
1925recent_init(void)
1926{
1927 memset(&recent, 0, sizeof(recent_settings_t));
1928}
1929
1930void
1931recent_cleanup(void)
1932{
1933 recent_free_column_width_info(&recent);
1934 g_free(recent.gui_geometry_main);
1935 g_free(recent.gui_geometry_main_master_split);
1936 g_free(recent.gui_geometry_main_extra_split);
1937 g_free(recent.gui_fileopen_remembered_dir);
1938 g_list_free_full(recent.gui_additional_toolbars, g_free);
1939 g_list_free_full(recent.interface_toolbars, g_free);
1940 prefs_clear_string_list(recent.conversation_tabs);
1941 prefs_clear_string_list(recent.conversation_tabs_columns);
1942 prefs_clear_string_list(recent.endpoint_tabs);
1943 prefs_clear_string_list(recent.endpoint_tabs_columns);
1944 prefs_clear_string_list(recent.custom_colors);
1945}