Bug Summary

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