From 7d6cd184fd178cffaf5984defdb1ebeebbe1a1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abdullah=20=C3=96mer=20Yama=C3=A7?= Date: Tue, 21 May 2024 12:10:07 +0300 Subject: [PATCH] FEAT(client): Introduced new mumble API This patch introduces a new API to link, unlink, start to listen, stop the listen the channels and send the messages to the plugins --- plugins/MumblePlugin.h | 128 +++++++++- src/mumble/API.h | 27 +++ src/mumble/API_v_1_x_x.cpp | 418 +++++++++++++++++++++++++++++++++ src/mumble/MumbleAPI_structs.h | 11 + src/mumble/Plugin.cpp | 3 + src/mumble/ServerHandler.cpp | 38 +++ src/mumble/ServerHandler.h | 4 + 7 files changed, 628 insertions(+), 1 deletion(-) diff --git a/plugins/MumblePlugin.h b/plugins/MumblePlugin.h index a2592f7ce85..d8d43daf917 100644 --- a/plugins/MumblePlugin.h +++ b/plugins/MumblePlugin.h @@ -43,7 +43,7 @@ # define MUMBLE_PLUGIN_API_MAJOR_MACRO 1 # endif # ifndef MUMBLE_PLUGIN_API_MINOR_MACRO -# define MUMBLE_PLUGIN_API_MINOR_MACRO 2 +# define MUMBLE_PLUGIN_API_MINOR_MACRO 3 # endif # ifndef MUMBLE_PLUGIN_API_PATCH_MACRO # define MUMBLE_PLUGIN_API_PATCH_MACRO 0 @@ -1515,6 +1515,42 @@ struct MUMBLE_API_STRUCT_NAME { mumble_channelid_t channelID, const char **description); +# if SELECTED_API_VERSION >= MUMBLE_PLUGIN_VERSION_CHECK(1, 3, 0) + + /** + * Checks whether the linkedChannelID is linked to channelID. + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelID The ID of the channel + * @param linkedChannelID The ID of the linked channel + * @param[out] linked A pointer to where the result of the check + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *isChannelLinkedTo)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t channelID, + mumble_channelid_t linkedChannelID, + bool *linked); + + /** + * Gets the channel set the given channel is linked to. + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelID The ID of the channel + * @param[out] channels The set of channel IDs linked to the channelID + * @param[out] channelCount The amount of linked channels + * @returns The error code. If everything went well, STATUS_OK will be returned. Only then the passed pointers + * may be accessed. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *getLinkedChannels)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t channelID, + mumble_channelid_t **channels, + size_t *channelCount); + +# endif // -------- Request functions -------- @@ -1608,7 +1644,97 @@ struct MUMBLE_API_STRUCT_NAME { mumble_connection_t connection, const char *comment); +# if SELECTED_API_VERSION >= MUMBLE_PLUGIN_VERSION_CHECK(1, 3, 0) + + /** + * Requests Mumble to link all channels in the given set to each other. + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelSet The set of channel IDs to link + * @param channelCount The number of elements in the channel list + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *requestLinkChannels)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t *channelSet, + size_t channelCount); + + /** + * Requests Mumble to remove any existing links between the provided channel and channels in the provided set. + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelID The ID of the channel to unlink + * @param channelSet The set of channel IDs to remove link from the channelID + * @param channelCount The number of elements in the channel set + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *requestUnlinkChannels)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t channelID, + mumble_channelid_t *channelSet, + size_t channelCount); + + + /** + * Requests Mumble to remove all links between the provided channels. + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelSet The set of channel IDs to remove link + * @param channelCount The number of elements in the channel set + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *requestUnlinkGivenChannels)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t *channelSet, + size_t channelCount); + + + /** + * Starts to listen channel set + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelSet The set of channel IDs to listen + * @param channelCount The number of elements in the channel set + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *requestStartListeningToChannels)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t *channelSet, + size_t channelCount); + + /** + * Stops to listen channel set + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param channelSet The set of channel IDs to stop listen + * @param channelCount The number of elements in the channel set + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *requestStopListeningToChannels)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_channelid_t *channelSet, + size_t channelCount); + /** + * Send text message to the given user + * + * @param callerID The ID of the plugin calling this function + * @param connection The ID of the server-connection + * @param userID The ID of the user to send the message + * @param message The message to send + * @returns The error code. If everything went well, STATUS_OK will be returned. + */ + mumble_error_t(MUMBLE_PLUGIN_CALLING_CONVENTION *requestSendUserTextMessage)(mumble_plugin_id_t callerID, + mumble_connection_t connection, + mumble_userid_t userID, + const char *message); + +# endif // -------- Find functions -------- diff --git a/src/mumble/API.h b/src/mumble/API.h index e48e740a87b..1d0a186ffd5 100644 --- a/src/mumble/API.h +++ b/src/mumble/API.h @@ -107,6 +107,9 @@ public slots: void isLocalUserMuted_v_1_0_x(mumble_plugin_id_t callerID, bool *muted, std::shared_ptr< api_promise_t > promise); void isLocalUserDeafened_v_1_0_x(mumble_plugin_id_t callerID, bool *deafened, std::shared_ptr< api_promise_t > promise); + void isChannelLinkedTo_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t channelID, mumble_channelid_t linkedChannelID, bool *linked, + std::shared_ptr< api_promise_t > promise); void getUserHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, const char **hash, std::shared_ptr< api_promise_t > promise); void getServerHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char **hash, @@ -119,6 +122,9 @@ public slots: void getChannelDescription_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t channelID, const char **description, std::shared_ptr< api_promise_t > promise); + void getLinkedChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t channelID, mumble_channelid_t **channels, + std::size_t *channelCount, std::shared_ptr< api_promise_t > promise); void requestUserMove_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, mumble_channelid_t channelID, const char *password, std::shared_ptr< api_promise_t > promise); @@ -132,6 +138,24 @@ public slots: std::shared_ptr< api_promise_t > promise); void requestSetLocalUserComment_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char *comment, std::shared_ptr< api_promise_t > promise); + void requestLinkChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelList, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise); + void requestUnlinkChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t channelID, mumble_channelid_t *unlinkList, + std::size_t unlinkCount, std::shared_ptr< api_promise_t > promise); + void requestUnlinkGivenChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *unlinkList, std::size_t unlinkCount, + std::shared_ptr< api_promise_t > promise); + void requestStartListeningToChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelList, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise); + void requestStopListeningToChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelList, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise); + void requestSendUserTextMessage_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_userid_t userID, const char *message, + std::shared_ptr< api_promise_t > promise); void findUserByName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char *userName, mumble_userid_t *userID, std::shared_ptr< api_promise_t > promise); void findChannelByName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char *channelName, @@ -174,6 +198,9 @@ MumbleAPI_v_1_0_x getMumbleAPI_v_1_0_x(); /// @returns The Mumble API struct (v1.2.x) MumbleAPI_v_1_2_x getMumbleAPI_v_1_2_x(); +/// @returns The Mumble API struct (v1.3.x) +MumbleAPI_v_1_3_x getMumbleAPI_v_1_3_x(); + /// Converts from the Qt key-encoding to the API's key encoding. /// /// @param keyCode The Qt key-code that shall be converted diff --git a/src/mumble/API_v_1_x_x.cpp b/src/mumble/API_v_1_x_x.cpp index a787d7924a5..a71e4e6d4f6 100644 --- a/src/mumble/API_v_1_x_x.cpp +++ b/src/mumble/API_v_1_x_x.cpp @@ -47,12 +47,22 @@ EXIT_WITH(MUMBLE_EC_INVALID_PLUGIN_ID); \ } +#define VERIFY_CHANNEL_ID(id) \ + if (!Channel::get((static_cast< unsigned int >(id)))) { \ + EXIT_WITH(MUMBLE_EC_CHANNEL_NOT_FOUND); \ + } + // Right now there can only be one connection managed by the current ServerHandler #define VERIFY_CONNECTION(connection) \ if (!Global::get().sh || Global::get().sh->getConnectionID() != connection) { \ EXIT_WITH(MUMBLE_EC_CONNECTION_NOT_FOUND); \ } +#define VERIFY_USER_ID(id) \ + if (!ClientUser::get(id)) { \ + EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND); \ + } + // Right now whether or not a connection has finished synchronizing is indicated by Global::get().uiSession. If it is // zero, synchronization is not done yet (or there is no connection to begin with). The connection parameter in the // macro is only present in case it will be needed in the future @@ -658,6 +668,42 @@ void MumbleAPI::isLocalUserDeafened_v_1_0_x(mumble_plugin_id_t callerID, bool *d EXIT_WITH(MUMBLE_STATUS_OK); } +void MumbleAPI::isChannelLinkedTo_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t channelID, mumble_channelid_t linkedChannelID, + bool *linked, std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "isChannelLinkedTo_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t, channelID), Q_ARG(mumble_channelid_t, linkedChannelID), + Q_ARG(bool *, linked), Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + const Channel *channel = Channel::get(static_cast< unsigned int >(channelID)); + if (!channel) { + EXIT_WITH(MUMBLE_EC_CHANNEL_NOT_FOUND); + } + + Channel *linkedChannel = Channel::get(static_cast< unsigned int >(linkedChannelID)); + if (!linkedChannel) { + EXIT_WITH(MUMBLE_EC_CHANNEL_NOT_FOUND); + } + + *linked = channel->isLinked(linkedChannel); + EXIT_WITH(MUMBLE_STATUS_OK); +} + void MumbleAPI::getUserHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, const char **hash, std::shared_ptr< api_promise_t > promise) { if (QThread::currentThread() != thread()) { @@ -894,6 +940,52 @@ void MumbleAPI::getChannelDescription_v_1_0_x(mumble_plugin_id_t callerID, mumbl EXIT_WITH(MUMBLE_STATUS_OK); } +void MumbleAPI::getLinkedChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t channelID, mumble_channelid_t **channels, + std::size_t *channelCount, std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "getLinkedChannels_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t, channelID), Q_ARG(mumble_channelid_t **, channels), + Q_ARG(std::size_t *, channelCount), Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + Channel *channel = Channel::get(static_cast< unsigned int >(channelID)); + + if (!channel) { + EXIT_WITH(MUMBLE_EC_CHANNEL_NOT_FOUND); + } + + const QSet< Channel * > linkedChannels = channel->allLinks(); + + auto amount = static_cast< std::size_t >(linkedChannels.size()); + auto *channelIDs = reinterpret_cast< mumble_channelid_t * >(malloc(sizeof(mumble_channelid_t) * amount)); + + std::size_t index = 0; + for (const Channel *linkedChannel : linkedChannels) { + channelIDs[index++] = static_cast< mumble_channelid_t >(linkedChannel->iId); + } + + m_curator.m_entries.insert({ channelIDs, { defaultDeleter, callerID, "getLinkedChannels" } }); + + *channels = channelIDs; + *channelCount = amount; + + EXIT_WITH(MUMBLE_STATUS_OK); +} + void MumbleAPI::requestUserMove_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, mumble_channelid_t channelID, const char *password, std::shared_ptr< api_promise_t > promise) { @@ -1093,6 +1185,221 @@ void MumbleAPI::requestSetLocalUserComment_v_1_0_x(mumble_plugin_id_t callerID, EXIT_WITH(MUMBLE_STATUS_OK); } +void MumbleAPI::requestLinkChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelSet, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "requestLinkChannels_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t *, channelSet), Q_ARG(std::size_t, channelCount), + Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + if (channelCount < 2) { + EXIT_WITH(MUMBLE_STATUS_OK); + } + + for (std::size_t i = 0; i < channelCount; i++) { + VERIFY_CHANNEL_ID(channelSet[i]); + } + + Global::get().sh->addChannelLinks((unsigned int) channelCount, (const unsigned int *) channelSet); + + EXIT_WITH(MUMBLE_STATUS_OK); +} + +void MumbleAPI::requestUnlinkChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t channelID, mumble_channelid_t *channelSet, + std::size_t channelCount, std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "requestUnlinkChannels_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t, channelID), Q_ARG(mumble_channelid_t *, channelSet), + Q_ARG(std::size_t, channelCount), Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + if (channelCount < 1) { + EXIT_WITH(MUMBLE_STATUS_OK); + } + + VERIFY_CHANNEL_ID(channelID); + + for (std::size_t i = 0; i < channelCount; i++) { + VERIFY_CHANNEL_ID(channelSet[i]); + } + + Global::get().sh->removeChannelLinks((unsigned int) channelID, (unsigned int) channelCount, + (const unsigned int *) channelSet); + + EXIT_WITH(MUMBLE_STATUS_OK); +} + +void MumbleAPI::requestUnlinkGivenChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelSet, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "requestUnlinkGivenChannels_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t *, channelSet), Q_ARG(std::size_t, channelCount), + Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + if (channelCount < 1) { + EXIT_WITH(MUMBLE_STATUS_OK); + } + + for (std::size_t i = 0; i < channelCount; i++) { + VERIFY_CHANNEL_ID(channelSet[i]); + } + + Global::get().sh->removeChannelLinks((unsigned int) channelCount, (const unsigned int *) channelSet); + + EXIT_WITH(MUMBLE_STATUS_OK); +} + +void MumbleAPI::requestStartListeningToChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelSet, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "requestStartListeningToChannels_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t *, channelSet), Q_ARG(std::size_t, channelCount), + Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + if (channelCount < 1) { + EXIT_WITH(MUMBLE_STATUS_OK); + } + + QList< unsigned int > channelList; + for (std::size_t i = 0; i < channelCount; i++) { + VERIFY_CHANNEL_ID(channelSet[i]); + channelList.append((unsigned int) channelSet[i]); + } + + Global::get().sh->startListeningToChannels(channelList); + + EXIT_WITH(MUMBLE_STATUS_OK); +} + +void MumbleAPI::requestStopListeningToChannels_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_channelid_t *channelSet, std::size_t channelCount, + std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "requestStopListeningToChannels_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_channelid_t *, channelSet), Q_ARG(std::size_t, channelCount), + Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + if (channelCount < 1) { + EXIT_WITH(MUMBLE_STATUS_OK); + } + + QList< unsigned int > channelList; + for (std::size_t i = 0; i < channelCount; i++) { + VERIFY_CHANNEL_ID(channelSet[i]); + channelList.append((unsigned int) channelSet[i]); + } + + Global::get().sh->stopListeningToChannels(channelList); + + EXIT_WITH(MUMBLE_STATUS_OK); +} + +void MumbleAPI::requestSendUserTextMessage_v_1_3_x(mumble_plugin_id_t callerID, mumble_connection_t connection, + mumble_userid_t userID, const char *message, + std::shared_ptr< api_promise_t > promise) { + if (QThread::currentThread() != thread()) { + // Invoke in main thread + QMetaObject::invokeMethod(this, "requestSendUserTextMessage_v_1_3_x", Qt::QueuedConnection, + Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection), + Q_ARG(mumble_userid_t, userID), Q_ARG(const char *, message), + Q_ARG(std::shared_ptr< api_promise_t >, promise)); + + return; + } + + api_promise_t::lock_guard_t guard = promise->lock(); + if (promise->isCancelled()) { + return; + } + + VERIFY_PLUGIN_ID(callerID); + + VERIFY_CONNECTION(connection); + + ENSURE_CONNECTION_SYNCHRONIZED(connection); + + VERIFY_USER_ID(userID); + + const ClientUser *user = ClientUser::get(userID); + + Global::get().sh->sendUserTextMessage(user->uiSession, QString::fromUtf8(message)); + + EXIT_WITH(MUMBLE_STATUS_OK); +} + void MumbleAPI::findUserByName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char *userName, mumble_userid_t *userID, std::shared_ptr< api_promise_t > promise) { @@ -1767,6 +2074,14 @@ C_WRAPPER(isLocalUserDeafened_v_1_0_x) #undef TYPED_ARGS #undef ARG_NAMES +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t channelID, \ + mumble_channelid_t linkedChannelID, bool *linked +#define ARG_NAMES callerID, connection, channelID, linkedChannelID, linked +C_WRAPPER(isChannelLinkedTo_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + #define TYPED_ARGS \ mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, const char **hash #define ARG_NAMES callerID, connection, userID, hash @@ -1800,6 +2115,14 @@ C_WRAPPER(getChannelDescription_v_1_0_x) #undef TYPED_ARGS #undef ARG_NAMES +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t channelID, \ + mumble_channelid_t **channels, std::size_t *channelCount +#define ARG_NAMES callerID, connection, channelID, channels, channelCount +C_WRAPPER(getLinkedChannels_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + #define TYPED_ARGS \ mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, mumble_channelid_t channelID, \ const char *password @@ -1838,6 +2161,52 @@ C_WRAPPER(requestSetLocalUserComment_v_1_0_x) #undef TYPED_ARGS #undef ARG_NAMES +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t *channelList, \ + std::size_t channelCount +#define ARG_NAMES callerID, connection, channelList, channelCount +C_WRAPPER(requestLinkChannels_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t channelID, \ + mumble_channelid_t *unlinkList, std::size_t unlinkCount +#define ARG_NAMES callerID, connection, channelID, unlinkList, unlinkCount +C_WRAPPER(requestUnlinkChannels_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t *unlinkList, std::size_t unlinkCount +#define ARG_NAMES callerID, connection, unlinkList, unlinkCount +C_WRAPPER(requestUnlinkGivenChannels_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t *channelSet, \ + std::size_t channelCount +#define ARG_NAMES callerID, connection, channelSet, channelCount +C_WRAPPER(requestStartListeningToChannels_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_channelid_t *channelSet, \ + std::size_t channelCount +#define ARG_NAMES callerID, connection, channelSet, channelCount +C_WRAPPER(requestStopListeningToChannels_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + +#define TYPED_ARGS \ + mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, const char *message +#define ARG_NAMES callerID, connection, userID, message +C_WRAPPER(requestSendUserTextMessage_v_1_3_x) +#undef TYPED_ARGS +#undef ARG_NAMES + #define TYPED_ARGS \ mumble_plugin_id_t callerID, mumble_connection_t connection, const char *userName, mumble_userid_t *userID #define ARG_NAMES callerID, connection, userName, userID @@ -2016,6 +2385,55 @@ MumbleAPI_v_1_2_x getMumbleAPI_v_1_2_x() { playSample_v_1_2_x }; } +MumbleAPI_v_1_3_x getMumbleAPI_v_1_3_x() { + return { freeMemory_v_1_0_x, + getActiveServerConnection_v_1_0_x, + isConnectionSynchronized_v_1_0_x, + getLocalUserID_v_1_0_x, + getUserName_v_1_0_x, + getChannelName_v_1_0_x, + getAllUsers_v_1_0_x, + getAllChannels_v_1_0_x, + getChannelOfUser_v_1_0_x, + getUsersInChannel_v_1_0_x, + getLocalUserTransmissionMode_v_1_0_x, + isUserLocallyMuted_v_1_0_x, + isLocalUserMuted_v_1_0_x, + isLocalUserDeafened_v_1_0_x, + getUserHash_v_1_0_x, + getServerHash_v_1_0_x, + getUserComment_v_1_0_x, + getChannelDescription_v_1_0_x, + isChannelLinkedTo_v_1_3_x, + getLinkedChannels_v_1_3_x, + requestLocalUserTransmissionMode_v_1_0_x, + requestUserMove_v_1_0_x, + requestMicrophoneActivationOverwrite_v_1_0_x, + requestLocalMute_v_1_0_x, + requestLocalUserMute_v_1_0_x, + requestLocalUserDeaf_v_1_0_x, + requestSetLocalUserComment_v_1_0_x, + requestLinkChannels_v_1_3_x, + requestUnlinkChannels_v_1_3_x, + requestUnlinkGivenChannels_v_1_3_x, + requestStartListeningToChannels_v_1_3_x, + requestStopListeningToChannels_v_1_3_x, + requestSendUserTextMessage_v_1_3_x, + findUserByName_v_1_0_x, + findChannelByName_v_1_0_x, + getMumbleSetting_bool_v_1_0_x, + getMumbleSetting_int_v_1_0_x, + getMumbleSetting_double_v_1_0_x, + getMumbleSetting_string_v_1_0_x, + setMumbleSetting_bool_v_1_0_x, + setMumbleSetting_int_v_1_0_x, + setMumbleSetting_double_v_1_0_x, + setMumbleSetting_string_v_1_0_x, + sendData_v_1_0_x, + log_v_1_0_x, + playSample_v_1_2_x }; +} + #define MAP(qtName, apiName) \ case Qt::Key_##qtName: \ return MUMBLE_KC_##apiName diff --git a/src/mumble/MumbleAPI_structs.h b/src/mumble/MumbleAPI_structs.h index fe8da575e62..df5212b083b 100644 --- a/src/mumble/MumbleAPI_structs.h +++ b/src/mumble/MumbleAPI_structs.h @@ -15,6 +15,17 @@ // First, include the latest plugin API header file completely #include "MumblePlugin.h" +// Now, include all older API structs for backward compatibility +// Re-include the API definition +#undef EXTERNAL_MUMBLE_PLUGIN_MUMBLE_API_ +// But this time, overwrite the version +#undef MUMBLE_PLUGIN_API_MAJOR_MACRO +#define MUMBLE_PLUGIN_API_MAJOR_MACRO 1 +#undef MUMBLE_PLUGIN_API_MINOR_MACRO +#define MUMBLE_PLUGIN_API_MINOR_MACRO 2 + +#include "MumblePlugin.h" + // Re-include the API definition #undef EXTERNAL_MUMBLE_PLUGIN_MUMBLE_API_ diff --git a/src/mumble/Plugin.cpp b/src/mumble/Plugin.cpp index d1e6ba27327..058a787e10e 100644 --- a/src/mumble/Plugin.cpp +++ b/src/mumble/Plugin.cpp @@ -329,6 +329,9 @@ mumble_error_t Plugin::init() { } else if (apiVersion >= mumble_version_t({ 1, 2, 0 }) && apiVersion < mumble_version_t({ 1, 3, 0 })) { MumbleAPI_v_1_2_x api = API::getMumbleAPI_v_1_2_x(); registerAPIFunctions(&api); + } else if (apiVersion >= mumble_version_t({ 1, 3, 0 }) && apiVersion < mumble_version_t({ 1, 4, 0 })) { + MumbleAPI_v_1_3_x api = API::getMumbleAPI_v_1_3_x(); + registerAPIFunctions(&api); } else { // The API version could not be obtained -> this is an invalid plugin that shouldn't have been loaded in the // first place diff --git a/src/mumble/ServerHandler.cpp b/src/mumble/ServerHandler.cpp index fe590960f65..3e2c7436315 100644 --- a/src/mumble/ServerHandler.cpp +++ b/src/mumble/ServerHandler.cpp @@ -1104,6 +1104,18 @@ void ServerHandler::addChannelLink(unsigned int channel, unsigned int link) { sendMessage(mpcs); } +void ServerHandler::addChannelLinks(const unsigned int channelCount, const unsigned int *channelSet) { + if (channelCount < 2) { + return; + } + MumbleProto::ChannelState mpcs; + mpcs.set_channel_id(channelSet[0]); + for (unsigned int i = 1; i < channelCount; i++) { + mpcs.add_links_add(channelSet[i]); + } + sendMessage(mpcs); +} + void ServerHandler::removeChannelLink(unsigned int channel, unsigned int link) { MumbleProto::ChannelState mpcs; mpcs.set_channel_id(channel); @@ -1111,6 +1123,32 @@ void ServerHandler::removeChannelLink(unsigned int channel, unsigned int link) { sendMessage(mpcs); } +void ServerHandler::removeChannelLinks(unsigned int channel, const unsigned int channelCount, + const unsigned int *channelSet) { + if (channelCount < 1) { + return; + } + MumbleProto::ChannelState mpcs; + mpcs.set_channel_id(channel); + for (unsigned int i = 0; i < channelCount; i++) { + mpcs.add_links_remove(channelSet[i]); + } + sendMessage(mpcs); +} + +void ServerHandler::removeChannelLinks(const unsigned int channelCount, const unsigned int *channelSet) { + if (channelCount < 2) { + return; + } + MumbleProto::ChannelState mpcs; + unsigned int link = channelSet[0]; + for (unsigned int i = 1; i < channelCount; i++) { + mpcs.set_channel_id(link); + mpcs.add_links_remove(channelSet[i]); + } + sendMessage(mpcs); +} + void ServerHandler::requestChannelPermissions(unsigned int channel) { MumbleProto::PermissionQuery mppq; mppq.set_channel_id(channel); diff --git a/src/mumble/ServerHandler.h b/src/mumble/ServerHandler.h index d64745f9c86..cd247f54d6e 100644 --- a/src/mumble/ServerHandler.h +++ b/src/mumble/ServerHandler.h @@ -173,7 +173,11 @@ class ServerHandler : public QThread { void setTokens(const QStringList &tokens); void removeChannel(unsigned int channel); void addChannelLink(unsigned int channel, unsigned int link); + void addChannelLinks(const unsigned int channelCount, const unsigned int *channelSet); void removeChannelLink(unsigned int channel, unsigned int link); + void removeChannelLinks(const unsigned int channel, const unsigned int channelCount, + const unsigned int *channelSet); + void removeChannelLinks(const unsigned int channelCount, const unsigned int *channelSet); void requestChannelPermissions(unsigned int channel); void setSelfMuteDeafState(bool mute, bool deaf); void announceRecordingState(bool recording);