Remmina - The GTK+ Remote Desktop Client  v1.4.33
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_mpchange.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-2023 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 "config.h"
40 #include "remmina_mpchange.h"
41 #include "remmina_file.h"
42 #include "remmina_file_manager.h"
43 #include "remmina_pref.h"
44 #include "remmina_public.h"
45 #include "remmina_main.h"
46 #include "remmina_plugin_manager.h"
47 #include "remmina_log.h"
49 
50 #define GET_DIALOG_OBJECT(object_name) gtk_builder_get_object(bu, object_name)
51 
53  gchar *username; // New username
54  gchar *domain; // New domain
55  gchar *password; // New password
56  gchar *group;
58  gchar *gatewaydomain;
60 
63  GtkListStore* store;
64  GtkDialog* dialog;
65  GtkTreeView* table;
66  GtkButton* btnDoChange;
67  GtkLabel* statusLabel;
68 
69  GtkTreeIter iter;
71  guint sid;
73 };
74 
75 enum {
76  COL_F = 0,
83 };
84 
85 static gboolean remmina_mpchange_fieldcompare(const gchar *needle, const gchar *haystack, int *matchcount)
86 {
87  TRACE_CALL(__func__);
88 
89  if (needle[0] == 0) {
90  (*matchcount)++;
91  return TRUE;
92  }
93 
94  if (haystack[0] == 0 || strstr(haystack, needle) == NULL){
95  return FALSE;
96  }
97 
98  (*matchcount)++;
99  return TRUE;
100 
101 }
102 
103 static void remmina_mpchange_file_list_callback(RemminaFile *remminafile, gpointer user_data)
104 {
105  TRACE_CALL(__func__);
106  GtkListStore* store;
107  GtkTreeIter iter;
108  int matchcount;
109  const gchar *username, *domain, *group, *gatewayusername, *gatewaydomain;
110 
111  gchar* s;
112  gchar* t;
113  struct mpchanger_params* mpcp;
114 
115  mpcp = (struct mpchanger_params*)user_data;
116  store = GTK_LIST_STORE(mpcp->store);
117 
118 
119  username = remmina_file_get_string(remminafile, "username");
120  domain = remmina_file_get_string(remminafile, "domain");
121  group = remmina_file_get_string(remminafile, "group");
122  gatewayusername = remmina_file_get_string(remminafile, "gateway_username");
123  gatewaydomain = remmina_file_get_string(remminafile, "gateway_domain");
124 
125  if (username == NULL)
126  username = "";
127 
128  if (domain == NULL)
129  domain = "";
130 
131  if (group == NULL)
132  group = "";
133 
134  if (gatewayusername == NULL)
135  gatewayusername = "";
136 
137  if (gatewaydomain == NULL)
138  gatewaydomain = "";
139 
140  matchcount = 0;
141  if (!remmina_mpchange_fieldcompare(mpcp->username, username, &matchcount))
142  return;
143  if (!remmina_mpchange_fieldcompare(mpcp->domain, domain, &matchcount))
144  return;
145  if (!remmina_mpchange_fieldcompare(mpcp->group, group, &matchcount))
146  return;
147  if (!remmina_mpchange_fieldcompare(mpcp->gatewayusername, gatewayusername, &matchcount))
148  return;
149  if (!remmina_mpchange_fieldcompare(mpcp->gatewaydomain, gatewaydomain, &matchcount))
150  return;
151 
152  gtk_list_store_append(store, &iter);
153  s = g_strdup_printf("%s\\%s", domain, username);
154  t = g_strdup_printf("%s\\%s", gatewaydomain, gatewayusername);
155  gtk_list_store_set(store, &iter,
156  COL_F, matchcount >= 5 ? TRUE : FALSE,
157  COL_NAME, remmina_file_get_string(remminafile, "name"),
158  COL_GROUP, group,
159  COL_USERNAME, s,
161  COL_FILENAME, remminafile->filename,
162  -1);
163  g_free(s);
164  g_free(t);
165 
166 }
167 
168 static void remmina_mpchange_checkbox_toggle(GtkCellRendererToggle *cell, gchar *path_string, gpointer user_data)
169 {
170  TRACE_CALL(__func__);
171  GtkTreeIter iter;
172  struct mpchanger_params* mpcp = (struct mpchanger_params*)user_data;
173  GtkTreePath *path;
174 
175  gboolean a = gtk_cell_renderer_toggle_get_active(cell);
176  path = gtk_tree_path_new_from_string(path_string);
177  gtk_tree_model_get_iter(GTK_TREE_MODEL(mpcp->store), &iter, path);
178  gtk_tree_path_free(path);
179  gtk_list_store_set(mpcp->store, &iter, COL_F, !a, -1);
180 }
181 
182 static void remmina_mpchange_dochange(gchar* fname, struct mpchanger_params* mpcp)
183 {
184  TRACE_CALL(__func__);
185 
186  RemminaFile* remminafile;
187 
188  remminafile = remmina_file_load(fname);
189  if (remminafile) {
190  if(mpcp->password[0] != 0){
191  remmina_file_store_secret_plugin_password(remminafile, "password", mpcp->password);
192  }
193  if(mpcp->gatewaypassword[0] != 0){
194  remmina_file_store_secret_plugin_password(remminafile, "gateway_password", mpcp->gatewaypassword);
195  }
196  remmina_file_free(remminafile);
197  mpcp->changed_passwords_count++;
198  }
199 
200 }
201 
202 static void enable_inputs(struct mpchanger_params* mpcp, gboolean ena)
203 {
204  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eGroup), ena);
205  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eUsername), ena);
206  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eDomain), ena);
207  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->ePassword1), ena);
208  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->ePassword2), ena);
209  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eGatewayUsername), ena);
210  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eGatewayDomain), ena);
211  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eGatewayPassword1), ena);
212  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->eGatewayPassword2), ena);
213  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->btnDoChange), ena);
214  gtk_widget_set_sensitive(GTK_WIDGET(mpcp->table), ena);
215 }
216 
217 static gboolean changenext(gpointer user_data)
218 {
219  TRACE_CALL(__func__);
220  struct mpchanger_params* mpcp = (struct mpchanger_params*)user_data;
221  gchar* fname;
222  gboolean sel;
223 
224  gtk_tree_model_get(GTK_TREE_MODEL(mpcp->store), &mpcp->iter, COL_F, &sel, -1);
225  gtk_tree_model_get(GTK_TREE_MODEL(mpcp->store), &mpcp->iter, COL_FILENAME, &fname, -1);
226  if (sel) {
227  remmina_mpchange_dochange(fname, mpcp);
228  }
229  g_free(fname);
230 
231  if (gtk_tree_model_iter_next(GTK_TREE_MODEL(mpcp->store), &mpcp->iter)) {
232  return G_SOURCE_CONTINUE;
233  }else {
234  gtk_dialog_response(mpcp->dialog, 1);
235  mpcp->sid = 0;
236  return G_SOURCE_REMOVE;
237  }
238 }
239 
240 static void remmina_mpchange_dochange_clicked(GtkButton *btn, gpointer user_data)
241 {
242  TRACE_CALL(__func__);
243  struct mpchanger_params* mpcp = (struct mpchanger_params*)user_data;
244  const gchar *passwd1, *passwd2, *gatewaypasswd1, *gatewaypasswd2;
245 
247  g_source_remove(mpcp->searchentrychange_timeout_source_id);
249  }
250 
251  if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mpcp->store), &mpcp->iter))
252  return;
253 
254  passwd1 = gtk_entry_get_text(mpcp->ePassword1);
255  passwd2 = gtk_entry_get_text(mpcp->ePassword2);
256 
257  if (g_strcmp0(passwd1, passwd2) != 0) {
258  GtkWidget *msgDialog;
259  msgDialog = gtk_message_dialog_new(GTK_WINDOW(mpcp->dialog),
260  GTK_DIALOG_DESTROY_WITH_PARENT,
261  GTK_MESSAGE_ERROR,
262  GTK_BUTTONS_CLOSE,
263  _("The passwords do not match"));
264  gtk_dialog_run(GTK_DIALOG(msgDialog));
265  gtk_widget_destroy(msgDialog);
266  return;
267  }
268  gatewaypasswd1 = gtk_entry_get_text(mpcp->eGatewayPassword1);
269  gatewaypasswd2 = gtk_entry_get_text(mpcp->eGatewayPassword2);
270  if (g_strcmp0(gatewaypasswd1, gatewaypasswd2) != 0) {
271  GtkWidget *msgDialog;
272  msgDialog = gtk_message_dialog_new(GTK_WINDOW(mpcp->dialog),
273  GTK_DIALOG_DESTROY_WITH_PARENT,
274  GTK_MESSAGE_ERROR,
275  GTK_BUTTONS_CLOSE,
276  _("The Gateway passwords do not match"));
277  gtk_dialog_run(GTK_DIALOG(msgDialog));
278  gtk_widget_destroy(msgDialog);
279  return;
280  }
281 
282  g_free(mpcp->password);
283  mpcp->password = g_strdup(passwd1);
284  mpcp->changed_passwords_count = 0;
285 
286  g_free(mpcp->gatewaypassword);
287  mpcp->gatewaypassword = g_strdup(gatewaypasswd1);
288  mpcp->changed_passwords_count = 0;
289 
290  gtk_label_set_text(mpcp->statusLabel, _("Resetting passwords, please wait…"));
291 
292  enable_inputs(mpcp, FALSE);
293  mpcp->sid = g_idle_add(changenext, (gpointer)mpcp);
294 
295 }
296 
297 static gboolean remmina_mpchange_searchfield_changed_to(gpointer user_data)
298 {
299  TRACE_CALL(__func__);
300  struct mpchanger_params *mpcp = (struct mpchanger_params *)user_data;
301  const gchar *s;
302 
304  g_source_remove(mpcp->searchentrychange_timeout_source_id);
306  }
307 
308  s = gtk_entry_get_text(mpcp->eGroup);
309  g_free(mpcp->group);
310  mpcp->group = g_strdup(s);
311 
312  s = gtk_entry_get_text(mpcp->eDomain);
313  g_free(mpcp->domain);
314  mpcp->domain = g_strdup(s);
315 
316  s = gtk_entry_get_text(mpcp->eUsername);
317  g_free(mpcp->username);
318  mpcp->username = g_strdup(s);
319 
320  s = gtk_entry_get_text(mpcp->eGatewayDomain);
321  g_free(mpcp->gatewaydomain);
322  mpcp->gatewaydomain = g_strdup(s);
323 
324  s = gtk_entry_get_text(mpcp->eGatewayUsername);
325  g_free(mpcp->gatewayusername);
326  mpcp->gatewayusername = g_strdup(s);
327 
328  if (mpcp->store != NULL) {
329  gtk_tree_view_set_model(mpcp->table, NULL);
330  }
331  mpcp->store = gtk_list_store_new(NUM_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
332 
333  if (mpcp->group[0] != 0 || mpcp->domain[0] != 0 || mpcp->username[0] != 0 || mpcp->gatewayusername[0] != 0 || mpcp->gatewaydomain[0] != 0)
335 
336  gtk_tree_view_set_model(mpcp->table, GTK_TREE_MODEL(mpcp->store));
337 
338  return G_SOURCE_CONTINUE; // Source already remove at the beginning
339 
340 }
341 
342 static void remmina_mpchange_searchfield_changed(GtkSearchEntry *se, gpointer user_data)
343 {
344  TRACE_CALL(__func__);
345  struct mpchanger_params *mpcp = (struct mpchanger_params *)user_data;
346 
348  g_source_remove(mpcp->searchentrychange_timeout_source_id);
350  }
351 
353 }
354 
355 
356 static void remmina_mpchange_stopsearch(GtkSearchEntry *entry, gpointer user_data)
357 {
358  TRACE_CALL(__func__);
359  /* The stop-search signal is emitted when pressing Esc on a GtkSearchEntry. We end the dialog. */
360  struct mpchanger_params *mpcp = (struct mpchanger_params *)user_data;
361  gtk_dialog_response(mpcp->dialog, 1);
362 }
363 
364 static gboolean remmina_file_multipasswd_changer_mt(gpointer d)
365 {
366  TRACE_CALL(__func__);
367  struct mpchanger_params *mpcp = d;
368  GtkBuilder* bu;
369  GtkDialog* dialog;
370  GtkWindow* mainwindow;
371  GtkCellRendererToggle *toggle;
372  RemminaSecretPlugin *secret_plugin;
373  char *initerror;
374 
375  mainwindow = remmina_main_get_window();
376 
377  /* The multiple password changer works only when a secrecy plugin is available */
378  initerror = NULL;
380  if (secret_plugin == NULL) {
381  initerror = _("The multi password changer requires a secrecy plugin.\n");
382  }else {
383  if (!secret_plugin->is_service_available(secret_plugin)) {
384  initerror = _("The multi password changer requires a secrecy service.\n");
385  }
386  }
387  if (initerror) {
388  GtkWidget *msgDialog;
389  msgDialog = gtk_message_dialog_new(mainwindow, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
390  "%s", initerror);
391  gtk_dialog_run(GTK_DIALOG(msgDialog));
392  gtk_widget_destroy(msgDialog);
393  return FALSE;
394  }
395 
396 
397  bu = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_mpc.glade");
398  if (!bu) {
399  REMMINA_DEBUG("Unable to load the multiple password changer Glade file interface\n");
400  return FALSE;
401  }
402 
403  dialog = GTK_DIALOG(gtk_builder_get_object(bu, "MPCDialog"));
404  mpcp->dialog = dialog;
405  if (mainwindow)
406  gtk_window_set_transient_for(GTK_WINDOW(dialog), mainwindow);
407 
408 
409  mpcp->eGroup = GTK_ENTRY(GET_DIALOG_OBJECT("groupEntry"));
410  gtk_entry_set_text(mpcp->eGroup, mpcp->group);
411  g_signal_connect(G_OBJECT(mpcp->eGroup), "changed", G_CALLBACK(remmina_mpchange_searchfield_changed), (gpointer)mpcp);
412  g_signal_connect(G_OBJECT(mpcp->eGroup), "stop-search", G_CALLBACK(remmina_mpchange_stopsearch), (gpointer)mpcp);
413 
414  mpcp->eUsername = GTK_ENTRY(GET_DIALOG_OBJECT("usernameEntry"));
415  gtk_entry_set_text(mpcp->eUsername, mpcp->username);
416  g_signal_connect(G_OBJECT(mpcp->eUsername), "changed", G_CALLBACK(remmina_mpchange_searchfield_changed), (gpointer)mpcp);
417 
418  mpcp->eGatewayUsername = GTK_ENTRY(GET_DIALOG_OBJECT("gatewayUsernameEntry"));
419  gtk_entry_set_text(mpcp->eGatewayUsername, mpcp->gatewayusername);
420  g_signal_connect(G_OBJECT(mpcp->eGatewayUsername), "changed", G_CALLBACK(remmina_mpchange_searchfield_changed), (gpointer)mpcp);
421 
422  mpcp->eDomain = GTK_ENTRY(GET_DIALOG_OBJECT("domainEntry"));
423  gtk_entry_set_text(mpcp->eDomain, mpcp->domain);
424  g_signal_connect(G_OBJECT(mpcp->eDomain), "changed", G_CALLBACK(remmina_mpchange_searchfield_changed), (gpointer)mpcp);
425 
426  mpcp->eGatewayDomain = GTK_ENTRY(GET_DIALOG_OBJECT("gatewayDomainEntry"));
427  gtk_entry_set_text(mpcp->eGatewayDomain, mpcp->gatewaydomain);
428  g_signal_connect(G_OBJECT(mpcp->eGatewayDomain), "changed", G_CALLBACK(remmina_mpchange_searchfield_changed), (gpointer)mpcp);
429 
430  mpcp->ePassword1 = GTK_ENTRY(GET_DIALOG_OBJECT("password1Entry"));
431  gtk_entry_set_text(mpcp->ePassword1, mpcp->password);
432 
433  mpcp->eGatewayPassword1 = GTK_ENTRY(GET_DIALOG_OBJECT("gatewayPassword1Entry"));
434  gtk_entry_set_text(mpcp->eGatewayPassword1, mpcp->gatewaypassword);
435 
436  mpcp->ePassword2 = GTK_ENTRY(GET_DIALOG_OBJECT("password2Entry"));
437  gtk_entry_set_text(mpcp->ePassword2, mpcp->password);
438 
439  mpcp->eGatewayPassword2 = GTK_ENTRY(GET_DIALOG_OBJECT("gatewayPassword2Entry"));
440  gtk_entry_set_text(mpcp->eGatewayPassword2, mpcp->gatewaypassword);
441 
442  mpcp->statusLabel = GTK_LABEL(GET_DIALOG_OBJECT("statusLabel"));
443 
444 
445 
446 
447  mpcp->store = NULL;
448 
449  mpcp->table = GTK_TREE_VIEW(GET_DIALOG_OBJECT("profchangelist"));
450 
451  /* Fire a fake searchfield changed, so a new list store is created */
452  remmina_mpchange_searchfield_changed(NULL, (gpointer)mpcp);
453 
454  toggle = GTK_CELL_RENDERER_TOGGLE(GET_DIALOG_OBJECT("cellrenderertoggle1"));
455  g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(remmina_mpchange_checkbox_toggle), (gpointer)mpcp);
456 
457  mpcp->btnDoChange = GTK_BUTTON(GET_DIALOG_OBJECT("btnDoChange"));
458  g_signal_connect(mpcp->btnDoChange, "clicked", G_CALLBACK(remmina_mpchange_dochange_clicked), (gpointer)mpcp);
459 
460  gtk_dialog_run(dialog);
461  gtk_widget_destroy(GTK_WIDGET(dialog));
462 
463  if (mpcp->sid) {
464  g_source_remove(mpcp->sid);
465  mpcp->sid = 0;
466  }
467 
468  if (mpcp->searchentrychange_timeout_source_id) {
469  g_source_remove(mpcp->searchentrychange_timeout_source_id);
470  mpcp->searchentrychange_timeout_source_id = 0;
471  }
472 
473  if (mpcp->changed_passwords_count) {
474  GtkWidget *msgDialog;
475  msgDialog = gtk_message_dialog_new(GTK_WINDOW(mpcp->dialog),
476  GTK_DIALOG_DESTROY_WITH_PARENT,
477  GTK_MESSAGE_INFO,
478  GTK_BUTTONS_OK,
479  ngettext("%d password changed.", "%d passwords changed.", mpcp->changed_passwords_count), mpcp->changed_passwords_count);
480  gtk_dialog_run(GTK_DIALOG(msgDialog));
481  gtk_widget_destroy(msgDialog);
482  }
483 
484  // Free data
485  g_free(mpcp->username);
486  g_free(mpcp->password);
487  g_free(mpcp->domain);
488  g_free(mpcp->group);
489  g_free(mpcp->gatewayusername);
490  g_free(mpcp->gatewaypassword);
491  g_free(mpcp->gatewaydomain);
492  g_free(mpcp);
493  return FALSE;
494 }
495 
496 
497 void
498 remmina_mpchange_schedule(gboolean has_domain, const gchar *group, const gchar *domain, const gchar *username, const gchar *password, const gchar *gatewayusername, const gchar *gatewaydomain, const gchar *gatewaypassword)
499 {
500  // We could also be called in a subthread after a successful connection
501  // (not currently implemented)
502  // So we just schedule the multipassword changer to be executed on
503  // the main thread
504 
505  TRACE_CALL(__func__);
506  struct mpchanger_params *mpcp;
507 
508  mpcp = g_malloc0(sizeof(struct mpchanger_params));
509  mpcp->username = g_strdup(username);
510  mpcp->password = g_strdup(password);
511  mpcp->domain = g_strdup(domain);
512  mpcp->group = g_strdup(group);
513  mpcp->gatewayusername = g_strdup(gatewayusername);
514  mpcp->gatewaypassword = g_strdup(gatewaypassword);
515  mpcp->gatewaydomain = g_strdup(gatewaydomain);
516  gdk_threads_add_idle(remmina_file_multipasswd_changer_mt, (gpointer)mpcp);
517 
518 }
GtkButton * btnDoChange
RemminaFile * remmina_file_load(const gchar *filename)
Definition: remmina_file.c:350
void remmina_file_free(RemminaFile *remminafile)
Definition: remmina_file.c:709
const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:516
guint searchentrychange_timeout_source_id
static void remmina_mpchange_stopsearch(GtkSearchEntry *entry, gpointer user_data)
GtkWindow * remmina_main_get_window()
GtkEntry * eGatewayPassword2
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
GtkDialog * dialog
RemminaSecretPlugin * remmina_plugin_manager_get_secret_plugin(void)
GtkEntry * ePassword1
gboolean(* is_service_available)(struct _RemminaSecretPlugin *instance)
Definition: plugin.h:144
GtkLabel * statusLabel
static gboolean remmina_mpchange_fieldcompare(const gchar *needle, const gchar *haystack, int *matchcount)
static void remmina_mpchange_file_list_callback(RemminaFile *remminafile, gpointer user_data)
static void remmina_mpchange_searchfield_changed(GtkSearchEntry *se, gpointer user_data)
GtkTreeView * table
static gboolean remmina_file_multipasswd_changer_mt(gpointer d)
GtkEntry * eUsername
GtkEntry * eGatewayDomain
static gboolean remmina_mpchange_searchfield_changed_to(gpointer user_data)
static void enable_inputs(struct mpchanger_params *mpcp, gboolean ena)
GtkBuilder * remmina_public_gtk_builder_new_from_resource(gchar *resource)
static void remmina_mpchange_dochange(gchar *fname, struct mpchanger_params *mpcp)
void remmina_file_store_secret_plugin_password(RemminaFile *remminafile, const gchar *key, const gchar *value)
Definition: remmina_file.c:846
GtkListStore * store
static void remmina_mpchange_dochange_clicked(GtkButton *btn, gpointer user_data)
GtkEntry * eGatewayPassword1
GtkEntry * eGatewayUsername
static void remmina_mpchange_checkbox_toggle(GtkCellRendererToggle *cell, gchar *path_string, gpointer user_data)
void remmina_mpchange_schedule(gboolean has_domain, const gchar *group, const gchar *domain, const gchar *username, const gchar *password, const gchar *gatewayusername, const gchar *gatewaydomain, const gchar *gatewaypassword)
static gboolean changenext(gpointer user_data)
GtkEntry * ePassword2
gint remmina_file_manager_iterate(GFunc func, gpointer user_data)