From 2c4ae68da02d5680fa4599b87aa3dfb25a57886d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 9 Apr 2014 11:40:09 -0700 Subject: [PATCH] GUAC-608: Add support for outbound clipboard for SSH. Partial inbound support. --- src/protocols/ssh/Makefile.am | 6 ++-- src/protocols/ssh/client.c | 2 +- src/protocols/ssh/client.h | 8 ++++- src/protocols/ssh/clipboard.c | 55 +++++++++++++++++++++++++++++++ src/protocols/ssh/clipboard.h | 49 +++++++++++++++++++++++++++ src/protocols/ssh/guac_handlers.c | 46 +++++++++++--------------- src/protocols/ssh/guac_handlers.h | 2 +- 7 files changed, 136 insertions(+), 32 deletions(-) create mode 100644 src/protocols/ssh/clipboard.c create mode 100644 src/protocols/ssh/clipboard.h diff --git a/src/protocols/ssh/Makefile.am b/src/protocols/ssh/Makefile.am index e5f02fbb..9f58eba5 100644 --- a/src/protocols/ssh/Makefile.am +++ b/src/protocols/ssh/Makefile.am @@ -31,6 +31,7 @@ libguac_client_ssh_la_SOURCES = \ buffer.c \ char_mappings.c \ client.c \ + clipboard.c \ common.c \ cursor.c \ display.c \ @@ -48,6 +49,7 @@ noinst_HEADERS = \ buffer.h \ char_mappings.h \ client.h \ + clipboard.h \ common.h \ cursor.h \ display.h \ @@ -67,7 +69,7 @@ libguac_client_ssh_la_SOURCES += ssh_agent.c noinst_HEADERS += ssh_agent.h endif -libguac_client_ssh_la_CFLAGS = -Werror -Wall -Iinclude @PANGO_CFLAGS@ @PANGOCAIRO_CFLAGS@ @LIBGUAC_INCLUDE@ -libguac_client_ssh_la_LIBADD = @LIBGUAC_LTLIB@ +libguac_client_ssh_la_CFLAGS = -Werror -Wall -Iinclude @PANGO_CFLAGS@ @PANGOCAIRO_CFLAGS@ @LIBGUAC_INCLUDE@ @COMMON_INCLUDE@ +libguac_client_ssh_la_LIBADD = @LIBGUAC_LTLIB@ @COMMON_LTLIB@ libguac_client_ssh_la_LDFLAGS = -version-info 0:0:0 @SSH_LIBS@ @SSL_LIBS@ @PTHREAD_LIBS@ @PANGO_LIBS@ @PANGOCAIRO_LIBS@ @CAIRO_LIBS@ diff --git a/src/protocols/ssh/client.c b/src/protocols/ssh/client.c index ebbd2003..90a9dd54 100644 --- a/src/protocols/ssh/client.c +++ b/src/protocols/ssh/client.c @@ -127,7 +127,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) { client_data->mod_alt = client_data->mod_ctrl = client_data->mod_shift = 0; - client_data->clipboard_data = NULL; + client_data->clipboard = guac_common_clipboard_alloc(GUAC_SSH_CLIPBOARD_MAX_LENGTH); client_data->term_channel = NULL; if (argc != SSH_ARGS_COUNT) { diff --git a/src/protocols/ssh/client.h b/src/protocols/ssh/client.h index 95891fff..11598e73 100644 --- a/src/protocols/ssh/client.h +++ b/src/protocols/ssh/client.h @@ -27,6 +27,7 @@ #include "config.h" #include "cursor.h" +#include "guac_clipboard.h" #include "sftp.h" #include "ssh_key.h" #include "terminal.h" @@ -40,6 +41,11 @@ #include "ssh_agent.h" #endif +/** + * The maximum number of bytes to allow within the clipboard. + */ +#define GUAC_SSH_CLIPBOARD_MAX_LENGTH 262144 + /** * SSH-specific client data. */ @@ -145,7 +151,7 @@ typedef struct ssh_guac_client_data { /** * The current contents of the clipboard. */ - char* clipboard_data; + guac_common_clipboard* clipboard; /** * Whether the alt key is currently being held down. diff --git a/src/protocols/ssh/clipboard.c b/src/protocols/ssh/clipboard.c new file mode 100644 index 00000000..7edd39ee --- /dev/null +++ b/src/protocols/ssh/clipboard.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "config.h" +#include "client.h" +#include "clipboard.h" +#include "guac_clipboard.h" +#include "guac_iconv.h" + +int guac_ssh_clipboard_handler(guac_client* client, guac_stream* stream, + char* mimetype) { + + /* Clear clipboard and prepare for new data */ + ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data; + guac_common_clipboard_reset(client_data->clipboard, mimetype); + + return 0; +} + +int guac_ssh_clipboard_blob_handler(guac_client* client, guac_stream* stream, + void* data, int length) { + + /* Append new data */ + ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data; + guac_common_clipboard_append(client_data->clipboard, (char*) data, length); + + return 0; +} + +int guac_ssh_clipboard_end_handler(guac_client* client, guac_stream* stream) { + + /* Nothing to do - clipboard is implemented within client */ + + return 0; +} + diff --git a/src/protocols/ssh/clipboard.h b/src/protocols/ssh/clipboard.h new file mode 100644 index 00000000..dfa2bd6e --- /dev/null +++ b/src/protocols/ssh/clipboard.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _GUAC_SSH_CLIPBOARD_H +#define _GUAC_SSH_CLIPBOARD_H + +#include "config.h" + +#include +#include + +/** + * Handler for inbound clipboard data. + */ +int guac_ssh_clipboard_handler(guac_client* client, guac_stream* stream, + char* mimetype); + +/** + * Handler for stream data related to clipboard. + */ +int guac_ssh_clipboard_blob_handler(guac_client* client, guac_stream* stream, + void* data, int length); + +/** + * Handler for end-of-stream related to clipboard. + */ +int guac_ssh_clipboard_end_handler(guac_client* client, guac_stream* stream); + +#endif + diff --git a/src/protocols/ssh/guac_handlers.c b/src/protocols/ssh/guac_handlers.c index 10452764..719759d0 100644 --- a/src/protocols/ssh/guac_handlers.c +++ b/src/protocols/ssh/guac_handlers.c @@ -23,6 +23,7 @@ #include "config.h" #include "client.h" +#include "clipboard.h" #include "common.h" #include "cursor.h" #include "guac_handlers.h" @@ -102,15 +103,8 @@ int ssh_guac_client_handle_messages(guac_client* client) { } -int ssh_guac_client_clipboard_handler(guac_client* client, char* data) { - - ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data; - - free(client_data->clipboard_data); - - client_data->clipboard_data = strdup(data); - - return 0; +int ssh_guac_client_clipboard_handler(guac_client* client, guac_stream* stream, char* mimetype) { + return guac_ssh_clipboard_handler(client, stream, mimetype); } int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) { @@ -136,12 +130,8 @@ int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) { } /* Paste contents of clipboard on right or middle mouse button up */ - if ((released_mask & GUAC_CLIENT_MOUSE_RIGHT) || (released_mask & GUAC_CLIENT_MOUSE_MIDDLE)) { - if (client_data->clipboard_data != NULL) - return guac_terminal_send_string(term, client_data->clipboard_data); - else - return 0; - } + if ((released_mask & GUAC_CLIENT_MOUSE_RIGHT) || (released_mask & GUAC_CLIENT_MOUSE_MIDDLE)) + return guac_terminal_send_data(term, client_data->clipboard->buffer, client_data->clipboard->length); /* If text selected, change state based on left mouse mouse button */ if (term->text_selected) { @@ -150,16 +140,22 @@ int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) { /* If mouse button released, stop selection */ if (released_mask & GUAC_CLIENT_MOUSE_LEFT) { + int selected_length; + /* End selection and get selected text */ - char* string = malloc(term->term_width * term->term_height * sizeof(char)); + int selectable_size = term->term_width * term->term_height * sizeof(char); + char* string = malloc(selectable_size); guac_terminal_select_end(term, string); + selected_length = strnlen(string, selectable_size); + /* Store new data */ - free(client_data->clipboard_data); - client_data->clipboard_data = string; + guac_common_clipboard_reset(client_data->clipboard, "text/plain"); + guac_common_clipboard_append(client_data->clipboard, string, selected_length); + free(string); /* Send data */ - guac_protocol_send_clipboard(client->socket, string); + guac_common_clipboard_send(client_data->clipboard, client); guac_socket_flush(client->socket); } @@ -231,12 +227,8 @@ int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed) { else if (pressed) { /* Ctrl+Shift+V shortcut for paste */ - if (keysym == 'V' && client_data->mod_ctrl) { - if (client_data->clipboard_data != NULL) - return guac_terminal_send_string(term, client_data->clipboard_data); - else - return 0; - } + if (keysym == 'V' && client_data->mod_ctrl) + return guac_terminal_send_data(term, client_data->clipboard->buffer, client_data->clipboard->length); /* Shift+PgUp / Shift+PgDown shortcuts for scrolling */ if (client_data->mod_shift) { @@ -426,8 +418,8 @@ int ssh_guac_client_free_handler(guac_client* client) { if (guac_client_data->key != NULL) ssh_key_free(guac_client_data->key); - /* Free clipboard data */ - free(guac_client_data->clipboard_data); + /* Free clipboard */ + guac_common_clipboard_free(guac_client_data->clipboard); /* Free cursors */ guac_ssh_cursor_free(client, guac_client_data->ibar_cursor); diff --git a/src/protocols/ssh/guac_handlers.h b/src/protocols/ssh/guac_handlers.h index 14a0c4ee..0d74a5ba 100644 --- a/src/protocols/ssh/guac_handlers.h +++ b/src/protocols/ssh/guac_handlers.h @@ -31,7 +31,7 @@ int ssh_guac_client_handle_messages(guac_client* client); int ssh_guac_client_key_handler(guac_client* client, int keysym, int pressed); int ssh_guac_client_mouse_handler(guac_client* client, int x, int y, int mask); -int ssh_guac_client_clipboard_handler(guac_client* client, char* data); +int ssh_guac_client_clipboard_handler(guac_client* client, guac_stream* stream, char* mimetype); int ssh_guac_client_size_handler(guac_client* client, int width, int height); int ssh_guac_client_free_handler(guac_client* client);