Embed format information along with default cursor image data. Refactor default curso...
[libguac-client-rdp.git] / src / client.c
index 42030b5..f82e75a 100644 (file)
@@ -57,6 +57,7 @@
 #include <guacamole/socket.h>
 #include <guacamole/protocol.h>
 #include <guacamole/client.h>
+#include <guacamole/error.h>
 
 #include "client.h"
 #include "guac_handlers.h"
 #include "rdp_glyph.h"
 #include "rdp_pointer.h"
 #include "rdp_gdi.h"
+#include "default_pointer.h"
 
 /* Client plugin arguments */
 const char* GUAC_CLIENT_ARGS[] = {
     "hostname",
     "port",
+    "domain",
     "username",
     "password",
     "width",
     "height",
-    "initial_program",
-    "color_depth",
+    "initial-program",
+    "color-depth",
     NULL
 };
 
 enum ARGS_IDX {
     IDX_HOSTNAME,
     IDX_PORT,
+    IDX_DOMAIN,
     IDX_USERNAME,
     IDX_PASSWORD,
     IDX_WIDTH,
@@ -90,6 +94,10 @@ enum ARGS_IDX {
     IDX_COLOR_DEPTH
 };
 
+int __guac_receive_channel_data(freerdp* rdp_inst, int channelId, uint8* data, int size, int flags, int total_size) {
+    return freerdp_channels_data(rdp_inst, channelId, data, size, flags, total_size);
+}
+
 boolean rdp_freerdp_pre_connect(freerdp* instance) {
 
     rdpContext* context = instance->context;
@@ -101,6 +109,9 @@ boolean rdp_freerdp_pre_connect(freerdp* instance) {
     rdpPrimaryUpdate* primary;
     CLRCONV* clrconv;
 
+    /* Load clipboard plugin */
+    freerdp_channels_load_plugin(channels, instance->settings, "cliprdr", NULL);
+
     /* Init color conversion structure */
     clrconv = xnew(CLRCONV);
     clrconv->alpha = 1;
@@ -121,6 +132,7 @@ boolean rdp_freerdp_pre_connect(freerdp* instance) {
     bitmap->Decompress = guac_rdp_bitmap_decompress;
     bitmap->SetSurface = guac_rdp_bitmap_setsurface;
     graphics_register_bitmap(context->graphics, bitmap);
+    xfree(bitmap);
 
     /* Set up glyph handling */
     glyph = xnew(rdpGlyph);
@@ -131,6 +143,7 @@ boolean rdp_freerdp_pre_connect(freerdp* instance) {
     glyph->BeginDraw = guac_rdp_glyph_begindraw;
     glyph->EndDraw = guac_rdp_glyph_enddraw;
     graphics_register_glyph(context->graphics, glyph);
+    xfree(glyph);
 
     /* Set up pointer handling */
     pointer = xnew(rdpPointer);
@@ -139,8 +152,10 @@ boolean rdp_freerdp_pre_connect(freerdp* instance) {
     pointer->Free = guac_rdp_pointer_free;
     pointer->Set = guac_rdp_pointer_set;
     graphics_register_pointer(context->graphics, pointer);
+    xfree(pointer);
 
     /* Set up GDI */
+    instance->update->EndPaint = guac_rdp_gdi_end_paint;
     instance->update->Palette = guac_rdp_gdi_palette_update;
     instance->update->SetBounds = guac_rdp_gdi_set_bounds;
 
@@ -187,10 +202,7 @@ boolean rdp_freerdp_post_connect(freerdp* instance) {
     client->handle_messages = rdp_guac_client_handle_messages;
     client->mouse_handler = rdp_guac_client_mouse_handler;
     client->key_handler = rdp_guac_client_key_handler;
-
-    /* Send size */
-    guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER,
-            instance->settings->width, instance->settings->height);
+    client->clipboard_handler = rdp_guac_client_clipboard_handler;
 
     return true;
 
@@ -209,6 +221,7 @@ void __guac_rdp_client_load_keymap(guac_client* client,
 
     rdp_guac_client_data* guac_client_data =
         (rdp_guac_client_data*) client->data;
+
     /* Get mapping */
     const guac_rdp_keysym_desc* mapping = keymap->mapping;
 
@@ -217,7 +230,7 @@ void __guac_rdp_client_load_keymap(guac_client* client,
         __guac_rdp_client_load_keymap(client, keymap->parent);
 
     /* Log load */
-    guac_client_log_info(client, "Loading keymap %s", keymap->name);
+    guac_client_log_info(client, "Loading keymap \"%s\"", keymap->name);
 
     /* Load mapping into keymap */
     while (mapping->keysym != 0) {
@@ -244,9 +257,24 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
     int port = RDP_DEFAULT_PORT;
     boolean bitmap_cache;
 
-    if (argc < 8) {
-        guac_protocol_send_error(client->socket, "Wrong argument count received.");
+    /**
+     * Selected server-side keymap. Client will be assumed to also use this
+     * keymap. Keys will be sent to server based on client input on a
+     * best-effort basis.
+     *
+     * Currently hard-coded to en-us-qwerty.
+     */
+    const guac_rdp_keymap* chosen_keymap = &guac_rdp_keymap_en_us;
+
+    if (argc < 9) {
+
+        guac_protocol_send_error(client->socket,
+                "Wrong argument count received.");
         guac_socket_flush(client->socket);
+
+        guac_error = GUAC_STATUS_BAD_ARGUMENT;
+        guac_error_message = "Wrong argument count received";
+
         return 1;
     }
 
@@ -264,6 +292,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
     rdp_inst = freerdp_new();
     rdp_inst->PreConnect = rdp_freerdp_pre_connect;
     rdp_inst->PostConnect = rdp_freerdp_post_connect;
+    rdp_inst->ReceiveChannelData = __guac_receive_channel_data;
 
     /* Allocate FreeRDP context */
     rdp_inst->context_size = sizeof(rdp_freerdp_context);
@@ -304,20 +333,24 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
     settings->port = port;
     settings->window_title = strdup(hostname);
 
-    /* username */
+    /* Domain */
+    if (argv[IDX_DOMAIN][0] != '\0')
+        settings->domain = strdup(argv[IDX_DOMAIN]);
+
+    /* Username */
     settings->username = "guest";
     if (argv[IDX_USERNAME][0] != '\0')
-        settings->username = strdup (argv[IDX_USERNAME]);
+        settings->username = strdup(argv[IDX_USERNAME]);
 
-    /* password */
+    /* Password */
     if (argv[IDX_PASSWORD][0] != '\0') {
-        settings->password = strdup (argv[IDX_PASSWORD]);
+        settings->password = strdup(argv[IDX_PASSWORD]);
         settings->autologon = 1;
     }
 
-    /* initial program */
+    /* Initial program */
     if (argv[IDX_INITIAL_PROGRAM][0] != '\0')
-        settings->shell = strdup (argv[IDX_INITIAL_PROGRAM]);
+        settings->shell = strdup(argv[IDX_INITIAL_PROGRAM]);
 
     /* Order support */
     bitmap_cache = settings->bitmap_cache;
@@ -352,6 +385,7 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
     guac_client_data->rdp_inst = rdp_inst;
     guac_client_data->mouse_button_mask = 0;
     guac_client_data->current_surface = GUAC_DEFAULT_LAYER;
+    guac_client_data->clipboard = NULL;
 
     /* Clear keysym state mapping and keymap */
     memset(guac_client_data->keysym_state, 0,
@@ -364,15 +398,41 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
     ((rdp_freerdp_context*) rdp_inst->context)->client = client;
 
     /* Load keymap into client */
-    __guac_rdp_client_load_keymap(client, &guac_rdp_keymap_en_us);
+    __guac_rdp_client_load_keymap(client, chosen_keymap);
+
+    /* Set server-side keymap */
+    settings->kbd_layout = chosen_keymap->freerdp_keyboard_layout; 
 
     /* Connect to RDP server */
     if (!freerdp_connect(rdp_inst)) {
-        guac_protocol_send_error(client->socket, "Error connecting to RDP server");
+
+        guac_protocol_send_error(client->socket,
+                "Error connecting to RDP server");
         guac_socket_flush(client->socket);
+
+        guac_error = GUAC_STATUS_BAD_STATE;
+        guac_error_message = "Error connecting to RDP server";
+
         return 1;
     }
 
+    /* Send connection name */
+    guac_protocol_send_name(client->socket, settings->window_title);
+
+    /* Send size */
+    guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER,
+            settings->width, settings->height);
+
+    /* Create glyph surfaces */
+    guac_client_data->opaque_glyph_surface = cairo_image_surface_create(
+            CAIRO_FORMAT_RGB24, settings->width, settings->height);
+
+    guac_client_data->trans_glyph_surface = cairo_image_surface_create(
+            CAIRO_FORMAT_ARGB32, settings->width, settings->height);
+
+    /* Set default pointer */
+    guac_rdp_pointer_set_default(client);
+
     /* Success */
     return 0;