diff options
Diffstat (limited to 'plugins/gvnc')
-rw-r--r-- | plugins/gvnc/CMakeLists.txt | 54 | ||||
-rw-r--r-- | plugins/gvnc/gvnc_plugin.c | 941 | ||||
-rw-r--r-- | plugins/gvnc/gvnc_plugin.h | 131 | ||||
-rw-r--r-- | plugins/gvnc/gvnc_plugin_config.h | 43 | ||||
-rw-r--r-- | plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-ssh-symbolic.svg | 90 | ||||
-rw-r--r-- | plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-symbolic.svg | 115 |
6 files changed, 1374 insertions, 0 deletions
diff --git a/plugins/gvnc/CMakeLists.txt b/plugins/gvnc/CMakeLists.txt new file mode 100644 index 0000000..ca5c1cd --- /dev/null +++ b/plugins/gvnc/CMakeLists.txt @@ -0,0 +1,54 @@ +# remmina-plugin-gvnc - The GTK+ Remote Desktop Client +# +# Copyright (C) 2016-2023 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. + +set(REMMINA_PLUGIN_GVNC_SRCS + gvnc_plugin_config.h + gvnc_plugin.h + gvnc_plugin.c + ) + +add_library(remmina-plugin-gvnc MODULE ${REMMINA_PLUGIN_GVNC_SRCS}) +set_target_properties(remmina-plugin-gvnc PROPERTIES PREFIX "") +set_target_properties(remmina-plugin-gvnc PROPERTIES NO_SONAME 1) + +include_directories(${REMMINA_COMMON_INCLUDE_DIRS} ${GTK-VNC_INCLUDE_DIRS}) +target_link_libraries(remmina-plugin-gvnc ${REMMINA_COMMON_LIBRARIES} ${GTK-VNC_LIBRARIES}) + +install(TARGETS remmina-plugin-gvnc DESTINATION ${REMMINA_PLUGINDIR}) + +install(FILES + scalable/emblems/org.remmina.Remmina-gvnc-symbolic.svg + DESTINATION ${APPICONSCALE_EMBLEMS_DIR}) + +if(WITH_ICON_CACHE) + gtk_update_icon_cache("${REMMINA_DATADIR}/icons/hicolor") +endif() diff --git a/plugins/gvnc/gvnc_plugin.c b/plugins/gvnc/gvnc_plugin.c new file mode 100644 index 0000000..14cead9 --- /dev/null +++ b/plugins/gvnc/gvnc_plugin.c @@ -0,0 +1,941 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2016-2023 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. + * + */ + +#include "gvnc_plugin_config.h" +#include "gvnc_plugin.h" + +#include <vncdisplay.h> +#include <vncutil.h> +#include <vncaudiopulse.h> + +#define GVNC_DEFAULT_PORT 5900 + +#ifndef VNC_CHECK_VERSION +# define VNC_CHECK_VERSION(a, b, c) 0 +#endif +#if VNC_CHECK_VERSION(1, 2, 0) +# define HAVE_VNC_REMOTE_RESIZE +# define HAVE_VNC_POWER_CONTROL +#endif + +enum { + GVNC_PLUGIN_FEATURE_PREF_VIEWONLY = 1, + GVNC_PLUGIN_FEATURE_DYNRESUPDATE, + GVNC_PLUGIN_FEATURE_PREF_DISABLECLIPBOARD, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTDEL, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTBACKSPACE, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF1, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF2, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF3, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF4, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF5, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF6, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF7, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF8, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF9, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF10, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF11, + GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF12, +#ifdef HAVE_VNC_POWER_CONTROL + GVNC_PLUGIN_FEATURE_TOOL_REBOOT, + GVNC_PLUGIN_FEATURE_TOOL_RESET, + GVNC_PLUGIN_FEATURE_TOOL_SHUTDOWN, +#endif + GVNC_PLUGIN_FEATURE_SCALE +}; + + +static RemminaPluginService *remmina_plugin_service = NULL; + +gchar* str_replace(const gchar *string, const gchar *search, const gchar *replacement) +{ + TRACE_CALL(__func__); + gchar *str, **arr; + + g_return_val_if_fail(string != NULL, NULL); + g_return_val_if_fail(search != NULL, NULL); + + if (replacement == NULL) + replacement = ""; + + arr = g_strsplit(string, search, -1); + if (arr != NULL && arr[0] != NULL) + str = g_strjoinv(replacement, arr); + else + str = g_strdup(string); + + g_strfreev(arr); + return str; +} + +/* Send a keystroke to the plugin window */ +static void gvnc_plugin_keystroke(RemminaProtocolWidget *gp, const guint keystrokes[], const gint keylen) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + if (gpdata->vnc) { + vnc_display_send_keys(VNC_DISPLAY(gpdata->vnc), + keystrokes, + keylen); + } +} + +#ifdef HAVE_VNC_POWER_CONTROL +static void gvnc_plugin_power_ctrl(RemminaProtocolWidget *gp, VncConnectionPowerAction action) +{ + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + VncConnection *conn = vnc_display_get_connection(VNC_DISPLAY(gpdata->vnc)); + + if (!vnc_connection_get_power_control(conn)) { + REMMINA_PLUGIN_DEBUG("Power control not available on this server"); + return; + } + vnc_connection_power_control(conn, action); +} +#endif + + +static void gvnc_plugin_mouse_grab(GtkWidget *vncdisplay, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + VncGrabSequence *seq = vnc_display_get_grab_keys(VNC_DISPLAY(gpdata->vnc)); + gchar *seqstr = vnc_grab_sequence_as_string(seq); + + REMMINA_PLUGIN_DEBUG("Pointer grabbed: %s", seqstr); +} + +static void gvnc_plugin_mouse_ungrab(GtkWidget *vncdisplay, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + REMMINA_PLUGIN_DEBUG("Pointer ungrabbed"); +} + +static void gvnc_plugin_on_vnc_error(GtkWidget *vncdisplay G_GNUC_UNUSED, const gchar *msg, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + REMMINA_PLUGIN_DEBUG("Error: %s\n", msg); + /* "vnc-error" is always followed by "vnc-disconnected", + * so save the error for that signal */ + g_free(gpdata->error_msg); + gpdata->error_msg = g_strdup(msg); +} + +static gboolean gvnc_plugin_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd) __attribute__ ((unused)); +static gboolean gvnc_plugin_get_screenshot(RemminaProtocolWidget *gp, RemminaPluginScreenshotData *rpsd) +{ + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + //gsize szmem; + const VncPixelFormat *currentFormat; + //GError *err = NULL; + + if (!gpdata) + return FALSE; + + /* Get current pixel format for server */ + currentFormat = vnc_connection_get_pixel_format(gpdata->conn); + + + GdkPixbuf *pix = vnc_display_get_pixbuf(VNC_DISPLAY(gpdata->vnc)); + + rpsd->width = gdk_pixbuf_get_width(pix); + rpsd->height = gdk_pixbuf_get_height(pix); + rpsd->bitsPerPixel = currentFormat->bits_per_pixel; + rpsd->bytesPerPixel = rpsd->bitsPerPixel / 8; + //szmem = gdk_pixbuf_get_byte_length(pix); + + //szmem = rpsd->width * rpsd->height * rpsd->bytesPerPixel; + + //REMMINA_PLUGIN_DEBUG("allocating %zu bytes for a full screenshot", szmem); + //REMMINA_PLUGIN_DEBUG("Calculated screenshot size: %zu", szcalc); + //rpsd->buffer = malloc(szmem); + + //memcpy(rpsd->buffer, pix, szmem); + //gdk_pixbuf_save_to_buffer(pix, &rpsd->buffer, &szmem, "jpeg", &err, "quality", "100", NULL); + + + /* Returning TRUE instruct also the caller to deallocate rpsd->buffer */ + return TRUE; +} + +void gvnc_plugin_paste_text(RemminaProtocolWidget *gp, const gchar *text) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + gchar *out; + gsize a, b; + GError *error = NULL; + + if (!gpdata) return; + + out = g_convert_with_fallback(text, -1, "iso8859-1//TRANSLIT", "utf-8", NULL, &a, &b, &error); + if (out) { + REMMINA_PLUGIN_DEBUG("Pasting text"); + vnc_display_client_cut_text(VNC_DISPLAY(gpdata->vnc), out); + g_free(out); + } else { + REMMINA_PLUGIN_DEBUG("Error pasting text: %s", error->message); + g_error_free(error); + } +} + +static void gvnc_plugin_clipboard_cb(GtkClipboard *cb, GdkEvent *event, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + //GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + gchar *text; + + REMMINA_PLUGIN_DEBUG("owner-change event received"); + + if (cb && gtk_clipboard_get_owner(cb) == (GObject *)gp) + return; + + text = gtk_clipboard_wait_for_text(cb); + if (!text) + return; + + gvnc_plugin_paste_text(gp, text); + g_free(text); +} + + +/* text was actually requested */ +static void gvnc_plugin_clipboard_copy(GtkClipboard *clipboard G_GNUC_UNUSED, GtkSelectionData *data, guint info G_GNUC_UNUSED, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + if (!gpdata) return; + gtk_selection_data_set_text(data, gpdata->clipstr, -1); + REMMINA_PLUGIN_DEBUG("Text copied"); +} + +static void gvnc_plugin_cut_text(VncDisplay *vnc G_GNUC_UNUSED, const gchar *text, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + REMMINA_PLUGIN_DEBUG("Got clipboard request for ā%sā", text); + + GtkClipboard *cb; + gsize a, b; + GtkTargetEntry targets[] = { + { g_strdup("UTF8_STRING"), 0, 0 }, + { g_strdup("COMPOUND_TEXT"), 0, 0 }, + { g_strdup("TEXT"), 0, 0 }, + { g_strdup("STRING"), 0, 0 }, + }; + + if (!text) + return; + g_free(gpdata->clipstr); + gpdata->clipstr = g_convert(text, -1, "utf-8", "iso8859-1", &a, &b, NULL); + + if (gpdata->clipstr) { + cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + + REMMINA_PLUGIN_DEBUG("setting clipboard with owner to owner %p", gp); + gtk_clipboard_set_with_owner(cb, + targets, + G_N_ELEMENTS(targets), + (GtkClipboardGetFunc)gvnc_plugin_clipboard_copy, + NULL, + G_OBJECT(gp)); + } + + //g_signal_emit_by_name(session, "session-cut-text", text); +} + + +static void gvnc_plugin_desktop_resize(GtkWidget *vncdisplay G_GNUC_UNUSED, int width, int height, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + REMMINA_PLUGIN_DEBUG("Remote desktop size changed to %dx%d\n", width, height); + REMMINA_PLUGIN_DEBUG("Desktop size is set to %dx%d\n", gpdata->width, gpdata->height); + remmina_plugin_service->protocol_plugin_set_width(gp, width); + remmina_plugin_service->protocol_plugin_set_height(gp, height); + + remmina_plugin_service->protocol_plugin_desktop_resize(gp); +} + +static void gvnc_plugin_on_bell(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + REMMINA_PLUGIN_DEBUG("Bell message received"); + //GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + if (remmina_plugin_service->file_get_int(remminafile, "disableserverbell", FALSE)) + return; + GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(gp)); + + if (window) + gdk_window_beep(window); + REMMINA_PLUGIN_DEBUG("Beep emitted"); +} +static void gvnc_plugin_update_scale_mode(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + RemminaScaleMode scaleMode = remmina_plugin_service->remmina_protocol_widget_get_current_scale_mode(gp); + +#if 0 + g_object_set(gpdata->display, + "scaling", (scaleMode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED), + "resize-guest", (scaleMode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES), + NULL); +#endif + if (scaleMode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_SCALED || scaleMode == REMMINA_PROTOCOL_WIDGET_SCALE_MODE_DYNRES) + vnc_display_set_scaling(VNC_DISPLAY(gpdata->vnc), TRUE); + else + vnc_display_set_scaling(VNC_DISPLAY(gpdata->vnc), FALSE); + + //width = remmina_plugin_service->protocol_plugin_get_width(gp); + //height = remmina_plugin_service->protocol_plugin_get_height(gp); + gpdata->width = vnc_display_get_width(VNC_DISPLAY(gpdata->vnc)); + gpdata->height = vnc_display_get_height(VNC_DISPLAY(gpdata->vnc)); + + if (scaleMode != REMMINA_PROTOCOL_WIDGET_SCALE_MODE_NONE) { + /* In scaled mode, the VncDisplay will get its dimensions from its parent */ + gtk_widget_set_size_request(GTK_WIDGET(gpdata->vnc), -1, -1); + } else { + /* In non scaled mode, the plugins forces dimensions of the VncDisplay */ +#if 0 + g_object_get(gpdata->display_channel, + "width", &width, + "height", &height, + NULL); + gtk_widget_set_size_request(GTK_WIDGET(gpdata->vnc), width, height); +#endif + gtk_widget_set_size_request(GTK_WIDGET(gpdata->vnc), gpdata->width, gpdata->height); + } + remmina_plugin_service->protocol_plugin_update_align(gp); +} + +static gboolean gvnc_plugin_query_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature) +{ + TRACE_CALL(__func__); + + return TRUE; +} + +static void gvnc_plugin_call_feature(RemminaProtocolWidget *gp, const RemminaProtocolFeature *feature) +{ + TRACE_CALL(__func__); + + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + guint keys[3]; + + switch (feature->id) { + case GVNC_PLUGIN_FEATURE_PREF_VIEWONLY: + gpdata->viewonly = remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE); + break; + case GVNC_PLUGIN_FEATURE_DYNRESUPDATE: + case GVNC_PLUGIN_FEATURE_SCALE: + gvnc_plugin_update_scale_mode(gp); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTDEL: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_Delete; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTBACKSPACE: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_BackSpace; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF1: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F1; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF2: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F2; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF3: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F3; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF4: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F4; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF5: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F5; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF6: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F6; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF7: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F7; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF9: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F9; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF10: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F10; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF11: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F11; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF12: + keys[0] = GDK_KEY_Control_L; + keys[1] = GDK_KEY_Alt_L; + keys[2] = GDK_KEY_F12; + gvnc_plugin_keystroke(gp, keys, G_N_ELEMENTS(keys)); + break; +#ifdef HAVE_VNC_POWER_CONTROL + case GVNC_PLUGIN_FEATURE_TOOL_REBOOT: + gvnc_plugin_power_ctrl(gp, VNC_CONNECTION_POWER_ACTION_REBOOT); + break; + case GVNC_PLUGIN_FEATURE_TOOL_RESET: + gvnc_plugin_power_ctrl(gp, VNC_CONNECTION_POWER_ACTION_RESET); + break; + case GVNC_PLUGIN_FEATURE_TOOL_SHUTDOWN: + gvnc_plugin_power_ctrl(gp, VNC_CONNECTION_POWER_ACTION_SHUTDOWN); + break; +#endif + default: + break; + } +} + +static void gvnc_plugin_auth_unsupported(VncDisplay *vnc G_GNUC_UNUSED, unsigned int authType, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + g_clear_pointer(&gpdata->error_msg, g_free); + gchar *msg = g_strdup_printf(_("Unsupported authentication type %u"), authType); + + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", msg); + g_free(msg); +} + +static void gvnc_plugin_auth_failure(VncDisplay *vnc G_GNUC_UNUSED, const gchar *reason, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + g_clear_pointer(&gpdata->error_msg, g_free); + gchar *msg = g_strdup_printf(_("Authentication failure: %s"), reason); + + remmina_plugin_service->protocol_plugin_set_error(gp, "%s", msg); + g_free(msg); +} + +static gboolean gvnc_plugin_ask_auth(GtkWidget *vncdisplay, GValueArray *credList, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + + gint ret; + gboolean disablepasswordstoring; + gchar *s_username = NULL, *s_password = NULL; + gboolean wantPassword = FALSE, wantUsername = FALSE; + int i; + gboolean save; + + + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + + GArray *credArray = g_array_sized_new(FALSE, TRUE, sizeof(GValue), credList->n_values); + g_array_set_clear_func(credArray, (GDestroyNotify) g_value_unset); + g_array_append_vals(credArray, credList->values, credList->n_values); + + REMMINA_PLUGIN_DEBUG("Got credential request for %d credential(s)\n", credArray->len); + + for (i = 0 ; i < credArray->len ; i++) { + GValue *cred = &g_array_index(credArray, GValue, i); + switch (g_value_get_enum(cred)) { + case VNC_DISPLAY_CREDENTIAL_USERNAME: + wantUsername = TRUE; + break; + case VNC_DISPLAY_CREDENTIAL_PASSWORD: + wantPassword = TRUE; + break; + case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: + break; + default: + REMMINA_PLUGIN_DEBUG("Unsupported credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(gpdata->vnc)); + goto cleanup; + } + } + disablepasswordstoring = remmina_plugin_service->file_get_int(remminafile, "disablepasswordstoring", FALSE); + + ret = remmina_plugin_service->protocol_plugin_init_auth(gp, + (disablepasswordstoring ? 0 : REMMINA_MESSAGE_PANEL_FLAG_SAVEPASSWORD) + | (wantUsername ? REMMINA_MESSAGE_PANEL_FLAG_USERNAME : 0), + _("Enter VNC authentication credentials"), + (wantUsername ? remmina_plugin_service->file_get_string(remminafile, "username") : NULL), + (wantPassword ? remmina_plugin_service->file_get_string(remminafile, "password") : NULL), + NULL, + NULL); + if (ret == GTK_RESPONSE_OK) { + s_username = remmina_plugin_service->protocol_plugin_init_get_username(gp); + s_password = remmina_plugin_service->protocol_plugin_init_get_password(gp); + remmina_plugin_service->file_set_string(remminafile, "username", s_username); + + save = remmina_plugin_service->protocol_plugin_init_get_savepassword(gp); + if (save) { + // User has requested to save credentials. We put the password + // into remminafile->settings. It will be saved later, on successful connection, by + // rcw.c + remmina_plugin_service->file_set_string(remminafile, "password", s_password); + } else { + remmina_plugin_service->file_set_string(remminafile, "password", NULL); + } + + for (i = 0 ; i < credArray->len ; i++) { + GValue *cred = &g_array_index(credArray, GValue, i); + switch (g_value_get_enum(cred)) { + case VNC_DISPLAY_CREDENTIAL_USERNAME: + if (!s_username || + vnc_display_set_credential(VNC_DISPLAY(gpdata->vnc), + g_value_get_enum(cred), + s_username)) { + g_debug("Failed to set credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(gpdata->vnc)); + } + break; + case VNC_DISPLAY_CREDENTIAL_PASSWORD: + if (!s_password || + vnc_display_set_credential(VNC_DISPLAY(gpdata->vnc), + g_value_get_enum(cred), + s_password)) { + g_debug("Failed to set credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(gpdata->vnc)); + } + break; + case VNC_DISPLAY_CREDENTIAL_CLIENTNAME: + if (vnc_display_set_credential(VNC_DISPLAY(gpdata->vnc), + g_value_get_enum(cred), + "remmina")) { + g_debug("Failed to set credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(gpdata->vnc)); + } + break; + default: + g_debug("Unsupported credential type %d", g_value_get_enum(cred)); + vnc_display_close(VNC_DISPLAY(gpdata->vnc)); + } + } + + if (s_username) g_free(s_username); + if (s_password) g_free(s_password); + + return TRUE; + } else { + return FALSE; + } + +cleanup: + g_free(s_username); + g_free(s_password); + + //g_object_set(gpdata->session, "password", s_password, NULL); + return TRUE; +} + +static void gvnc_plugin_initialized(GtkWidget *vncdisplay, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + REMMINA_PLUGIN_DEBUG("Connection initialized"); + g_return_if_fail(gpdata != NULL); + REMMINA_PLUGIN_DEBUG("Presenting the window"); + + VncAudioFormat format = { + VNC_AUDIO_FORMAT_RAW_S32, + 2, + 44100, + }; + + REMMINA_PLUGIN_DEBUG("Gathering the VNC connection object"); + gpdata->conn = vnc_display_get_connection(VNC_DISPLAY(gpdata->vnc)); + g_return_if_fail(gpdata->conn != NULL); + + if (remmina_plugin_service->file_get_int(remminafile, "enableaudio", FALSE)) { + REMMINA_PLUGIN_DEBUG("Setting up VNC audio channel"); + if (vnc_connection_set_audio_format(gpdata->conn, &format)) + REMMINA_PLUGIN_DEBUG("VNC audio format set"); + else { + REMMINA_PLUGIN_DEBUG("VNC audio format returned an error"); + return; + } + + if (vnc_connection_set_audio(gpdata->conn, VNC_AUDIO(gpdata->pa))) + REMMINA_PLUGIN_DEBUG("VNC audio channel has been set"); + else { + REMMINA_PLUGIN_DEBUG("VNC audio channel cannot be set"); + return; + } + REMMINA_PLUGIN_DEBUG("Enabling audio"); + if (vnc_connection_audio_enable(gpdata->conn)) + REMMINA_PLUGIN_DEBUG("Audio enabled"); + else + REMMINA_PLUGIN_DEBUG("Audio cannot be enabled"); + } + gpdata->width = vnc_display_get_width(VNC_DISPLAY(gpdata->vnc)); + gpdata->width = vnc_display_get_height(VNC_DISPLAY(gpdata->vnc)); +} + +static void gvnc_plugin_disconnected(VncDisplay *vnc G_GNUC_UNUSED, RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + //GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + REMMINA_PLUGIN_DEBUG("[%s] Plugin disconnected", PLUGIN_NAME); +} +static gboolean gvnc_plugin_close_connection(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + + REMMINA_PLUGIN_DEBUG("[%s] Plugin close connection", PLUGIN_NAME); + + if (gpdata) { + if (gpdata->error_msg) g_free(gpdata->error_msg); + if (gpdata->vnc) + vnc_display_close(VNC_DISPLAY(gpdata->vnc)); + //g_object_unref(gpdata->vnc); + } + + /* Remove instance->context from gp object data to avoid double free */ + g_object_steal_data(G_OBJECT(gp), "plugin-data"); + remmina_plugin_service->protocol_plugin_signal_connection_closed(gp); + return FALSE; +} + +static void gvnc_plugin_init(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + GVncPluginData *gpdata; + //VncGrabSequence *seq; + + GtkClipboard *cb; + + gpdata = g_new0(GVncPluginData, 1); + g_object_set_data_full(G_OBJECT(gp), "plugin-data", gpdata, g_free); + + gpdata->pa = NULL; + + REMMINA_PLUGIN_DEBUG("[%s] Plugin init", PLUGIN_NAME); + + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + if (remmina_plugin_service->file_get_int(remminafile, "gvncdebug", FALSE)) + vnc_util_set_debug(TRUE); + + gpdata->vnc = vnc_display_new(); + if (remmina_plugin_service->file_get_int(remminafile, "enableaudio", FALSE)) + gpdata->pa = vnc_audio_pulse_new(); + + + g_signal_connect(gpdata->vnc, "vnc-auth-credential", + G_CALLBACK(gvnc_plugin_ask_auth), gp); + g_signal_connect(gpdata->vnc, "vnc-auth-failure", + G_CALLBACK(gvnc_plugin_auth_failure), gp); + g_signal_connect(gpdata->vnc, "vnc-auth-unsupported", + G_CALLBACK(gvnc_plugin_auth_unsupported), gp); + g_signal_connect(gpdata->vnc, "vnc-disconnected", + G_CALLBACK(gvnc_plugin_disconnected), gp); + g_signal_connect(gpdata->vnc, "vnc-initialized", + G_CALLBACK(gvnc_plugin_initialized), gp); + g_signal_connect(gpdata->vnc, "vnc-desktop-resize", + G_CALLBACK(gvnc_plugin_desktop_resize), gp); + g_signal_connect(gpdata->vnc, "vnc-bell", + G_CALLBACK(gvnc_plugin_on_bell), gp); + g_signal_connect(gpdata->vnc, "vnc-error", + G_CALLBACK(gvnc_plugin_on_vnc_error), gp); + g_signal_connect(gpdata->vnc, "vnc-pointer-grab", + G_CALLBACK(gvnc_plugin_mouse_grab), gp); + g_signal_connect(gpdata->vnc, "vnc-pointer-ungrab", + G_CALLBACK(gvnc_plugin_mouse_ungrab), gp); + g_signal_connect(gpdata->vnc, "vnc-server-cut-text", + G_CALLBACK(gvnc_plugin_cut_text), gp); + //seq = vnc_grab_sequence_new_from_string ("Control_R"); + //vnc_display_set_grab_keys(VNC_DISPLAY(gpdata->vnc), seq); + //vnc_grab_sequence_free(seq); + + /* Setup the clipboard */ + cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); + gpdata->signal_clipboard = g_signal_connect(cb, + "owner-change", + G_CALLBACK(gvnc_plugin_clipboard_cb), + gp); +} + +static gboolean gvnc_plugin_open_connection(RemminaProtocolWidget *gp) +{ + TRACE_CALL(__func__); + + gint port; + gchar *host = NULL, *tunnel = NULL; + GVncPluginData *gpdata = GET_PLUGIN_DATA(gp); + RemminaFile *remminafile = remmina_plugin_service->protocol_plugin_get_file(gp); + + REMMINA_PLUGIN_DEBUG("[%s] Plugin open connection", PLUGIN_NAME); + + gpdata->box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add(GTK_CONTAINER(gp), gpdata->box); + gtk_widget_set_hexpand(GTK_WIDGET(gpdata->vnc), TRUE); + gtk_widget_set_vexpand(GTK_WIDGET(gpdata->vnc), TRUE); + gtk_container_add(GTK_CONTAINER(gpdata->box), gpdata->vnc); + + remmina_plugin_service->protocol_plugin_register_hostkey(gp, gpdata->vnc); + + + const gchar *address = remmina_plugin_service->file_get_string(remminafile, "server"); + if(strstr(g_strdup(address), "unix:///") != NULL) { + REMMINA_PLUGIN_DEBUG("address contain unix:// -> %s", address); + gchar *val = str_replace (address, "unix://", ""); + REMMINA_PLUGIN_DEBUG("address after cleaning = %s", val); + gint fd = remmina_plugin_service->open_unix_sock(val); + REMMINA_PLUGIN_DEBUG("Unix socket fd: %d", fd); + gpdata->fd = fd; + g_free(val); + + } else { + /* Setup SSH tunnel if needed */ + tunnel = remmina_plugin_service->protocol_plugin_start_direct_tunnel(gp, GVNC_DEFAULT_PORT, FALSE); + if (!tunnel) + return FALSE; + remmina_plugin_service->get_server_port(tunnel, + GVNC_DEFAULT_PORT, + &host, + &port); + } + + + + gpdata->depth_profile = remmina_plugin_service->file_get_int(remminafile, "depth_profile", 24); + gpdata->viewonly = remmina_plugin_service->file_get_int(remminafile, "viewonly", FALSE); + vnc_display_set_depth(VNC_DISPLAY(gpdata->vnc), gpdata->depth_profile); + if (gpdata->fd > 0) + vnc_display_open_fd(VNC_DISPLAY(gpdata->vnc), gpdata->fd); + else + vnc_display_open_host(VNC_DISPLAY(gpdata->vnc), host, g_strdup_printf("%d", port)); + gpdata->lossy_encoding = remmina_plugin_service->file_get_int(remminafile, "lossy_encoding", FALSE); + vnc_display_set_lossy_encoding(VNC_DISPLAY(gpdata->vnc), gpdata->lossy_encoding); + vnc_display_set_shared_flag(VNC_DISPLAY(gpdata->vnc), gpdata->shared); + + if(host) g_free(host); + if(tunnel) g_free(tunnel); + + /* TRUE Conflict with remmina? */ + vnc_display_set_keyboard_grab(VNC_DISPLAY(gpdata->vnc), FALSE); + vnc_display_set_read_only(VNC_DISPLAY(gpdata->vnc), gpdata->viewonly); + /* TRUE Conflict with remmina? */ + vnc_display_set_pointer_grab(VNC_DISPLAY(gpdata->vnc), FALSE); + vnc_display_set_pointer_local(VNC_DISPLAY(gpdata->vnc), TRUE); + + vnc_display_set_force_size(VNC_DISPLAY(gpdata->vnc), FALSE); + vnc_display_set_scaling(VNC_DISPLAY(gpdata->vnc), TRUE); +#ifdef HAVE_VNC_REMOTE_RESIZE + vnc_display_set_allow_resize(VNC_DISPLAY(gpdata->vnc), TRUE); + vnc_display_set_zoom_level(VNC_DISPLAY(gpdata->vnc), opt_zoom); +#endif + remmina_plugin_service->protocol_plugin_signal_connection_opened(gp); + gtk_widget_show_all(gpdata->box); + return TRUE; +} + +/* Array of key/value pairs for color depths */ +static gpointer colordepth_list[] = +{ + "0", N_("Use server settings"), + "1", N_("True colour (24 bits)"), + "2", N_("High colour (16 bits)"), + "3", N_("Low colour (8 bits)"), + "4", N_("Ultra low colour (3 bits)"), + NULL +}; + +/* Array of RemminaProtocolSetting for basic settings. + * Each item is composed by: + * a) RemminaProtocolSettingType for setting type + * b) Setting name + * c) Setting description + * d) Compact disposition + * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO + * f) Setting tooltip + * g) Validation data pointer, will be passed to the validation callback method. + * h) Validation callback method (Can be NULL. Every entry will be valid then.) + * use following prototype: + * gboolean mysetting_validator_method(gpointer key, gpointer value, + * gpointer validator_data); + * gpointer key is a gchar* containing the setting's name, + * gpointer value contains the value which should be validated, + * gpointer validator_data contains your passed data. + */ +static const RemminaProtocolSetting gvnc_plugin_basic_settings[] = +{ + { REMMINA_PROTOCOL_SETTING_TYPE_SERVER, "server", NULL, FALSE, NULL, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_PASSWORD, "password", N_("VNC password"), FALSE, NULL, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_SELECT, "depth_profile", N_("Colour depth"), FALSE, colordepth_list, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "lossy_encoding", N_("Use JPEG Compression"), TRUE, NULL, N_("This might not work on all VNC servers"), NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "gvncdebug", N_("Enable GTK-VNC debug"), FALSE, NULL, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, FALSE, NULL, NULL, NULL, NULL } +}; + +/* Array of RemminaProtocolSetting for advanced settings. + * Each item is composed by: + * a) RemminaProtocolSettingType for setting type + * b) Setting name + * c) Setting description + * d) Compact disposition + * e) Values for REMMINA_PROTOCOL_SETTING_TYPE_SELECT or REMMINA_PROTOCOL_SETTING_TYPE_COMBO + * f) Setting Tooltip + */ +static const RemminaProtocolSetting gvnc_plugin_advanced_settings[] = +{ + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableclipboard", N_("No clipboard sync"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disablepasswordstoring", N_("Forget passwords after use"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "disableserverbell", N_("Ignore remote bell messages"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "enableaudio", N_("Enable audio channel"), FALSE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "viewonly", N_("View only"), TRUE, NULL, NULL }, + { REMMINA_PROTOCOL_SETTING_TYPE_CHECK, "shared", N_("Shared connection"), TRUE, NULL, N_("If the server should try to share the desktop by leaving other clients connected") }, + { REMMINA_PROTOCOL_SETTING_TYPE_END, NULL, NULL, TRUE, NULL, NULL } +}; + +/* Array for available features. + * The last element of the array must be REMMINA_PROTOCOL_FEATURE_TYPE_END. */ +static const RemminaProtocolFeature gvnc_plugin_features[] = +{ + { REMMINA_PROTOCOL_FEATURE_TYPE_PREF, GVNC_PLUGIN_FEATURE_PREF_VIEWONLY, GINT_TO_POINTER(REMMINA_PROTOCOL_FEATURE_PREF_CHECK), "viewonly", N_("View only") }, + { REMMINA_PROTOCOL_FEATURE_TYPE_PREF, GVNC_PLUGIN_FEATURE_PREF_DISABLECLIPBOARD, GINT_TO_POINTER(REMMINA_PROTOCOL_FEATURE_PREF_CHECK), "disableclipboard", N_("No clipboard sync") }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTDEL, N_("Send Ctrl+Alt+_Del"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTBACKSPACE, N_("Send Ctrl+Alt+_Backspace"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF1, N_("Send Ctrl+Alt+_F1"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF2, N_("Send Ctrl+Alt+_F2"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF3, N_("Send Ctrl+Alt+_F3"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF4, N_("Send Ctrl+Alt+_F4"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF5, N_("Send Ctrl+Alt+_F5"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF6, N_("Send Ctrl+Alt+_F6"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF7, N_("Send Ctrl+Alt+_F7"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF8, N_("Send Ctrl+Alt+_F8"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF9, N_("Send Ctrl+Alt+_F9"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF10, N_("Send Ctrl+Alt+_F10"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF11, N_("Send Ctrl+Alt+_F11"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SENDCTRLALTF12, N_("Send Ctrl+Alt+_F12"), NULL, NULL }, +#ifdef HAVE_VNC_POWER_CONTROL + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_REBOOT, N_("Reboot remote host"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_RESET, N_("Reset remote host (hard reboot)"), NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_TOOL, GVNC_PLUGIN_FEATURE_TOOL_SHUTDOWN, N_("Shutdown remote host"), NULL, NULL }, +#endif + { REMMINA_PROTOCOL_FEATURE_TYPE_DYNRESUPDATE, GVNC_PLUGIN_FEATURE_DYNRESUPDATE, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_SCALE, GVNC_PLUGIN_FEATURE_SCALE, NULL, NULL, NULL }, + { REMMINA_PROTOCOL_FEATURE_TYPE_END, 0, NULL, NULL, NULL } +}; + +/* Protocol plugin definition and features */ +static RemminaProtocolPlugin remmina_plugin = { + REMMINA_PLUGIN_TYPE_PROTOCOL, // Type + PLUGIN_NAME, // Name + PLUGIN_DESCRIPTION, // Description + GETTEXT_PACKAGE, // Translation domain + PLUGIN_VERSION, // Version number + PLUGIN_APPICON, // Icon for normal connection + PLUGIN_APPICON, // Icon for SSH connection + gvnc_plugin_basic_settings, // Array for basic settings + gvnc_plugin_advanced_settings, // Array for advanced settings + REMMINA_PROTOCOL_SSH_SETTING_TUNNEL, // SSH settings type + gvnc_plugin_features, // Array for available features + gvnc_plugin_init, // Plugin initialization + gvnc_plugin_open_connection, // Plugin open connection + gvnc_plugin_close_connection, // Plugin close connection + gvnc_plugin_query_feature, // Query for available features + gvnc_plugin_call_feature, // Call a feature + gvnc_plugin_keystroke, // Send a keystroke + NULL, // No screenshot support available + //gvnc_plugin_get_screenshot, // No screenshot support available + NULL, // RCW map event + NULL // RCW unmap event +}; + +G_MODULE_EXPORT gboolean remmina_plugin_entry(RemminaPluginService *service) +{ + TRACE_CALL(__func__); + remmina_plugin_service = service; + + bindtextdomain(GETTEXT_PACKAGE, REMMINA_RUNTIME_LOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + + if (!service->register_plugin((RemminaPlugin *)&remmina_plugin)) + return FALSE; + + return TRUE; +} diff --git a/plugins/gvnc/gvnc_plugin.h b/plugins/gvnc/gvnc_plugin.h new file mode 100644 index 0000000..613d032 --- /dev/null +++ b/plugins/gvnc/gvnc_plugin.h @@ -0,0 +1,131 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2016-2023 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. + * + */ + +#include "common/remmina_plugin.h" + +#include <gdk/gdkkeysyms.h> +#include <vncdisplay.h> +#include <vncutil.h> +#include <vncaudiopulse.h> + + +#ifndef GDK_Return +#define GDK_Return GDK_KEY_Return +#endif +#ifndef GDK_Escape +#define GDK_Escape GDK_KEY_Escape +#endif +#ifndef GDK_BackSpace +#define GDK_BackSpace GDK_KEY_BackSpace +#endif +#ifndef GDK_Delete +#define GDK_Delete GDK_KEY_Delete +#endif +#ifndef GDK_Control_L +#define GDK_Control_L GDK_KEY_Control_L +#endif +#ifndef GDK_Alt_L +#define GDK_Alt_L GDK_KEY_Alt_L +#endif +#ifndef GDK_F1 +#define GDK_F1 GDK_KEY_F1 +#endif +#ifndef GDK_F2 +#define GDK_F2 GDK_KEY_F2 +#endif +#ifndef GDK_F3 +#define GDK_F3 GDK_KEY_F3 +#endif +#ifndef GDK_F4 +#define GDK_F4 GDK_KEY_F4 +#endif +#ifndef GDK_F5 +#define GDK_F5 GDK_KEY_F5 +#endif +#ifndef GDK_F6 +#define GDK_F6 GDK_KEY_F6 +#endif +#ifndef GDK_F7 +#define GDK_F7 GDK_KEY_F7 +#endif +#ifndef GDK_F8 +#define GDK_F8 GDK_KEY_F8 +#endif +#ifndef GDK_F11 +#define GDK_F11 GDK_KEY_F11 +#endif + +#define GET_PLUGIN_DATA(gp) (GVncPluginData *)g_object_get_data(G_OBJECT(gp), "plugin-data") + +#define REMMINA_PLUGIN_INFO(fmt, ...) \ + remmina_plugin_service->_remmina_info(__func__, fmt, ##__VA_ARGS__) + +#define REMMINA_PLUGIN_MESSAGE(fmt, ...) \ + remmina_plugin_service->_remmina_message(__func, fmt, ##__VA_ARGS__) + +#define REMMINA_PLUGIN_DEBUG(fmt, ...) \ + remmina_plugin_service->_remmina_debug(__func__, fmt, ##__VA_ARGS__) + +#define REMMINA_PLUGIN_WARNING(fmt, ...) \ + remmina_plugin_service->_remmina_warning(__func__, fmt, ##__VA_ARGS__) + +/* This will intentionally crash Remmina */ +#define REMMINA_PLUGIN_ERROR(fmt, ...) \ + remmina_plugin_service->_remmina_error(__func__, fmt, ##__VA_ARGS__) + +#define REMMINA_PLUGIN_CRITICAL(fmt, ...) \ + remmina_plugin_service->_remmina_critical(__func__, fmt, ##__VA_ARGS__) +#define REMMINA_PLUGIN_AUDIT(fmt, ...) \ + remmina_plugin_service->_remmina_audit(__func__, fmt, ##__VA_ARGS__) + +typedef struct _GVncPluginData { + GtkWidget * box; + GtkWidget * vnc; + VncConnection * conn; + VncAudioPulse * pa; + gchar * error_msg; + gchar * clipstr; + gulong signal_clipboard; + gint depth_profile; + gint shared; + gboolean lossy_encoding; + gboolean viewonly; + gint width; + gint height; + gint fd; + gchar * addr; +} GVncPluginData; + +G_BEGIN_DECLS +G_END_DECLS diff --git a/plugins/gvnc/gvnc_plugin_config.h b/plugins/gvnc/gvnc_plugin_config.h new file mode 100644 index 0000000..af55b3c --- /dev/null +++ b/plugins/gvnc/gvnc_plugin_config.h @@ -0,0 +1,43 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2023 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. + * + */ + +#ifndef __PLUGIN_CONFIG_H +#define __PLUGIN_CONFIG_H + +#define PLUGIN_NAME "GVNC" +#define PLUGIN_DESCRIPTION N_("Remmina VNC plugin for GNOME and KVM") +#define PLUGIN_VERSION "0.1b" +#define PLUGIN_APPICON "org.remmina.Remmina-gvnc-symbolic" +#endif diff --git a/plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-ssh-symbolic.svg b/plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-ssh-symbolic.svg new file mode 100644 index 0000000..6c1da59 --- /dev/null +++ b/plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-ssh-symbolic.svg @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="99.772003" + height="99.772079" + viewBox="0 0 26.39801 26.398028" + version="1.1" + id="svg8" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="vnc over ssh.svg"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:zoom="1.0493442" + inkscape:cx="-11.459557" + inkscape:cy="109.76653" + inkscape:document-units="px" + inkscape:current-layer="layer1" + inkscape:document-rotation="0" + showgrid="false" + borderlayer="true" + inkscape:showpageshadow="true" + units="px" + inkscape:pagecheckerboard="false" + showguides="true" + inkscape:window-width="1366" + inkscape:window-height="715" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + objecttolerance="10" + guidetolerance="10" + inkscape:snap-tangential="true" + inkscape:snap-perpendicular="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0"> + <inkscape:grid + type="xygrid" + id="grid10" + dotted="false" + originx="-162.7958" + originy="-83.119086" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + <cc:license + rdf:resource="" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-162.79579,-187.48289)"> + <path + d="m 175.99485,195.20186 c -1.73487,0 -3.13161,1.42611 -3.13161,3.18029 v 1.51686 h -0.7829 c -0.43365,0 -0.7829,0.34925 -0.7829,0.7829 v 4.69715 c 0,0.43365 0.34925,0.7829 0.7829,0.7829 h 7.82875 c 0.43366,0 0.78291,-0.34925 0.78291,-0.7829 v -4.69715 c 0,-0.43365 -0.34925,-0.7829 -0.78291,-0.7829 h -0.7829 v -1.51686 c 0,-1.75365 -1.39673,-3.18029 -3.13134,-3.18029 z m 0,1.56581 c 0.8673,0 1.56554,0.69823 1.56554,1.56554 v 1.5658 h -3.13135 v -1.5658 c 0,-0.86731 0.69824,-1.56554 1.56581,-1.56554 z" + id="path34" + inkscape:connector-curvature="0" + style="isolation:isolate;fill:#171717;stroke-width:0.26458332" /> + <path + d="m 187.30817,213.88092 c 0,0 0.14367,-0.008 0.34237,-0.0442 0.38523,-0.0569 0.67627,-0.195 0.89138,-0.38312 0.0415,-0.0317 0.082,-0.0661 0.12144,-0.10319 0.037,-0.0394 0.0712,-0.0796 0.10319,-0.12144 0.18785,-0.21484 0.32623,-0.50615 0.38285,-0.89112 0.0368,-0.1987 0.0444,-0.34263 0.0444,-0.34263 v -22.62691 c 0,-1.88542 -1.88568,-1.88542 -1.88568,-1.88542 h -22.6269 c 0,0 -1.88543,0 -1.88543,1.88542 v 22.6269 c 0,0 0.008,0.14393 0.0442,0.34264 0.0585,0.38497 0.19447,0.67627 0.38285,0.89111 0.032,0.0418 0.0675,0.082 0.10319,0.12145 0.0397,0.037 0.0802,0.0714 0.12144,0.10318 0.21511,0.18812 0.50668,0.32624 0.89138,0.38312 0.19976,0.0363 0.34238,0.0442 0.34238,0.0442 z m -1.88569,-4.5347 h -18.85553 v -18.09221 h 18.85553 z" + id="path36" + inkscape:connector-curvature="0" + style="isolation:isolate;fill:#171717;stroke-width:0.26458332" /> + </g> +</svg> diff --git a/plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-symbolic.svg b/plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-symbolic.svg new file mode 100644 index 0000000..060a62a --- /dev/null +++ b/plugins/gvnc/scalable/emblems/org.remmina.Remmina-gvnc-symbolic.svg @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="100" + height="100" + viewBox="0 0 26.458335 26.458332" + version="1.1" + id="svg8" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="vnc protocol.svg"> + <defs + id="defs2"> + <mask + id="_mask_t2Us8opi94eYjaS69EfyEcHSNVQ03DDZ" + x="-200%" + y="-200%" + width="400%" + height="400%"> + <rect + x="0" + y="0" + width="100%" + height="100%" + style="fill:#ffffff" + id="rect40" /> + <path + d="m 850.286,202.852 c 0,0 0.452,-0.025 1.077,-0.139 1.211,-0.179 2.128,-0.614 2.804,-1.205 0.13,-0.1 0.257,-0.208 0.382,-0.324 0.116,-0.125 0.224,-0.251 0.324,-0.382 0.592,-0.677 1.026,-1.593 1.205,-2.804 0.115,-0.625 0.139,-1.077 0.139,-1.077 V 125.75 c 0,-5.931 -5.931,-5.931 -5.931,-5.931 h -71.171 c 0,0 -5.931,0 -5.931,5.931 v 71.171 c 0,0 0.026,0.452 0.139,1.077 0.184,1.211 0.612,2.127 1.205,2.804 0.101,0.131 0.212,0.257 0.324,0.382 0.125,0.116 0.252,0.224 0.383,0.324 0.676,0.591 1.593,1.026 2.803,1.205 0.628,0.114 1.077,0.139 1.077,0.139 z m -5.931,-14.263 h -59.309 v -56.908 h 59.309 z" + id="path42" + inkscape:connector-curvature="0" + style="fill:#000000;stroke:none" /> + </mask> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:zoom="1.4839967" + inkscape:cx="-65.390539" + inkscape:cy="-17.020138" + inkscape:document-units="px" + inkscape:current-layer="g820" + inkscape:document-rotation="0" + showgrid="false" + borderlayer="true" + inkscape:showpageshadow="true" + units="px" + inkscape:pagecheckerboard="false" + showguides="true" + inkscape:window-width="1366" + inkscape:window-height="715" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + objecttolerance="10" + guidetolerance="10" + inkscape:snap-tangential="true" + inkscape:snap-perpendicular="true" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0"> + <inkscape:grid + type="xygrid" + id="grid10" + dotted="false" + originx="-146.65307" + originy="-135.56714" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + <cc:license + rdf:resource="" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-146.65306,-134.97453)"> + <g + id="g820" + transform="matrix(1.0697634,0,0,1.0697634,-9.2735492,-11.925523)"> + <path + inkscape:connector-curvature="0" + id="path38" + d="m 147.83075,137.94029 c 0,0 -1.17769,2e-5 -1.17769,1.17769 v 14.13263 c 0,0 0.005,0.09 0.0274,0.21405 0.0365,0.24056 0.12144,0.42255 0.23928,0.55686 0.02,0.0261 0.0421,0.051 0.0644,0.0757 0.0248,0.023 0.0503,0.0445 0.0761,0.0644 0.13431,0.11739 0.31608,0.20363 0.55643,0.23928 0.12474,0.0227 0.21405,0.0278 0.21405,0.0278 h 4.62807 v -2.83218 H 149.0084 V 140.2961 h 11.77727 v 4.05511 h 2.35536 v -5.23323 c 0,-1.17767 -1.17768,-1.17769 -1.17768,-1.17769 z m 12.95495,10.06883 v 3.58743 h -4.66941 v 2.83218 h 5.84709 c 0,0 0.09,-0.005 0.21405,-0.0278 0.24056,-0.0356 0.4221,-0.1219 0.55643,-0.23928 0.0258,-0.0199 0.0514,-0.0414 0.0761,-0.0644 0.023,-0.0247 0.0445,-0.0497 0.0644,-0.0757 0.11738,-0.13431 0.20386,-0.3163 0.23927,-0.55686 0.023,-0.12408 0.0274,-0.21405 0.0274,-0.21405 v -5.24149 z" + style="isolation:isolate;fill:#171717;stroke-width:0.22274615" /> + <path + style="isolation:isolate;fill:#171717;stroke-width:0.22274615" + inkscape:connector-curvature="0" + id="path38-5" + d="m 168.41828,161.43286 c 0,0 0.0898,-0.005 0.21384,-0.0276 0.24056,-0.0356 0.42232,-0.12185 0.55664,-0.23923 0.0258,-0.0199 0.0513,-0.0414 0.0759,-0.0644 0.0229,-0.0248 0.0445,-0.0499 0.0644,-0.0759 0.11739,-0.13432 0.20381,-0.31608 0.23923,-0.55665 0.023,-0.12407 0.0276,-0.21405 0.0276,-0.21405 v -14.13259 c 0,-1.17766 -1.17767,-1.17766 -1.17767,-1.17766 h -14.13279 c 0,0 -1.17765,0 -1.17765,1.17766 v 14.13258 c 0,0 0.005,0.09 0.0276,0.21406 0.0365,0.24057 0.1214,0.42233 0.23924,0.55664 0.02,0.0261 0.0421,0.0512 0.0644,0.0759 0.0248,0.023 0.0501,0.0445 0.0759,0.0644 0.13432,0.11738 0.3163,0.20359 0.55664,0.23923 0.12474,0.0227 0.21384,0.0276 0.21384,0.0276 z m -1.17788,-2.83222 v -11.30036 h -11.77704 11.77704 z" + sodipodi:nodetypes="cccccccsccsccccccccccccc" /> + </g> + </g> +</svg> |