Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / ui / recent.c
blobd602ec86373c44de124be8842ad047f556e1689c
1 /* recent.c
2 * Recent "preference" handling routines
3 * Copyright 2004, Ulf Lamping <ulf.lamping@web.de>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include <wireshark.h>
16 #include <stdlib.h>
17 #include <errno.h>
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>
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"
35 #include <wsutil/file_util.h>
36 #include <wsutil/strtoi.h>
38 #define RECENT_KEY_MAIN_TOOLBAR_SHOW "gui.toolbar_main_show"
39 #define RECENT_KEY_FILTER_TOOLBAR_SHOW "gui.filter_toolbar_show"
40 #define RECENT_KEY_WIRELESS_TOOLBAR_SHOW "gui.wireless_toolbar_show"
41 #define RECENT_KEY_PACKET_LIST_SHOW "gui.packet_list_show"
42 #define RECENT_KEY_TREE_VIEW_SHOW "gui.tree_view_show"
43 #define RECENT_KEY_BYTE_VIEW_SHOW "gui.byte_view_show"
44 #define RECENT_KEY_PACKET_DIAGRAM_SHOW "gui.packet_diagram_show"
45 #define RECENT_KEY_STATUSBAR_SHOW "gui.statusbar_show"
46 #define RECENT_KEY_PACKET_LIST_COLORIZE "gui.packet_list_colorize"
47 #define RECENT_KEY_CAPTURE_AUTO_SCROLL "capture.auto_scroll"
48 #define RECENT_GUI_TIME_FORMAT "gui.time_format"
49 #define RECENT_GUI_TIME_PRECISION "gui.time_precision"
50 #define RECENT_GUI_SECONDS_FORMAT "gui.seconds_format"
51 #define RECENT_GUI_ZOOM_LEVEL "gui.zoom_level"
52 #define RECENT_GUI_BYTES_VIEW "gui.bytes_view"
53 #define RECENT_GUI_BYTES_ENCODING "gui.bytes_encoding"
54 #define RECENT_GUI_ALLOW_HOVER_SELECTION "gui.allow_hover_selection"
55 #define RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES "gui.packet_diagram_field_values"
56 #define RECENT_GUI_GEOMETRY_MAIN_X "gui.geometry_main_x"
57 #define RECENT_GUI_GEOMETRY_MAIN_Y "gui.geometry_main_y"
58 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH "gui.geometry_main_width"
59 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT "gui.geometry_main_height"
60 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED "gui.geometry_main_maximized"
61 #define RECENT_GUI_GEOMETRY_MAIN "gui.geometry_main"
62 #define RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS "gui.geometry_leftalign_actions"
63 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE "gui.geometry_main_upper_pane"
64 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE "gui.geometry_main_lower_pane"
65 #define RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT "gui.geometry_main_master_split"
66 #define RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT "gui.geometry_main_extra_split"
67 #define RECENT_LAST_USED_PROFILE "gui.last_used_profile"
68 #define RECENT_PROFILE_SWITCH_CHECK_COUNT "gui.profile_switch_check_count"
69 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen_remembered_dir"
70 #define RECENT_GUI_CONVERSATION_TABS "gui.conversation_tabs"
71 #define RECENT_GUI_CONVERSATION_TABS_COLUMNS "gui.conversation_tabs_columns"
72 #define RECENT_GUI_ENDPOINT_TABS "gui.endpoint_tabs"
73 #define RECENT_GUI_ENDPOINT_TABS_COLUMNS "gui.endpoint_tabs_columns"
74 #define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES "gui.rlc_pdus_from_mac_frames"
75 #define RECENT_GUI_CUSTOM_COLORS "gui.custom_colors"
76 #define RECENT_GUI_TOOLBAR_SHOW "gui.additional_toolbar_show"
77 #define RECENT_GUI_INTERFACE_TOOLBAR_SHOW "gui.interface_toolbar_show"
78 #define RECENT_GUI_SEARCH_IN "gui.search_in"
79 #define RECENT_GUI_SEARCH_CHAR_SET "gui.search_char_set"
80 #define RECENT_GUI_SEARCH_CASE_SENSITIVE "gui.search_case_sensitive"
81 #define RECENT_GUI_SEARCH_REVERSE_DIR "gui.search_reverse_dir"
82 #define RECENT_GUI_SEARCH_MULTIPLE_OCCURS "gui.search_multiple_occurs"
83 #define RECENT_GUI_SEARCH_TYPE "gui.search_type"
84 #define RECENT_GUI_FOLLOW_SHOW "gui.follow_show"
85 #define RECENT_GUI_FOLLOW_DELTA "gui.follow_delta"
86 #define RECENT_GUI_SHOW_BYTES_DECODE "gui.show_bytes_decode"
87 #define RECENT_GUI_SHOW_BYTES_SHOW "gui.show_bytes_show"
89 #define RECENT_GUI_GEOMETRY "gui.geom."
91 #define RECENT_KEY_PRIVS_WARN_IF_ELEVATED "privs.warn_if_elevated"
92 #define RECENT_KEY_SYS_WARN_IF_NO_CAPTURE "sys.warn_if_no_capture"
94 #define RECENT_FILE_NAME "recent"
95 #define RECENT_COMMON_FILE_NAME "recent_common"
97 recent_settings_t recent;
99 static const value_string ts_type_values[] = {
100 { TS_RELATIVE, "RELATIVE" },
101 { TS_ABSOLUTE, "ABSOLUTE" },
102 { TS_ABSOLUTE_WITH_YMD, "ABSOLUTE_WITH_YMD" },
103 { TS_ABSOLUTE_WITH_YDOY, "ABSOLUTE_WITH_YDOY" },
104 { TS_ABSOLUTE_WITH_YMD, "ABSOLUTE_WITH_DATE" }, /* Backward compatibility */
105 { TS_DELTA, "DELTA" },
106 { TS_DELTA_DIS, "DELTA_DIS" },
107 { TS_EPOCH, "EPOCH" },
108 { TS_UTC, "UTC" },
109 { TS_UTC_WITH_YMD, "UTC_WITH_YMD" },
110 { TS_UTC_WITH_YDOY, "UTC_WITH_YDOY" },
111 { TS_UTC_WITH_YMD, "UTC_WITH_DATE" }, /* Backward compatibility */
112 { 0, NULL }
116 * NOTE: all values other than TS_PREC_AUTO are the number of digits
117 * of precision.
119 * We continue to use the old names for values where they may have
120 * been written to the recent file by previous releases. For other
121 * values, we just write it out numerically.
123 static const value_string ts_precision_values[] = {
124 { TS_PREC_AUTO, "AUTO" },
125 { TS_PREC_FIXED_SEC, "SEC" },
126 { TS_PREC_FIXED_100_MSEC, "DSEC" },
127 { TS_PREC_FIXED_10_MSEC, "CSEC" },
128 { TS_PREC_FIXED_MSEC, "MSEC" },
129 { TS_PREC_FIXED_USEC, "USEC" },
130 { TS_PREC_FIXED_NSEC, "NSEC" },
131 { 0, NULL }
134 static const value_string ts_seconds_values[] = {
135 { TS_SECONDS_DEFAULT, "SECONDS" },
136 { TS_SECONDS_HOUR_MIN_SEC, "HOUR_MIN_SEC" },
137 { 0, NULL }
140 static const value_string bytes_view_type_values[] = {
141 { BYTES_HEX, "HEX" },
142 { BYTES_BITS, "BITS" },
143 { BYTES_DEC, "DEC" },
144 { BYTES_OCT, "OCT" },
145 { 0, NULL }
148 static const value_string bytes_encoding_type_values[] = {
149 { BYTES_ENC_FROM_PACKET, "FROM_PACKET" },
150 { BYTES_ENC_ASCII, "ASCII" },
151 { BYTES_ENC_EBCDIC, "EBCDIC" },
152 { 0, NULL }
155 static const value_string search_in_values[] = {
156 { SEARCH_IN_PACKET_LIST, "PACKET_LIST" },
157 { SEARCH_IN_PACKET_DETAILS, "PACKET_DETAILS" },
158 { SEARCH_IN_PACKET_BYTES, "PACKET_BYTES" },
159 { 0, NULL }
162 static const value_string search_char_set_values[] = {
163 { SEARCH_CHAR_SET_NARROW_AND_WIDE, "NARROW_AND_WIDE" },
164 { SEARCH_CHAR_SET_NARROW, "NARROW" },
165 { SEARCH_CHAR_SET_WIDE, "WIDE" },
166 { 0, NULL }
169 static const value_string search_type_values[] = {
170 { SEARCH_TYPE_DISPLAY_FILTER, "DISPLAY_FILTER" },
171 { SEARCH_TYPE_HEX_VALUE, "HEX_VALUE" },
172 { SEARCH_TYPE_STRING, "STRING" },
173 { SEARCH_TYPE_REGEX, "REGEX" },
174 { 0, NULL }
177 static const value_string bytes_show_values[] = {
178 { SHOW_ASCII, "ASCII" },
179 { SHOW_ASCII_CONTROL, "ASCII_CONTROL" },
180 { SHOW_CARRAY, "C_ARRAYS" },
181 { SHOW_EBCDIC, "EBCDIC" },
182 { SHOW_HEXDUMP, "HEX_DUMP" },
183 { SHOW_HTML, "HTML" },
184 { SHOW_IMAGE, "IMAGE" },
185 { SHOW_JSON, "JSON" },
186 { SHOW_RAW, "RAW" },
187 { SHOW_RUSTARRAY, "RUST_ARRAY" },
188 { SHOW_CODEC, "UTF-8" },
189 // Other codecs are generated at runtime
190 { SHOW_YAML, "YAML"},
191 { 0, NULL }
194 static const value_string follow_delta_values[] = {
195 { FOLLOW_DELTA_NONE, "NONE" },
196 { FOLLOW_DELTA_TURN, "TURN" },
197 { FOLLOW_DELTA_ALL, "ALL" },
198 { 0, NULL }
201 static const value_string show_bytes_decode_values[] = {
202 { DecodeAsNone, "NONE" },
203 { DecodeAsBASE64, "BASE64" },
204 { DecodeAsCompressed, "COMPRESSED" },
205 { DecodeAsHexDigits, "HEX_DIGITS" },
206 { DecodeAsPercentEncoding, "PERCENT_ENCODING" },
207 { DecodeAsQuotedPrintable, "QUOTED_PRINTABLE" },
208 { DecodeAsROT13, "ROT13"},
209 { 0, NULL }
212 static void
213 free_col_width_data(void *data)
215 col_width_data *cfmt = (col_width_data *)data;
216 g_free(cfmt);
219 void
220 recent_free_column_width_info(recent_settings_t *rs)
222 g_list_free_full(rs->col_width_list, free_col_width_data);
223 rs->col_width_list = NULL;
226 /** Write the geometry values of a single window to the recent file.
228 * @param key unused
229 * @param value the geometry values
230 * @param rfh recent file handle (FILE)
232 static void
233 write_recent_geom(void *key _U_, void *value, void *rfh)
235 window_geometry_t *geom = (window_geometry_t *)value;
236 FILE *rf = (FILE *)rfh;
238 fprintf(rf, "\n# Geometry and maximized state of %s window.\n", geom->key);
239 fprintf(rf, "# Decimal integers.\n");
240 fprintf(rf, RECENT_GUI_GEOMETRY "%s.x: %d\n", geom->key, geom->x);
241 fprintf(rf, RECENT_GUI_GEOMETRY "%s.y: %d\n", geom->key, geom->y);
242 fprintf(rf, RECENT_GUI_GEOMETRY "%s.width: %d\n", geom->key,
243 geom->width);
244 fprintf(rf, RECENT_GUI_GEOMETRY "%s.height: %d\n", geom->key,
245 geom->height);
247 fprintf(rf, "# true or false (case-insensitive).\n");
248 fprintf(rf, RECENT_GUI_GEOMETRY "%s.maximized: %s\n", geom->key,
249 geom->maximized == true ? "true" : "false");
251 fprintf(rf, "# Qt Geometry State (hex byte string).\n");
252 fprintf(rf, RECENT_GUI_GEOMETRY "%s.qt_geometry: %s\n", geom->key,
253 geom->qt_geom);
256 /* the geometry hashtable for all known window classes,
257 * the window name is the key, and the geometry struct is the value */
258 static GHashTable *window_geom_hash;
260 static GHashTable *window_splitter_hash;
262 void
263 window_geom_free(void *data)
265 window_geometry_t *geom = (window_geometry_t*)data;
266 g_free(geom->key);
267 g_free(geom->qt_geom);
268 g_free(geom);
271 /* save the window and its current geometry into the geometry hashtable */
272 void
273 window_geom_save(const char *name, window_geometry_t *geom)
275 char *key;
276 window_geometry_t *work;
278 /* init hashtable, if not already done */
279 if (!window_geom_hash) {
280 window_geom_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, window_geom_free);
283 /* g_malloc and insert the new one */
284 work = g_new(window_geometry_t, 1);
285 *work = *geom;
286 key = g_strdup(name);
287 work->key = key;
288 g_hash_table_replace(window_geom_hash, key, work);
291 /* load the desired geometry for this window from the geometry hashtable */
292 bool
293 window_geom_load(const char *name,
294 window_geometry_t *geom)
296 window_geometry_t *p;
298 /* init hashtable, if not already done */
299 if (!window_geom_hash) {
300 window_geom_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, window_geom_free);
303 p = (window_geometry_t *)g_hash_table_lookup(window_geom_hash, name);
304 if (p) {
305 *geom = *p;
306 return true;
307 } else {
308 return false;
312 /* save the window and its splitter state into the splitter hashtable */
313 void
314 window_splitter_save(const char *name, const char *splitter_state)
316 /* init hashtable, if not already done */
317 if (!window_splitter_hash) {
318 window_splitter_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
321 g_hash_table_replace(window_splitter_hash, g_strdup(name), g_strdup(splitter_state));
324 /* save the window and its splitter state into the geometry hashtable */
325 const char*
326 window_splitter_load(const char *name)
328 /* init hashtable, if not already done */
329 if (!window_splitter_hash) {
330 return NULL;
333 return g_hash_table_lookup(window_splitter_hash, name);
337 /* parse values of particular types */
338 static void
339 parse_recent_boolean(const char *val_str, bool *valuep)
341 if (g_ascii_strcasecmp(val_str, "true") == 0) {
342 *valuep = true;
344 else {
345 *valuep = false;
349 /** Read in a single geometry key value pair from the recent file.
351 * @param name the geom_name of the window
352 * @param key the subkey of this pair (e.g. "x")
353 * @param value the new value (e.g. "123")
355 static void
356 window_geom_recent_read_pair(const char *name,
357 const char *key,
358 const char *value)
360 window_geometry_t geom;
362 if (strcmp(key, "splitter") == 0) {
363 window_splitter_save(name, value);
364 return;
367 /* find window geometry maybe already in hashtable */
368 if (!window_geom_load(name, &geom)) {
369 /* not in table, init geom with "basic" values */
370 geom.key = NULL; /* Will be set in window_geom_save() */
371 geom.set_pos = false;
372 geom.x = -1;
373 geom.y = -1;
374 geom.set_size = false;
375 geom.width = -1;
376 geom.height = -1;
377 geom.qt_geom = NULL;
380 if (strcmp(key, "x") == 0) {
381 geom.x = (int)strtol(value, NULL, 10);
382 geom.set_pos = true;
383 } else if (strcmp(key, "y") == 0) {
384 geom.y = (int)strtol(value, NULL, 10);
385 geom.set_pos = true;
386 } else if (strcmp(key, "width") == 0) {
387 geom.width = (int)strtol(value, NULL, 10);
388 geom.set_size = true;
389 } else if (strcmp(key, "height") == 0) {
390 geom.height = (int)strtol(value, NULL, 10);
391 geom.set_size = true;
392 } else if (strcmp(key, "maximized") == 0) {
393 parse_recent_boolean(value, &geom.maximized);
394 geom.set_maximized = true;
395 } else if (strcmp(key, "qt_geometry") == 0) {
396 geom.qt_geom = g_strdup(value);
397 } else {
399 * Silently ignore the bogus key. We shouldn't abort here,
400 * as this could be due to a corrupt recent file.
402 * XXX - should we print a message about this?
404 return;
407 /* save / replace geometry in hashtable */
408 window_geom_save(name, &geom);
411 /** Write all geometry values of all windows to the recent file.
412 * Will call write_recent_geom() for every existing window type.
414 * @param rf recent file handle from caller
416 static void
417 window_geom_recent_write_all(FILE *rf)
419 /* init hashtable, if not already done */
420 if (!window_geom_hash) {
421 window_geom_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, window_geom_free);
424 g_hash_table_foreach(window_geom_hash, write_recent_geom, rf);
427 /** Write all known window splitter states to the recent file.
429 * @param rf recent file handle from caller
431 static void
432 window_splitter_recent_write_all(FILE *rf)
434 /* init hashtable, if not already done */
435 if (!window_splitter_hash) {
436 return;
439 GHashTableIter iter;
440 void *key, *value;
441 g_hash_table_iter_init(&iter, window_splitter_hash);
442 while (g_hash_table_iter_next(&iter, &key, &value)) {
443 fprintf(rf, "\n# Splitter state of %s window.\n", (char*)key);
444 fprintf(rf, "# Qt Splitter state (hex byte string).\n");
445 fprintf(rf, RECENT_GUI_GEOMETRY "%s.splitter: %s\n", (char*)key,
446 (char*)value);
450 /* Global list of recent capture filters. */
451 static GList *recent_cfilter_list;
454 * Per-interface lists of recent capture filters; stored in a hash
455 * table indexed by interface name.
457 static GHashTable *per_interface_cfilter_lists_hash;
459 /* XXX: use a preference for this setting! */
460 /* N.B.: If we use a pref, we will read the recent_common file
461 * before the pref, so don't truncate the list when reading
462 * (see the similar #16782 for the recent files.)
464 static unsigned cfilter_combo_max_recent = 20;
467 * Returns a list of recent capture filters.
469 * @param ifname interface name; NULL refers to the global list.
471 GList *
472 recent_get_cfilter_list(const char *ifname)
474 if (ifname == NULL)
475 return recent_cfilter_list;
476 if (per_interface_cfilter_lists_hash == NULL) {
477 /* No such lists exist. */
478 return NULL;
480 return (GList *)g_hash_table_lookup(per_interface_cfilter_lists_hash, ifname);
484 * Add a capture filter to the global recent capture filter list or
485 * the recent capture filter list for an interface.
487 * @param ifname interface name; NULL refers to the global list.
488 * @param s text of capture filter
490 void
491 recent_add_cfilter(const char *ifname, const char *s)
493 GList *cfilter_list;
494 GList *li;
495 char *li_filter, *newfilter = NULL;
497 /* Don't add empty filters to the list. */
498 if (s[0] == '\0')
499 return;
501 if (ifname == NULL)
502 cfilter_list = recent_cfilter_list;
503 else {
504 /* If we don't yet have a hash table for per-interface recent
505 capture filter lists, create one. Have it free the new key
506 if we're updating an entry rather than creating it below. */
507 if (per_interface_cfilter_lists_hash == NULL)
508 per_interface_cfilter_lists_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
509 cfilter_list = (GList *)g_hash_table_lookup(per_interface_cfilter_lists_hash, ifname);
512 li = g_list_first(cfilter_list);
513 while (li) {
514 /* If the filter is already in the list, remove the old one and
515 * append the new one at the latest position (at g_list_append() below) */
516 li_filter = (char *)li->data;
517 if (strcmp(s, li_filter) == 0) {
518 /* No need to copy the string, we're just moving it. */
519 newfilter = li_filter;
520 cfilter_list = g_list_remove(cfilter_list, li->data);
521 break;
523 li = li->next;
525 if (newfilter == NULL) {
526 /* The filter wasn't already in the list; make a copy to add. */
527 newfilter = g_strdup(s);
529 cfilter_list = g_list_prepend(cfilter_list, newfilter);
531 if (ifname == NULL)
532 recent_cfilter_list = cfilter_list;
533 else
534 g_hash_table_insert(per_interface_cfilter_lists_hash, g_strdup(ifname), cfilter_list);
537 #ifdef HAVE_PCAP_REMOTE
538 /* XXX: use a preference for this setting! */
539 /* N.B.: If we use a pref, we will read the recent_common file
540 * before the pref, so don't truncate the list when reading
541 * (see the similar #16782 for the recent files.)
543 static unsigned remote_host_max_recent = 20;
544 static GList *remote_host_list;
546 int recent_get_remote_host_list_size(void)
548 if (remote_host_list == NULL) {
549 /* No entries exist. */
550 return 0;
552 return g_list_length(remote_host_list);
555 static void
556 free_remote_host(void *value)
558 struct remote_host* rh = (struct remote_host*)value;
560 g_free(rh->r_host);
561 g_free(rh->remote_port);
562 g_free(rh->auth_username);
563 g_free(rh->auth_password);
567 static int
568 remote_host_compare(const void *a, const void *b)
570 const struct remote_host* rh_a = (const struct remote_host*)a;
571 const struct remote_host* rh_b = (const struct remote_host*)b;
573 /* We assume only one entry per host (the GUI assumes that too.) */
574 return g_strcmp0(rh_a->r_host, rh_b->r_host);
577 static void
578 remote_host_reverse(void)
580 if (remote_host_list) {
581 remote_host_list = g_list_reverse(remote_host_list);
585 void recent_add_remote_host(char *host _U_, struct remote_host *rh)
587 GList* li = NULL;
588 if (remote_host_list) {
589 li = g_list_find_custom(remote_host_list, rh, remote_host_compare);
590 if (li != NULL) {
591 free_remote_host(li->data);
592 remote_host_list = g_list_delete_link(remote_host_list, li);
595 remote_host_list = g_list_prepend(remote_host_list, rh);
598 void
599 recent_remote_host_list_foreach(GFunc func, void *user_data)
601 if (remote_host_list != NULL) {
602 g_list_foreach(remote_host_list, func, user_data);
606 static void
607 recent_print_remote_host(void *value, void *user)
609 FILE *rf = (FILE *)user;
610 struct remote_host_info *ri = (struct remote_host_info *)value;
612 fprintf (rf, RECENT_KEY_REMOTE_HOST ": %s,%s,%d\n", ri->remote_host, ri->remote_port, ri->auth_type);
616 * Write the contents of the remote_host_list to the 'recent' file.
618 * @param rf File to write to.
620 static void
621 capture_remote_combo_recent_write_all(FILE *rf)
623 unsigned max_count = 0;
624 GList *li = g_list_first(remote_host_list);
626 /* write all non empty remote capture hosts to the recent file (until max count) */
627 while (li && (max_count++ <= remote_host_max_recent)) {
628 recent_print_remote_host(li->data, rf);
629 li = li->next;
634 void recent_free_remote_host_list(void)
636 g_list_free_full(remote_host_list, free_remote_host);
637 remote_host_list = NULL;
640 struct remote_host *
641 recent_get_remote_host(const char *host)
643 if (host == NULL)
644 return NULL;
645 for (GList* li = g_list_first(remote_host_list); li != NULL; li = li->next) {
646 struct remote_host *rh = (struct remote_host*)li->data;
647 if (g_strcmp0(host, rh->r_host) == 0) {
648 return rh;
651 return NULL;
655 * Fill the remote_host_list with the entries stored in the 'recent' file.
657 * @param s String to be filled from the 'recent' file.
658 * @return True, if the list was written successfully, False otherwise.
660 static bool
661 capture_remote_combo_add_recent(const char *s)
663 GList *vals = prefs_get_string_list (s);
664 GList *valp = vals;
665 capture_auth auth_type;
666 char *p;
667 struct remote_host *rh;
669 if (valp == NULL)
670 return false;
672 /* First value is the host */
673 if (recent_get_remote_host(valp->data)) {
674 /* Don't add it, it's already in the list (shouldn't happen). */
675 return false; // Should this be true or false?
677 rh = (struct remote_host *) g_malloc (sizeof (*rh));
679 /* First value is the host */
680 rh->r_host = (char *)g_strdup ((const char *)valp->data);
681 if (strlen(rh->r_host) == 0) {
682 /* Empty remote host */
683 g_free(rh->r_host);
684 g_free(rh);
685 return false;
687 rh->auth_type = CAPTURE_AUTH_NULL;
688 valp = valp->next;
690 if (valp) {
691 /* Found value 2, this is the port number */
692 if (!strcmp((const char*)valp->data, "0")) {
693 /* Port 0 isn't valid, so leave port blank */
694 rh->remote_port = (char *)g_strdup ("");
695 } else {
696 rh->remote_port = (char *)g_strdup ((const char *)valp->data);
698 valp = valp->next;
699 } else {
700 /* Did not find a port number */
701 rh->remote_port = g_strdup ("");
704 if (valp) {
705 /* Found value 3, this is the authentication type */
706 auth_type = (capture_auth)strtol((const char *)valp->data, &p, 0);
707 if (p != valp->data && *p == '\0') {
708 rh->auth_type = auth_type;
712 /* Do not store username and password */
713 rh->auth_username = g_strdup ("");
714 rh->auth_password = g_strdup ("");
716 prefs_clear_string_list(vals);
718 remote_host_list = g_list_prepend(remote_host_list, rh);
719 return true;
721 #endif
723 static void
724 cfilter_recent_write_all_list(FILE *rf, const char *ifname, GList *cfilter_list)
726 unsigned max_count = 0;
727 GList *li;
729 /* write all non empty capture filter strings to the recent file (until max count) */
730 li = g_list_first(cfilter_list);
731 while (li && (max_count++ <= cfilter_combo_max_recent) ) {
732 if (li->data && strlen((const char *)li->data)) {
733 if (ifname == NULL)
734 fprintf (rf, RECENT_KEY_CAPTURE_FILTER ": %s\n", (char *)li->data);
735 else
736 fprintf (rf, RECENT_KEY_CAPTURE_FILTER ".%s: %s\n", ifname, (char *)li->data);
738 li = li->next;
742 static void
743 cfilter_recent_write_all_hash_callback(void *key, void *value, void *user_data)
745 cfilter_recent_write_all_list((FILE *)user_data, (const char *)key, (GList *)value);
748 /** Write all capture filter values to the recent file.
750 * @param rf recent file handle from caller
752 static void
753 cfilter_recent_write_all(FILE *rf)
755 /* Write out the global list. */
756 cfilter_recent_write_all_list(rf, NULL, recent_cfilter_list);
758 /* Write out all the per-interface lists. */
759 if (per_interface_cfilter_lists_hash != NULL) {
760 g_hash_table_foreach(per_interface_cfilter_lists_hash, cfilter_recent_write_all_hash_callback, (void *)rf);
764 /** Reverse the order of all the capture filter lists after
765 * reading recent_common (we want the latest first).
766 * Note this is O(N), whereas appendng N items to a GList is O(N^2),
767 * since it doesn't have a pointer to the end like a GQueue.
769 static void
770 cfilter_recent_reverse_all(void)
772 recent_cfilter_list = g_list_reverse(recent_cfilter_list);
774 /* Reverse all the per-interface lists. */
775 if (per_interface_cfilter_lists_hash != NULL) {
776 GHashTableIter iter;
777 void *key, *value;
778 g_hash_table_iter_init(&iter, per_interface_cfilter_lists_hash);
779 GList *li;
780 while (g_hash_table_iter_next(&iter, &key, &value)) {
781 li = (GList *)value;
782 li = g_list_reverse(li);
783 /* per_interface_cfilter_lists_hash was created without a
784 * value_destroy_func, so this is fine.
786 g_hash_table_iter_replace(&iter, li);
791 /* Write out recent settings of particular types. */
792 static void
793 write_recent_boolean(FILE *rf, const char *description, const char *name,
794 bool value)
796 fprintf(rf, "\n# %s.\n", description);
797 fprintf(rf, "# true or false (case-insensitive).\n");
798 fprintf(rf, "%s: %s\n", name, value == true ? "true" : "false");
801 static void
802 write_recent_enum(FILE *rf, const char *description, const char *name,
803 const value_string *values, unsigned value)
805 const char *if_invalid = NULL;
806 const value_string *valp;
807 const char *str_value;
809 fprintf(rf, "\n# %s.\n", description);
810 fprintf(rf, "# One of: ");
811 valp = values;
812 while (valp->strptr != NULL) {
813 if (if_invalid == NULL)
814 if_invalid = valp->strptr;
815 fprintf(rf, "%s", valp->strptr);
816 valp++;
817 if (valp->strptr != NULL)
818 fprintf(rf, ", ");
820 fprintf(rf, "\n");
821 str_value = try_val_to_str(value, values);
822 if (str_value != NULL)
823 fprintf(rf, "%s: %s\n", name, str_value);
824 else
825 fprintf(rf, "%s: %s\n", name, if_invalid != NULL ? if_invalid : "Unknown");
828 /* Attempt to write out "recent common" to the user's recent_common file.
829 If we got an error report it with a dialog box and return false,
830 otherwise return true. */
831 bool
832 write_recent(void)
834 char *pf_dir_path;
835 char *rf_path;
836 FILE *rf;
837 char *string_list;
839 /* To do:
840 * - Split output lines longer than MAX_VAL_LEN
841 * - Create a function for the preference directory check/creation
842 * so that duplication can be avoided with filter.c
845 /* Create the directory that holds personal configuration files, if
846 necessary. */
847 if (create_persconffile_dir(&pf_dir_path) == -1) {
848 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
849 "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
850 g_strerror(errno));
851 g_free(pf_dir_path);
852 return false;
855 rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, false);
856 if ((rf = ws_fopen(rf_path, "w")) == NULL) {
857 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
858 "Can't open recent file\n\"%s\": %s.", rf_path,
859 g_strerror(errno));
860 g_free(rf_path);
861 return false;
863 g_free(rf_path);
865 fprintf(rf, "# Common recent settings file for %s " VERSION ".\n"
866 "#\n"
867 "# This file is regenerated each time %s is quit\n"
868 "# and when changing configuration profile.\n"
869 "# So be careful, if you want to make manual changes here.\n"
870 "\n"
871 "######## Recent capture files (latest last), cannot be altered through command line ########\n"
872 "\n",
873 application_flavor_name_proper(), application_flavor_name_proper());
876 menu_recent_file_write_all(rf);
878 fputs("\n"
879 "######## Recent capture filters (latest first), cannot be altered through command line ########\n"
880 "\n", rf);
882 cfilter_recent_write_all(rf);
884 fputs("\n"
885 "######## Recent display filters (latest last), cannot be altered through command line ########\n"
886 "\n", rf);
888 dfilter_recent_combo_write_all(rf);
890 #ifdef HAVE_PCAP_REMOTE
891 fputs("\n"
892 "######## Recent remote hosts (latest first), cannot be altered through command line ########\n"
893 "\n", rf);
895 capture_remote_combo_recent_write_all(rf);
896 #endif
898 fprintf(rf, "\n# Main window geometry.\n");
899 fprintf(rf, "# Decimal numbers.\n");
900 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_X ": %d\n", recent.gui_geometry_main_x);
901 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_Y ": %d\n", recent.gui_geometry_main_y);
902 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_WIDTH ": %d\n",
903 recent.gui_geometry_main_width);
904 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_HEIGHT ": %d\n",
905 recent.gui_geometry_main_height);
907 write_recent_boolean(rf, "Main window maximized",
908 RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED,
909 recent.gui_geometry_main_maximized);
911 if (recent.gui_geometry_main != NULL) {
912 fprintf(rf, "\n# Main window geometry state.\n");
913 fprintf(rf, "# Hex byte string.\n");
914 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN ": %s\n",
915 recent.gui_geometry_main);
918 write_recent_boolean(rf, "Leftalign Action Buttons",
919 RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS,
920 recent.gui_geometry_leftalign_actions);
922 fprintf(rf, "\n# Last used Configuration Profile.\n");
923 fprintf(rf, RECENT_LAST_USED_PROFILE ": %s\n", get_profile_name());
925 fprintf(rf, "\n# Number of packets or events to check for automatic profile switching.\n");
926 fprintf(rf, "# Decimal number. Zero disables switching.\n");
927 const char * def_prefix = recent.gui_profile_switch_check_count == 1000 ? "#" : "";
928 fprintf(rf, "%s" RECENT_PROFILE_SWITCH_CHECK_COUNT ": %d\n", def_prefix,
929 recent.gui_profile_switch_check_count);
931 write_recent_boolean(rf, "Warn if running with elevated permissions (e.g. as root)",
932 RECENT_KEY_PRIVS_WARN_IF_ELEVATED,
933 recent.privs_warn_if_elevated);
935 write_recent_boolean(rf, "Warn if Wireshark is unable to capture",
936 RECENT_KEY_SYS_WARN_IF_NO_CAPTURE,
937 recent.sys_warn_if_no_capture);
939 write_recent_enum(rf, "Find packet search in", RECENT_GUI_SEARCH_IN, search_in_values,
940 recent.gui_search_in);
941 write_recent_enum(rf, "Find packet character set", RECENT_GUI_SEARCH_CHAR_SET, search_char_set_values,
942 recent.gui_search_char_set);
943 write_recent_boolean(rf, "Find packet case sensitive search",
944 RECENT_GUI_SEARCH_CASE_SENSITIVE,
945 recent.gui_search_case_sensitive);
946 write_recent_boolean(rf, "Find packet search reverse direction",
947 RECENT_GUI_SEARCH_REVERSE_DIR,
948 recent.gui_search_reverse_dir);
949 write_recent_boolean(rf, "Find packet search multiple occurrences",
950 RECENT_GUI_SEARCH_MULTIPLE_OCCURS,
951 recent.gui_search_multiple_occurs);
952 write_recent_enum(rf, "Find packet search type", RECENT_GUI_SEARCH_TYPE, search_type_values,
953 recent.gui_search_type);
955 window_geom_recent_write_all(rf);
957 fprintf(rf, "\n# Custom colors.\n");
958 fprintf(rf, "# List of custom colors selected in Qt color picker.\n");
959 string_list = join_string_list(recent.custom_colors);
960 fprintf(rf, RECENT_GUI_CUSTOM_COLORS ": %s\n", string_list);
961 g_free(string_list);
963 fclose(rf);
965 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
966 an error indication, or maybe write to a new recent file and
967 rename that file on top of the old one only if there are not I/O
968 errors. */
969 return true;
973 /* Attempt to Write out profile "recent" to the user's profile recent file.
974 If we got an error report it with a dialog box and return false,
975 otherwise return true. */
976 bool
977 write_profile_recent(void)
979 char *pf_dir_path;
980 char *rf_path;
981 char *string_list;
982 FILE *rf;
984 /* To do:
985 * - Split output lines longer than MAX_VAL_LEN
986 * - Create a function for the preference directory check/creation
987 * so that duplication can be avoided with filter.c
990 /* Create the directory that holds personal configuration files, if
991 necessary. */
992 if (create_persconffile_dir(&pf_dir_path) == -1) {
993 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
994 "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path,
995 g_strerror(errno));
996 g_free(pf_dir_path);
997 return false;
1000 rf_path = get_persconffile_path(RECENT_FILE_NAME, true);
1001 if ((rf = ws_fopen(rf_path, "w")) == NULL) {
1002 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1003 "Can't open recent file\n\"%s\": %s.", rf_path,
1004 g_strerror(errno));
1005 g_free(rf_path);
1006 return false;
1008 g_free(rf_path);
1010 fprintf(rf, "# Recent settings file for %s " VERSION ".\n"
1011 "#\n"
1012 "# This file is regenerated each time %s is quit\n"
1013 "# and when changing configuration profile.\n"
1014 "# So be careful, if you want to make manual changes here.\n"
1015 "\n",
1016 application_flavor_name_proper(), application_flavor_name_proper());
1018 write_recent_boolean(rf, "Main Toolbar show (hide)",
1019 RECENT_KEY_MAIN_TOOLBAR_SHOW,
1020 recent.main_toolbar_show);
1022 write_recent_boolean(rf, "Filter Toolbar show (hide)",
1023 RECENT_KEY_FILTER_TOOLBAR_SHOW,
1024 recent.filter_toolbar_show);
1026 write_recent_boolean(rf, "Wireless Settings Toolbar show (hide)",
1027 RECENT_KEY_WIRELESS_TOOLBAR_SHOW,
1028 recent.wireless_toolbar_show);
1030 write_recent_boolean(rf, "Packet list show (hide)",
1031 RECENT_KEY_PACKET_LIST_SHOW,
1032 recent.packet_list_show);
1034 write_recent_boolean(rf, "Tree view show (hide)",
1035 RECENT_KEY_TREE_VIEW_SHOW,
1036 recent.tree_view_show);
1038 write_recent_boolean(rf, "Byte view show (hide)",
1039 RECENT_KEY_BYTE_VIEW_SHOW,
1040 recent.byte_view_show);
1042 write_recent_boolean(rf, "Packet diagram show (hide)",
1043 RECENT_KEY_PACKET_DIAGRAM_SHOW,
1044 recent.packet_diagram_show);
1046 write_recent_boolean(rf, "Statusbar show (hide)",
1047 RECENT_KEY_STATUSBAR_SHOW,
1048 recent.statusbar_show);
1050 write_recent_boolean(rf, "Packet list colorize (hide)",
1051 RECENT_KEY_PACKET_LIST_COLORIZE,
1052 recent.packet_list_colorize);
1054 write_recent_boolean(rf, "Auto scroll packet list when capturing",
1055 RECENT_KEY_CAPTURE_AUTO_SCROLL,
1056 recent.capture_auto_scroll);
1058 write_recent_enum(rf, "Timestamp display format",
1059 RECENT_GUI_TIME_FORMAT, ts_type_values,
1060 recent.gui_time_format);
1063 * The value of this item is either TS_PREC_AUTO, which is a
1064 * negative number meaning "pick the display precision based
1065 * on the time stamp precision of the packet", or is a numerical
1066 * value giving the number of decimal places to display, from 0
1067 * to WS_TSPREC_MAX.
1069 * It used to be that not all values between 0 and 9 (the maximum
1070 * precision back then) were supported, and that names were
1071 * written out to the recent file.
1073 * For backwards compatibility with those older versions of
1074 * Wireshark, write out the names for those values, and the
1075 * raw number for other values.
1078 const char *if_invalid = NULL;
1079 const value_string *valp;
1080 const char *str_value;
1082 fprintf(rf, "\n# %s.\n", "Timestamp display precision");
1083 fprintf(rf, "# One of: ");
1084 valp = ts_precision_values;
1085 while (valp->strptr != NULL) {
1086 if (if_invalid == NULL)
1087 if_invalid = valp->strptr;
1088 fprintf(rf, "%s", valp->strptr);
1089 valp++;
1090 if (valp->strptr != NULL)
1091 fprintf(rf, ", ");
1093 fprintf(rf, ", or a number between 0 and %d\n", WS_TSPREC_MAX);
1095 str_value = try_val_to_str(recent.gui_time_precision, ts_precision_values);
1096 if (str_value != NULL)
1097 fprintf(rf, "%s: %s\n", RECENT_GUI_TIME_PRECISION, str_value);
1098 else {
1099 if (recent.gui_time_precision >= 0 && recent.gui_time_precision < WS_TSPREC_MAX)
1100 fprintf(rf, "%s: %d\n", RECENT_GUI_TIME_PRECISION, recent.gui_time_precision);
1101 else
1102 fprintf(rf, "%s: %s\n", RECENT_GUI_TIME_PRECISION, if_invalid != NULL ? if_invalid : "Unknown");
1106 write_recent_enum(rf, "Seconds display format",
1107 RECENT_GUI_SECONDS_FORMAT, ts_seconds_values,
1108 recent.gui_seconds_format);
1110 fprintf(rf, "\n# Zoom level.\n");
1111 fprintf(rf, "# A decimal number.\n");
1112 fprintf(rf, RECENT_GUI_ZOOM_LEVEL ": %d\n",
1113 recent.gui_zoom_level);
1115 write_recent_enum(rf, "Bytes view display type",
1116 RECENT_GUI_BYTES_VIEW, bytes_view_type_values,
1117 recent.gui_bytes_view);
1119 write_recent_enum(rf, "Bytes view text encoding",
1120 RECENT_GUI_BYTES_ENCODING, bytes_encoding_type_values,
1121 recent.gui_bytes_encoding);
1123 write_recent_boolean(rf, "Packet diagram field values show (hide)",
1124 RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES,
1125 recent.gui_packet_diagram_field_values);
1127 write_recent_boolean(rf, "Allow hover selection in byte view",
1128 RECENT_GUI_ALLOW_HOVER_SELECTION,
1129 recent.gui_allow_hover_selection);
1131 write_recent_enum(rf, "Follow stream show as",
1132 RECENT_GUI_FOLLOW_SHOW, bytes_show_values,
1133 recent.gui_follow_show);
1135 write_recent_enum(rf, "Follow stream delta times",
1136 RECENT_GUI_FOLLOW_DELTA, follow_delta_values,
1137 recent.gui_follow_delta);
1139 write_recent_enum(rf, "Show packet bytes decode as",
1140 RECENT_GUI_SHOW_BYTES_DECODE, show_bytes_decode_values,
1141 recent.gui_show_bytes_decode);
1143 write_recent_enum(rf, "Show packet bytes show as",
1144 RECENT_GUI_SHOW_BYTES_SHOW, bytes_show_values,
1145 recent.gui_show_bytes_show);
1147 fprintf(rf, "\n# Main window upper (or leftmost) pane size.\n");
1148 fprintf(rf, "# Decimal number.\n");
1149 if (recent.gui_geometry_main_upper_pane != 0) {
1150 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE ": %d\n",
1151 recent.gui_geometry_main_upper_pane);
1153 fprintf(rf, "\n# Main window middle pane size.\n");
1154 fprintf(rf, "# Decimal number.\n");
1155 if (recent.gui_geometry_main_lower_pane != 0) {
1156 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE ": %d\n",
1157 recent.gui_geometry_main_lower_pane);
1160 if (recent.gui_geometry_main_master_split != NULL) {
1161 fprintf(rf, "\n# Main window master splitter state.\n");
1162 fprintf(rf, "# Hex byte string.\n");
1163 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT ": %s\n",
1164 recent.gui_geometry_main_master_split);
1167 if (recent.gui_geometry_main_extra_split != NULL) {
1168 fprintf(rf, "\n# Main window extra splitter state.\n");
1169 fprintf(rf, "# Hex byte string.\n");
1170 fprintf(rf, RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT ": %s\n",
1171 recent.gui_geometry_main_extra_split);
1174 window_splitter_recent_write_all(rf);
1176 fprintf(rf, "\n# Packet list column pixel widths.\n");
1177 fprintf(rf, "# Each pair of strings consists of a column format and its pixel width.\n");
1178 packet_list_recent_write_all(rf);
1180 fprintf(rf, "\n# Open conversation dialog tabs.\n");
1181 fprintf(rf, "# List of conversation names, e.g. \"TCP\", \"IPv6\".\n");
1182 string_list = join_string_list(recent.conversation_tabs);
1183 fprintf(rf, RECENT_GUI_CONVERSATION_TABS ": %s\n", string_list);
1184 g_free(string_list);
1186 fprintf(rf, "\n# Conversation dialog tabs columns.\n");
1187 fprintf(rf, "# List of conversation columns numbers.\n");
1188 string_list = join_string_list(recent.conversation_tabs_columns);
1189 fprintf(rf, RECENT_GUI_CONVERSATION_TABS_COLUMNS ": %s\n", string_list);
1190 g_free(string_list);
1192 fprintf(rf, "\n# Open endpoint dialog tabs.\n");
1193 fprintf(rf, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
1194 string_list = join_string_list(recent.endpoint_tabs);
1195 fprintf(rf, RECENT_GUI_ENDPOINT_TABS ": %s\n", string_list);
1196 g_free(string_list);
1198 fprintf(rf, "\n# Endpoint dialog tabs columns.\n");
1199 fprintf(rf, "# List of endpoint columns numbers.\n");
1200 string_list = join_string_list(recent.endpoint_tabs_columns);
1201 fprintf(rf, RECENT_GUI_ENDPOINT_TABS_COLUMNS ": %s\n", string_list);
1202 g_free(string_list);
1204 write_recent_boolean(rf, "For RLC stats, whether to use RLC PDUs found inside MAC frames",
1205 RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES,
1206 recent.gui_rlc_use_pdus_from_mac);
1208 if (get_last_open_dir() != NULL) {
1209 fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
1210 fprintf(rf, RECENT_GUI_FILEOPEN_REMEMBERED_DIR ": %s\n", get_last_open_dir());
1213 fprintf(rf, "\n# Additional Toolbars shown\n");
1214 fprintf(rf, "# List of additional toolbars to show.\n");
1215 string_list = join_string_list(recent.gui_additional_toolbars);
1216 fprintf(rf, RECENT_GUI_TOOLBAR_SHOW ": %s\n", string_list);
1217 g_free(string_list);
1219 fprintf(rf, "\n# Interface Toolbars show.\n");
1220 fprintf(rf, "# List of interface toolbars to show.\n");
1221 string_list = join_string_list(recent.interface_toolbars);
1222 fprintf(rf, RECENT_GUI_INTERFACE_TOOLBAR_SHOW ": %s\n", string_list);
1223 g_free(string_list);
1225 fclose(rf);
1227 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
1228 an error indication, or maybe write to a new recent file and
1229 rename that file on top of the old one only if there are not I/O
1230 errors. */
1231 return true;
1234 /* set one user's recent common file key/value pair */
1235 static prefs_set_pref_e
1236 read_set_recent_common_pair_static(char *key, const char *value,
1237 void *private_data _U_,
1238 bool return_range_errors _U_)
1240 long num;
1241 char *p;
1243 if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED) == 0) {
1244 parse_recent_boolean(value, &recent.gui_geometry_main_maximized);
1245 } else if (strcmp(key, RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS) == 0) {
1246 parse_recent_boolean(value, &recent.gui_geometry_leftalign_actions);
1247 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_X) == 0) {
1248 num = strtol(value, &p, 0);
1249 if (p == value || *p != '\0')
1250 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1251 recent.gui_geometry_main_x = (int)num;
1252 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_Y) == 0) {
1253 num = strtol(value, &p, 0);
1254 if (p == value || *p != '\0')
1255 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1256 recent.gui_geometry_main_y = (int)num;
1257 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_WIDTH) == 0) {
1258 num = strtol(value, &p, 0);
1259 if (p == value || *p != '\0')
1260 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1261 if (num <= 0)
1262 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1263 recent.gui_geometry_main_width = (int)num;
1264 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {
1265 num = strtol(value, &p, 0);
1266 if (p == value || *p != '\0')
1267 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1268 if (num <= 0)
1269 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1270 recent.gui_geometry_main_height = (int)num;
1271 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN) == 0) {
1272 g_free(recent.gui_geometry_main);
1273 recent.gui_geometry_main = g_strdup(value);
1274 } else if (strcmp(key, RECENT_LAST_USED_PROFILE) == 0) {
1275 if ((strcmp(value, DEFAULT_PROFILE) != 0) && profile_exists (value, false)) {
1276 set_profile_name (value);
1278 } else if (strcmp(key, RECENT_PROFILE_SWITCH_CHECK_COUNT) == 0) {
1279 num = strtol(value, &p, 0);
1280 if (p == value || *p != '\0')
1281 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1282 if (num <= 0)
1283 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1284 recent.gui_profile_switch_check_count = (int)num;
1285 } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
1286 /* now have something like "gui.geom.main.x", split it into win and sub_key */
1287 char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
1288 char *sub_key = strchr(win, '.');
1289 if (sub_key) {
1290 *sub_key = '\0';
1291 sub_key++;
1292 window_geom_recent_read_pair(win, sub_key, value);
1294 } else if (strcmp(key, RECENT_KEY_PRIVS_WARN_IF_ELEVATED) == 0) {
1295 parse_recent_boolean(value, &recent.privs_warn_if_elevated);
1296 } else if (strcmp(key, RECENT_KEY_SYS_WARN_IF_NO_CAPTURE) == 0) {
1297 parse_recent_boolean(value, &recent.sys_warn_if_no_capture);
1298 } else if (strcmp(key, RECENT_GUI_SEARCH_IN) == 0) {
1299 recent.gui_search_in = (search_in_type)str_to_val(value, search_in_values, SEARCH_IN_PACKET_LIST);
1300 } else if (strcmp(key, RECENT_GUI_SEARCH_CHAR_SET) == 0) {
1301 recent.gui_search_char_set = (search_char_set_type)str_to_val(value, search_char_set_values, SEARCH_CHAR_SET_NARROW_AND_WIDE);
1302 } else if (strcmp(key, RECENT_GUI_SEARCH_CASE_SENSITIVE) == 0) {
1303 parse_recent_boolean(value, &recent.gui_search_case_sensitive);
1304 } else if (strcmp(key, RECENT_GUI_SEARCH_REVERSE_DIR) == 0) {
1305 parse_recent_boolean(value, &recent.gui_search_reverse_dir);
1306 } else if (strcmp(key, RECENT_GUI_SEARCH_MULTIPLE_OCCURS) == 0) {
1307 parse_recent_boolean(value, &recent.gui_search_multiple_occurs);
1308 } else if (strcmp(key, RECENT_GUI_SEARCH_TYPE) == 0) {
1309 recent.gui_search_type = (search_type_type)str_to_val(value, search_type_values, SEARCH_TYPE_DISPLAY_FILTER);
1310 } else if (strcmp(key, RECENT_GUI_CUSTOM_COLORS) == 0) {
1311 recent.custom_colors = prefs_get_string_list(value);
1314 return PREFS_SET_OK;
1317 /* set one user's recent file key/value pair */
1318 static prefs_set_pref_e
1319 read_set_recent_pair_static(char *key, const char *value,
1320 void *private_data _U_,
1321 bool return_range_errors _U_)
1323 long num;
1324 int32_t num_int32;
1325 char *p;
1326 GList *col_l, *col_l_elt;
1327 col_width_data *cfmt;
1329 if (strcmp(key, RECENT_KEY_MAIN_TOOLBAR_SHOW) == 0) {
1330 parse_recent_boolean(value, &recent.main_toolbar_show);
1331 } else if (strcmp(key, RECENT_KEY_FILTER_TOOLBAR_SHOW) == 0) {
1332 parse_recent_boolean(value, &recent.filter_toolbar_show);
1333 /* check both the old and the new keyword */
1334 } else if (strcmp(key, RECENT_KEY_WIRELESS_TOOLBAR_SHOW) == 0 || (strcmp(key, "gui.airpcap_toolbar_show") == 0)) {
1335 parse_recent_boolean(value, &recent.wireless_toolbar_show);
1336 } else if (strcmp(key, RECENT_KEY_PACKET_LIST_SHOW) == 0) {
1337 parse_recent_boolean(value, &recent.packet_list_show);
1338 } else if (strcmp(key, RECENT_KEY_TREE_VIEW_SHOW) == 0) {
1339 parse_recent_boolean(value, &recent.tree_view_show);
1340 } else if (strcmp(key, RECENT_KEY_BYTE_VIEW_SHOW) == 0) {
1341 parse_recent_boolean(value, &recent.byte_view_show);
1342 } else if (strcmp(key, RECENT_KEY_PACKET_DIAGRAM_SHOW) == 0) {
1343 parse_recent_boolean(value, &recent.packet_diagram_show);
1344 } else if (strcmp(key, RECENT_KEY_STATUSBAR_SHOW) == 0) {
1345 parse_recent_boolean(value, &recent.statusbar_show);
1346 } else if (strcmp(key, RECENT_KEY_PACKET_LIST_COLORIZE) == 0) {
1347 parse_recent_boolean(value, &recent.packet_list_colorize);
1348 } else if (strcmp(key, RECENT_KEY_CAPTURE_AUTO_SCROLL) == 0) {
1349 parse_recent_boolean(value, &recent.capture_auto_scroll);
1350 } else if (strcmp(key, RECENT_GUI_TIME_FORMAT) == 0) {
1351 recent.gui_time_format = (ts_type)str_to_val(value, ts_type_values,
1352 application_flavor_is_wireshark() ? TS_RELATIVE : TS_ABSOLUTE);
1353 } else if (strcmp(key, RECENT_GUI_TIME_PRECISION) == 0) {
1355 * The value of this item is either TS_PREC_AUTO, which is a
1356 * negative number meaning "pick the display precision based
1357 * on the time stamp precision of the packet", or is a numerical
1358 * value giving the number of decimal places to display, from 0
1359 * to WS_TSPREC_MAX.
1361 * It used to be that not all values between 0 and 9 (the maximum
1362 * precision back then) were supported, and that names were
1363 * written out to the recent file.
1365 * If the string value is a valid number in that range, use
1366 * that number, otherwise look it up in the table of names,
1367 * and, if that fails, set it to TS_PREC_AUTO.
1369 if (ws_strtoi32(value, NULL, &num_int32) && num_int32 >= 0 &&
1370 num_int32 <= WS_TSPREC_MAX) {
1371 recent.gui_time_precision = num_int32;
1372 } else {
1373 recent.gui_time_precision =
1374 (ts_precision)str_to_val(value, ts_precision_values, TS_PREC_AUTO);
1376 } else if (strcmp(key, RECENT_GUI_SECONDS_FORMAT) == 0) {
1377 recent.gui_seconds_format =
1378 (ts_seconds_type)str_to_val(value, ts_seconds_values, TS_SECONDS_DEFAULT);
1379 } else if (strcmp(key, RECENT_GUI_ZOOM_LEVEL) == 0) {
1380 num = strtol(value, &p, 0);
1381 if (p == value || *p != '\0')
1382 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1383 recent.gui_zoom_level = (int)num;
1384 } else if (strcmp(key, RECENT_GUI_BYTES_VIEW) == 0) {
1385 recent.gui_bytes_view =
1386 (bytes_view_type)str_to_val(value, bytes_view_type_values, BYTES_HEX);
1387 } else if (strcmp(key, RECENT_GUI_BYTES_ENCODING) == 0) {
1388 recent.gui_bytes_encoding =
1389 (bytes_encoding_type)str_to_val(value, bytes_encoding_type_values, BYTES_ENC_FROM_PACKET);
1390 } else if (strcmp(key, RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES) == 0) {
1391 parse_recent_boolean(value, &recent.gui_packet_diagram_field_values);
1392 } else if (strcmp(key, RECENT_GUI_ALLOW_HOVER_SELECTION) == 0) {
1393 parse_recent_boolean(value, &recent.gui_allow_hover_selection);
1394 } else if (strcmp(key, RECENT_GUI_FOLLOW_SHOW) == 0) {
1395 recent.gui_follow_show = (bytes_show_type)str_to_val(value, bytes_show_values, SHOW_ASCII);
1396 } else if (strcmp(key, RECENT_GUI_FOLLOW_DELTA) == 0) {
1397 recent.gui_follow_delta = (follow_delta_type)str_to_val(value, follow_delta_values, FOLLOW_DELTA_NONE);
1398 } else if (strcmp(key, RECENT_GUI_SHOW_BYTES_DECODE) == 0) {
1399 recent.gui_show_bytes_decode = (bytes_decode_type)str_to_val(value, show_bytes_decode_values, DecodeAsNone);
1400 } else if (strcmp(key, RECENT_GUI_SHOW_BYTES_SHOW) == 0) {
1401 recent.gui_show_bytes_show = (bytes_show_type)str_to_val(value, bytes_show_values, SHOW_ASCII);
1402 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE) == 0) {
1403 num = strtol(value, &p, 0);
1404 if (p == value || *p != '\0')
1405 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1406 if (num <= 0)
1407 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1408 recent.gui_geometry_main_upper_pane = (int)num;
1409 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE) == 0) {
1410 num = strtol(value, &p, 0);
1411 if (p == value || *p != '\0')
1412 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1413 if (num <= 0)
1414 return PREFS_SET_SYNTAX_ERR; /* number must be positive */
1415 recent.gui_geometry_main_lower_pane = (int)num;
1416 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT) == 0) {
1417 g_free(recent.gui_geometry_main_master_split);
1418 recent.gui_geometry_main_master_split = g_strdup(value);
1419 } else if (strcmp(key, RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT) == 0) {
1420 g_free(recent.gui_geometry_main_extra_split);
1421 recent.gui_geometry_main_extra_split = g_strdup(value);
1422 } else if (strncmp(key, RECENT_GUI_GEOMETRY, sizeof(RECENT_GUI_GEOMETRY)-1) == 0) {
1423 /* now have something like "gui.geom.win.sub_key", split it into win and sub_key */
1424 char *win = &key[sizeof(RECENT_GUI_GEOMETRY)-1];
1425 char *sub_key = strchr(win, '.');
1426 if (sub_key) {
1427 *sub_key = '\0';
1428 sub_key++;
1429 window_geom_recent_read_pair(win, sub_key, value);
1431 } else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS) == 0) {
1432 g_list_free_full(recent.conversation_tabs, g_free);
1433 recent.conversation_tabs = prefs_get_string_list(value);
1434 } else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS_COLUMNS) == 0) {
1435 g_list_free_full(recent.conversation_tabs_columns, g_free);
1436 recent.conversation_tabs_columns = prefs_get_string_list(value);
1437 } else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS) == 0) {
1438 g_list_free_full(recent.endpoint_tabs, g_free);
1439 recent.endpoint_tabs = prefs_get_string_list(value);
1440 } else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS_COLUMNS) == 0) {
1441 g_list_free_full(recent.endpoint_tabs_columns, g_free);
1442 recent.endpoint_tabs_columns = prefs_get_string_list(value);
1443 } else if (strcmp(key, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES) == 0) {
1444 parse_recent_boolean(value, &recent.gui_rlc_use_pdus_from_mac);
1445 } else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) {
1446 col_l = prefs_get_string_list(value);
1447 if (col_l == NULL)
1448 return PREFS_SET_SYNTAX_ERR;
1449 if ((g_list_length(col_l) % 2) != 0) {
1450 /* A title didn't have a matching width. */
1451 prefs_clear_string_list(col_l);
1452 return PREFS_SET_SYNTAX_ERR;
1454 recent_free_column_width_info(&recent);
1455 recent.col_width_list = NULL;
1456 col_l_elt = g_list_first(col_l);
1457 while (col_l_elt) {
1458 cfmt = g_new(col_width_data, 1);
1459 /* Skip the column format, we don't use it anymore because the
1460 * column indices are in sync and the key since 4.4. Format is
1461 * still written for backwards compatibility.
1463 col_l_elt = col_l_elt->next;
1464 cfmt->width = (int)strtol((const char *)col_l_elt->data, &p, 0);
1465 if (p == col_l_elt->data || (*p != '\0' && *p != ':')) {
1466 g_free(cfmt);
1467 return PREFS_SET_SYNTAX_ERR; /* number was bad */
1470 if (*p == ':') {
1471 cfmt->xalign = *(++p);
1472 } else {
1473 cfmt->xalign = COLUMN_XALIGN_DEFAULT;
1476 col_l_elt = col_l_elt->next;
1477 recent.col_width_list = g_list_append(recent.col_width_list, cfmt);
1479 prefs_clear_string_list(col_l);
1480 } else if (strcmp(key, RECENT_GUI_FILEOPEN_REMEMBERED_DIR) == 0) {
1481 g_free(recent.gui_fileopen_remembered_dir);
1482 recent.gui_fileopen_remembered_dir = g_strdup(value);
1483 } else if (strcmp(key, RECENT_GUI_TOOLBAR_SHOW) == 0) {
1484 recent.gui_additional_toolbars = prefs_get_string_list(value);
1485 } else if (strcmp(key, RECENT_GUI_INTERFACE_TOOLBAR_SHOW) == 0) {
1486 recent.interface_toolbars = prefs_get_string_list(value);
1487 } else {
1488 return PREFS_SET_NO_SUCH_PREF;
1491 return PREFS_SET_OK;
1495 /* set one user's recent file key/value pair */
1496 static prefs_set_pref_e
1497 read_set_recent_pair_dynamic(char *key, const char *value,
1498 void *private_data _U_,
1499 bool return_range_errors _U_)
1501 if (!g_utf8_validate(value, -1, NULL)) {
1502 return PREFS_SET_SYNTAX_ERR;
1504 if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) {
1505 add_menu_recent_capture_file(value, true);
1506 } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) {
1507 dfilter_combo_add_recent(value);
1508 } else if (strcmp(key, RECENT_KEY_CAPTURE_FILTER) == 0) {
1509 recent_add_cfilter(NULL, value);
1510 } else if (g_str_has_prefix(key, RECENT_KEY_CAPTURE_FILTER ".")) {
1511 /* strrchr() can't fail - string has a prefix that ends with a "." */
1512 recent_add_cfilter(strrchr(key, '.') + 1, value);
1513 #ifdef HAVE_PCAP_REMOTE
1514 } else if (strcmp(key, RECENT_KEY_REMOTE_HOST) == 0) {
1515 capture_remote_combo_add_recent(value);
1516 #endif
1519 return PREFS_SET_OK;
1524 * Given a string of the form "<recent name>:<recent value>", as might appear
1525 * as an argument to a "-o" option, parse it and set the recent value in
1526 * question. Return an indication of whether it succeeded or failed
1527 * in some fashion.
1530 recent_set_arg(char *prefarg)
1532 char *p, *colonp;
1533 int ret;
1535 colonp = strchr(prefarg, ':');
1536 if (colonp == NULL)
1537 return PREFS_SET_SYNTAX_ERR;
1539 p = colonp;
1540 *p++ = '\0';
1543 * Skip over any white space (there probably won't be any, but
1544 * as we allow it in the preferences file, we might as well
1545 * allow it here).
1547 while (g_ascii_isspace(*p))
1548 p++;
1549 if (*p == '\0') {
1551 * Put the colon back, so if our caller uses, in an
1552 * error message, the string they passed us, the message
1553 * looks correct.
1555 *colonp = ':';
1556 return PREFS_SET_SYNTAX_ERR;
1559 ret = read_set_recent_pair_static(prefarg, p, NULL, true);
1560 *colonp = ':'; /* put the colon back */
1561 return ret;
1565 /* opens the user's recent common file and read the first part */
1566 bool
1567 recent_read_static(char **rf_path_return, int *rf_errno_return)
1569 char *rf_path;
1570 FILE *rf;
1572 /* set defaults */
1573 recent.gui_geometry_main_x = 20;
1574 recent.gui_geometry_main_y = 20;
1575 recent.gui_geometry_main_width = DEF_WIDTH;
1576 recent.gui_geometry_main_height = DEF_HEIGHT;
1577 recent.gui_geometry_main_maximized= false;
1579 recent.gui_geometry_leftalign_actions = false;
1581 recent.privs_warn_if_elevated = true;
1582 recent.sys_warn_if_no_capture = true;
1584 recent.col_width_list = NULL;
1585 recent.gui_geometry_main = NULL;
1586 recent.gui_geometry_main_master_split = NULL;
1587 recent.gui_geometry_main_extra_split = NULL;
1588 recent.gui_profile_switch_check_count = 1000;
1589 recent.gui_fileopen_remembered_dir = NULL;
1591 /* Construct the pathname of the user's recent common file. */
1592 rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, false);
1594 /* Read the user's recent common file, if it exists. */
1595 *rf_path_return = NULL;
1596 if ((rf = ws_fopen(rf_path, "r")) != NULL) {
1597 /* We succeeded in opening it; read it. */
1598 read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
1600 fclose(rf);
1601 } else {
1602 /* We failed to open it. If we failed for some reason other than
1603 "it doesn't exist", return the errno and the pathname, so our
1604 caller can report the error. */
1605 if (errno != ENOENT) {
1606 *rf_errno_return = errno;
1607 *rf_path_return = rf_path;
1608 return false;
1611 g_free(rf_path);
1612 return true;
1617 /* opens the user's recent file and read the first part */
1618 bool
1619 recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
1621 char *rf_path, *rf_common_path;
1622 FILE *rf;
1624 /* set defaults */
1625 recent.main_toolbar_show = true;
1626 recent.filter_toolbar_show = true;
1627 recent.wireless_toolbar_show = false;
1628 recent.packet_list_show = true;
1629 recent.tree_view_show = true;
1630 recent.byte_view_show = true;
1631 recent.packet_diagram_show = true;
1632 recent.statusbar_show = true;
1633 recent.packet_list_colorize = true;
1634 recent.capture_auto_scroll = true;
1635 recent.gui_time_format = TS_RELATIVE;
1636 recent.gui_time_precision = TS_PREC_AUTO;
1637 recent.gui_seconds_format = TS_SECONDS_DEFAULT;
1638 recent.gui_zoom_level = 0;
1639 recent.gui_bytes_view = BYTES_HEX;
1640 recent.gui_bytes_encoding = BYTES_ENC_FROM_PACKET;
1641 recent.gui_allow_hover_selection = true;
1642 recent.gui_follow_show = SHOW_ASCII;
1643 recent.gui_follow_delta = FOLLOW_DELTA_NONE;
1644 recent.gui_show_bytes_decode = DecodeAsNone;
1645 recent.gui_show_bytes_show = SHOW_ASCII;
1647 /* pane size of zero will autodetect */
1648 recent.gui_geometry_main_upper_pane = 0;
1649 recent.gui_geometry_main_lower_pane = 0;
1651 if (recent.gui_geometry_main) {
1652 g_free(recent.gui_geometry_main);
1653 recent.gui_geometry_main = NULL;
1656 if (recent.gui_geometry_main_master_split) {
1657 g_free(recent.gui_geometry_main_master_split);
1658 recent.gui_geometry_main_master_split = NULL;
1660 if (recent.gui_geometry_main_extra_split) {
1661 g_free(recent.gui_geometry_main_extra_split);
1662 recent.gui_geometry_main_extra_split = NULL;
1665 if (recent.col_width_list) {
1666 recent_free_column_width_info(&recent);
1669 if (recent.gui_fileopen_remembered_dir) {
1670 g_free (recent.gui_fileopen_remembered_dir);
1671 recent.gui_fileopen_remembered_dir = NULL;
1674 if (recent.gui_additional_toolbars) {
1675 g_list_free_full (recent.gui_additional_toolbars, g_free);
1676 recent.gui_additional_toolbars = NULL;
1679 if (recent.interface_toolbars) {
1680 g_list_free_full (recent.interface_toolbars, g_free);
1681 recent.interface_toolbars = NULL;
1684 /* Construct the pathname of the user's profile recent file. */
1685 rf_path = get_persconffile_path(RECENT_FILE_NAME, true);
1687 /* Read the user's recent file, if it exists. */
1688 *rf_path_return = NULL;
1689 if ((rf = ws_fopen(rf_path, "r")) != NULL) {
1690 /* We succeeded in opening it; read it. */
1691 read_prefs_file(rf_path, rf, read_set_recent_pair_static, NULL);
1692 fclose(rf);
1694 /* XXX: The following code doesn't actually do anything since
1695 * the "recent common file" always exists. Presumably the
1696 * "if (!file_exists())" should actually be "if (file_exists())".
1697 * However, I've left the code as is because this
1698 * behaviour has existed for quite some time and I don't
1699 * know what's supposed to happen at this point.
1700 * ToDo: Determine if the "recent common file" should be read at this point
1702 rf_common_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, false);
1703 if (!file_exists(rf_common_path)) {
1704 /* Read older common settings from recent file */
1705 rf = ws_fopen(rf_path, "r");
1706 read_prefs_file(rf_path, rf, read_set_recent_common_pair_static, NULL);
1707 fclose(rf);
1709 g_free(rf_common_path);
1710 } else {
1711 /* We failed to open it. If we failed for some reason other than
1712 "it doesn't exist", return the errno and the pathname, so our
1713 caller can report the error. */
1714 if (errno != ENOENT) {
1715 *rf_errno_return = errno;
1716 *rf_path_return = rf_path;
1717 return false;
1720 g_free(rf_path);
1721 return true;
1724 /* opens the user's recent file and read it out */
1725 bool
1726 recent_read_dynamic(char **rf_path_return, int *rf_errno_return)
1728 char *rf_path;
1729 FILE *rf;
1732 /* Construct the pathname of the user's recent common file. */
1733 rf_path = get_persconffile_path(RECENT_COMMON_FILE_NAME, false);
1734 if (!file_exists (rf_path)) {
1735 /* Recent common file does not exist, read from default recent */
1736 g_free (rf_path);
1737 rf_path = get_persconffile_path(RECENT_FILE_NAME, false);
1740 /* Read the user's recent file, if it exists. */
1741 *rf_path_return = NULL;
1742 if ((rf = ws_fopen(rf_path, "r")) != NULL) {
1743 /* We succeeded in opening it; read it. */
1744 read_prefs_file(rf_path, rf, read_set_recent_pair_dynamic, NULL);
1745 #if 0
1746 /* set dfilter combobox to have an empty line */
1747 dfilter_combo_add_empty();
1748 #endif
1749 /* We prepend new capture filters, so reverse them after adding
1750 * all to keep the latest first.
1752 cfilter_recent_reverse_all();
1753 #ifdef HAVE_PCAP_REMOTE
1754 remote_host_reverse();
1755 #endif
1756 fclose(rf);
1757 } else {
1758 /* We failed to open it. If we failed for some reason other than
1759 "it doesn't exist", return the errno and the pathname, so our
1760 caller can report the error. */
1761 if (errno != ENOENT) {
1762 *rf_errno_return = errno;
1763 *rf_path_return = rf_path;
1764 return false;
1767 g_free(rf_path);
1768 return true;
1771 void
1772 recent_insert_column(int col)
1774 col_width_data *col_w;
1776 col_w = g_new(col_width_data, 1);
1777 col_w->width = -1;
1778 col_w->xalign = COLUMN_XALIGN_DEFAULT;
1779 recent.col_width_list = g_list_insert(recent.col_width_list, col_w, col);
1782 void
1783 recent_remove_column(int col)
1785 GList *col_l = g_list_nth(recent.col_width_list, col);
1786 col_width_data *col_w;
1788 if (!col_l) return;
1790 col_w = (col_width_data*)col_l->data;
1792 if (col_w) {
1793 free_col_width_data(col_w);
1796 recent.col_width_list = g_list_delete_link(recent.col_width_list, col_l);
1800 recent_get_column_width(int col)
1802 col_width_data *col_w;
1804 col_w = g_list_nth_data(recent.col_width_list, col);
1805 if (col_w) {
1806 return col_w->width;
1807 } else {
1808 /* Make sure the recent column list isn't out of sync with the
1809 * number of columns (e.g., for a brand new profile.)
1811 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1812 recent_insert_column(colnr);
1816 return -1;
1819 void
1820 recent_set_column_width(int col, int width)
1822 col_width_data *col_w;
1824 col_w = g_list_nth_data(recent.col_width_list, col);
1825 if (col_w) {
1826 col_w->width = width;
1827 } else {
1828 /* Make sure the recent column list isn't out of sync with the
1829 * number of columns (e.g., for a brand new profile.)
1831 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1832 recent_insert_column(colnr);
1834 col_w = g_list_nth_data(recent.col_width_list, col);
1835 if (col_w) {
1836 col_w->width = width;
1841 char
1842 recent_get_column_xalign(int col)
1844 col_width_data *col_w;
1846 col_w = g_list_nth_data(recent.col_width_list, col);
1847 if (col_w) {
1848 return col_w->xalign;
1849 } else {
1850 /* Make sure the recent column list isn't out of sync with the
1851 * number of columns (e.g., for a brand new profile.)
1853 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1854 recent_insert_column(colnr);
1858 return COLUMN_XALIGN_DEFAULT;
1861 void
1862 recent_set_column_xalign(int col, char xalign)
1864 col_width_data *col_w;
1866 col_w = g_list_nth_data(recent.col_width_list, col);
1867 if (col_w) {
1868 col_w->xalign = xalign;
1869 } else {
1870 /* Make sure the recent column list isn't out of sync with the
1871 * number of columns (e.g., for a brand new profile.)
1873 for (unsigned colnr = g_list_length(recent.col_width_list); colnr < g_list_length(prefs.col_list); colnr++) {
1874 recent_insert_column(colnr);
1876 col_w = g_list_nth_data(recent.col_width_list, col);
1877 if (col_w) {
1878 col_w->xalign = xalign;
1883 void
1884 recent_init(void)
1886 memset(&recent, 0, sizeof(recent_settings_t));
1889 void
1890 recent_cleanup(void)
1892 recent_free_column_width_info(&recent);
1893 g_free(recent.gui_geometry_main);
1894 g_free(recent.gui_geometry_main_master_split);
1895 g_free(recent.gui_geometry_main_extra_split);
1896 g_free(recent.gui_fileopen_remembered_dir);
1897 g_list_free_full(recent.gui_additional_toolbars, g_free);
1898 g_list_free_full(recent.interface_toolbars, g_free);
1899 prefs_clear_string_list(recent.conversation_tabs);
1900 prefs_clear_string_list(recent.conversation_tabs_columns);
1901 prefs_clear_string_list(recent.endpoint_tabs);
1902 prefs_clear_string_list(recent.endpoint_tabs_columns);
1903 prefs_clear_string_list(recent.custom_colors);