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/LegacyPlugin.cpp')
-rw-r--r--src/mumble/LegacyPlugin.cpp267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/mumble/LegacyPlugin.cpp b/src/mumble/LegacyPlugin.cpp
new file mode 100644
index 000000000..420f3cf73
--- /dev/null
+++ b/src/mumble/LegacyPlugin.cpp
@@ -0,0 +1,267 @@
+// 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 "LegacyPlugin.h"
+#include "MumblePlugin_v_1_0_x.h"
+
+#include <cstdlib>
+#include <wchar.h>
+#include <map>
+#include <string.h>
+#include <codecvt>
+#include <locale>
+
+#include <QRegularExpression>
+
+
+/// A regular expression used to extract the version from the legacy plugin's description
+static const QRegularExpression versionRegEx(QString::fromLatin1("(?:v)?(?:ersion)?[ \\t]*(\\d+)\\.(\\d+)(?:\\.(\\d+))?"), QRegularExpression::CaseInsensitiveOption);
+
+
+LegacyPlugin::LegacyPlugin(QString path, bool isBuiltIn, QObject *p)
+ : Plugin(path, isBuiltIn, p),
+ m_name(),
+ m_description(),
+ m_version(VERSION_UNKNOWN),
+ m_mumPlug(0),
+ m_mumPlug2(0),
+ m_mumPlugQt(0) {
+}
+
+LegacyPlugin::~LegacyPlugin() {
+}
+
+bool LegacyPlugin::doInitialize() {
+ if (Plugin::doInitialize()) {
+ // initialization seems to have succeeded so far
+ // This means that mumPlug is initialized
+
+ m_name = QString::fromStdWString(m_mumPlug->shortname);
+ // Although the MumblePlugin struct has a member called "description", the actual description seems to
+ // always only be returned by the longdesc function (The description member is actually just the name with some version
+ // info)
+ m_description = QString::fromStdWString(m_mumPlug->longdesc());
+ // The version field in the MumblePlugin2 struct is the positional-audio-plugin-API version and not the version
+ // of the plugin itself. This information is not provided for legacy plugins.
+ // Most of them however provide information about the version of the game they support. Thus we will try to parse the
+ // description and extract this version using it for the plugin's version as well.
+ // Some plugins have the version in the actual description field of the old API (see above comment why these aren't the same)
+ // so we will use a combination of both to search for the version. If multiple version(-like) strings are found, the last one
+ // will be used.
+ QString matchContent = m_description + QChar::Null + QString::fromStdWString(m_mumPlug->description);
+ QRegularExpressionMatchIterator matchIt = versionRegEx.globalMatch(matchContent);
+
+ // Only consider the last match
+ QRegularExpressionMatch match;
+ while (matchIt.hasNext()) {
+ match = matchIt.next();
+ }
+
+ if (match.hasMatch()) {
+ // Store version
+ m_version = { match.captured(1).toInt(), match.captured(2).toInt(), match.captured(3).toInt() };
+ }
+
+ return true;
+ } else {
+ // initialization has failed
+ // pass on info about failed init
+ return false;
+ }
+}
+
+void LegacyPlugin::resolveFunctionPointers() {
+ // We don't set any functions inside the apiFnc struct variable in order for the default
+ // implementations in the Plugin class to mimic empty default implementations for all functions
+ // not explicitly overwritten by this class
+
+ if (isValid()) {
+ // The corresponding library was loaded -> try to locate all API functions of the legacy plugin's spec
+ // (for positional audio) and set defaults for the other ones in order to maintain compatibility with
+ // the new plugin system
+
+ QWriteLocker lock(&m_pluginLock);
+
+ mumblePluginFunc pluginFunc = reinterpret_cast<mumblePluginFunc>(m_lib.resolve("getMumblePlugin"));
+ mumblePlugin2Func plugin2Func = reinterpret_cast<mumblePlugin2Func>(m_lib.resolve("getMumblePlugin2"));
+ mumblePluginQtFunc pluginQtFunc = reinterpret_cast<mumblePluginQtFunc>(m_lib.resolve("getMumblePluginQt"));
+
+ if (pluginFunc) {
+ m_mumPlug = pluginFunc();
+ }
+ if (plugin2Func) {
+ m_mumPlug2 = plugin2Func();
+ }
+ if (pluginQtFunc) {
+ m_mumPlugQt = pluginQtFunc();
+ }
+
+ // A legacy plugin is valid as long as there is a function to get the MumblePlugin struct from it
+ // and the plugin has been compiled by the same compiler as this client (determined by the plugin's
+ // "magic") and it isn't retracted
+ bool suitableMagic = m_mumPlug && m_mumPlug->magic == MUMBLE_PLUGIN_MAGIC;
+ bool retracted = m_mumPlug && m_mumPlug->shortname == L"Retracted";
+ m_pluginIsValid = pluginFunc && suitableMagic && !retracted;
+
+#ifdef MUMBLE_PLUGIN_DEBUG
+ if (!m_pluginIsValid) {
+ if (!pluginFunc) {
+ qDebug("Plugin \"%s\" is missing the getMumblePlugin() function", qPrintable(m_pluginPath));
+ } else if (!suitableMagic) {
+ qDebug("Plugin \"%s\" was compiled with a different compiler (magic differs)", qPrintable(m_pluginPath));
+ } else {
+ qDebug("Plugin \"%s\" is retracted", qPrintable(m_pluginPath));
+ }
+ }
+#endif
+ }
+}
+
+mumble_error_t LegacyPlugin::init() {
+ {
+ QWriteLocker lock(&m_pluginLock);
+
+ m_pluginIsLoaded = true;
+ }
+
+ // No-op as legacy plugins never have anything to initialize
+ // The only init function they care about is the one that inits positional audio
+ return STATUS_OK;
+}
+
+QString LegacyPlugin::getName() const {
+ PluginReadLocker lock(&m_pluginLock);
+
+ if (!m_name.isEmpty()) {
+ return m_name;
+ } else {
+ return QString::fromLatin1("<Unknown Legacy Plugin>");
+ }
+}
+
+QString LegacyPlugin::getDescription() const {
+ PluginReadLocker lock(&m_pluginLock);
+
+ if (!m_description.isEmpty()) {
+ return m_description;
+ } else {
+ return QString::fromLatin1("<No description provided by the legacy plugin>");
+ }
+}
+
+bool LegacyPlugin::showAboutDialog(QWidget *parent) const {
+ if (m_mumPlugQt && m_mumPlugQt->about) {
+ m_mumPlugQt->about(parent);
+
+ return true;
+ }
+ if (m_mumPlug->about) {
+ // the original implementation in Mumble would pass nullptr to the about-function in the mumPlug struct
+ // so we'll mimic that behaviour for compatibility
+ m_mumPlug->about(nullptr);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool LegacyPlugin::showConfigDialog(QWidget *parent) const {
+ if (m_mumPlugQt && m_mumPlugQt->config) {
+ m_mumPlugQt->config(parent);
+
+ return true;
+ }
+ if (m_mumPlug->config) {
+ // the original implementation in Mumble would pass nullptr to the about-function in the mumPlug struct
+ // so we'll mimic that behaviour for compatibility
+ m_mumPlug->config(nullptr);
+
+ return true;
+ }
+
+ return false;
+}
+
+uint8_t LegacyPlugin::initPositionalData(const char *const*programNames, const uint64_t *programPIDs, size_t programCount) {
+ int retCode;
+
+ if (m_mumPlug2) {
+ // Create and populate a multimap holding the names and PIDs to pass to the tryLock-function
+ std::multimap<std::wstring, unsigned long long int> pidMap;
+
+ for (size_t i=0; i<programCount; i++) {
+ std::string currentName = programNames[i];
+ std::wstring currentNameWstr = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(currentName);
+
+ pidMap.insert(std::pair<std::wstring, unsigned long long int>(currentNameWstr, programPIDs[i]));
+ }
+
+ retCode = m_mumPlug2->trylock(pidMap);
+ } else {
+ // The default MumblePlugin doesn't take the name and PID arguments
+ retCode = m_mumPlug->trylock();
+ }
+
+ // ensure that only expected return codes are being returned from this function
+ // the legacy plugins return 1 on successfull locking and 0 on failure
+ if (retCode) {
+ QWriteLocker wLock(&m_pluginLock);
+
+ m_positionalDataIsActive = true;
+
+ return PDEC_OK;
+ } else {
+ // legacy plugins don't have the concept of indicating a permanent error
+ // so we'll return a temporary error for them
+ return PDEC_ERROR_TEMP;
+ }
+}
+
+bool LegacyPlugin::fetchPositionalData(Position3D& avatarPos, Vector3D& avatarDir, Vector3D& avatarAxis, Position3D& cameraPos, Vector3D& cameraDir,
+ Vector3D& cameraAxis, QString& context, QString& identity) const {
+ std::wstring identityWstr;
+ std::string contextStr;
+
+ int retCode = m_mumPlug->fetch(static_cast<float*>(avatarPos), static_cast<float*>(avatarDir), static_cast<float*>(avatarAxis),
+ static_cast<float*>(cameraPos), static_cast<float*>(cameraDir), static_cast<float*>(cameraAxis), contextStr, identityWstr);
+
+ context = QString::fromStdString(contextStr);
+ identity = QString::fromStdWString(identityWstr);
+
+ // The fetch-function should return if it is "still locked on" meaning that it can continue providing
+ // positional audio
+ return retCode == 1;
+}
+
+void LegacyPlugin::shutdownPositionalData() {
+ QWriteLocker lock(&m_pluginLock);
+
+ m_positionalDataIsActive = false;
+
+ m_mumPlug->unlock();
+}
+
+uint32_t LegacyPlugin::getFeatures() const {
+ return FEATURE_POSITIONAL;
+}
+
+mumble_version_t LegacyPlugin::getVersion() const {
+ return m_version;
+}
+
+bool LegacyPlugin::providesAboutDialog() const {
+ return m_mumPlug->about || (m_mumPlugQt && m_mumPlugQt->about);
+}
+
+bool LegacyPlugin::providesConfigDialog() const {
+ return m_mumPlug->config || (m_mumPlugQt && m_mumPlugQt->config);
+}
+
+mumble_version_t LegacyPlugin::getAPIVersion() const {
+ // Legacy plugins are always on most recent API as they don't use it in any case -> no need to perform
+ // backwards compatibility stuff
+ return MUMBLE_PLUGIN_API_VERSION;
+}