diff --git a/src/libguac/client.c b/src/libguac/client.c index cd4b5463..3f307579 100644 --- a/src/libguac/client.c +++ b/src/libguac/client.c @@ -302,6 +302,10 @@ int guac_client_add_user(guac_client* client, guac_user* user, int argc, char** /* Update owner pointer if user is owner */ if (user->owner) client->__owner = user; + + /* Notify owner of user joining connection. */ + else + guac_client_owner_notify_join(client, user); } @@ -331,6 +335,10 @@ void guac_client_remove_user(guac_client* client, guac_user* user) { if (user->owner) client->__owner = NULL; + /* Update owner of user having left the connection. */ + else + guac_client_owner_notify_leave(client, user); + pthread_rwlock_unlock(&(client->__users_lock)); /* Call handler, if defined */ @@ -731,6 +739,126 @@ int guac_client_owner_supports_required(guac_client* client) { } +/** + * A callback function that is invokved by guac_client_owner_notify_join() to + * notify the owner of a connection that another user has joined the + * connection, returning zero if the message is sent successfully, or non-zero + * if an error occurs. + * + * @param user + * The user to send the notification to, which will be the owner of the + * connection. + * + * @param data + * The data provided to the callback, which is the user that is joining the + * connection. + * + * @return + * Zero if the message is sent successfully to the owner, otherwise + * non-zero, cast as a void*. + */ +static void* guac_client_owner_notify_join_callback(guac_user* user, void* data) { + + const guac_user* joiner = (const guac_user *) data; + int retval = 0; + + char* owner = "owner"; + if (user->info.name != NULL) + owner = strdup(user->info.name); + + char* joinName = "anonymous"; + if (joiner->info.name != NULL) + joinName = strdup(joiner->info.name); + + guac_user_log(user, GUAC_LOG_DEBUG, "Notifying %s of %s joining.", owner, joinName); + + size_t msg_size = snprintf(NULL, 0, "User %s has joined the connection.", joinName); + char* msg = malloc(msg_size + 1); + sprintf(msg, "User %s has joined the connection.", joinName); + + /* Send required parameters to owner. */ + if (user != NULL) + retval = guac_protocol_send_msg(user->socket, msg); + + else + retval = -1; + + free(owner); + free(joinName); + free(msg); + + return (void*) ((intptr_t) retval); + +} + +int guac_client_owner_notify_join(guac_client* client, guac_user* joiner) { + + /* Don't send msg instruction if client does not support it. */ + if (!guac_client_owner_supports_msg(client)) + return -1; + + guac_client_log(client, GUAC_LOG_DEBUG, "Notifying owner of %s joining.", joiner->user_id); + + return (int) ((intptr_t) guac_client_for_owner(client, guac_client_owner_notify_join_callback, joiner)); + +} + +/** + * A callback function that is invokved by guac_client_owner_notify_leave() to + * notify the owner of a connection that another user has left the connection, + * returning zero if the message is sent successfully, or non-zero + * if an error occurs. + * + * @param user + * The user to send the notification to, which will be the owner of the + * connection. + * + * @param data + * The data provided to the callback, which is the user that is leaving the + * connection. + * + * @return + * Zero if the message is sent successfully to the owner, otherwise + * non-zero, cast as a void*. + */ +static void* guac_client_owner_notify_leave_callback(guac_user* user, void* data) { + + const guac_user* quitter = (const guac_user *) data; + + char* owner = "owner"; + if (user->info.name != NULL) + owner = strdup(user->info.name); + + char* quitterName = "anonymous"; + if (quitter->info.name != NULL) + quitterName = strdup(quitter->info.name); + + guac_user_log(user, GUAC_LOG_DEBUG, "Notifying %s of %s leaving.", owner, quitterName); + + size_t msg_size = snprintf(NULL, 0, "User %s has left the connection.", quitterName); + char* msg = malloc(msg_size + 1); + sprintf(msg, "User %s has left the connection.", quitterName); + + /* Send required parameters to owner. */ + if (user != NULL) + return (void*) ((intptr_t) guac_protocol_send_msg(user->socket, msg)); + + return (void*) ((intptr_t) -1); + +} + +int guac_client_owner_notify_leave(guac_client* client, guac_user* quitter) { + + /* Don't send msg instruction if client does not support it. */ + if (!guac_client_owner_supports_msg(client)) + return -1; + + guac_client_log(client, GUAC_LOG_DEBUG, "Notifying owner of %s leaving.", quitter->user_id); + + return (int) ((intptr_t) guac_client_for_owner(client, guac_client_owner_notify_leave_callback, quitter)); + +} + int guac_client_supports_webp(guac_client* client) { #ifdef ENABLE_WEBP diff --git a/src/libguac/guacamole/client.h b/src/libguac/guacamole/client.h index 2067c5cd..5712476f 100644 --- a/src/libguac/guacamole/client.h +++ b/src/libguac/guacamole/client.h @@ -738,6 +738,42 @@ int guac_client_owner_supports_msg(guac_client* client); */ int guac_client_owner_supports_required(guac_client* client); +/** + * Notifies the owner of the given client that a user has joined the connection, + * and returns zero if the message was sent successfully, or non-zero if the + * notification failed. + * + * @param client + * The Guacamole Client whose owner should be notified of a user joining + * the connection. + * + * @param joiner + * The Guacamole User who joined the connection. + * + * @return + * Zero if the notification to the owner was sent successfully, or non-zero + * if an error occurred. + */ +int guac_client_owner_notify_join(guac_client* client, guac_user* joiner); + +/** + * Notifies the owner of the given client that a user has left the connection, + * and returns zero if the message was sent successfully, or non-zero if the + * notification failed. + * + * @param client + * The Guacamole Client whose owner should be notified of a user leaving + * the connection. + * + * @param quitter + * The Guacamole User who left the connection. + * + * @return + * Zero if the notification to the owner was sent successfully, or non-zero + * if an error occurred. + */ +int guac_client_owner_notify_leave(guac_client* client, guac_user* quitter); + /** * Returns whether all users of the given client support WebP. If any user does * not support WebP, or the server cannot encode WebP images, zero is returned.