Remmina - The GTK+ Remote Desktop Client  v1.4.25
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_plugin_python_module.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2014-2022 Antenore Gatta, Giovanni Panozzo
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * In addition, as a special exception, the copyright holders give
21  * permission to link the code of portions of this program with the
22  * OpenSSL library under certain conditions as described in each
23  * individual source file, and distribute linked combinations
24  * including the two.
25  * You must obey the GNU General Public License in all respects
26  * for all of the code used other than OpenSSL. * If you modify
27  * file(s) with this exception, you may extend this exception to your
28  * version of the file(s), but you are not obligated to do so. * If you
29  * do not wish to do so, delete this exception statement from your
30  * version. * If you delete this exception statement from all source
31  * files in the program, then also delete it here.
32  *
33  */
34 
49 #include <glib.h>
50 #include <gtk/gtk.h>
51 #define PY_SSIZE_T_CLEAN
52 #include <Python.h>
53 #include <structmember.h>
54 
55 #include "config.h"
56 #include "remmina_plugin_manager.h"
58 #include "remmina/plugin.h"
60 
69 {
70  TRACE_CALL(__func__);
72  py_plugin->gp->gp = gp;
73  PyObject_CallMethod(py_plugin, "init", "O", py_plugin->gp);
74 }
75 
83 {
84  TRACE_CALL(__func__);
87  PyObject* result = PyObject_CallMethod(py_plugin, "open_connection", "O", py_plugin->gp);
88  return result == Py_True;
89 }
90 
98 {
99  TRACE_CALL(__func__);
101  PyObject* result = PyObject_CallMethod(py_plugin, "close_connection", "O", py_plugin->gp);
102  return result == Py_True;
103 }
104 
112 {
113  TRACE_CALL(__func__);
115  PyObject* result = PyObject_CallMethod(py_plugin, "query_feature", "O", py_plugin->gp);
116  return result == Py_True;
117 }
118 
126 {
127  TRACE_CALL(__func__);
129  PyObject* result = PyObject_CallMethod(py_plugin, "call_feature", "O", py_plugin->gp);
130 }
131 
138 static void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
139 {
140  TRACE_CALL(__func__);
142  PyObject* result = PyObject_CallMethod(py_plugin, "send_keystrokes", "O", py_plugin->gp);
143 }
144 
152 {
153  TRACE_CALL(__func__);
155  PyObject* result = PyObject_CallMethod(py_plugin, "get_plugin_screenshot", "O", py_plugin->gp);
156  return result == Py_True;
157 }
158 
159 
160 static long GetEnumOrDefault(PyObject* instance, gchar* constant_name, long def) {
161  PyObject* attr = PyObject_GetAttrString(instance, constant_name);
162  if (attr && PyLong_Check(attr)) {
163  return PyLong_AsLong(attr);
164  } else {
165  return def;
166  }
167 }
168 
170 {
172 
173  if(!PyObject_HasAttrString(pluginInstance, "icon_name_ssh")) {
174  g_printerr("Error creating Remmina plugin. Python plugin instance is missing member: icon_name_ssh\n");
175  return NULL;
176  }
177  else if(!PyObject_HasAttrString(pluginInstance, "icon_name")) {
178  g_printerr("Error creating Remmina plugin. Python plugin instance is missing member: icon_name\n");
179  return NULL;
180  }
181  else if(!PyObject_HasAttrString(pluginInstance, "features")) {
182  g_printerr("Error creating Remmina plugin. Python plugin instance is missing member: features\n");
183  return NULL;
184  }
185  else if(!PyObject_HasAttrString(pluginInstance, "basic_settings")) {
186  g_printerr("Error creating Remmina plugin. Python plugin instance is missing member: basic_settings\n");
187  return NULL;
188  }
189  else if(!PyObject_HasAttrString(pluginInstance, "advanced_settings")) {
190  g_printerr("Error creating Remmina plugin. Python plugin instance is missing member: advanced_settings\n");
191  return NULL;
192  }
193  else if(!PyObject_HasAttrString(pluginInstance, "ssh_setting")) {
194  g_printerr("Error creating Remmina plugin. Python plugin instance is missing member: ssh_setting\n");
195  return NULL;
196  }
197 
198  remmina_plugin->type = REMMINA_PLUGIN_TYPE_PROTOCOL;
199  remmina_plugin->name = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "name")); // Name
200  remmina_plugin->description = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "description")); // Description
201  remmina_plugin->domain = GETTEXT_PACKAGE; // Translation domain
202  remmina_plugin->version = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "version")); // Version number
203  remmina_plugin->icon_name = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "icon_name")); // Icon for normal connection
204  remmina_plugin->icon_name_ssh = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "icon_name_ssh")); // Icon for SSH connection
205 
206  PyObject* basic_settings_list = PyObject_GetAttrString(pluginInstance, "basic_settings");
207  Py_ssize_t len = PyList_Size(basic_settings_list);
208  if (len) {
209  remmina_plugin->basic_settings = (RemminaProtocolSetting*)malloc(sizeof(RemminaProtocolSetting) * len);
210  memset(&remmina_plugin->basic_settings[len], 0, sizeof(RemminaProtocolSetting));
211 
212  for (Py_ssize_t i = 0; i < len; ++i) {
213  RemminaProtocolSetting* dest = remmina_plugin->basic_settings + i;
214  ToRemminaProtocolSetting(dest, PyList_GetItem(basic_settings_list, i));
215  }
216  } else {
217  remmina_plugin->basic_settings = NULL;
218  }
219 
220  PyObject* advanced_settings_list = PyObject_GetAttrString(pluginInstance, "advanced_settings");
221  len = PyList_Size(advanced_settings_list);
222  if (len) {
223  remmina_plugin->advanced_settings = (RemminaProtocolSetting*)malloc(sizeof(RemminaProtocolSetting) * (len+1));
224  memset(&remmina_plugin->advanced_settings[len], 0, sizeof(RemminaProtocolSetting));
225 
226  for (Py_ssize_t i = 0; i < len; ++i) {
227  RemminaProtocolSetting* dest = remmina_plugin->advanced_settings + i;
228  ToRemminaProtocolSetting(dest, PyList_GetItem(advanced_settings_list, i));
229  }
230  } else {
231  remmina_plugin->advanced_settings = NULL;
232  }
233 
234 
235  PyObject* features_list = PyObject_GetAttrString(pluginInstance, "features");
236  len = PyList_Size(features_list);
237  if (len) {
238  remmina_plugin->features = (RemminaProtocolFeature*)malloc(sizeof(RemminaProtocolFeature) * (len+1));
239  memset(&remmina_plugin->features[len], 0, sizeof(RemminaProtocolFeature));
240 
241  for (Py_ssize_t i = 0; i < len; ++i) {
242  RemminaProtocolFeature* dest = remmina_plugin->features + i;
243  ToRemminaProtocolFeature(dest, PyList_GetItem(features_list, i));
244  }
245  } else {
246  remmina_plugin->features = NULL;
247  }
248 
249  remmina_plugin->ssh_setting = (RemminaProtocolSSHSetting)GetEnumOrDefault(pluginInstance, "ssh_setting", REMMINA_PROTOCOL_SSH_SETTING_NONE);
250 
251  remmina_plugin->init = remmina_protocol_init_wrapper ; // Plugin initialization
252  remmina_plugin->open_connection = remmina_protocol_open_connection_wrapper ; // Plugin open connection
253  remmina_plugin->close_connection = remmina_protocol_close_connection_wrapper ; // Plugin close connection
254  remmina_plugin->query_feature = remmina_protocol_query_feature_wrapper ; // Query for available features
255  remmina_plugin->call_feature = remmina_protocol_call_feature_wrapper ; // Call a feature
256  remmina_plugin->send_keystrokes = remmina_protocol_send_keytrokes_wrapper; // Send a keystroke
257  remmina_plugin->get_plugin_screenshot = remmina_protocol_get_plugin_screenshot_wrapper; // Screenshot support unavailable
258 
259  return remmina_plugin;
260 }
261 
263 {
264 
265 }
267 {
268 
269 }
271 {
272 
273 }
275 {
276 
277 }
279 {
280 
281 }
static void remmina_protocol_call_feature_wrapper(RemminaProtocolPlugin *plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
void(* call_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: plugin.h:81
Maps an instance of a Python plugin to a Remmina one.
void ToRemminaProtocolFeature(RemminaProtocolFeature *dest, PyObject *feature)
RemminaProtocolSSHSetting ssh_setting
Definition: plugin.h:74
void(* init)(RemminaProtocolWidget *gp)
Definition: plugin.h:77
static RemminaProtocolPlugin remmina_plugin
Definition: exec_plugin.c:280
const RemminaProtocolFeature * features
Definition: plugin.h:75
PyObject_HEAD RemminaProtocolWidget * gp
static gboolean remmina_protocol_get_plugin_screenshot_wrapper(RemminaProtocolPlugin *plugin, RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
static gboolean remmina_protocol_query_feature_wrapper(RemminaProtocolPlugin *plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
RemminaPlugin * remmina_plugin_python_create_file_plugin(pluginInstance)
gboolean(* open_connection)(RemminaProtocolWidget *gp)
Definition: plugin.h:78
static void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolPlugin *plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
void(* protocol_plugin_signal_connection_opened)(RemminaProtocolWidget *gp)
Definition: plugin.h:172
const gchar * icon_name_ssh
Definition: plugin.h:71
PyRemminaProtocolWidget * gp
RemminaPluginService remmina_plugin_manager_service
PyPlugin * remmina_plugin_python_module_get_plugin(RemminaProtocolWidget *gp)
Returns a pointer to the Python instance, mapped to the RemminaProtocolWidget or null if not found...
RemminaPlugin * remmina_plugin_python_create_secret_plugin(pluginInstance)
const gchar * description
Definition: plugin.h:66
void(* send_keystrokes)(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: plugin.h:82
RemminaProtocolSSHSetting
Definition: types.h:111
static void remmina_protocol_init_wrapper(RemminaProtocolWidget *gp)
Handles the initialization of the Python plugin.
RemminaPlugin * remmina_plugin_python_create_protocol_plugin(PyObject *pluginInstance)
const RemminaProtocolSetting * basic_settings
Definition: plugin.h:72
RemminaPluginType type
Definition: plugin.h:64
static long GetEnumOrDefault(PyObject *instance, gchar *constant_name, long def)
gboolean(* close_connection)(RemminaProtocolWidget *gp)
Definition: plugin.h:79
void ToRemminaProtocolSetting(RemminaProtocolSetting *dest, PyObject *setting)
gboolean(* query_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: plugin.h:80
const gchar * version
Definition: plugin.h:68
const gchar * name
Definition: plugin.h:65
const RemminaProtocolSetting * advanced_settings
Definition: plugin.h:73
RemminaPlugin * remmina_plugin_python_create_tool_plugin(pluginInstance)
static gboolean remmina_protocol_close_connection_wrapper(RemminaProtocolWidget *gp)
gboolean(* get_plugin_screenshot)(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: plugin.h:83
RemminaPlugin * remmina_plugin_python_create_entry_plugin(pluginInstance)
const gchar * icon_name
Definition: plugin.h:70
const gchar * domain
Definition: plugin.h:67
RemminaPlugin * remmina_plugin_python_create_pref_plugin(pluginInstance)
static gboolean remmina_protocol_open_connection_wrapper(RemminaProtocolWidget *gp)