mumble-voip_mumble/src/mumble/API_v_1_x_x.cpp

2169 lines
68 KiB
C++

// Copyright 2022-2023 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 "AudioOutputToken.h"
#include "Channel.h"
#include "ClientUser.h"
#include "Database.h"
#include "Log.h"
#include "MainWindow.h"
#include "MumbleConstants.h"
#include "PluginManager.h"
#include "ServerHandler.h"
#include "Settings.h"
#include "UserModel.h"
#include "Version.h"
#include "Global.h"
#define MUMBLE_PLUGIN_NO_DEFAULT_FUNCTION_DEFINITIONS
#include "MumblePlugin.h"
#undef MUMBLE_PLUGIN_NO_DEFAULT_FUNCTION_DEFINITIONS
#include <QVariant>
#include <QtCore/QHash>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
#include <QtCore/QReadLocker>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <chrono>
#include <cstdint>
#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(MUMBLE_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(MUMBLE_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(MUMBLE_EC_CONNECTION_UNSYNCHRONIZED); \
}
#define UNUSED(var) (void) var;
namespace API {
void APIPromise::set_value(mumble_error_t value) {
m_promise.set_value(value);
}
std::future< mumble_error_t > APIPromise::get_future() {
return m_promise.get_future();
}
APIPromise::lock_guard_t APIPromise::lock() {
return APIPromise::lock_guard_t(m_lock);
}
bool APIPromise::isCancelled() const {
APIPromise::lock_guard_t guard(m_lock);
return m_cancelled;
}
void APIPromise::cancel() {
APIPromise::lock_guard_t guard(m_lock);
m_cancelled = true;
}
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(std::size_t);
REGISTER_METATYPE(uint8_t);
// Define additional types that can't be defined using macro REGISTER_METATYPE
qRegisterMetaType< std::shared_ptr< api_promise_t > >("std::shared_ptr< api_promise_t >");
qRegisterMetaType< std::shared_ptr< API::api_promise_t > >("std::shared_ptr< 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,
std::shared_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(std::shared_ptr< api_promise_t >, promise));
return;
}
api_promise_t::lock_guard_t guard = promise->lock();
if (promise->isCancelled()) {
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(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_EC_POINTER_NOT_FOUND);
}
}
void MumbleAPI::getActiveServerConnection_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t *connection,
std::shared_ptr< 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(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);
if (Global::get().sh) {
*connection = Global::get().sh->getConnectionID();
EXIT_WITH(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_EC_NO_ACTIVE_CONNECTION);
}
}
void MumbleAPI::isConnectionSynchronized_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
bool *synchronized, std::shared_ptr< 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(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);
// 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(MUMBLE_STATUS_OK);
}
void MumbleAPI::getLocalUserID_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
mumble_userid_t *userID, std::shared_ptr< 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(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);
*userID = Global::get().uiSession;
EXIT_WITH(MUMBLE_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, std::shared_ptr< 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(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);
const ClientUser *user = ClientUser::get(userID);
if (user) {
// +1 for NULL terminator
std::size_t size = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_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,
std::shared_ptr< 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(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);
const Channel *channel = Channel::get(static_cast< unsigned int >(channelID));
if (channel) {
// +1 for NULL terminator
std::size_t size = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_EC_CHANNEL_NOT_FOUND);
}
}
void MumbleAPI::getAllUsers_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
mumble_userid_t **users, std::size_t *userCount,
std::shared_ptr< 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(std::size_t *, userCount),
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);
QReadLocker userLock(&ClientUser::c_qrwlUsers);
std::size_t amount = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
}
void MumbleAPI::getAllChannels_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
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, "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(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);
ENSURE_CONNECTION_SYNCHRONIZED(connection);
QReadLocker channelLock(&Channel::c_qrwlChannels);
std::size_t amount = static_cast< std::size_t >(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] = static_cast< mumble_channelid_t >(it.key());
it++;
index++;
}
m_curator.m_entries.insert({ channelIDs, { defaultDeleter, callerID, "getAllChannels" } });
*channels = channelIDs;
*channelCount = amount;
EXIT_WITH(MUMBLE_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,
std::shared_ptr< 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(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);
const ClientUser *user = ClientUser::get(userID);
if (!user) {
EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND);
}
if (user->cChannel) {
*channelID = static_cast< mumble_channelid_t >(user->cChannel->iId);
EXIT_WITH(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_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, std::size_t *userCount,
std::shared_ptr< 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(std::size_t *, userCount), 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);
const Channel *channel = Channel::get(static_cast< unsigned int >(channelID));
if (!channel) {
EXIT_WITH(MUMBLE_EC_CHANNEL_NOT_FOUND);
}
std::size_t amount = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
}
void MumbleAPI::getLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID,
mumble_transmission_mode_t *transmissionMode,
std::shared_ptr< 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(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);
switch (Global::get().s.atTransmit) {
case Settings::AudioTransmit::Continuous:
*transmissionMode = MUMBLE_TM_CONTINOUS;
EXIT_WITH(MUMBLE_STATUS_OK);
case Settings::AudioTransmit::VAD:
*transmissionMode = MUMBLE_TM_VOICE_ACTIVATION;
EXIT_WITH(MUMBLE_STATUS_OK);
case Settings::AudioTransmit::PushToTalk:
*transmissionMode = MUMBLE_TM_PUSH_TO_TALK;
EXIT_WITH(MUMBLE_STATUS_OK);
}
// Unable to resolve transmission mode
EXIT_WITH(MUMBLE_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,
std::shared_ptr< 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(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);
const ClientUser *user = ClientUser::get(userID);
if (!user) {
EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND);
}
*muted = user->bLocalMute;
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::isLocalUserMuted_v_1_0_x(mumble_plugin_id_t callerID, bool *muted,
std::shared_ptr< 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(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);
*muted = Global::get().s.bMute;
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::isLocalUserDeafened_v_1_0_x(mumble_plugin_id_t callerID, bool *deafened,
std::shared_ptr< 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(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);
*deafened = Global::get().s.bDeaf;
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()) {
// 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(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);
const ClientUser *user = ClientUser::get(userID);
if (!user) {
EXIT_WITH(MUMBLE_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
std::size_t size = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
}
void MumbleAPI::getServerHash_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection, const char **hash,
std::shared_ptr< 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(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);
// 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
std::size_t size = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
}
void MumbleAPI::requestLocalUserTransmissionMode_v_1_0_x(mumble_plugin_id_t callerID,
mumble_transmission_mode_t transmissionMode,
std::shared_ptr< 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(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);
Settings::AudioTransmit mode = Settings::PushToTalk;
bool identifiedTransmissionMode = false;
switch (transmissionMode) {
case MUMBLE_TM_CONTINOUS:
mode = Settings::Continuous;
identifiedTransmissionMode = true;
break;
case MUMBLE_TM_VOICE_ACTIVATION:
mode = Settings::VAD;
identifiedTransmissionMode = true;
break;
case MUMBLE_TM_PUSH_TO_TALK:
mode = Settings::PushToTalk;
identifiedTransmissionMode = true;
break;
}
if (identifiedTransmissionMode) {
if (!Global::get().mw) {
EXIT_WITH(MUMBLE_EC_INTERNAL_ERROR);
}
Global::get().mw->setTransmissionMode(mode);
EXIT_WITH(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_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,
std::shared_ptr< 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(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);
ClientUser *user = ClientUser::get(userID);
if (!user) {
EXIT_WITH(MUMBLE_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(MUMBLE_EC_UNSYNCHRONIZED_BLOB);
}
}
// +1 for NULL terminator
std::size_t size = static_cast< std::size_t >(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(MUMBLE_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,
std::shared_ptr< 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(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);
Channel *channel = Channel::get(static_cast< unsigned int >(channelID));
if (!channel) {
EXIT_WITH(MUMBLE_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(MUMBLE_EC_UNSYNCHRONIZED_BLOB);
}
}
// +1 for NULL terminator
std::size_t size = static_cast< std::size_t >(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(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) {
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(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);
const ClientUser *user = ClientUser::get(userID);
if (!user) {
EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND);
}
const Channel *channel = Channel::get(static_cast< unsigned int >(channelID));
if (!channel) {
EXIT_WITH(MUMBLE_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, static_cast< unsigned int >(channel->iId), passwordList);
}
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::requestMicrophoneActivationOverwrite_v_1_0_x(mumble_plugin_id_t callerID, bool activate,
std::shared_ptr< 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(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);
PluginData::get().overwriteMicrophoneActivation.store(activate);
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::requestLocalMute_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
mumble_userid_t userID, bool muted, std::shared_ptr< 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(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);
if (userID == Global::get().uiSession) {
// Can't locally mute the local user
EXIT_WITH(MUMBLE_EC_INVALID_MUTE_TARGET);
}
ClientUser *user = ClientUser::get(userID);
if (!user) {
EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND);
}
user->setLocalMute(muted);
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::requestLocalUserMute_v_1_0_x(mumble_plugin_id_t callerID, bool muted,
std::shared_ptr< 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(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);
if (!Global::get().mw) {
EXIT_WITH(MUMBLE_EC_INTERNAL_ERROR);
}
Global::get().mw->setAudioMute(muted);
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::requestLocalUserDeaf_v_1_0_x(mumble_plugin_id_t callerID, bool deafened,
std::shared_ptr< 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(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);
if (!Global::get().mw) {
EXIT_WITH(MUMBLE_EC_INTERNAL_ERROR);
}
Global::get().mw->setAudioDeaf(deafened);
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::requestSetLocalUserComment_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_t connection,
const char *comment, std::shared_ptr< 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(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);
ClientUser *localUser = ClientUser::get(Global::get().uiSession);
if (!localUser) {
EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND);
}
if (!Global::get().mw || !Global::get().mw->pmModel) {
EXIT_WITH(MUMBLE_EC_INTERNAL_ERROR);
}
Global::get().mw->pmModel->setComment(localUser, QString::fromUtf8(comment));
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) {
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(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);
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(MUMBLE_STATUS_OK);
}
it++;
}
EXIT_WITH(MUMBLE_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,
std::shared_ptr< 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(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);
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 = static_cast< mumble_channelid_t >(it.key());
EXIT_WITH(MUMBLE_STATUS_OK);
}
it++;
}
EXIT_WITH(MUMBLE_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 MUMBLE_SK_AUDIO_INPUT_VOICE_HOLD:
value = static_cast< int >(Global::get().s.iVoiceHold);
break;
case MUMBLE_SK_AUDIO_INPUT_VAD_SILENCE_THRESHOLD:
value = static_cast< double >(Global::get().s.fVADmin);
break;
case MUMBLE_SK_AUDIO_INPUT_VAD_SPEECH_THRESHOLD:
value = static_cast< double >(Global::get().s.fVADmax);
break;
case MUMBLE_SK_AUDIO_OUTPUT_PA_MINIMUM_DISTANCE:
value = static_cast< double >(Global::get().s.fAudioMinDistance);
break;
case MUMBLE_SK_AUDIO_OUTPUT_PA_MAXIMUM_DISTANCE:
value = static_cast< double >(Global::get().s.fAudioMaxDistance);
break;
case MUMBLE_SK_AUDIO_OUTPUT_PA_BLOOM:
value = static_cast< double >(Global::get().s.fAudioBloom);
break;
case MUMBLE_SK_AUDIO_OUTPUT_PA_MINIMUM_VOLUME:
value = static_cast< double >(Global::get().s.fAudioMaxDistVolume);
break;
case MUMBLE_SK_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,
std::shared_ptr< 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(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);
QVariant value = getMumbleSettingHelper(key);
if (!value.isValid()) {
// We also return that for MUMBLE_SK_INVALID
EXIT_WITH(MUMBLE_EC_UNKNOWN_SETTINGS_KEY);
}
if (IS_NOT_TYPE(value, QMetaType::Bool)) {
EXIT_WITH(MUMBLE_EC_WRONG_SETTINGS_TYPE);
}
*outValue = value.toBool();
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::getMumbleSetting_int_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t *outValue,
std::shared_ptr< 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(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);
QVariant value = getMumbleSettingHelper(key);
if (!value.isValid()) {
// We also return that for MUMBLE_SK_INVALID
EXIT_WITH(MUMBLE_EC_UNKNOWN_SETTINGS_KEY);
}
if (IS_NOT_TYPE(value, QMetaType::Int)) {
EXIT_WITH(MUMBLE_EC_WRONG_SETTINGS_TYPE);
}
*outValue = value.toInt();
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::getMumbleSetting_double_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key,
double *outValue, std::shared_ptr< 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(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);
QVariant value = getMumbleSettingHelper(key);
if (!value.isValid()) {
// We also return that for MUMBLE_SK_INVALID
EXIT_WITH(MUMBLE_EC_UNKNOWN_SETTINGS_KEY);
}
if (IS_NOT_TYPE(value, QMetaType::Double)) {
EXIT_WITH(MUMBLE_EC_WRONG_SETTINGS_TYPE);
}
*outValue = value.toDouble();
EXIT_WITH(MUMBLE_STATUS_OK);
}
void MumbleAPI::getMumbleSetting_string_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key,
const char **outValue, std::shared_ptr< 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(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);
QVariant value = getMumbleSettingHelper(key);
if (!value.isValid()) {
// We also return that for MUMBLE_SK_INVALID
EXIT_WITH(MUMBLE_EC_UNKNOWN_SETTINGS_KEY);
}
if (IS_NOT_TYPE(value, QMetaType::QString)) {
EXIT_WITH(MUMBLE_EC_WRONG_SETTINGS_TYPE);
}
const QString stringValue = value.toString();
// +1 for NULL terminator
std::size_t size = static_cast< std::size_t >(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(MUMBLE_STATUS_OK);
}
mumble_error_t setMumbleSettingHelper(mumble_settings_key_t key, QVariant value) {
switch (key) {
case MUMBLE_SK_AUDIO_INPUT_VOICE_HOLD:
if (IS_TYPE(value, QMetaType::Int)) {
Global::get().s.iVoiceHold = value.toInt();
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_AUDIO_INPUT_VAD_SILENCE_THRESHOLD:
if (IS_TYPE(value, QMetaType::Double)) {
Global::get().s.fVADmin = static_cast< float >(value.toDouble());
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_AUDIO_INPUT_VAD_SPEECH_THRESHOLD:
if (IS_TYPE(value, QMetaType::Double)) {
Global::get().s.fVADmax = static_cast< float >(value.toDouble());
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_AUDIO_OUTPUT_PA_MINIMUM_DISTANCE:
if (IS_TYPE(value, QMetaType::Double)) {
Global::get().s.fAudioMinDistance = static_cast< float >(value.toDouble());
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_AUDIO_OUTPUT_PA_MAXIMUM_DISTANCE:
if (IS_TYPE(value, QMetaType::Double)) {
Global::get().s.fAudioMaxDistance = static_cast< float >(value.toDouble());
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_AUDIO_OUTPUT_PA_BLOOM:
if (IS_TYPE(value, QMetaType::Double)) {
Global::get().s.fAudioBloom = static_cast< float >(value.toDouble());
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_AUDIO_OUTPUT_PA_MINIMUM_VOLUME:
if (IS_TYPE(value, QMetaType::Double)) {
Global::get().s.fAudioMaxDistVolume = static_cast< float >(value.toDouble());
return MUMBLE_STATUS_OK;
} else {
return MUMBLE_EC_WRONG_SETTINGS_TYPE;
}
case MUMBLE_SK_INVALID:
// Do nothing
break;
}
return MUMBLE_EC_UNKNOWN_SETTINGS_KEY;
}
void MumbleAPI::setMumbleSetting_bool_v_1_0_x(mumble_plugin_id_t callerID, mumble_settings_key_t key, bool value,
std::shared_ptr< 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(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);
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,
std::shared_ptr< 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(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);
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,
std::shared_ptr< 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(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);
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, std::shared_ptr< 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(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);
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, std::size_t userCount, const uint8_t *data,
std::size_t dataLength, const char *dataID, std::shared_ptr< 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(std::size_t, userCount), Q_ARG(const uint8_t *, data),
Q_ARG(std::size_t, dataLength), Q_ARG(const char *, dataID),
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);
if (dataLength > Mumble::Plugins::PluginMessage::MAX_DATA_LENGTH) {
EXIT_WITH(MUMBLE_EC_DATA_TOO_BIG);
}
if (std::strlen(dataID) > Mumble::Plugins::PluginMessage::MAX_DATA_ID_LENGTH) {
EXIT_WITH(MUMBLE_EC_DATA_ID_TOO_LONG);
}
MumbleProto::PluginDataTransmission mpdt;
mpdt.set_sendersession(Global::get().uiSession);
for (std::size_t i = 0; i < userCount; i++) {
const ClientUser *user = ClientUser::get(users[i]);
if (user) {
mpdt.add_receiversessions(users[i]);
} else {
EXIT_WITH(MUMBLE_EC_USER_NOT_FOUND);
}
}
mpdt.set_data(data, dataLength);
mpdt.set_dataid(dataID);
if (Global::get().sh) {
if (Global::get().sh->m_version < Version::fromComponents(1, 4, 0)) {
// The sendMessage call relies on the server relaying the message to the respective receiver. This
// functionality was added to the server protocol in version 1.4.0, so an older server will not know what to
// do with the received message.
EXIT_WITH(MUMBLE_EC_OPERATION_UNSUPPORTED_BY_SERVER);
}
Global::get().sh->sendMessage(mpdt);
EXIT_WITH(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_EC_CONNECTION_NOT_FOUND);
}
}
void MumbleAPI::log_v_1_0_x(mumble_plugin_id_t callerID, const char *message,
std::shared_ptr< 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(std::shared_ptr< api_promise_t >, promise));
return;
}
api_promise_t::lock_guard_t guard = promise->lock();
if (promise->isCancelled()) {
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(MUMBLE_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(MUMBLE_STATUS_OK);
}
void MumbleAPI::playSample_v_1_0_x(mumble_plugin_id_t callerID, const char *samplePath,
std::shared_ptr< api_promise_t > promise) {
playSample_v_1_2_x(callerID, samplePath, 1.0f, promise);
}
void MumbleAPI::playSample_v_1_2_x(mumble_plugin_id_t callerID, const char *samplePath, float volume,
std::shared_ptr< api_promise_t > promise) {
if (QThread::currentThread() != thread()) {
// Invoke in main thread
QMetaObject::invokeMethod(this, "playSample_v_1_2_x", Qt::QueuedConnection, Q_ARG(mumble_plugin_id_t, callerID),
Q_ARG(const char *, samplePath), Q_ARG(float, volume),
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);
if (!Global::get().ao) {
EXIT_WITH(MUMBLE_EC_AUDIO_NOT_AVAILABLE);
}
if (Global::get().ao->playSample(QString::fromUtf8(samplePath), volume, false)) {
EXIT_WITH(MUMBLE_STATUS_OK);
} else {
EXIT_WITH(MUMBLE_EC_INVALID_SAMPLE);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////// C FUNCTION WRAPPERS FOR USE IN API STRUCT ///////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
#define C_WRAPPER(funcName) \
mumble_error_t MUMBLE_PLUGIN_CALLING_CONVENTION funcName(TYPED_ARGS) { \
auto promise = std::make_shared< api_promise_t >(); \
api_future_t future = promise->get_future(); \
\
MumbleAPI::get().funcName(ARG_NAMES, promise); \
\
if (future.wait_for(std::chrono::milliseconds(800)) != std::future_status::ready) { \
/* The call to cancel may block until the operation is finished, if and only if the operation \
has already started and is thus in progress.*/ \
promise->cancel(); \
\
/* If the cancel-operation above blocked, this means that the operation has now finished in which \
case this will fail and we continue as if nothing had happened. \
If however it did not block the operation will immediately abort once it starts, meaning that the \
check below will succeed. */ \
if (future.wait_for(std::chrono::milliseconds(0)) != std::future_status::ready) { \
promise->set_value(MUMBLE_EC_API_REQUEST_TIMEOUT); \
} \
} \
\
return future.get(); \
}
#define TYPED_ARGS mumble_plugin_id_t callerID, const void *ptr
#define ARG_NAMES callerID, ptr
C_WRAPPER(freeMemory_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t *connection
#define ARG_NAMES callerID, connection
C_WRAPPER(getActiveServerConnection_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t connection, bool *synchronized
#define ARG_NAMES callerID, connection, synchronized
C_WRAPPER(isConnectionSynchronized_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t *userID
#define ARG_NAMES callerID, connection, userID
C_WRAPPER(getLocalUserID_v_1_0_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 **name
#define ARG_NAMES callerID, connection, userID, name
C_WRAPPER(getUserName_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, const char **name
#define ARG_NAMES callerID, connection, channelID, name
C_WRAPPER(getChannelName_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS \
mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t **users, std::size_t *userCount
#define ARG_NAMES callerID, connection, users, userCount
C_WRAPPER(getAllUsers_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 **channels, \
std::size_t *channelCount
#define ARG_NAMES callerID, connection, channels, channelCount
C_WRAPPER(getAllChannels_v_1_0_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 *channel
#define ARG_NAMES callerID, connection, userID, channel
C_WRAPPER(getChannelOfUser_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_userid_t **userList, std::size_t *userCount
#define ARG_NAMES callerID, connection, channelID, userList, userCount
C_WRAPPER(getUsersInChannel_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_transmission_mode_t *transmissionMode
#define ARG_NAMES callerID, transmissionMode
C_WRAPPER(getLocalUserTransmissionMode_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, bool *muted
#define ARG_NAMES callerID, connection, userID, muted
C_WRAPPER(isUserLocallyMuted_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, bool *muted
#define ARG_NAMES callerID, muted
C_WRAPPER(isLocalUserMuted_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, bool *deafened
#define ARG_NAMES callerID, deafened
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_userid_t userID, const char **hash
#define ARG_NAMES callerID, connection, userID, hash
C_WRAPPER(getUserHash_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t connection, const char **hash
#define ARG_NAMES callerID, connection, hash
C_WRAPPER(getServerHash_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_transmission_mode_t transmissionMode
#define ARG_NAMES callerID, transmissionMode
C_WRAPPER(requestLocalUserTransmissionMode_v_1_0_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 **comment
#define ARG_NAMES callerID, connection, userID, comment
C_WRAPPER(getUserComment_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, const char **description
#define ARG_NAMES callerID, connection, channelID, description
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_userid_t userID, mumble_channelid_t channelID, \
const char *password
#define ARG_NAMES callerID, connection, userID, channelID, password
C_WRAPPER(requestUserMove_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, bool activate
#define ARG_NAMES callerID, activate
C_WRAPPER(requestMicrophoneActivationOverwrite_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t userID, bool muted
#define ARG_NAMES callerID, connection, userID, muted
C_WRAPPER(requestLocalMute_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, bool muted
#define ARG_NAMES callerID, muted
C_WRAPPER(requestLocalUserMute_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, bool deafened
#define ARG_NAMES callerID, deafened
C_WRAPPER(requestLocalUserDeaf_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_connection_t connection, const char *comment
#define ARG_NAMES callerID, connection, comment
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, const char *userName, mumble_userid_t *userID
#define ARG_NAMES callerID, connection, userName, userID
C_WRAPPER(findUserByName_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS \
mumble_plugin_id_t callerID, mumble_connection_t connection, const char *channelName, mumble_channelid_t *channelID
#define ARG_NAMES callerID, connection, channelName, channelID
C_WRAPPER(findChannelByName_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, bool *outValue
#define ARG_NAMES callerID, key, outValue
C_WRAPPER(getMumbleSetting_bool_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t *outValue
#define ARG_NAMES callerID, key, outValue
C_WRAPPER(getMumbleSetting_int_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, double *outValue
#define ARG_NAMES callerID, key, outValue
C_WRAPPER(getMumbleSetting_double_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, const char **outValue
#define ARG_NAMES callerID, key, outValue
C_WRAPPER(getMumbleSetting_string_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, bool value
#define ARG_NAMES callerID, key, value
C_WRAPPER(setMumbleSetting_bool_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, int64_t value
#define ARG_NAMES callerID, key, value
C_WRAPPER(setMumbleSetting_int_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, double value
#define ARG_NAMES callerID, key, value
C_WRAPPER(setMumbleSetting_double_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, mumble_settings_key_t key, const char *value
#define ARG_NAMES callerID, key, value
C_WRAPPER(setMumbleSetting_string_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS \
mumble_plugin_id_t callerID, mumble_connection_t connection, const mumble_userid_t *users, std::size_t userCount, \
const uint8_t *data, std::size_t dataLength, const char *dataID
#define ARG_NAMES callerID, connection, users, userCount, data, dataLength, dataID
C_WRAPPER(sendData_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, const char *message
#define ARG_NAMES callerID, message
C_WRAPPER(log_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, const char *samplePath
#define ARG_NAMES callerID, samplePath
C_WRAPPER(playSample_v_1_0_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#define TYPED_ARGS mumble_plugin_id_t callerID, const char *samplePath, float volume
#define ARG_NAMES callerID, samplePath, volume
C_WRAPPER(playSample_v_1_2_x)
#undef TYPED_ARGS
#undef ARG_NAMES
#undef C_WRAPPER
/////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// 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 };
}
MumbleAPI_v_1_2_x getMumbleAPI_v_1_2_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_2_x };
}
#define MAP(qtName, apiName) \
case Qt::Key_##qtName: \
return MUMBLE_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 MUMBLE_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 MUMBLE_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 MUMBLE_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