Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/mumble/API_v_1_0_x.cpp')
-rw-r--r--src/mumble/API_v_1_0_x.cpp1980
1 files changed, 1980 insertions, 0 deletions
diff --git a/src/mumble/API_v_1_0_x.cpp b/src/mumble/API_v_1_0_x.cpp
new file mode 100644
index 000000000..ac8adf6f1
--- /dev/null
+++ b/src/mumble/API_v_1_0_x.cpp
@@ -0,0 +1,1980 @@
+// Copyright 2021 The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at <https://www.mumble.info/LICENSE>.
+
+#include "API.h"
+#include "AudioOutput.h"
+#include "Channel.h"
+#include "ClientUser.h"
+#include "Database.h"
+#include "Log.h"
+#include "MainWindow.h"
+#include "PluginComponents_v_1_0_x.h"
+#include "PluginManager.h"
+#include "ServerHandler.h"
+#include "Settings.h"
+#include "UserModel.h"
+#include "MumbleConstants.h"
+#include "Global.h"
+
+#include <QVariant>
+#include <QtCore/QHash>
+#include <QtCore/QMutex>
+#include <QtCore/QMutexLocker>
+#include <QtCore/QReadLocker>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+
+#include <cstring>
+#include <string>
+
+#define EXIT_WITH(code) \
+ if (promise) { \
+ promise->set_value(code); \
+ } \
+ return;
+
+#define VERIFY_PLUGIN_ID(id) \
+ if (!Global::get().pluginManager->pluginExists(id)) { \
+ EXIT_WITH(EC_INVALID_PLUGIN_ID); \
+ }
+
+// 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(EC_CONNECTION_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
+#define ENSURE_CONNECTION_SYNCHRONIZED(connection) \
+ if (Global::get().uiSession == 0) { \
+ EXIT_WITH(EC_CONNECTION_UNSYNCHRONIZED); \
+ }
+
+#define UNUSED(var) (void) var;
+
+namespace API {
+
+MumbleAPICurator::~MumbleAPICurator() {
+ // free all remaining resources using the stored deleters
+ for (const auto &current : m_entries) {
+ const Entry &entry = current.second;
+
+ // Delete leaked resource
+ entry.m_deleter(current.first);
+
+ // Print an error about the leaked resource
+ printf("[ERROR]: Plugin with ID %d leaked memory from a call to API function \"%s\"\n", entry.m_pluginID, entry.m_sourceFunctionName);
+ }
+}
+// Some common delete-functions
+void defaultDeleter(const void *ptr) {
+ // We use const-cast in order to circumvent the shortcoming of the free() signature only taking
+ // in void * and not const void *. Delete on the other hand is allowed on const pointers which is
+ // why this is an okay thing to do.
+ // See also https://stackoverflow.com/questions/2819535/unable-to-free-const-pointers-in-c
+ free(const_cast< void * >(ptr));
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// API IMPLEMENTATION //////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// This macro registers type, type * and type ** to Qt's metatype system
+// and also their const variants (except const value as that doesn't make sense)
+#define REGISTER_METATYPE(type) \
+ qRegisterMetaType< type >(#type); \
+ qRegisterMetaType< type * >(#type " *"); \
+ qRegisterMetaType< type ** >(#type " **"); \
+ qRegisterMetaType< const type * >("const " #type " *"); \
+ qRegisterMetaType< const type ** >("const " #type " **"); \
+
+MumbleAPI::MumbleAPI() {
+ // Move this object to the main thread
+ moveToThread(qApp->thread());
+
+ // Register all API types to Qt's metatype system
+ REGISTER_METATYPE(bool);
+ REGISTER_METATYPE(char);
+ REGISTER_METATYPE(double);
+ REGISTER_METATYPE(int);
+ REGISTER_METATYPE(int64_t);
+ REGISTER_METATYPE(mumble_channelid_t);
+ REGISTER_METATYPE(mumble_connection_t);
+ REGISTER_METATYPE(mumble_plugin_id_t);
+ REGISTER_METATYPE(mumble_settings_key_t);
+ REGISTER_METATYPE(mumble_transmission_mode_t);
+ REGISTER_METATYPE(mumble_userid_t);
+ REGISTER_METATYPE(mumble_userid_t);
+ REGISTER_METATYPE(size_t);
+ REGISTER_METATYPE(uint8_t);
+
+ // Define additional types that can't be defined using macro REGISTER_METATYPE
+ qRegisterMetaType< api_promise_t * >("api_promise_t *");
+ qRegisterMetaType< API::api_promise_t * >("API::api_promise_t *");
+ qRegisterMetaType< const void * >("const void *");
+ qRegisterMetaType< const void ** >("const void **");
+ qRegisterMetaType< void * >("void *");
+ qRegisterMetaType< void ** >("void **");
+}
+
+#undef REFGISTER_METATYPE
+
+MumbleAPI &MumbleAPI::get() {
+ static MumbleAPI api;
+
+ return api;
+}
+
+void MumbleAPI::freeMemory_v_1_0_x(mumble_plugin_id_t callerID, const void *ptr, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "freeMemory_v_1_0_x", Qt::QueuedConnection, Q_ARG(mumble_plugin_id_t, callerID),
+ Q_ARG(const void *, ptr), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ // Don't verify plugin ID here to avoid memory leaks
+ UNUSED(callerID);
+
+ auto it = m_curator.m_entries.find(ptr);
+ if (it != m_curator.m_entries.cend()) {
+ MumbleAPICurator::Entry &entry = (*it).second;
+
+ // call the deleter to delete the resource
+ entry.m_deleter(ptr);
+
+ // Remove pointer from curator
+ m_curator.m_entries.erase(it);
+
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_POINTER_NOT_FOUND);
+ }
+}
+
+void MumbleAPI::getActiveServerConnection_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t *connection,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getActiveServerConnection_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t *, connection),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ if (Global::get().sh) {
+ *connection = Global::get().sh->getConnectionID();
+
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_NO_ACTIVE_CONNECTION);
+ }
+}
+
+void MumbleAPI::isConnectionSynchronized_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ bool *synchronized, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "isConnectionSynchronized_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(bool *, synchronized), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+ VERIFY_CONNECTION(connection);
+
+ // Right now there can only be one connection and if Global::get().uiSession is zero, then the synchronization has not finished
+ // yet (or there is no connection to begin with)
+ *synchronized = Global::get().uiSession != 0;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getLocalUserID_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_userid_t *userID, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getLocalUserID_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_userid_t *, userID), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ *userID = Global::get().uiSession;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getUserName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID,
+ const char **name, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getUserName_v_1_0_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 **, name),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const ClientUser *user = ClientUser::get(userID);
+
+ if (user) {
+ // +1 for NULL terminator
+ size_t size = user->qsName.toUtf8().size() + 1;
+
+ char *nameArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(nameArray, user->qsName.toUtf8().data());
+
+ // save the allocated pointer and how to delete it
+ m_curator.m_entries.insert({ nameArray, { defaultDeleter, callerID, "getUserName" } });
+
+ *name = nameArray;
+
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+}
+
+void MumbleAPI::getChannelName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_channelid_t channelID, const char **name, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getChannelName_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_channelid_t, channelID), Q_ARG(const char **, name),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const Channel *channel = Channel::get(channelID);
+
+ if (channel) {
+ // +1 for NULL terminator
+ size_t size = channel->qsName.toUtf8().size() + 1;
+
+ char *nameArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(nameArray, channel->qsName.toUtf8().data());
+
+ // save the allocated pointer and how to delete it
+ m_curator.m_entries.insert({ nameArray, { defaultDeleter, callerID, "getChannelName" } });
+
+ *name = nameArray;
+
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_CHANNEL_NOT_FOUND);
+ }
+}
+
+void MumbleAPI::getAllUsers_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_userid_t **users, size_t *userCount, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getAllUsers_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_userid_t **, users), Q_ARG(size_t *, userCount),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ QReadLocker userLock(&ClientUser::c_qrwlUsers);
+
+ size_t amount = ClientUser::c_qmUsers.size();
+
+ auto it = ClientUser::c_qmUsers.constBegin();
+
+ mumble_userid_t *userIDs = reinterpret_cast< mumble_userid_t * >(malloc(sizeof(mumble_userid_t) * amount));
+
+ unsigned int index = 0;
+ while (it != ClientUser::c_qmUsers.constEnd()) {
+ userIDs[index] = it.key();
+
+ it++;
+ index++;
+ }
+
+ m_curator.m_entries.insert({ userIDs, { defaultDeleter, callerID, "getAllUsers" } });
+
+ *users = userIDs;
+ *userCount = amount;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getAllChannels_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_channelid_t **channels, size_t *channelCount, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getAllChannels_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_channelid_t **, channels), Q_ARG(size_t *, channelCount),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ QReadLocker channelLock(&Channel::c_qrwlChannels);
+
+ size_t amount = Channel::c_qhChannels.size();
+
+ auto it = Channel::c_qhChannels.constBegin();
+
+ mumble_channelid_t *channelIDs =
+ reinterpret_cast< mumble_channelid_t * >(malloc(sizeof(mumble_channelid_t) * amount));
+
+ unsigned int index = 0;
+ while (it != Channel::c_qhChannels.constEnd()) {
+ channelIDs[index] = it.key();
+
+ it++;
+ index++;
+ }
+
+ m_curator.m_entries.insert({ channelIDs, { defaultDeleter, callerID, "getAllChannels" } });
+
+ *channels = channelIDs;
+ *channelCount = amount;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getChannelOfUser_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_userid_t userID, mumble_channelid_t *channelID,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getChannelOfUser_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_userid_t, userID), Q_ARG(mumble_channelid_t *, channelID),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const ClientUser *user = ClientUser::get(userID);
+
+ if (!user) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ if (user->cChannel) {
+ *channelID = user->cChannel->iId;
+
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_GENERIC_ERROR);
+ }
+}
+
+void MumbleAPI::getUsersInChannel_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_channelid_t channelID, mumble_userid_t **users, size_t *userCount,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getUsersInChannel_v_1_0_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_userid_t **, users),
+ Q_ARG(size_t *, userCount), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const Channel *channel = Channel::get(channelID);
+
+ if (!channel) {
+ EXIT_WITH(EC_CHANNEL_NOT_FOUND);
+ }
+
+ size_t amount = channel->qlUsers.size();
+
+ mumble_userid_t *userIDs = reinterpret_cast< mumble_userid_t * >(malloc(sizeof(mumble_userid_t) * amount));
+
+ int index = 0;
+ foreach (const User *currentUser, channel->qlUsers) {
+ userIDs[index] = currentUser->uiSession;
+
+ index++;
+ }
+
+ m_curator.m_entries.insert({ userIDs, { defaultDeleter, callerID, "getUsersInChannel" } });
+
+ *users = userIDs;
+ *userCount = amount;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_transmission_mode_t *transmissionMode,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(
+ this, "getLocalUserTransmissionMode_v_1_0_x", Qt::QueuedConnection, Q_ARG(mumble_plugin_id_t, callerID),
+ Q_ARG(mumble_transmission_mode_t *, transmissionMode), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ switch (Global::get().s.atTransmit) {
+ case Settings::AudioTransmit::Continuous:
+ *transmissionMode = TM_CONTINOUS;
+ EXIT_WITH(STATUS_OK);
+ case Settings::AudioTransmit::VAD:
+ *transmissionMode = TM_VOICE_ACTIVATION;
+ EXIT_WITH(STATUS_OK);
+ case Settings::AudioTransmit::PushToTalk:
+ *transmissionMode = TM_PUSH_TO_TALK;
+ EXIT_WITH(STATUS_OK);
+ }
+
+ // Unable to resolve transmission mode
+ EXIT_WITH(EC_GENERIC_ERROR);
+}
+
+void MumbleAPI::isUserLocallyMuted_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_userid_t userID, bool *muted, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "isUserLocallyMuted_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_userid_t, userID), Q_ARG(bool *, muted),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const ClientUser *user = ClientUser::get(userID);
+
+ if (!user) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ *muted = user->bLocalMute;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::isLocalUserMuted_v_1_0_x(mumble_plugin_id_t callerID, bool *muted, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "isLocalUserMuted_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(bool *, muted),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ *muted = Global::get().s.bMute;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::isLocalUserDeafened_v_1_0_x(mumble_plugin_id_t callerID, bool *deafened, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "isLocalUserDeafened_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(bool *, deafened),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ *deafened = Global::get().s.bDeaf;
+
+ EXIT_WITH(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, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getUserHash_v_1_0_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 **, hash),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const ClientUser *user = ClientUser::get(userID);
+
+ if (!user) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ // The user's hash is already in hexadecimal representation, so we don't have to worry about null-bytes in it
+ // +1 for NULL terminator
+ size_t size = user->qsHash.toUtf8().size() + 1;
+
+ char *hashArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(hashArray, user->qsHash.toUtf8().data());
+
+ m_curator.m_entries.insert({ hashArray, { defaultDeleter, callerID, "getUserHash" } });
+
+ *hash = hashArray;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getServerHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char **hash,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getServerHash_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(const char **, hash), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ // Use hexadecimal representation in order for the String to be properly printable and for it to be C-encodable
+ QByteArray hashHex = Global::get().sh->qbaDigest.toHex();
+ QString strHash = QString::fromLatin1(hashHex);
+
+ // +1 for NULL terminator
+ size_t size = strHash.toUtf8().size() + 1;
+
+ char *hashArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(hashArray, strHash.toUtf8().data());
+
+ m_curator.m_entries.insert({ hashArray, { defaultDeleter, callerID, "getServerHash" } });
+
+ *hash = hashArray;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::requestLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_transmission_mode_t transmissionMode,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestLocalUserTransmissionMode_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID),
+ Q_ARG(mumble_transmission_mode_t, transmissionMode), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ switch (transmissionMode) {
+ case TM_CONTINOUS:
+ Global::get().s.atTransmit = Settings::AudioTransmit::Continuous;
+ EXIT_WITH(STATUS_OK);
+ case TM_VOICE_ACTIVATION:
+ Global::get().s.atTransmit = Settings::AudioTransmit::VAD;
+ EXIT_WITH(STATUS_OK);
+ case TM_PUSH_TO_TALK:
+ Global::get().s.atTransmit = Settings::AudioTransmit::PushToTalk;
+ EXIT_WITH(STATUS_OK);
+ }
+
+ EXIT_WITH(EC_UNKNOWN_TRANSMISSION_MODE);
+}
+
+void MumbleAPI::getUserComment_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_userid_t userID, const char **comment, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getUserComment_v_1_0_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 **, comment),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ ClientUser *user = ClientUser::get(userID);
+
+ if (!user) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ if (user->qsComment.isEmpty() && !user->qbaCommentHash.isEmpty()) {
+ user->qsComment = QString::fromUtf8(Global::get().db->blob(user->qbaCommentHash));
+
+ if (user->qsComment.isEmpty()) {
+ // The user's comment hasn't been synchronized to this client yet
+ EXIT_WITH(EC_UNSYNCHRONIZED_BLOB);
+ }
+ }
+
+ // +1 for NULL terminator
+ size_t size = user->qsComment.toUtf8().size() + 1;
+
+ char *nameArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(nameArray, user->qsComment.toUtf8().data());
+
+ m_curator.m_entries.insert({ nameArray, { defaultDeleter, callerID, "getUserComment" } });
+
+ *comment = nameArray;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getChannelDescription_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_channelid_t channelID, const char **description,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getChannelDescription_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_channelid_t, channelID), Q_ARG(const char **, description),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ Channel *channel = Channel::get(channelID);
+
+ if (!channel) {
+ EXIT_WITH(EC_CHANNEL_NOT_FOUND);
+ }
+
+ if (channel->qsDesc.isEmpty() && !channel->qbaDescHash.isEmpty()) {
+ channel->qsDesc = QString::fromUtf8(Global::get().db->blob(channel->qbaDescHash));
+
+ if (channel->qsDesc.isEmpty()) {
+ // The channel's description hasn't been synchronized to this client yet
+ EXIT_WITH(EC_UNSYNCHRONIZED_BLOB);
+ }
+ }
+
+ // +1 for NULL terminator
+ size_t size = channel->qsDesc.toUtf8().size() + 1;
+
+ char *nameArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(nameArray, channel->qsDesc.toUtf8().data());
+
+ m_curator.m_entries.insert({ nameArray, { defaultDeleter, callerID, "getChannelDescription" } });
+
+ *description = nameArray;
+
+ EXIT_WITH(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,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestUserMove_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_userid_t, userID), Q_ARG(mumble_channelid_t, channelID),
+ Q_ARG(const char *, password), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const ClientUser *user = ClientUser::get(userID);
+
+ if (!user) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ const Channel *channel = Channel::get(channelID);
+
+ if (!channel) {
+ EXIT_WITH(EC_CHANNEL_NOT_FOUND);
+ }
+
+ if (channel != user->cChannel) {
+ // send move-request to the server only if the user is not in the channel already
+ QStringList passwordList;
+ if (password) {
+ passwordList << QString::fromUtf8(password);
+ }
+
+ Global::get().sh->joinChannel(user->uiSession, channel->iId, passwordList);
+ }
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::requestMicrophoneActivationOverwrite_v_1_0_x(mumble_plugin_id_t callerID, bool activate,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestMicrophoneActivationOverwrite_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(bool, activate),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ PluginData::get().overwriteMicrophoneActivation.store(activate);
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::requestLocalMute_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ mumble_userid_t userID, bool muted, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestLocalMute_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(mumble_userid_t, userID), Q_ARG(bool, muted), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ if (userID == Global::get().uiSession) {
+ // Can't locally mute the local user
+ EXIT_WITH(EC_INVALID_MUTE_TARGET);
+ }
+
+ ClientUser *user = ClientUser::get(userID);
+
+ if (!user) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ user->setLocalMute(muted);
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::requestLocalUserMute_v_1_0_x(mumble_plugin_id_t callerID, bool muted, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestLocalUserMute_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(bool, muted),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ if (!Global::get().mw) {
+ EXIT_WITH(EC_INTERNAL_ERROR);
+ }
+
+ Global::get().mw->setAudioMute(muted);
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::requestLocalUserDeaf_v_1_0_x(mumble_plugin_id_t callerID, bool deafened, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestLocalUserDeaf_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(bool, deafened),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ if (!Global::get().mw) {
+ EXIT_WITH(EC_INTERNAL_ERROR);
+ }
+
+ Global::get().mw->setAudioDeaf(deafened);
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::requestSetLocalUserComment_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ const char *comment, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "requestSetLocalUserComment_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(const char *, comment), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ ClientUser *localUser = ClientUser::get(Global::get().uiSession);
+
+ if (!localUser) {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+
+ if (!Global::get().mw || !Global::get().mw->pmModel) {
+ EXIT_WITH(EC_INTERNAL_ERROR);
+ }
+
+ Global::get().mw->pmModel->setComment(localUser, QString::fromUtf8(comment));
+
+ EXIT_WITH(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, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "findUserByName_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(const char *, userName), Q_ARG(mumble_userid_t *, userID),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const QString qsUserName = QString::fromUtf8(userName);
+
+ QReadLocker userLock(&ClientUser::c_qrwlUsers);
+
+ auto it = ClientUser::c_qmUsers.constBegin();
+ while (it != ClientUser::c_qmUsers.constEnd()) {
+ if (it.value()->qsName == qsUserName) {
+ *userID = it.key();
+
+ EXIT_WITH(STATUS_OK);
+ }
+
+ it++;
+ }
+
+ EXIT_WITH(EC_USER_NOT_FOUND);
+}
+
+void MumbleAPI::findChannelByName_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ const char *channelName, mumble_channelid_t *channelID,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "findChannelByName_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_connection_t, connection),
+ Q_ARG(const char *, channelName), Q_ARG(mumble_channelid_t *, channelID),
+ Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ const QString qsChannelName = QString::fromUtf8(channelName);
+
+ QReadLocker channelLock(&Channel::c_qrwlChannels);
+
+ auto it = Channel::c_qhChannels.constBegin();
+ while (it != Channel::c_qhChannels.constEnd()) {
+ if (it.value()->qsName == qsChannelName) {
+ *channelID = it.key();
+
+ EXIT_WITH(STATUS_OK);
+ }
+
+ it++;
+ }
+
+ EXIT_WITH(EC_CHANNEL_NOT_FOUND);
+}
+
+QVariant getMumbleSettingHelper(mumble_settings_key_t key) {
+ QVariant value;
+
+ // All values are explicitly cast to the target type of their associated API. For instance there is not API to
+ // get float values but there is one for doubles. Therefore floats have to be cast to doubles in order for the
+ // type checking to work out.
+ switch (key) {
+ case MSK_AUDIO_INPUT_VOICE_HOLD:
+ value = static_cast< int >(Global::get().s.iVoiceHold);
+ break;
+ case MSK_AUDIO_INPUT_VAD_SILENCE_THRESHOLD:
+ value = static_cast< double >(Global::get().s.fVADmin);
+ break;
+ case MSK_AUDIO_INPUT_VAD_SPEECH_THRESHOLD:
+ value = static_cast< double >(Global::get().s.fVADmax);
+ break;
+ case MSK_AUDIO_OUTPUT_PA_MINIMUM_DISTANCE:
+ value = static_cast< double >(Global::get().s.fAudioMinDistance);
+ break;
+ case MSK_AUDIO_OUTPUT_PA_MAXIMUM_DISTANCE:
+ value = static_cast< double >(Global::get().s.fAudioMaxDistance);
+ break;
+ case MSK_AUDIO_OUTPUT_PA_BLOOM:
+ value = static_cast< double >(Global::get().s.fAudioBloom);
+ break;
+ case MSK_AUDIO_OUTPUT_PA_MINIMUM_VOLUME:
+ value = static_cast< double >(Global::get().s.fAudioMaxDistVolume);
+ break;
+ case MSK_INVALID:
+ // There is no setting associated with this key
+ break;
+ }
+
+ return value;
+}
+
+// IS_TYPE actually only checks if the QVariant can be converted to the needed type since that's all that we really care
+// about at the end of the day.
+#define IS_TYPE(var, varType) static_cast< QMetaType::Type >(var.type()) == varType
+#define IS_NOT_TYPE(var, varType) static_cast< QMetaType::Type >(var.type()) != varType
+
+void MumbleAPI::getMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, bool *outValue,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getMumbleSetting_bool_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(bool *, outValue), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ QVariant value = getMumbleSettingHelper(key);
+
+ if (!value.isValid()) {
+ // We also return that for MSK_INVALID
+ EXIT_WITH(EC_UNKNOWN_SETTINGS_KEY);
+ }
+
+ if (IS_NOT_TYPE(value, QMetaType::Bool)) {
+ EXIT_WITH(EC_WRONG_SETTINGS_TYPE);
+ }
+
+ *outValue = value.toBool();
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t *outValue,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getMumbleSetting_int_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(int64_t *, outValue), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ QVariant value = getMumbleSettingHelper(key);
+
+ if (!value.isValid()) {
+ // We also return that for MSK_INVALID
+ EXIT_WITH(EC_UNKNOWN_SETTINGS_KEY);
+ }
+
+ if (IS_NOT_TYPE(value, QMetaType::Int)) {
+ EXIT_WITH(EC_WRONG_SETTINGS_TYPE);
+ }
+
+ *outValue = value.toInt();
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key,
+ double *outValue, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getMumbleSetting_double_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(double *, outValue), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ QVariant value = getMumbleSettingHelper(key);
+
+ if (!value.isValid()) {
+ // We also return that for MSK_INVALID
+ EXIT_WITH(EC_UNKNOWN_SETTINGS_KEY);
+ }
+
+ if (IS_NOT_TYPE(value, QMetaType::Double)) {
+ EXIT_WITH(EC_WRONG_SETTINGS_TYPE);
+ }
+
+ *outValue = value.toDouble();
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::getMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key,
+ const char **outValue, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "getMumbleSetting_string_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(const char **, outValue), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ QVariant value = getMumbleSettingHelper(key);
+
+ if (!value.isValid()) {
+ // We also return that for MSK_INVALID
+ EXIT_WITH(EC_UNKNOWN_SETTINGS_KEY);
+ }
+
+ if (IS_NOT_TYPE(value, QMetaType::QString)) {
+ EXIT_WITH(EC_WRONG_SETTINGS_TYPE);
+ }
+
+ const QString stringValue = value.toString();
+
+ // +1 for NULL terminator
+ size_t size = stringValue.toUtf8().size() + 1;
+
+ char *valueArray = reinterpret_cast< char * >(malloc(size * sizeof(char)));
+
+ std::strcpy(valueArray, stringValue.toUtf8().data());
+
+ m_curator.m_entries.insert({ valueArray, { defaultDeleter, callerID, "getMumbleSetting_string" } });
+
+ *outValue = valueArray;
+
+ EXIT_WITH(STATUS_OK);
+}
+
+mumble_error_t setMumbleSettingHelper(mumble_settings_key_t key, QVariant value) {
+ switch (key) {
+ case MSK_AUDIO_INPUT_VOICE_HOLD:
+ if (IS_TYPE(value, QMetaType::Int)) {
+ Global::get().s.iVoiceHold = value.toInt();
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_AUDIO_INPUT_VAD_SILENCE_THRESHOLD:
+ if (IS_TYPE(value, QMetaType::Double)) {
+ Global::get().s.fVADmin = static_cast< float >(value.toDouble());
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_AUDIO_INPUT_VAD_SPEECH_THRESHOLD:
+ if (IS_TYPE(value, QMetaType::Double)) {
+ Global::get().s.fVADmax = static_cast< float >(value.toDouble());
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_AUDIO_OUTPUT_PA_MINIMUM_DISTANCE:
+ if (IS_TYPE(value, QMetaType::Double)) {
+ Global::get().s.fAudioMinDistance = static_cast< float >(value.toDouble());
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_AUDIO_OUTPUT_PA_MAXIMUM_DISTANCE:
+ if (IS_TYPE(value, QMetaType::Double)) {
+ Global::get().s.fAudioMaxDistance = static_cast< float >(value.toDouble());
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_AUDIO_OUTPUT_PA_BLOOM:
+ if (IS_TYPE(value, QMetaType::Double)) {
+ Global::get().s.fAudioBloom = static_cast< float >(value.toDouble());
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_AUDIO_OUTPUT_PA_MINIMUM_VOLUME:
+ if (IS_TYPE(value, QMetaType::Double)) {
+ Global::get().s.fAudioMaxDistVolume = static_cast< float >(value.toDouble());
+
+ return STATUS_OK;
+ } else {
+ return EC_WRONG_SETTINGS_TYPE;
+ }
+ case MSK_INVALID:
+ // Do nothing
+ break;
+ }
+
+ return EC_UNKNOWN_SETTINGS_KEY;
+}
+
+void MumbleAPI::setMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, bool value,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "setMumbleSetting_bool_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(bool, value), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ mumble_error_t exitCode = setMumbleSettingHelper(key, value);
+ EXIT_WITH(exitCode);
+}
+
+void MumbleAPI::setMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t value,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "setMumbleSetting_int_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(int64_t, value), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ mumble_error_t exitCode = setMumbleSettingHelper(key, QVariant::fromValue(value));
+ EXIT_WITH(exitCode);
+}
+
+void MumbleAPI::setMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, double value,
+ api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "setMumbleSetting_double_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(double, value), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ mumble_error_t exitCode = setMumbleSettingHelper(key, value);
+ EXIT_WITH(exitCode);
+}
+
+void MumbleAPI::setMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key,
+ const char *value, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "setMumbleSetting_string_v_1_0_x", Qt::QueuedConnection,
+ Q_ARG(mumble_plugin_id_t, callerID), Q_ARG(mumble_settings_key_t, key),
+ Q_ARG(const char *, value), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ mumble_error_t exitCode = setMumbleSettingHelper(key, QString::fromUtf8(value));
+ EXIT_WITH(exitCode);
+}
+#undef IS_TYPE
+#undef IS_NOT_TYPE
+
+void MumbleAPI::sendData_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ const mumble_userid_t *users, size_t userCount, const uint8_t *data, size_t dataLength,
+ const char *dataID, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "sendData_v_1_0_x", Qt::QueuedConnection, Q_ARG(mumble_plugin_id_t, callerID),
+ Q_ARG(mumble_connection_t, connection), Q_ARG(const mumble_userid_t *, users),
+ Q_ARG(size_t, userCount), Q_ARG(const uint8_t *, data), Q_ARG(size_t, dataLength),
+ Q_ARG(const char *, dataID), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ VERIFY_CONNECTION(connection);
+ ENSURE_CONNECTION_SYNCHRONIZED(connection);
+
+ if (dataLength > Mumble::Plugins::PluginMessage::MAX_DATA_LENGTH) {
+ EXIT_WITH(EC_DATA_TOO_BIG);
+ }
+ if (std::strlen(dataID) > Mumble::Plugins::PluginMessage::MAX_DATA_ID_LENGTH) {
+ EXIT_WITH(EC_DATA_ID_TOO_LONG);
+ }
+
+ MumbleProto::PluginDataTransmission mpdt;
+ mpdt.set_sendersession(Global::get().uiSession);
+
+ for (size_t i = 0; i < userCount; i++) {
+ const ClientUser *user = ClientUser::get(users[i]);
+
+ if (user) {
+ mpdt.add_receiversessions(users[i]);
+ } else {
+ EXIT_WITH(EC_USER_NOT_FOUND);
+ }
+ }
+
+ mpdt.set_data(data, dataLength);
+ mpdt.set_dataid(dataID);
+
+ if (Global::get().sh) {
+ Global::get().sh->sendMessage(mpdt);
+
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_CONNECTION_NOT_FOUND);
+ }
+}
+
+void MumbleAPI::log_v_1_0_x(mumble_plugin_id_t callerID, const char *message, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "log_v_1_0_x", Qt::QueuedConnection, Q_ARG(mumble_plugin_id_t, callerID),
+ Q_ARG(const char *, message), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ // We verify the plugin manually as we need a handle to it later
+ const_plugin_ptr_t plugin = Global::get().pluginManager->getPlugin(callerID);
+ if (!plugin) {
+ EXIT_WITH(EC_INVALID_PLUGIN_ID);
+ }
+
+ QString msg = QString::fromLatin1("<b>%1:</b> %2")
+ .arg(plugin->getName().toHtmlEscaped())
+ .arg(QString::fromUtf8(message).toHtmlEscaped());
+
+ // Use static method that handles the case in which the Log object doesn't exist yet
+ Log::logOrDefer(Log::PluginMessage, msg);
+
+ EXIT_WITH(STATUS_OK);
+}
+
+void MumbleAPI::playSample_v_1_0_x(mumble_plugin_id_t callerID, const char *samplePath, api_promise_t *promise) {
+ if (QThread::currentThread() != thread()) {
+ // Invoke in main thread
+ QMetaObject::invokeMethod(this, "playSample_v_1_0_x", Qt::QueuedConnection, Q_ARG(mumble_plugin_id_t, callerID),
+ Q_ARG(const char *, samplePath), Q_ARG(api_promise_t *, promise));
+
+ return;
+ }
+
+ VERIFY_PLUGIN_ID(callerID);
+
+ if (!Global::get().ao) {
+ EXIT_WITH(EC_AUDIO_NOT_AVAILABLE);
+ }
+
+ if (Global::get().ao->playSample(QString::fromUtf8(samplePath), false)) {
+ EXIT_WITH(STATUS_OK);
+ } else {
+ EXIT_WITH(EC_INVALID_SAMPLE);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////// C FUNCTION WRAPPERS FOR USE IN API STRUCT ///////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+mumble_error_t PLUGIN_CALLING_CONVENTION freeMemory_v_1_0_x(mumble_plugin_id_t callerID, const void *ptr) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().freeMemory_v_1_0_x(callerID, ptr, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getActiveServerConnection_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t *connection) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getActiveServerConnection_v_1_0_x(callerID, connection, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION isConnectionSynchronized_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ bool *synchronized) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().isConnectionSynchronized_v_1_0_x(callerID, connection, synchronized, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getLocalUserID_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_userid_t *userID) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getLocalUserID_v_1_0_x(callerID, connection, userID, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getUserName_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection, mumble_userid_t userID,
+ const char **name) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getUserName_v_1_0_x(callerID, connection, userID, name, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getChannelName_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_channelid_t channelID, const char **name) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getChannelName_v_1_0_x(callerID, connection, channelID, name, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getAllUsers_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection, mumble_userid_t **users,
+ size_t *userCount) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getAllUsers_v_1_0_x(callerID, connection, users, userCount, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getAllChannels_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_channelid_t **channels, size_t *channelCount) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getAllChannels_v_1_0_x(callerID, connection, channels, channelCount, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getChannelOfUser_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_userid_t userID, mumble_channelid_t *channel) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getChannelOfUser_v_1_0_x(callerID, connection, userID, channel, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getUsersInChannel_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_channelid_t channelID,
+ mumble_userid_t **userList, size_t *userCount) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getUsersInChannel_v_1_0_x(callerID, connection, channelID, userList, userCount, &promise);
+
+ return future.get();
+}
+
+
+mumble_error_t PLUGIN_CALLING_CONVENTION
+ getLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID, mumble_transmission_mode_t *transmissionMode) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getLocalUserTransmissionMode_v_1_0_x(callerID, transmissionMode, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION isUserLocallyMuted_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_userid_t userID, bool *muted) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().isUserLocallyMuted_v_1_0_x(callerID, connection, userID, muted, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION isLocalUserMuted_v_1_0_x(mumble_plugin_id_t callerID, bool *muted) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().isLocalUserMuted_v_1_0_x(callerID, muted, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION isLocalUserDeafened_v_1_0_x(mumble_plugin_id_t callerID, bool *deafened) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().isLocalUserDeafened_v_1_0_x(callerID, deafened, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getUserHash_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection, mumble_userid_t userID,
+ const char **hash) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getUserHash_v_1_0_x(callerID, connection, userID, hash, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getServerHash_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection, const char **hash) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getServerHash_v_1_0_x(callerID, connection, hash, &promise);
+
+ return future.get();
+}
+
+
+mumble_error_t PLUGIN_CALLING_CONVENTION
+ requestLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID, mumble_transmission_mode_t transmissionMode) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestLocalUserTransmissionMode_v_1_0_x(callerID, transmissionMode, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getUserComment_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection, mumble_userid_t userID,
+ const char **comment) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getUserComment_v_1_0_x(callerID, connection, userID, comment, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getChannelDescription_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_channelid_t channelID,
+ const char **description) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getChannelDescription_v_1_0_x(callerID, connection, channelID, description, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION 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) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestUserMove_v_1_0_x(callerID, connection, userID, channelID, password, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION requestMicrophoneActivationOverwrite_v_1_0_x(mumble_plugin_id_t callerID,
+ bool activate) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestMicrophoneActivationOverwrite_v_1_0_x(callerID, activate, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION requestLocalMute_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ mumble_userid_t userID, bool muted) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestLocalMute_v_1_0_x(callerID, connection, userID, muted, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION requestLocalUserMute_v_1_0_x(mumble_plugin_id_t callerID, bool muted) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestLocalUserMute_v_1_0_x(callerID, muted, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION requestLocalUserDeaf_v_1_0_x(mumble_plugin_id_t callerID, bool deafened) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestLocalUserDeaf_v_1_0_x(callerID, deafened, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION requestSetLocalUserComment_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ const char *comment) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().requestSetLocalUserComment_v_1_0_x(callerID, connection, comment, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION findUserByName_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection, const char *userName,
+ mumble_userid_t *userID) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().findUserByName_v_1_0_x(callerID, connection, userName, userID, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION findChannelByName_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_connection_t connection,
+ const char *channelName,
+ mumble_channelid_t *channelID) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().findChannelByName_v_1_0_x(callerID, connection, channelName, channelID, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, bool *outValue) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getMumbleSetting_bool_v_1_0_x(callerID, key, outValue, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, int64_t *outValue) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getMumbleSetting_int_v_1_0_x(callerID, key, outValue, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, double *outValue) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getMumbleSetting_double_v_1_0_x(callerID, key, outValue, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION getMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key,
+ const char **outValue) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().getMumbleSetting_string_v_1_0_x(callerID, key, outValue, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION setMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, bool value) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().setMumbleSetting_bool_v_1_0_x(callerID, key, value, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION setMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, int64_t value) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().setMumbleSetting_int_v_1_0_x(callerID, key, value, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION setMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, double value) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().setMumbleSetting_double_v_1_0_x(callerID, key, value, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION setMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID,
+ mumble_settings_key_t key, const char *value) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().setMumbleSetting_string_v_1_0_x(callerID, key, value, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION sendData_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
+ const mumble_userid_t *users, size_t userCount,
+ const uint8_t *data, size_t dataLength, const char *dataID) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().sendData_v_1_0_x(callerID, connection, users, userCount, data, dataLength, dataID, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION log_v_1_0_x(mumble_plugin_id_t callerID, const char *message) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().log_v_1_0_x(callerID, message, &promise);
+
+ return future.get();
+}
+
+mumble_error_t PLUGIN_CALLING_CONVENTION playSample_v_1_0_x(mumble_plugin_id_t callerID, const char *samplePath) {
+ api_promise_t promise;
+ api_future_t future = promise.get_future();
+
+ MumbleAPI::get().playSample_v_1_0_x(callerID, samplePath, &promise);
+
+ return future.get();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////// GETTER FOR API STRUCTS /////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MumbleAPI_v_1_0_x getMumbleAPI_v_1_0_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,
+ 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,
+ 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_0_x };
+}
+
+#define MAP(qtName, apiName) \
+ case Qt::Key_##qtName: \
+ return KC_##apiName
+
+mumble_keycode_t qtKeyCodeToAPIKeyCode(unsigned int keyCode) {
+ switch (keyCode) {
+ MAP(Escape, ESCAPE);
+ MAP(Tab, TAB);
+ MAP(Backspace, BACKSPACE);
+ case Qt::Key_Return:
+ // Fallthrough
+ case Qt::Key_Enter:
+ return KC_ENTER;
+ MAP(Delete, DELETE);
+ MAP(Print, PRINT);
+ MAP(Home, HOME);
+ MAP(End, END);
+ MAP(Up, UP);
+ MAP(Down, DOWN);
+ MAP(Left, LEFT);
+ MAP(Right, RIGHT);
+ MAP(PageUp, PAGE_UP);
+ MAP(PageDown, PAGE_DOWN);
+ MAP(Shift, SHIFT);
+ MAP(Control, CONTROL);
+ MAP(Meta, META);
+ MAP(Alt, ALT);
+ MAP(AltGr, ALT_GR);
+ MAP(CapsLock, CAPSLOCK);
+ MAP(NumLock, NUMLOCK);
+ MAP(ScrollLock, SCROLLLOCK);
+ MAP(F1, F1);
+ MAP(F2, F2);
+ MAP(F3, F3);
+ MAP(F4, F4);
+ MAP(F5, F5);
+ MAP(F6, F6);
+ MAP(F7, F7);
+ MAP(F8, F8);
+ MAP(F9, F9);
+ MAP(F10, F10);
+ MAP(F11, F11);
+ MAP(F12, F12);
+ MAP(F13, F13);
+ MAP(F14, F14);
+ MAP(F15, F15);
+ MAP(F16, F16);
+ MAP(F17, F17);
+ MAP(F18, F18);
+ MAP(F19, F19);
+ case Qt::Key_Super_L:
+ // Fallthrough
+ case Qt::Key_Super_R:
+ return KC_SUPER;
+ MAP(Space, SPACE);
+ MAP(Exclam, EXCLAMATION_MARK);
+ MAP(QuoteDbl, DOUBLE_QUOTE);
+ MAP(NumberSign, HASHTAG);
+ MAP(Dollar, DOLLAR);
+ MAP(Percent, PERCENT);
+ MAP(Ampersand, AMPERSAND);
+ MAP(Apostrophe, SINGLE_QUOTE);
+ MAP(ParenLeft, OPEN_PARENTHESIS);
+ MAP(ParenRight, CLOSE_PARENTHESIS);
+ MAP(Asterisk, ASTERISK);
+ MAP(Plus, PLUS);
+ MAP(Comma, COMMA);
+ MAP(Minus, MINUS);
+ MAP(Period, PERIOD);
+ MAP(Slash, SLASH);
+ MAP(0, 0);
+ MAP(1, 1);
+ MAP(2, 2);
+ MAP(3, 3);
+ MAP(4, 4);
+ MAP(5, 5);
+ MAP(6, 6);
+ MAP(7, 7);
+ MAP(8, 8);
+ MAP(9, 9);
+ MAP(Colon, COLON);
+ MAP(Semicolon, SEMICOLON);
+ MAP(Less, LESS_THAN);
+ MAP(Equal, EQUALS);
+ MAP(Greater, GREATER_THAN);
+ MAP(Question, QUESTION_MARK);
+ MAP(At, AT_SYMBOL);
+ MAP(A, A);
+ MAP(B, B);
+ MAP(C, C);
+ MAP(D, D);
+ MAP(E, E);
+ MAP(F, F);
+ MAP(G, G);
+ MAP(H, H);
+ MAP(I, I);
+ MAP(J, J);
+ MAP(K, K);
+ MAP(L, L);
+ MAP(M, M);
+ MAP(N, N);
+ MAP(O, O);
+ MAP(P, P);
+ MAP(Q, Q);
+ MAP(R, R);
+ MAP(S, S);
+ MAP(T, T);
+ MAP(U, U);
+ MAP(V, V);
+ MAP(W, W);
+ MAP(X, X);
+ MAP(Y, Y);
+ MAP(Z, Z);
+ MAP(BracketLeft, OPEN_BRACKET);
+ MAP(BracketRight, CLOSE_BRACKET);
+ MAP(Backslash, BACKSLASH);
+ MAP(AsciiCircum, CIRCUMFLEX);
+ MAP(Underscore, UNDERSCORE);
+ MAP(BraceLeft, OPEN_BRACE);
+ MAP(BraceRight, CLOSE_BRACE);
+ MAP(Bar, VERTICAL_BAR);
+ MAP(AsciiTilde, TILDE);
+ MAP(degree, DEGREE_SIGN);
+ }
+
+ return KC_INVALID;
+}
+
+#undef MAP
+
+
+// Implementation of PluginData
+PluginData::PluginData() : overwriteMicrophoneActivation(false) {
+}
+
+PluginData::~PluginData() {
+}
+
+PluginData &PluginData::get() {
+ static PluginData *instance = new PluginData();
+
+ return *instance;
+}
+}; // namespace API
+
+#undef EXIT_WITH
+#undef VERIFY_PLUGIN_ID
+#undef VERIFY_CONNECTION
+#undef ENSURE_CONNECTION_SYNCHRONIZED
+#undef UNUSED