From 6c0cd22b903e041575c9749bbf04c1198fe05282 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 8 Jan 2016 12:47:02 -0800 Subject: [PATCH 01/10] GUAC-1452: Update guacctl defining the terminal codes for controlling pipe streams. --- bin/guacctl | 72 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/bin/guacctl b/bin/guacctl index 4c0508f1..252c8c4d 100755 --- a/bin/guacctl +++ b/bin/guacctl @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (C) 2013 Glyptodon LLC +# Copyright (C) 2016 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 @@ -25,11 +25,12 @@ # guacctl # ------- # -# Utility for sending Guacamole-specific console codes for controlling the SSH -# session, such as: +# Utility for sending Guacamole-specific console codes for controlling a +# terminal session, such as: # -# * Downloading files -# * Setting the destination directory for uploads +# * Downloading files (SSH only) +# * Setting the destination directory for uploads (SSH only) +# * Redirecting output to a named pipe stream (SSH or telnet) # # This script may also be run as "guacget", in which case the script accepts # no options and assumes anything given on the commandline is a file to be @@ -58,6 +59,19 @@ send_set_directory() { printf "\033]482201;%s\007" "$FILENAME" } +# Sends the Guacamole-specific console code for redirecting output to a named +# pipe stream (instead of the terminal emulator) +send_open_pipe_stream() { + NAME="$1" + printf "\033]482202;%s\007" "$NAME" +} + +# Sends the Guacamole-specific console code for redirecting output back to the +# terminal emulator +send_close_pipe_stream() { + printf "\033]482203\007" +} + # Prints the given error text to STDERR. error() { echo "$NAME:" "$@" >&2 @@ -66,12 +80,16 @@ error() { # Prints usage documentation for this script. usage() { cat >&2 < Date: Fri, 8 Jan 2016 12:58:19 -0800 Subject: [PATCH 02/10] GUAC-1452: Clean up comment style within guacctl. --- bin/guacctl | 117 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 17 deletions(-) diff --git a/bin/guacctl b/bin/guacctl index 252c8c4d..e1cc1bec 100755 --- a/bin/guacctl +++ b/bin/guacctl @@ -37,9 +37,13 @@ # downloaded. # - -# Given the name of a file, which may be a relative path, produce the full, -# real, non-relative path for that same file. +## +## Given the name of a file, which may be a relative path, produce the full, +## real, non-relative path for that same file. +## +## @param FILENAME +## The name of the file to produce the full path of. +## fullpath() { FILENAME="$1" DIR=`dirname "$FILENAME"` @@ -47,37 +51,61 @@ fullpath() { (cd "$DIR" && echo "$PWD/$FILE") } -# Sends the Guacamole-specific console code for initiating a download. +## +## Sends the Guacamole-specific console code for initiating a download. +## +## @param FILENAME +## The full path of the file to download. +## send_download_file() { FILENAME="$1" printf "\033]482200;%s\007" "$FILENAME" } -# Sends the Guacamole-specific console code for setting the upload directory. +## +## Sends the Guacamole-specific console code for setting the upload directory. +## +## @param FILENAME +## The full path to the directory which should receive uploads. +## send_set_directory() { FILENAME="$1" printf "\033]482201;%s\007" "$FILENAME" } -# Sends the Guacamole-specific console code for redirecting output to a named -# pipe stream (instead of the terminal emulator) +## +## Sends the Guacamole-specific console code for redirecting output to a named +## pipe stream (instead of the terminal emulator) +## +## @param NAME +## The name of the pipe stream to open. +## send_open_pipe_stream() { NAME="$1" printf "\033]482202;%s\007" "$NAME" } -# Sends the Guacamole-specific console code for redirecting output back to the -# terminal emulator +## +## Sends the Guacamole-specific console code for redirecting output back to the +## terminal emulator +## send_close_pipe_stream() { printf "\033]482203\007" } -# Prints the given error text to STDERR. +## +## Prints the given error text to STDERR. +## +## @param ... +## The text to print as an error message. +## error() { echo "$NAME:" "$@" >&2 } -# Prints usage documentation for this script. +## +## Prints usage documentation for this script. +## usage() { cat >&2 < Date: Fri, 8 Jan 2016 14:29:58 -0800 Subject: [PATCH 03/10] GUAC-1452: Clean up option parsing logic. --- bin/guacctl | 70 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/bin/guacctl b/bin/guacctl index e1cc1bec..27cac2eb 100755 --- a/bin/guacctl +++ b/bin/guacctl @@ -253,25 +253,63 @@ close_pipe_stream() { NAME=`basename "$0"` # -# Parse options +# Handle downloads directly if invoked as "guacget" # if [ "x$NAME" = "xguacget" ]; then download_files "$@" -elif [ "x$1" = "x--download" -o "x$1" = "x-d" ]; then - shift - download_files "$@" -elif [ "x$1" = "x--set-directory" -o "x$1" = "x-s" ]; then - shift - set_directory "$@" -elif [ "x$1" = "x--open-pipe" -o "x$1" = "x-o" ]; then - shift - open_pipe_stream "$@" -elif [ "x$1" = "x--close-pipe" -o "x$1" = "x-c" ]; then - shift - close_pipe_stream "$@" -else - usage - exit 1 + exit 0; fi +# +# Parse options +# + +case "$1" in + + # + # Download files + # + + "--download"|"-d") + shift + download_files "$@" + ;; + + # + # Set upload directory + # + + "--set-directory"|"-s") + shift + set_directory "$@" + ;; + + # + # Redirect to pipe + # + + "--open-pipe"|"-o") + shift + open_pipe_stream "$@" + ;; + + # + # Redirect back to terminal + # + + "--close-pipe"|"-c") + shift + close_pipe_stream "$@" + ;; + + # + # Show usage info if options are invalid + # + + *) + usage + exit 1 + ;; +esac + From 97bfcef20d3610660bd44c773c27f8a8d6fa135a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 Jan 2016 16:26:50 -0800 Subject: [PATCH 04/10] GUAC-1452: Add semicolon to pipe closure terminal code. --- bin/guacctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/guacctl b/bin/guacctl index 27cac2eb..6749ec0c 100755 --- a/bin/guacctl +++ b/bin/guacctl @@ -90,7 +90,7 @@ send_open_pipe_stream() { ## terminal emulator ## send_close_pipe_stream() { - printf "\033]482203\007" + printf "\033]482203;\007" } ## From b869edb0a2328151123fc8022279a706e284d5ba Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 Jan 2016 16:28:25 -0800 Subject: [PATCH 05/10] GUAC-1452: Add stub handlers for new pipe OSC codes. --- src/terminal/terminal_handlers.c | 43 ++++++++++++++++++++++++++++++++ src/terminal/terminal_handlers.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/src/terminal/terminal_handlers.c b/src/terminal/terminal_handlers.c index 49a45df1..a5e7085e 100644 --- a/src/terminal/terminal_handlers.c +++ b/src/terminal/terminal_handlers.c @@ -936,6 +936,41 @@ int guac_terminal_download(guac_terminal* term, unsigned char c) { } +int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c) { + + static char stream_name[2048]; + static int length = 0; + + /* Open pipe on ECMA-48 ST (String Terminator) */ + if (c == 0x9C || c == 0x5C || c == 0x07) { + stream_name[length++] = '\0'; + term->char_handler = guac_terminal_echo; + guac_client_log(term->client, GUAC_LOG_DEBUG, + "STUB: Opening pipe: '%s'", stream_name); + length = 0; + } + + /* Otherwise, store character within stream name */ + else if (length < sizeof(stream_name)-1) + stream_name[length++] = c; + + return 0; + +} + +int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c) { + + /* Handle closure on ECMA-48 ST (String Terminator) */ + if (c == 0x9C || c == 0x5C || c == 0x07) { + term->char_handler = guac_terminal_echo; + guac_client_log(term->client, GUAC_LOG_DEBUG, "STUB: Closing pipe"); + } + + /* Ignore all other characters */ + return 0; + +} + int guac_terminal_osc(guac_terminal* term, unsigned char c) { static int operation = 0; @@ -955,6 +990,14 @@ int guac_terminal_osc(guac_terminal* term, unsigned char c) { else if (operation == 482201) term->char_handler = guac_terminal_set_directory; + /* Open and redirect output to pipe stream OSC */ + else if (operation == 482202) + term->char_handler = guac_terminal_open_pipe_stream; + + /* Close pipe stream OSC */ + else if (operation == 482203) + term->char_handler = guac_terminal_close_pipe_stream; + /* Reset parameter for next OSC */ operation = 0; diff --git a/src/terminal/terminal_handlers.h b/src/terminal/terminal_handlers.h index a6d8f225..027ddc8f 100644 --- a/src/terminal/terminal_handlers.h +++ b/src/terminal/terminal_handlers.h @@ -35,6 +35,8 @@ int guac_terminal_g1_charset(guac_terminal* term, unsigned char c); int guac_terminal_csi(guac_terminal* term, unsigned char c); int guac_terminal_download(guac_terminal* term, unsigned char c); int guac_terminal_set_directory(guac_terminal* term, unsigned char c); +int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c); +int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c); int guac_terminal_osc(guac_terminal* term, unsigned char c); int guac_terminal_ctrl_func(guac_terminal* term, unsigned char c); From 528de383599f0fd195c9b5abe5b2ef89af292612 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 Jan 2016 16:47:19 -0800 Subject: [PATCH 06/10] GUAC-1452: Document terminal char handlers. --- src/terminal/terminal_handlers.h | 124 +++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/src/terminal/terminal_handlers.h b/src/terminal/terminal_handlers.h index 027ddc8f..daed43a0 100644 --- a/src/terminal/terminal_handlers.h +++ b/src/terminal/terminal_handlers.h @@ -28,16 +28,140 @@ #include "terminal.h" +/** + * The default mode of the terminal. This character handler simply echoes + * received characters to the terminal display, entering other terminal modes + * if control characters are received. + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_echo(guac_terminal* term, unsigned char c); + +/** + * Handles any characters which follow an ANSI ESC (0x1B) character. + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_escape(guac_terminal* term, unsigned char c); + +/** + * Selects the G0 character mapping from the provided character mapping + * specifier (such as B, 0, U, or K). + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_g0_charset(guac_terminal* term, unsigned char c); + +/** + * Selects the G1 character mapping from the provided character mapping + * specifier (such as B, 0, U, or K). + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_g1_charset(guac_terminal* term, unsigned char c); + +/** + * Handles characters within a CSI sequence. CSI sequences are most often + * introduced with "ESC [". + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_csi(guac_terminal* term, unsigned char c); + +/** + * Parses the remainder of the download initiation OSC specific to the + * Guacamole terminal emulator. A download will be initiated for the specified + * file once the OSC sequence is complete. + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_download(guac_terminal* term, unsigned char c); + +/** + * Parses the remainder of the set directory OSC specific to the Guacamole + * terminal emulator. The upload directory will be set to the specified path + * once the OSC sequence is complete. + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_set_directory(guac_terminal* term, unsigned char c); + +/** + * Parses the remainder of the open pipe OSC specific to the + * Guacamole terminal emulator. Terminal output will be redirected to a new + * named pipe having the given name once the OSC sequence is complete. + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c); + +/** + * Parses the remainder of the close pipe OSC specific to the Guacamole + * terminal emulator. Terminal output will be redirected back to the terminal + * display and any open named pipe will be closed once the OSC sequence is + * complete. + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c); + +/** + * Handles the remaining characters of an Operating System Code (OSC) sequence, + * typically initiated with "ESC ]". + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_osc(guac_terminal* term, unsigned char c); + +/** + * Handles terminal control function sequences initiated with "ESC #". + * + * @param term + * The terminal that received the given character of data. + * + * @param c + * The character that was received by the given terminal. + */ int guac_terminal_ctrl_func(guac_terminal* term, unsigned char c); #endif From 051701d566d1bc03c265979aac6251b336dcb460 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 Jan 2016 16:51:32 -0800 Subject: [PATCH 07/10] GUAC-1452: Provide for storage of pipe stream within terminal struct. --- src/terminal/terminal.c | 3 +++ src/terminal/terminal.h | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index cf7d84fe..9ee56812 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -326,6 +326,9 @@ guac_terminal* guac_terminal_create(guac_client* client, return NULL; } + /* Init pipe stream (output to display by default) */ + term->pipe_stream = NULL; + /* Init terminal lock */ pthread_mutex_init(&(term->lock), NULL); diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 488692d6..3b244ae0 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -149,6 +149,13 @@ struct guac_terminal { */ int stdin_pipe_fd[2]; + /** + * The currently-open pipe stream to which all terminal output should be + * written, if any. If no pipe stream is open, terminal output will be + * written to the terminal display, and this value will be NULL. + */ + guac_stream* pipe_stream; + /** * Graphical representation of the current scroll state. */ From 01edd8ccd8b90fa6c54fad6fad1e9a620443bc08 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 Jan 2016 17:07:32 -0800 Subject: [PATCH 08/10] GUAC-1452: Implement pipe open/close within OSC. --- src/terminal/terminal_handlers.c | 45 +++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/terminal/terminal_handlers.c b/src/terminal/terminal_handlers.c index a5e7085e..7ad23208 100644 --- a/src/terminal/terminal_handlers.c +++ b/src/terminal/terminal_handlers.c @@ -28,6 +28,8 @@ #include "types.h" #include +#include +#include #include #include @@ -938,16 +940,36 @@ int guac_terminal_download(guac_terminal* term, unsigned char c) { int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c) { + guac_client* client = term->client; + guac_socket* socket = client->socket; + static char stream_name[2048]; static int length = 0; /* Open pipe on ECMA-48 ST (String Terminator) */ if (c == 0x9C || c == 0x5C || c == 0x07) { + + /* End stream name string */ stream_name[length++] = '\0'; term->char_handler = guac_terminal_echo; - guac_client_log(term->client, GUAC_LOG_DEBUG, - "STUB: Opening pipe: '%s'", stream_name); length = 0; + + /* Close existing stream, if any */ + if (term->pipe_stream != NULL) { + guac_protocol_send_end(socket, term->pipe_stream); + guac_client_free_stream(client, term->pipe_stream); + } + + /* Allocate and assign new pipe stream */ + term->pipe_stream = guac_client_alloc_stream(client); + + /* Open new pipe stream */ + guac_protocol_send_pipe(socket, term->pipe_stream, + "text/plain", stream_name); + + /* Log redirect at debug level */ + guac_client_log(client, GUAC_LOG_DEBUG, + "Terminal output now redirected to pipe '%s'.", stream_name); } /* Otherwise, store character within stream name */ @@ -960,10 +982,27 @@ int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c) { int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c) { + guac_client* client = term->client; + guac_socket* socket = client->socket; + /* Handle closure on ECMA-48 ST (String Terminator) */ if (c == 0x9C || c == 0x5C || c == 0x07) { term->char_handler = guac_terminal_echo; - guac_client_log(term->client, GUAC_LOG_DEBUG, "STUB: Closing pipe"); + + /* Close any existing pipe */ + if (term->pipe_stream != NULL) { + guac_protocol_send_end(socket, term->pipe_stream); + guac_client_free_stream(client, term->pipe_stream); + term->pipe_stream = NULL; + guac_client_log(client, GUAC_LOG_DEBUG, + "Terminal output now redirected to display."); + } + + /* Warn if OSC is inappropriate */ + else + guac_client_log(client, GUAC_LOG_DEBUG, + "Cannot handle pipe close OSC - no open pipe exists."); + } /* Ignore all other characters */ From ff557a7f0150715e8a7b744d21b1215a5005b690 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 13 Jan 2016 17:38:13 -0800 Subject: [PATCH 09/10] GUAC-1452: Echo to pipe stream if open (buffered). --- src/terminal/terminal.c | 77 ++++++++++++++++++++++++++++++++ src/terminal/terminal.h | 66 +++++++++++++++++++++++++++ src/terminal/terminal_handlers.c | 46 ++++++------------- 3 files changed, 156 insertions(+), 33 deletions(-) diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 9ee56812..99ae54d6 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -1731,3 +1731,80 @@ int guac_terminal_next_tab(guac_terminal* term, int column) { return tabstop; } +void guac_terminal_pipe_stream_open(guac_terminal* term, const char* name) { + + guac_client* client = term->client; + guac_socket* socket = client->socket; + + /* Close existing stream, if any */ + guac_terminal_pipe_stream_close(term); + + /* Allocate and assign new pipe stream */ + term->pipe_stream = guac_client_alloc_stream(client); + term->pipe_buffer_length = 0; + + /* Open new pipe stream */ + guac_protocol_send_pipe(socket, term->pipe_stream, "text/plain", name); + + /* Log redirect at debug level */ + guac_client_log(client, GUAC_LOG_DEBUG, + "Terminal output now redirected to pipe '%s'.", name); + +} + +void guac_terminal_pipe_stream_write(guac_terminal* term, char c) { + + /* Append byte to buffer only if pipe is open */ + if (term->pipe_stream != NULL) { + + /* Flush buffer if no space is available */ + if (term->pipe_buffer_length == sizeof(term->pipe_buffer)) + guac_terminal_pipe_stream_flush(term); + + /* Append single byte to buffer */ + term->pipe_buffer[term->pipe_buffer_length++] = c; + + } + +} + +void guac_terminal_pipe_stream_flush(guac_terminal* term) { + + guac_client* client = term->client; + guac_socket* socket = client->socket; + guac_stream* pipe_stream = term->pipe_stream; + + /* Write blob if data exists in buffer */ + if (pipe_stream != NULL && term->pipe_buffer_length > 0) { + guac_protocol_send_blob(socket, pipe_stream, + term->pipe_buffer, term->pipe_buffer_length); + term->pipe_buffer_length = 0; + } + +} + +void guac_terminal_pipe_stream_close(guac_terminal* term) { + + guac_client* client = term->client; + guac_socket* socket = client->socket; + guac_stream* pipe_stream = term->pipe_stream; + + /* Close any existing pipe */ + if (pipe_stream != NULL) { + + /* Write end of stream */ + guac_terminal_pipe_stream_flush(term); + guac_protocol_send_end(socket, pipe_stream); + + /* Destroy stream */ + guac_client_free_stream(client, pipe_stream); + term->pipe_stream = NULL; + + /* Log redirect at debug level */ + guac_client_log(client, GUAC_LOG_DEBUG, + "Terminal output now redirected to display."); + + } + +} + diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 3b244ae0..91bebfa9 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -156,6 +156,19 @@ struct guac_terminal { */ guac_stream* pipe_stream; + /** + * Buffer of data pending write to the pipe_stream. Data within this buffer + * will be flushed to the pipe_stream when either (1) the buffer is full + * and another character needs to be written or (2) the pipe_stream is + * closed. + */ + char pipe_buffer[6048]; + + /** + * The number of bytes currently stored within the pipe_buffer. + */ + int pipe_buffer_length; + /** * Graphical representation of the current scroll state. */ @@ -663,5 +676,58 @@ void guac_terminal_clear_tabs(guac_terminal* term); */ int guac_terminal_next_tab(guac_terminal* term, int column); +/** + * Opens a new pipe stream, redirecting all output from the given terminal to + * that pipe stream. If a pipe stream is already open, that pipe stream will + * be flushed and closed prior to opening the new pipe stream. + * + * @param term + * The terminal which should redirect output to a new pipe stream having + * the given name. + * + * @param name + * The name of the pipe stream to open. + */ +void guac_terminal_pipe_stream_open(guac_terminal* term, const char* name); + +/** + * Writes a single byte of data to the pipe stream currently open and + * associated with the given terminal. The pipe stream must already have been + * opened via guac_terminal_pipe_stream_open(). If no pipe stream is currently + * open, this function has no effect. Data written through this function may + * be buffered. + * + * @param term + * The terminal whose currently-open pipe stream should be written to. + * + * @param c + * The byte of data to write to the pipe stream. + */ +void guac_terminal_pipe_stream_write(guac_terminal* term, char c); + +/** + * Flushes any data currently buffered for the currently-open pipe stream + * associated with the given terminal. The pipe stream must already have been + * opened via guac_terminal_pipe_stream_open(). If no pipe stream is currently + * open or no data is in the buffer, this function has no effect. + * + * @param term + * The terminal whose pipe stream buffer should be flushed. + */ +void guac_terminal_pipe_stream_flush(guac_terminal* term); + +/** + * Closes the currently-open pipe stream associated with the given terminal, + * redirecting all output back to the terminal display. Any data currently + * buffered for output to the pipe stream will be flushed prior to closure. The + * pipe stream must already have been opened via + * guac_terminal_pipe_stream_open(). If no pipe stream is currently open, this + * function has no effect. + * + * @param term + * The terminal whose currently-open pipe stream should be closed. + */ +void guac_terminal_pipe_stream_close(guac_terminal* term); + #endif diff --git a/src/terminal/terminal_handlers.c b/src/terminal/terminal_handlers.c index 7ad23208..ad943b00 100644 --- a/src/terminal/terminal_handlers.c +++ b/src/terminal/terminal_handlers.c @@ -59,6 +59,12 @@ int guac_terminal_echo(guac_terminal* term, unsigned char c) { const int* char_mapping = term->char_mapping[term->active_char_set]; + /* Echo to pipe stream if open and not starting an ESC sequence */ + if (term->pipe_stream != NULL && c != 0x1B) { + guac_terminal_pipe_stream_write(term, c); + return 0; + } + /* If using non-Unicode mapping, just map straight bytes */ if (char_mapping != NULL) { codepoint = c; @@ -940,9 +946,6 @@ int guac_terminal_download(guac_terminal* term, unsigned char c) { int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c) { - guac_client* client = term->client; - guac_socket* socket = client->socket; - static char stream_name[2048]; static int length = 0; @@ -951,25 +954,14 @@ int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c) { /* End stream name string */ stream_name[length++] = '\0'; - term->char_handler = guac_terminal_echo; length = 0; - /* Close existing stream, if any */ - if (term->pipe_stream != NULL) { - guac_protocol_send_end(socket, term->pipe_stream); - guac_client_free_stream(client, term->pipe_stream); - } - - /* Allocate and assign new pipe stream */ - term->pipe_stream = guac_client_alloc_stream(client); - /* Open new pipe stream */ - guac_protocol_send_pipe(socket, term->pipe_stream, - "text/plain", stream_name); + guac_terminal_pipe_stream_open(term, stream_name); + + /* Return to echo mode */ + term->char_handler = guac_terminal_echo; - /* Log redirect at debug level */ - guac_client_log(client, GUAC_LOG_DEBUG, - "Terminal output now redirected to pipe '%s'.", stream_name); } /* Otherwise, store character within stream name */ @@ -982,26 +974,14 @@ int guac_terminal_open_pipe_stream(guac_terminal* term, unsigned char c) { int guac_terminal_close_pipe_stream(guac_terminal* term, unsigned char c) { - guac_client* client = term->client; - guac_socket* socket = client->socket; - /* Handle closure on ECMA-48 ST (String Terminator) */ if (c == 0x9C || c == 0x5C || c == 0x07) { - term->char_handler = guac_terminal_echo; /* Close any existing pipe */ - if (term->pipe_stream != NULL) { - guac_protocol_send_end(socket, term->pipe_stream); - guac_client_free_stream(client, term->pipe_stream); - term->pipe_stream = NULL; - guac_client_log(client, GUAC_LOG_DEBUG, - "Terminal output now redirected to display."); - } + guac_terminal_pipe_stream_close(term); - /* Warn if OSC is inappropriate */ - else - guac_client_log(client, GUAC_LOG_DEBUG, - "Cannot handle pipe close OSC - no open pipe exists."); + /* Return to echo mode */ + term->char_handler = guac_terminal_echo; } From 4bc5ebe7da9d30b9146b157e232af054f2171f4d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 13 Jan 2016 18:07:37 -0800 Subject: [PATCH 10/10] GUAC-1452: Ensure pipe is flushed and closed if terminal is destroyed. --- src/terminal/terminal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index 99ae54d6..95a71806 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -371,7 +371,10 @@ guac_terminal* guac_terminal_create(guac_client* client, } void guac_terminal_free(guac_terminal* term) { - + + /* Close and flush any open pipe stream */ + guac_terminal_pipe_stream_close(term); + /* Close terminal output pipe */ close(term->stdout_pipe_fd[1]); close(term->stdout_pipe_fd[0]);