diff --git a/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java b/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java index c87d32a2f..a2cbc40b3 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java +++ b/guacamole/client/src/net/sourceforge/guacamole/GuacamoleClient.java @@ -113,7 +113,13 @@ public class GuacamoleClient extends Client { } public void setClipboard(String clipboard) throws GuacamoleException { - // STUB + try { + output.write("clipboard:" + Instruction.escape(clipboard) + ";"); + output.flush(); + } + catch (IOException e) { + throw new GuacamoleException(e); + } } public void disconnect() throws GuacamoleException { diff --git a/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java b/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java index 07f7e92d5..81e506e60 100644 --- a/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java +++ b/guacamole/client/src/net/sourceforge/guacamole/instruction/Instruction.java @@ -29,7 +29,7 @@ public abstract class Instruction { @Override public abstract String toString(); - public String escape(String str) { + public static String escape(String str) { StringBuffer sb = new StringBuffer(); diff --git a/guacamole/proxy/client.c b/guacamole/proxy/client.c index 0a6b37d81..859620f09 100644 --- a/guacamole/proxy/client.c +++ b/guacamole/proxy/client.c @@ -120,6 +120,14 @@ void guac_start_client(guac_client* client) { ); } + else if (strcmp(instruction.opcode, "clipboard") == 0) { + if (client->clipboard_handler) + client->clipboard_handler( + client, + guac_unescape_string_inplace(instruction.argv[0]) /* data */ + ); + } + } while ((retval = guac_read_instruction(io, &instruction)) > 0); if (retval < 0) diff --git a/guacamole/proxy/client.h b/guacamole/proxy/client.h index 7a0602005..a4d7403f5 100644 --- a/guacamole/proxy/client.h +++ b/guacamole/proxy/client.h @@ -32,6 +32,7 @@ typedef struct guac_client { void (*handle_messages)(struct guac_client* client); void (*mouse_handler)(struct guac_client* client, int x, int y, int button_mask); void (*key_handler)(struct guac_client* client, int keysym, int pressed); + void (*clipboard_handler)(struct guac_client* client, char* copied); void (*free_handler)(void* client); } guac_client; diff --git a/guacamole/proxy/protocol.c b/guacamole/proxy/protocol.c index a091f51a1..e0bb9096d 100644 --- a/guacamole/proxy/protocol.c +++ b/guacamole/proxy/protocol.c @@ -81,16 +81,65 @@ char* guac_escape_string(const char* str) { } + *current = '\0'; + return escaped; } +char* guac_unescape_string_inplace(char* str) { + + char* from; + char* to; + + from = to = str; + for (;;) { + + char c = *(from++); + + if (c == '\\') { + + c = *(from++); + if (c == 's') + *(to++) = ';'; + + else if (c == 'c') + *(to++) = ','; + + else if (c == '\\') + *(to++) = '\\'; + + else if (c == '\0') { + *(to++) = '\\'; + break; + } + + else { + *(to++) = '\\'; + *(to++) = c; + } + } + + else if (c == '\0') + break; + + else + *(to++) = c; + + } + + *to = '\0'; + + return str; + +} + void guac_send_name(GUACIO* io, const char* name) { char* escaped = guac_escape_string(name); guac_write_string(io, "name:"); - guac_write_string(io, name); + guac_write_string(io, escaped); guac_write_string(io, ";"); free(escaped); @@ -105,6 +154,30 @@ void guac_send_size(GUACIO* io, int w, int h) { guac_write_string(io, ";"); } +void guac_send_clipboard(GUACIO* io, const char* data) { + + char* escaped = guac_escape_string(data); + + guac_write_string(io, "clipboard:"); + guac_write_string(io, escaped); + guac_write_string(io, ";"); + + free(escaped); + +} + +void guac_send_error(GUACIO* io, const char* error) { + + char* escaped = guac_escape_string(error); + + guac_write_string(io, "error:"); + guac_write_string(io, escaped); + guac_write_string(io, ";"); + + free(escaped); + +} + void guac_send_copy(GUACIO* io, int srcx, int srcy, int w, int h, int dstx, int dsty) { guac_write_string(io, "copy:"); guac_write_int(io, srcx); diff --git a/guacamole/proxy/protocol.h b/guacamole/proxy/protocol.h index 798eaa571..6edb06ca4 100644 --- a/guacamole/proxy/protocol.h +++ b/guacamole/proxy/protocol.h @@ -36,7 +36,10 @@ typedef struct guac_instruction { void guac_free_instruction(guac_instruction* instruction); char* guac_escape_string(const char* str); +char* guac_unescape_string_inplace(char* str); void guac_send_name(GUACIO* io, const char* name); +void guac_send_error(GUACIO* io, const char* error); +void guac_send_clipboard(GUACIO* io, const char* data); void guac_send_size(GUACIO* io, int w, int h); void guac_send_copy(GUACIO* io, int srcx, int srcy, int w, int h, int dstx, int dsty); void guac_send_png(GUACIO* io, int x, int y, png_byte** png_rows, int w, int h); diff --git a/guacamole/proxy/vnc_client.c b/guacamole/proxy/vnc_client.c index c42d568cd..cab5cbe6d 100644 --- a/guacamole/proxy/vnc_client.c +++ b/guacamole/proxy/vnc_client.c @@ -34,10 +34,12 @@ char __guac_password[] = "potato"; static char* __GUAC_CLIENT = "GUAC_CLIENT"; typedef struct vnc_guac_client_data { + rfbClient* rfb_client; png_byte** png_buffer; png_byte** png_buffer_alpha; int copy_rect_used; + } vnc_guac_client_data; void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) { @@ -178,6 +180,16 @@ char* guac_vnc_get_password(rfbClient* client) { } +void guac_vnc_cut_text(rfbClient* client, const char* text, int textlen) { + + guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT); + GUACIO* io = gc->io; + + guac_send_clipboard(io, text); + +} + + void vnc_guac_client_handle_messages(guac_client* client) { int wait_result; @@ -228,6 +240,14 @@ void vnc_guac_client_key_handler(guac_client* client, int keysym, int pressed) { } +void vnc_guac_client_clipboard_handler(guac_client* client, char* data) { + + rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client; + + SendClientCutText(rfb_client, data, strlen(data)); + +} + void vnc_guac_client_free_handler(guac_client* client) { rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client; @@ -266,6 +286,9 @@ void vnc_guac_client_init(guac_client* client, const char* hostname, int port) { rfb_client->GotCursorShape = guac_vnc_cursor; rfb_client->appData.useRemoteCursor = TRUE; + /* Clipboard */ + rfb_client->GotXCutText = guac_vnc_cut_text; + /* Password */ rfb_client->GetPassword = guac_vnc_get_password; @@ -297,6 +320,7 @@ void vnc_guac_client_init(guac_client* client, const char* hostname, int port) { client->handle_messages = vnc_guac_client_handle_messages; client->mouse_handler = vnc_guac_client_mouse_handler; client->key_handler = vnc_guac_client_key_handler; + client->clipboard_handler = vnc_guac_client_clipboard_handler; /* Send name */ guac_send_name(client->io, rfb_client->desktopName);