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
14 #include <wireshark.h>
19 #ifdef HAVE_PCAP_REMOTE
20 #include <capture_opts.h>
22 #include <wsutil/filesystem.h>
23 #include <epan/prefs.h>
24 #include <epan/prefs-int.h>
25 #include <epan/column.h>
26 #include <epan/value_string.h>
29 #include "ui/recent.h"
30 #include "ui/recent_utils.h"
31 #include "ui/packet_list_utils.h"
32 #include "ui/simple_dialog.h"
34 #include <wsutil/file_util.h>
35 #include <wsutil/strtoi.h>
37 #define RECENT_KEY_MAIN_TOOLBAR_SHOW "gui.toolbar_main_show"
38 #define RECENT_KEY_FILTER_TOOLBAR_SHOW "gui.filter_toolbar_show"
39 #define RECENT_KEY_WIRELESS_TOOLBAR_SHOW "gui.wireless_toolbar_show"
40 #define RECENT_KEY_PACKET_LIST_SHOW "gui.packet_list_show"
41 #define RECENT_KEY_TREE_VIEW_SHOW "gui.tree_view_show"
42 #define RECENT_KEY_BYTE_VIEW_SHOW "gui.byte_view_show"
43 #define RECENT_KEY_PACKET_DIAGRAM_SHOW "gui.packet_diagram_show"
44 #define RECENT_KEY_STATUSBAR_SHOW "gui.statusbar_show"
45 #define RECENT_KEY_PACKET_LIST_COLORIZE "gui.packet_list_colorize"
46 #define RECENT_KEY_CAPTURE_AUTO_SCROLL "capture.auto_scroll"
47 #define RECENT_GUI_TIME_FORMAT "gui.time_format"
48 #define RECENT_GUI_TIME_PRECISION "gui.time_precision"
49 #define RECENT_GUI_SECONDS_FORMAT "gui.seconds_format"
50 #define RECENT_GUI_ZOOM_LEVEL "gui.zoom_level"
51 #define RECENT_GUI_BYTES_VIEW "gui.bytes_view"
52 #define RECENT_GUI_BYTES_ENCODING "gui.bytes_encoding"
53 #define RECENT_GUI_ALLOW_HOVER_SELECTION "gui.allow_hover_selection"
54 #define RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES "gui.packet_diagram_field_values"
55 #define RECENT_GUI_GEOMETRY_MAIN_X "gui.geometry_main_x"
56 #define RECENT_GUI_GEOMETRY_MAIN_Y "gui.geometry_main_y"
57 #define RECENT_GUI_GEOMETRY_MAIN_WIDTH "gui.geometry_main_width"
58 #define RECENT_GUI_GEOMETRY_MAIN_HEIGHT "gui.geometry_main_height"
59 #define RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED "gui.geometry_main_maximized"
60 #define RECENT_GUI_GEOMETRY_MAIN "gui.geometry_main"
61 #define RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS "gui.geometry_leftalign_actions"
62 #define RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE "gui.geometry_main_upper_pane"
63 #define RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE "gui.geometry_main_lower_pane"
64 #define RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT "gui.geometry_main_master_split"
65 #define RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT "gui.geometry_main_extra_split"
66 #define RECENT_LAST_USED_PROFILE "gui.last_used_profile"
67 #define RECENT_PROFILE_SWITCH_CHECK_COUNT "gui.profile_switch_check_count"
68 #define RECENT_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen_remembered_dir"
69 #define RECENT_GUI_CONVERSATION_TABS "gui.conversation_tabs"
70 #define RECENT_GUI_CONVERSATION_TABS_COLUMNS "gui.conversation_tabs_columns"
71 #define RECENT_GUI_ENDPOINT_TABS "gui.endpoint_tabs"
72 #define RECENT_GUI_ENDPOINT_TABS_COLUMNS "gui.endpoint_tabs_columns"
73 #define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES "gui.rlc_pdus_from_mac_frames"
74 #define RECENT_GUI_CUSTOM_COLORS "gui.custom_colors"
75 #define RECENT_GUI_TOOLBAR_SHOW "gui.additional_toolbar_show"
76 #define RECENT_GUI_INTERFACE_TOOLBAR_SHOW "gui.interface_toolbar_show"
77 #define RECENT_GUI_SEARCH_IN "gui.search_in"
78 #define RECENT_GUI_SEARCH_CHAR_SET "gui.search_char_set"
79 #define RECENT_GUI_SEARCH_CASE_SENSITIVE "gui.search_case_sensitive"
80 #define RECENT_GUI_SEARCH_REVERSE_DIR "gui.search_reverse_dir"
81 #define RECENT_GUI_SEARCH_MULTIPLE_OCCURS "gui.search_multiple_occurs"
82 #define RECENT_GUI_SEARCH_TYPE "gui.search_type"
83 #define RECENT_GUI_FOLLOW_SHOW "gui.follow_show"
84 #define RECENT_GUI_FOLLOW_DELTA "gui.follow_delta"
85 #define RECENT_GUI_SHOW_BYTES_DECODE "gui.show_bytes_decode"
86 #define RECENT_GUI_SHOW_BYTES_SHOW "gui.show_bytes_show"
88 #define RECENT_GUI_GEOMETRY "gui.geom."
90 #define RECENT_KEY_PRIVS_WARN_IF_ELEVATED "privs.warn_if_elevated"
91 #define RECENT_KEY_SYS_WARN_IF_NO_CAPTURE "sys.warn_if_no_capture"
93 #define RECENT_FILE_NAME "recent"
94 #define RECENT_COMMON_FILE_NAME "recent_common"
96 recent_settings_t recent
;
98 static const value_string ts_type_values
[] = {
99 { TS_RELATIVE
, "RELATIVE" },
100 { TS_ABSOLUTE
, "ABSOLUTE" },
101 { TS_ABSOLUTE_WITH_YMD
, "ABSOLUTE_WITH_YMD" },
102 { TS_ABSOLUTE_WITH_YDOY
, "ABSOLUTE_WITH_YDOY" },
103 { TS_ABSOLUTE_WITH_YMD
, "ABSOLUTE_WITH_DATE" }, /* Backward compatibility */
104 { TS_DELTA
, "DELTA" },
105 { TS_DELTA_DIS
, "DELTA_DIS" },
106 { TS_EPOCH
, "EPOCH" },
108 { TS_UTC_WITH_YMD
, "UTC_WITH_YMD" },
109 { TS_UTC_WITH_YDOY
, "UTC_WITH_YDOY" },
110 { TS_UTC_WITH_YMD
, "UTC_WITH_DATE" }, /* Backward compatibility */
115 * NOTE: all values other than TS_PREC_AUTO are the number of digits
118 * We continue to use the old names for values where they may have
119 * been written to the recent file by previous releases. For other
120 * values, we just write it out numerically.
122 static const value_string ts_precision_values
[] = {
123 { TS_PREC_AUTO
, "AUTO" },
124 { TS_PREC_FIXED_SEC
, "SEC" },
125 { TS_PREC_FIXED_100_MSEC
, "DSEC" },
126 { TS_PREC_FIXED_10_MSEC
, "CSEC" },
127 { TS_PREC_FIXED_MSEC
, "MSEC" },
128 { TS_PREC_FIXED_USEC
, "USEC" },
129 { TS_PREC_FIXED_NSEC
, "NSEC" },
133 static const value_string ts_seconds_values
[] = {
134 { TS_SECONDS_DEFAULT
, "SECONDS" },
135 { TS_SECONDS_HOUR_MIN_SEC
, "HOUR_MIN_SEC" },
139 static const value_string bytes_view_type_values
[] = {
140 { BYTES_HEX
, "HEX" },
141 { BYTES_BITS
, "BITS" },
142 { BYTES_DEC
, "DEC" },
143 { BYTES_OCT
, "OCT" },
147 static const value_string bytes_encoding_type_values
[] = {
148 { BYTES_ENC_FROM_PACKET
, "FROM_PACKET" },
149 { BYTES_ENC_ASCII
, "ASCII" },
150 { BYTES_ENC_EBCDIC
, "EBCDIC" },
154 static const value_string search_in_values
[] = {
155 { SEARCH_IN_PACKET_LIST
, "PACKET_LIST" },
156 { SEARCH_IN_PACKET_DETAILS
, "PACKET_DETAILS" },
157 { SEARCH_IN_PACKET_BYTES
, "PACKET_BYTES" },
161 static const value_string search_char_set_values
[] = {
162 { SEARCH_CHAR_SET_NARROW_AND_WIDE
, "NARROW_AND_WIDE" },
163 { SEARCH_CHAR_SET_NARROW
, "NARROW" },
164 { SEARCH_CHAR_SET_WIDE
, "WIDE" },
168 static const value_string search_type_values
[] = {
169 { SEARCH_TYPE_DISPLAY_FILTER
, "DISPLAY_FILTER" },
170 { SEARCH_TYPE_HEX_VALUE
, "HEX_VALUE" },
171 { SEARCH_TYPE_STRING
, "STRING" },
172 { SEARCH_TYPE_REGEX
, "REGEX" },
176 static const value_string bytes_show_values
[] = {
177 { SHOW_ASCII
, "ASCII" },
178 { SHOW_ASCII_CONTROL
, "ASCII_CONTROL" },
179 { SHOW_CARRAY
, "C_ARRAYS" },
180 { SHOW_EBCDIC
, "EBCDIC" },
181 { SHOW_HEXDUMP
, "HEX_DUMP" },
182 { SHOW_HTML
, "HTML" },
183 { SHOW_IMAGE
, "IMAGE" },
184 { SHOW_JSON
, "JSON" },
186 { SHOW_RUSTARRAY
, "RUST_ARRAY" },
187 { SHOW_CODEC
, "UTF-8" },
188 // Other codecs are generated at runtime
189 { SHOW_YAML
, "YAML"},
193 static const value_string follow_delta_values
[] = {
194 { FOLLOW_DELTA_NONE
, "NONE" },
195 { FOLLOW_DELTA_TURN
, "TURN" },
196 { FOLLOW_DELTA_ALL
, "ALL" },
200 static const value_string show_bytes_decode_values
[] = {
201 { DecodeAsNone
, "NONE" },
202 { DecodeAsBASE64
, "BASE64" },
203 { DecodeAsCompressed
, "COMPRESSED" },
204 { DecodeAsHexDigits
, "HEX_DIGITS" },
205 { DecodeAsPercentEncoding
, "PERCENT_ENCODING" },
206 { DecodeAsQuotedPrintable
, "QUOTED_PRINTABLE" },
207 { DecodeAsROT13
, "ROT13"},
212 free_col_width_data(void *data
)
214 col_width_data
*cfmt
= (col_width_data
*)data
;
219 recent_free_column_width_info(recent_settings_t
*rs
)
221 g_list_free_full(rs
->col_width_list
, free_col_width_data
);
222 rs
->col_width_list
= NULL
;
225 /** Write the geometry values of a single window to the recent file.
228 * @param value the geometry values
229 * @param rfh recent file handle (FILE)
232 write_recent_geom(void *key _U_
, void *value
, void *rfh
)
234 window_geometry_t
*geom
= (window_geometry_t
*)value
;
235 FILE *rf
= (FILE *)rfh
;
237 fprintf(rf
, "\n# Geometry and maximized state of %s window.\n", geom
->key
);
238 fprintf(rf
, "# Decimal integers.\n");
239 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.x: %d\n", geom
->key
, geom
->x
);
240 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.y: %d\n", geom
->key
, geom
->y
);
241 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.width: %d\n", geom
->key
,
243 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.height: %d\n", geom
->key
,
246 fprintf(rf
, "# true or false (case-insensitive).\n");
247 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.maximized: %s\n", geom
->key
,
248 geom
->maximized
== true ? "true" : "false");
250 fprintf(rf
, "# Qt Geometry State (hex byte string).\n");
251 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.qt_geometry: %s\n", geom
->key
,
255 /* the geometry hashtable for all known window classes,
256 * the window name is the key, and the geometry struct is the value */
257 static GHashTable
*window_geom_hash
;
259 static GHashTable
*window_splitter_hash
;
262 window_geom_free(void *data
)
264 window_geometry_t
*geom
= (window_geometry_t
*)data
;
266 g_free(geom
->qt_geom
);
270 /* save the window and its current geometry into the geometry hashtable */
272 window_geom_save(const char *name
, window_geometry_t
*geom
)
275 window_geometry_t
*work
;
277 /* init hashtable, if not already done */
278 if (!window_geom_hash
) {
279 window_geom_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, window_geom_free
);
282 /* g_malloc and insert the new one */
283 work
= g_new(window_geometry_t
, 1);
285 key
= g_strdup(name
);
287 g_hash_table_replace(window_geom_hash
, key
, work
);
290 /* load the desired geometry for this window from the geometry hashtable */
292 window_geom_load(const char *name
,
293 window_geometry_t
*geom
)
295 window_geometry_t
*p
;
297 /* init hashtable, if not already done */
298 if (!window_geom_hash
) {
299 window_geom_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, window_geom_free
);
302 p
= (window_geometry_t
*)g_hash_table_lookup(window_geom_hash
, name
);
311 /* save the window and its splitter state into the splitter hashtable */
313 window_splitter_save(const char *name
, const char *splitter_state
)
315 /* init hashtable, if not already done */
316 if (!window_splitter_hash
) {
317 window_splitter_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
320 g_hash_table_replace(window_splitter_hash
, g_strdup(name
), g_strdup(splitter_state
));
323 /* save the window and its splitter state into the geometry hashtable */
325 window_splitter_load(const char *name
)
327 /* init hashtable, if not already done */
328 if (!window_splitter_hash
) {
332 return g_hash_table_lookup(window_splitter_hash
, name
);
336 /* parse values of particular types */
338 parse_recent_boolean(const char *val_str
, bool *valuep
)
340 if (g_ascii_strcasecmp(val_str
, "true") == 0) {
348 /** Read in a single geometry key value pair from the recent file.
350 * @param name the geom_name of the window
351 * @param key the subkey of this pair (e.g. "x")
352 * @param value the new value (e.g. "123")
355 window_geom_recent_read_pair(const char *name
,
359 window_geometry_t geom
;
361 if (strcmp(key
, "splitter") == 0) {
362 window_splitter_save(name
, value
);
366 /* find window geometry maybe already in hashtable */
367 if (!window_geom_load(name
, &geom
)) {
368 /* not in table, init geom with "basic" values */
369 geom
.key
= NULL
; /* Will be set in window_geom_save() */
370 geom
.set_pos
= false;
373 geom
.set_size
= false;
379 if (strcmp(key
, "x") == 0) {
380 geom
.x
= (int)strtol(value
, NULL
, 10);
382 } else if (strcmp(key
, "y") == 0) {
383 geom
.y
= (int)strtol(value
, NULL
, 10);
385 } else if (strcmp(key
, "width") == 0) {
386 geom
.width
= (int)strtol(value
, NULL
, 10);
387 geom
.set_size
= true;
388 } else if (strcmp(key
, "height") == 0) {
389 geom
.height
= (int)strtol(value
, NULL
, 10);
390 geom
.set_size
= true;
391 } else if (strcmp(key
, "maximized") == 0) {
392 parse_recent_boolean(value
, &geom
.maximized
);
393 geom
.set_maximized
= true;
394 } else if (strcmp(key
, "qt_geometry") == 0) {
395 geom
.qt_geom
= g_strdup(value
);
398 * Silently ignore the bogus key. We shouldn't abort here,
399 * as this could be due to a corrupt recent file.
401 * XXX - should we print a message about this?
406 /* save / replace geometry in hashtable */
407 window_geom_save(name
, &geom
);
410 /** Write all geometry values of all windows to the recent file.
411 * Will call write_recent_geom() for every existing window type.
413 * @param rf recent file handle from caller
416 window_geom_recent_write_all(FILE *rf
)
418 /* init hashtable, if not already done */
419 if (!window_geom_hash
) {
420 window_geom_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, window_geom_free
);
423 g_hash_table_foreach(window_geom_hash
, write_recent_geom
, rf
);
426 /** Write all known window splitter states to the recent file.
428 * @param rf recent file handle from caller
431 window_splitter_recent_write_all(FILE *rf
)
433 /* init hashtable, if not already done */
434 if (!window_splitter_hash
) {
440 g_hash_table_iter_init(&iter
, window_splitter_hash
);
441 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
442 fprintf(rf
, "\n# Splitter state of %s window.\n", (char*)key
);
443 fprintf(rf
, "# Qt Splitter state (hex byte string).\n");
444 fprintf(rf
, RECENT_GUI_GEOMETRY
"%s.splitter: %s\n", (char*)key
,
449 /* Global list of recent capture filters. */
450 static GList
*recent_cfilter_list
;
453 * Per-interface lists of recent capture filters; stored in a hash
454 * table indexed by interface name.
456 static GHashTable
*per_interface_cfilter_lists_hash
;
458 /* XXX: use a preference for this setting! */
459 /* N.B.: If we use a pref, we will read the recent_common file
460 * before the pref, so don't truncate the list when reading
461 * (see the similar #16782 for the recent files.)
463 static unsigned cfilter_combo_max_recent
= 20;
466 * Returns a list of recent capture filters.
468 * @param ifname interface name; NULL refers to the global list.
471 recent_get_cfilter_list(const char *ifname
)
474 return recent_cfilter_list
;
475 if (per_interface_cfilter_lists_hash
== NULL
) {
476 /* No such lists exist. */
479 return (GList
*)g_hash_table_lookup(per_interface_cfilter_lists_hash
, ifname
);
483 * Add a capture filter to the global recent capture filter list or
484 * the recent capture filter list for an interface.
486 * @param ifname interface name; NULL refers to the global list.
487 * @param s text of capture filter
490 recent_add_cfilter(const char *ifname
, const char *s
)
494 char *li_filter
, *newfilter
= NULL
;
496 /* Don't add empty filters to the list. */
501 cfilter_list
= recent_cfilter_list
;
503 /* If we don't yet have a hash table for per-interface recent
504 capture filter lists, create one. Have it free the new key
505 if we're updating an entry rather than creating it below. */
506 if (per_interface_cfilter_lists_hash
== NULL
)
507 per_interface_cfilter_lists_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
508 cfilter_list
= (GList
*)g_hash_table_lookup(per_interface_cfilter_lists_hash
, ifname
);
511 li
= g_list_first(cfilter_list
);
513 /* If the filter is already in the list, remove the old one and
514 * append the new one at the latest position (at g_list_append() below) */
515 li_filter
= (char *)li
->data
;
516 if (strcmp(s
, li_filter
) == 0) {
517 /* No need to copy the string, we're just moving it. */
518 newfilter
= li_filter
;
519 cfilter_list
= g_list_remove(cfilter_list
, li
->data
);
524 if (newfilter
== NULL
) {
525 /* The filter wasn't already in the list; make a copy to add. */
526 newfilter
= g_strdup(s
);
528 cfilter_list
= g_list_prepend(cfilter_list
, newfilter
);
531 recent_cfilter_list
= cfilter_list
;
533 g_hash_table_insert(per_interface_cfilter_lists_hash
, g_strdup(ifname
), cfilter_list
);
536 #ifdef HAVE_PCAP_REMOTE
537 /* XXX: use a preference for this setting! */
538 /* N.B.: If we use a pref, we will read the recent_common file
539 * before the pref, so don't truncate the list when reading
540 * (see the similar #16782 for the recent files.)
542 static unsigned remote_host_max_recent
= 20;
543 static GList
*remote_host_list
;
545 int recent_get_remote_host_list_size(void)
547 if (remote_host_list
== NULL
) {
548 /* No entries exist. */
551 return g_list_length(remote_host_list
);
555 free_remote_host(void *value
)
557 struct remote_host
* rh
= (struct remote_host
*)value
;
560 g_free(rh
->remote_port
);
561 g_free(rh
->auth_username
);
562 g_free(rh
->auth_password
);
567 remote_host_compare(const void *a
, const void *b
)
569 const struct remote_host
* rh_a
= (const struct remote_host
*)a
;
570 const struct remote_host
* rh_b
= (const struct remote_host
*)b
;
572 /* We assume only one entry per host (the GUI assumes that too.) */
573 return g_strcmp0(rh_a
->r_host
, rh_b
->r_host
);
577 remote_host_reverse(void)
579 if (remote_host_list
) {
580 remote_host_list
= g_list_reverse(remote_host_list
);
584 void recent_add_remote_host(char *host _U_
, struct remote_host
*rh
)
587 if (remote_host_list
) {
588 li
= g_list_find_custom(remote_host_list
, rh
, remote_host_compare
);
590 free_remote_host(li
->data
);
591 remote_host_list
= g_list_delete_link(remote_host_list
, li
);
594 remote_host_list
= g_list_prepend(remote_host_list
, rh
);
598 recent_remote_host_list_foreach(GFunc func
, void *user_data
)
600 if (remote_host_list
!= NULL
) {
601 g_list_foreach(remote_host_list
, func
, user_data
);
606 recent_print_remote_host(void *value
, void *user
)
608 FILE *rf
= (FILE *)user
;
609 struct remote_host_info
*ri
= (struct remote_host_info
*)value
;
611 fprintf (rf
, RECENT_KEY_REMOTE_HOST
": %s,%s,%d\n", ri
->remote_host
, ri
->remote_port
, ri
->auth_type
);
615 * Write the contents of the remote_host_list to the 'recent' file.
617 * @param rf File to write to.
620 capture_remote_combo_recent_write_all(FILE *rf
)
622 unsigned max_count
= 0;
623 GList
*li
= g_list_first(remote_host_list
);
625 /* write all non empty remote capture hosts to the recent file (until max count) */
626 while (li
&& (max_count
++ <= remote_host_max_recent
)) {
627 recent_print_remote_host(li
->data
, rf
);
633 void recent_free_remote_host_list(void)
635 g_list_free_full(remote_host_list
, free_remote_host
);
636 remote_host_list
= NULL
;
640 recent_get_remote_host(const char *host
)
644 for (GList
* li
= g_list_first(remote_host_list
); li
!= NULL
; li
= li
->next
) {
645 struct remote_host
*rh
= (struct remote_host
*)li
->data
;
646 if (g_strcmp0(host
, rh
->r_host
) == 0) {
654 * Fill the remote_host_list with the entries stored in the 'recent' file.
656 * @param s String to be filled from the 'recent' file.
657 * @return True, if the list was written successfully, False otherwise.
660 capture_remote_combo_add_recent(const char *s
)
662 GList
*vals
= prefs_get_string_list (s
);
664 capture_auth auth_type
;
666 struct remote_host
*rh
;
671 /* First value is the host */
672 if (recent_get_remote_host(valp
->data
)) {
673 /* Don't add it, it's already in the list (shouldn't happen). */
674 return false; // Should this be true or false?
676 rh
= (struct remote_host
*) g_malloc (sizeof (*rh
));
678 /* First value is the host */
679 rh
->r_host
= (char *)g_strdup ((const char *)valp
->data
);
680 if (strlen(rh
->r_host
) == 0) {
681 /* Empty remote host */
686 rh
->auth_type
= CAPTURE_AUTH_NULL
;
690 /* Found value 2, this is the port number */
691 if (!strcmp((const char*)valp
->data
, "0")) {
692 /* Port 0 isn't valid, so leave port blank */
693 rh
->remote_port
= (char *)g_strdup ("");
695 rh
->remote_port
= (char *)g_strdup ((const char *)valp
->data
);
699 /* Did not find a port number */
700 rh
->remote_port
= g_strdup ("");
704 /* Found value 3, this is the authentication type */
705 auth_type
= (capture_auth
)strtol((const char *)valp
->data
, &p
, 0);
706 if (p
!= valp
->data
&& *p
== '\0') {
707 rh
->auth_type
= auth_type
;
711 /* Do not store username and password */
712 rh
->auth_username
= g_strdup ("");
713 rh
->auth_password
= g_strdup ("");
715 prefs_clear_string_list(vals
);
717 remote_host_list
= g_list_prepend(remote_host_list
, rh
);
723 cfilter_recent_write_all_list(FILE *rf
, const char *ifname
, GList
*cfilter_list
)
725 unsigned max_count
= 0;
728 /* write all non empty capture filter strings to the recent file (until max count) */
729 li
= g_list_first(cfilter_list
);
730 while (li
&& (max_count
++ <= cfilter_combo_max_recent
) ) {
731 if (li
->data
&& strlen((const char *)li
->data
)) {
733 fprintf (rf
, RECENT_KEY_CAPTURE_FILTER
": %s\n", (char *)li
->data
);
735 fprintf (rf
, RECENT_KEY_CAPTURE_FILTER
".%s: %s\n", ifname
, (char *)li
->data
);
742 cfilter_recent_write_all_hash_callback(void *key
, void *value
, void *user_data
)
744 cfilter_recent_write_all_list((FILE *)user_data
, (const char *)key
, (GList
*)value
);
747 /** Write all capture filter values to the recent file.
749 * @param rf recent file handle from caller
752 cfilter_recent_write_all(FILE *rf
)
754 /* Write out the global list. */
755 cfilter_recent_write_all_list(rf
, NULL
, recent_cfilter_list
);
757 /* Write out all the per-interface lists. */
758 if (per_interface_cfilter_lists_hash
!= NULL
) {
759 g_hash_table_foreach(per_interface_cfilter_lists_hash
, cfilter_recent_write_all_hash_callback
, (void *)rf
);
763 /** Reverse the order of all the capture filter lists after
764 * reading recent_common (we want the latest first).
765 * Note this is O(N), whereas appendng N items to a GList is O(N^2),
766 * since it doesn't have a pointer to the end like a GQueue.
769 cfilter_recent_reverse_all(void)
771 recent_cfilter_list
= g_list_reverse(recent_cfilter_list
);
773 /* Reverse all the per-interface lists. */
774 if (per_interface_cfilter_lists_hash
!= NULL
) {
777 g_hash_table_iter_init(&iter
, per_interface_cfilter_lists_hash
);
779 while (g_hash_table_iter_next(&iter
, &key
, &value
)) {
781 li
= g_list_reverse(li
);
782 /* per_interface_cfilter_lists_hash was created without a
783 * value_destroy_func, so this is fine.
785 g_hash_table_iter_replace(&iter
, li
);
790 /* Write out recent settings of particular types. */
792 write_recent_boolean(FILE *rf
, const char *description
, const char *name
,
795 fprintf(rf
, "\n# %s.\n", description
);
796 fprintf(rf
, "# true or false (case-insensitive).\n");
797 fprintf(rf
, "%s: %s\n", name
, value
== true ? "true" : "false");
801 write_recent_enum(FILE *rf
, const char *description
, const char *name
,
802 const value_string
*values
, unsigned value
)
804 const char *if_invalid
= NULL
;
805 const value_string
*valp
;
806 const char *str_value
;
808 fprintf(rf
, "\n# %s.\n", description
);
809 fprintf(rf
, "# One of: ");
811 while (valp
->strptr
!= NULL
) {
812 if (if_invalid
== NULL
)
813 if_invalid
= valp
->strptr
;
814 fprintf(rf
, "%s", valp
->strptr
);
816 if (valp
->strptr
!= NULL
)
820 str_value
= try_val_to_str(value
, values
);
821 if (str_value
!= NULL
)
822 fprintf(rf
, "%s: %s\n", name
, str_value
);
824 fprintf(rf
, "%s: %s\n", name
, if_invalid
!= NULL
? if_invalid
: "Unknown");
827 /* Attempt to write out "recent common" to the user's recent_common file.
828 If we got an error report it with a dialog box and return false,
829 otherwise return true. */
839 * - Split output lines longer than MAX_VAL_LEN
840 * - Create a function for the preference directory check/creation
841 * so that duplication can be avoided with filter.c
844 /* Create the directory that holds personal configuration files, if
846 if (create_persconffile_dir(&pf_dir_path
) == -1) {
847 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
848 "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path
,
854 rf_path
= get_persconffile_path(RECENT_COMMON_FILE_NAME
, false);
855 if ((rf
= ws_fopen(rf_path
, "w")) == NULL
) {
856 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
857 "Can't open recent file\n\"%s\": %s.", rf_path
,
864 fprintf(rf
, "# Common recent settings file for %s " VERSION
".\n"
866 "# This file is regenerated each time %s is quit\n"
867 "# and when changing configuration profile.\n"
868 "# So be careful, if you want to make manual changes here.\n"
870 "######## Recent capture files (latest last), cannot be altered through command line ########\n"
872 get_configuration_namespace(), get_configuration_namespace());
875 menu_recent_file_write_all(rf
);
878 "######## Recent capture filters (latest first), cannot be altered through command line ########\n"
881 cfilter_recent_write_all(rf
);
884 "######## Recent display filters (latest last), cannot be altered through command line ########\n"
887 dfilter_recent_combo_write_all(rf
);
889 #ifdef HAVE_PCAP_REMOTE
891 "######## Recent remote hosts (latest first), cannot be altered through command line ########\n"
894 capture_remote_combo_recent_write_all(rf
);
897 fprintf(rf
, "\n# Main window geometry.\n");
898 fprintf(rf
, "# Decimal numbers.\n");
899 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_X
": %d\n", recent
.gui_geometry_main_x
);
900 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_Y
": %d\n", recent
.gui_geometry_main_y
);
901 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_WIDTH
": %d\n",
902 recent
.gui_geometry_main_width
);
903 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_HEIGHT
": %d\n",
904 recent
.gui_geometry_main_height
);
906 write_recent_boolean(rf
, "Main window maximized",
907 RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED
,
908 recent
.gui_geometry_main_maximized
);
910 if (recent
.gui_geometry_main
!= NULL
) {
911 fprintf(rf
, "\n# Main window geometry state.\n");
912 fprintf(rf
, "# Hex byte string.\n");
913 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN
": %s\n",
914 recent
.gui_geometry_main
);
917 write_recent_boolean(rf
, "Leftalign Action Buttons",
918 RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS
,
919 recent
.gui_geometry_leftalign_actions
);
921 fprintf(rf
, "\n# Last used Configuration Profile.\n");
922 fprintf(rf
, RECENT_LAST_USED_PROFILE
": %s\n", get_profile_name());
924 fprintf(rf
, "\n# Number of packets or events to check for automatic profile switching.\n");
925 fprintf(rf
, "# Decimal number. Zero disables switching.\n");
926 const char * def_prefix
= recent
.gui_profile_switch_check_count
== 1000 ? "#" : "";
927 fprintf(rf
, "%s" RECENT_PROFILE_SWITCH_CHECK_COUNT
": %d\n", def_prefix
,
928 recent
.gui_profile_switch_check_count
);
930 write_recent_boolean(rf
, "Warn if running with elevated permissions (e.g. as root)",
931 RECENT_KEY_PRIVS_WARN_IF_ELEVATED
,
932 recent
.privs_warn_if_elevated
);
934 write_recent_boolean(rf
, "Warn if Wireshark is unable to capture",
935 RECENT_KEY_SYS_WARN_IF_NO_CAPTURE
,
936 recent
.sys_warn_if_no_capture
);
938 write_recent_enum(rf
, "Find packet search in", RECENT_GUI_SEARCH_IN
, search_in_values
,
939 recent
.gui_search_in
);
940 write_recent_enum(rf
, "Find packet character set", RECENT_GUI_SEARCH_CHAR_SET
, search_char_set_values
,
941 recent
.gui_search_char_set
);
942 write_recent_boolean(rf
, "Find packet case sensitive search",
943 RECENT_GUI_SEARCH_CASE_SENSITIVE
,
944 recent
.gui_search_case_sensitive
);
945 write_recent_boolean(rf
, "Find packet search reverse direction",
946 RECENT_GUI_SEARCH_REVERSE_DIR
,
947 recent
.gui_search_reverse_dir
);
948 write_recent_boolean(rf
, "Find packet search multiple occurrences",
949 RECENT_GUI_SEARCH_MULTIPLE_OCCURS
,
950 recent
.gui_search_multiple_occurs
);
951 write_recent_enum(rf
, "Find packet search type", RECENT_GUI_SEARCH_TYPE
, search_type_values
,
952 recent
.gui_search_type
);
954 window_geom_recent_write_all(rf
);
956 fprintf(rf
, "\n# Custom colors.\n");
957 fprintf(rf
, "# List of custom colors selected in Qt color picker.\n");
958 string_list
= join_string_list(recent
.custom_colors
);
959 fprintf(rf
, RECENT_GUI_CUSTOM_COLORS
": %s\n", string_list
);
964 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
965 an error indication, or maybe write to a new recent file and
966 rename that file on top of the old one only if there are not I/O
972 /* Attempt to Write out profile "recent" to the user's profile recent file.
973 If we got an error report it with a dialog box and return false,
974 otherwise return true. */
976 write_profile_recent(void)
984 * - Split output lines longer than MAX_VAL_LEN
985 * - Create a function for the preference directory check/creation
986 * so that duplication can be avoided with filter.c
989 /* Create the directory that holds personal configuration files, if
991 if (create_persconffile_dir(&pf_dir_path
) == -1) {
992 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
993 "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path
,
999 rf_path
= get_persconffile_path(RECENT_FILE_NAME
, true);
1000 if ((rf
= ws_fopen(rf_path
, "w")) == NULL
) {
1001 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
1002 "Can't open recent file\n\"%s\": %s.", rf_path
,
1009 fprintf(rf
, "# Recent settings file for %s " VERSION
".\n"
1011 "# This file is regenerated each time %s is quit\n"
1012 "# and when changing configuration profile.\n"
1013 "# So be careful, if you want to make manual changes here.\n"
1015 get_configuration_namespace(), get_configuration_namespace());
1017 write_recent_boolean(rf
, "Main Toolbar show (hide)",
1018 RECENT_KEY_MAIN_TOOLBAR_SHOW
,
1019 recent
.main_toolbar_show
);
1021 write_recent_boolean(rf
, "Filter Toolbar show (hide)",
1022 RECENT_KEY_FILTER_TOOLBAR_SHOW
,
1023 recent
.filter_toolbar_show
);
1025 write_recent_boolean(rf
, "Wireless Settings Toolbar show (hide)",
1026 RECENT_KEY_WIRELESS_TOOLBAR_SHOW
,
1027 recent
.wireless_toolbar_show
);
1029 write_recent_boolean(rf
, "Packet list show (hide)",
1030 RECENT_KEY_PACKET_LIST_SHOW
,
1031 recent
.packet_list_show
);
1033 write_recent_boolean(rf
, "Tree view show (hide)",
1034 RECENT_KEY_TREE_VIEW_SHOW
,
1035 recent
.tree_view_show
);
1037 write_recent_boolean(rf
, "Byte view show (hide)",
1038 RECENT_KEY_BYTE_VIEW_SHOW
,
1039 recent
.byte_view_show
);
1041 write_recent_boolean(rf
, "Packet diagram show (hide)",
1042 RECENT_KEY_PACKET_DIAGRAM_SHOW
,
1043 recent
.packet_diagram_show
);
1045 write_recent_boolean(rf
, "Statusbar show (hide)",
1046 RECENT_KEY_STATUSBAR_SHOW
,
1047 recent
.statusbar_show
);
1049 write_recent_boolean(rf
, "Packet list colorize (hide)",
1050 RECENT_KEY_PACKET_LIST_COLORIZE
,
1051 recent
.packet_list_colorize
);
1053 write_recent_boolean(rf
, "Auto scroll packet list when capturing",
1054 RECENT_KEY_CAPTURE_AUTO_SCROLL
,
1055 recent
.capture_auto_scroll
);
1057 write_recent_enum(rf
, "Timestamp display format",
1058 RECENT_GUI_TIME_FORMAT
, ts_type_values
,
1059 recent
.gui_time_format
);
1062 * The value of this item is either TS_PREC_AUTO, which is a
1063 * negative number meaning "pick the display precision based
1064 * on the time stamp precision of the packet", or is a numerical
1065 * value giving the number of decimal places to display, from 0
1068 * It used to be that not all values between 0 and 9 (the maximum
1069 * precision back then) were supported, and that names were
1070 * written out to the recent file.
1072 * For backwards compatibility with those older versions of
1073 * Wireshark, write out the names for those values, and the
1074 * raw number for other values.
1077 const char *if_invalid
= NULL
;
1078 const value_string
*valp
;
1079 const char *str_value
;
1081 fprintf(rf
, "\n# %s.\n", "Timestamp display precision");
1082 fprintf(rf
, "# One of: ");
1083 valp
= ts_precision_values
;
1084 while (valp
->strptr
!= NULL
) {
1085 if (if_invalid
== NULL
)
1086 if_invalid
= valp
->strptr
;
1087 fprintf(rf
, "%s", valp
->strptr
);
1089 if (valp
->strptr
!= NULL
)
1092 fprintf(rf
, ", or a number between 0 and %d\n", WS_TSPREC_MAX
);
1094 str_value
= try_val_to_str(recent
.gui_time_precision
, ts_precision_values
);
1095 if (str_value
!= NULL
)
1096 fprintf(rf
, "%s: %s\n", RECENT_GUI_TIME_PRECISION
, str_value
);
1098 if (recent
.gui_time_precision
>= 0 && recent
.gui_time_precision
< WS_TSPREC_MAX
)
1099 fprintf(rf
, "%s: %d\n", RECENT_GUI_TIME_PRECISION
, recent
.gui_time_precision
);
1101 fprintf(rf
, "%s: %s\n", RECENT_GUI_TIME_PRECISION
, if_invalid
!= NULL
? if_invalid
: "Unknown");
1105 write_recent_enum(rf
, "Seconds display format",
1106 RECENT_GUI_SECONDS_FORMAT
, ts_seconds_values
,
1107 recent
.gui_seconds_format
);
1109 fprintf(rf
, "\n# Zoom level.\n");
1110 fprintf(rf
, "# A decimal number.\n");
1111 fprintf(rf
, RECENT_GUI_ZOOM_LEVEL
": %d\n",
1112 recent
.gui_zoom_level
);
1114 write_recent_enum(rf
, "Bytes view display type",
1115 RECENT_GUI_BYTES_VIEW
, bytes_view_type_values
,
1116 recent
.gui_bytes_view
);
1118 write_recent_enum(rf
, "Bytes view text encoding",
1119 RECENT_GUI_BYTES_ENCODING
, bytes_encoding_type_values
,
1120 recent
.gui_bytes_encoding
);
1122 write_recent_boolean(rf
, "Packet diagram field values show (hide)",
1123 RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES
,
1124 recent
.gui_packet_diagram_field_values
);
1126 write_recent_boolean(rf
, "Allow hover selection in byte view",
1127 RECENT_GUI_ALLOW_HOVER_SELECTION
,
1128 recent
.gui_allow_hover_selection
);
1130 write_recent_enum(rf
, "Follow stream show as",
1131 RECENT_GUI_FOLLOW_SHOW
, bytes_show_values
,
1132 recent
.gui_follow_show
);
1134 write_recent_enum(rf
, "Follow stream delta times",
1135 RECENT_GUI_FOLLOW_DELTA
, follow_delta_values
,
1136 recent
.gui_follow_delta
);
1138 write_recent_enum(rf
, "Show packet bytes decode as",
1139 RECENT_GUI_SHOW_BYTES_DECODE
, show_bytes_decode_values
,
1140 recent
.gui_show_bytes_decode
);
1142 write_recent_enum(rf
, "Show packet bytes show as",
1143 RECENT_GUI_SHOW_BYTES_SHOW
, bytes_show_values
,
1144 recent
.gui_show_bytes_show
);
1146 fprintf(rf
, "\n# Main window upper (or leftmost) pane size.\n");
1147 fprintf(rf
, "# Decimal number.\n");
1148 if (recent
.gui_geometry_main_upper_pane
!= 0) {
1149 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE
": %d\n",
1150 recent
.gui_geometry_main_upper_pane
);
1152 fprintf(rf
, "\n# Main window middle pane size.\n");
1153 fprintf(rf
, "# Decimal number.\n");
1154 if (recent
.gui_geometry_main_lower_pane
!= 0) {
1155 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE
": %d\n",
1156 recent
.gui_geometry_main_lower_pane
);
1159 if (recent
.gui_geometry_main_master_split
!= NULL
) {
1160 fprintf(rf
, "\n# Main window master splitter state.\n");
1161 fprintf(rf
, "# Hex byte string.\n");
1162 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT
": %s\n",
1163 recent
.gui_geometry_main_master_split
);
1166 if (recent
.gui_geometry_main_extra_split
!= NULL
) {
1167 fprintf(rf
, "\n# Main window extra splitter state.\n");
1168 fprintf(rf
, "# Hex byte string.\n");
1169 fprintf(rf
, RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT
": %s\n",
1170 recent
.gui_geometry_main_extra_split
);
1173 window_splitter_recent_write_all(rf
);
1175 fprintf(rf
, "\n# Packet list column pixel widths.\n");
1176 fprintf(rf
, "# Each pair of strings consists of a column format and its pixel width.\n");
1177 packet_list_recent_write_all(rf
);
1179 fprintf(rf
, "\n# Open conversation dialog tabs.\n");
1180 fprintf(rf
, "# List of conversation names, e.g. \"TCP\", \"IPv6\".\n");
1181 string_list
= join_string_list(recent
.conversation_tabs
);
1182 fprintf(rf
, RECENT_GUI_CONVERSATION_TABS
": %s\n", string_list
);
1183 g_free(string_list
);
1185 fprintf(rf
, "\n# Conversation dialog tabs columns.\n");
1186 fprintf(rf
, "# List of conversation columns numbers.\n");
1187 string_list
= join_string_list(recent
.conversation_tabs_columns
);
1188 fprintf(rf
, RECENT_GUI_CONVERSATION_TABS_COLUMNS
": %s\n", string_list
);
1189 g_free(string_list
);
1191 fprintf(rf
, "\n# Open endpoint dialog tabs.\n");
1192 fprintf(rf
, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
1193 string_list
= join_string_list(recent
.endpoint_tabs
);
1194 fprintf(rf
, RECENT_GUI_ENDPOINT_TABS
": %s\n", string_list
);
1195 g_free(string_list
);
1197 fprintf(rf
, "\n# Endpoint dialog tabs columns.\n");
1198 fprintf(rf
, "# List of endpoint columns numbers.\n");
1199 string_list
= join_string_list(recent
.endpoint_tabs_columns
);
1200 fprintf(rf
, RECENT_GUI_ENDPOINT_TABS_COLUMNS
": %s\n", string_list
);
1201 g_free(string_list
);
1203 write_recent_boolean(rf
, "For RLC stats, whether to use RLC PDUs found inside MAC frames",
1204 RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES
,
1205 recent
.gui_rlc_use_pdus_from_mac
);
1207 if (get_last_open_dir() != NULL
) {
1208 fprintf(rf
, "\n# Last directory navigated to in File Open dialog.\n");
1209 fprintf(rf
, RECENT_GUI_FILEOPEN_REMEMBERED_DIR
": %s\n", get_last_open_dir());
1212 fprintf(rf
, "\n# Additional Toolbars shown\n");
1213 fprintf(rf
, "# List of additional toolbars to show.\n");
1214 string_list
= join_string_list(recent
.gui_additional_toolbars
);
1215 fprintf(rf
, RECENT_GUI_TOOLBAR_SHOW
": %s\n", string_list
);
1216 g_free(string_list
);
1218 fprintf(rf
, "\n# Interface Toolbars show.\n");
1219 fprintf(rf
, "# List of interface toolbars to show.\n");
1220 string_list
= join_string_list(recent
.interface_toolbars
);
1221 fprintf(rf
, RECENT_GUI_INTERFACE_TOOLBAR_SHOW
": %s\n", string_list
);
1222 g_free(string_list
);
1226 /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
1227 an error indication, or maybe write to a new recent file and
1228 rename that file on top of the old one only if there are not I/O
1233 /* set one user's recent common file key/value pair */
1234 static prefs_set_pref_e
1235 read_set_recent_common_pair_static(char *key
, const char *value
,
1236 void *private_data _U_
,
1237 bool return_range_errors _U_
)
1242 if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_MAXIMIZED
) == 0) {
1243 parse_recent_boolean(value
, &recent
.gui_geometry_main_maximized
);
1244 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_LEFTALIGN_ACTIONS
) == 0) {
1245 parse_recent_boolean(value
, &recent
.gui_geometry_leftalign_actions
);
1246 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_X
) == 0) {
1247 num
= strtol(value
, &p
, 0);
1248 if (p
== value
|| *p
!= '\0')
1249 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1250 recent
.gui_geometry_main_x
= (int)num
;
1251 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_Y
) == 0) {
1252 num
= strtol(value
, &p
, 0);
1253 if (p
== value
|| *p
!= '\0')
1254 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1255 recent
.gui_geometry_main_y
= (int)num
;
1256 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_WIDTH
) == 0) {
1257 num
= strtol(value
, &p
, 0);
1258 if (p
== value
|| *p
!= '\0')
1259 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1261 return PREFS_SET_SYNTAX_ERR
; /* number must be positive */
1262 recent
.gui_geometry_main_width
= (int)num
;
1263 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_HEIGHT
) == 0) {
1264 num
= strtol(value
, &p
, 0);
1265 if (p
== value
|| *p
!= '\0')
1266 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1268 return PREFS_SET_SYNTAX_ERR
; /* number must be positive */
1269 recent
.gui_geometry_main_height
= (int)num
;
1270 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN
) == 0) {
1271 g_free(recent
.gui_geometry_main
);
1272 recent
.gui_geometry_main
= g_strdup(value
);
1273 } else if (strcmp(key
, RECENT_LAST_USED_PROFILE
) == 0) {
1274 if ((strcmp(value
, DEFAULT_PROFILE
) != 0) && profile_exists (value
, false)) {
1275 set_profile_name (value
);
1277 } else if (strcmp(key
, RECENT_PROFILE_SWITCH_CHECK_COUNT
) == 0) {
1278 num
= strtol(value
, &p
, 0);
1279 if (p
== value
|| *p
!= '\0')
1280 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1282 return PREFS_SET_SYNTAX_ERR
; /* number must be positive */
1283 recent
.gui_profile_switch_check_count
= (int)num
;
1284 } else if (strncmp(key
, RECENT_GUI_GEOMETRY
, sizeof(RECENT_GUI_GEOMETRY
)-1) == 0) {
1285 /* now have something like "gui.geom.main.x", split it into win and sub_key */
1286 char *win
= &key
[sizeof(RECENT_GUI_GEOMETRY
)-1];
1287 char *sub_key
= strchr(win
, '.');
1291 window_geom_recent_read_pair(win
, sub_key
, value
);
1293 } else if (strcmp(key
, RECENT_KEY_PRIVS_WARN_IF_ELEVATED
) == 0) {
1294 parse_recent_boolean(value
, &recent
.privs_warn_if_elevated
);
1295 } else if (strcmp(key
, RECENT_KEY_SYS_WARN_IF_NO_CAPTURE
) == 0) {
1296 parse_recent_boolean(value
, &recent
.sys_warn_if_no_capture
);
1297 } else if (strcmp(key
, RECENT_GUI_SEARCH_IN
) == 0) {
1298 recent
.gui_search_in
= (search_in_type
)str_to_val(value
, search_in_values
, SEARCH_IN_PACKET_LIST
);
1299 } else if (strcmp(key
, RECENT_GUI_SEARCH_CHAR_SET
) == 0) {
1300 recent
.gui_search_char_set
= (search_char_set_type
)str_to_val(value
, search_char_set_values
, SEARCH_CHAR_SET_NARROW_AND_WIDE
);
1301 } else if (strcmp(key
, RECENT_GUI_SEARCH_CASE_SENSITIVE
) == 0) {
1302 parse_recent_boolean(value
, &recent
.gui_search_case_sensitive
);
1303 } else if (strcmp(key
, RECENT_GUI_SEARCH_REVERSE_DIR
) == 0) {
1304 parse_recent_boolean(value
, &recent
.gui_search_reverse_dir
);
1305 } else if (strcmp(key
, RECENT_GUI_SEARCH_MULTIPLE_OCCURS
) == 0) {
1306 parse_recent_boolean(value
, &recent
.gui_search_multiple_occurs
);
1307 } else if (strcmp(key
, RECENT_GUI_SEARCH_TYPE
) == 0) {
1308 recent
.gui_search_type
= (search_type_type
)str_to_val(value
, search_type_values
, SEARCH_TYPE_DISPLAY_FILTER
);
1309 } else if (strcmp(key
, RECENT_GUI_CUSTOM_COLORS
) == 0) {
1310 recent
.custom_colors
= prefs_get_string_list(value
);
1313 return PREFS_SET_OK
;
1316 /* set one user's recent file key/value pair */
1317 static prefs_set_pref_e
1318 read_set_recent_pair_static(char *key
, const char *value
,
1319 void *private_data _U_
,
1320 bool return_range_errors _U_
)
1325 GList
*col_l
, *col_l_elt
;
1326 col_width_data
*cfmt
;
1328 if (strcmp(key
, RECENT_KEY_MAIN_TOOLBAR_SHOW
) == 0) {
1329 parse_recent_boolean(value
, &recent
.main_toolbar_show
);
1330 } else if (strcmp(key
, RECENT_KEY_FILTER_TOOLBAR_SHOW
) == 0) {
1331 parse_recent_boolean(value
, &recent
.filter_toolbar_show
);
1332 /* check both the old and the new keyword */
1333 } else if (strcmp(key
, RECENT_KEY_WIRELESS_TOOLBAR_SHOW
) == 0 || (strcmp(key
, "gui.airpcap_toolbar_show") == 0)) {
1334 parse_recent_boolean(value
, &recent
.wireless_toolbar_show
);
1335 } else if (strcmp(key
, RECENT_KEY_PACKET_LIST_SHOW
) == 0) {
1336 parse_recent_boolean(value
, &recent
.packet_list_show
);
1337 } else if (strcmp(key
, RECENT_KEY_TREE_VIEW_SHOW
) == 0) {
1338 parse_recent_boolean(value
, &recent
.tree_view_show
);
1339 } else if (strcmp(key
, RECENT_KEY_BYTE_VIEW_SHOW
) == 0) {
1340 parse_recent_boolean(value
, &recent
.byte_view_show
);
1341 } else if (strcmp(key
, RECENT_KEY_PACKET_DIAGRAM_SHOW
) == 0) {
1342 parse_recent_boolean(value
, &recent
.packet_diagram_show
);
1343 } else if (strcmp(key
, RECENT_KEY_STATUSBAR_SHOW
) == 0) {
1344 parse_recent_boolean(value
, &recent
.statusbar_show
);
1345 } else if (strcmp(key
, RECENT_KEY_PACKET_LIST_COLORIZE
) == 0) {
1346 parse_recent_boolean(value
, &recent
.packet_list_colorize
);
1347 } else if (strcmp(key
, RECENT_KEY_CAPTURE_AUTO_SCROLL
) == 0) {
1348 parse_recent_boolean(value
, &recent
.capture_auto_scroll
);
1349 } else if (strcmp(key
, RECENT_GUI_TIME_FORMAT
) == 0) {
1350 recent
.gui_time_format
= (ts_type
)str_to_val(value
, ts_type_values
,
1351 is_packet_configuration_namespace() ? TS_RELATIVE
: TS_ABSOLUTE
);
1352 } else if (strcmp(key
, RECENT_GUI_TIME_PRECISION
) == 0) {
1354 * The value of this item is either TS_PREC_AUTO, which is a
1355 * negative number meaning "pick the display precision based
1356 * on the time stamp precision of the packet", or is a numerical
1357 * value giving the number of decimal places to display, from 0
1360 * It used to be that not all values between 0 and 9 (the maximum
1361 * precision back then) were supported, and that names were
1362 * written out to the recent file.
1364 * If the string value is a valid number in that range, use
1365 * that number, otherwise look it up in the table of names,
1366 * and, if that fails, set it to TS_PREC_AUTO.
1368 if (ws_strtoi32(value
, NULL
, &num_int32
) && num_int32
>= 0 &&
1369 num_int32
<= WS_TSPREC_MAX
) {
1370 recent
.gui_time_precision
= num_int32
;
1372 recent
.gui_time_precision
=
1373 (ts_precision
)str_to_val(value
, ts_precision_values
, TS_PREC_AUTO
);
1375 } else if (strcmp(key
, RECENT_GUI_SECONDS_FORMAT
) == 0) {
1376 recent
.gui_seconds_format
=
1377 (ts_seconds_type
)str_to_val(value
, ts_seconds_values
, TS_SECONDS_DEFAULT
);
1378 } else if (strcmp(key
, RECENT_GUI_ZOOM_LEVEL
) == 0) {
1379 num
= strtol(value
, &p
, 0);
1380 if (p
== value
|| *p
!= '\0')
1381 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1382 recent
.gui_zoom_level
= (int)num
;
1383 } else if (strcmp(key
, RECENT_GUI_BYTES_VIEW
) == 0) {
1384 recent
.gui_bytes_view
=
1385 (bytes_view_type
)str_to_val(value
, bytes_view_type_values
, BYTES_HEX
);
1386 } else if (strcmp(key
, RECENT_GUI_BYTES_ENCODING
) == 0) {
1387 recent
.gui_bytes_encoding
=
1388 (bytes_encoding_type
)str_to_val(value
, bytes_encoding_type_values
, BYTES_ENC_FROM_PACKET
);
1389 } else if (strcmp(key
, RECENT_GUI_PACKET_DIAGRAM_FIELD_VALUES
) == 0) {
1390 parse_recent_boolean(value
, &recent
.gui_packet_diagram_field_values
);
1391 } else if (strcmp(key
, RECENT_GUI_ALLOW_HOVER_SELECTION
) == 0) {
1392 parse_recent_boolean(value
, &recent
.gui_allow_hover_selection
);
1393 } else if (strcmp(key
, RECENT_GUI_FOLLOW_SHOW
) == 0) {
1394 recent
.gui_follow_show
= (bytes_show_type
)str_to_val(value
, bytes_show_values
, SHOW_ASCII
);
1395 } else if (strcmp(key
, RECENT_GUI_FOLLOW_DELTA
) == 0) {
1396 recent
.gui_follow_delta
= (follow_delta_type
)str_to_val(value
, follow_delta_values
, FOLLOW_DELTA_NONE
);
1397 } else if (strcmp(key
, RECENT_GUI_SHOW_BYTES_DECODE
) == 0) {
1398 recent
.gui_show_bytes_decode
= (bytes_decode_type
)str_to_val(value
, show_bytes_decode_values
, DecodeAsNone
);
1399 } else if (strcmp(key
, RECENT_GUI_SHOW_BYTES_SHOW
) == 0) {
1400 recent
.gui_show_bytes_show
= (bytes_show_type
)str_to_val(value
, bytes_show_values
, SHOW_ASCII
);
1401 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_UPPER_PANE
) == 0) {
1402 num
= strtol(value
, &p
, 0);
1403 if (p
== value
|| *p
!= '\0')
1404 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1406 return PREFS_SET_SYNTAX_ERR
; /* number must be positive */
1407 recent
.gui_geometry_main_upper_pane
= (int)num
;
1408 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_LOWER_PANE
) == 0) {
1409 num
= strtol(value
, &p
, 0);
1410 if (p
== value
|| *p
!= '\0')
1411 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1413 return PREFS_SET_SYNTAX_ERR
; /* number must be positive */
1414 recent
.gui_geometry_main_lower_pane
= (int)num
;
1415 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_MASTER_SPLIT
) == 0) {
1416 g_free(recent
.gui_geometry_main_master_split
);
1417 recent
.gui_geometry_main_master_split
= g_strdup(value
);
1418 } else if (strcmp(key
, RECENT_GUI_GEOMETRY_MAIN_EXTRA_SPLIT
) == 0) {
1419 g_free(recent
.gui_geometry_main_extra_split
);
1420 recent
.gui_geometry_main_extra_split
= g_strdup(value
);
1421 } else if (strncmp(key
, RECENT_GUI_GEOMETRY
, sizeof(RECENT_GUI_GEOMETRY
)-1) == 0) {
1422 /* now have something like "gui.geom.win.sub_key", split it into win and sub_key */
1423 char *win
= &key
[sizeof(RECENT_GUI_GEOMETRY
)-1];
1424 char *sub_key
= strchr(win
, '.');
1428 window_geom_recent_read_pair(win
, sub_key
, value
);
1430 } else if (strcmp(key
, RECENT_GUI_CONVERSATION_TABS
) == 0) {
1431 g_list_free_full(recent
.conversation_tabs
, g_free
);
1432 recent
.conversation_tabs
= prefs_get_string_list(value
);
1433 } else if (strcmp(key
, RECENT_GUI_CONVERSATION_TABS_COLUMNS
) == 0) {
1434 g_list_free_full(recent
.conversation_tabs_columns
, g_free
);
1435 recent
.conversation_tabs_columns
= prefs_get_string_list(value
);
1436 } else if (strcmp(key
, RECENT_GUI_ENDPOINT_TABS
) == 0) {
1437 g_list_free_full(recent
.endpoint_tabs
, g_free
);
1438 recent
.endpoint_tabs
= prefs_get_string_list(value
);
1439 } else if (strcmp(key
, RECENT_GUI_ENDPOINT_TABS_COLUMNS
) == 0) {
1440 g_list_free_full(recent
.endpoint_tabs_columns
, g_free
);
1441 recent
.endpoint_tabs_columns
= prefs_get_string_list(value
);
1442 } else if (strcmp(key
, RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES
) == 0) {
1443 parse_recent_boolean(value
, &recent
.gui_rlc_use_pdus_from_mac
);
1444 } else if (strcmp(key
, RECENT_KEY_COL_WIDTH
) == 0) {
1445 col_l
= prefs_get_string_list(value
);
1447 return PREFS_SET_SYNTAX_ERR
;
1448 if ((g_list_length(col_l
) % 2) != 0) {
1449 /* A title didn't have a matching width. */
1450 prefs_clear_string_list(col_l
);
1451 return PREFS_SET_SYNTAX_ERR
;
1453 recent_free_column_width_info(&recent
);
1454 recent
.col_width_list
= NULL
;
1455 col_l_elt
= g_list_first(col_l
);
1457 cfmt
= g_new(col_width_data
, 1);
1458 /* Skip the column format, we don't use it anymore because the
1459 * column indices are in sync and the key since 4.4. Format is
1460 * still written for backwards compatibility.
1462 col_l_elt
= col_l_elt
->next
;
1463 cfmt
->width
= (int)strtol((const char *)col_l_elt
->data
, &p
, 0);
1464 if (p
== col_l_elt
->data
|| (*p
!= '\0' && *p
!= ':')) {
1466 return PREFS_SET_SYNTAX_ERR
; /* number was bad */
1470 cfmt
->xalign
= *(++p
);
1472 cfmt
->xalign
= COLUMN_XALIGN_DEFAULT
;
1475 col_l_elt
= col_l_elt
->next
;
1476 recent
.col_width_list
= g_list_append(recent
.col_width_list
, cfmt
);
1478 prefs_clear_string_list(col_l
);
1479 } else if (strcmp(key
, RECENT_GUI_FILEOPEN_REMEMBERED_DIR
) == 0) {
1480 g_free(recent
.gui_fileopen_remembered_dir
);
1481 recent
.gui_fileopen_remembered_dir
= g_strdup(value
);
1482 } else if (strcmp(key
, RECENT_GUI_TOOLBAR_SHOW
) == 0) {
1483 recent
.gui_additional_toolbars
= prefs_get_string_list(value
);
1484 } else if (strcmp(key
, RECENT_GUI_INTERFACE_TOOLBAR_SHOW
) == 0) {
1485 recent
.interface_toolbars
= prefs_get_string_list(value
);
1487 return PREFS_SET_NO_SUCH_PREF
;
1490 return PREFS_SET_OK
;
1494 /* set one user's recent file key/value pair */
1495 static prefs_set_pref_e
1496 read_set_recent_pair_dynamic(char *key
, const char *value
,
1497 void *private_data _U_
,
1498 bool return_range_errors _U_
)
1500 if (!g_utf8_validate(value
, -1, NULL
)) {
1501 return PREFS_SET_SYNTAX_ERR
;
1503 if (strcmp(key
, RECENT_KEY_CAPTURE_FILE
) == 0) {
1504 add_menu_recent_capture_file(value
, true);
1505 } else if (strcmp(key
, RECENT_KEY_DISPLAY_FILTER
) == 0) {
1506 dfilter_combo_add_recent(value
);
1507 } else if (strcmp(key
, RECENT_KEY_CAPTURE_FILTER
) == 0) {
1508 recent_add_cfilter(NULL
, value
);
1509 } else if (g_str_has_prefix(key
, RECENT_KEY_CAPTURE_FILTER
".")) {
1510 /* strrchr() can't fail - string has a prefix that ends with a "." */
1511 recent_add_cfilter(strrchr(key
, '.') + 1, value
);
1512 #ifdef HAVE_PCAP_REMOTE
1513 } else if (strcmp(key
, RECENT_KEY_REMOTE_HOST
) == 0) {
1514 capture_remote_combo_add_recent(value
);
1518 return PREFS_SET_OK
;
1523 * Given a string of the form "<recent name>:<recent value>", as might appear
1524 * as an argument to a "-o" option, parse it and set the recent value in
1525 * question. Return an indication of whether it succeeded or failed
1529 recent_set_arg(char *prefarg
)
1534 colonp
= strchr(prefarg
, ':');
1536 return PREFS_SET_SYNTAX_ERR
;
1542 * Skip over any white space (there probably won't be any, but
1543 * as we allow it in the preferences file, we might as well
1546 while (g_ascii_isspace(*p
))
1550 * Put the colon back, so if our caller uses, in an
1551 * error message, the string they passed us, the message
1555 return PREFS_SET_SYNTAX_ERR
;
1558 ret
= read_set_recent_pair_static(prefarg
, p
, NULL
, true);
1559 *colonp
= ':'; /* put the colon back */
1564 /* opens the user's recent common file and read the first part */
1566 recent_read_static(char **rf_path_return
, int *rf_errno_return
)
1572 recent
.gui_geometry_main_x
= 20;
1573 recent
.gui_geometry_main_y
= 20;
1574 recent
.gui_geometry_main_width
= DEF_WIDTH
;
1575 recent
.gui_geometry_main_height
= DEF_HEIGHT
;
1576 recent
.gui_geometry_main_maximized
= false;
1578 recent
.gui_geometry_leftalign_actions
= false;
1580 recent
.privs_warn_if_elevated
= true;
1581 recent
.sys_warn_if_no_capture
= true;
1583 recent
.col_width_list
= NULL
;
1584 recent
.gui_geometry_main
= NULL
;
1585 recent
.gui_geometry_main_master_split
= NULL
;
1586 recent
.gui_geometry_main_extra_split
= NULL
;
1587 recent
.gui_profile_switch_check_count
= 1000;
1588 recent
.gui_fileopen_remembered_dir
= NULL
;
1590 /* Construct the pathname of the user's recent common file. */
1591 rf_path
= get_persconffile_path(RECENT_COMMON_FILE_NAME
, false);
1593 /* Read the user's recent common file, if it exists. */
1594 *rf_path_return
= NULL
;
1595 if ((rf
= ws_fopen(rf_path
, "r")) != NULL
) {
1596 /* We succeeded in opening it; read it. */
1597 read_prefs_file(rf_path
, rf
, read_set_recent_common_pair_static
, NULL
);
1601 /* We failed to open it. If we failed for some reason other than
1602 "it doesn't exist", return the errno and the pathname, so our
1603 caller can report the error. */
1604 if (errno
!= ENOENT
) {
1605 *rf_errno_return
= errno
;
1606 *rf_path_return
= rf_path
;
1616 /* opens the user's recent file and read the first part */
1618 recent_read_profile_static(char **rf_path_return
, int *rf_errno_return
)
1620 char *rf_path
, *rf_common_path
;
1624 recent
.main_toolbar_show
= true;
1625 recent
.filter_toolbar_show
= true;
1626 recent
.wireless_toolbar_show
= false;
1627 recent
.packet_list_show
= true;
1628 recent
.tree_view_show
= true;
1629 recent
.byte_view_show
= true;
1630 recent
.packet_diagram_show
= true;
1631 recent
.statusbar_show
= true;
1632 recent
.packet_list_colorize
= true;
1633 recent
.capture_auto_scroll
= true;
1634 recent
.gui_time_format
= TS_RELATIVE
;
1635 recent
.gui_time_precision
= TS_PREC_AUTO
;
1636 recent
.gui_seconds_format
= TS_SECONDS_DEFAULT
;
1637 recent
.gui_zoom_level
= 0;
1638 recent
.gui_bytes_view
= BYTES_HEX
;
1639 recent
.gui_bytes_encoding
= BYTES_ENC_FROM_PACKET
;
1640 recent
.gui_allow_hover_selection
= true;
1641 recent
.gui_follow_show
= SHOW_ASCII
;
1642 recent
.gui_follow_delta
= FOLLOW_DELTA_NONE
;
1643 recent
.gui_show_bytes_decode
= DecodeAsNone
;
1644 recent
.gui_show_bytes_show
= SHOW_ASCII
;
1646 /* pane size of zero will autodetect */
1647 recent
.gui_geometry_main_upper_pane
= 0;
1648 recent
.gui_geometry_main_lower_pane
= 0;
1650 if (recent
.gui_geometry_main
) {
1651 g_free(recent
.gui_geometry_main
);
1652 recent
.gui_geometry_main
= NULL
;
1655 if (recent
.gui_geometry_main_master_split
) {
1656 g_free(recent
.gui_geometry_main_master_split
);
1657 recent
.gui_geometry_main_master_split
= NULL
;
1659 if (recent
.gui_geometry_main_extra_split
) {
1660 g_free(recent
.gui_geometry_main_extra_split
);
1661 recent
.gui_geometry_main_extra_split
= NULL
;
1664 if (recent
.col_width_list
) {
1665 recent_free_column_width_info(&recent
);
1668 if (recent
.gui_fileopen_remembered_dir
) {
1669 g_free (recent
.gui_fileopen_remembered_dir
);
1670 recent
.gui_fileopen_remembered_dir
= NULL
;
1673 if (recent
.gui_additional_toolbars
) {
1674 g_list_free_full (recent
.gui_additional_toolbars
, g_free
);
1675 recent
.gui_additional_toolbars
= NULL
;
1678 if (recent
.interface_toolbars
) {
1679 g_list_free_full (recent
.interface_toolbars
, g_free
);
1680 recent
.interface_toolbars
= NULL
;
1683 /* Construct the pathname of the user's profile recent file. */
1684 rf_path
= get_persconffile_path(RECENT_FILE_NAME
, true);
1686 /* Read the user's recent file, if it exists. */
1687 *rf_path_return
= NULL
;
1688 if ((rf
= ws_fopen(rf_path
, "r")) != NULL
) {
1689 /* We succeeded in opening it; read it. */
1690 read_prefs_file(rf_path
, rf
, read_set_recent_pair_static
, NULL
);
1693 /* XXX: The following code doesn't actually do anything since
1694 * the "recent common file" always exists. Presumably the
1695 * "if (!file_exists())" should actually be "if (file_exists())".
1696 * However, I've left the code as is because this
1697 * behaviour has existed for quite some time and I don't
1698 * know what's supposed to happen at this point.
1699 * ToDo: Determine if the "recent common file" should be read at this point
1701 rf_common_path
= get_persconffile_path(RECENT_COMMON_FILE_NAME
, false);
1702 if (!file_exists(rf_common_path
)) {
1703 /* Read older common settings from recent file */
1704 rf
= ws_fopen(rf_path
, "r");
1705 read_prefs_file(rf_path
, rf
, read_set_recent_common_pair_static
, NULL
);
1708 g_free(rf_common_path
);
1710 /* We failed to open it. If we failed for some reason other than
1711 "it doesn't exist", return the errno and the pathname, so our
1712 caller can report the error. */
1713 if (errno
!= ENOENT
) {
1714 *rf_errno_return
= errno
;
1715 *rf_path_return
= rf_path
;
1723 /* opens the user's recent file and read it out */
1725 recent_read_dynamic(char **rf_path_return
, int *rf_errno_return
)
1731 /* Construct the pathname of the user's recent common file. */
1732 rf_path
= get_persconffile_path(RECENT_COMMON_FILE_NAME
, false);
1733 if (!file_exists (rf_path
)) {
1734 /* Recent common file does not exist, read from default recent */
1736 rf_path
= get_persconffile_path(RECENT_FILE_NAME
, false);
1739 /* Read the user's recent file, if it exists. */
1740 *rf_path_return
= NULL
;
1741 if ((rf
= ws_fopen(rf_path
, "r")) != NULL
) {
1742 /* We succeeded in opening it; read it. */
1743 read_prefs_file(rf_path
, rf
, read_set_recent_pair_dynamic
, NULL
);
1745 /* set dfilter combobox to have an empty line */
1746 dfilter_combo_add_empty();
1748 /* We prepend new capture filters, so reverse them after adding
1749 * all to keep the latest first.
1751 cfilter_recent_reverse_all();
1752 #ifdef HAVE_PCAP_REMOTE
1753 remote_host_reverse();
1757 /* We failed to open it. If we failed for some reason other than
1758 "it doesn't exist", return the errno and the pathname, so our
1759 caller can report the error. */
1760 if (errno
!= ENOENT
) {
1761 *rf_errno_return
= errno
;
1762 *rf_path_return
= rf_path
;
1771 recent_insert_column(int col
)
1773 col_width_data
*col_w
;
1775 col_w
= g_new(col_width_data
, 1);
1777 col_w
->xalign
= COLUMN_XALIGN_DEFAULT
;
1778 recent
.col_width_list
= g_list_insert(recent
.col_width_list
, col_w
, col
);
1782 recent_remove_column(int col
)
1784 GList
*col_l
= g_list_nth(recent
.col_width_list
, col
);
1785 col_width_data
*col_w
;
1789 col_w
= (col_width_data
*)col_l
->data
;
1792 free_col_width_data(col_w
);
1795 recent
.col_width_list
= g_list_delete_link(recent
.col_width_list
, col_l
);
1799 recent_get_column_width(int col
)
1801 col_width_data
*col_w
;
1803 col_w
= g_list_nth_data(recent
.col_width_list
, col
);
1805 return col_w
->width
;
1807 /* Make sure the recent column list isn't out of sync with the
1808 * number of columns (e.g., for a brand new profile.)
1810 for (unsigned colnr
= g_list_length(recent
.col_width_list
); colnr
< g_list_length(prefs
.col_list
); colnr
++) {
1811 recent_insert_column(colnr
);
1819 recent_set_column_width(int col
, int width
)
1821 col_width_data
*col_w
;
1823 col_w
= g_list_nth_data(recent
.col_width_list
, col
);
1825 col_w
->width
= width
;
1827 /* Make sure the recent column list isn't out of sync with the
1828 * number of columns (e.g., for a brand new profile.)
1830 for (unsigned colnr
= g_list_length(recent
.col_width_list
); colnr
< g_list_length(prefs
.col_list
); colnr
++) {
1831 recent_insert_column(colnr
);
1833 col_w
= g_list_nth_data(recent
.col_width_list
, col
);
1835 col_w
->width
= width
;
1841 recent_get_column_xalign(int col
)
1843 col_width_data
*col_w
;
1845 col_w
= g_list_nth_data(recent
.col_width_list
, col
);
1847 return col_w
->xalign
;
1849 /* Make sure the recent column list isn't out of sync with the
1850 * number of columns (e.g., for a brand new profile.)
1852 for (unsigned colnr
= g_list_length(recent
.col_width_list
); colnr
< g_list_length(prefs
.col_list
); colnr
++) {
1853 recent_insert_column(colnr
);
1857 return COLUMN_XALIGN_DEFAULT
;
1861 recent_set_column_xalign(int col
, char xalign
)
1863 col_width_data
*col_w
;
1865 col_w
= g_list_nth_data(recent
.col_width_list
, col
);
1867 col_w
->xalign
= xalign
;
1869 /* Make sure the recent column list isn't out of sync with the
1870 * number of columns (e.g., for a brand new profile.)
1872 for (unsigned colnr
= g_list_length(recent
.col_width_list
); colnr
< g_list_length(prefs
.col_list
); colnr
++) {
1873 recent_insert_column(colnr
);
1875 col_w
= g_list_nth_data(recent
.col_width_list
, col
);
1877 col_w
->xalign
= xalign
;
1885 memset(&recent
, 0, sizeof(recent_settings_t
));
1889 recent_cleanup(void)
1891 recent_free_column_width_info(&recent
);
1892 g_free(recent
.gui_geometry_main
);
1893 g_free(recent
.gui_geometry_main_master_split
);
1894 g_free(recent
.gui_geometry_main_extra_split
);
1895 g_free(recent
.gui_fileopen_remembered_dir
);
1896 g_list_free_full(recent
.gui_additional_toolbars
, g_free
);
1897 g_list_free_full(recent
.interface_toolbars
, g_free
);
1898 prefs_clear_string_list(recent
.conversation_tabs
);
1899 prefs_clear_string_list(recent
.conversation_tabs_columns
);
1900 prefs_clear_string_list(recent
.endpoint_tabs
);
1901 prefs_clear_string_list(recent
.endpoint_tabs_columns
);
1902 prefs_clear_string_list(recent
.custom_colors
);