[WIP]: Add support for links channel.
This commit is contained in:
parent
a175a3d902
commit
2cff6c6b73
@ -717,3 +717,62 @@ int guac_client_supports_webp(guac_client* client) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback that it is invokved by the call to guac_client_owner_send_uri
|
||||||
|
* which sends the 'uri" instruction and parameter to the specified user, who
|
||||||
|
* is the owner of the connection.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user to send the "uri" instruction and parameter to, who owns the
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* The URI to send to the owner, cast as a void*.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero if the operation succeeds or non-zero on failure.
|
||||||
|
*/
|
||||||
|
static void* guac_client_owner_send_uri_callback(guac_user* user, void* data) {
|
||||||
|
|
||||||
|
const char* uri = (const char *) data;
|
||||||
|
|
||||||
|
/* Send uri parameter to owner. */
|
||||||
|
if (user != NULL)
|
||||||
|
return (void*) ((intptr_t) guac_protocol_send_uri(user->socket, uri));
|
||||||
|
|
||||||
|
return (void*) ((intptr_t) -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_client_owner_send_uri(guac_client* client, const char* uri) {
|
||||||
|
|
||||||
|
/* Don't send the uri instruction if the client does not support it. */
|
||||||
|
if (!guac_client_owner_supports_uri(client))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return (int) ((intptr_t) guac_client_for_owner(client, guac_client_owner_send_uri_callback, (void *) uri));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function that is invoked by guac_client_owner_supports_uri to
|
||||||
|
* determine if the owner of a connection supports the "uri" instruction,
|
||||||
|
* so that Guacamole can pass URIs to the client browser.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user that is being checked for URI support, which should be the
|
||||||
|
* owner of the connection.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* Additional data - this will always be null.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A non-zero integer if the user supports the "uri" instruction, otherwise
|
||||||
|
* zero to indicate a lack of URI support.
|
||||||
|
*/
|
||||||
|
static void* guac_owner_supports_uri_callback(guac_user* user, void* data) {
|
||||||
|
return (void*) ((intptr_t) guac_user_supports_uri(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
int guac_client_owner_supports_uri(guac_client* client) {
|
||||||
|
return (int) ((intptr_t) guac_client_for_owner(client, guac_owner_supports_uri_callback, NULL));
|
||||||
|
}
|
@ -565,6 +565,22 @@ int guac_client_get_processing_lag(guac_client* client);
|
|||||||
*/
|
*/
|
||||||
int guac_client_owner_send_required(guac_client* client, const char** required);
|
int guac_client_owner_send_required(guac_client* client, const char** required);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the "uri" instruction to the given guac_client so that the remote
|
||||||
|
* client can process the URI, if the client supports it and has a handler
|
||||||
|
* configured for the URI.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The client to which to send the URI instruction.
|
||||||
|
*
|
||||||
|
* @param uri
|
||||||
|
* The URI to send to the remote client.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on failure.
|
||||||
|
*/
|
||||||
|
int guac_client_owner_send_uri(guac_client* client, const char* uri);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streams the given connection parameter value over an argument value stream
|
* Streams the given connection parameter value over an argument value stream
|
||||||
* ("argv" instruction), exposing the current value of the named connection
|
* ("argv" instruction), exposing the current value of the named connection
|
||||||
@ -736,6 +752,8 @@ int guac_client_owner_supports_required(guac_client* client);
|
|||||||
*/
|
*/
|
||||||
int guac_client_supports_webp(guac_client* client);
|
int guac_client_supports_webp(guac_client* client);
|
||||||
|
|
||||||
|
int guac_client_owner_supports_uri(guac_client* client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default Guacamole client layer, layer 0.
|
* The default Guacamole client layer, layer 0.
|
||||||
*/
|
*/
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
* This version is passed by the __guac_protocol_send_args() function from the
|
* This version is passed by the __guac_protocol_send_args() function from the
|
||||||
* server to the client during the client/server handshake.
|
* server to the client during the client/server handshake.
|
||||||
*/
|
*/
|
||||||
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_3_0"
|
#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_6_0"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of bytes that should be sent in any one blob instruction
|
* The maximum number of bytes that should be sent in any one blob instruction
|
||||||
|
@ -306,7 +306,13 @@ typedef enum guac_protocol_version {
|
|||||||
* allowing connections in guacd to request information from the client and
|
* allowing connections in guacd to request information from the client and
|
||||||
* await a response.
|
* await a response.
|
||||||
*/
|
*/
|
||||||
GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300
|
GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protocol version 1.6.0, which supports the "uri" instruction, allowing
|
||||||
|
* remote systems to send
|
||||||
|
*/
|
||||||
|
GUAC_PROTOCOL_VERSION_1_6_0 = 0x010600
|
||||||
|
|
||||||
} guac_protocol_version;
|
} guac_protocol_version;
|
||||||
|
|
||||||
|
@ -1037,6 +1037,21 @@ int guac_protocol_send_shade(guac_socket* socket, const guac_layer* layer,
|
|||||||
int guac_protocol_send_size(guac_socket* socket, const guac_layer* layer,
|
int guac_protocol_send_size(guac_socket* socket, const guac_layer* layer,
|
||||||
int w, int h);
|
int w, int h);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the uri instruction over the given guac_socket connection,
|
||||||
|
* providing a URI that the client should then process locally.
|
||||||
|
*
|
||||||
|
* @param socket
|
||||||
|
* The guac_socket connection to which to send the uri instruction.
|
||||||
|
*
|
||||||
|
* @param uri
|
||||||
|
* The URI that should be sent to the client.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int guac_protocol_send_uri(guac_socket* socket, const char* uri);
|
||||||
|
|
||||||
/* TEXT INSTRUCTIONS */
|
/* TEXT INSTRUCTIONS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -861,6 +861,17 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket,
|
|||||||
*/
|
*/
|
||||||
int guac_user_supports_required(guac_user* user);
|
int guac_user_supports_required(guac_user* user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns non-zero if the user supports the "uri" instruction.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The Guacamole user to check for support of the "uri" instruction.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Non-zero if the user supports the "uri" instruction, otherwise zero.
|
||||||
|
*/
|
||||||
|
int guac_user_supports_uri(guac_user* user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the given user supports WebP. If the user does not
|
* Returns whether the given user supports WebP. If the user does not
|
||||||
* support WebP, or the server cannot encode WebP images, zero is returned.
|
* support WebP, or the server cannot encode WebP images, zero is returned.
|
||||||
|
@ -65,6 +65,7 @@ guac_protocol_version_mapping guac_protocol_version_table[] = {
|
|||||||
{ GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" },
|
{ GUAC_PROTOCOL_VERSION_1_0_0, "VERSION_1_0_0" },
|
||||||
{ GUAC_PROTOCOL_VERSION_1_1_0, "VERSION_1_1_0" },
|
{ GUAC_PROTOCOL_VERSION_1_1_0, "VERSION_1_1_0" },
|
||||||
{ GUAC_PROTOCOL_VERSION_1_3_0, "VERSION_1_3_0" },
|
{ GUAC_PROTOCOL_VERSION_1_3_0, "VERSION_1_3_0" },
|
||||||
|
{ GUAC_PROTOCOL_VERSION_1_6_0, "VERSION_1_6_0" },
|
||||||
{ GUAC_PROTOCOL_VERSION_UNKNOWN, NULL }
|
{ GUAC_PROTOCOL_VERSION_UNKNOWN, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1274,6 +1275,21 @@ int guac_protocol_send_undefine(guac_socket* socket,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_protocol_send_uri(guac_socket* socket, const char* uri) {
|
||||||
|
|
||||||
|
int ret_val;
|
||||||
|
|
||||||
|
guac_socket_instruction_begin(socket);
|
||||||
|
ret_val =
|
||||||
|
guac_socket_write_string(socket, "3.uri,")
|
||||||
|
|| __guac_socket_write_length_string(socket, uri)
|
||||||
|
|| guac_socket_write_string(socket, ";");
|
||||||
|
|
||||||
|
guac_socket_instruction_end(socket);
|
||||||
|
return ret_val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int guac_protocol_send_video(guac_socket* socket, const guac_stream* stream,
|
int guac_protocol_send_video(guac_socket* socket, const guac_stream* stream,
|
||||||
const guac_layer* layer, const char* mimetype) {
|
const guac_layer* layer, const char* mimetype) {
|
||||||
|
|
||||||
|
@ -325,6 +325,14 @@ int guac_user_supports_required(guac_user* user) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int guac_user_supports_uri(guac_user* user) {
|
||||||
|
|
||||||
|
if (user == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (user->info.protocol_version >= GUAC_PROTOCOL_VERSION_1_6_0);
|
||||||
|
}
|
||||||
|
|
||||||
int guac_user_supports_webp(guac_user* user) {
|
int guac_user_supports_webp(guac_user* user) {
|
||||||
|
|
||||||
#ifdef ENABLE_WEBP
|
#ifdef ENABLE_WEBP
|
||||||
|
@ -59,6 +59,7 @@ libguac_client_rdp_la_SOURCES = \
|
|||||||
channels/rdpei.c \
|
channels/rdpei.c \
|
||||||
channels/rdpsnd/rdpsnd-messages.c \
|
channels/rdpsnd/rdpsnd-messages.c \
|
||||||
channels/rdpsnd/rdpsnd.c \
|
channels/rdpsnd/rdpsnd.c \
|
||||||
|
channels/rdpuri.c \
|
||||||
client.c \
|
client.c \
|
||||||
color.c \
|
color.c \
|
||||||
decompose.c \
|
decompose.c \
|
||||||
@ -105,6 +106,7 @@ noinst_HEADERS = \
|
|||||||
channels/rdpei.h \
|
channels/rdpei.h \
|
||||||
channels/rdpsnd/rdpsnd-messages.h \
|
channels/rdpsnd/rdpsnd-messages.h \
|
||||||
channels/rdpsnd/rdpsnd.h \
|
channels/rdpsnd/rdpsnd.h \
|
||||||
|
channels/rdpuri.h \
|
||||||
client.h \
|
client.h \
|
||||||
color.h \
|
color.h \
|
||||||
decompose.h \
|
decompose.h \
|
||||||
|
133
src/protocols/rdp/channels/rdpuri.c
Normal file
133
src/protocols/rdp/channels/rdpuri.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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 "channels/rdpuri.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "plugins/channels.h"
|
||||||
|
#include "rdp.h"
|
||||||
|
#include "unicode.h"
|
||||||
|
|
||||||
|
#include <freerdp/client/cliprdr.h>
|
||||||
|
#include <freerdp/event.h>
|
||||||
|
#include <freerdp/freerdp.h>
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/stream.h>
|
||||||
|
#include <guacamole/user.h>
|
||||||
|
#include <winpr/wtsapi.h>
|
||||||
|
#include <winpr/wtypes.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback which associates handlers specific to Guacamole with the
|
||||||
|
* CliprdrClientContext instance allocated by FreeRDP to deal with received
|
||||||
|
* CLIPRDR (clipboard redirection) messages.
|
||||||
|
*
|
||||||
|
* This function is called whenever a channel connects via the PubSub event
|
||||||
|
* system within FreeRDP, but only has any effect if the connected channel is
|
||||||
|
* the CLIPRDR channel. This specific callback is registered with the PubSub
|
||||||
|
* system of the relevant rdpContext when guac_rdp_clipboard_load_plugin() is
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* The rdpContext associated with the active RDP session.
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
|
*/
|
||||||
|
static void guac_rdpuri_channel_connected(guac_rdp_common_svc* svc) {
|
||||||
|
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_DEBUG, "RDPURI (URI redirection) "
|
||||||
|
"channel connected.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback which disassociates Guacamole from the CliprdrClientContext
|
||||||
|
* instance that was originally allocated by FreeRDP and is about to be
|
||||||
|
* deallocated.
|
||||||
|
*
|
||||||
|
* This function is called whenever a channel disconnects via the PubSub event
|
||||||
|
* system within FreeRDP, but only has any effect if the disconnected channel
|
||||||
|
* is the CLIPRDR channel. This specific callback is registered with the PubSub
|
||||||
|
* system of the relevant rdpContext when guac_rdp_clipboard_load_plugin() is
|
||||||
|
* called.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* The rdpContext associated with the active RDP session.
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* Event-specific arguments, mainly the name of the channel, and a
|
||||||
|
* reference to the associated plugin loaded for that channel by FreeRDP.
|
||||||
|
*/
|
||||||
|
static void guac_rdpuri_channel_disconnected(guac_rdp_common_svc* svc) {
|
||||||
|
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_DEBUG, "RDPURI (URI redirection) "
|
||||||
|
"channel disconnected.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void guac_rdpuri_channel_receive(guac_rdp_common_svc* svc, wStream* input_stream) {
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_DEBUG, "RDPURI (URI redirection) "
|
||||||
|
"channel received data.");
|
||||||
|
|
||||||
|
// int len = Stream_Length(input_stream);
|
||||||
|
int len = Stream_Length(input_stream);
|
||||||
|
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_DEBUG, "Received URI %d in length.", len);
|
||||||
|
|
||||||
|
if (len < 1) {
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_WARNING, "Received URI data is too "
|
||||||
|
"small.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert input stream to UTF8 and send it to the client. */
|
||||||
|
char uri[len/2];
|
||||||
|
guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), len/2 - 1, uri, sizeof(uri));
|
||||||
|
guac_client_log(svc->client, GUAC_LOG_DEBUG, "Received URI from server: %s", uri);
|
||||||
|
guac_client_owner_send_uri(svc->client, uri);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_rdpuri_load_plugin(rdpContext* context) {
|
||||||
|
|
||||||
|
guac_client* client = ((rdp_freerdp_context*) context)->client;
|
||||||
|
|
||||||
|
/* Attempt to load FreeRDP support for the CLIPRDR channel */
|
||||||
|
if (guac_rdp_common_svc_load_plugin(context, "rdpuri", 0,
|
||||||
|
guac_rdpuri_channel_connected, guac_rdpuri_channel_receive,
|
||||||
|
guac_rdpuri_channel_disconnected)) {
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
|
"Support for the RDPURI channel (URI redirection) "
|
||||||
|
"could not be loaded. This support normally takes the form of "
|
||||||
|
"a plugin which is built into FreeRDP. Lacking this support, "
|
||||||
|
"URI redirection will not work.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG, "Support for RDPURI "
|
||||||
|
"(URI redirection) registered. Awaiting channel "
|
||||||
|
"connection.");
|
||||||
|
|
||||||
|
}
|
45
src/protocols/rdp/channels/rdpuri.h
Normal file
45
src/protocols/rdp/channels/rdpuri.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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_RDP_CHANNELS_RDPURI_H
|
||||||
|
#define GUAC_RDP_CHANNELS_RDPURI_H
|
||||||
|
|
||||||
|
#include "channels/common-svc.h"
|
||||||
|
|
||||||
|
#include <freerdp/freerdp.h>
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <guacamole/user.h>
|
||||||
|
#include <winpr/stream.h>
|
||||||
|
#include <winpr/wtypes.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes clipboard support for RDP and handling of the RDPURI channel.
|
||||||
|
* If failures occur, messages noting the specifics of those failures will be
|
||||||
|
* logged, and the RDP side of URI redirection will not be functional.
|
||||||
|
*
|
||||||
|
* This MUST be called within the PreConnect callback of the freerdp instance
|
||||||
|
* for RDPURI support to be loaded.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* The rdpContext associated with the FreeRDP side of the RDP connection.
|
||||||
|
*/
|
||||||
|
void guac_rdpuri_load_plugin(rdpContext* context);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -29,6 +29,7 @@
|
|||||||
#include "channels/rdpdr/rdpdr.h"
|
#include "channels/rdpdr/rdpdr.h"
|
||||||
#include "channels/rdpei.h"
|
#include "channels/rdpei.h"
|
||||||
#include "channels/rdpsnd/rdpsnd.h"
|
#include "channels/rdpsnd/rdpsnd.h"
|
||||||
|
#include "channels/rdpuri.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "common/cursor.h"
|
#include "common/cursor.h"
|
||||||
@ -123,6 +124,9 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
guac_rdpsnd_load_plugin(context);
|
guac_rdpsnd_load_plugin(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load rdpuri service */
|
||||||
|
guac_rdpuri_load_plugin(context);
|
||||||
|
|
||||||
/* Load RAIL plugin if RemoteApp in use */
|
/* Load RAIL plugin if RemoteApp in use */
|
||||||
if (settings->remote_app != NULL)
|
if (settings->remote_app != NULL)
|
||||||
guac_rdp_rail_load_plugin(context);
|
guac_rdp_rail_load_plugin(context);
|
||||||
|
Loading…
Reference in New Issue
Block a user