Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/Remmina/Remmina.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/remmina.c3
-rw-r--r--src/remmina_plugin_manager.c59
-rw-r--r--src/remmina_plugin_python.c124
-rw-r--r--src/remmina_plugin_python_module.c402
4 files changed, 355 insertions, 233 deletions
diff --git a/src/remmina.c b/src/remmina.c
index f1f28df43..4cb3f5d56 100644
--- a/src/remmina.c
+++ b/src/remmina.c
@@ -356,9 +356,6 @@ int main(int argc, char *argv[])
/* Initialize some Remmina parts needed also on a local instance for correct handle-local-options */
remmina_pref_init();
remmina_file_manager_init();
-
- remmina_plugin_manager_add_loader("so", remmina_plugin_native_load);
- remmina_plugin_manager_add_loader("py", remmina_plugin_python_load);
remmina_plugin_manager_init();
diff --git a/src/remmina_plugin_manager.c b/src/remmina_plugin_manager.c
index 3f51beb85..df762abb2 100644
--- a/src/remmina_plugin_manager.c
+++ b/src/remmina_plugin_manager.c
@@ -53,6 +53,8 @@
#include "remmina_widget_pool.h"
#include "rcw.h"
#include "remmina_plugin_manager.h"
+#include "remmina_plugin_native.h"
+#include "remmina_plugin_python.h"
#include "remmina_public.h"
#include "remmina_masterthread_exec.h"
#include "remmina/remmina_trace_calls.h"
@@ -68,9 +70,6 @@ static RemminaSecretPlugin *remmina_secret_plugin = NULL;
static const gchar *remmina_plugin_type_name[] =
{ N_("Protocol"), N_("Entry"), N_("File"), N_("Tool"), N_("Preference"), N_("Secret"), NULL };
-
-GPtrArray* remmina_plugin_loaders = NULL;
-
static gint remmina_plugin_manager_compare_func(RemminaPlugin **a, RemminaPlugin **b)
{
TRACE_CALL(__func__);
@@ -251,30 +250,24 @@ RemminaPluginService remmina_plugin_manager_service =
remmina_protocol_widget_get_profile_remote_height
};
-typedef struct {
- const gchar* filetype;
- const gchar* name;
-} RemminaPluginLoaderArgs;
-
const char *get_filename_ext(const char *filename) {
- const char *dot = strrchr(filename, '.');
+ const char* last = strrchr(filename, '/');
+ const char *dot = strrchr(last, '.');
if(!dot || dot == filename) return "";
return dot + 1;
}
-static void remmina_plugin_manager_use_loader(const RemminaPluginLoader* loader, const RemminaPluginLoaderArgs* args) {
- if (g_str_equal(loader->filetype, args->filetype)) {
- loader->func(&remmina_plugin_manager_service, args->name);
- }
-}
-
-static void remmina_plugin_manager_load_plugin(char *name)
+static void remmina_plugin_manager_load_plugin(const gchar *name)
{
const char* ext = get_filename_ext(name);
- RemminaPluginLoaderArgs args;
- args.filetype = ext;
- args.name = name;
- g_ptr_array_foreach(remmina_plugin_loaders, (GFunc)remmina_plugin_manager_use_loader, &args);
+
+ if (g_str_equal(G_MODULE_SUFFIX, ext)) {
+ remmina_plugin_native_load(&remmina_plugin_manager_service, name);
+ } else if (g_str_equal("py", ext)) {
+ remmina_plugin_python_load(&remmina_plugin_manager_service, name);
+ } else {
+ g_print("%s: Skip unsupported file type '%s'\n", name, ext);
+ }
}
static gint compare_secret_plugin_init_order(gconstpointer a, gconstpointer b)
@@ -321,7 +314,7 @@ void remmina_plugin_manager_init()
continue;
ptr++;
// TODO: Iterate plugin loaders to find out at runtime if we support it
- if (g_strcmp0(ptr, G_MODULE_SUFFIX) != 0 && !remmina_plugin_manager_supported(ptr))
+ if (!remmina_plugin_manager_loader_supported(ptr))
continue;
fullpath = g_strdup_printf(REMMINA_RUNTIME_PLUGINDIR "/%s", name);
remmina_plugin_manager_load_plugin(fullpath);
@@ -359,29 +352,9 @@ void remmina_plugin_manager_init()
g_slist_free(secret_plugins);
}
-gboolean remmina_plugin_manager_supported(const char *filetype) {
+gboolean remmina_plugin_manager_loader_supported(const char *filetype) {
TRACE_CALL(__func__);
- RemminaPluginLoader *loader;
- gint i;
-
- for (i = 0; i < remmina_plugin_loaders->len; i++) {
- loader = (RemminaPluginLoader*)g_ptr_array_index(remmina_plugin_loaders, i);
- if (g_strcmp0(loader->filetype, filetype) == 0) {
- g_print("Plugin type %s for %s is supported!\n", filetype, loader->filetype);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-void remmina_plugin_manager_add_loader(char *filetype, RemminaPluginLoaderFunc func) {
- if (!remmina_plugin_loaders)
- remmina_plugin_loaders = g_ptr_array_new();
-
- RemminaPluginLoader* loader = (RemminaPluginLoader*)malloc(sizeof(RemminaPluginLoader*));
- loader->filetype = filetype;
- loader->func = func;
- g_ptr_array_add(remmina_plugin_loaders, loader);
+ return g_str_equal("py", filetype) || g_str_equal(G_MODULE_SUFFIX, filetype);
}
RemminaPlugin* remmina_plugin_manager_get_plugin(RemminaPluginType type, const gchar *name)
diff --git a/src/remmina_plugin_python.c b/src/remmina_plugin_python.c
index 1a1273cbd..5e619d761 100644
--- a/src/remmina_plugin_python.c
+++ b/src/remmina_plugin_python.c
@@ -1,71 +1,111 @@
-#include "config.h"
-
-#include <gtk/gtk.h>
-
-#include "remmina/remmina_trace_calls.h"
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2009-2011 Vic Lee
+ * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
+ * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
+ *
+ * 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.
+ *
+ */
+/**
+ * @file remmina_plugin_python.c
+ * @brief Remmina Python plugin loader.
+ * @author Mathias Winterhalter
+ * @date 14.10.2020
+ *
+ * When Remmina discovers Python scripts in the plugin root folder the plugin manager
+ * passes the path to the Python plugin loader. There it gets exexuted and the plugin
+ * classes get mapped to "real" Remmina plugin instances.
+ *
+ * For the communication between Remmina and Python the python module called 'remmina'
+ * is initialized and loaded into the environment of the plugin script
+ * (@see remmina_plugin_python_module.c).
+ *
+ * @see http://www.remmina.org/wp for more information.
+ */
+#include <gtk/gtk.h>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
+#include <structmember.h>
+
#include "pygobject.h"
-#include "structmember.h"
+#include "config.h"
+#include "remmina/remmina_trace_calls.h"
#include "remmina_plugin_python.h"
#include "remmina_plugin_python_module.h"
+static int basename_no_ext(const char* in, char** out) {
+ const char* base = strrchr(in, '/');
+ if (base) base++;
+
+ const char* base_end = strrchr(base, '.');
+ if (!base_end) base_end = base + strlen(base);
+
+ int length = base_end - base;
+ int memsize = sizeof(char*) * ((length) + 1);
+ *out = (char*)malloc(memsize);
+ memset(*out, 0, memsize);
+ strncpy(*out, base, length);
+ (*out)[length] = '\0';
+
+ return length;
+}
void remmina_plugin_python_init(void) {
TRACE_CALL(__FUNC__);
- // Initialize Python environment
+
remmina_plugin_python_module_init();
Py_Initialize();
+
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('" REMMINA_RUNTIME_PLUGINDIR "')");
pygobject_init(-1, -1, -1);
}
-int basename_no_ext(const char* in, char** out) {
- // Find last segment of path...
- const char* end = in + strlen(in);
- const char* from = in;
- const char* to = end;
- for (const char* ptr = in; ptr != end; ++ptr) {
- if (*ptr == '/') {
- while (*ptr == '/' && ptr != end)
- ++ptr;
- if (ptr == end)
- return NULL;
- from = ptr;
- } else if (*ptr == '.') {
- to = ptr;
- }
- }
-
- int length = to - from;
- *out = (char*)malloc(sizeof(char*) * ((length) + 1));
- strncpy(*out, from, to-from);
- (*out)[length] = '\0';
- return length;
-}
-
-gboolean
-remmina_plugin_python_load(RemminaPluginService* service, const char* name) {
+gboolean remmina_plugin_python_load(RemminaPluginService* service, const char* name) {
TRACE_CALL(__FUNC__);
- PyObject *plugin_name, *plugin_file;
- PyObject *pArgs, *pValue;
- int i;
+
char* filename = NULL;
basename_no_ext(name, &filename);
- plugin_name = PyUnicode_DecodeFSDefault(filename);
- plugin_file = PyImport_Import(plugin_name);
- if (plugin_file != NULL) {
- return TRUE;
- } else {
- g_print("Failed to load \"%s\"\n", name);
+ PyObject *plugin_name = PyUnicode_DecodeFSDefault(filename);
+ free(filename);
+
+ if (!PyImport_Import(plugin_name)) {
+ g_print("Failed to load python plugin file: \"%s\"\n", name);
PyErr_Print();
return FALSE;
}
+
return TRUE;
}
diff --git a/src/remmina_plugin_python_module.c b/src/remmina_plugin_python_module.c
index 34100f40a..4d1c1598c 100644
--- a/src/remmina_plugin_python_module.c
+++ b/src/remmina_plugin_python_module.c
@@ -1,69 +1,190 @@
-#include "config.h"
+/*
+ * Remmina - The GTK+ Remote Desktop Client
+ * Copyright (C) 2009-2011 Vic Lee
+ * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo
+ * Copyright (C) 2016-2020 Antenore Gatta, Giovanni Panozzo
+ *
+ * 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.
+ *
+ */
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include "pygobject.h"
-#include "structmember.h"
+/**
+ * @file remmina_plugin_python_module.c
+ * @brief Implementation of the Python module 'remmina'.
+ * @author Mathias Winterhalter
+ * @date 14.10.2020
+ *
+ * The RemminaPluginService provides an API for plugins to interact with Remmina. The
+ * module called 'remmina' forwards this interface to make it accessible for Python
+ * scripts.
+ *
+ * This is an example of a minimal protocol plugin:
+ *
+ * @code
+ * import remmina
+ *
+ * class MyProtocol:
+ * def __init__(self):
+ * self.name = "MyProtocol"
+ * self.description = "Example protocol plugin to explain how Python plugins work."
+ * self.version = "0.1"
+ * self.icon_name = ""
+ * self.icon_name_ssh = ""
+ *
+ * def init(self, handle):
+ * print("This is getting logged to the standard output of Remmina.")
+ * remmina.log_print("For debugging purposes it would be better to log the output to the %s window %s!" % ("debug", ":)"))
+ * self.init_your_stuff(handle)
+ *
+ * def open_connection(self, handle):
+ * if not self.connect():
+ * remmina.log_print("Error! Can not connect...")
+ * return False
+ *
+ * remmina.remmina_signal_connected(handle)
+ * remmina.log_print("Connection established!")
+ * return True
+ *
+ *
+ * def close_connection(self, handle):
+ * self.disconnect()
+ * return True
+ *
+ * plugin = MyProtocol()
+ * remmina.register_plugin(plugin)
+ * @endcode
+ *
+ *
+ *
+ * @see http://www.remmina.org/wp for more information.
+ */
#include <glib.h>
#include <gtk/gtk.h>
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <structmember.h>
+
+#include "config.h"
+#include "pygobject.h"
#include "remmina_plugin_manager.h"
#include "remmina/plugin.h"
#include "remmina_protocol_widget.h"
-GPtrArray* remmina_plugin_registry = NULL;
+/**
+ * @brief Holds pairs of Python and Remmina plugin instances (PyPlugin).
+ */
+GPtrArray *remmina_plugin_registry = NULL;
typedef struct {
- PyObject* pythonInstance;
- RemminaProtocolPlugin* protocolPlugin;
-} PyPlugin;
+ PyObject_HEAD
+ RemminaProtocolWidget* gp;
+} PyRemminaProtocolWidget;
/**
- * A list of objects initialized and provided by the Remmina Python module.
+ * @brief Maps an instance of a Python plugin to a Remmina one.
*/
-static GPtrArray* remmina_python_module_object_table = NULL;
-static GPtrArray* remmina_python_module_member_table = NULL;
-
-static void remmina_protocol_plugin_wrapper_init(RemminaProtocolWidget *gp);
-static gboolean remmina_protocol_plugin_wrapper_open_connection(RemminaProtocolWidget *gp);
-static gboolean remmina_protocol_plugin_wrapper_close_connection(RemminaProtocolWidget *gp);
-static gboolean remmina_protocol_plugin_wrapper_query_feature(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature);
-static void remmina_protocol_plugin_wrapper_call_feature(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature);
-static void remmina_protocol_plugin_wrapper_send_keystrokes(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen);
-static gboolean remmina_protocol_plugin_wrapper_get_plugin_screenshot(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd);
-
-
-static void remmina_protocol_plugin_wrapper_init(RemminaProtocolWidget *gp) {
+typedef struct {
+ PyObject *pythonInstance;
-}
-
-static gboolean remmina_protocol_plugin_wrapper_open_connection(RemminaProtocolWidget *gp) {
- return FALSE;
-}
-
-static gboolean remmina_protocol_plugin_wrapper_close_connection(RemminaProtocolWidget *gp) {
- return FALSE;
-}
-
-static gboolean remmina_protocol_plugin_wrapper_query_feature(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature) {
- return TRUE;
-}
+ RemminaProtocolPlugin *protocolPlugin;
+ //@TODO: Add more plugin types
+ PyRemminaProtocolWidget *gp;
+} PyPlugin;
-static void remmina_protocol_plugin_wrapper_call_feature(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature) {
-}
+/**
+ * @brief Wraps the log_printf function of RemminaPluginService.
+ *
+ * @details This function is only called by the Python engine! There is only one argument
+ * since Python offers an inline string formatting which renders any formatting capabilities
+ * redundant.
+ *
+ * @param self Is always NULL since it is a static function of the 'remmina' module
+ * @param msg The message to print.
+ */
+static PyObject* remmina_plugin_python_log_printf_wrapper(PyObject* self, PyObject* msg);
-static void remmina_protocol_plugin_wrapper_send_keystrokes(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen) {
+/**
+ * @brief Accepts an instance of a Python class representing a Remmina plugin.
+ *
+ * @details This function is only called by the Python engine!
+ *
+ * @param self Is always NULL since it is a static function of the 'remmina' module
+ * @param plugin An instance of a Python plugin class.
+ */
+static PyObject* remmina_plugin_python_register_plugin(PyObject* self, PyObject* plugin);
-}
+/**
+ * @brief Retrieves the viewport of the current connection window if available.
+ *
+ * @details This function is only called by the Python engine!
+ *
+ * @param self Is always NULL since it is a static function of the 'remmina' module
+ * @param plugin The handle to retrieve the RemminaConnectionWidget
+ */
+static PyObject* remmina_plugin_python_get_viewport(PyObject* self, PyObject* handle);
-static gboolean remmina_protocol_plugin_wrapper_get_plugin_screenshot(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd) {
- return TRUE;
-}
+/**
+ * @brief Initializes the 'remmina' module
+ * @details This function is only called by the Python engine!
+ */
+PyMODINIT_FUNC remmina_plugin_python_module_initialize(void);
+/**
+ * @brief The functions of the remmina module.
+ *
+ * @details If any function has to be added this is the place to do it. This list is referenced
+ * by the PyModuleDef (describing the module) instance below.
+ */
+static PyMethodDef remmina_python_module_type_methods[] = {
+ // @TODO: Add all functions from RemminaPluginService
+ {"register_plugin", (PyCFunction)remmina_plugin_python_register_plugin, METH_O, NULL },
+ {"log_print", (PyCFunction)remmina_plugin_python_log_printf_wrapper, METH_VARARGS, NULL },
+ {"get_viewport", (PyCFunction)remmina_plugin_python_get_viewport, METH_O, NULL },
+ {NULL} /* Sentinel */
+};
+/**
+ * @brief The definition of the Python module 'remmina'.
+ */
+static PyModuleDef remmina_python_module_type = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "remmina",
+ .m_doc = "Remmina API.",
+ .m_size = -1,
+ .m_methods = remmina_python_module_type_methods
+};
-static PyObject* remmina_plugin_python_log_printf_wrapper(PyObject* self, PyObject* n) {
+static PyObject* remmina_plugin_python_log_printf_wrapper(PyObject* self, PyObject* n)
+{
+ TRACE_CALL(__func__);
char* fmt = NULL;
if (!PyArg_ParseTuple(n, "s", &fmt)) {
g_print("Failed to load.\n");
@@ -76,148 +197,139 @@ static PyObject* remmina_plugin_python_log_printf_wrapper(PyObject* self, PyObje
return Py_None;
}
-static void remmina_protocol_init_wrapper(RemminaProtocolWidget *gp);
-static void remmina_protocol_basic_settings_wrapper(RemminaProtocolWidget *gp);
-static void remmina_protocol_features_wrapper(RemminaProtocolWidget *gp);
-static gboolean remmina_protocol_open_connection_wrapper(RemminaProtocolWidget *gp);
-static gboolean remmina_protocol_close_connection_wrapper(RemminaProtocolWidget *gp);
-static gboolean remmina_protocol_query_feature_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature);
-static void remmina_protocol_call_feature_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature);
-static void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen);
-static gboolean remmina_protocol_get_plugin_screensho_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd);
-
-static PyObject* remmina_plugin_python_register_plugin(PyObject* self, PyObject* pluginInstance) {
- if (pluginInstance) {
- g_ptr_array_add(remmina_plugin_registry, pluginInstance);
-
- /* Protocol plugin definition and features */
- RemminaProtocolPlugin* remmina_plugin = (RemminaProtocolPlugin*)malloc(sizeof(RemminaProtocolPlugin));
- remmina_plugin->type = REMMINA_PLUGIN_TYPE_PROTOCOL;
- remmina_plugin->name = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "name")); // Name
- remmina_plugin->description = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "description")); // Description
- remmina_plugin->domain = GETTEXT_PACKAGE; // Translation domain
- remmina_plugin->version = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "version")); // Version number
- remmina_plugin->icon_name = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "icon_name")); // Icon for normal connection
- remmina_plugin->icon_name_ssh = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "icon_name_ssh")); // Icon for SSH connection
- remmina_plugin->basic_settings = NULL; // Array for basic settings
- remmina_plugin->advanced_settings = NULL; // Array for advanced settings
- remmina_plugin->ssh_setting = REMMINA_PROTOCOL_SSH_SETTING_TUNNEL; // SSH settings type
- remmina_plugin->features = NULL; // Array for available features
- remmina_plugin->init = remmina_protocol_init_wrapper ; // Plugin initialization
- remmina_plugin->open_connection = remmina_protocol_open_connection_wrapper ; // Plugin open connection
- remmina_plugin->close_connection = remmina_protocol_close_connection_wrapper ; // Plugin close connection
- remmina_plugin->query_feature = remmina_protocol_query_feature_wrapper ; // Query for available features
- remmina_plugin->call_feature = remmina_protocol_call_feature_wrapper ; // Call a feature
- remmina_plugin->send_keystrokes = remmina_protocol_send_keytrokes_wrapper; // Send a keystroke
- remmina_plugin->get_plugin_screenshot = remmina_protocol_get_plugin_screensho_wrapper; // Screenshot support unavailable
-
- remmina_plugin_manager_service.register_plugin((RemminaPlugin *)remmina_plugin);
-
- PyPlugin* plugin = (PyPlugin*)malloc(sizeof(PyPlugin));
- plugin->protocolPlugin = remmina_plugin;
- plugin->pythonInstance = pluginInstance;
- g_ptr_array_add(remmina_plugin_registry, plugin);
- }
-
- return Py_None;
+static PyObject* remmina_plugin_python_get_viewport(PyObject* self, PyObject* handle) {
+ PyRemminaProtocolWidget *gp = (PyRemminaProtocolWidget*)handle;
+ return pygobject_new(G_OBJECT(remmina_protocol_widget_gtkviewport(gp->gp)));
}
-static PyMethodDef remmina_python_module_type_methods[] = {
- {"register_plugin", (PyCFunction)remmina_plugin_python_register_plugin, METH_O, NULL },
- {"log_print", (PyCFunction)remmina_plugin_python_log_printf_wrapper, METH_VARARGS, NULL },
- {NULL} /* Sentinel */
-};
-
-static PyModuleDef remmina_python_module_type = {
- PyModuleDef_HEAD_INIT,
- .m_name = "remmina",
- .m_doc = "Remmina API.",
- .m_size = -1,
- .m_methods = remmina_python_module_type_methods
-};
-
/**
- *
+ * @brief Initializes the remmina module and maps it to the Python engine.
*/
-PyMODINIT_FUNC remmina_plugin_python_module_initialize(void);
-
-void remmina_plugin_python_module_init(void) {
+void remmina_plugin_python_module_init(void)
+{
+ TRACE_CALL(__func__);
remmina_plugin_registry = g_ptr_array_new();
- if (PyImport_AppendInittab("remmina", remmina_plugin_python_module_initialize))
- return FALSE;
-
-}
-
-PyMODINIT_FUNC remmina_plugin_python_module_initialize(void) {
- PyObject* module_instance = NULL;
- PyTypeObject* builtin;
- PyMethodDef* method;
- gint i;
-
- module_instance = PyModule_Create(&remmina_python_module_type);
-
- if (remmina_python_module_object_table) {
- for (i = 0; i < remmina_python_module_object_table->len; i++) {
- builtin = (PyTypeObject*)g_ptr_array_index(remmina_python_module_object_table, i);
- if (builtin) {
- Py_INCREF(builtin);
- if (PyModule_AddObject(module_instance, "ProtocolPlugin", (PyObject*)builtin)) {
- printf("%s: Error initializing\n", builtin->tp_name);
- Py_INCREF(builtin);
- }
- }
- }
+ if (PyImport_AppendInittab("remmina", remmina_plugin_python_module_initialize)) {
+ g_print("Error initializing remmina module for python!\n");
+ PyErr_Print();
+ return;
}
+}
- // TODO: Initialize Remmina module for Python
- return module_instance;
+PyMODINIT_FUNC remmina_plugin_python_module_initialize(void)
+{
+ TRACE_CALL(__func__);
+ return PyModule_Create(&remmina_python_module_type);
}
-static void remmina_protocol_init_executor(PyPlugin* plugin, RemminaProtocolWidget *gp) {
+/**
+ *
+ */
+static void remmina_protocol_init_executor(PyPlugin* plugin, RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
if (g_str_equal(plugin->protocolPlugin->name, gp->plugin->name)) {
- PyObject_CallMethod(plugin->pythonInstance, "init", NULL);
+ plugin->gp->gp = gp;
+ PyObject_CallMethod(plugin->pythonInstance, "init", "O", plugin);
}
}
-static void remmina_protocol_init_wrapper(RemminaProtocolWidget *gp) {
+static void remmina_protocol_init_wrapper(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
g_ptr_array_foreach(remmina_plugin_registry, (GFunc)remmina_protocol_init_executor, gp);
}
static PyObject* remmina_protocol_open_connection_executor_result = NULL;
-static void remmina_protocol_open_connection_executor(PyPlugin* plugin, RemminaProtocolWidget *gp) {
+static void remmina_protocol_open_connection_executor(PyPlugin* plugin, RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
if (g_str_equal(plugin->protocolPlugin->name, gp->plugin->name)) {
- remmina_protocol_open_connection_executor_result = PyObject_CallMethod(plugin->pythonInstance, "open_connection", "O", pygobject_new(G_OBJECT(remmina_protocol_widget_gtkviewport(gp))));
+ remmina_protocol_open_connection_executor_result = PyObject_CallMethod(plugin->pythonInstance, "open_connection", "O", plugin);
}
}
-static gboolean remmina_protocol_open_connection_wrapper(RemminaProtocolWidget *gp) {
+static gboolean remmina_protocol_open_connection_wrapper(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
remmina_plugin_manager_service.protocol_plugin_signal_connection_opened(gp);
g_ptr_array_foreach(remmina_plugin_registry, (GFunc)remmina_protocol_open_connection_executor, gp);
return remmina_protocol_open_connection_executor_result == Py_True;
}
static PyObject* remmina_protocol_close_connection_executor_result = NULL;
-static void remmina_protocol_close_connection_executor(PyPlugin* plugin, RemminaProtocolWidget *gp) {
+static void remmina_protocol_close_connection_executor(PyPlugin* plugin, RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
if (g_str_equal(plugin->protocolPlugin->name, gp->plugin->name)) {
- remmina_protocol_close_connection_executor_result = PyObject_CallMethod(plugin->pythonInstance, "close_connection","O", pygobject_new(G_OBJECT(remmina_protocol_widget_get_gtkwindow(gp))));
+ remmina_protocol_close_connection_executor_result = PyObject_CallMethod(plugin->pythonInstance, "close_connection", "O", plugin);
}
}
-static gboolean remmina_protocol_close_connection_wrapper(RemminaProtocolWidget *gp) {
+static gboolean remmina_protocol_close_connection_wrapper(RemminaProtocolWidget *gp)
+{
+ TRACE_CALL(__func__);
g_ptr_array_foreach(remmina_plugin_registry, (GFunc)remmina_protocol_close_connection_executor, gp);
return remmina_protocol_close_connection_executor_result == Py_True;
}
-static gboolean remmina_protocol_query_feature_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature) {
+static gboolean remmina_protocol_query_feature_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
+{
+ TRACE_CALL(__func__);
return TRUE;
}
-static void remmina_protocol_call_feature_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature) {
+static void remmina_protocol_call_feature_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature)
+{
+ TRACE_CALL(__func__);
return;
}
-static void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen) {
+static void remmina_protocol_send_keytrokes_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen)
+{
+ TRACE_CALL(__func__);
return;
}
-static gboolean remmina_protocol_get_plugin_screensho_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd) {
+static gboolean remmina_protocol_get_plugin_screensho_wrapper(RemminaProtocolPlugin* plugin, RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd)
+{
+ TRACE_CALL(__func__);
return TRUE;
}
+static PyObject* remmina_plugin_python_register_plugin(PyObject* self, PyObject* pluginInstance)
+{
+ TRACE_CALL(__func__);
+ if (pluginInstance) {
+ g_ptr_array_add(remmina_plugin_registry, pluginInstance);
+
+ /* Protocol plugin definition and features */
+ RemminaProtocolPlugin* remmina_plugin = (RemminaProtocolPlugin*)malloc(sizeof(RemminaProtocolPlugin));
+ remmina_plugin->type = REMMINA_PLUGIN_TYPE_PROTOCOL;
+ remmina_plugin->name = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "name")); // Name
+ remmina_plugin->description = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "description")); // Description
+ remmina_plugin->domain = GETTEXT_PACKAGE; // Translation domain
+ remmina_plugin->version = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "version")); // Version number
+ remmina_plugin->icon_name = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "icon_name")); // Icon for normal connection
+ remmina_plugin->icon_name_ssh = PyUnicode_AsUTF8(PyObject_GetAttrString(pluginInstance, "icon_name_ssh")); // Icon for SSH connection
+ remmina_plugin->basic_settings = NULL; // Array for basic settings
+ remmina_plugin->advanced_settings = NULL; // Array for advanced settings
+ remmina_plugin->ssh_setting = REMMINA_PROTOCOL_SSH_SETTING_TUNNEL; // SSH settings type
+ remmina_plugin->features = NULL; // Array for available features
+ remmina_plugin->init = remmina_protocol_init_wrapper ; // Plugin initialization
+ remmina_plugin->open_connection = remmina_protocol_open_connection_wrapper ; // Plugin open connection
+ remmina_plugin->close_connection = remmina_protocol_close_connection_wrapper ; // Plugin close connection
+ remmina_plugin->query_feature = remmina_protocol_query_feature_wrapper ; // Query for available features
+ remmina_plugin->call_feature = remmina_protocol_call_feature_wrapper ; // Call a feature
+ remmina_plugin->send_keystrokes = remmina_protocol_send_keytrokes_wrapper; // Send a keystroke
+ remmina_plugin->get_plugin_screenshot = remmina_protocol_get_plugin_screensho_wrapper; // Screenshot support unavailable
+
+ remmina_plugin_manager_service.register_plugin((RemminaPlugin *)remmina_plugin);
+
+ PyPlugin* plugin = (PyPlugin*)malloc(sizeof(PyPlugin));
+ plugin->protocolPlugin = remmina_plugin;
+ plugin->pythonInstance = pluginInstance;
+ plugin->gp = malloc(sizeof(PyRemminaProtocolWidget));
+ plugin->gp->gp = NULL;
+ g_ptr_array_add(remmina_plugin_registry, plugin);
+ }
+
+ return Py_None;
+} \ No newline at end of file