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_ext_exec.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2009-2010 Vic Lee
4  * Copyright (C) 2014-2023 Antenore Gatta, Giovanni Panozzo
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * In addition, as a special exception, the copyright holders give
22  * permission to link the code of portions of this program with the
23  * OpenSSL library under certain conditions as described in each
24  * individual source file, and distribute linked combinations
25  * including the two.
26  * You must obey the GNU General Public License in all respects
27  * for all of the code used other than OpenSSL. * If you modify
28  * file(s) with this exception, you may extend this exception to your
29  * version of the file(s), but you are not obligated to do so. * If you
30  * do not wish to do so, delete this exception statement from your
31  * version. * If you delete this exception statement from all source
32  * files in the program, then also delete it here.
33  *
34  */
35 
36 #include <gdk/gdkkeysyms.h>
37 #include <glib/gi18n.h>
38 #include <glib.h>
39 #include <stdlib.h>
40 #include <sys/wait.h>
41 #include <unistd.h>
42 #include "remmina_utils.h"
43 #include "remmina_ext_exec.h"
44 #include "remmina_public.h"
46 
47 #define SPAWN_TIMEOUT 10
48 
49 #define GET_OBJECT(object_name) gtk_builder_get_object(builder, object_name)
50 
51 static void wait_for_child(GPid pid, gint script_retval, gpointer data)
52 {
53  PCon_Spinner *pcspinner = (PCon_Spinner*)data;
54 
55  gtk_spinner_stop(GTK_SPINNER(pcspinner->spinner));
56  gtk_widget_destroy(GTK_WIDGET(pcspinner->dialog));
57  g_spawn_close_pid(pid);
58  /* TODO At the moment background processes will fail to start before the
59  * remmina connection.
60  * Adding a delay here could be a (not good) solution, or we should
61  * monitor each child opened, but it could be quit tricky and messy */
62 }
63 
64 GtkDialog* remmina_ext_exec_new(RemminaFile* remminafile, const char *remmina_ext_exec_type)
65 {
66  TRACE_CALL(__func__);
67  GtkBuilder *builder;
68  PCon_Spinner *pcspinner;
69  GError *error = NULL;
70  char **argv;
71  gchar *cmd = NULL;
72  gchar pre[11];
73  gchar post[12];
74  GPid child_pid;
75 
76  strcpy(pre, "precommand");
77  strcpy(post, "postcommand");
78 
79  if (remmina_ext_exec_type != NULL && (
80  strcmp(remmina_ext_exec_type, pre) |
81  strcmp(remmina_ext_exec_type, post) )) {
82  cmd = g_strdup(remmina_file_get_string(remminafile, remmina_ext_exec_type));
83  g_debug("[%s] %s", remmina_ext_exec_type, cmd);
84  } else
85  return FALSE;
86 
87  cmd = remmina_file_format_properties(remminafile, cmd);
88  g_debug("[%s] updated to: %s", remmina_ext_exec_type, cmd);
89  if (*cmd != 0) {
90 
91  pcspinner = g_new(PCon_Spinner, 1);
92  builder = remmina_public_gtk_builder_new_from_resource("/org/remmina/Remmina/src/../data/ui/remmina_spinner.glade");
93  pcspinner->dialog = GTK_DIALOG(gtk_builder_get_object(builder, "DialogSpinner"));
94  pcspinner->label_pleasewait = GTK_LABEL(GET_OBJECT("label_pleasewait"));
95  pcspinner->spinner = GTK_WIDGET(GET_OBJECT("spinner"));
96  pcspinner->button_cancel = GTK_BUTTON(GET_OBJECT("button_cancel"));
97  /* Connect signals */
98  gtk_builder_connect_signals(builder, NULL);
99 
100  /* Exec a predefined command */
101  g_shell_parse_argv(cmd, NULL, &argv, &error);
102 
103  if (error) {
104  g_warning("%s\n", error->message);
105  g_error_free(error);
106  }
107 
108  /* Consider using G_SPAWN_SEARCH_PATH_FROM_ENVP (from glib 2.38)*/
109  g_spawn_async( NULL, // cwd
110  argv, // argv
111  NULL, // envp
112  G_SPAWN_SEARCH_PATH |
113  G_SPAWN_SEARCH_PATH_FROM_ENVP |
114  G_SPAWN_DO_NOT_REAP_CHILD, // flags
115  NULL, // child_setup
116  NULL, // child_setup user data
117  &child_pid, // pid location
118  &error); // error
119  if (!error) {
120  gtk_spinner_start(GTK_SPINNER(pcspinner->spinner));
121  g_child_watch_add(child_pid, wait_for_child, (gpointer)pcspinner);
122  gtk_dialog_run(pcspinner->dialog);
123  }else {
124  g_warning("Command %s exited with error: %s\n", cmd, error->message);
125  g_error_free(error);
126  }
127  g_strfreev(argv);
128  g_free(cmd);
129  return (pcspinner->dialog);
130  }
131  g_free(cmd);
132  return FALSE;
133 }
const gchar * remmina_file_get_string(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:516
typedefG_BEGIN_DECLS struct _RemminaFile RemminaFile
Definition: types.h:44
gchar * remmina_file_format_properties(RemminaFile *remminafile, const gchar *setting)
Definition: remmina_file.c:561
GtkDialog * remmina_ext_exec_new(RemminaFile *remminafile, const char *remmina_ext_exec_type)
General utility functions, non-GTK related.
static void wait_for_child(GPid pid, gint script_retval, gpointer data)
GtkDialog * dialog
GtkButton * button_cancel
GtkBuilder * remmina_public_gtk_builder_new_from_resource(gchar *resource)
GtkWidget * spinner
GtkLabel * label_pleasewait