summaryrefslogtreecommitdiffstats
path: root/plugins/python_wrapper/python_wrapper_common.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 17:06:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 17:06:32 +0000
commit2dad5357405ad33cfa792f04b3ab62a5d188841e (patch)
treeb8f8893942060fe3cfb04ac374cda96fdfc8f453 /plugins/python_wrapper/python_wrapper_common.c
parentInitial commit. (diff)
downloadremmina-2dad5357405ad33cfa792f04b3ab62a5d188841e.tar.xz
remmina-2dad5357405ad33cfa792f04b3ab62a5d188841e.zip
Adding upstream version 1.4.34+dfsg.upstream/1.4.34+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plugins/python_wrapper/python_wrapper_common.c')
-rw-r--r--plugins/python_wrapper/python_wrapper_common.c327
1 files changed, 327 insertions, 0 deletions
diff --git a/plugins/python_wrapper/python_wrapper_common.c b/plugins/python_wrapper/python_wrapper_common.c
new file mode 100644
index 0000000..e6a2d05
--- /dev/null
+++ b/plugins/python_wrapper/python_wrapper_common.c
@@ -0,0 +1,327 @@
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2014-2023 Antenore Gatta, Giovanni Panozzo, Mathias Winterhalter (ToolsDevler)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. * If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. * If you
+ * do not wish to do so, delete this exception statement from your
+ * version. * If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// I N C L U D E S
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "python_wrapper_common.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#include "pygobject.h"
+#pragma GCC diagnostic pop
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// D E C L A R A T I O N S
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A cache to store the last result that has been returned by the Python code using CallPythonMethod
+ * (@see python_wrapper_common.h)
+ */
+static PyObject* __last_result;
+static GPtrArray* plugin_map = NULL;
+
+static RemminaPluginService* remmina_plugin_service;
+
+const char* ATTR_NAME = "name";
+const char* ATTR_ICON_NAME = "icon_name";
+const char* ATTR_DESCRIPTION = "description";
+const char* ATTR_VERSION = "version";
+const char* ATTR_ICON_NAME_SSH = "icon_name_ssh";
+const char* ATTR_FEATURES = "features";
+const char* ATTR_BASIC_SETTINGS = "basic_settings";
+const char* ATTR_ADVANCED_SETTINGS = "advanced_settings";
+const char* ATTR_SSH_SETTING = "ssh_setting";
+const char* ATTR_EXPORT_HINTS = "export_hints";
+const char* ATTR_PREF_LABEL = "pref_label";
+const char* ATTR_INIT_ORDER = "init_order";
+
+/**
+ * To prevent some memory related attacks or accidental allocation of an excessive amount of byes, this limit should
+ * always be used to check for a sane amount of bytes to allocate.
+ */
+static const int REASONABLE_LIMIT_FOR_MALLOC = 1024 * 1024;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// A P I
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+PyObject* python_wrapper_last_result(void)
+{
+ TRACE_CALL(__func__);
+
+ return __last_result;
+}
+
+PyObject* python_wrapper_last_result_set(PyObject* last_result)
+{
+ TRACE_CALL(__func__);
+
+ return __last_result = last_result;
+}
+
+gboolean python_wrapper_check_error(void)
+{
+ TRACE_CALL(__func__);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void python_wrapper_log_method_call(PyObject* instance, const char* method)
+{
+ TRACE_CALL(__func__);
+
+ assert(instance);
+ assert(method);
+ g_print("Python@%ld: %s.%s(...) -> %s\n",
+ PyObject_Hash(instance),
+ instance->ob_type->tp_name,
+ method,
+ PyUnicode_AsUTF8(PyObject_Str(python_wrapper_last_result())));
+}
+
+long python_wrapper_get_attribute_long(PyObject* instance, const char* attr_name, long def)
+{
+ TRACE_CALL(__func__);
+
+ assert(instance);
+ assert(attr_name);
+ PyObject* attr = PyObject_GetAttrString(instance, attr_name);
+ if (attr && PyLong_Check(attr))
+ {
+ return PyLong_AsLong(attr);
+ }
+
+ return def;
+}
+
+gboolean python_wrapper_check_attribute(PyObject* instance, const char* attr_name)
+{
+ TRACE_CALL(__func__);
+
+ assert(instance);
+ assert(attr_name);
+ if (PyObject_HasAttrString(instance, attr_name))
+ {
+ return TRUE;
+ }
+
+ g_printerr("Python plugin instance is missing member: %s\n", attr_name);
+ return FALSE;
+}
+
+void* python_wrapper_malloc(int bytes)
+{
+ TRACE_CALL(__func__);
+
+ assert(bytes > 0);
+ assert(bytes <= REASONABLE_LIMIT_FOR_MALLOC);
+
+ void* result = malloc(bytes);
+
+ if (!result)
+ {
+ g_printerr("Unable to allocate %d bytes in memory!\n", bytes);
+ perror("malloc");
+ }
+
+ return result;
+}
+
+char* python_wrapper_copy_string_from_python(PyObject* string, Py_ssize_t len)
+{
+ TRACE_CALL(__func__);
+
+ char* result = NULL;
+ if (len <= 0 || string == NULL)
+ {
+ return NULL;
+ }
+
+ const char* py_str = PyUnicode_AsUTF8(string);
+ if (py_str)
+ {
+ const int label_size = sizeof(char) * (len + 1);
+ result = (char*)python_wrapper_malloc(label_size);
+ result[len] = '\0';
+ memcpy(result, py_str, len);
+ }
+
+ return result;
+}
+
+void python_wrapper_set_service(RemminaPluginService* service)
+{
+ remmina_plugin_service = service;
+}
+
+RemminaPluginService* python_wrapper_get_service(void)
+{
+ return remmina_plugin_service;
+}
+
+void python_wrapper_add_plugin(PyPlugin* plugin)
+{
+ TRACE_CALL(__func__);
+
+ if (!plugin_map)
+ {
+ plugin_map = g_ptr_array_new();
+ }
+
+ PyPlugin* test = python_wrapper_get_plugin(plugin->generic_plugin->name);
+ if (test)
+ {
+ g_printerr("A plugin named '%s' has already been registered! Skipping...", plugin->generic_plugin->name);
+ }
+ else
+ {
+ g_ptr_array_add(plugin_map, plugin);
+ }
+}
+
+RemminaTypeHint python_wrapper_to_generic(PyObject* field, gpointer* target)
+{
+ TRACE_CALL(__func__);
+
+ if (PyUnicode_Check(field))
+ {
+ Py_ssize_t len = PyUnicode_GetLength(field);
+
+ if (len > 0)
+ {
+ *target = python_wrapper_copy_string_from_python(field, len);
+ }
+ else
+ {
+ *target = "";
+ }
+
+ return REMMINA_TYPEHINT_STRING;
+ }
+ else if (PyBool_Check(field))
+ {
+ *target = python_wrapper_malloc(sizeof(long));
+ long* long_target = (long*)target;
+ *long_target = PyLong_AsLong(field);
+ return REMMINA_TYPEHINT_BOOLEAN;
+ }
+ else if (PyLong_Check(field))
+ {
+ *target = python_wrapper_malloc(sizeof(long));
+ long* long_target = (long*)target;
+ *long_target = PyLong_AsLong(field);
+ return REMMINA_TYPEHINT_SIGNED;
+ }
+ else if (PyTuple_Check(field))
+ {
+ Py_ssize_t len = PyTuple_Size(field);
+ if (len)
+ {
+ gpointer* dest = (gpointer*)python_wrapper_malloc(sizeof(gpointer) * (len + 1));
+ memset(dest, 0, sizeof(gpointer) * (len + 1));
+
+ for (Py_ssize_t i = 0; i < len; ++i)
+ {
+ PyObject* item = PyTuple_GetItem(field, i);
+ python_wrapper_to_generic(item, dest + i);
+ }
+
+ *target = dest;
+ }
+ return REMMINA_TYPEHINT_TUPLE;
+ }
+
+ *target = NULL;
+ return REMMINA_TYPEHINT_UNDEFINED;
+}
+
+PyPlugin* python_wrapper_get_plugin(const gchar* name)
+{
+ TRACE_CALL(__func__);
+
+ assert(plugin_map);
+ assert(name);
+
+ for (gint i = 0; i < plugin_map->len; ++i)
+ {
+ PyPlugin* plugin = (PyPlugin*)g_ptr_array_index(plugin_map, i);
+ if (plugin->generic_plugin && plugin->generic_plugin->name && g_str_equal(name, plugin->generic_plugin->name))
+ {
+ return plugin;
+ }
+ }
+
+ return NULL;
+}
+
+PyPlugin* python_wrapper_get_plugin_by_protocol_widget(RemminaProtocolWidget* gp)
+{
+ TRACE_CALL(__func__);
+
+ assert(plugin_map);
+ assert(gp);
+
+ const gchar* name = python_wrapper_get_service()->protocol_widget_get_name(gp);
+ if (!name) {
+ return NULL;
+ }
+
+ return python_wrapper_get_plugin(name);
+}
+
+void init_pygobject()
+{
+ pygobject_init(-1, -1, -1);
+}
+
+GtkWidget* new_pywidget(GObject* obj)
+{
+ return (GtkWidget*)pygobject_new(obj);
+}
+
+GtkWidget* get_pywidget(PyObject* obj)
+{
+ return (GtkWidget*)pygobject_get(obj);
+}