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_exec.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2010 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 "config.h"
38 #include "buildflags.h"
39 #include <gtk/gtk.h>
40 #include <glib/gi18n.h>
41 #include <stdlib.h>
42 #include "remmina.h"
43 #include "remmina_main.h"
44 #include "remmina_log.h"
45 #include "remmina_pref.h"
46 #include "remmina_widget_pool.h"
47 #include "remmina_unlock.h"
48 #include "remmina_pref_dialog.h"
49 #include "remmina_file.h"
50 #include "remmina_file_manager.h"
51 #include "remmina_file_editor.h"
52 #include "rcw.h"
53 #include "remmina_about.h"
54 #include "remmina_plugin_manager.h"
55 #include "remmina_exec.h"
56 #include "remmina_icon.h"
58 #include "remmina_file_manager.h"
59 
60 #ifdef SNAP_BUILD
61 # define ISSNAP "- SNAP Build -"
62 #else
63 # define ISSNAP "-"
64 #endif
65 
66 static gboolean cb_closewidget(GtkWidget *widget, gpointer data)
67 {
68  TRACE_CALL(__func__);
69  /* The correct way to close a rcw is to send
70  * it a "delete-event" signal. Simply destroying it will not close
71  * all network connections */
72  if (REMMINA_IS_CONNECTION_WINDOW(widget))
73  return rcw_delete(RCW(widget));
74  return TRUE;
75 }
76 
78 {
79  static const gchar build_config[] =
80  "Build configuration: " BUILD_CONFIG "\n"
81  "Build type: " BUILD_TYPE "\n"
82  "CFLAGS: " CFLAGS "\n"
83  "Compiler: " COMPILER_ID ", " COMPILER_VERSION "\n"
84  "Target architecture: " TARGET_ARCH "\n";
85  return build_config;
86 }
87 
89 {
90  TRACE_CALL(__func__);
91 
92  /* Save main window state/position */
94 
95  /* Delete all widgets, main window not included */
97 
98  /* Remove systray menu */
100 
101  /* Exit from Remmina */
102  g_application_quit(g_application_get_default());
103 }
104 
105 static gboolean disable_rcw_delete_confirm_cb(GtkWidget *widget, gpointer data)
106 {
107  TRACE_CALL(__func__);
109 
110  if (REMMINA_IS_CONNECTION_WINDOW(widget)) {
111  rcw = (RemminaConnectionWindow*)widget;
113  }
114  return TRUE;
115 }
116 
118 {
119  TRACE_CALL(__func__);
120 
121  /* Exit remmina only if there are no interesting windows left:
122  * no main window, no systray menu, no connection window.
123  * This function is usually called after a disconnection */
124 
125  switch (why) {
127  // A connection has disconnected, should we exit remmina ?
130  break;
132  /* If we are in Kiosk mode, we just exit */
133  if (kioskmode && kioskmode == TRUE)
135  // Main window has been deleted
138  break;
140  // Quit command has been sent from main window or appindicator/systray menu
141  // quit means QUIT.
144  break;
145  }
146 }
147 
148 
149 static void newline_remove(char *s)
150 {
151  char c;
152  while((c = *s) != 0 && c != '\r' && c != '\n')
153  s++;
154  *s = 0;
155 }
156 
157 /* used for commandline parameter --update-profile X --set-option Y --set-option Z
158  * return a status code for exit()
159  */
160 int remmina_exec_set_setting(gchar *profilefilename, gchar **settings)
161 {
162  RemminaFile *remminafile;
163  int i;
164  gchar **tk, *value;
165  char *line = NULL;
166  size_t len = 0;
167  ssize_t read;
168  gboolean abort = FALSE;
169 
170  remminafile = remmina_file_manager_load_file(profilefilename);
171 
172  if (!remminafile) {
173  g_print("Unable to open profile file %s\n", profilefilename);
174  return 2;
175  }
176 
177  for(i = 0; settings[i] != NULL && !abort; i++) {
178  if (strlen(settings[i]) > 0) {
179  tk = g_strsplit(settings[i], "=", 2);
180  if (tk[1] == NULL) {
181  read = getline(&line, &len, stdin);
182  if (read > 0) {
183  newline_remove(line);
184  value = line;
185  } else {
186  g_print("Error: an extra line of standard input is needed\n");
187  abort = TRUE;
188  }
189  } else
190  value = tk[1];
191  remmina_file_set_string(remminafile, tk[0], value);
192  g_strfreev(tk);
193  }
194  }
195 
196  if (line) free(line);
197 
198  if (!abort) remmina_file_save(remminafile);
199 
200  return 0;
201 
202 }
203 
204 static void remmina_exec_autostart_cb(RemminaFile *remminafile, gpointer user_data)
205 {
206  TRACE_CALL(__func__);
207 
208  if (remmina_file_get_int(remminafile, "enable-autostart", FALSE)) {
209  remmina_debug ("Profile %s is set to autostart", remminafile->filename);
210  rcw_open_from_filename(remminafile->filename);
211  }
212 
213 }
214 void remmina_exec_command(RemminaCommandType command, const gchar* data)
215 {
216  TRACE_CALL(__func__);
217  gchar* s1;
218  gchar* s2;
219  GtkWidget* widget;
220  GtkWindow* mainwindow;
221  GtkDialog* prefdialog;
222  RemminaEntryPlugin* plugin;
223 
224  mainwindow = remmina_main_get_window();
225 
226  switch (command) {
229  break;
230 
232  if (mainwindow) {
233  gtk_window_present(mainwindow);
234  gtk_window_deiconify(GTK_WINDOW(mainwindow));
235  }else {
236  widget = remmina_main_new();
237  gtk_widget_show(widget);
238  }
239  break;
240 
242  if (remmina_unlock_new(mainwindow) == 0)
243  break;
244  prefdialog = remmina_pref_dialog_get_dialog();
245  if (prefdialog) {
246  gtk_window_present(GTK_WINDOW(prefdialog));
247  gtk_window_deiconify(GTK_WINDOW(prefdialog));
248  }else {
249  /* Create a new preference dialog */
250  widget = GTK_WIDGET(remmina_pref_dialog_new(atoi(data), NULL));
251  gtk_widget_show(widget);
252  }
253  break;
254 
255  case REMMINA_COMMAND_NEW:
256  s1 = (data ? strchr(data, ',') : NULL);
257  if (s1) {
258  s1 = g_strdup(data);
259  s2 = strchr(s1, ',');
260  *s2++ = '\0';
261  widget = remmina_file_editor_new_full(s2, s1);
262  g_free(s1);
263  }else {
264  widget = remmina_file_editor_new_full(NULL, data);
265  }
266  gtk_widget_show(widget);
267  break;
268 
275  break;
276 
279  if (widget)
280  gtk_widget_show(widget);
281  break;
282 
284  remmina_about_open(NULL);
285  break;
286 
288  mainwindow = remmina_main_get_window();
289  if (mainwindow) {
290  remmina_about_open(NULL);
291  }else {
292  g_print("%s %s %s (git %s)\n", g_get_application_name(), ISSNAP, VERSION, REMMINA_GIT_REVISION);
293  /* As we do not use the "handle-local-options" signal, we have to exit Remmina */
295  }
296 
297  break;
298 
300  mainwindow = remmina_main_get_window();
301  if (mainwindow) {
302  /* Show th widget with the list of plugins and versions */
303  remmina_plugin_manager_show(mainwindow);
304  }else {
305  g_print("\n%s %s %s (git %s)\n\n", g_get_application_name(), ISSNAP, VERSION, REMMINA_GIT_REVISION);
306 
308  g_print("\n%s\n", remmina_exec_get_build_config());
310  }
311 
312  break;
313 
314 
317  if (plugin) {
318  plugin->entry_func();
319  }else {
320  widget = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
321  _("Plugin %s is not registered."), data);
322  g_signal_connect(G_OBJECT(widget), "response", G_CALLBACK(gtk_widget_destroy), NULL);
323  gtk_widget_show(widget);
325  }
326  break;
327 
331  break;
332 
333  default:
334  break;
335  }
336 }
337 
int remmina_exec_set_setting(gchar *profilefilename, gchar **settings)
Definition: remmina_exec.c:160
RemminaCondExitType
Definition: remmina_exec.h:55
GtkWindow * remmina_main_get_window()
void(* entry_func)(void)
Definition: plugin.h:91
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:41
void remmina_widget_pool_register(GtkWidget *widget)
gboolean rcw_delete(RemminaConnectionWindow *cnnwin)
Definition: rcw.c:624
gboolean remmina_icon_is_available(void)
Determine whenever the Remmina icon is available.
Definition: remmina_icon.c:376
GtkWidget * remmina_file_editor_new_full(const gchar *server, const gchar *protocol)
GtkWidget * remmina_main_new(void)
void remmina_main_save_before_destroy()
Save the Remmina Main Window size and the exapnded group before to close Remmina. ...
Definition: remmina_main.c:172
const gchar * remmina_exec_get_build_config(void)
Definition: remmina_exec.c:77
Definition: plugin.h:84
void remmina_debug(const gchar *fmt,...)
Print a string in the Remmina Debug Windows and in the terminal.
Definition: remmina_log.c:194
void remmina_plugin_manager_show(GtkWindow *parent)
static void remmina_exec_autostart_cb(RemminaFile *remminafile, gpointer user_data)
Definition: remmina_exec.c:204
void remmina_icon_destroy(void)
Definition: remmina_icon.c:74
gint remmina_widget_pool_count()
void rcw_set_delete_confirm_mode(RemminaConnectionWindow *cnnwin, RemminaConnectionWindowOnDeleteConfirmMode mode)
Definition: rcw.c:4050
void remmina_exec_command(RemminaCommandType command, const gchar *data)
Definition: remmina_exec.c:214
void remmina_exec_exitremmina()
Definition: remmina_exec.c:88
GtkWidget * remmina_file_editor_new_from_filename(const gchar *filename)
gint remmina_file_get_int(RemminaFile *remminafile, const gchar *setting, gint default_value)
Definition: remmina_file.c:524
void remmina_about_open(GtkWindow *parent)
Definition: remmina_about.c:45
RemminaPlugin * remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
GtkDialog * remmina_pref_dialog_get_dialog()
gboolean rcw_open_from_filename(const gchar *filename)
Definition: rcw.c:3847
static gboolean cb_closewidget(GtkWidget *widget, gpointer data)
Definition: remmina_exec.c:66
gboolean kioskmode
Definition: remmina.c:79
void remmina_application_condexit(RemminaCondExitType why)
Definition: remmina_exec.c:117
static gboolean disable_rcw_delete_confirm_cb(GtkWidget *widget, gpointer data)
Definition: remmina_exec.c:105
GtkDialog * remmina_pref_dialog_new(gint default_tab, GtkWindow *parent)
void remmina_file_set_string(RemminaFile *remminafile, const gchar *setting, const gchar *value)
Definition: remmina_file.c:423
void remmina_file_save(RemminaFile *remminafile)
Definition: remmina_file.c:561
RemminaFile * remmina_file_manager_load_file(const gchar *filename)
static void newline_remove(char *s)
Definition: remmina_exec.c:149
gint remmina_unlock_new(GtkWindow *parent)
void remmina_plugin_manager_show_stdout()
RemminaCommandType
Definition: remmina_exec.h:40
gint remmina_widget_pool_foreach(RemminaWidgetPoolForEachFunc callback, gpointer data)
gint remmina_file_manager_iterate(GFunc func, gpointer user_data)