1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2011 Vic Lee
4  * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
5  * Copyright (C) 2016-2021 Antenore Gatta, Giovanni Panozzo
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA  02110-1301, USA.
21  *
22  *  In addition, as a special exception, the copyright holders give
23  *  permission to link the code of portions of this program with the
24  *  OpenSSL library under certain conditions as described in each
25  *  individual source file, and distribute linked combinations
26  *  including the two.
27  *  You must obey the GNU General Public License in all respects
28  *  for all of the code used other than OpenSSL. *  If you modify
29  *  file(s) with this exception, you may extend this exception to your
30  *  version of the file(s), but you are not obligated to do so. *  If you
31  *  do not wish to do so, delete this exception statement from your
32  *  version. *  If you delete this exception statement from all source
33  *  files in the program, then also delete it here.
34  *
35  */
36 
37 #include "config.h"
38 
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/time.h>
43 #include <sys/utsname.h>
44 
45 #include <glib/gstdio.h>
46 #include <gdk/gdkkeysyms.h>
47 #include <gtk/gtk.h>
48 
49 #include "remmina_sodium.h"
50 
51 #include "remmina_public.h"
52 #include "remmina_string_array.h"
53 #include "remmina_pref.h"
54 #include "remmina/remmina_trace_calls.h"
55 
56 const gchar *default_resolutions = "640x480,800x600,1024x768,1152x864,1280x960,1400x1050";
57 const gchar *default_keystrokes = "Send hello world§hello world\\n";
58 
59 gchar *remmina_keymap_file;
60 static GHashTable *remmina_keymap_table = NULL;
61 
62 /* We could customize this further if there are more requirements */
63 static const gchar *default_keymap_data = "# Please check gdk/gdkkeysyms.h for a full list of all key names or hex key values\n"
64 					  "\n"
65 					  "[Map Meta Keys]\n"
66 					  "Super_L = Meta_L\n"
67 					  "Super_R = Meta_R\n"
68 					  "Meta_L = Super_L\n"
69 					  "Meta_R = Super_R\n";
70 
remmina_pref_gen_secret(void)71 static void remmina_pref_gen_secret(void)
72 {
73 	TRACE_CALL(__func__);
74 	guchar s[32];
75 	gint i;
76 	GKeyFile *gkeyfile;
77 	g_autofree gchar *content = NULL;
78 	gsize length;
79 
80 	for (i = 0; i < 32; i++)
81 		s[i] = (guchar)(randombytes_uniform(257));
82 	remmina_pref.secret = g_base64_encode(s, 32);
83 
84 	gkeyfile = g_key_file_new();
85 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
86 	g_key_file_set_string(gkeyfile, "remmina_pref", "secret", remmina_pref.secret);
87 	content = g_key_file_to_data(gkeyfile, &length, NULL);
88 	g_file_set_contents(remmina_pref_file, content, length, NULL);
89 
90 	g_key_file_free(gkeyfile);
91 }
92 
remmina_pref_get_keyval_from_str(const gchar * str)93 static guint remmina_pref_get_keyval_from_str(const gchar *str)
94 {
95 	TRACE_CALL(__func__);
96 	guint k;
97 
98 	if (!str)
99 		return 0;
100 
101 	k = gdk_keyval_from_name(str);
102 	if (!k)
103 		if (sscanf(str, "%x", &k) < 1)
104 			k = 0;
105 	return k;
106 }
107 
remmina_pref_init_keymap(void)108 static void remmina_pref_init_keymap(void)
109 {
110 	TRACE_CALL(__func__);
111 	GKeyFile *gkeyfile;
112 	gchar **groups;
113 	gchar **gptr;
114 	gchar **keys;
115 	gchar **kptr;
116 	gsize nkeys;
117 	g_autofree gchar *value = NULL;
118 	guint *table;
119 	guint *tableptr;
120 	guint k1, k2;
121 
122 	if (remmina_keymap_table)
123 		g_hash_table_destroy(remmina_keymap_table);
124 	remmina_keymap_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
125 
126 	gkeyfile = g_key_file_new();
127 	if (!g_key_file_load_from_file(gkeyfile, remmina_keymap_file, G_KEY_FILE_NONE, NULL)) {
128 		if (!g_key_file_load_from_data(gkeyfile, default_keymap_data, strlen(default_keymap_data), G_KEY_FILE_NONE,
129 					       NULL)) {
130 			g_print("Failed to initialize keymap table\n");
131 			g_key_file_free(gkeyfile);
132 			return;
133 		}
134 	}
135 
136 	groups = g_key_file_get_groups(gkeyfile, NULL);
137 	gptr = groups;
138 	while (*gptr) {
139 		keys = g_key_file_get_keys(gkeyfile, *gptr, &nkeys, NULL);
140 		table = g_new0(guint, nkeys * 2 + 1);
141 		g_hash_table_insert(remmina_keymap_table, g_strdup(*gptr), table);
142 
143 		kptr = keys;
144 		tableptr = table;
145 		while (*kptr) {
146 			k1 = remmina_pref_get_keyval_from_str(*kptr);
147 			if (k1) {
148 				value = g_key_file_get_string(gkeyfile, *gptr, *kptr, NULL);
149 				k2 = remmina_pref_get_keyval_from_str(value);
150 				*tableptr++ = k1;
151 				*tableptr++ = k2;
152 			}
153 			kptr++;
154 		}
155 		g_strfreev(keys);
156 		gptr++;
157 	}
158 	g_strfreev(groups);
159 	g_key_file_free(gkeyfile);
160 }
161 
162 /** @todo remmina_pref_file_do_copy and remmina_file_manager_do_copy to remmina_files_copy */
remmina_pref_file_do_copy(const char * src_path,const char * dst_path)163 static gboolean remmina_pref_file_do_copy(const char *src_path, const char *dst_path)
164 {
165 	GFile *src = g_file_new_for_path(src_path), *dst = g_file_new_for_path(dst_path);
166 	/* We don’t overwrite the target if it exists, because overwrite is not set */
167 	const gboolean ok = g_file_copy(src, dst, G_FILE_COPY_NONE, NULL, NULL, NULL, NULL);
168 
169 	g_object_unref(dst);
170 	g_object_unref(src);
171 
172 	return ok;
173 }
174 
remmina_pref_file_load_colors(GKeyFile * gkeyfile,RemminaColorPref * color_pref)175 void remmina_pref_file_load_colors(GKeyFile *gkeyfile, RemminaColorPref *color_pref)
176 {
177 	const struct {
178 		const char *	name;
179 		char **		setting;
180 		char *		fallback;
181 	} colors[] = {
182 		{ "background",		  &color_pref->background,	     "#d5ccba" },
183 		{ "cursor",		  &color_pref->cursor,		     "#45373c" },
184 		{ "cursor_foreground",	  &color_pref->cursor_foreground,    "#d5ccba" },
185 		{ "highlight",		  &color_pref->highlight,	     "#45373c" },
186 		{ "highlight_foreground", &color_pref->highlight_foreground, "#d5ccba" },
187 		{ "colorBD",		  &color_pref->colorBD,		     "#45373c" },
188 		{ "foreground",		  &color_pref->foreground,	     "#45373c" },
189 		{ "color0",		  &color_pref->color0,		     "#20111b" },
190 		{ "color1",		  &color_pref->color1,		     "#be100e" },
191 		{ "color2",		  &color_pref->color2,		     "#858162" },
192 		{ "color3",		  &color_pref->color3,		     "#eaa549" },
193 		{ "color4",		  &color_pref->color4,		     "#426a79" },
194 		{ "color5",		  &color_pref->color5,		     "#97522c" },
195 		{ "color6",		  &color_pref->color6,		     "#989a9c" },
196 		{ "color7",		  &color_pref->color7,		     "#968c83" },
197 		{ "color8",		  &color_pref->color8,		     "#5e5252" },
198 		{ "color9",		  &color_pref->color9,		     "#be100e" },
199 		{ "color10",		  &color_pref->color10,		     "#858162" },
200 		{ "color11",		  &color_pref->color11,		     "#eaa549" },
201 		{ "color12",		  &color_pref->color12,		     "#426a79" },
202 		{ "color13",		  &color_pref->color13,		     "#97522c" },
203 		{ "color14",		  &color_pref->color14,		     "#989a9c" },
204 		{ "color15",		  &color_pref->color15,		     "#d5ccba" },
205 	};
206 
207 	int i;
208 
209 	for (i = 0; i < (sizeof(colors) / sizeof(colors[0])); i++) {
210 		if (g_key_file_has_key(gkeyfile, "ssh_colors", colors[i].name, NULL))
211 			*colors[i].setting = g_key_file_get_string(gkeyfile, "ssh_colors", colors[i].name,
212 								   NULL);
213 		else
214 			*colors[i].setting = colors[i].fallback;
215 	}
216 }
217 
remmina_pref_init(void)218 void remmina_pref_init(void)
219 {
220 	TRACE_CALL(__func__);
221 	GKeyFile *gkeyfile;
222 	gchar *remmina_dir;
223 	const gchar *filename = "remmina.pref";
224 	const gchar *colors_filename = "remmina.colors";
225 	g_autofree gchar *remmina_colors_file = NULL;
226 	GDir *dir;
227 	const gchar *legacy = ".remmina";
228 	int i;
229 
230 	remmina_dir = g_build_path("/", g_get_user_config_dir(), "remmina", NULL);
231 	/* Create the XDG_CONFIG_HOME directory */
232 	g_mkdir_with_parents(remmina_dir, 0750);
233 
234 	g_free(remmina_dir), remmina_dir = NULL;
235 	/* Legacy ~/.remmina we copy the existing remmina.pref file inside
236 	 * XDG_CONFIG_HOME */
237 	remmina_dir = g_build_path("/", g_get_home_dir(), legacy, NULL);
238 	if (g_file_test(remmina_dir, G_FILE_TEST_IS_DIR)) {
239 		dir = g_dir_open(remmina_dir, 0, NULL);
240 		remmina_pref_file_do_copy(
241 			g_build_path("/", remmina_dir, filename, NULL),
242 			g_build_path("/", g_get_user_config_dir(),
243 				     "remmina", filename, NULL));
244 	}
245 
246 	/* /usr/local/etc/remmina */
247 	const gchar *const *dirs = g_get_system_config_dirs();
248 
249 	g_free(remmina_dir), remmina_dir = NULL;
250 	for (i = 0; dirs[i] != NULL; ++i) {
251 		remmina_dir = g_build_path("/", dirs[i], "remmina", NULL);
252 		if (g_file_test(remmina_dir, G_FILE_TEST_IS_DIR)) {
253 			dir = g_dir_open(remmina_dir, 0, NULL);
254 			while ((filename = g_dir_read_name(dir)) != NULL) {
255 				remmina_pref_file_do_copy(
256 					g_build_path("/", remmina_dir, filename, NULL),
257 					g_build_path("/", g_get_user_config_dir(),
258 						     "remmina", filename, NULL));
259 			}
260 			g_free(remmina_dir), remmina_dir = NULL;
261 		}
262 	}
263 
264 	/* The last case we use  the home ~/.config/remmina */
265 	if (remmina_dir != NULL)
266 		g_free(remmina_dir), remmina_dir = NULL;
267 	remmina_dir = g_build_path("/", g_get_user_config_dir(),
268 				   "remmina", NULL);
269 
270 	remmina_pref_file = g_strdup_printf("%s/remmina.pref", remmina_dir);
271 	/* remmina.colors */
272 	remmina_colors_file = g_strdup_printf("%s/%s", remmina_dir, colors_filename);
273 
274 	remmina_keymap_file = g_strdup_printf("%s/remmina.keymap", remmina_dir);
275 
276 	gkeyfile = g_key_file_new();
277 
278 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
279 
280 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "save_view_mode", NULL))
281 		remmina_pref.save_view_mode = g_key_file_get_boolean(gkeyfile, "remmina_pref", "save_view_mode", NULL);
282 	else
283 		remmina_pref.save_view_mode = TRUE;
284 
285 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "use_master_password", NULL))
286 		remmina_pref.use_master_password = g_key_file_get_boolean(gkeyfile, "remmina_pref", "use_master_password", NULL);
287 	else
288 		remmina_pref.use_master_password = FALSE;
289 
290 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "unlock_timeout", NULL))
291 		remmina_pref.unlock_timeout = g_key_file_get_integer(gkeyfile, "remmina_pref", "unlock_timeout", NULL);
292 	else
293 		remmina_pref.unlock_timeout = 0;
294 
295 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "unlock_password", NULL))
296 		remmina_pref.unlock_password = g_key_file_get_string(gkeyfile, "remmina_pref", "unlock_password", NULL);
297 	else
298 		remmina_pref.unlock_password = g_strdup("");
299 
300 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "trust_all", NULL))
301 		remmina_pref.trust_all = g_key_file_get_boolean(gkeyfile, "remmina_pref", "trust_all", NULL);
302 	else
303 		remmina_pref.trust_all = FALSE;
304 
305 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "fullscreen_on_auto", NULL))
306 		remmina_pref.fullscreen_on_auto = g_key_file_get_boolean(gkeyfile, "remmina_pref", "fullscreen_on_auto", NULL);
307 	else
308 		remmina_pref.fullscreen_on_auto = TRUE;
309 
310 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "floating_toolbar_placement", NULL))
311 		remmina_pref.floating_toolbar_placement = g_key_file_get_integer(gkeyfile, "remmina_pref", "floating_toolbar_placement", NULL);
312 	else
313 		remmina_pref.floating_toolbar_placement = FLOATING_TOOLBAR_PLACEMENT_TOP;
314 
315 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "prevent_snap_welcome_message", NULL))
316 		remmina_pref.prevent_snap_welcome_message = g_key_file_get_boolean(gkeyfile, "remmina_pref", "prevent_snap_welcome_message", NULL);
317 	else
318 		remmina_pref.prevent_snap_welcome_message = FALSE;
319 
320 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "last_quickconnect_protocol", NULL))
321 		remmina_pref.last_quickconnect_protocol = g_key_file_get_string(gkeyfile, "remmina_pref", "last_quickconnect_protocol", NULL);
322 	else
323 		remmina_pref.last_quickconnect_protocol = g_strdup("");
324 
325 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "toolbar_placement", NULL))
326 		remmina_pref.toolbar_placement = g_key_file_get_integer(gkeyfile, "remmina_pref", "toolbar_placement", NULL);
327 	else
328 		remmina_pref.toolbar_placement = TOOLBAR_PLACEMENT_LEFT;
329 
330 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "always_show_tab", NULL))
331 		remmina_pref.always_show_tab = g_key_file_get_boolean(gkeyfile, "remmina_pref", "always_show_tab", NULL);
332 	else
333 		remmina_pref.always_show_tab = TRUE;
334 
335 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "hide_connection_toolbar", NULL))
336 		remmina_pref.hide_connection_toolbar = g_key_file_get_boolean(gkeyfile, "remmina_pref",
337 									      "hide_connection_toolbar", NULL);
338 	else
339 		remmina_pref.hide_connection_toolbar = FALSE;
340 
341 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "hide_searchbar", NULL))
342 		remmina_pref.hide_searchbar = g_key_file_get_boolean(gkeyfile, "remmina_pref",
343 								     "hide_searchbar", NULL);
344 	else
345 		remmina_pref.hide_searchbar = FALSE;
346 
347 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "default_action", NULL))
348 		remmina_pref.default_action = g_key_file_get_integer(gkeyfile, "remmina_pref", "default_action", NULL);
349 	else
350 		remmina_pref.default_action = REMMINA_ACTION_CONNECT;
351 
352 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "scale_quality", NULL))
353 		remmina_pref.scale_quality = g_key_file_get_integer(gkeyfile, "remmina_pref", "scale_quality", NULL);
354 	else
355 		remmina_pref.scale_quality = GDK_INTERP_HYPER;
356 
357 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "hide_toolbar", NULL))
358 		remmina_pref.hide_toolbar = g_key_file_get_boolean(gkeyfile, "remmina_pref", "hide_toolbar", NULL);
359 	else
360 		remmina_pref.hide_toolbar = FALSE;
361 
362 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "small_toolbutton", NULL))
363 		remmina_pref.small_toolbutton = g_key_file_get_boolean(gkeyfile, "remmina_pref", "small_toolbutton", NULL);
364 	else
365 		remmina_pref.small_toolbutton = FALSE;
366 
367 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "view_file_mode", NULL))
368 		remmina_pref.view_file_mode = g_key_file_get_integer(gkeyfile, "remmina_pref", "view_file_mode", NULL);
369 	else
370 		remmina_pref.view_file_mode = REMMINA_VIEW_FILE_LIST;
371 
372 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "resolutions", NULL))
373 		remmina_pref.resolutions = g_key_file_get_string(gkeyfile, "remmina_pref", "resolutions", NULL);
374 	else
375 		remmina_pref.resolutions = g_strdup(default_resolutions);
376 
377 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "keystrokes", NULL))
378 		remmina_pref.keystrokes = g_key_file_get_string(gkeyfile, "remmina_pref", "keystrokes", NULL);
379 	else
380 		remmina_pref.keystrokes = g_strdup(default_keystrokes);
381 
382 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "main_width", NULL))
383 		remmina_pref.main_width = MAX(600, g_key_file_get_integer(gkeyfile, "remmina_pref", "main_width", NULL));
384 	else
385 		remmina_pref.main_width = 600;
386 
387 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "main_height", NULL))
388 		remmina_pref.main_height = MAX(400, g_key_file_get_integer(gkeyfile, "remmina_pref", "main_height", NULL));
389 	else
390 		remmina_pref.main_height = 400;
391 
392 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "main_maximize", NULL))
393 		remmina_pref.main_maximize = g_key_file_get_boolean(gkeyfile, "remmina_pref", "main_maximize", NULL);
394 	else
395 		remmina_pref.main_maximize = FALSE;
396 
397 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "main_sort_column_id", NULL))
398 		remmina_pref.main_sort_column_id = g_key_file_get_integer(gkeyfile, "remmina_pref", "main_sort_column_id",
399 									  NULL);
400 	else
401 		remmina_pref.main_sort_column_id = 1;
402 
403 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "main_sort_order", NULL))
404 		remmina_pref.main_sort_order = g_key_file_get_integer(gkeyfile, "remmina_pref", "main_sort_order", NULL);
405 	else
406 		remmina_pref.main_sort_order = 0;
407 
408 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "expanded_group", NULL))
409 		remmina_pref.expanded_group = g_key_file_get_string(gkeyfile, "remmina_pref", "expanded_group", NULL);
410 	else
411 		remmina_pref.expanded_group = g_strdup("");
412 
413 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "toolbar_pin_down", NULL))
414 		remmina_pref.toolbar_pin_down = g_key_file_get_boolean(gkeyfile, "remmina_pref", "toolbar_pin_down", NULL);
415 	else
416 		remmina_pref.toolbar_pin_down = FALSE;
417 
418 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "ssh_loglevel", NULL))
419 		remmina_pref.ssh_loglevel = g_key_file_get_integer(gkeyfile, "remmina_pref", "ssh_loglevel", NULL);
420 	else
421 		remmina_pref.ssh_loglevel = DEFAULT_SSH_LOGLEVEL;
422 
423 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "deny_screenshot_clipboard", NULL))
424 		remmina_pref.deny_screenshot_clipboard = g_key_file_get_boolean(gkeyfile, "remmina_pref", "deny_screenshot_clipboard", NULL);
425 	else
426 		remmina_pref.deny_screenshot_clipboard = TRUE;
427 
428 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "datadir_path", NULL))
429 		remmina_pref.datadir_path = g_key_file_get_string(gkeyfile, "remmina_pref", "datadir_path", NULL);
430 	else
431 		remmina_pref.datadir_path = g_strdup("");
432 
433 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "remmina_file_name", NULL))
434 		remmina_pref.remmina_file_name = g_key_file_get_string(gkeyfile, "remmina_pref", "remmina_file_name", NULL);
435 	else
436 		remmina_pref.remmina_file_name = g_strdup("%G_%P_%N_%h");
437 
438 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "screenshot_path", NULL)) {
439 		remmina_pref.screenshot_path = g_key_file_get_string(gkeyfile, "remmina_pref", "screenshot_path", NULL);
440 	} else {
441 		remmina_pref.screenshot_path = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
442 		if (remmina_pref.screenshot_path == NULL)
443 			remmina_pref.screenshot_path = g_get_home_dir();
444 	}
445 
446 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "screenshot_name", NULL))
447 		remmina_pref.screenshot_name = g_key_file_get_string(gkeyfile, "remmina_pref", "screenshot_name", NULL);
448 	else
449 		remmina_pref.screenshot_name = g_strdup("remmina_%p_%h_%Y%m%d-%H%M%S");
450 
451 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "ssh_parseconfig", NULL))
452 		remmina_pref.ssh_parseconfig = g_key_file_get_boolean(gkeyfile, "remmina_pref", "ssh_parseconfig", NULL);
453 	else
454 		remmina_pref.ssh_parseconfig = DEFAULT_SSH_PARSECONFIG;
455 
456 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "sshtunnel_port", NULL))
457 		remmina_pref.sshtunnel_port = g_key_file_get_integer(gkeyfile, "remmina_pref", "sshtunnel_port", NULL);
458 	else
459 		remmina_pref.sshtunnel_port = DEFAULT_SSHTUNNEL_PORT;
460 
461 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "ssh_tcp_keepidle", NULL))
462 		remmina_pref.ssh_tcp_keepidle = g_key_file_get_integer(gkeyfile, "remmina_pref", "ssh_tcp_keepidle", NULL);
463 	else
464 		remmina_pref.ssh_tcp_keepidle = SSH_SOCKET_TCP_KEEPIDLE;
465 
466 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "ssh_tcp_keepintvl", NULL))
467 		remmina_pref.ssh_tcp_keepintvl = g_key_file_get_integer(gkeyfile, "remmina_pref", "ssh_tcp_keepintvl", NULL);
468 	else
469 		remmina_pref.ssh_tcp_keepintvl = SSH_SOCKET_TCP_KEEPINTVL;
470 
471 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "ssh_tcp_keepcnt", NULL))
472 		remmina_pref.ssh_tcp_keepcnt = g_key_file_get_integer(gkeyfile, "remmina_pref", "ssh_tcp_keepcnt", NULL);
473 	else
474 		remmina_pref.ssh_tcp_keepcnt = SSH_SOCKET_TCP_KEEPCNT;
475 
476 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "ssh_tcp_usrtimeout", NULL))
477 		remmina_pref.ssh_tcp_usrtimeout = g_key_file_get_integer(gkeyfile, "remmina_pref", "ssh_tcp_usrtimeout", NULL);
478 	else
479 		remmina_pref.ssh_tcp_usrtimeout = SSH_SOCKET_TCP_USER_TIMEOUT;
480 
481 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "applet_new_ontop", NULL))
482 		remmina_pref.applet_new_ontop = g_key_file_get_boolean(gkeyfile, "remmina_pref", "applet_new_ontop", NULL);
483 	else
484 		remmina_pref.applet_new_ontop = FALSE;
485 
486 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "applet_hide_count", NULL))
487 		remmina_pref.applet_hide_count = g_key_file_get_boolean(gkeyfile, "remmina_pref", "applet_hide_count", NULL);
488 	else
489 		remmina_pref.applet_hide_count = FALSE;
490 
491 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "applet_enable_avahi", NULL))
492 		remmina_pref.applet_enable_avahi = g_key_file_get_boolean(gkeyfile, "remmina_pref", "applet_enable_avahi",
493 									  NULL);
494 	else
495 		remmina_pref.applet_enable_avahi = FALSE;
496 
497 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "disable_tray_icon", NULL))
498 		remmina_pref.disable_tray_icon = g_key_file_get_boolean(gkeyfile, "remmina_pref", "disable_tray_icon", NULL);
499 	else
500 		remmina_pref.disable_tray_icon = FALSE;
501 
502 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "dark_theme", NULL))
503 		remmina_pref.dark_theme = g_key_file_get_boolean(gkeyfile, "remmina_pref", "dark_theme", NULL);
504 	else
505 		remmina_pref.dark_theme = FALSE;
506 
507 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "grab_color_switch", NULL))
508 		remmina_pref.grab_color_switch = g_key_file_get_boolean(gkeyfile, "remmina_pref", "grab_color_switch", NULL);
509 	else
510 		remmina_pref.grab_color_switch = FALSE;
511 
512 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "grab_color", NULL))
513 		remmina_pref.grab_color = g_key_file_get_string(gkeyfile, "remmina_pref", "grab_color", NULL);
514 	else
515 		remmina_pref.grab_color = "#00ff00";
516 
517 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "recent_maximum", NULL))
518 		remmina_pref.recent_maximum = g_key_file_get_integer(gkeyfile, "remmina_pref", "recent_maximum", NULL);
519 	else
520 		remmina_pref.recent_maximum = 10;
521 
522 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "default_mode", NULL))
523 		remmina_pref.default_mode = g_key_file_get_integer(gkeyfile, "remmina_pref", "default_mode", NULL);
524 	else
525 		remmina_pref.default_mode = 0;
526 
527 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "tab_mode", NULL))
528 		remmina_pref.tab_mode = g_key_file_get_integer(gkeyfile, "remmina_pref", "tab_mode", NULL);
529 	else
530 		remmina_pref.tab_mode = 0;
531 
532 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "fullscreen_toolbar_visibility", NULL))
533 		remmina_pref.fullscreen_toolbar_visibility = g_key_file_get_integer(gkeyfile, "remmina_pref", "fullscreen_toolbar_visibility", NULL);
534 	else
535 		remmina_pref.fullscreen_toolbar_visibility = FLOATING_TOOLBAR_VISIBILITY_PEEKING;
536 
537 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "auto_scroll_step", NULL))
538 		remmina_pref.auto_scroll_step = g_key_file_get_integer(gkeyfile, "remmina_pref", "auto_scroll_step", NULL);
539 	else
540 		remmina_pref.auto_scroll_step = 10;
541 
542 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "hostkey", NULL))
543 		remmina_pref.hostkey = g_key_file_get_integer(gkeyfile, "remmina_pref", "hostkey", NULL);
544 	else
545 		remmina_pref.hostkey = GDK_KEY_Control_R;
546 
547 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_fullscreen", NULL))
548 		remmina_pref.shortcutkey_fullscreen = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_fullscreen",
549 									     NULL);
550 	else
551 		remmina_pref.shortcutkey_fullscreen = GDK_KEY_f;
552 
553 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_autofit", NULL))
554 		remmina_pref.shortcutkey_autofit = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_autofit",
555 									  NULL);
556 	else
557 		remmina_pref.shortcutkey_autofit = GDK_KEY_1;
558 
559 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_nexttab", NULL))
560 		remmina_pref.shortcutkey_nexttab = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_nexttab",
561 									  NULL);
562 	else
563 		remmina_pref.shortcutkey_nexttab = GDK_KEY_Right;
564 
565 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_prevtab", NULL))
566 		remmina_pref.shortcutkey_prevtab = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_prevtab",
567 									  NULL);
568 	else
569 		remmina_pref.shortcutkey_prevtab = GDK_KEY_Left;
570 
571 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_scale", NULL))
572 		remmina_pref.shortcutkey_scale = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_scale", NULL);
573 	else
574 		remmina_pref.shortcutkey_scale = GDK_KEY_s;
575 
576 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_viewonly", NULL))
577 		remmina_pref.shortcutkey_viewonly = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_viewonly", NULL);
578 	else
579 		remmina_pref.shortcutkey_viewonly = GDK_KEY_m;
580 
581 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_multimon", NULL))
582 		remmina_pref.shortcutkey_multimon = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_multimon", NULL);
583 	else
584 		remmina_pref.shortcutkey_multimon = GDK_KEY_Page_Up;
585 
586 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_grab", NULL))
587 		remmina_pref.shortcutkey_grab = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_grab", NULL);
588 	else
589 		remmina_pref.shortcutkey_grab = GDK_KEY_Control_R;
590 
591 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_minimize", NULL))
592 		remmina_pref.shortcutkey_minimize = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_minimize", NULL);
593 	else
594 		remmina_pref.shortcutkey_minimize = GDK_KEY_F9;
595 
596 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_screenshot", NULL))
597 		remmina_pref.shortcutkey_screenshot = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_screenshot", NULL);
598 	else
599 		remmina_pref.shortcutkey_screenshot = GDK_KEY_F12;
600 
601 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_disconnect", NULL))
602 		remmina_pref.shortcutkey_disconnect = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_disconnect",
603 									     NULL);
604 	else
605 		remmina_pref.shortcutkey_disconnect = GDK_KEY_F4;
606 
607 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "shortcutkey_toolbar", NULL))
608 		remmina_pref.shortcutkey_toolbar = g_key_file_get_integer(gkeyfile, "remmina_pref", "shortcutkey_toolbar",
609 									  NULL);
610 	else
611 		remmina_pref.shortcutkey_toolbar = GDK_KEY_t;
612 
613 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "secret", NULL))
614 		remmina_pref.secret = g_key_file_get_string(gkeyfile, "remmina_pref", "secret", NULL);
615 	else
616 		remmina_pref.secret = NULL;
617 
618 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "uid", NULL))
619 		remmina_pref.uid = g_key_file_get_string(gkeyfile, "remmina_pref", "uid", NULL);
620 	else
621 		remmina_pref.uid = NULL;
622 
623 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_font", NULL))
624 		remmina_pref.vte_font = g_key_file_get_string(gkeyfile, "remmina_pref", "vte_font", NULL);
625 	else
626 		remmina_pref.vte_font = 0;
627 
628 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_allow_bold_text", NULL))
629 		remmina_pref.vte_allow_bold_text = g_key_file_get_boolean(gkeyfile, "remmina_pref", "vte_allow_bold_text",
630 									  NULL);
631 	else
632 		remmina_pref.vte_allow_bold_text = TRUE;
633 
634 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_lines", NULL))
635 		remmina_pref.vte_lines = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_lines", NULL);
636 	else
637 		remmina_pref.vte_lines = 512;
638 
639 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_copy", NULL))
640 		remmina_pref.vte_shortcutkey_copy = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_copy",
641 									   NULL);
642 	else
643 		remmina_pref.vte_shortcutkey_copy = GDK_KEY_c;
644 
645 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_paste", NULL))
646 		remmina_pref.vte_shortcutkey_paste = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_paste",
647 									    NULL);
648 	else
649 		remmina_pref.vte_shortcutkey_paste = GDK_KEY_v;
650 
651 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_select_all", NULL))
652 		remmina_pref.vte_shortcutkey_select_all = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_select_all",
653 										 NULL);
654 	else
655 		remmina_pref.vte_shortcutkey_select_all = GDK_KEY_a;
656 
657 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_increase_font", NULL))
658 		remmina_pref.vte_shortcutkey_increase_font = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_increase_font",
659 										    NULL);
660 	else
661 		remmina_pref.vte_shortcutkey_increase_font = GDK_KEY_Page_Up;
662 
663 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_decrease_font", NULL))
664 		remmina_pref.vte_shortcutkey_decrease_font = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_decrease_font",
665 										    NULL);
666 	else
667 		remmina_pref.vte_shortcutkey_decrease_font = GDK_KEY_Page_Down;
668 
669 	if (g_key_file_has_key(gkeyfile, "remmina_pref", "vte_shortcutkey_search_text", NULL))
670 		remmina_pref.vte_shortcutkey_search_text = g_key_file_get_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_search_text",
671 										  NULL);
672 	else
673 		remmina_pref.vte_shortcutkey_search_text = GDK_KEY_g;
674 
675 
676 	remmina_pref_file_load_colors(gkeyfile, &remmina_pref.color_pref);
677 
678 	if (g_key_file_has_key(gkeyfile, "usage_stats", "periodic_usage_stats_permitted", NULL))
679 		remmina_pref.periodic_usage_stats_permitted = g_key_file_get_boolean(gkeyfile, "usage_stats", "periodic_usage_stats_permitted", NULL);
680 	else
681 		remmina_pref.periodic_usage_stats_permitted = FALSE;
682 
683 	if (g_key_file_has_key(gkeyfile, "usage_stats", "periodic_usage_stats_last_sent", NULL))
684 		remmina_pref.periodic_usage_stats_last_sent = g_key_file_get_int64(gkeyfile, "usage_stats", "periodic_usage_stats_last_sent", NULL);
685 	else
686 		remmina_pref.periodic_usage_stats_last_sent = 0;
687 
688 	if (g_key_file_has_key(gkeyfile, "usage_stats", "periodic_usage_stats_uuid_prefix", NULL))
689 		remmina_pref.periodic_usage_stats_uuid_prefix = g_key_file_get_string(gkeyfile, "usage_stats", "periodic_usage_stats_uuid_prefix", NULL);
690 	else
691 		remmina_pref.periodic_usage_stats_uuid_prefix = NULL;
692 
693 	/** RMNEWS_ENABLE_NEWS is equal to 0 (FALSE) when compiled with -DWiTH_NEWS=OFF,
694 	 * otherwise is value is 1 (TRUE), that is the default value
695 	 */
696 	if (RMNEWS_ENABLE_NEWS == 0)
697 		remmina_pref.periodic_news_permitted = RMNEWS_ENABLE_NEWS;
698 	else if (g_key_file_has_key(gkeyfile, "remmina_news", "periodic_news_permitted", NULL))
699 		remmina_pref.periodic_news_permitted = g_key_file_get_boolean(gkeyfile, "remmina_news", "periodic_news_permitted", NULL);
700 	else
701 		remmina_pref.periodic_news_permitted = RMNEWS_ENABLE_NEWS;
702 
703 
704 	if (g_key_file_has_key(gkeyfile, "remmina_news", "periodic_rmnews_last_get", NULL)) {
705 		remmina_pref.periodic_rmnews_last_get = g_key_file_get_int64(gkeyfile, "remmina_news", "periodic_rmnews_last_get", NULL);
706 		g_debug("(%s) - periodic_rmnews_last_get set to %ld", __func__, remmina_pref.periodic_rmnews_last_get);
707 	} else {
708 		remmina_pref.periodic_rmnews_last_get = 0;
709 		g_debug("(%s) - periodic_rmnews_last_get set to 0", __func__);
710 	}
711 
712 	if (g_key_file_has_key(gkeyfile, "remmina_news", "periodic_rmnews_get_count", NULL))
713 		remmina_pref.periodic_rmnews_get_count = g_key_file_get_int64(gkeyfile, "remmina_news", "periodic_rmnews_get_count", NULL);
714 	else
715 		remmina_pref.periodic_rmnews_get_count = 0;
716 
717 	if (g_key_file_has_key(gkeyfile, "remmina_news", "periodic_rmnews_uuid_prefix", NULL))
718 		remmina_pref.periodic_rmnews_uuid_prefix = g_key_file_get_string(gkeyfile, "remmina_news", "periodic_rmnews_uuid_prefix", NULL);
719 	else
720 		remmina_pref.periodic_rmnews_uuid_prefix = NULL;
721 
722 	/* If we have a color scheme file, we switch to it, GIO will merge it in the
723 	 * remmina.pref file */
724 	if (g_file_test(remmina_colors_file, G_FILE_TEST_IS_REGULAR)) {
725 		g_key_file_load_from_file(gkeyfile, remmina_colors_file, G_KEY_FILE_NONE, NULL);
726 		g_remove(remmina_colors_file);
727 	}
728 
729 	/* Default settings */
730 	if (!g_key_file_has_key(gkeyfile, "remmina", "name", NULL)) {
731 		g_key_file_set_string(gkeyfile, "remmina", "name", "");
732 		g_key_file_set_integer(gkeyfile, "remmina", "ignore-tls-errors", 1);
733 		g_key_file_set_integer(gkeyfile, "remmina", "enable-plugins", 1);
734 		remmina_pref_save();
735 	}
736 
737 	g_key_file_free(gkeyfile);
738 
739 	if (remmina_pref.secret == NULL)
740 		remmina_pref_gen_secret();
741 
742 	remmina_pref_init_keymap();
743 }
744 
remmina_pref_is_rw(void)745 gboolean remmina_pref_is_rw(void)
746 {
747 	TRACE_CALL(__func__);
748 	if (access(remmina_pref_file, W_OK) == 0)
749 		return TRUE;
750 	else
751 		return FALSE;
752 	return FALSE;
753 }
754 
remmina_pref_save(void)755 gboolean remmina_pref_save(void)
756 {
757 	TRACE_CALL(__func__);
758 
759 	if (remmina_pref_is_rw() == FALSE) {
760 		g_debug("remmina.pref is not writable, returning");
761 		return FALSE;
762 	}
763 	GKeyFile *gkeyfile;
764 	GError *error = NULL;
765 	g_autofree gchar *content = NULL;
766 	gsize length;
767 
768 	gkeyfile = g_key_file_new();
769 
770 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
771 
772 	g_key_file_set_string(gkeyfile, "remmina_pref", "datadir_path", remmina_pref.datadir_path);
773 	g_key_file_set_string(gkeyfile, "remmina_pref", "remmina_file_name", remmina_pref.remmina_file_name);
774 	g_key_file_set_string(gkeyfile, "remmina_pref", "screenshot_path", remmina_pref.screenshot_path);
775 	g_key_file_set_string(gkeyfile, "remmina_pref", "screenshot_name", remmina_pref.screenshot_name);
776 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "deny_screenshot_clipboard", remmina_pref.deny_screenshot_clipboard);
777 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "save_view_mode", remmina_pref.save_view_mode);
778 #if SODIUM_VERSION_INT >= 90200
779 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "use_master_password", remmina_pref.use_master_password);
780 	g_key_file_set_integer(gkeyfile, "remmina_pref", "unlock_timeout", remmina_pref.unlock_timeout);
781 	g_key_file_set_string(gkeyfile, "remmina_pref", "unlock_password", remmina_pref.unlock_password);
782 #else
783 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "use_master_password", FALSE);
784 	g_key_file_set_integer(gkeyfile, "remmina_pref", "unlock_timeout", 0);
785 	g_key_file_set_string(gkeyfile, "remmina_pref", "unlock_password", g_strdup(""));
786 #endif
787 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "trust_all", remmina_pref.trust_all);
788 	g_key_file_set_integer(gkeyfile, "remmina_pref", "floating_toolbar_placement", remmina_pref.floating_toolbar_placement);
789 	g_key_file_set_integer(gkeyfile, "remmina_pref", "toolbar_placement", remmina_pref.toolbar_placement);
790 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "prevent_snap_welcome_message", remmina_pref.prevent_snap_welcome_message);
791 	g_key_file_set_string(gkeyfile, "remmina_pref", "last_quickconnect_protocol", remmina_pref.last_quickconnect_protocol);
792 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "fullscreen_on_auto", remmina_pref.fullscreen_on_auto);
793 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "always_show_tab", remmina_pref.always_show_tab);
794 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "hide_connection_toolbar", remmina_pref.hide_connection_toolbar);
795 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "hide_searchbar", remmina_pref.hide_searchbar);
796 	g_key_file_set_integer(gkeyfile, "remmina_pref", "default_action", remmina_pref.default_action);
797 	g_key_file_set_integer(gkeyfile, "remmina_pref", "scale_quality", remmina_pref.scale_quality);
798 	g_key_file_set_integer(gkeyfile, "remmina_pref", "ssh_loglevel", remmina_pref.ssh_loglevel);
799 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "ssh_parseconfig", remmina_pref.ssh_parseconfig);
800 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "hide_toolbar", remmina_pref.hide_toolbar);
801 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "small_toolbutton", remmina_pref.small_toolbutton);
802 	g_key_file_set_integer(gkeyfile, "remmina_pref", "view_file_mode", remmina_pref.view_file_mode);
803 	g_key_file_set_string(gkeyfile, "remmina_pref", "resolutions", remmina_pref.resolutions);
804 	g_key_file_set_string(gkeyfile, "remmina_pref", "keystrokes", remmina_pref.keystrokes);
805 	g_key_file_set_integer(gkeyfile, "remmina_pref", "main_width", remmina_pref.main_width);
806 	g_key_file_set_integer(gkeyfile, "remmina_pref", "main_height", remmina_pref.main_height);
807 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "main_maximize", remmina_pref.main_maximize);
808 	g_key_file_set_integer(gkeyfile, "remmina_pref", "main_sort_column_id", remmina_pref.main_sort_column_id);
809 	g_key_file_set_integer(gkeyfile, "remmina_pref", "main_sort_order", remmina_pref.main_sort_order);
810 	g_key_file_set_string(gkeyfile, "remmina_pref", "expanded_group", remmina_pref.expanded_group);
811 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "toolbar_pin_down", remmina_pref.toolbar_pin_down);
812 	g_key_file_set_integer(gkeyfile, "remmina_pref", "sshtunnel_port", remmina_pref.sshtunnel_port);
813 	g_key_file_set_integer(gkeyfile, "remmina_pref", "ssh_tcp_keepidle", remmina_pref.ssh_tcp_keepidle);
814 	g_key_file_set_integer(gkeyfile, "remmina_pref", "ssh_tcp_keepintvl", remmina_pref.ssh_tcp_keepintvl);
815 	g_key_file_set_integer(gkeyfile, "remmina_pref", "ssh_tcp_keepcnt", remmina_pref.ssh_tcp_keepcnt);
816 	g_key_file_set_integer(gkeyfile, "remmina_pref", "ssh_tcp_usrtimeout", remmina_pref.ssh_tcp_usrtimeout);
817 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "applet_new_ontop", remmina_pref.applet_new_ontop);
818 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "applet_hide_count", remmina_pref.applet_hide_count);
819 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "applet_enable_avahi", remmina_pref.applet_enable_avahi);
820 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "disable_tray_icon", remmina_pref.disable_tray_icon);
821 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "dark_theme", remmina_pref.dark_theme);
822 	g_key_file_set_integer(gkeyfile, "remmina_pref", "recent_maximum", remmina_pref.recent_maximum);
823 	g_key_file_set_integer(gkeyfile, "remmina_pref", "default_mode", remmina_pref.default_mode);
824 	g_key_file_set_integer(gkeyfile, "remmina_pref", "tab_mode", remmina_pref.tab_mode);
825 	g_key_file_set_integer(gkeyfile, "remmina_pref", "fullscreen_toolbar_visibility", remmina_pref.fullscreen_toolbar_visibility);
826 	g_key_file_set_integer(gkeyfile, "remmina_pref", "auto_scroll_step", remmina_pref.auto_scroll_step);
827 	g_key_file_set_integer(gkeyfile, "remmina_pref", "hostkey", remmina_pref.hostkey);
828 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_fullscreen", remmina_pref.shortcutkey_fullscreen);
829 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_autofit", remmina_pref.shortcutkey_autofit);
830 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_nexttab", remmina_pref.shortcutkey_nexttab);
831 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_prevtab", remmina_pref.shortcutkey_prevtab);
832 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_scale", remmina_pref.shortcutkey_scale);
833 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_grab", remmina_pref.shortcutkey_grab);
834 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_multimon", remmina_pref.shortcutkey_multimon);
835 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_viewonly", remmina_pref.shortcutkey_viewonly);
836 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_screenshot", remmina_pref.shortcutkey_screenshot);
837 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_minimize", remmina_pref.shortcutkey_minimize);
838 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_disconnect", remmina_pref.shortcutkey_disconnect);
839 	g_key_file_set_integer(gkeyfile, "remmina_pref", "shortcutkey_toolbar", remmina_pref.shortcutkey_toolbar);
840 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_copy", remmina_pref.vte_shortcutkey_copy);
841 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_paste", remmina_pref.vte_shortcutkey_paste);
842 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_select_all", remmina_pref.vte_shortcutkey_select_all);
843 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_increase_font", remmina_pref.vte_shortcutkey_increase_font);
844 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_decrease_font", remmina_pref.vte_shortcutkey_decrease_font);
845 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_shortcutkey_search_text", remmina_pref.vte_shortcutkey_search_text);
846 	g_key_file_set_string(gkeyfile, "remmina_pref", "vte_font", remmina_pref.vte_font ? remmina_pref.vte_font : "");
847 	g_key_file_set_string(gkeyfile, "remmina_pref", "grab_color", remmina_pref.grab_color ? remmina_pref.grab_color : "");
848 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "grab_color_switch", remmina_pref.grab_color_switch);
849 	g_key_file_set_boolean(gkeyfile, "remmina_pref", "vte_allow_bold_text", remmina_pref.vte_allow_bold_text);
850 	g_key_file_set_integer(gkeyfile, "remmina_pref", "vte_lines", remmina_pref.vte_lines);
851 	g_key_file_set_string(gkeyfile, "ssh_colors", "background", remmina_pref.color_pref.background ? remmina_pref.color_pref.background : "");
852 	g_key_file_set_string(gkeyfile, "ssh_colors", "cursor", remmina_pref.color_pref.cursor ? remmina_pref.color_pref.cursor : "");
853 	g_key_file_set_string(gkeyfile, "ssh_colors", "cursor_foreground", remmina_pref.color_pref.cursor_foreground ? remmina_pref.color_pref.cursor_foreground : "");
854 	g_key_file_set_string(gkeyfile, "ssh_colors", "highlight", remmina_pref.color_pref.highlight ? remmina_pref.color_pref.highlight : "");
855 	g_key_file_set_string(gkeyfile, "ssh_colors", "highlight_foreground", remmina_pref.color_pref.highlight_foreground ? remmina_pref.color_pref.highlight_foreground : "");
856 	g_key_file_set_string(gkeyfile, "ssh_colors", "colorBD", remmina_pref.color_pref.colorBD ? remmina_pref.color_pref.colorBD : "");
857 	g_key_file_set_string(gkeyfile, "ssh_colors", "foreground", remmina_pref.color_pref.foreground ? remmina_pref.color_pref.foreground : "");
858 	g_key_file_set_string(gkeyfile, "ssh_colors", "color0", remmina_pref.color_pref.color0 ? remmina_pref.color_pref.color0 : "");
859 	g_key_file_set_string(gkeyfile, "ssh_colors", "color1", remmina_pref.color_pref.color1 ? remmina_pref.color_pref.color1 : "");
860 	g_key_file_set_string(gkeyfile, "ssh_colors", "color2", remmina_pref.color_pref.color2 ? remmina_pref.color_pref.color2 : "");
861 	g_key_file_set_string(gkeyfile, "ssh_colors", "color3", remmina_pref.color_pref.color3 ? remmina_pref.color_pref.color3 : "");
862 	g_key_file_set_string(gkeyfile, "ssh_colors", "color4", remmina_pref.color_pref.color4 ? remmina_pref.color_pref.color4 : "");
863 	g_key_file_set_string(gkeyfile, "ssh_colors", "color5", remmina_pref.color_pref.color5 ? remmina_pref.color_pref.color5 : "");
864 	g_key_file_set_string(gkeyfile, "ssh_colors", "color6", remmina_pref.color_pref.color6 ? remmina_pref.color_pref.color6 : "");
865 	g_key_file_set_string(gkeyfile, "ssh_colors", "color7", remmina_pref.color_pref.color7 ? remmina_pref.color_pref.color7 : "");
866 	g_key_file_set_string(gkeyfile, "ssh_colors", "color8", remmina_pref.color_pref.color8 ? remmina_pref.color_pref.color8 : "");
867 	g_key_file_set_string(gkeyfile, "ssh_colors", "color9", remmina_pref.color_pref.color9 ? remmina_pref.color_pref.color9 : "");
868 	g_key_file_set_string(gkeyfile, "ssh_colors", "color10", remmina_pref.color_pref.color10 ? remmina_pref.color_pref.color10 : "");
869 	g_key_file_set_string(gkeyfile, "ssh_colors", "color11", remmina_pref.color_pref.color11 ? remmina_pref.color_pref.color11 : "");
870 	g_key_file_set_string(gkeyfile, "ssh_colors", "color12", remmina_pref.color_pref.color12 ? remmina_pref.color_pref.color12 : "");
871 	g_key_file_set_string(gkeyfile, "ssh_colors", "color13", remmina_pref.color_pref.color13 ? remmina_pref.color_pref.color13 : "");
872 	g_key_file_set_string(gkeyfile, "ssh_colors", "color14", remmina_pref.color_pref.color14 ? remmina_pref.color_pref.color14 : "");
873 	g_key_file_set_string(gkeyfile, "ssh_colors", "color15", remmina_pref.color_pref.color15 ? remmina_pref.color_pref.color15 : "");
874 
875 	g_key_file_set_boolean(gkeyfile, "usage_stats", "periodic_usage_stats_permitted", remmina_pref.periodic_usage_stats_permitted);
876 	g_key_file_set_int64(gkeyfile, "usage_stats", "periodic_usage_stats_last_sent", remmina_pref.periodic_usage_stats_last_sent);
877 	g_key_file_set_string(gkeyfile, "usage_stats", "periodic_usage_stats_uuid_prefix",
878 			      remmina_pref.periodic_usage_stats_uuid_prefix ? remmina_pref.periodic_usage_stats_uuid_prefix : "");
879 	g_key_file_set_boolean(gkeyfile, "remmina_news", "periodic_news_permitted", remmina_pref.periodic_news_permitted);
880 	g_debug("(%s) - Setting periodic_rmnews_last_get to %ld", __func__, remmina_pref.periodic_rmnews_last_get);
881 	g_key_file_set_int64(gkeyfile, "remmina_news", "periodic_rmnews_last_get", remmina_pref.periodic_rmnews_last_get);
882 	g_key_file_set_integer(gkeyfile, "remmina_news", "periodic_rmnews_get_count", remmina_pref.periodic_rmnews_get_count);
883 	g_key_file_set_string(gkeyfile, "remmina_news", "periodic_rmnews_uuid_prefix",
884 			      remmina_pref.periodic_rmnews_uuid_prefix ? remmina_pref.periodic_rmnews_uuid_prefix : "");
885 
886 	/* Default settings */
887 	g_key_file_set_string(gkeyfile, "remmina", "name", "");
888 	g_key_file_set_integer(gkeyfile, "remmina", "ignore-tls-errors", 1);
889 
890 	content = g_key_file_to_data(gkeyfile, &length, NULL);
891 	g_file_set_contents(remmina_pref_file, content, length, &error);
892 
893 	if (error != NULL) {
894 		g_warning("remmina_pref_save error: %s", error->message);
895 		g_clear_error(&error);
896 		g_key_file_free(gkeyfile);
897 		return FALSE;
898 	}
899 	g_key_file_free(gkeyfile);
900 	return TRUE;
901 }
902 
remmina_pref_add_recent(const gchar * protocol,const gchar * server)903 void remmina_pref_add_recent(const gchar *protocol, const gchar *server)
904 {
905 	TRACE_CALL(__func__);
906 	RemminaStringArray *array;
907 	GKeyFile *gkeyfile;
908 	gchar key[20];
909 	g_autofree gchar *val = NULL;
910 	g_autofree gchar *content = NULL;
911 	gsize length;
912 
913 	if (remmina_pref.recent_maximum <= 0 || server == NULL || server[0] == 0)
914 		return;
915 
916 	/* Load original value into memory */
917 	gkeyfile = g_key_file_new();
918 
919 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
920 
921 	g_snprintf(key, sizeof(key), "recent_%s", protocol);
922 	array = remmina_string_array_new_from_allocated_string(g_key_file_get_string(gkeyfile, "remmina_pref", key, NULL));
923 
924 	/* Add the new value */
925 	remmina_string_array_remove(array, server);
926 	while (array->len >= remmina_pref.recent_maximum)
927 		remmina_string_array_remove_index(array, 0);
928 	remmina_string_array_add(array, server);
929 
930 	/* Save */
931 	val = remmina_string_array_to_string(array);
932 	g_key_file_set_string(gkeyfile, "remmina_pref", key, val);
933 
934 	content = g_key_file_to_data(gkeyfile, &length, NULL);
935 	g_file_set_contents(remmina_pref_file, content, length, NULL);
936 
937 	g_key_file_free(gkeyfile);
938 }
939 
940 gchar *
remmina_pref_get_recent(const gchar * protocol)941 remmina_pref_get_recent(const gchar *protocol)
942 {
943 	TRACE_CALL(__func__);
944 	GKeyFile *gkeyfile;
945 	gchar key[20];
946 	gchar *val = NULL;
947 
948 	gkeyfile = g_key_file_new();
949 
950 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
951 
952 	g_snprintf(key, sizeof(key), "recent_%s", protocol);
953 	val = g_key_file_get_string(gkeyfile, "remmina_pref", key, NULL);
954 
955 	g_key_file_free(gkeyfile);
956 
957 	return val;
958 }
959 
remmina_pref_clear_recent(void)960 void remmina_pref_clear_recent(void)
961 {
962 	TRACE_CALL(__func__);
963 	GKeyFile *gkeyfile;
964 	gchar **keys;
965 	gint i;
966 	g_autofree gchar *content = NULL;
967 	gsize length;
968 
969 	gkeyfile = g_key_file_new();
970 
971 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
972 	keys = g_key_file_get_keys(gkeyfile, "remmina_pref", NULL, NULL);
973 	if (keys) {
974 		for (i = 0; keys[i]; i++)
975 			if (strncmp(keys[i], "recent_", 7) == 0)
976 				g_key_file_set_string(gkeyfile, "remmina_pref", keys[i], "");
977 		g_strfreev(keys);
978 	}
979 
980 	content = g_key_file_to_data(gkeyfile, &length, NULL);
981 	g_file_set_contents(remmina_pref_file, content, length, NULL);
982 
983 	g_key_file_free(gkeyfile);
984 }
985 
remmina_pref_keymap_get_keyval(const gchar * keymap,guint keyval)986 guint remmina_pref_keymap_get_keyval(const gchar *keymap, guint keyval)
987 {
988 	TRACE_CALL(__func__);
989 	guint *table;
990 	gint i;
991 
992 	if (!keymap || keymap[0] == '\0')
993 		return keyval;
994 
995 	table = (guint *)g_hash_table_lookup(remmina_keymap_table, keymap);
996 	if (!table)
997 		return keyval;
998 	for (i = 0; table[i] > 0; i += 2)
999 		if (table[i] == keyval)
1000 			return table[i + 1];
1001 	return keyval;
1002 }
1003 
1004 gchar **
remmina_pref_keymap_groups(void)1005 remmina_pref_keymap_groups(void)
1006 {
1007 	TRACE_CALL(__func__);
1008 	GList *list;
1009 	guint len;
1010 	gchar **keys;
1011 	guint i;
1012 
1013 	list = g_hash_table_get_keys(remmina_keymap_table);
1014 	len = g_list_length(list);
1015 
1016 	keys = g_new0(gchar *, (len + 1) * 2 + 1);
1017 	keys[0] = g_strdup("");
1018 	keys[1] = g_strdup("");
1019 	for (i = 0; i < len; i++) {
1020 		keys[(i + 1) * 2] = g_strdup((gchar *)g_list_nth_data(list, i));
1021 		keys[(i + 1) * 2 + 1] = g_strdup((gchar *)g_list_nth_data(list, i));
1022 	}
1023 	g_list_free(list);
1024 
1025 	return keys;
1026 }
1027 
remmina_pref_get_scale_quality(void)1028 gint remmina_pref_get_scale_quality(void)
1029 {
1030 	TRACE_CALL(__func__);
1031 	/* Paranoid programming */
1032 	if (remmina_pref.scale_quality < 0)
1033 		remmina_pref.scale_quality = 0;
1034 	return remmina_pref.scale_quality;
1035 }
1036 
remmina_pref_get_ssh_loglevel(void)1037 gint remmina_pref_get_ssh_loglevel(void)
1038 {
1039 	TRACE_CALL(__func__);
1040 	return remmina_pref.ssh_loglevel;
1041 }
1042 
remmina_pref_get_ssh_parseconfig(void)1043 gboolean remmina_pref_get_ssh_parseconfig(void)
1044 {
1045 	TRACE_CALL(__func__);
1046 	return remmina_pref.ssh_parseconfig;
1047 }
1048 
remmina_pref_get_sshtunnel_port(void)1049 gint remmina_pref_get_sshtunnel_port(void)
1050 {
1051 	TRACE_CALL(__func__);
1052 	return remmina_pref.sshtunnel_port;
1053 }
1054 
remmina_pref_get_ssh_tcp_keepidle(void)1055 gint remmina_pref_get_ssh_tcp_keepidle(void)
1056 {
1057 	TRACE_CALL(__func__);
1058 	return remmina_pref.ssh_tcp_keepidle;
1059 }
1060 
remmina_pref_get_ssh_tcp_keepintvl(void)1061 gint remmina_pref_get_ssh_tcp_keepintvl(void)
1062 {
1063 	TRACE_CALL(__func__);
1064 	return remmina_pref.ssh_tcp_keepintvl;
1065 }
1066 
remmina_pref_get_ssh_tcp_keepcnt(void)1067 gint remmina_pref_get_ssh_tcp_keepcnt(void)
1068 {
1069 	TRACE_CALL(__func__);
1070 	return remmina_pref.ssh_tcp_keepcnt;
1071 }
1072 
remmina_pref_get_ssh_tcp_usrtimeout(void)1073 gint remmina_pref_get_ssh_tcp_usrtimeout(void)
1074 {
1075 	TRACE_CALL(__func__);
1076 	return remmina_pref.ssh_tcp_usrtimeout;
1077 }
1078 
remmina_pref_set_value(const gchar * key,const gchar * value)1079 void remmina_pref_set_value(const gchar *key, const gchar *value)
1080 {
1081 	TRACE_CALL(__func__);
1082 	GKeyFile *gkeyfile;
1083 	gchar *content;
1084 	gsize length;
1085 
1086 	gkeyfile = g_key_file_new();
1087 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
1088 	g_key_file_set_string(gkeyfile, "remmina_pref", key, value);
1089 	content = g_key_file_to_data(gkeyfile, &length, NULL);
1090 	g_file_set_contents(remmina_pref_file, content, length, NULL);
1091 
1092 	g_key_file_free(gkeyfile);
1093 	g_free(content);
1094 }
1095 
remmina_pref_get_value(const gchar * key)1096 gchar *remmina_pref_get_value(const gchar *key)
1097 {
1098 	TRACE_CALL(__func__);
1099 	GKeyFile *gkeyfile;
1100 	gchar *value = NULL;
1101 
1102 	gkeyfile = g_key_file_new();
1103 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
1104 	value = g_key_file_get_string(gkeyfile, "remmina_pref", key, NULL);
1105 	g_key_file_free(gkeyfile);
1106 
1107 	return value;
1108 }
1109 
remmina_pref_get_boolean(const gchar * key)1110 gboolean remmina_pref_get_boolean(const gchar *key)
1111 {
1112 	TRACE_CALL(__func__);
1113 	GKeyFile *gkeyfile;
1114 	gboolean value;
1115 
1116 	gkeyfile = g_key_file_new();
1117 	g_key_file_load_from_file(gkeyfile, remmina_pref_file, G_KEY_FILE_NONE, NULL);
1118 	value = g_key_file_get_boolean(gkeyfile, "remmina_pref", key, NULL);
1119 	g_key_file_free(gkeyfile);
1120 
1121 	return value;
1122 }
1123