Remmina - The GTK+ Remote Desktop Client  v1.4.2
Remmina is a remote desktop client written in GTK+, aiming to be useful for system administrators and travellers, who need to work with lots of remote computers in front of either large monitors or tiny netbooks. Remmina supports multiple network protocols in an integrated and consistent user interface. Currently RDP, VNC, NX, XDMCP and SSH are supported.
remmina_file_editor.c
Go to the documentation of this file.
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-2020 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 <gtk/gtk.h>
38 #include <glib/gi18n.h>
39 #include <stdlib.h>
40 #include "config.h"
41 #ifdef HAVE_LIBAVAHI_UI
42 #include <avahi-ui/avahi-ui.h>
43 #endif
44 #include "remmina_public.h"
45 #include "remmina_pref.h"
46 #include "rcw.h"
47 #include "remmina_string_list.h"
48 #include "remmina_pref_dialog.h"
49 #include "remmina_file.h"
50 #include "remmina_file_manager.h"
51 #include "remmina_ssh.h"
52 #include "remmina_widget_pool.h"
53 #include "remmina_plugin_manager.h"
54 #include "remmina_icon.h"
55 #include "remmina_file_editor.h"
57 
58 G_DEFINE_TYPE(RemminaFileEditor, remmina_file_editor, GTK_TYPE_DIALOG)
59 
60 #ifdef HAVE_LIBSSH
61 static const gchar *charset_list = "ASCII,BIG5,"
62  "CP437,CP720,CP737,CP775,CP850,CP852,CP855,"
63  "CP857,CP858,CP862,CP866,CP874,CP1125,CP1250,"
64  "CP1251,CP1252,CP1253,CP1254,CP1255,CP1256,"
65  "CP1257,CP1258,"
66  "EUC-JP,EUC-KR,GBK,"
67  "ISO-8859-1,ISO-8859-2,ISO-8859-3,ISO-8859-4,"
68  "ISO-8859-5,ISO-8859-6,ISO-8859-7,ISO-8859-8,"
69  "ISO-8859-9,ISO-8859-10,ISO-8859-11,ISO-8859-12,"
70  "ISO-8859-13,ISO-8859-14,ISO-8859-15,ISO-8859-16,"
71  "KOI8-R,SJIS,UTF-8";
72 #endif
73 
74 static const gchar *server_tips = N_("<tt><big>"
75  "Supported formats\n"
76  "• server\n"
77  "• server:port\n"
78  "• [server]:port"
79  "</big></tt>");
80 
81 static const gchar *cmd_tips = N_("<tt><big>"
82  "• command in PATH args %h\n"
83  "• /path/to/foo -options %h %u\n"
84  "• %h is substituted with the server name\n"
85  "• %t is substituted with the SSH server name\n"
86  "• %u is substituted with the username\n"
87  "• %U is substituted with the SSH username\n"
88  "• %p is substituted with Remmina profile name\n"
89  "• %g is substituted with Remmina profile group name\n"
90  "• %d is substituted with local datetime in iso8601 format\n"
91  "Do not run in background if you want the command to be executed before connecting.\n"
92  "</big></tt>");
93 
94 #ifdef HAVE_LIBSSH
95 static const gchar *server_tips2 = N_("<tt><big>"
96  "Supported formats\n"
97  "• :port\n"
98  "• server\n"
99  "• server:port\n"
100  "• [server]:port\n"
101  "• username@server:port (SSH protocol only)"
102  "</big></tt>");
103 #endif
104 
105 struct _RemminaFileEditorPriv {
106  RemminaFile * remmina_file;
107  RemminaProtocolPlugin * plugin;
108  const gchar * avahi_service_type;
109 
110  GtkWidget * name_entry;
111  GtkWidget * group_combo;
112  GtkWidget * protocol_combo;
113  GtkWidget * precommand_entry;
114  GtkWidget * postcommand_entry;
115  GtkWidget * save_button;
116 
117  GtkWidget * config_box;
118  GtkWidget * config_scrollable;
119  GtkWidget * config_viewport;
120  GtkWidget * config_container;
121 
122  GtkWidget * server_combo;
123  GtkWidget * resolution_iws_radio;
124  GtkWidget * resolution_auto_radio;
125  GtkWidget * resolution_custom_radio;
126  GtkWidget * resolution_custom_combo;
127  GtkWidget * keymap_combo;
128 
129  GtkWidget * ssh_tunnel_enabled_check;
130  GtkWidget * ssh_tunnel_loopback_check;
131  GtkWidget * ssh_tunnel_server_default_radio;
132  GtkWidget * ssh_tunnel_server_custom_radio;
133  GtkWidget * ssh_tunnel_server_entry;
134  GtkWidget * ssh_tunnel_auth_agent_radio;
135  GtkWidget * ssh_tunnel_auth_password_radio;
136  GtkWidget * ssh_tunnel_auth_password;
137  GtkWidget * ssh_tunnel_passphrase;
138  GtkWidget * ssh_tunnel_auth_publickey_radio;
139  GtkWidget * ssh_tunnel_auth_auto_publickey_radio;
140  GtkWidget * ssh_tunnel_username_entry;
141  GtkWidget * ssh_tunnel_privatekey_chooser;
142 
143  GHashTable * setting_widgets;
144 };
145 
147 {
148  TRACE_CALL(__func__);
149 }
150 
151 #ifdef HAVE_LIBAVAHI_UI
152 
153 static void remmina_file_editor_browse_avahi(GtkWidget *button, RemminaFileEditor *gfe)
154 {
155  TRACE_CALL(__func__);
156  GtkWidget *dialog;
157  gchar *host;
158 
159  dialog = aui_service_dialog_new(_("Choose a Remote Desktop Server"),
160  GTK_WINDOW(gfe),
161  _("_Cancel"), GTK_RESPONSE_CANCEL,
162  _("_OK"), GTK_RESPONSE_ACCEPT,
163  NULL);
164 
165  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gfe));
166  aui_service_dialog_set_resolve_service(AUI_SERVICE_DIALOG(dialog), TRUE);
167  aui_service_dialog_set_resolve_host_name(AUI_SERVICE_DIALOG(dialog), TRUE);
168  aui_service_dialog_set_browse_service_types(AUI_SERVICE_DIALOG(dialog),
169  gfe->priv->avahi_service_type, NULL);
170 
171  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
172  host = g_strdup_printf("[%s]:%i",
173  aui_service_dialog_get_host_name(AUI_SERVICE_DIALOG(dialog)),
174  aui_service_dialog_get_port(AUI_SERVICE_DIALOG(dialog)));
175  } else {
176  host = NULL;
177  }
178  gtk_widget_destroy(dialog);
179 
180  if (host) {
181  gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(gfe->priv->server_combo))), host);
182  g_free(host);
183  }
184 }
185 #endif
186 
187 static void remmina_file_editor_on_realize(GtkWidget *widget, gpointer user_data)
188 {
189  TRACE_CALL(__func__);
190  RemminaFileEditor *gfe;
191  GtkWidget *defaultwidget;
192 
193  gfe = REMMINA_FILE_EDITOR(widget);
194 
195  defaultwidget = gfe->priv->server_combo;
196 
197  if (defaultwidget) {
198  if (GTK_IS_EDITABLE(defaultwidget))
199  gtk_editable_select_region(GTK_EDITABLE(defaultwidget), 0, -1);
200  gtk_widget_grab_focus(defaultwidget);
201  }
202 }
203 
204 static void remmina_file_editor_destroy(GtkWidget *widget, gpointer data)
205 {
206  TRACE_CALL(__func__);
207  remmina_file_free(REMMINA_FILE_EDITOR(widget)->priv->remmina_file);
208  g_hash_table_destroy(REMMINA_FILE_EDITOR(widget)->priv->setting_widgets);
209  g_free(REMMINA_FILE_EDITOR(widget)->priv);
210 }
211 
212 static void remmina_file_editor_button_on_toggled(GtkToggleButton *togglebutton, GtkWidget *widget)
213 {
214  TRACE_CALL(__func__);
215  gtk_widget_set_sensitive(widget, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)));
216 }
217 
219 {
220  TRACE_CALL(__func__);
221  /* Create the notebook */
222  gfe->priv->config_container = gtk_notebook_new();
223  gfe->priv->config_viewport = gtk_viewport_new(NULL, NULL);
224  gfe->priv->config_scrollable = gtk_scrolled_window_new(NULL, NULL);
225  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_scrollable), 2);
226  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gfe->priv->config_scrollable),
227  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
228  gtk_widget_show(gfe->priv->config_scrollable);
229 
230  gtk_container_add(GTK_CONTAINER(gfe->priv->config_viewport), gfe->priv->config_container);
231  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_viewport), 2);
232  gtk_widget_show(gfe->priv->config_viewport);
233  gtk_container_add(GTK_CONTAINER(gfe->priv->config_scrollable), gfe->priv->config_viewport);
234  gtk_container_set_border_width(GTK_CONTAINER(gfe->priv->config_container), 2);
235  gtk_widget_show(gfe->priv->config_container);
236 
237  gtk_container_add(GTK_CONTAINER(gfe->priv->config_box), gfe->priv->config_scrollable);
238 }
239 
241  const gchar *stock_id, const gchar *label, gint rows, gint cols)
242 {
243  TRACE_CALL(__func__);
244  GtkWidget *tablabel;
245  GtkWidget *tabbody;
246  GtkWidget *grid;
247  GtkWidget *widget;
248 
249  tablabel = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
250  gtk_widget_show(tablabel);
251 
252  widget = gtk_image_new_from_icon_name(stock_id, GTK_ICON_SIZE_BUTTON);
253  gtk_box_pack_start(GTK_BOX(tablabel), widget, FALSE, FALSE, 0);
254  gtk_widget_show(widget);
255 
256  widget = gtk_label_new(label);
257  gtk_box_pack_start(GTK_BOX(tablabel), widget, FALSE, FALSE, 0);
258  gtk_widget_show(widget);
259 
260  tabbody = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
261  gtk_widget_show(tabbody);
262  gtk_notebook_append_page(GTK_NOTEBOOK(gfe->priv->config_container), tabbody, tablabel);
263 
264  grid = gtk_grid_new();
265  gtk_widget_show(grid);
266  gtk_grid_set_row_spacing(GTK_GRID(grid), 8);
267  gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
268  gtk_container_set_border_width(GTK_CONTAINER(grid), 15);
269  gtk_box_pack_start(GTK_BOX(tabbody), grid, FALSE, FALSE, 0);
270 
271  return grid;
272 }
273 
274 #ifdef HAVE_LIBSSH
275 
277 {
278  TRACE_CALL(__func__);
279  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_entry),
280  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check)) &&
281  (gfe->priv->ssh_tunnel_server_custom_radio == NULL ||
282  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_server_custom_radio)))
283  );
284 }
285 
287 {
288  TRACE_CALL(__func__);
289  gboolean b;
290  const gchar *s;
291 
292  b = ((!gfe->priv->ssh_tunnel_enabled_check ||
293  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check))) &&
294  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_auth_publickey_radio)));
295  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_privatekey_chooser), b);
296 
297  if (b && (s = remmina_file_get_string(gfe->priv->remmina_file, "ssh_tunnel_privatekey")))
298  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(gfe->priv->ssh_tunnel_privatekey_chooser), s);
299 }
300 
301 static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled(GtkToggleButton *togglebutton,
303 {
304  TRACE_CALL(__func__);
305  RemminaFileEditorPriv *priv = gfe->priv;
306  gboolean enabled = TRUE;
307  gchar *p;
308  const gchar *cp;
309 
310  if (gfe->priv->ssh_tunnel_enabled_check) {
311  enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->ssh_tunnel_enabled_check));
312  if (gfe->priv->ssh_tunnel_loopback_check)
313  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_loopback_check), enabled);
314  if (gfe->priv->ssh_tunnel_server_default_radio)
315  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_default_radio), enabled);
316  if (gfe->priv->ssh_tunnel_server_custom_radio)
317  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_server_custom_radio), enabled);
319  p = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo));
320  //if (!(g_strcmp0(p, "SFTP") == 0 || g_strcmp0(p, "SSH") == 0)) {
321  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_username_entry), enabled);
322  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_agent_radio), enabled);
323  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_password_radio), enabled);
324  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_password), enabled);
325  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_publickey_radio), enabled);
326  gtk_widget_set_sensitive(GTK_WIDGET(gfe->priv->ssh_tunnel_auth_auto_publickey_radio), enabled);
327  //}
328  g_free(p);
329  }
331 
332  if (gfe->priv->ssh_tunnel_username_entry)
333  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_username_entry)) [0] == '\0') {
334  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_username");
335  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_username_entry), cp ? cp : "");
336  }
337 
338  if (gfe->priv->ssh_tunnel_auth_password) {
339  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_auth_password)) [0] == '\0') {
340  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_password");
341  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_auth_password), cp ? cp : "");
342  }
343  }
344  if (gfe->priv->ssh_tunnel_passphrase) {
345  if (enabled && gtk_entry_get_text(GTK_ENTRY(gfe->priv->ssh_tunnel_passphrase)) [0] == '\0') {
346  cp = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_passphrase");
347  gtk_entry_set_text(GTK_ENTRY(gfe->priv->ssh_tunnel_passphrase), cp ? cp : "");
348  }
349  }
350 }
351 
352 static void remmina_file_editor_create_ssh_privatekey(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint column)
353 {
354  TRACE_CALL(__func__);
355  gchar *s;
356  GtkWidget *widget;
357  GtkWidget *dialog;
358  const gchar *ssh_privatekey;
359  RemminaFileEditorPriv *priv = gfe->priv;
360 
361  widget = gtk_radio_button_new_with_label_from_widget(
362  GTK_RADIO_BUTTON(priv->ssh_tunnel_auth_agent_radio), _("SSH identity file"));
363  g_signal_connect(G_OBJECT(widget), "toggled",
365  priv->ssh_tunnel_auth_publickey_radio = widget;
366  gtk_widget_show(widget);
367  gtk_grid_attach(GTK_GRID(grid), widget, 0, row + 22, 1, 1);
368 
369  dialog = gtk_file_chooser_dialog_new(_("SSH identity file"), GTK_WINDOW(gfe), GTK_FILE_CHOOSER_ACTION_OPEN,
370  _("_Cancel"), GTK_RESPONSE_CANCEL,
371  _("_Open"), GTK_RESPONSE_ACCEPT,
372  NULL);
373 
374  widget = gtk_file_chooser_button_new_with_dialog(dialog);
375 #ifdef SNAP_BUILD
376  s = g_strdup_printf("%s/.ssh", g_getenv("SNAP_USER_COMMON"));
377 #else
378  s = g_strdup_printf("%s/.ssh", g_get_home_dir());
379 #endif
380  if (g_file_test(s, G_FILE_TEST_IS_DIR))
381  gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widget), s);
382  g_free(s);
383  gtk_widget_show(widget);
384  gtk_grid_attach(GTK_GRID(grid), widget, column + 1, row + 22, 1, 1);
385  priv->ssh_tunnel_privatekey_chooser = widget;
386 
387  ssh_privatekey = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_privatekey");
388  if (ssh_privatekey &&
389  g_file_test(ssh_privatekey, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS))
390  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(priv->ssh_tunnel_privatekey_chooser),
391  ssh_privatekey);
392  else
393  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_privatekey", NULL);
394 }
395 #endif
396 
397 static void remmina_file_editor_create_server(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid,
398  gint row)
399 {
400  TRACE_CALL(__func__);
401  RemminaProtocolPlugin *plugin = gfe->priv->plugin;
402  GtkWidget *widget;
403 #ifdef HAVE_LIBAVAHI_UI
404  GtkWidget *hbox;
405 #endif
406  gchar *s;
407 
408  widget = gtk_label_new(_("Server"));
409  gtk_widget_show(widget);
410  gtk_widget_set_valign(widget, GTK_ALIGN_START);
411  gtk_widget_set_halign(widget, GTK_ALIGN_START);
412  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, row + 1);
413 
414  s = remmina_pref_get_recent(plugin->name);
415  widget = remmina_public_create_combo_entry(s, remmina_file_get_string(gfe->priv->remmina_file, "server"), TRUE);
416  gtk_widget_set_hexpand(widget, TRUE);
417  gtk_widget_show(widget);
418  gtk_widget_set_tooltip_markup(widget, _(server_tips));
419  gtk_entry_set_activates_default(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(widget))), TRUE);
420  gfe->priv->server_combo = widget;
421  g_free(s);
422 
423 #ifdef HAVE_LIBAVAHI_UI
424  if (setting->opt1) {
425  gfe->priv->avahi_service_type = (const gchar *)setting->opt1;
426 
427  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
428  gtk_widget_show(hbox);
429  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
430 
431  widget = gtk_button_new_with_label("…");
432  s = g_strdup_printf(_("Browse the network to find a %s server"), plugin->name);
433  gtk_widget_set_tooltip_text(widget, s);
434  g_free(s);
435  gtk_widget_show(widget);
436  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
437  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_browse_avahi), gfe);
438 
439  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
440  } else
441 #endif
442  {
443  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
444  }
445 }
446 
447 static GtkWidget *remmina_file_editor_create_password(RemminaFileEditor *gfe, GtkWidget *grid,
448  gint row, gint col, const gchar *label, const gchar *value)
449 {
450  TRACE_CALL(__func__);
451  GtkWidget *widget;
452 
453  widget = gtk_label_new(label);
454  gtk_widget_show(widget);
455 #if GTK_CHECK_VERSION(3, 12, 0)
456  gtk_widget_set_margin_end(widget, 40);
457 #else
458  gtk_widget_set_margin_right(widget, 40);
459 #endif
460  gtk_widget_set_valign(widget, GTK_ALIGN_START);
461  gtk_widget_set_halign(widget, GTK_ALIGN_START);
462  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
463 
464  widget = gtk_entry_new();
465  gtk_widget_show(widget);
466  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
467  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
468  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
469  gtk_widget_set_hexpand(widget, TRUE);
470  gtk_entry_set_activates_default(GTK_ENTRY(widget), TRUE);
471 
472  if (value)
473  gtk_entry_set_text(GTK_ENTRY(widget), value);
474  return widget;
475 }
476 
477 static void remmina_file_editor_update_resolution(GtkWidget *widget, RemminaFileEditor *gfe)
478 {
479  TRACE_CALL(__func__);
480  gchar *res_str;
481  res_str = g_strdup_printf("%dx%d",
482  remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", 0),
483  remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", 0)
484  );
485  remmina_public_load_combo_text_d(gfe->priv->resolution_custom_combo, remmina_pref.resolutions,
486  res_str, NULL);
487  g_free(res_str);
488 }
489 
490 static void remmina_file_editor_browse_resolution(GtkWidget *button, RemminaFileEditor *gfe)
491 {
492  TRACE_CALL(__func__);
493 
494  GtkDialog *dialog = remmina_string_list_new(FALSE, NULL);
497  remmina_string_list_set_titles(_("Resolutions"), _("Configure the available resolutions"));
498  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gfe));
499  gtk_dialog_run(dialog);
500  g_free(remmina_pref.resolutions);
502  g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(remmina_file_editor_update_resolution), gfe);
503  gtk_widget_destroy(GTK_WIDGET(dialog));
504 }
505 
507  GtkWidget *grid, gint row)
508 {
509  TRACE_CALL(__func__);
510  GtkWidget *widget;
511  GtkWidget *hbox;
512  int resolution_w, resolution_h;
513  gchar *res_str;
515 
516  res_mode = remmina_file_get_int(gfe->priv->remmina_file, "resolution_mode", RES_INVALID);
517  resolution_w = remmina_file_get_int(gfe->priv->remmina_file, "resolution_width", -1);
518  resolution_h = remmina_file_get_int(gfe->priv->remmina_file, "resolution_height", -1);
519 
520  /* If resolution_mode is non-existent (-1), then we try to calculate it
521  * as we did before having resolution_mode */
522  if (res_mode == RES_INVALID) {
523  if (resolution_w <= 0 || resolution_h <= 0)
524  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
525  else
526  res_mode = RES_USE_CUSTOM;
527  }
528  if (res_mode == RES_USE_CUSTOM)
529  res_str = g_strdup_printf("%dx%d", resolution_w, resolution_h);
530  else
531  res_str = NULL;
532 
533  widget = gtk_label_new(_("Resolution"));
534  gtk_widget_show(widget);
535  gtk_widget_set_valign(widget, GTK_ALIGN_START);
536  gtk_widget_set_halign(widget, GTK_ALIGN_START);
537  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
538 
539  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
540  widget = gtk_radio_button_new_with_label(NULL, _("Use initial window size"));
541  gtk_widget_show(widget);
542  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
543  gfe->priv->resolution_iws_radio = widget;
544  widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Use client resolution"));
545  gtk_widget_show(widget);
546  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
547  gfe->priv->resolution_auto_radio = widget;
548  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
549  gtk_widget_show(hbox);
550 
551  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
552  gtk_widget_show(hbox);
553  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row + 1, 1, 1);
554 
555  widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(gfe->priv->resolution_iws_radio), _("Custom"));
556  gtk_widget_show(widget);
557  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
558  gfe->priv->resolution_custom_radio = widget;
559 
561  gtk_widget_show(widget);
562  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
563  gfe->priv->resolution_custom_combo = widget;
564 
565  widget = gtk_button_new_with_label("…");
566  gtk_widget_show(widget);
567  gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
568  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_browse_resolution), gfe);
569 
570  g_signal_connect(G_OBJECT(gfe->priv->resolution_custom_radio), "toggled",
571  G_CALLBACK(remmina_file_editor_button_on_toggled), gfe->priv->resolution_custom_combo);
572 
573  if (res_mode == RES_USE_CUSTOM)
574  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio), TRUE);
575  else if (res_mode == RES_USE_CLIENT)
576  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_auto_radio), TRUE);
577  else
578  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_iws_radio), TRUE);
579 
580  gtk_widget_set_sensitive(gfe->priv->resolution_custom_combo, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gfe->priv->resolution_custom_radio)));
581 
582  g_free(res_str);
583 }
584 
585 static GtkWidget *remmina_file_editor_create_text(RemminaFileEditor *gfe, GtkWidget *grid,
586  gint row, gint col, const gchar *label, const gchar *value)
587 {
588  TRACE_CALL(__func__);
589  GtkWidget *widget;
590 
591  widget = gtk_label_new(label);
592  gtk_widget_show(widget);
593 #if GTK_CHECK_VERSION(3, 12, 0)
594  gtk_widget_set_margin_end(widget, 40);
595 #else
596  gtk_widget_set_margin_right(widget, 40);
597 #endif
598  gtk_widget_set_valign(widget, GTK_ALIGN_START);
599  gtk_widget_set_halign(widget, GTK_ALIGN_START);
600  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
601 
602  widget = gtk_entry_new();
603  gtk_widget_show(widget);
604  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
605  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
606  gtk_widget_set_hexpand(widget, TRUE);
607 
608  if (value)
609  gtk_entry_set_text(GTK_ENTRY(widget), value);
610 
611  return widget;
612 }
613 
614 static GtkWidget *remmina_file_editor_create_select(RemminaFileEditor *gfe, GtkWidget *grid,
615  gint row, gint col, const gchar *label, const gpointer *list, const gchar *value)
616 {
617  TRACE_CALL(__func__);
618  GtkWidget *widget;
619 
620  widget = gtk_label_new(label);
621  gtk_widget_show(widget);
622  gtk_widget_set_valign(widget, GTK_ALIGN_START);
623  gtk_widget_set_halign(widget, GTK_ALIGN_START);
624  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
625 
626  widget = remmina_public_create_combo_map(list, value, FALSE, gfe->priv->plugin->domain);
627  gtk_widget_show(widget);
628  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
629 
630  return widget;
631 }
632 
633 static GtkWidget *remmina_file_editor_create_combo(RemminaFileEditor *gfe, GtkWidget *grid,
634  gint row, gint col, const gchar *label, const gchar *list, const gchar *value)
635 {
636  TRACE_CALL(__func__);
637  GtkWidget *widget;
638 
639  widget = gtk_label_new(label);
640  gtk_widget_show(widget);
641  gtk_widget_set_valign(widget, GTK_ALIGN_START);
642  gtk_widget_set_halign(widget, GTK_ALIGN_START);
643  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
644 
645  widget = remmina_public_create_combo_entry(list, value, FALSE);
646  gtk_widget_show(widget);
647  gtk_widget_set_hexpand(widget, TRUE);
648  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 1, 1);
649 
650  return widget;
651 }
652 
653 static GtkWidget *remmina_file_editor_create_check(RemminaFileEditor *gfe, GtkWidget *grid,
654  gint row, gint top, const gchar *label, gboolean value)
655 {
656  TRACE_CALL(__func__);
657  GtkWidget *widget;
658  widget = gtk_check_button_new_with_label(label);
659  gtk_widget_show(widget);
660  gtk_grid_set_row_spacing(GTK_GRID(grid), 1);
661  gtk_grid_attach(GTK_GRID(grid), widget, top, row, 1, 1);
662 
663  if (value)
664  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
665 
666  return widget;
667 }
668 
669 static GtkWidget *
670 remmina_file_editor_create_chooser(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label,
671  const gchar *value, gint type)
672 {
673  TRACE_CALL(__func__);
674  GtkWidget *check;
675  GtkWidget *widget;
676  GtkWidget *hbox;
677 
678  widget = gtk_label_new(label);
679  gtk_widget_show(widget);
680  gtk_widget_set_valign(widget, GTK_ALIGN_START);
681  gtk_widget_set_halign(widget, GTK_ALIGN_START);
682  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
683 
684  hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
685  gtk_widget_show(hbox);
686  gtk_grid_attach(GTK_GRID(grid), hbox, 1, row, 1, 1);
687 
688  check = gtk_check_button_new();
689  gtk_widget_show(check);
690  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), (value && value[0] == '/'));
691  gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
692 
693  widget = gtk_file_chooser_button_new(label, type);
694  gtk_widget_show(widget);
695  if (value)
696  gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widget), value);
697  gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
698 
699  g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(remmina_file_editor_button_on_toggled), widget);
700  remmina_file_editor_button_on_toggled(GTK_TOGGLE_BUTTON(check), widget);
701 
702  return widget;
703 }
704 
705 static void remmina_file_editor_create_settings(RemminaFileEditor *gfe, GtkWidget *grid,
706  const RemminaProtocolSetting *settings)
707 {
708  TRACE_CALL(__func__);
709  RemminaFileEditorPriv *priv = gfe->priv;
710  GtkWidget *widget;
711  gint grid_row = 0;
712  gint grid_column = 0;
713  gchar **strarr;
714  gchar *setting_name;
715 
716 
717  while (settings->type != REMMINA_PROTOCOL_SETTING_TYPE_END) {
718  setting_name = (gchar *)(remmina_plugin_manager_get_canonical_setting_name(settings));
719  switch (settings->type) {
721  remmina_file_editor_create_server(gfe, settings, grid, grid_row);
722  break;
723 
725  widget = remmina_file_editor_create_password(gfe, grid, grid_row, 0,
726  g_dgettext(priv->plugin->domain, settings->label),
727  remmina_file_get_string(priv->remmina_file, setting_name));
728  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
729  grid_row++;
730  break;
731 
733  remmina_file_editor_create_resolution(gfe, settings, grid, grid_row);
734  grid_row += 1;
735  break;
736 
738  strarr = remmina_pref_keymap_groups();
739  priv->keymap_combo = remmina_file_editor_create_select(gfe, grid,
740  grid_row + 1, 0,
741  _("Keyboard mapping"), (const gpointer *)strarr,
742  remmina_file_get_string(priv->remmina_file, "keymap"));
743  g_strfreev(strarr);
744  grid_row++;
745  break;
746 
748  widget = remmina_file_editor_create_text(gfe, grid, grid_row, 0,
749  g_dgettext(priv->plugin->domain, settings->label),
750  remmina_file_get_string(priv->remmina_file, setting_name));
751  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
752  if (settings->opt2)
753  gtk_widget_set_tooltip_text(widget, (const gchar *)settings->opt2);
754  grid_row++;
755  break;
756 
758  widget = remmina_file_editor_create_select(gfe, grid, grid_row, 0,
759  g_dgettext(priv->plugin->domain, settings->label),
760  (const gpointer *)settings->opt1,
761  remmina_file_get_string(priv->remmina_file, setting_name));
762  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
763  if (settings->opt2)
764  gtk_widget_set_tooltip_text(widget, (const gchar *)settings->opt2);
765  break;
766 
768  widget = remmina_file_editor_create_combo(gfe, grid, grid_row, 0,
769  g_dgettext(priv->plugin->domain, settings->label),
770  (const gchar *)settings->opt1,
771  remmina_file_get_string(priv->remmina_file, setting_name));
772  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
773  if (settings->opt2)
774  gtk_widget_set_tooltip_text(widget, (const gchar *)settings->opt2);
775  break;
776 
778  widget = remmina_file_editor_create_check(gfe, grid, grid_row, grid_column,
779  g_dgettext(priv->plugin->domain, settings->label),
780  remmina_file_get_int(priv->remmina_file, setting_name, FALSE));
781  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
782  if (settings->opt2)
783  gtk_widget_set_tooltip_text(widget, (const gchar *)settings->opt2);
784  break;
785 
787  widget = remmina_file_editor_create_chooser(gfe, grid, grid_row, 0,
788  g_dgettext(priv->plugin->domain, settings->label),
789  remmina_file_get_string(priv->remmina_file, setting_name),
790  GTK_FILE_CHOOSER_ACTION_OPEN);
791  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
792  if (settings->opt2)
793  gtk_widget_set_tooltip_text(widget, (const gchar *)settings->opt2);
794  break;
795 
797  widget = remmina_file_editor_create_chooser(gfe, grid, grid_row, 0,
798  g_dgettext(priv->plugin->domain, settings->label),
799  remmina_file_get_string(priv->remmina_file, setting_name),
800  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
801  g_hash_table_insert(priv->setting_widgets, setting_name, widget);
802  if (settings->opt2)
803  gtk_widget_set_tooltip_text(widget, (const gchar *)settings->opt2);
804  break;
805 
806  default:
807  break;
808  }
809  /* If the setting wants compactness, move to the next column */
810  if (settings->compact)
811  grid_column++;
812  /* Add a new settings row and move to the first column
813  * if the setting doesn’t want the compactness
814  * or we already have two columns */
815  if (!settings->compact || grid_column > 1) {
816  grid_row++;
817  grid_column = 0;
818  }
819  settings++;
820  }
821 }
822 
824 {
825  TRACE_CALL(__func__);
826 #ifdef HAVE_LIBSSH
827  RemminaFileEditorPriv *priv = gfe->priv;
828  GtkWidget *grid;
829  GtkWidget *widget;
830  const gchar *cs;
831  gchar *s;
832  gchar *p;
833  gint row = 0;
834 
835  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_NONE) return;
836 
837  /* The SSH tab (implementation) */
839  _("SSH Tunnel"), 9, 3);
840  widget = gtk_toggle_button_new_with_label(_("Enable SSH tunnel"));
841  gtk_widget_set_halign(widget, GTK_ALIGN_START);
842  gtk_grid_attach(GTK_GRID(grid), widget, 0, 0, 1, 1);
843  g_signal_connect(G_OBJECT(widget), "toggled",
845  priv->ssh_tunnel_enabled_check = widget;
846 
847  widget = gtk_check_button_new_with_label(_("Tunnel via loopback address"));
848  gtk_grid_attach(GTK_GRID(grid), widget, 1, 0, 2, 1);
849  priv->ssh_tunnel_loopback_check = widget;
850 
851  row++;
852  /* SSH Server group */
853 
854  switch (ssh_setting) {
856  s = g_strdup_printf(_("Same server at port %i"), DEFAULT_SSH_PORT);
857  widget = gtk_radio_button_new_with_label(NULL, s);
858  g_free(s);
859  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 3, 1);
860  priv->ssh_tunnel_server_default_radio = widget;
861  row++;
862 
863  widget = gtk_radio_button_new_with_label_from_widget(
864  GTK_RADIO_BUTTON(priv->ssh_tunnel_server_default_radio), _("Custom"));
865  gtk_grid_attach(GTK_GRID(grid), widget, 0, row, 1, 1);
866  g_signal_connect(G_OBJECT(widget), "toggled",
868  priv->ssh_tunnel_server_custom_radio = widget;
869 
870  widget = gtk_entry_new();
871  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
872  gtk_widget_set_tooltip_markup(widget, _(server_tips2));
873  gtk_grid_attach(GTK_GRID(grid), widget, 1, row, 2, 1);
874  priv->ssh_tunnel_server_entry = widget;
875  row++;
876  break;
877 
879  priv->ssh_tunnel_server_default_radio = NULL;
880  priv->ssh_tunnel_server_custom_radio = NULL;
881 
882  priv->ssh_tunnel_server_entry = remmina_file_editor_create_text(gfe, grid, 1, 0,
883  _("Server"), NULL);
884  gtk_widget_set_tooltip_markup(priv->ssh_tunnel_server_entry, _(server_tips));
885  row++;
886  break;
889  priv->ssh_tunnel_server_default_radio = NULL;
890  priv->ssh_tunnel_server_custom_radio = NULL;
891  priv->ssh_tunnel_server_entry = NULL;
892 
893  break;
894 
895  default:
896  break;
897  }
898 
899  p = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo));
900  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_SFTP) {
901  widget = remmina_file_editor_create_text(gfe, grid, row + 8, 1,
902  _("Startup path"), NULL);
903  cs = remmina_file_get_string(priv->remmina_file, "execpath");
904  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
905  g_hash_table_insert(priv->setting_widgets, "execpath", widget);
906  row++;
907  }
908 
909  /* SSH Authentication frame */
910  //if (!(g_strcmp0(p, "SFTP") == 0 || g_strcmp0(p, "SSH") == 0)) {
911  remmina_public_create_group(GTK_GRID(grid), _("SSH Authentication"), row + 8, 6, 1);
912  row++;
913 
914  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_TUNNEL ||
916  priv->ssh_tunnel_username_entry =
917  remmina_file_editor_create_text(gfe, grid, row + 10, 0,
918  _("Username"), NULL);
919  row++;
920  }
921  widget = gtk_radio_button_new_with_label(NULL, _("SSH agent (automatic)"));
922  gtk_grid_attach(GTK_GRID(grid), widget, 0, row + 19, 1, 1);
923  priv->ssh_tunnel_auth_agent_radio = widget;
924  row++;
925 
926  widget = gtk_radio_button_new_with_label_from_widget(
927  GTK_RADIO_BUTTON(priv->ssh_tunnel_auth_agent_radio), _("Password"));
928  gtk_grid_attach(GTK_GRID(grid), widget, 0, row + 21, 1, 1);
929  priv->ssh_tunnel_auth_password_radio = widget;
930 
931  widget = gtk_entry_new();
932  gtk_grid_attach(GTK_GRID(grid), widget, 1, row + 21, 2, 1);
933  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
934  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
935  gtk_widget_set_hexpand(widget, TRUE);
936  priv->ssh_tunnel_auth_password = widget;
937  row++;
938 
939  widget = gtk_radio_button_new_with_label_from_widget(
940  GTK_RADIO_BUTTON(priv->ssh_tunnel_auth_agent_radio), _("Public key (automatic)"));
941  gtk_grid_attach(GTK_GRID(grid), widget, 0, row + 22, 1, 1);
942  priv->ssh_tunnel_auth_auto_publickey_radio = widget;
943  row++;
944 
945  remmina_file_editor_create_ssh_privatekey(gfe, grid, row + 1, 0);
946  //}
947  row++;
948 
949  widget = gtk_label_new(_("Password to unlock private key"));
950  gtk_grid_attach(GTK_GRID(grid), widget, 0, row + 23, 1, 1);
951  widget = gtk_entry_new();
952  gtk_grid_attach(GTK_GRID(grid), widget, 1, row + 23, 2, 1);
953  gtk_entry_set_max_length(GTK_ENTRY(widget), 300);
954  gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
955  gtk_widget_set_hexpand(widget, TRUE);
956  priv->ssh_tunnel_passphrase = widget;
957  row++;
958 
959  /* Set the values */
960  cs = remmina_file_get_string(priv->remmina_file, "ssh_tunnel_server");
961  if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_TUNNEL) {
962  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check),
963  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_enabled", FALSE));
964  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check),
965  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_loopback", FALSE));
966 
967  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cs ?
968  priv->ssh_tunnel_server_custom_radio : priv->ssh_tunnel_server_default_radio), TRUE);
969  gtk_entry_set_text(GTK_ENTRY(priv->ssh_tunnel_server_entry),
970  cs ? cs : "");
971  } else if (ssh_setting == REMMINA_PROTOCOL_SSH_SETTING_REVERSE_TUNNEL) {
972  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check),
973  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_enabled", FALSE));
974  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check),
975  remmina_file_get_int(priv->remmina_file, "ssh_tunnel_loopback", FALSE));
976  gtk_entry_set_text(GTK_ENTRY(priv->ssh_tunnel_server_entry),
977  cs ? cs : "");
978  }
979 
980  //if (!(g_strcmp0(p, "SFTP") == 0 || g_strcmp0(p, "SSH") == 0)) {
981  gint ssh_tunnel_auth_status = remmina_file_get_int(priv->remmina_file, "ssh_tunnel_auth", 0);
982  g_debug ("[Editor - tunnel] ssh_tunnel_auth_status is: %d", ssh_tunnel_auth_status);
983  switch (ssh_tunnel_auth_status) {
984  case SSH_AUTH_PUBLICKEY:
985  g_debug("[Editor - tunnel] Auth set from file to SSH_AUTH_PUBLICKEY");
986  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_publickey_radio), TRUE);
987  break;
989  g_debug("[Editor - tunnel] Auth set from file to SSH_AUTH_AUTO_PUBLICKEY");
990  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_auto_publickey_radio), TRUE);
991  break;
992  case SSH_AUTH_AGENT:
993  g_debug("[Editor - tunnel] Auth set from file to SSH_AUTH_AGENT");
994  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_agent_radio), TRUE);
995  break;
996  default:
997  g_debug("[Editor - tunnel] Auth set from file to SSH_AUTH_PASSWORD");
998  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_password_radio), TRUE);
999  break;
1000  }
1001 
1003  //}
1004  gtk_widget_show_all(grid);
1005  g_free(p);
1006 #endif
1007 }
1008 
1010 {
1011  TRACE_CALL(__func__);
1012  RemminaFileEditorPriv *priv = gfe->priv;
1013  GtkWidget *grid;
1014 
1015  static const RemminaProtocolSetting autostart_settings[] =
1016  {
1017  { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enable-autostart", N_("Autostart this profile"), FALSE, NULL, NULL },
1018  { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL }
1019  };
1020 
1022 
1023  /* The Basic tab */
1024  if (priv->plugin->basic_settings) {
1025  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Basic"), 20, 2);
1026  remmina_file_editor_create_settings(gfe, grid, priv->plugin->basic_settings);
1027  }
1028 
1029  /* The Advanced tab */
1030  if (priv->plugin->advanced_settings) {
1031  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Advanced"), 20, 2);
1032  remmina_file_editor_create_settings(gfe, grid, priv->plugin->advanced_settings);
1033  }
1034 
1035  /* Autostart tab */
1036  grid = remmina_file_editor_create_notebook_tab(gfe, NULL, _("Autostart"), 20, 2);
1037  remmina_file_editor_create_settings(gfe, grid, autostart_settings);
1038 
1039  /* The SSH tab */
1040  remmina_file_editor_create_ssh_tunnel_tab(gfe, priv->plugin->ssh_setting);
1041 }
1042 
1044 {
1045  TRACE_CALL(__func__);
1046  RemminaFileEditorPriv *priv = gfe->priv;
1047  gchar *protocol;
1048 
1049  if (priv->config_container) {
1050  gtk_widget_destroy(priv->config_container);
1051  priv->config_container = NULL;
1052  gtk_widget_destroy(priv->config_viewport);
1053  priv->config_viewport = NULL;
1054  gtk_widget_destroy(priv->config_scrollable);
1055  priv->config_scrollable = NULL;
1056  }
1057 
1058  priv->server_combo = NULL;
1059  priv->resolution_iws_radio = NULL;
1060  priv->resolution_auto_radio = NULL;
1061  priv->resolution_custom_radio = NULL;
1062  priv->resolution_custom_combo = NULL;
1063  priv->keymap_combo = NULL;
1064 
1065  priv->ssh_tunnel_enabled_check = NULL;
1066  priv->ssh_tunnel_loopback_check = NULL;
1067  priv->ssh_tunnel_server_default_radio = NULL;
1068  priv->ssh_tunnel_server_custom_radio = NULL;
1069  priv->ssh_tunnel_server_entry = NULL;
1070  priv->ssh_tunnel_username_entry = NULL;
1071  priv->ssh_tunnel_auth_agent_radio = NULL;
1072  priv->ssh_tunnel_auth_password_radio = NULL;
1073  priv->ssh_tunnel_auth_publickey_radio = NULL;
1074  priv->ssh_tunnel_auth_auto_publickey_radio = NULL;
1075  priv->ssh_tunnel_privatekey_chooser = NULL;
1076 
1077  g_hash_table_remove_all(priv->setting_widgets);
1078 
1079  protocol = remmina_public_combo_get_active_text(combo);
1080  if (protocol) {
1082  protocol);
1083  g_free(protocol);
1085  }
1086 }
1087 
1089 {
1090  TRACE_CALL(__func__);
1091  RemminaFileEditorPriv *priv = gfe->priv;
1092  gboolean ssh_tunnel_enabled;
1093  int ssh_tunnel_auth;
1094 
1095  ssh_tunnel_enabled = (priv->ssh_tunnel_enabled_check ?
1096  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_enabled_check)) : FALSE);
1097  remmina_file_set_int(priv->remmina_file,
1098  "ssh_tunnel_loopback",
1099  (priv->ssh_tunnel_loopback_check ?
1100  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->ssh_tunnel_loopback_check)) :
1101  FALSE));
1102  remmina_file_set_int(priv->remmina_file, "ssh_tunnel_enabled", ssh_tunnel_enabled);
1103  remmina_file_set_string(priv->remmina_file, "ssh_tunnel_username",
1104  (ssh_tunnel_enabled ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_username_entry)) : NULL));
1106  priv->remmina_file,
1107  "ssh_tunnel_server",
1108  (ssh_tunnel_enabled && priv->ssh_tunnel_server_entry
1109  && (priv->ssh_tunnel_server_custom_radio == NULL
1110  || gtk_toggle_button_get_active(
1111  GTK_TOGGLE_BUTTON(priv->ssh_tunnel_server_custom_radio))) ?
1112  gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_server_entry)) : NULL));
1113 
1114  ssh_tunnel_auth = (priv->ssh_tunnel_auth_publickey_radio
1115  && gtk_toggle_button_get_active(
1116  GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_publickey_radio)) ?
1118  priv->ssh_tunnel_auth_auto_publickey_radio
1119  && gtk_toggle_button_get_active(
1120  GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_auto_publickey_radio)) ?
1122  priv->ssh_tunnel_auth_agent_radio
1123  && gtk_toggle_button_get_active(
1124  GTK_TOGGLE_BUTTON(priv->ssh_tunnel_auth_agent_radio)) ?
1126 
1128  priv->remmina_file,
1129  "ssh_tunnel_auth",
1130  ssh_tunnel_auth
1131  );
1133  priv->remmina_file,
1134  "ssh_tunnel_privatekey",
1135  (priv->ssh_tunnel_privatekey_chooser ?
1136  gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(priv->ssh_tunnel_privatekey_chooser)) : NULL));
1137 
1139  priv->remmina_file,
1140  "ssh_tunnel_password",
1141  (ssh_tunnel_enabled && (ssh_tunnel_auth == SSH_AUTH_PASSWORD)) ? gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_auth_password)) : NULL);
1142 
1144  priv->remmina_file,
1145  "ssh_tunnel_passphrase",
1146  (ssh_tunnel_enabled && (ssh_tunnel_auth == SSH_AUTH_PUBLICKEY || ssh_tunnel_auth == SSH_AUTH_AUTO_PUBLICKEY)) ?
1147  gtk_entry_get_text(GTK_ENTRY(priv->ssh_tunnel_passphrase)) : NULL);
1148 }
1149 
1151 {
1152  TRACE_CALL(__func__);
1153  RemminaFileEditorPriv *priv = gfe->priv;
1154  GHashTableIter iter;
1155  gpointer key, value;
1156 
1157  g_hash_table_iter_init(&iter, priv->setting_widgets);
1158  while (g_hash_table_iter_next(&iter, &key, &value)) {
1159  if (GTK_IS_ENTRY(value)) {
1160  remmina_file_set_string(priv->remmina_file, (gchar *)key, gtk_entry_get_text(GTK_ENTRY(value)));
1161  } else if (GTK_IS_COMBO_BOX(value)) {
1162  remmina_file_set_string_ref(priv->remmina_file, (gchar *)key,
1163  remmina_public_combo_get_active_text(GTK_COMBO_BOX(value)));
1164  } else if (GTK_IS_FILE_CHOOSER(value)) {
1166  priv->remmina_file,
1167  (gchar *)key,
1168  gtk_widget_get_sensitive(GTK_WIDGET(value)) ?
1169  gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(value)) :
1170  NULL);
1171  } else if (GTK_IS_TOGGLE_BUTTON(value)) {
1172  remmina_file_set_int(priv->remmina_file, (gchar *)key,
1173  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(value)));
1174  }
1175  }
1176 }
1177 
1179 {
1180  TRACE_CALL(__func__);
1181  int res_w, res_h;
1182  gchar *custom_resolution;
1184 
1185  RemminaFileEditorPriv *priv = gfe->priv;
1186 
1187  remmina_file_set_string(priv->remmina_file, "name", gtk_entry_get_text(GTK_ENTRY(priv->name_entry)));
1188 
1189  remmina_file_set_string_ref(priv->remmina_file, "group",
1190  (priv->group_combo ? remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->group_combo)) : NULL));
1191 
1192  remmina_file_set_string_ref(priv->remmina_file, "protocol",
1193  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->protocol_combo)));
1194 
1195  remmina_file_set_string(priv->remmina_file, "precommand", gtk_entry_get_text(GTK_ENTRY(priv->precommand_entry)));
1196  remmina_file_set_string(priv->remmina_file, "postcommand", gtk_entry_get_text(GTK_ENTRY(priv->postcommand_entry)));
1197 
1198  remmina_file_set_string_ref(priv->remmina_file, "server",
1199  (priv->server_combo ? remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->server_combo)) : NULL));
1200 
1201  if (priv->resolution_auto_radio) {
1202  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_auto_radio))) {
1203  /* Resolution is set to auto (which means: Use client fullscreen resolution, aka use client resolution) */
1204  res_w = res_h = 0;
1205  res_mode = RES_USE_CLIENT;
1206  } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->resolution_iws_radio))) {
1207  /* Resolution is set to initial window size */
1208  res_w = res_h = 0;
1209  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
1210  } else {
1211  /* Resolution is set to a value from the list */
1212  custom_resolution = remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->resolution_custom_combo));
1213  if (remmina_public_split_resolution_string(custom_resolution, &res_w, &res_h))
1214  res_mode = RES_USE_CUSTOM;
1215  else
1216  res_mode = RES_USE_INITIAL_WINDOW_SIZE;
1217  g_free(custom_resolution);
1218  }
1219  remmina_file_set_int(priv->remmina_file, "resolution_mode", res_mode);
1220  remmina_file_set_int(priv->remmina_file, "resolution_width", res_w);
1221  remmina_file_set_int(priv->remmina_file, "resolution_height", res_h);
1222  }
1223 
1224  if (priv->keymap_combo)
1225  remmina_file_set_string_ref(priv->remmina_file, "keymap",
1226  remmina_public_combo_get_active_text(GTK_COMBO_BOX(priv->keymap_combo)));
1227 
1230 }
1231 
1232 static void remmina_file_editor_on_default(GtkWidget *button, RemminaFileEditor *gfe)
1233 {
1234  TRACE_CALL(__func__);
1235  RemminaFile *gf;
1236  GtkWidget *dialog;
1237 
1239 
1240  gf = remmina_file_dup(gfe->priv->remmina_file);
1241 
1243 
1244  /* Clear properties that should never be default */
1245  remmina_file_set_string(gf, "name", NULL);
1246  remmina_file_set_string(gf, "server", NULL);
1247  remmina_file_set_string(gf, "password", NULL);
1248  remmina_file_set_string(gf, "precommand", NULL);
1249  remmina_file_set_string(gf, "postcommand", NULL);
1250 
1251  remmina_file_set_string(gf, "ssh_tunnel_server", NULL);
1252  remmina_file_set_string(gf, "ssh_tunnel_password", NULL);
1253  remmina_file_set_string(gf, "ssh_tunnel_passphrase", NULL);
1254 
1255  remmina_file_save(gf);
1256  remmina_file_free(gf);
1257 
1258  dialog = gtk_message_dialog_new(GTK_WINDOW(gfe), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
1259  _("Default settings saved."));
1260  gtk_dialog_run(GTK_DIALOG(dialog));
1261  gtk_widget_destroy(dialog);
1262 }
1263 
1264 static void remmina_file_editor_on_save(GtkWidget *button, RemminaFileEditor *gfe)
1265 {
1266  TRACE_CALL(__func__);
1267 
1270 
1271  remmina_file_save(gfe->priv->remmina_file);
1273 
1274  gtk_widget_destroy(GTK_WIDGET(gfe));
1275 }
1276 
1277 static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
1278 {
1279  TRACE_CALL(__func__);
1280  RemminaFile *gf;
1281 
1283 
1284  gf = remmina_file_dup(gfe->priv->remmina_file);
1285  /* Put server into name for "Quick Connect" */
1286  if (remmina_file_get_filename(gf) == NULL)
1287  remmina_file_set_string(gf, "name", remmina_file_get_string(gf, "server"));
1288  gtk_widget_destroy(GTK_WIDGET(gfe));
1289  gf->prevent_saving = TRUE;
1290  rcw_open_from_file(gf);
1291 }
1292 
1293 static void remmina_file_editor_on_save_connect(GtkWidget *button, RemminaFileEditor *gfe)
1294 {
1295  TRACE_CALL(__func__);
1297  RemminaFile *gf;
1298 
1301 
1302  remmina_file_save(gfe->priv->remmina_file);
1304 
1305  gf = remmina_file_dup(gfe->priv->remmina_file);
1306  /* Put server into name for Quick Connect */
1307  if (remmina_file_get_filename(gf) == NULL)
1308  remmina_file_set_string(gf, "name", remmina_file_get_string(gf, "server"));
1309  gtk_widget_destroy(GTK_WIDGET(gfe));
1310  rcw_open_from_file(gf);
1311 }
1312 
1313 static void remmina_file_editor_on_cancel(GtkWidget *button, RemminaFileEditor *gfe)
1314 {
1315  TRACE_CALL(__func__);
1316  gtk_widget_destroy(GTK_WIDGET(gfe));
1317 }
1318 
1320 {
1321  TRACE_CALL(__func__);
1322  RemminaFileEditorPriv *priv;
1323  GtkWidget *widget;
1324 
1325  priv = g_new0(RemminaFileEditorPriv, 1);
1326  gfe->priv = priv;
1327 
1328  /* Create the editor dialog */
1329  gtk_window_set_title(GTK_WINDOW(gfe), _("Remote Desktop Preference"));
1330 
1331  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Cancel")), GTK_RESPONSE_CANCEL);
1332  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_cancel), gfe);
1333 
1334  /* Default button */
1335  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("Save as Default")), GTK_RESPONSE_OK);
1336  gtk_widget_set_tooltip_text(GTK_WIDGET(widget), _("Use the current settings as the default for all new connection profiles"));
1337  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_default), gfe);
1338 
1339  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Save")), GTK_RESPONSE_APPLY);
1340  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_save), gfe);
1341  gtk_widget_set_sensitive(widget, FALSE);
1342  priv->save_button = widget;
1343 
1344  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("Connect")), GTK_RESPONSE_ACCEPT);
1345  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_connect), gfe);
1346 
1347  widget = gtk_dialog_add_button(GTK_DIALOG(gfe), (_("_Save and Connect")), GTK_RESPONSE_OK);
1348  gtk_widget_set_can_default(widget, TRUE);
1349  g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(remmina_file_editor_on_save_connect), gfe);
1350 
1351  gtk_dialog_set_default_response(GTK_DIALOG(gfe), GTK_RESPONSE_OK);
1352  gtk_window_set_default_size(GTK_WINDOW(gfe), 800, 600);
1353 
1354  g_signal_connect(G_OBJECT(gfe), "destroy", G_CALLBACK(remmina_file_editor_destroy), NULL);
1355  g_signal_connect(G_OBJECT(gfe), "realize", G_CALLBACK(remmina_file_editor_on_realize), NULL);
1356 
1357  priv->setting_widgets = g_hash_table_new(g_str_hash, g_str_equal);
1358 
1359  remmina_widget_pool_register(GTK_WIDGET(gfe));
1360 }
1361 
1362 static gboolean remmina_file_editor_iterate_protocol(gchar *protocol, RemminaPlugin *plugin, gpointer data)
1363 {
1364  TRACE_CALL(__func__);
1365  RemminaFileEditor *gfe = REMMINA_FILE_EDITOR(data);
1366  GtkListStore *store;
1367  GtkTreeIter iter;
1368  gboolean first;
1369 
1370  store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(gfe->priv->protocol_combo)));
1371 
1372  first = !gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
1373 
1374  gtk_list_store_append(store, &iter);
1375  gtk_list_store_set(store, &iter, 0, protocol, 1, g_dgettext(plugin->domain, plugin->description), 2,
1376  ((RemminaProtocolPlugin *)plugin)->icon_name, -1);
1377 
1378  if (first || g_strcmp0(protocol, remmina_file_get_string(gfe->priv->remmina_file, "protocol")) == 0)
1379  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(gfe->priv->protocol_combo), &iter);
1380 
1381  return FALSE;
1382 }
1383 
1385 {
1386  TRACE_CALL(__func__);
1387  RemminaFileEditorPriv *priv;
1388 
1389  priv = gfe->priv;
1390  gtk_widget_set_sensitive(priv->group_combo, TRUE);
1391  gtk_widget_set_sensitive(priv->save_button, TRUE);
1392 }
1393 
1394 static void remmina_file_editor_entry_on_changed(GtkEditable *editable, RemminaFileEditor *gfe)
1395 {
1396  TRACE_CALL(__func__);
1397  RemminaFileEditorPriv *priv;
1398 
1399  priv = gfe->priv;
1400  if (remmina_file_get_filename(priv->remmina_file) == NULL) {
1401  remmina_file_generate_filename(priv->remmina_file);
1402  /* TODO: Probably to be removed */
1404  } else {
1405  remmina_file_delete(remmina_file_get_filename(priv->remmina_file));
1406  remmina_file_generate_filename(priv->remmina_file);
1408  }
1409 }
1410 
1412 {
1413  TRACE_CALL(__func__);
1414  RemminaFileEditorPriv *priv;
1415 
1416  priv = gfe->priv;
1417  if (remmina_file_get_filename(priv->remmina_file) == NULL) {
1418  remmina_file_generate_filename(priv->remmina_file);
1419  } else {
1420  remmina_file_delete(remmina_file_get_filename(priv->remmina_file));
1421  remmina_file_generate_filename(priv->remmina_file);
1422  }
1423 }
1424 
1425 
1427 {
1428  TRACE_CALL(__func__);
1429  RemminaFileEditor *gfe;
1430  RemminaFileEditorPriv *priv;
1431  GtkWidget *grid;
1432  GtkWidget *widget;
1433  gchar *groups;
1434  gchar *s;
1435  const gchar *cs;
1436 
1437  gfe = REMMINA_FILE_EDITOR(g_object_new(REMMINA_TYPE_FILE_EDITOR, NULL));
1438  priv = gfe->priv;
1439  priv->remmina_file = remminafile;
1440 
1441  if (remmina_file_get_filename(remminafile) == NULL)
1442  gtk_dialog_set_response_sensitive(GTK_DIALOG(gfe), GTK_RESPONSE_APPLY, FALSE);
1443 
1444  /* Create the "Profile" group on the top (for name and protocol) */
1445  grid = gtk_grid_new();
1446  gtk_widget_show(grid);
1447  gtk_grid_set_row_spacing(GTK_GRID(grid), 4);
1448  gtk_grid_set_column_spacing(GTK_GRID(grid), 8);
1449  gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
1450  gtk_container_set_border_width(GTK_CONTAINER(grid), 8);
1451  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gfe))), grid, FALSE, FALSE, 2);
1452 
1453  //remmina_public_create_group(GTK_GRID(grid), _("Profile"), 0, 4, 3);
1454 
1455  /* Profile: Name */
1456  widget = gtk_label_new(_("Name"));
1457  gtk_widget_show(widget);
1458  gtk_widget_set_valign(widget, GTK_ALIGN_START);
1459  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1460  gtk_grid_attach(GTK_GRID(grid), widget, 0, 3, 2, 1);
1461  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
1462 
1463  widget = gtk_entry_new();
1464  gtk_widget_show(widget);
1465  gtk_grid_attach(GTK_GRID(grid), widget, 1, 3, 3, 1);
1466  gtk_entry_set_max_length(GTK_ENTRY(widget), 100);
1467  priv->name_entry = widget;
1468 
1469  if (remmina_file_get_filename(remminafile) == NULL) {
1470  gtk_entry_set_text(GTK_ENTRY(widget), _("Quick Connect"));
1471 #if GTK_CHECK_VERSION(3, 16, 0)
1472  gtk_entry_grab_focus_without_selecting(GTK_ENTRY(widget));
1473 #endif
1474  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_entry_on_changed), gfe);
1475  } else {
1476  cs = remmina_file_get_string(remminafile, "name");
1477  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
1478  }
1479 
1480  /* Profile: Group */
1481  widget = gtk_label_new(_("Group"));
1482  gtk_widget_show(widget);
1483  gtk_widget_set_valign(widget, GTK_ALIGN_START);
1484  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1485  gtk_grid_attach(GTK_GRID(grid), widget, 0, 6, 2, 1);
1486 
1488  priv->group_combo = remmina_public_create_combo_entry(groups, remmina_file_get_string(remminafile, "group"), FALSE);
1489  g_free(groups);
1490  gtk_widget_show(priv->group_combo);
1491  gtk_grid_attach(GTK_GRID(grid), priv->group_combo, 1, 6, 3, 1);
1492  gtk_widget_set_sensitive(priv->group_combo, FALSE);
1493 
1494  s = g_strdup_printf(_("Use '%s' as subgroup delimiter"), "/");
1495  gtk_widget_set_tooltip_text(priv->group_combo, s);
1496  g_free(s);
1497 
1498  /* Profile: Protocol */
1499  widget = gtk_label_new(_("Protocol"));
1500  gtk_widget_show(widget);
1501  gtk_widget_set_valign(widget, GTK_ALIGN_START);
1502  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1503  gtk_grid_attach(GTK_GRID(grid), widget, 0, 9, 2, 1);
1504 
1505  widget = remmina_public_create_combo(TRUE);
1506  gtk_widget_show(widget);
1507  gtk_grid_attach(GTK_GRID(grid), widget, 1, 9, 3, 1);
1508  priv->protocol_combo = widget;
1510  g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(remmina_file_editor_protocol_combo_on_changed), gfe);
1511 
1512  /* Prior connection command */
1513  widget = gtk_label_new(_("Pre-command"));
1514  gtk_widget_show(widget);
1515  gtk_widget_set_valign(widget, GTK_ALIGN_START);
1516  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1517  gtk_grid_attach(GTK_GRID(grid), widget, 0, 12, 3, 1);
1518  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
1519 
1520  widget = gtk_entry_new();
1521  gtk_widget_show(widget);
1522  gtk_grid_attach(GTK_GRID(grid), widget, 1, 12, 3, 1);
1523  gtk_entry_set_max_length(GTK_ENTRY(widget), 200);
1524  priv->precommand_entry = widget;
1525  cs = remmina_file_get_string(remminafile, "precommand");
1526  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
1527  gtk_entry_set_placeholder_text(GTK_ENTRY(widget), _("command %h %u %t %U %p %g --option"));
1528  gtk_widget_set_tooltip_markup(widget, _(cmd_tips));
1529 
1530  /* POST connection command */
1531  widget = gtk_label_new(_("Post-command"));
1532  gtk_widget_show(widget);
1533  gtk_widget_set_valign(widget, GTK_ALIGN_START);
1534  gtk_widget_set_halign(widget, GTK_ALIGN_START);
1535  gtk_grid_attach(GTK_GRID(grid), widget, 0, 15, 3, 1);
1536  gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
1537 
1538  widget = gtk_entry_new();
1539  gtk_widget_show(widget);
1540  gtk_grid_attach(GTK_GRID(grid), widget, 1, 15, 3, 1);
1541  gtk_entry_set_max_length(GTK_ENTRY(widget), 200);
1542  priv->postcommand_entry = widget;
1543  cs = remmina_file_get_string(remminafile, "postcommand");
1544  gtk_entry_set_text(GTK_ENTRY(widget), cs ? cs : "");
1545  gtk_entry_set_placeholder_text(GTK_ENTRY(widget), _("/path/to/command -opt1 arg %h %u %t -opt2 %U %p %g"));
1546  gtk_widget_set_tooltip_markup(widget, _(cmd_tips));
1547 
1548  /* Create the "Preference" frame */
1549  widget = gtk_event_box_new();
1550  gtk_widget_show(widget);
1551  gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(gfe))), widget, TRUE, TRUE, 2);
1552  priv->config_box = widget;
1553 
1554  priv->config_container = NULL;
1555  priv->config_scrollable = NULL;
1556 
1557  remmina_file_editor_protocol_combo_on_changed(GTK_COMBO_BOX(priv->protocol_combo), gfe);
1558 
1560 
1561  return GTK_WIDGET(gfe);
1562 }
1563 
1564 GtkWidget *remmina_file_editor_new(void)
1565 {
1566  TRACE_CALL(__func__);
1567  return remmina_file_editor_new_full(NULL, NULL);
1568 }
1569 
1570 GtkWidget *remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
1571 {
1572  TRACE_CALL(__func__);
1573  RemminaFile *remminafile;
1574 
1575  remminafile = remmina_file_new();
1576  if (server)
1577  remmina_file_set_string(remminafile, "server", server);
1578  if (protocol)
1579  remmina_file_set_string(remminafile, "protocol", protocol);
1580 
1581  return remmina_file_editor_new_from_file(remminafile);
1582 }
1583 
1584 GtkWidget *remmina_file_editor_new_copy(const gchar *filename)
1585 {
1586  TRACE_CALL(__func__);
1587  RemminaFile *remminafile;
1588  GtkWidget *dialog;
1589 
1590  remminafile = remmina_file_copy(filename);
1591 
1592  if (remminafile) {
1593  return remmina_file_editor_new_from_file(remminafile);
1594  } else {
1595  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1596  _("Could not find the file \"%s\"."), filename);
1597  gtk_dialog_run(GTK_DIALOG(dialog));
1598  gtk_widget_destroy(dialog);
1599  return NULL;
1600  }
1601 }
1602 
1603 GtkWidget *remmina_file_editor_new_from_filename(const gchar *filename)
1604 {
1605  TRACE_CALL(__func__);
1606  RemminaFile *remminafile;
1607  GtkWidget *dialog;
1608 
1609  remminafile = remmina_file_manager_load_file(filename);
1610  if (remminafile) {
1611  return remmina_file_editor_new_from_file(remminafile);
1612  } else {
1613  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
1614  _("Could not find the file \"%s\"."), filename);
1615  gtk_dialog_run(GTK_DIALOG(dialog));
1616  gtk_widget_destroy(dialog);
1617  return NULL;
1618  }
1619 }
void remmina_public_create_group(GtkGrid *grid, const gchar *group, gint row, gint rows, gint cols)
const gchar * remmina_plugin_manager_get_canonical_setting_name(const RemminaProtocolSetting *setting)
GtkDialog * remmina_string_list_new(gboolean two_columns, const gchar *fields_separator)
void remmina_file_free(RemminaFile *remminafile)
Definition: remmina_file.c:548
const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:449
gchar ** remmina_pref_keymap_groups(void)
Definition: remmina_pref.c:951
static void remmina_file_editor_create_resolution(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
RemminaFile * remmina_file_dup(RemminaFile *remminafile)
Definition: remmina_file.c:679
GtkWidget * remmina_public_create_combo_entry(const gchar *text, const gchar *def, gboolean descending)
static void remmina_file_editor_on_connect(GtkWidget *button, RemminaFileEditor *gfe)
gchar * remmina_pref_file
Definition: rcw.c:72
void remmina_string_list_set_validation_func(RemminaStringListValidationFunc func)
G_DEFINE_TYPE(RemminaFileEditor, remmina_file_editor, GTK_TYPE_DIALOG)
static void remmina_file_editor_ssh_tunnel_enabled_check_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)
const gchar * remmina_file_get_filename(RemminaFile *remminafile)
Definition: remmina_file.c:184
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:41
static void remmina_file_editor_protocol_combo_on_changed(GtkComboBox *combo, RemminaFileEditor *gfe)
void remmina_plugin_manager_for_each_plugin(RemminaPluginType type, RemminaPluginFunc func, gpointer data)
static GtkWidget * remmina_file_editor_create_check(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint top, const gchar *label, gboolean value)
void remmina_widget_pool_register(GtkWidget *widget)
static void remmina_file_editor_destroy(GtkWidget *widget, gpointer data)
gchar * remmina_public_combo_get_active_text(GtkComboBox *combo)
gboolean remmina_public_resolution_validation_func(const gchar *new_str, gchar **error)
const gchar * domain
Definition: plugin.h:57
gchar * remmina_pref_get_recent(const gchar *protocol)
Definition: remmina_pref.c:883
static void remmina_file_editor_create_server(RemminaFileEditor *gfe, const RemminaProtocolSetting *setting, GtkWidget *grid, gint row)
void remmina_icon_populate_menu(void)
Definition: remmina_icon.c:264
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
const gpointer opt2
Definition: types.h:100
static void remmina_file_editor_init(RemminaFileEditor *gfe)
static GtkWidget * remmina_file_editor_create_chooser(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value, gint type)
gchar * resolutions
Definition: remmina_pref.h:127
void remmina_file_generate_filename(RemminaFile *remminafile)
Definition: remmina_file.c:108
const gchar * description
Definition: plugin.h:56
static void remmina_file_editor_create_ssh_privatekey(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint column)
int remmina_public_split_resolution_string(const char *resolution_string, int *w, int *h)
gboolean compact
Definition: types.h:98
RemminaProtocolWidgetResolutionMode
Definition: types.h:123
GtkWidget * remmina_public_create_combo_map(const gpointer *key_value_list, const gchar *def, gboolean use_icon, const gchar *domain)
static void remmina_file_editor_update(RemminaFileEditor *gfe)
void remmina_file_set_filename(RemminaFile *remminafile, const gchar *filename)
Definition: remmina_file.c:176
void remmina_file_editor_check_profile(RemminaFileEditor *gfe)
GtkWidget * remmina_public_create_combo_text_d(const gchar *text, const gchar *def, const gchar *empty_choice)
const gpointer opt1
Definition: types.h:99
struct _RemminaFileEditorPriv RemminaFileEditorPriv
static GtkWidget * remmina_file_editor_create_notebook_tab(RemminaFileEditor *gfe, const gchar *stock_id, const gchar *label, gint rows, gint cols)
GtkWidget * remmina_public_create_combo(gboolean use_icon)
RemminaProtocolSSHSetting
Definition: types.h:103
void remmina_file_set_int(RemminaFile *remminafile, const gchar *setting, gint value)
Definition: remmina_file.c:518
void remmina_file_delete(const gchar *filename)
Definition: remmina_file.c:723
static void remmina_file_editor_entry_on_changed(GtkEditable *editable, RemminaFileEditor *gfe)
static void remmina_file_editor_create_all_settings(RemminaFileEditor *gfe)
static void remmina_file_editor_create_notebook_container(RemminaFileEditor *gfe)
GtkWidget * remmina_file_editor_new_from_file(RemminaFile *remminafile)
void remmina_string_list_set_text(const gchar *text, const gboolean clear_data)
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
static void remmina_file_editor_create_ssh_tunnel_tab(RemminaFileEditor *gfe, RemminaProtocolSSHSetting ssh_setting)
RemminaProtocolSettingType type
Definition: types.h:95
RemminaFile * remmina_file_new(void)
Definition: remmina_file.c:90
void remmina_string_list_set_titles(gchar *title1, gchar *title2)
static void remmina_file_editor_create_settings(RemminaFileEditor *gfe, GtkWidget *grid, const RemminaProtocolSetting *settings)
static void remmina_file_editor_on_save_connect(GtkWidget *button, RemminaFileEditor *gfe)
void rcw_open_from_file(RemminaFile *remminafile)
Definition: rcw.c:3892
RemminaPref remmina_pref
Definition: rcw.c:73
void remmina_file_editor_file_save(RemminaFileEditor *gfe)
gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: remmina_file.c:524
GtkWidget * remmina_file_editor_new(void)
static void remmina_file_editor_on_realize(GtkWidget *widget, gpointer user_data)
static void remmina_file_editor_button_on_toggled(GtkToggleButton *togglebutton, GtkWidget *widget)
static GtkWidget * remmina_file_editor_create_select(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gpointer *list, const gchar *value)
static void remmina_file_editor_on_cancel(GtkWidget *button, RemminaFileEditor *gfe)
RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
static void remmina_file_editor_on_save(GtkWidget *button, RemminaFileEditor *gfe)
static void remmina_file_editor_on_default(GtkWidget *button, RemminaFileEditor *gfe)
static GtkWidget * remmina_file_editor_create_combo(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *list, const gchar *value)
const gchar * name
Definition: plugin.h:63
gchar * remmina_file_manager_get_groups(void)
void remmina_file_set_string(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: remmina_file.c:423
static GtkWidget * remmina_file_editor_create_text(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value)
void remmina_file_save(RemminaFile *remminafile)
Definition: remmina_file.c:561
static void remmina_file_editor_browse_resolution(GtkWidget *button, RemminaFileEditor *gfe)
static void remmina_file_editor_ssh_tunnel_server_custom_radio_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe)
RemminaFile * remmina_file_copy(const gchar *filename)
Definition: remmina_file.c:191
RemminaFile * remmina_file_manager_load_file(const gchar *filename)
static gboolean remmina_file_editor_iterate_protocol(gchar *protocol, RemminaPlugin *plugin, gpointer data)
GtkWidget * remmina_file_editor_new_copy(const gchar *filename)
RemminaFileEditorPriv * priv
static void remmina_file_editor_browse_avahi(GtkWidget *button, RemminaFileEditor *gfe)
static void remmina_file_editor_update_settings(RemminaFileEditor *gfe)
static void remmina_file_editor_ssh_tunnel_auth_publickey_radio_on_toggled(GtkToggleButton *togglebutton, RemminaFileEditor *gfe)
static GtkWidget * remmina_file_editor_create_password(RemminaFileEditor *gfe, GtkWidget *grid, gint row, gint col, const gchar *label, const gchar *value)
void remmina_public_load_combo_text_d(GtkWidget *combo, const gchar *text, const gchar *def, const gchar *empty_choice)
static void remmina_file_editor_update_resolution(GtkWidget *widget, RemminaFileEditor *gfe)
N_("Unable to connect to VNC server")
Definition: vnc_plugin.c:907
static void remmina_file_editor_class_init(RemminaFileEditorClass *klass)
const gchar * label
Definition: types.h:97
static void remmina_file_editor_save_ssh_tunnel_tab(RemminaFileEditor *gfe)
void remmina_file_set_string_ref(RemminaFile *remminafile, const gchar *setting, gchar *value)
Definition: remmina_file.c:429
gchar * remmina_string_list_get_text(void)