diff --git a/src/libguac/client.c b/src/libguac/client.c index 9738c0c2..cd4b5463 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -671,6 +671,36 @@ static void* __webp_support_callback(guac_user* user, void* data) { } #endif +/** + * A callback function which is invoked by guac_client_owner_supports_msg() + * to determine if the owner of a client supports the "msg" instruction, + * returning zero if the user does not support the instruction or non-zero if + * the user supports it. + * + * @param user + * The guac_user that will be checked for "msg" instruction support. + * + * @param data + * Data provided to the callback. This value is never used within this + * callback. + * + * @return + * A non-zero integer if the provided user who owns the connection supports + * the "msg" instruction, or zero if the user does not. The integer is cast + * as a void*. + */ +static void* guac_owner_supports_msg_callback(guac_user* user, void* data) { + + return (void*) ((intptr_t) guac_user_supports_msg(user)); + +} + +int guac_client_owner_supports_msg(guac_client* client) { + + return (int) ((intptr_t) guac_client_for_owner(client, guac_owner_supports_msg_callback, NULL)); + +} + /** * A callback function which is invoked by guac_client_owner_supports_required() * to determine if the owner of a client supports the "required" instruction, diff --git a/src/libguac/guacamole/client.h b/src/libguac/guacamole/client.h index 4ffe5cf4..2067c5cd 100644 --- a/src/libguac/guacamole/client.h +++ b/src/libguac/guacamole/client.h @@ -708,6 +708,21 @@ void guac_client_stream_webp(guac_client* client, guac_socket* socket, guac_composite_mode mode, const guac_layer* layer, int x, int y, cairo_surface_t* surface, int quality, int lossless); +/** + * Returns whether the owner of the given client supports the "msg" + * instruction, returning non-zero if the client owner does support the + * instruction, or zero if the owner does not. + * + * @param client + * The Guacamole client whose owner should be checked for supporting + * the "msg" instruction. + * + * @return + * Non-zero if the owner of the given client supports the "msg" + * instruction, zero otherwise. + */ +int guac_client_owner_supports_msg(guac_client* client); + /** * Returns whether the owner of the given client supports the "required" * instruction, returning non-zero if the client owner does support the diff --git a/src/libguac/guacamole/protocol-constants.h b/src/libguac/guacamole/protocol-constants.h index 13d7f680..a8fc9777 100644 --- a/src/libguac/guacamole/protocol-constants.h +++ b/src/libguac/guacamole/protocol-constants.h @@ -38,7 +38,7 @@ * This version is passed by the __guac_protocol_send_args() function from the * server to the client during the client/server handshake. */ -#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_3_0" +#define GUACAMOLE_PROTOCOL_VERSION "VERSION_1_5_0" /** * The maximum number of bytes that should be sent in any one blob instruction diff --git a/src/libguac/guacamole/protocol-types.h b/src/libguac/guacamole/protocol-types.h index 51652d2b..1cb1de25 100644 --- a/src/libguac/guacamole/protocol-types.h +++ b/src/libguac/guacamole/protocol-types.h @@ -306,7 +306,13 @@ typedef enum guac_protocol_version { * allowing connections in guacd to request information from the client and * await a response. */ - GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300 + GUAC_PROTOCOL_VERSION_1_3_0 = 0x010300, + + /** + * Protocol version 1.5.0, which supports the "msg" instruction, allowing + * messages to be sent to the client. + */ + GUAC_PROTOCOL_VERSION_1_5_0 = 0x010500 } guac_protocol_version; diff --git a/src/libguac/guacamole/protocol.h b/src/libguac/guacamole/protocol.h index 362351c5..73578ba7 100644 --- a/src/libguac/guacamole/protocol.h +++ b/src/libguac/guacamole/protocol.h @@ -171,6 +171,21 @@ int guac_protocol_send_log(guac_socket* socket, const char* format, ...); int vguac_protocol_send_log(guac_socket* socket, const char* format, va_list args); +/** + * Sends the given string over the socket to be displayed on the client. Returns + * zero if the message was sent successfully or non-zero if an error occurs. + * + * @param socket + * The guac_socket connection to send the message to. + * + * @param message + * The message to send to the client. + * + * @return + * Zero if the message is sent successfully; otherwise non-zero. + */ +int guac_protocol_send_msg(guac_socket* socket, const char* message); + /** * Sends a mouse instruction over the given guac_socket connection. * diff --git a/src/libguac/guacamole/user.h b/src/libguac/guacamole/user.h index 963dbe68..8f6a2721 100644 --- a/src/libguac/guacamole/user.h +++ b/src/libguac/guacamole/user.h @@ -850,6 +850,17 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket, guac_composite_mode mode, const guac_layer* layer, int x, int y, cairo_surface_t* surface, int quality, int lossless); +/** + * Returns whether the given user supports the "msg" instruction. + * + * @param user + * The Guacamole user to check for support of the "msg" instruction. + * + * @return + * Non-zero if the user supports the "msg" instruction, otherwise zero. + */ +int guac_user_supports_msg(guac_user* user); + /** * Returns whether the given user supports the "required" instruction. * diff --git a/src/libguac/protocol.c b/src/libguac/protocol.c index 1c53c200..0745c415 100644 --- a/src/libguac/protocol.c +++ b/src/libguac/protocol.c @@ -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_1_0, "VERSION_1_1_0" }, { GUAC_PROTOCOL_VERSION_1_3_0, "VERSION_1_3_0" }, + { GUAC_PROTOCOL_VERSION_1_5_0, "VERSION_1_5_0" }, { GUAC_PROTOCOL_VERSION_UNKNOWN, NULL } }; @@ -658,6 +659,21 @@ int guac_protocol_send_log(guac_socket* socket, const char* format, ...) { } +int guac_protocol_send_msg(guac_socket* socket, const char* message) { + + int ret_val; + + guac_socket_instruction_begin(socket); + ret_val = + guac_socket_write_string(socket, "3.msg,") + || __guac_socket_write_length_string(socket, message) + || guac_socket_write_string(socket, ";"); + + guac_socket_instruction_end(socket); + return ret_val; + +} + int guac_protocol_send_file(guac_socket* socket, const guac_stream* stream, const char* mimetype, const char* name) { diff --git a/src/libguac/tests/protocol/guac_protocol_version.c b/src/libguac/tests/protocol/guac_protocol_version.c index 37f42e0f..f9b2fdf2 100644 --- a/src/libguac/tests/protocol/guac_protocol_version.c +++ b/src/libguac/tests/protocol/guac_protocol_version.c @@ -27,11 +27,11 @@ */ void test_guac_protocol__version_to_string() { - guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_3_0; + guac_protocol_version version_a = GUAC_PROTOCOL_VERSION_1_5_0; guac_protocol_version version_b = GUAC_PROTOCOL_VERSION_1_0_0; guac_protocol_version version_c = GUAC_PROTOCOL_VERSION_UNKNOWN; - CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_a), "VERSION_1_3_0"); + CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_a), "VERSION_1_5_0"); CU_ASSERT_STRING_EQUAL(guac_protocol_version_to_string(version_b), "VERSION_1_0_0"); CU_ASSERT_PTR_NULL(guac_protocol_version_to_string(version_c)); diff --git a/src/libguac/user.c b/src/libguac/user.c index 4320ca77..d16f43b9 100644 --- a/src/libguac/user.c +++ b/src/libguac/user.c @@ -316,6 +316,15 @@ void guac_user_stream_webp(guac_user* user, guac_socket* socket, } +int guac_user_supports_msg(guac_user* user) { + + if (user == NULL) + return 0; + + return (user->info.protocol_version >= GUAC_PROTOCOL_VERSION_1_5_0); + +} + int guac_user_supports_required(guac_user* user) { if (user == NULL)