From e3d1a3f02367ec65bbba5e36f2be540e54df2c73 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 4 Aug 2011 19:17:44 -0700 Subject: [PATCH] Switching to handler functions rather than state values. --- protocols/ssh/Makefile.am | 2 +- protocols/ssh/include/ssh_client.h | 3 + protocols/ssh/include/ssh_terminal.h | 16 +- protocols/ssh/include/ssh_terminal_handlers.h | 61 ++++ protocols/ssh/src/ssh_client.c | 55 ++- protocols/ssh/src/ssh_terminal.c | 294 +--------------- protocols/ssh/src/ssh_terminal_handlers.c | 332 ++++++++++++++++++ 7 files changed, 459 insertions(+), 304 deletions(-) create mode 100644 protocols/ssh/include/ssh_terminal_handlers.h create mode 100644 protocols/ssh/src/ssh_terminal_handlers.c diff --git a/protocols/ssh/Makefile.am b/protocols/ssh/Makefile.am index 015802a6..915f9ba9 100644 --- a/protocols/ssh/Makefile.am +++ b/protocols/ssh/Makefile.am @@ -40,7 +40,7 @@ ACLOCAL_AMFLAGS = -I m4 lib_LTLIBRARIES = libguac-client-ssh.la -libguac_client_ssh_la_SOURCES = src/ssh_client.c src/ssh_handlers.c src/ssh_terminal.c +libguac_client_ssh_la_SOURCES = src/ssh_client.c src/ssh_handlers.c src/ssh_terminal.c src/ssh_terminal_handlers.c libguac_client_ssh_la_CFLAGS = -Werror -Wall -pedantic -Iinclude @PANGO_CFLAGS@ @PANGOCAIRO_CFLAGS@ libguac_client_ssh_la_LIBADD = @PANGO_LIBS@ @PANGOCAIRO_LIBS@ diff --git a/protocols/ssh/include/ssh_client.h b/protocols/ssh/include/ssh_client.h index 326140e5..205cc930 100644 --- a/protocols/ssh/include/ssh_client.h +++ b/protocols/ssh/include/ssh_client.h @@ -62,6 +62,9 @@ typedef struct ssh_guac_client_data { ssh_guac_terminal* term; + char password[1024]; + int password_length; + } ssh_guac_client_data; int ssh_guac_client_auth(guac_client* client, const char* password); diff --git a/protocols/ssh/include/ssh_terminal.h b/protocols/ssh/include/ssh_terminal.h index ab96aee4..b5cb33ed 100644 --- a/protocols/ssh/include/ssh_terminal.h +++ b/protocols/ssh/include/ssh_terminal.h @@ -49,14 +49,11 @@ #include #include -#define SSH_TERM_STATE_NULL 0 -#define SSH_TERM_STATE_ECHO 1 -#define SSH_TERM_STATE_ESC 2 -#define SSH_TERM_STATE_CSI 3 -#define SSH_TERM_STATE_OSC 4 -#define SSH_TERM_STATE_CHARSET 5 +typedef struct ssh_guac_terminal ssh_guac_terminal; -typedef struct ssh_guac_terminal { +typedef int ssh_guac_terminal_char_handler(ssh_guac_terminal* term, char c); + +struct ssh_guac_terminal { PangoFontDescription* font_desc; @@ -68,7 +65,7 @@ typedef struct ssh_guac_terminal { int term_width; int term_height; - int term_state; + ssh_guac_terminal_char_handler* char_handler; int term_seq_argc; int term_seq_argv[16]; @@ -78,12 +75,13 @@ typedef struct ssh_guac_terminal { int cursor_row; int cursor_col; -} ssh_guac_terminal; +}; ssh_guac_terminal* ssh_guac_terminal_create(guac_client* client); void ssh_guac_terminal_free(ssh_guac_terminal* term); int ssh_guac_terminal_write(ssh_guac_terminal* term, const char* c, int size); +int ssh_guac_terminal_send_glyph(ssh_guac_terminal* term, int row, int col, char c); #endif diff --git a/protocols/ssh/include/ssh_terminal_handlers.h b/protocols/ssh/include/ssh_terminal_handlers.h new file mode 100644 index 00000000..ed6b7430 --- /dev/null +++ b/protocols/ssh/include/ssh_terminal_handlers.h @@ -0,0 +1,61 @@ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is libguac-client-ssh. + * + * The Initial Developer of the Original Code is + * Michael Jumper. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _SSH_GUAC_TERMINAL_HANDLERS +#define _SSH_GUAC_TERMINAL_HANDLERS + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "ssh_terminal.h" + +int ssh_guac_terminal_echo(ssh_guac_terminal* term, char c); +int ssh_guac_terminal_escape(ssh_guac_terminal* term, char c); +int ssh_guac_terminal_charset(ssh_guac_terminal* term, char c); +int ssh_guac_terminal_csi(ssh_guac_terminal* term, char c); +int ssh_guac_terminal_osc(ssh_guac_terminal* term, char c); + +#endif + diff --git a/protocols/ssh/src/ssh_client.c b/protocols/ssh/src/ssh_client.c index 4c992a44..49147fb2 100644 --- a/protocols/ssh/src/ssh_client.c +++ b/protocols/ssh/src/ssh_client.c @@ -64,10 +64,49 @@ const char* GUAC_CLIENT_ARGS[] = { NULL }; -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_send_glyph(guac_client* client, int row, int col, char c); -int ssh_guac_client_write(guac_client* client, const char* c, int size); +int ssh_guac_client_password_key_handler(guac_client* client, int keysym, int pressed) { + + ssh_guac_client_data* client_data = (ssh_guac_client_data*) client->data; + + /* If key pressed */ + if (pressed) { + + /* If simple ASCII key */ + if (keysym >= 0x00 && keysym <= 0xFF) { + /* Add to password */ + client_data->password[client_data->password_length++] = keysym; + ssh_guac_terminal_write(client_data->term, "*", 1); + guac_flush(client->io); + } + else if (keysym == 0xFF08) { + + if (client_data->password_length > 0) { + client_data->password_length--; + + /* Backspace */ + ssh_guac_terminal_write(client_data->term, "\x08\x1B[K", 4); + guac_flush(client->io); + } + + } + else if (keysym == 0xFF0D) { + + /* Finish password */ + client_data->password[client_data->password_length] = '\0'; + + /* Clear screen */ + ssh_guac_terminal_write(client_data->term, "\x1B[2J\x1B[1;1H", 10); + guac_flush(client->io); + + return ssh_guac_client_auth(client, client_data->password); + + } + + } + + return 0; + +} int guac_client_init(guac_client* client, int argc, char** argv) { @@ -113,6 +152,13 @@ int guac_client_init(guac_client* client, int argc, char** argv) { /* Otherwise, prompt for password */ else { + + client_data->password_length = 0; + ssh_guac_terminal_write(client_data->term, "Password: ", 10); + guac_flush(client->io); + + client->key_handler = ssh_guac_client_password_key_handler; + } /* Success */ @@ -181,3 +227,4 @@ int ssh_guac_client_auth(guac_client* client, const char* password) { } + diff --git a/protocols/ssh/src/ssh_terminal.c b/protocols/ssh/src/ssh_terminal.c index d55a0383..99aa273c 100644 --- a/protocols/ssh/src/ssh_terminal.c +++ b/protocols/ssh/src/ssh_terminal.c @@ -47,6 +47,7 @@ #include #include "ssh_terminal.h" +#include "ssh_terminal_handlers.h" ssh_guac_terminal* ssh_guac_terminal_create(guac_client* client) { @@ -63,7 +64,7 @@ ssh_guac_terminal* ssh_guac_terminal_create(guac_client* client) { term->term_width = 160; term->term_height = 50; - term->term_state = SSH_TERM_STATE_ECHO; + term->char_handler = ssh_guac_terminal_echo; /* Get font */ term->font_desc = pango_font_description_new(); @@ -148,7 +149,7 @@ guac_layer* __ssh_guac_terminal_get_glyph(ssh_guac_terminal* term, char c) { } -int __ssh_guac_terminal_send_glyph(ssh_guac_terminal* term, int row, int col, char c) { +int ssh_guac_terminal_send_glyph(ssh_guac_terminal* term, int row, int col, char c) { GUACIO* io = term->client->io; guac_layer* glyph = __ssh_guac_terminal_get_glyph(term, c); @@ -163,295 +164,8 @@ int __ssh_guac_terminal_send_glyph(ssh_guac_terminal* term, int row, int col, ch int ssh_guac_terminal_write(ssh_guac_terminal* term, const char* c, int size) { - GUACIO* io = term->client->io; - while (size > 0) { - - switch (term->term_state) { - - case SSH_TERM_STATE_NULL: - break; - - case SSH_TERM_STATE_ECHO: - - /* Wrap if necessary */ - if (term->cursor_col >= term->term_width) { - term->cursor_col = 0; - term->cursor_row++; - } - - /* Scroll up if necessary */ - if (term->cursor_row >= term->term_height) { - term->cursor_row = term->term_height - 1; - - /* Copy screen up by one row */ - guac_send_copy(io, - GUAC_DEFAULT_LAYER, 0, term->char_height, - term->char_width * term->term_width, - term->char_height * (term->term_height - 1), - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, 0, 0); - - /* Fill bottom row with background */ - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, term->char_height * (term->term_height - 1), - term->char_width * term->term_width, - term->char_height * term->term_height, - 0, 0, 0, 255); - - } - - - - switch (*c) { - - /* Bell */ - case 0x07: - break; - - /* Backspace */ - case 0x08: - if (term->cursor_col >= 1) - term->cursor_col--; - break; - - /* Carriage return */ - case '\r': - term->cursor_col = 0; - break; - - /* Line feed */ - case '\n': - term->cursor_row++; - break; - - /* ESC */ - case 0x1B: - term->term_state = SSH_TERM_STATE_ESC; - break; - - /* Displayable chars */ - default: - __ssh_guac_terminal_send_glyph(term, - term->cursor_row, - term->cursor_col, - *c); - - /* Advance cursor */ - term->cursor_col++; - } - - /* End of SSH_TERM_STATE_ECHO */ - break; - - case SSH_TERM_STATE_CHARSET: - term->term_state = SSH_TERM_STATE_ECHO; - break; - - case SSH_TERM_STATE_ESC: - - switch (*c) { - - case '(': - term->term_state = SSH_TERM_STATE_CHARSET; - break; - - case ']': - term->term_state = SSH_TERM_STATE_OSC; - term->term_seq_argc = 0; - term->term_seq_argv_buffer_current = 0; - break; - - case '[': - term->term_state = SSH_TERM_STATE_CSI; - term->term_seq_argc = 0; - term->term_seq_argv_buffer_current = 0; - break; - - default: - guac_log_info("Unhandled ESC sequence: %c", *c); - term->term_state = SSH_TERM_STATE_ECHO; - - } - - /* End of SSH_TERM_STATE_ESC */ - break; - - case SSH_TERM_STATE_OSC: - - /* TODO: Implement OSC */ - if (*c == 0x9C || *c == 0x5C || *c == 0x07) /* ECMA-48 ST (String Terminator */ - term->term_state = SSH_TERM_STATE_ECHO; - - /* End of SSH_TERM_STATE_OSC */ - break; - - case SSH_TERM_STATE_CSI: - - /* FIXME: "The sequence of parameters may be preceded by a single question mark. */ - if (*c == '?') - break; /* Ignore question marks for now... */ - - /* Digits get concatenated into argv */ - if (*c >= '0' && *c <= '9') { - - /* Concatenate digit if there is space in buffer */ - if (term->term_seq_argv_buffer_current < - sizeof(term->term_seq_argv_buffer)) { - - term->term_seq_argv_buffer[ - term->term_seq_argv_buffer_current++ - ] = *c; - } - - } - - /* Any non-digit stops the parameter, and possibly the sequence */ - else { - - /* At most 16 parameters */ - if (term->term_seq_argc < 16) { - /* Finish parameter */ - term->term_seq_argv_buffer[term->term_seq_argv_buffer_current] = 0; - term->term_seq_argv[term->term_seq_argc++] = - atoi(term->term_seq_argv_buffer); - - /* Prepare for next parameter */ - term->term_seq_argv_buffer_current = 0; - } - - /* Handle CSI functions */ - switch (*c) { - - /* H: Move cursor */ - case 'H': - term->cursor_row = term->term_seq_argv[0] - 1; - term->cursor_col = term->term_seq_argv[1] - 1; - break; - - /* J: Erase display */ - case 'J': - - /* Erase from cursor to end of display */ - if (term->term_seq_argv[0] == 0) { - - /* Until end of line */ - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - term->cursor_col * term->char_width, - term->cursor_row * term->char_height, - (term->term_width - term->cursor_col) * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - - /* Until end of display */ - if (term->cursor_row < term->term_height - 1) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - (term->cursor_row+1) * term->char_height, - term->term_width * term->char_width, - term->term_height * term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - } - - /* Erase from start to cursor */ - else if (term->term_seq_argv[0] == 1) { - - /* Until start of line */ - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - term->cursor_row * term->char_height, - term->cursor_col * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - - /* From start */ - if (term->cursor_row >= 1) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - 0, - term->term_width * term->char_width, - (term->cursor_row-1) * term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - } - - /* Entire screen */ - else if (term->term_seq_argv[0] == 2) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - 0, - term->term_width * term->char_width, - term->term_height * term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - break; - - /* K: Erase line */ - case 'K': - - /* Erase from cursor to end of line */ - if (term->term_seq_argv[0] == 0) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - term->cursor_col * term->char_width, - term->cursor_row * term->char_height, - (term->term_width - term->cursor_col) * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - /* Erase from start to cursor */ - else if (term->term_seq_argv[0] == 1) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - term->cursor_row * term->char_height, - term->cursor_col * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - /* Erase line */ - else if (term->term_seq_argv[0] == 2) { - guac_send_rect(io, - GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, - 0, - term->cursor_row * term->char_height, - term->term_width * term->char_width, - term->char_height, - 0, 0, 0, 255); /* Background color */ - } - - break; - - /* Warn of unhandled codes */ - default: - if (*c != ';') - guac_log_info("Unhandled CSI sequence: %c", *c); - - } - - /* If not a semicolon, end of CSI sequence */ - if (*c != ';') - term->term_state = SSH_TERM_STATE_ECHO; - - } - - /* End of SSH_TERM_STATE_CSI */ - break; - - } - - c++; + term->char_handler(term, *(c++)); size--; } diff --git a/protocols/ssh/src/ssh_terminal_handlers.c b/protocols/ssh/src/ssh_terminal_handlers.c new file mode 100644 index 00000000..710a6eeb --- /dev/null +++ b/protocols/ssh/src/ssh_terminal_handlers.c @@ -0,0 +1,332 @@ + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is libguac-client-ssh. + * + * The Initial Developer of the Original Code is + * Michael Jumper. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "ssh_terminal.h" +#include "ssh_terminal_handlers.h" + +int ssh_guac_terminal_echo(ssh_guac_terminal* term, char c) { + + GUACIO* io = term->client->io; + + /* Wrap if necessary */ + if (term->cursor_col >= term->term_width) { + term->cursor_col = 0; + term->cursor_row++; + } + + /* Scroll up if necessary */ + if (term->cursor_row >= term->term_height) { + term->cursor_row = term->term_height - 1; + + /* Copy screen up by one row */ + guac_send_copy(io, + GUAC_DEFAULT_LAYER, 0, term->char_height, + term->char_width * term->term_width, + term->char_height * (term->term_height - 1), + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, 0, 0); + + /* Fill bottom row with background */ + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, term->char_height * (term->term_height - 1), + term->char_width * term->term_width, + term->char_height * term->term_height, + 0, 0, 0, 255); + + } + + switch (c) { + + /* Bell */ + case 0x07: + break; + + /* Backspace */ + case 0x08: + if (term->cursor_col >= 1) + term->cursor_col--; + break; + + /* Carriage return */ + case '\r': + term->cursor_col = 0; + break; + + /* Line feed */ + case '\n': + term->cursor_row++; + break; + + /* ESC */ + case 0x1B: + term->char_handler = ssh_guac_terminal_escape; + break; + + /* Displayable chars */ + default: + ssh_guac_terminal_send_glyph(term, + term->cursor_row, + term->cursor_col, + c); + + /* Advance cursor */ + term->cursor_col++; + } + + return 0; + +} + +int ssh_guac_terminal_escape(ssh_guac_terminal* term, char c) { + + switch (c) { + + case '(': + term->char_handler = ssh_guac_terminal_charset; + break; + + case ']': + term->char_handler = ssh_guac_terminal_osc; + term->term_seq_argc = 0; + term->term_seq_argv_buffer_current = 0; + break; + + case '[': + term->char_handler = ssh_guac_terminal_csi; + term->term_seq_argc = 0; + term->term_seq_argv_buffer_current = 0; + break; + + default: + guac_log_info("Unhandled ESC sequence: %c", c); + term->char_handler = ssh_guac_terminal_echo; + + } + + return 0; + +} + +int ssh_guac_terminal_charset(ssh_guac_terminal* term, char c) { + term->char_handler = ssh_guac_terminal_echo; + return 0; +} + +int ssh_guac_terminal_csi(ssh_guac_terminal* term, char c) { + + GUACIO* io = term->client->io; + + /* FIXME: "The sequence of parameters may be preceded by a single question mark. */ + if (c == '?') + return 0; + + /* Digits get concatenated into argv */ + if (c >= '0' && c <= '9') { + + /* Concatenate digit if there is space in buffer */ + if (term->term_seq_argv_buffer_current < + sizeof(term->term_seq_argv_buffer)) { + + term->term_seq_argv_buffer[ + term->term_seq_argv_buffer_current++ + ] = c; + } + + } + + /* Any non-digit stops the parameter, and possibly the sequence */ + else { + + /* At most 16 parameters */ + if (term->term_seq_argc < 16) { + /* Finish parameter */ + term->term_seq_argv_buffer[term->term_seq_argv_buffer_current] = 0; + term->term_seq_argv[term->term_seq_argc++] = + atoi(term->term_seq_argv_buffer); + + /* Prepare for next parameter */ + term->term_seq_argv_buffer_current = 0; + } + + /* Handle CSI functions */ + switch (c) { + + /* H: Move cursor */ + case 'H': + term->cursor_row = term->term_seq_argv[0] - 1; + term->cursor_col = term->term_seq_argv[1] - 1; + break; + + /* J: Erase display */ + case 'J': + + /* Erase from cursor to end of display */ + if (term->term_seq_argv[0] == 0) { + + /* Until end of line */ + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + term->cursor_col * term->char_width, + term->cursor_row * term->char_height, + (term->term_width - term->cursor_col) * term->char_width, + term->char_height, + 0, 0, 0, 255); /* Background color */ + + /* Until end of display */ + if (term->cursor_row < term->term_height - 1) { + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, + (term->cursor_row+1) * term->char_height, + term->term_width * term->char_width, + term->term_height * term->char_height, + 0, 0, 0, 255); /* Background color */ + } + + } + + /* Erase from start to cursor */ + else if (term->term_seq_argv[0] == 1) { + + /* Until start of line */ + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, + term->cursor_row * term->char_height, + term->cursor_col * term->char_width, + term->char_height, + 0, 0, 0, 255); /* Background color */ + + /* From start */ + if (term->cursor_row >= 1) { + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, + 0, + term->term_width * term->char_width, + (term->cursor_row-1) * term->char_height, + 0, 0, 0, 255); /* Background color */ + } + + } + + /* Entire screen */ + else if (term->term_seq_argv[0] == 2) { + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, + 0, + term->term_width * term->char_width, + term->term_height * term->char_height, + 0, 0, 0, 255); /* Background color */ + } + + break; + + /* K: Erase line */ + case 'K': + + /* Erase from cursor to end of line */ + if (term->term_seq_argv[0] == 0) { + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + term->cursor_col * term->char_width, + term->cursor_row * term->char_height, + (term->term_width - term->cursor_col) * term->char_width, + term->char_height, + 0, 0, 0, 255); /* Background color */ + } + + /* Erase from start to cursor */ + else if (term->term_seq_argv[0] == 1) { + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, + term->cursor_row * term->char_height, + term->cursor_col * term->char_width, + term->char_height, + 0, 0, 0, 255); /* Background color */ + } + + /* Erase line */ + else if (term->term_seq_argv[0] == 2) { + guac_send_rect(io, + GUAC_COMP_SRC, GUAC_DEFAULT_LAYER, + 0, + term->cursor_row * term->char_height, + term->term_width * term->char_width, + term->char_height, + 0, 0, 0, 255); /* Background color */ + } + + break; + + /* Warn of unhandled codes */ + default: + if (c != ';') + guac_log_info("Unhandled CSI sequence: %c", c); + + } + + /* If not a semicolon, end of CSI sequence */ + if (c != ';') + term->char_handler = ssh_guac_terminal_echo; + + } + + return 0; + +} + +int ssh_guac_terminal_osc(ssh_guac_terminal* term, char c) { + /* TODO: Implement OSC */ + if (c == 0x9C || c == 0x5C || c == 0x07) /* ECMA-48 ST (String Terminator */ + term->char_handler = ssh_guac_terminal_echo; + return 0; +} +