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.
python_wrapper_protocol.c
Go to the documentation of this file.
1 /*
2  * Remmina - The GTK+ Remote Desktop Client
3  * Copyright (C) 2014-2023 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 
45 #include "python_wrapper_common.h"
47 #include "python_wrapper_remmina.h"
48 
50 // D E C L A R A T I O N S
52 
54 // A P I
56 
58 {
59  TRACE_CALL(__func__);
60 }
61 
63 {
64  TRACE_CALL(__func__);
66  py_plugin->gp->gp = gp;
67  CallPythonMethod(py_plugin->instance, "init", "O", py_plugin->gp);
68 }
69 
71 {
72  TRACE_CALL(__func__);
74  if (py_plugin)
75  {
76  PyObject* result = CallPythonMethod(py_plugin->instance, "open_connection", "O", py_plugin->gp);
77  return result == Py_True;
78  }
79  else
80  {
81  return gtk_false();
82  }
83 }
84 
86 {
87  TRACE_CALL(__func__);
89  PyObject* result = CallPythonMethod(py_plugin->instance, "close_connection", "O", py_plugin->gp);
90  return result == Py_True;
91 }
92 
94  const RemminaProtocolFeature* feature)
95 {
96  TRACE_CALL(__func__);
99  pyFeature->type = (gint)feature->type;
100  pyFeature->id = feature->id;
101  pyFeature->opt1 = python_wrapper_generic_new();
102  pyFeature->opt1->raw = feature->opt1;
103  pyFeature->opt2 = python_wrapper_generic_new();
104  pyFeature->opt2->raw = feature->opt2;
105  pyFeature->opt3 = python_wrapper_generic_new();
106  pyFeature->opt3->raw = feature->opt3;
107 
108  PyObject* result = CallPythonMethod(py_plugin->instance, "query_feature", "OO", py_plugin->gp, pyFeature);
109  Py_DecRef((PyObject*)pyFeature);
110  Py_DecRef((PyObject*)pyFeature->opt1);
111  Py_DecRef((PyObject*)pyFeature->opt2);
112  Py_DecRef((PyObject*)pyFeature->opt3);
113  return result == Py_True;
114 }
115 
117 {
118  TRACE_CALL(__func__);
121  pyFeature->type = (gint)feature->type;
122  pyFeature->id = feature->id;
123  pyFeature->opt1 = python_wrapper_generic_new();
124  pyFeature->opt1->raw = feature->opt1;
125  pyFeature->opt1->type_hint = feature->opt1_type_hint;
126  pyFeature->opt2 = python_wrapper_generic_new();
127  pyFeature->opt2->raw = feature->opt2;
128  pyFeature->opt2->type_hint = feature->opt2_type_hint;
129  pyFeature->opt3 = python_wrapper_generic_new();
130  pyFeature->opt3->raw = feature->opt3;
131  pyFeature->opt3->type_hint = feature->opt3_type_hint;
132 
133  CallPythonMethod(py_plugin->instance, "call_feature", "OO", py_plugin->gp, pyFeature);
134  Py_DecRef((PyObject*)pyFeature);
135  Py_DecRef((PyObject*)pyFeature->opt1);
136  Py_DecRef((PyObject*)pyFeature->opt2);
137  Py_DecRef((PyObject*)pyFeature->opt3);
138 }
139 
141  const guint keystrokes[],
142  const gint keylen)
143 {
144  TRACE_CALL(__func__);
146  PyObject* obj = PyList_New(keylen);
147  Py_IncRef(obj);
148  for (int i = 0; i < keylen; ++i)
149  {
150  PyList_SetItem(obj, i, PyLong_FromLong(keystrokes[i]));
151  }
152  CallPythonMethod(py_plugin->instance, "send_keystrokes", "OO", py_plugin->gp, obj);
153  Py_DecRef(obj);
154 }
155 
158 {
159  TRACE_CALL(__func__);
160 
163  Py_IncRef((PyObject*)data);
164  PyObject* result = CallPythonMethod(py_plugin->instance, "get_plugin_screenshot", "OO", py_plugin->gp, data);
165  if (result == Py_True)
166  {
167  if (!PyByteArray_Check((PyObject*)data->buffer))
168  {
169  g_printerr("Unable to parse screenshot data. 'buffer' needs to be an byte array!");
170  return 0;
171  }
172  Py_ssize_t buffer_len = PyByteArray_Size((PyObject*)data->buffer);
173 
174  // Is being freed by Remmina!
175  rpsd->buffer = (unsigned char*)python_wrapper_malloc(sizeof(unsigned char) * buffer_len);
176  if (!rpsd->buffer)
177  {
178  return 0;
179  }
180  memcpy(rpsd->buffer, PyByteArray_AsString((PyObject*)data->buffer), sizeof(unsigned char) * buffer_len);
181  rpsd->bytesPerPixel = data->bytesPerPixel;
182  rpsd->bitsPerPixel = data->bitsPerPixel;
183  rpsd->height = data->height;
184  rpsd->width = data->width;
185  }
186  Py_DecRef((PyObject*)data->buffer);
187  Py_DecRef((PyObject*)data);
188  return result == Py_True;
189 }
190 
192 {
194  PyObject* result = CallPythonMethod(plugin->instance, "map_event", "O", plugin->gp);
195  return PyBool_Check(result) && result == Py_True;
196 }
197 
199 {
201  PyObject* result = CallPythonMethod(plugin->instance, "unmap_event", "O", plugin->gp);
202  return PyBool_Check(result) && result == Py_True;
203 }
204 
206 {
207  PyObject* instance = plugin->instance;
208 
215  {
216  g_printerr("Unable to create protocol plugin. Aborting!\n");
217  return NULL;
218  }
219 
221 
222  remmina_plugin->type = REMMINA_PLUGIN_TYPE_PROTOCOL;
223  remmina_plugin->domain = GETTEXT_PACKAGE;
224  remmina_plugin->basic_settings = NULL;
225  remmina_plugin->advanced_settings = NULL;
226  remmina_plugin->features = NULL;
227 
228  remmina_plugin->name = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_NAME));
229  remmina_plugin->description = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_DESCRIPTION));
230  remmina_plugin->version = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_VERSION));
231  remmina_plugin->icon_name = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_ICON_NAME));
232  remmina_plugin->icon_name_ssh = PyUnicode_AsUTF8(PyObject_GetAttrString(instance, ATTR_ICON_NAME_SSH));
233 
234  PyObject* list = PyObject_GetAttrString(instance, "basic_settings");
235  Py_ssize_t len = PyList_Size(list);
236  if (len)
237  {
239  sizeof(RemminaProtocolSetting) * (len + 1));
240  memset(basic_settings, 0, sizeof(RemminaProtocolSetting) * (len + 1));
241 
242  for (Py_ssize_t i = 0; i < len; ++i)
243  {
244  RemminaProtocolSetting* dest = basic_settings + i;
245  python_wrapper_to_protocol_setting(dest, PyList_GetItem(list, i));
246  }
247  RemminaProtocolSetting* dest = basic_settings + len;
249  remmina_plugin->basic_settings = basic_settings;
250  }
251 
252  list = PyObject_GetAttrString(instance, "advanced_settings");
253  len = PyList_Size(list);
254  if (len)
255  {
257  sizeof(RemminaProtocolSetting) * (len + 1));
258  memset(advanced_settings, 0, sizeof(RemminaProtocolSetting) * (len + 1));
259 
260  for (Py_ssize_t i = 0; i < len; ++i)
261  {
262  RemminaProtocolSetting* dest = advanced_settings + i;
263  python_wrapper_to_protocol_setting(dest, PyList_GetItem(list, i));
264  }
265 
266  RemminaProtocolSetting* dest = advanced_settings + len;
268 
269  remmina_plugin->advanced_settings = advanced_settings;
270  }
271 
272  list = PyObject_GetAttrString(instance, "features");
273  len = PyList_Size(list);
274  if (len)
275  {
277  sizeof(RemminaProtocolFeature) * (len + 1));
278  memset(features, 0, sizeof(RemminaProtocolFeature) * (len + 1));
279 
280  for (Py_ssize_t i = 0; i < len; ++i)
281  {
282  RemminaProtocolFeature* dest = features + i;
283  python_wrapper_to_protocol_feature(dest, PyList_GetItem(list, i));
284  }
285 
286  RemminaProtocolFeature* dest = features + len;
288 
289  remmina_plugin->features = features;
290  }
291 
295 
296  remmina_plugin->init = remmina_protocol_init_wrapper; // Plugin initialization
297  remmina_plugin->open_connection = remmina_protocol_open_connection_wrapper; // Plugin open connection
298  remmina_plugin->close_connection = remmina_protocol_close_connection_wrapper; // Plugin close connection
299  remmina_plugin->query_feature = remmina_protocol_query_feature_wrapper; // Query for available features
300  remmina_plugin->call_feature = remmina_protocol_call_feature_wrapper; // Call a feature
301  remmina_plugin->send_keystrokes =
302  remmina_protocol_send_keytrokes_wrapper; // Send a keystroke
303  remmina_plugin->get_plugin_screenshot =
304  remmina_protocol_get_plugin_screenshot_wrapper; // Screenshot support unavailable
305 
308 
310  plugin->generic_plugin = (RemminaPlugin*)remmina_plugin;
311 
313 
314  return (RemminaPlugin*)remmina_plugin;
315 }
PyPlugin * python_wrapper_get_plugin_by_protocol_widget(RemminaProtocolWidget *gp)
Tries to find the Python plugin matching to the given instance of RemminaPlugin.
PyObject_HEAD RemminaProtocolFeatureType type
void(* call_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: plugin.h:83
PyRemminaPluginScreenshotData * python_wrapper_screenshot_data_new(void)
void remmina_protocol_init_wrapper(RemminaProtocolWidget *gp)
Wrapper for a Python object that contains a pointer to an instance of RemminaProtocolFeature.
void python_wrapper_to_protocol_setting(RemminaProtocolSetting *dest, PyObject *setting)
Converts the PyObject to RemminaProtocolSetting.
Maps an instance of a Python plugin to a Remmina one.
gboolean python_wrapper_check_attribute(PyObject *instance, const char *attr_name)
Checks if a given attribute exists.
RemminaProtocolSSHSetting ssh_setting
Definition: plugin.h:76
gboolean remmina_protocol_get_plugin_screenshot_wrapper(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
const char * ATTR_VERSION
Contains the implementation of the Python module &#39;remmina&#39;, provided to interface with the applicatio...
void * python_wrapper_malloc(int bytes)
Allocates memory and checks for errors before returning.
void(* init)(RemminaProtocolWidget *gp)
Definition: plugin.h:79
static RemminaProtocolPlugin remmina_plugin
Definition: exec_plugin.c:304
long python_wrapper_get_attribute_long(PyObject *instance, const char *attr_name, long def)
Gets the attribute as long value.
const RemminaProtocolFeature * features
Definition: plugin.h:77
PyObject_HEAD RemminaProtocolWidget * gp
gboolean remmina_protocol_map_event_wrapper(RemminaProtocolWidget *gp)
void remmina_protocol_call_feature_wrapper(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
RemminaProtocolPlugin * protocol_plugin
gboolean(* open_connection)(RemminaProtocolWidget *gp)
Definition: plugin.h:80
const char * ATTR_ADVANCED_SETTINGS
void python_wrapper_protocol_init(void)
Initializes the Python plugin specialisation for protocol plugins.
void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Contains functions and constants that are commonly used throughout the Python plugin implementation...
const gchar * icon_name_ssh
Definition: plugin.h:73
PyRemminaProtocolWidget * gp
const char * ATTR_FEATURES
gboolean remmina_protocol_close_connection_wrapper(RemminaProtocolWidget *gp)
gboolean(* unmap_event)(RemminaProtocolWidget *gp)
Definition: plugin.h:87
void python_wrapper_add_plugin(PyPlugin *plugin)
Registers the given plugin if no other plugin with the same name has been already registered...
const gchar * description
Definition: plugin.h:68
RemminaProtocolFeatureType type
Definition: types.h:73
void(* send_keystrokes)(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
Definition: plugin.h:84
RemminaPlugin * generic_plugin
RemminaProtocolSSHSetting
Definition: types.h:128
const char * ATTR_BASIC_SETTINGS
gboolean remmina_protocol_query_feature_wrapper(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
const RemminaProtocolSetting * basic_settings
Definition: plugin.h:74
const char * ATTR_NAME
RemminaTypeHint opt1_type_hint
Definition: types.h:78
RemminaPluginType type
Definition: plugin.h:66
const char * ATTR_DESCRIPTION
gboolean(* close_connection)(RemminaProtocolWidget *gp)
Definition: plugin.h:81
RemminaProtocolSettingType type
Definition: types.h:118
const char * ATTR_ICON_NAME
Contains the specialisation of RemminaPluginFile plugins in Python.
RemminaTypeHint type_hint
RemminaTypeHint opt2_type_hint
Definition: types.h:79
void python_wrapper_to_protocol_feature(RemminaProtocolFeature *dest, PyObject *feature)
Converts the PyObject to RemminaProtocolFeature.
gboolean remmina_protocol_unmap_event_wrapper(RemminaProtocolWidget *gp)
gboolean(* map_event)(RemminaProtocolWidget *gp)
Definition: plugin.h:86
gboolean(* query_feature)(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
Definition: plugin.h:82
const gchar * version
Definition: plugin.h:70
PyRemminaProtocolFeature * python_wrapper_protocol_feature_new(void)
const char * ATTR_ICON_NAME_SSH
const gchar * name
Definition: plugin.h:67
PyGeneric * python_wrapper_generic_new(void)
Creates a new instance of PyGeneric.
const RemminaProtocolSetting * advanced_settings
Definition: plugin.h:75
const char * ATTR_SSH_SETTING
gboolean(* get_plugin_screenshot)(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
Definition: plugin.h:85
const gchar * icon_name
Definition: plugin.h:72
unsigned char * buffer
Definition: types.h:84
const gchar * domain
Definition: plugin.h:69
RemminaTypeHint opt3_type_hint
Definition: types.h:80
gboolean remmina_protocol_open_connection_wrapper(RemminaProtocolWidget *gp)
RemminaPlugin * python_wrapper_create_protocol_plugin(PyPlugin *plugin)
Creates a new instance of the RemminaPluginProtocol, initializes its members and references the wrapp...
PyObject * instance