From 2f16eadb358362d1925da343e530ab73417d4f55 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 23 Sep 2018 00:24:19 -0700 Subject: [PATCH] GUACAMOLE-630: Allow color scheme to be changed from webapp via argv streams. --- src/protocols/ssh/Makefile.am | 2 + src/protocols/ssh/argv.c | 128 +++++++++++++++++++++++++++++++ src/protocols/ssh/argv.h | 35 +++++++++ src/protocols/ssh/user.c | 4 + src/protocols/telnet/Makefile.am | 2 + src/protocols/telnet/argv.c | 128 +++++++++++++++++++++++++++++++ src/protocols/telnet/argv.h | 35 +++++++++ src/protocols/telnet/user.c | 4 + src/terminal/display.c | 4 +- src/terminal/terminal.c | 29 ++++++- src/terminal/terminal/display.h | 4 +- src/terminal/terminal/terminal.h | 15 ++++ 12 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 src/protocols/ssh/argv.c create mode 100644 src/protocols/ssh/argv.h create mode 100644 src/protocols/telnet/argv.c create mode 100644 src/protocols/telnet/argv.h diff --git a/src/protocols/ssh/Makefile.am b/src/protocols/ssh/Makefile.am index d60cf002..7bb1e349 100644 --- a/src/protocols/ssh/Makefile.am +++ b/src/protocols/ssh/Makefile.am @@ -29,6 +29,7 @@ ACLOCAL_AMFLAGS = -I m4 lib_LTLIBRARIES = libguac-client-ssh.la libguac_client_ssh_la_SOURCES = \ + argv.c \ client.c \ clipboard.c \ input.c \ @@ -40,6 +41,7 @@ libguac_client_ssh_la_SOURCES = \ user.c noinst_HEADERS = \ + argv.h \ client.h \ clipboard.h \ input.h \ diff --git a/src/protocols/ssh/argv.c b/src/protocols/ssh/argv.c new file mode 100644 index 00000000..85dca943 --- /dev/null +++ b/src/protocols/ssh/argv.c @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" +#include "argv.h" +#include "ssh.h" +#include "terminal/terminal.h" + +#include +#include +#include + +#include +#include + +/** + * The value or current status of a connection parameter received over an + * "argv" stream. + */ +typedef struct guac_ssh_argv { + + /** + * Buffer space for containing the received argument value. + */ + char buffer[16384]; + + /** + * The number of bytes received so far. + */ + int length; + +} guac_ssh_argv; + +/** + * Handler for "blob" instructions which appends the data from received blobs + * to the end of the in-progress argument value buffer. + * + * @see guac_user_blob_handler + */ +static int guac_ssh_argv_blob_handler(guac_user* user, + guac_stream* stream, void* data, int length) { + + guac_ssh_argv* argv = (guac_ssh_argv*) stream->data; + + /* Calculate buffer size remaining, including space for null terminator, + * adjusting received length accordingly */ + int remaining = sizeof(argv->buffer) - argv->length - 1; + if (length > remaining) + length = remaining; + + /* Append received data to end of buffer */ + memcpy(argv->buffer + argv->length, data, length); + argv->length += length; + + return 0; + +} + +/** + * Handler for "end" instructions which applies the changes specified by the + * argument value buffer associated with the stream. + * + * @see guac_user_end_handler + */ +static int guac_ssh_argv_end_handler(guac_user* user, + guac_stream* stream) { + + guac_client* client = user->client; + guac_ssh_client* telnet_client = (guac_ssh_client*) client->data; + guac_terminal* terminal = telnet_client->term; + + /* Append null terminator to value */ + guac_ssh_argv* argv = (guac_ssh_argv*) stream->data; + argv->buffer[argv->length] = '\0'; + + /* Update color scheme */ + guac_terminal_apply_color_scheme(terminal, argv->buffer); + free(argv); + return 0; + +} + +int guac_ssh_argv_handler(guac_user* user, guac_stream* stream, + char* mimetype, char* name) { + + /* Allow users to update the color scheme */ + if (strcmp(name, "color-scheme") == 0) { + + guac_ssh_argv* argv = malloc(sizeof(guac_ssh_argv)); + argv->length = 0; + + /* Prepare stream to receive argument value */ + stream->blob_handler = guac_ssh_argv_blob_handler; + stream->end_handler = guac_ssh_argv_end_handler; + stream->data = argv; + + /* Signal stream is ready */ + guac_protocol_send_ack(user->socket, stream, "Ready for color " + "scheme.", GUAC_PROTOCOL_STATUS_SUCCESS); + guac_socket_flush(user->socket); + return 0; + + } + + /* No other connection parameters may be updated */ + guac_protocol_send_ack(user->socket, stream, "Not allowed.", + GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN); + guac_socket_flush(user->socket); + return 0; + +} + diff --git a/src/protocols/ssh/argv.h b/src/protocols/ssh/argv.h new file mode 100644 index 00000000..27b08cbf --- /dev/null +++ b/src/protocols/ssh/argv.h @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef GUAC_SSH_ARGV_H +#define GUAC_SSH_ARGV_H + +#include "config.h" + +#include + +/** + * Handles an incoming stream from a Guacamole "argv" instruction, updating the + * given connection parameter if that parameter is allowed to be updated. + */ +guac_user_argv_handler guac_ssh_argv_handler; + +#endif + diff --git a/src/protocols/ssh/user.c b/src/protocols/ssh/user.c index e4dda40e..97ed87c6 100644 --- a/src/protocols/ssh/user.c +++ b/src/protocols/ssh/user.c @@ -19,6 +19,7 @@ #include "config.h" +#include "argv.h" #include "clipboard.h" #include "common/display.h" #include "input.h" @@ -87,6 +88,9 @@ int guac_ssh_user_join_handler(guac_user* user, int argc, char** argv) { /* STDIN redirection */ user->pipe_handler = guac_ssh_pipe_handler; + /* Updates to connection parameters */ + user->argv_handler = guac_ssh_argv_handler; + /* Display size change events */ user->size_handler = guac_ssh_user_size_handler; diff --git a/src/protocols/telnet/Makefile.am b/src/protocols/telnet/Makefile.am index bec0e955..d0264f67 100644 --- a/src/protocols/telnet/Makefile.am +++ b/src/protocols/telnet/Makefile.am @@ -29,6 +29,7 @@ ACLOCAL_AMFLAGS = -I m4 lib_LTLIBRARIES = libguac-client-telnet.la libguac_client_telnet_la_SOURCES = \ + argv.c \ client.c \ clipboard.c \ input.c \ @@ -38,6 +39,7 @@ libguac_client_telnet_la_SOURCES = \ user.c noinst_HEADERS = \ + argv.h \ client.h \ clipboard.h \ input.h \ diff --git a/src/protocols/telnet/argv.c b/src/protocols/telnet/argv.c new file mode 100644 index 00000000..da405aa9 --- /dev/null +++ b/src/protocols/telnet/argv.c @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "config.h" +#include "argv.h" +#include "telnet.h" +#include "terminal/terminal.h" + +#include +#include +#include + +#include +#include + +/** + * The value or current status of a connection parameter received over an + * "argv" stream. + */ +typedef struct guac_telnet_argv { + + /** + * Buffer space for containing the received argument value. + */ + char buffer[16384]; + + /** + * The number of bytes received so far. + */ + int length; + +} guac_telnet_argv; + +/** + * Handler for "blob" instructions which appends the data from received blobs + * to the end of the in-progress argument value buffer. + * + * @see guac_user_blob_handler + */ +static int guac_telnet_argv_blob_handler(guac_user* user, + guac_stream* stream, void* data, int length) { + + guac_telnet_argv* argv = (guac_telnet_argv*) stream->data; + + /* Calculate buffer size remaining, including space for null terminator, + * adjusting received length accordingly */ + int remaining = sizeof(argv->buffer) - argv->length - 1; + if (length > remaining) + length = remaining; + + /* Append received data to end of buffer */ + memcpy(argv->buffer + argv->length, data, length); + argv->length += length; + + return 0; + +} + +/** + * Handler for "end" instructions which applies the changes specified by the + * argument value buffer associated with the stream. + * + * @see guac_user_end_handler + */ +static int guac_telnet_argv_end_handler(guac_user* user, + guac_stream* stream) { + + guac_client* client = user->client; + guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; + guac_terminal* terminal = telnet_client->term; + + /* Append null terminator to value */ + guac_telnet_argv* argv = (guac_telnet_argv*) stream->data; + argv->buffer[argv->length] = '\0'; + + /* Update color scheme */ + guac_terminal_apply_color_scheme(terminal, argv->buffer); + free(argv); + return 0; + +} + +int guac_telnet_argv_handler(guac_user* user, guac_stream* stream, + char* mimetype, char* name) { + + /* Allow users to update the color scheme */ + if (strcmp(name, "color-scheme") == 0) { + + guac_telnet_argv* argv = malloc(sizeof(guac_telnet_argv)); + argv->length = 0; + + /* Prepare stream to receive argument value */ + stream->blob_handler = guac_telnet_argv_blob_handler; + stream->end_handler = guac_telnet_argv_end_handler; + stream->data = argv; + + /* Signal stream is ready */ + guac_protocol_send_ack(user->socket, stream, "Ready for color " + "scheme.", GUAC_PROTOCOL_STATUS_SUCCESS); + guac_socket_flush(user->socket); + return 0; + + } + + /* No other connection parameters may be updated */ + guac_protocol_send_ack(user->socket, stream, "Not allowed.", + GUAC_PROTOCOL_STATUS_CLIENT_FORBIDDEN); + guac_socket_flush(user->socket); + return 0; + +} + diff --git a/src/protocols/telnet/argv.h b/src/protocols/telnet/argv.h new file mode 100644 index 00000000..b1567ea8 --- /dev/null +++ b/src/protocols/telnet/argv.h @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef GUAC_TELNET_ARGV_H +#define GUAC_TELNET_ARGV_H + +#include "config.h" + +#include + +/** + * Handles an incoming stream from a Guacamole "argv" instruction, updating the + * given connection parameter if that parameter is allowed to be updated. + */ +guac_user_argv_handler guac_telnet_argv_handler; + +#endif + diff --git a/src/protocols/telnet/user.c b/src/protocols/telnet/user.c index 2e34f780..44ef9b5e 100644 --- a/src/protocols/telnet/user.c +++ b/src/protocols/telnet/user.c @@ -19,6 +19,7 @@ #include "config.h" +#include "argv.h" #include "clipboard.h" #include "input.h" #include "pipe.h" @@ -86,6 +87,9 @@ int guac_telnet_user_join_handler(guac_user* user, int argc, char** argv) { /* STDIN redirection */ user->pipe_handler = guac_telnet_pipe_handler; + /* Updates to connection parameters */ + user->argv_handler = guac_telnet_argv_handler; + /* Display size change events */ user->size_handler = guac_telnet_user_size_handler; diff --git a/src/terminal/display.c b/src/terminal/display.c index c4c74713..480e8398 100644 --- a/src/terminal/display.c +++ b/src/terminal/display.c @@ -199,7 +199,7 @@ int __guac_terminal_set(guac_terminal_display* display, int row, int col, int co guac_terminal_display* guac_terminal_display_alloc(guac_client* client, const char* font_name, int font_size, int dpi, guac_terminal_color* foreground, guac_terminal_color* background, - const guac_terminal_color (*palette)[256]) { + guac_terminal_color (*palette)[256]) { PangoFontMap* font_map; PangoFont* font; @@ -271,7 +271,7 @@ guac_terminal_display* guac_terminal_display_alloc(guac_client* client, void guac_terminal_display_free(guac_terminal_display* display) { /* Free default palette. */ - free((void*) display->default_palette); + free(display->default_palette); /* Free operations buffers */ free(display->operations); diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index a99bfb05..c12df4b9 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -384,7 +384,7 @@ guac_terminal* guac_terminal_create(guac_client* client, font_name, font_size, dpi, &default_char.attributes.foreground, &default_char.attributes.background, - (const guac_terminal_color(*)[256]) default_palette); + (guac_terminal_color(*)[256]) default_palette); /* Fail if display init failed */ if (term->display == NULL) { @@ -1940,3 +1940,30 @@ void guac_terminal_dup(guac_terminal* term, guac_user* user, } +void guac_terminal_apply_color_scheme(guac_terminal* terminal, + const char* color_scheme) { + + guac_client* client = terminal->client; + guac_terminal_char* default_char = &terminal->default_char; + guac_terminal_display* display = terminal->display; + + /* Reinitialize default terminal colors with values from color scheme */ + guac_terminal_parse_color_scheme(client, color_scheme, + &default_char->attributes.foreground, + &default_char->attributes.background, + display->default_palette); + + /* Reinitialize default attributes of buffer and display */ + terminal->buffer->default_character = *default_char; + display->default_foreground = default_char->attributes.foreground; + display->default_background = default_char->attributes.background; + + /* Redraw background with new color */ + guac_terminal_repaint_default_layer(terminal, client->socket); + + /* Force reset of terminal state */ + guac_terminal_reset(terminal); + guac_terminal_notify(terminal); + +} + diff --git a/src/terminal/terminal/display.h b/src/terminal/terminal/display.h index e54003bb..b1274235 100644 --- a/src/terminal/terminal/display.h +++ b/src/terminal/terminal/display.h @@ -142,7 +142,7 @@ typedef struct guac_terminal_display { * The default palette. Use GUAC_TERMINAL_INITIAL_PALETTE if null. * Must free on destruction if not null. */ - const guac_terminal_color (*default_palette)[256]; + guac_terminal_color (*default_palette)[256]; /** * Default foreground color for all glyphs. @@ -215,7 +215,7 @@ typedef struct guac_terminal_display { guac_terminal_display* guac_terminal_display_alloc(guac_client* client, const char* font_name, int font_size, int dpi, guac_terminal_color* foreground, guac_terminal_color* background, - const guac_terminal_color (*palette)[256]); + guac_terminal_color (*palette)[256]); /** * Frees the given display. diff --git a/src/terminal/terminal/terminal.h b/src/terminal/terminal/terminal.h index aee7742c..6de984bf 100644 --- a/src/terminal/terminal/terminal.h +++ b/src/terminal/terminal/terminal.h @@ -1072,5 +1072,20 @@ int guac_terminal_create_typescript(guac_terminal* term, const char* path, */ int guac_terminal_available_scroll(guac_terminal* term); +/** + * Immediately applies the given color scheme to the given terminal, overriding + * the color scheme provided when the terminal was created. Applying the color + * scheme implicitly clears the display and resets the terminal state. Valid + * color schemes are those accepted by guac_terminal_parse_color_scheme(). + * + * @param terminal + * The terminal to apply the color scheme to. + * + * @param color_scheme + * The color scheme to apply. + */ +void guac_terminal_apply_color_scheme(guac_terminal* terminal, + const char* color_scheme); + #endif