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_protocol.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, Mathias Winterhalter (ToolsDevler)
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 
41 // I N C L U D E S
44 
48 
50 
52 // D E C L A R A T I O N S
54 
56 // A P I
58 
60 {
61  TRACE_CALL(__func__);
62 }
63 
65 {
66  TRACE_CALL(__func__);
68  py_plugin->gp->gp = gp;
69  CallPythonMethod(py_plugin->instance, "init", "O", py_plugin->gp);
70 }
71 
73 {
74  TRACE_CALL(__func__);
76  if (py_plugin)
77  {
78  PyObject* result = CallPythonMethod(py_plugin->instance, "open_connection", "O", py_plugin->gp);
79  return result == Py_True;
80  }
81  else
82  {
83  return gtk_false();
84  }
85 }
86 
88 {
89  TRACE_CALL(__func__);
91  PyObject* result = CallPythonMethod(py_plugin->instance, "close_connection", "O", py_plugin->gp);
92  return result == Py_True;
93 }
94 
96  const RemminaProtocolFeature* feature)
97 {
98  TRACE_CALL(__func__);
101  pyFeature->type = (gint)feature->type;
102  pyFeature->id = feature->id;
104  pyFeature->opt1->raw = feature->opt1;
106  pyFeature->opt2->raw = feature->opt2;
108  pyFeature->opt3->raw = feature->opt3;
109 
110  PyObject* result = CallPythonMethod(py_plugin->instance, "query_feature", "OO", py_plugin->gp, pyFeature);
111  Py_DecRef((PyObject*)pyFeature);
112  Py_DecRef((PyObject*)pyFeature->opt1);
113  Py_DecRef((PyObject*)pyFeature->opt2);
114  Py_DecRef((PyObject*)pyFeature->opt3);
115  return result == Py_True;
116 }
117 
119 {
120  TRACE_CALL(__func__);
123  pyFeature->type = (gint)feature->type;
124  pyFeature->id = feature->id;
126  pyFeature->opt1->raw = feature->opt1;
127  pyFeature->opt1->type_hint = feature->opt1_type_hint;
129  pyFeature->opt2->raw = feature->opt2;
130  pyFeature->opt2->type_hint = feature->opt2_type_hint;
132  pyFeature->opt3->raw = feature->opt3;
133  pyFeature->opt3->type_hint = feature->opt3_type_hint;
134 
135  CallPythonMethod(py_plugin->instance, "call_feature", "OO", py_plugin->gp, pyFeature);
136  Py_DecRef((PyObject*)pyFeature);
137  Py_DecRef((PyObject*)pyFeature->opt1);
138  Py_DecRef((PyObject*)pyFeature->opt2);
139  Py_DecRef((PyObject*)pyFeature->opt3);
140 }
141 
143  const guint keystrokes[],
144  const gint keylen)
145 {
146  TRACE_CALL(__func__);
148  PyObject* obj = PyList_New(keylen);
149  Py_IncRef(obj);
150  for (int i = 0; i < keylen; ++i)
151  {
152  PyList_SetItem(obj, i, PyLong_FromLong(keystrokes[i]));
153  }
154  CallPythonMethod(py_plugin->instance, "send_keystrokes", "OO", py_plugin->gp, obj);
155  Py_DecRef(obj);
156 }
157 
160 {
161  TRACE_CALL(__func__);
162 
165  Py_IncRef((PyObject*)data);
166  PyObject* result = CallPythonMethod(py_plugin->instance, "get_plugin_screenshot", "OO", py_plugin->gp, data);
167  if (result == Py_True)
168  {
169  if (!PyByteArray_Check((PyObject*)data->buffer))
170  {
171  g_printerr("Unable to parse screenshot data. 'buffer' needs to be an byte array!");
172  return 0;
173  }
174  Py_ssize_t buffer_len = PyByteArray_Size((PyObject*)data->buffer);
175 
176  // Is being freed by Remmina!
177  rpsd->buffer = (unsigned char*)remmina_plugin_python_malloc(sizeof(unsigned char) * buffer_len);
178  if (!rpsd->buffer)
179  {
180  return 0;
181  }
182  memcpy(rpsd->buffer, PyByteArray_AsString((PyObject*)data->buffer), sizeof(unsigned char) * buffer_len);
183  rpsd->bytesPerPixel = data->bytesPerPixel;
184  rpsd->bitsPerPixel = data->bitsPerPixel;
185  rpsd->height = data->height;
186  rpsd->width = data->width;
187  }
188  Py_DecRef((PyObject*)data->buffer);
189  Py_DecRef((PyObject*)data);
190  return result == Py_True;
191 }
192 
194 {
196  PyObject* result = CallPythonMethod(plugin->instance, "map_event", "O", plugin->gp);
197  return PyBool_Check(result) && result == Py_True;
198 }
199 
201 {
203  PyObject* result = CallPythonMethod(plugin->instance, "unmap_event", "O", plugin->gp);
204  return PyBool_Check(result) && result == Py_True;
205 }
206 
208 {
209  PyObject* instance = plugin->instance;
210 
217  {
218  g_printerr("Unable to create protocol plugin. Aborting!\n");
219  return NULL;
220  }
221 
223 
224  remmina_plugin->type = REMMINA_PLUGIN_TYPE_PROTOCOL;
225  remmina_plugin->domain = GETTEXT_PACKAGE;
226  remmina_plugin->basic_settings = NULL;
227  remmina_plugin->advanced_settings = NULL;
228  remmina_plugin->features = NULL;
229 
230  remmina_plugin->name = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_NAME));
231  remmina_plugin->description = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_DESCRIPTION));
232  remmina_plugin->version = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_VERSION));
233  remmina_plugin->icon_name = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_ICON_NAME));
234  remmina_plugin->icon_name_ssh = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_ICON_NAME_SSH));
235 
236  PyObject* list = PyObject_GetAttrString(instance, "basic_settings");
237  Py_ssize_t len = PyList_Size(list);
238  if (len)
239  {
241  sizeof(RemminaProtocolSetting) * (len + 1));
242  memset(basic_settings, 0, sizeof(RemminaProtocolSetting) * (len + 1));
243 
244  for (Py_ssize_t i = 0; i < len; ++i)
245  {
246  RemminaProtocolSetting* dest = basic_settings + i;
247  remmina_plugin_python_to_protocol_setting(dest, PyList_GetItem(list, i));
248  }
249  RemminaProtocolSetting* dest = basic_settings + len;
251  remmina_plugin->basic_settings = basic_settings;
252  }
253 
254  list = PyObject_GetAttrString(instance, "advanced_settings");
255  len = PyList_Size(list);
256  if (len)
257  {
259  sizeof(RemminaProtocolSetting) * (len + 1));
260  memset(advanced_settings, 0, sizeof(RemminaProtocolSetting) * (len + 1));
261 
262  for (Py_ssize_t i = 0; i < len; ++i)
263  {
264  RemminaProtocolSetting* dest = advanced_settings + i;
265  remmina_plugin_python_to_protocol_setting(dest, PyList_GetItem(list, i));
266  }
267 
268  RemminaProtocolSetting* dest = advanced_settings + len;
270 
271  remmina_plugin->advanced_settings = advanced_settings;
272  }
273 
274  list = PyObject_GetAttrString(instance, "features");
275  len = PyList_Size(list);
276  if (len)
277  {
279  sizeof(RemminaProtocolFeature) * (len + 1));
280  memset(features, 0, sizeof(RemminaProtocolFeature) * (len + 1));
281 
282  for (Py_ssize_t i = 0; i < len; ++i)
283  {
284  RemminaProtocolFeature* dest = features + i;
285  remmina_plugin_python_to_protocol_feature(dest, PyList_GetItem(list, i));
286  }
287 
288  RemminaProtocolFeature* dest = features + len;
290 
291  remmina_plugin->features = features;
292  }
293 
297 
298  remmina_plugin->init = remmina_protocol_init_wrapper; // Plugin initialization
299  remmina_plugin->open_connection = remmina_protocol_open_connection_wrapper; // Plugin open connection
300  remmina_plugin->close_connection = remmina_protocol_close_connection_wrapper; // Plugin close connection
301  remmina_plugin->query_feature = remmina_protocol_query_feature_wrapper; // Query for available features
302  remmina_plugin->call_feature = remmina_protocol_call_feature_wrapper; // Call a feature
303  remmina_plugin->send_keystrokes =
304  remmina_protocol_send_keytrokes_wrapper; // Send a keystroke
305  remmina_plugin->get_plugin_screenshot =
306  remmina_protocol_get_plugin_screenshot_wrapper; // Screenshot support unavailable
307 
310 
312  plugin->generic_plugin = (RemminaPlugin*)remmina_plugin;
313 
315 
316  return (RemminaPlugin*)remmina_plugin;
317 }
PyObject_HEAD RemminaProtocolFeatureType type
void(* call_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: plugin.h:81
Wrapper for a Python object that contains a pointer to an instance of RemminaProtocolFeature.
void remmina_protocol_call_feature_wrapper(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
gboolean remmina_protocol_open_connection_wrapper(RemminaProtocolWidget *gp)
Maps an instance of a Python plugin to a Remmina one.
RemminaProtocolSSHSetting ssh_setting
Definition: plugin.h:74
void remmina_plugin_python_to_protocol_feature(RemminaProtocolFeature *dest, PyObject *feature)
Converts the PyObject to RemminaProtocolFeature.
void(* init)(RemminaProtocolWidget *gp)
Definition: plugin.h:77
static RemminaProtocolPlugin remmina_plugin
Definition: exec_plugin.c:280
gboolean remmina_protocol_get_plugin_screenshot_wrapper(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
const RemminaProtocolFeature * features
Definition: plugin.h:75
gboolean remmina_protocol_close_connection_wrapper(RemminaProtocolWidget *gp)
PyObject_HEAD RemminaProtocolWidget * gp
long remmina_plugin_python_get_attribute_long(PyObject *instance, const char *attr_name, long def)
Gets the attribute as long value.
void remmina_protocol_init_wrapper(RemminaProtocolWidget *gp)
Contains the implementation of the Python module &#39;remmina&#39;, provided to interface with the applicatio...
PyPlugin * remmina_plugin_python_get_plugin(const char *name)
Tries to find the Python plugin matching to the given instance of RemminaPlugin.
RemminaProtocolPlugin * protocol_plugin
gboolean(* open_connection)(RemminaProtocolWidget *gp)
Definition: plugin.h:78
Contains the specialisation of RemminaPluginFile plugins in Python.
gboolean remmina_protocol_unmap_event_wrapper(RemminaProtocolWidget *gp)
PyRemminaPluginScreenshotData * remmina_plugin_python_screenshot_data_new(void)
const gchar * icon_name_ssh
Definition: plugin.h:71
PyRemminaProtocolWidget * gp
gboolean remmina_protocol_map_event_wrapper(RemminaProtocolWidget *gp)
const char * ATTR_ADVANCED_SETTINGS
const char * ATTR_DESCRIPTION
gboolean(* unmap_event)(RemminaProtocolWidget *gp)
Definition: plugin.h:85
const char * ATTR_ICON_NAME_SSH
const gchar * description
Definition: plugin.h:66
RemminaProtocolFeatureType type
Definition: types.h:73
RemminaProtocolPlugin * plugin
void(* send_keystrokes)(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: plugin.h:82
RemminaPlugin * generic_plugin
PyRemminaProtocolFeature * remmina_plugin_python_protocol_feature_new(void)
RemminaProtocolSSHSetting
Definition: types.h:127
void remmina_plugin_python_add_plugin(PyPlugin *plugin)
Registers the given plugin if no other plugin with the same name has been already registered...
gboolean remmina_protocol_query_feature_wrapper(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
const RemminaProtocolSetting * basic_settings
Definition: plugin.h:72
const char * ATTR_FEATURES
RemminaTypeHint opt1_type_hint
Definition: types.h:78
RemminaPluginType type
Definition: plugin.h:64
gboolean remmina_plugin_python_check_attribute(PyObject *instance, const char *attr_name)
Checks if a given attribute exists.
const char * ATTR_BASIC_SETTINGS
void remmina_plugin_python_to_protocol_setting(RemminaProtocolSetting *dest, PyObject *setting)
Converts the PyObject to RemminaProtocolSetting.
const char * ATTR_NAME
gboolean(* close_connection)(RemminaProtocolWidget *gp)
Definition: plugin.h:79
RemminaProtocolSettingType type
Definition: types.h:117
RemminaTypeHint type_hint
RemminaTypeHint opt2_type_hint
Definition: types.h:79
gboolean(* map_event)(RemminaProtocolWidget *gp)
Definition: plugin.h:84
gboolean(* query_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: plugin.h:80
Contains functions and constants that are commonly used throughout the Python plugin implementation...
const gchar * version
Definition: plugin.h:68
const gchar * name
Definition: plugin.h:65
const RemminaProtocolSetting * advanced_settings
Definition: plugin.h:73
void * remmina_plugin_python_malloc(int bytes)
Allocates memory and checks for errors before returning.
gboolean(* get_plugin_screenshot)(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: plugin.h:83
RemminaPlugin * remmina_plugin_python_create_protocol_plugin(PyPlugin *plugin)
Creates a new instance of the RemminaPluginProtocol, initializes its members and references the wrapp...
const char * ATTR_ICON_NAME
const gchar * icon_name
Definition: plugin.h:70
void remmina_plugin_python_protocol_init(void)
Initializes the Python plugin specialisation for protocol plugins.
unsigned char * buffer
Definition: types.h:84
const gchar * domain
Definition: plugin.h:67
PyGeneric * remmina_plugin_python_generic_new(void)
Creates a new instance of PyGeneric.
RemminaTypeHint opt3_type_hint
Definition: types.h:80
const char * ATTR_SSH_SETTING
const char * ATTR_VERSION