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:
authorHartmnt <hartmunt@protonmail.com>2022-08-29 19:13:59 +0300
committerRobert Adam <dev@robert-adam.de>2022-09-09 20:05:23 +0300
commit79a20243c377b5a418694cb36e6d31bf5877adb2 (patch)
treea75c81e7b334d4e47768481cb4b8930ed62257e4
parent0e115aae9d840a20e684abb338474b7e7718278f (diff)
FIX(client, server): Fix patch versions > 255
Previously, the Mumble version was encoded with a uint32 in the network protocol reserving 2 bytes for the major component and 1 byte for each minor and patch. The versioning format was changed to include a build number in the patch field. With a recent update (1.4.274) the patch field exceeded 255 for the first time and broke the protocol version. This commit completely reworks how the version is stored internally and transfered with the network protocol. The new version is a uint64 and consists of 4 fields with 2 bytes each. This allows each version component to reach up to 65535. Furthermore, all instances of integer version types have been replaced with the alias Version::full_t for a better abstraction. Version literals have been replaced by Version::fromComponents calls. Fixes #5827
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/Mumble.proto16
-rw-r--r--src/OSInfo.cpp4
-rw-r--r--src/ProtoUtils.cpp40
-rw-r--r--src/ProtoUtils.h22
-rw-r--r--src/Version.cpp73
-rw-r--r--src/Version.h98
-rw-r--r--src/mumble/ACLEditor.cpp6
-rw-r--r--src/mumble/API_v_1_0_x.cpp2
-rw-r--r--src/mumble/About.cpp2
-rw-r--r--src/mumble/ConnectDialog.cpp4
-rw-r--r--src/mumble/ConnectDialog.h3
-rw-r--r--src/mumble/CrashReporter.cpp4
-rw-r--r--src/mumble/MainWindow.cpp48
-rw-r--r--src/mumble/Messages.cpp18
-rw-r--r--src/mumble/NetworkConfig.cpp9
-rw-r--r--src/mumble/Plugin.cpp4
-rw-r--r--src/mumble/ServerHandler.cpp15
-rw-r--r--src/mumble/ServerHandler.h3
-rw-r--r--src/mumble/UserInformation.cpp12
-rw-r--r--src/mumble/UserInformation.ui118
-rw-r--r--src/mumble/VersionCheck.cpp2
-rw-r--r--src/mumble/VoiceRecorder.cpp5
-rw-r--r--src/mumble/VoiceRecorderDialog.cpp2
-rw-r--r--src/mumble/os_win.cpp3
-rw-r--r--src/murmur/About.cpp2
-rw-r--r--src/murmur/DBus.cpp3
-rw-r--r--src/murmur/DBus.h3
-rw-r--r--src/murmur/Messages.cpp60
-rw-r--r--src/murmur/Meta.cpp7
-rw-r--r--src/murmur/Meta.h7
-rw-r--r--src/murmur/Murmur.ice4
-rw-r--r--src/murmur/MurmurGRPCImpl.cpp7
-rw-r--r--src/murmur/MurmurIce.cpp9
-rw-r--r--src/murmur/MurmurIceWrapper.cpp3
-rw-r--r--src/murmur/RPC.cpp15
-rw-r--r--src/murmur/Server.cpp83
-rw-r--r--src/murmur/Server.h23
-rw-r--r--src/murmur/ServerUser.cpp2
-rw-r--r--src/murmur/ServerUser.h3
-rw-r--r--src/murmur/Tray.cpp2
-rw-r--r--src/murmur/main.cpp8
-rw-r--r--src/tests/Benchmark.cpp2
43 files changed, 483 insertions, 280 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 456288bfe..9b6a0f095 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -63,6 +63,7 @@ set(SHARED_SOURCES
"PlatformCheck.cpp"
"QtUtils.cpp"
"ProcessResolver.cpp"
+ "ProtoUtils.cpp"
"SelfSignedCertificate.cpp"
"ServerAddress.cpp"
"ServerResolver.cpp"
@@ -97,6 +98,7 @@ set(SHARED_HEADERS
"PasswordGenerator.h"
"PlatformCheck.h"
"ProcessResolver.h"
+ "ProtoUtils.h"
"SelfSignedCertificate.h"
"ServerAddress.h"
"ServerResolver.h"
@@ -124,7 +126,10 @@ target_sources(shared
target_compile_definitions(shared
PUBLIC
- "MUMBLE_VERSION=${PROJECT_VERSION}"
+ "MUMBLE_VERSION=${CMAKE_PROJECT_VERSION}"
+ "MUMBLE_VERSION_MAJOR=${CMAKE_PROJECT_VERSION_MAJOR}"
+ "MUMBLE_VERSION_MINOR=${CMAKE_PROJECT_VERSION_MINOR}"
+ "MUMBLE_VERSION_PATCH=${CMAKE_PROJECT_VERSION_PATCH}"
)
target_compile_definitions(shared
diff --git a/src/Mumble.proto b/src/Mumble.proto
index 5132e7011..d23812606 100644
--- a/src/Mumble.proto
+++ b/src/Mumble.proto
@@ -10,8 +10,12 @@ package MumbleProto;
option optimize_for = SPEED;
message Version {
- // 2-byte Major, 1-byte Minor and 1-byte Patch version number.
- optional uint32 version = 1;
+ // Legacy version number format.
+ optional uint32 version_v1 = 1;
+ // New version number format.
+ // Necessary since patch level may exceed 255. (See https://github.com/mumble-voip/mumble/issues/5827)
+ optional uint64 version_v2 = 5;
+
// Client release name.
optional string release = 2;
// Client OS name.
@@ -576,8 +580,12 @@ message ServerConfig {
// Sent by the server to inform the clients of suggested client configuration
// specified by the server administrator.
message SuggestConfig {
- // Suggested client version.
- optional uint32 version = 1;
+ // Suggested client version in the legacy format.
+ optional uint32 version_v1 = 1;
+ // Suggested client version in the new format.
+ // Necessary since patch level may exceed 255. (See https://github.com/mumble-voip/mumble/issues/5827)
+ optional uint64 version_v2 = 4;
+
// True if the administrator suggests positional audio to be used on this
// server.
optional bool positional = 2;
diff --git a/src/OSInfo.cpp b/src/OSInfo.cpp
index 1305036ad..4afb54bcb 100644
--- a/src/OSInfo.cpp
+++ b/src/OSInfo.cpp
@@ -388,12 +388,12 @@ void OSInfo::fillXml(QDomDocument &doc, QDomElement &root, const QList< QHostAdd
tag = doc.createElement(QLatin1String("version"));
root.appendChild(tag);
- t = doc.createTextNode(QLatin1String(MUMTEXT(MUMBLE_VERSION)));
+ t = doc.createTextNode(Version::getRelease());
tag.appendChild(t);
tag = doc.createElement(QLatin1String("release"));
root.appendChild(tag);
- t = doc.createTextNode(QLatin1String(MUMBLE_RELEASE));
+ t = doc.createTextNode(Version::getRelease());
tag.appendChild(t);
tag = doc.createElement(QLatin1String("os"));
diff --git a/src/ProtoUtils.cpp b/src/ProtoUtils.cpp
new file mode 100644
index 000000000..3ee3ba666
--- /dev/null
+++ b/src/ProtoUtils.cpp
@@ -0,0 +1,40 @@
+// Copyright 2022 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 "ProtoUtils.h"
+
+namespace MumbleProto {
+
+::Version::full_t getVersion(const MumbleProto::Version &msg) {
+ if (msg.has_version_v2()) {
+ return static_cast<::Version::full_t >(msg.version_v2());
+ } else if (msg.has_version_v1()) {
+ return ::Version::fromLegacyVersion(msg.version_v1());
+ }
+
+ return ::Version::UNKNOWN;
+}
+
+void setVersion(MumbleProto::Version &msg, const ::Version::full_t version) {
+ msg.set_version_v2(version);
+ msg.set_version_v1(::Version::toLegacyVersion(version));
+}
+
+::Version::full_t getSuggestedVersion(const MumbleProto::SuggestConfig &msg) {
+ if (msg.has_version_v2()) {
+ return static_cast<::Version::full_t >(msg.version_v2());
+ } else if (msg.has_version_v1()) {
+ return ::Version::fromLegacyVersion(msg.version_v1());
+ }
+
+ return ::Version::UNKNOWN;
+}
+
+void setSuggestedVersion(MumbleProto::SuggestConfig &msg, const ::Version::full_t version) {
+ msg.set_version_v2(version);
+ msg.set_version_v1(::Version::toLegacyVersion(version));
+}
+
+}; // namespace MumbleProto
diff --git a/src/ProtoUtils.h b/src/ProtoUtils.h
new file mode 100644
index 000000000..f2013e1bc
--- /dev/null
+++ b/src/ProtoUtils.h
@@ -0,0 +1,22 @@
+// Copyright 2022 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>.
+
+#ifndef MUMBLE_PROTOUTILS_H_
+#define MUMBLE_PROTOUTILS_H_
+
+#include "Mumble.pb.h"
+#include "Version.h"
+
+namespace MumbleProto {
+
+::Version::full_t getVersion(const MumbleProto::Version &msg);
+void setVersion(MumbleProto::Version &msg, const ::Version::full_t version);
+
+::Version::full_t getSuggestedVersion(const MumbleProto::SuggestConfig &msg);
+void setSuggestedVersion(MumbleProto::SuggestConfig &msg, const ::Version::full_t version);
+
+}; // namespace MumbleProto
+
+#endif // MUMBLE_PROTOUTILS_H_
diff --git a/src/Version.cpp b/src/Version.cpp
index 95e9a4c55..3254703e4 100644
--- a/src/Version.cpp
+++ b/src/Version.cpp
@@ -5,35 +5,76 @@
#include "Version.h"
-#include <QtCore/QRegExp>
+#include <QObject>
+#include <QRegExp>
namespace Version {
-unsigned int getRaw(const QString &version) {
- int major, minor, patch;
+QString getRelease() {
+ return MUMBLE_RELEASE;
+}
+
+Version::full_t fromString(const QString &version) {
+ Version::component_t major, minor, patch;
+
+ if (Version::getComponents(major, minor, patch, version)) {
+ return Version::fromComponents(major, minor, patch);
+ }
+
+ return Version::UNKNOWN;
+}
+
+Version::full_t fromConfig(const QVariant &config) {
+ Version::full_t version;
- if (get(&major, &minor, &patch, version))
- return toRaw(major, minor, patch);
+ bool ok = false;
+ std::uint64_t integerValue = config.toULongLong(&ok);
+ if (ok) {
+ if ((integerValue >> Version::OFFSET_MAJOR) != 0) {
+ // We assume this must be the new version format (v2), as a bit
+ // after the 32nd is set.
+ version = static_cast< Version::full_t >(integerValue);
+ } else {
+ version = Version::fromLegacyVersion(static_cast< std::uint32_t >(integerValue));
+ }
+ } else {
+ // The config contains non-numeric characters -> We assume it contains a version string such as "1.5.0".
+ // If this call fails, UNKNOWN is returned.
+ version = Version::fromString(config.toString());
+ }
+
+ if (version == 0) {
+ // 0 is not a valid value for a suggested version
+ version = Version::UNKNOWN;
+ }
- return 0;
+ return version;
}
-QString toString(unsigned int v) {
- int major, minor, patch;
- fromRaw(v, &major, &minor, &patch);
+QString toString(Version::full_t v) {
+ if (v == Version::UNKNOWN) {
+ return QObject::tr("Unknown Version");
+ }
+ Version::component_t major, minor, patch;
+ Version::getComponents(major, minor, patch, v);
return QString::fromLatin1("%1.%2.%3").arg(major).arg(minor).arg(patch);
}
-bool get(int *major, int *minor, int *patch, const QString &version) {
+QString toConfigString(Version::full_t v) {
+ if (v == Version::UNKNOWN) {
+ return QString();
+ }
+ return Version::toString(v);
+}
+
+bool getComponents(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ const QString &version) {
QRegExp rx(QLatin1String("(\\d+)\\.(\\d+)\\.(\\d+)(?:\\.(\\d+))?"));
if (rx.exactMatch(version)) {
- if (major)
- *major = rx.cap(1).toInt();
- if (minor)
- *minor = rx.cap(2).toInt();
- if (patch)
- *patch = rx.cap(3).toInt();
+ major = rx.cap(1).toInt();
+ minor = rx.cap(2).toInt();
+ patch = rx.cap(3).toInt();
return true;
}
diff --git a/src/Version.h b/src/Version.h
index 2980b8fc8..3fcf9e188 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -6,7 +6,11 @@
#ifndef MUMBLE_VERSION_H_
#define MUMBLE_VERSION_H_
-#include <QtCore/QString>
+#include <cstdint>
+#include <limits>
+
+#include <QString>
+#include <QVariant>
#define MUMXTEXT(X) #X
#define MUMTEXT(X) MUMXTEXT(X)
@@ -15,12 +19,94 @@
namespace Version {
-unsigned int getRaw(const QString &version = QLatin1String(MUMTEXT(MUMBLE_VERSION)));
-QString toString(unsigned int version);
-bool get(int *major, int *minor, int *patch, const QString &version = QLatin1String(MUMTEXT(MUMBLE_VERSION)));
+enum class CompareMode { AtLeast, LessThan };
+
+//
+// The mumble version format (v2) is a uint64:
+// major minor patch reserved/unused
+// 0xFFFF 0xFFFF 0xFFFF 0xFFFF
+// (big-endian)
+//
+
+using full_t = std::uint64_t;
+using component_t = std::uint16_t;
+
+constexpr full_t OFFSET_MAJOR = 48;
+constexpr full_t OFFSET_MINOR = 32;
+constexpr full_t OFFSET_PATCH = 16;
+constexpr full_t OFFSET_UNUSED = 0;
+constexpr full_t FIELD_MASK = 0xFFFF;
+constexpr full_t FIELD_MAJOR = (FIELD_MASK << Version::OFFSET_MAJOR);
+constexpr full_t FIELD_MINOR = (FIELD_MASK << Version::OFFSET_MINOR);
+constexpr full_t FIELD_PATCH = (FIELD_MASK << Version::OFFSET_PATCH);
+constexpr full_t FIELD_UNUSED = (FIELD_MASK << Version::OFFSET_UNUSED);
+
+constexpr full_t UNKNOWN = 0;
+
+QString getRelease();
+full_t fromString(const QString &version);
+full_t fromConfig(const QVariant &config);
+QString toString(full_t version);
+QString toConfigString(full_t version);
+bool getComponents(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ const QString &version);
+
+constexpr Version::component_t getMajor(Version::full_t version) {
+ return static_cast< Version::component_t >((version & Version::FIELD_MAJOR) >> Version::OFFSET_MAJOR);
+}
+
+constexpr Version::component_t getMinor(Version::full_t version) {
+ return static_cast< Version::component_t >((version & Version::FIELD_MINOR) >> Version::OFFSET_MINOR);
+}
+
+constexpr Version::component_t getPatch(Version::full_t version) {
+ return static_cast< Version::component_t >((version & Version::FIELD_PATCH) >> Version::OFFSET_PATCH);
+}
+
+constexpr Version::full_t fromComponents(Version::component_t major, Version::component_t minor,
+ Version::component_t patch) {
+ return ((static_cast< full_t >(major) << Version::OFFSET_MAJOR)
+ | (static_cast< full_t >(minor) << Version::OFFSET_MINOR)
+ | (static_cast< full_t >(patch) << Version::OFFSET_PATCH));
+}
+
+constexpr full_t get() {
+ return fromComponents(MUMBLE_VERSION_MAJOR, MUMBLE_VERSION_MINOR, MUMBLE_VERSION_PATCH);
+}
+
+constexpr void getComponents(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ Version::full_t version = get()) {
+ major = Version::getMajor(version);
+ minor = Version::getMinor(version);
+ patch = Version::getPatch(version);
+}
+
+//
+// Legacy versions: These versions are kept around for backward compatibility, but
+// have since been replaced by other version formats.
+//
+// Mumble legacy version format (v1) is a uint32:
+// major minor patch
+// 0xFFFF 0xFF 0xFF
+// (big-endian)
+//
+
+constexpr Version::full_t fromLegacyVersion(std::uint32_t version) {
+ return fromComponents((version & 0xFFFF0000) >> 16, (version & 0xFF00) >> 8, version & 0xFF);
+}
-unsigned int toRaw(int major, int minor, int patch);
-void fromRaw(unsigned int version, int *major, int *minor, int *patch);
+constexpr std::uint32_t toLegacyVersion(Version::full_t version) {
+ // If any of the version components exceeds their allowed value range, they will
+ // be truncated to the highest representable value
+ return ((std::min(static_cast< std::uint32_t >(Version::getMajor(version)),
+ static_cast< std::uint32_t >(std::numeric_limits< std::uint16_t >::max()))
+ << 16)
+ | (std::min(static_cast< std::uint32_t >(Version::getMinor(version)),
+ static_cast< std::uint32_t >(std::numeric_limits< std::uint8_t >::max()))
+ << 8)
+ | std::min(static_cast< std::uint32_t >(Version::getPatch(version)),
+ static_cast< std::uint32_t >(std::numeric_limits< std::uint8_t >::max())));
+}
}; // namespace Version
diff --git a/src/mumble/ACLEditor.cpp b/src/mumble/ACLEditor.cpp
index ba709e372..cdf96a2f4 100644
--- a/src/mumble/ACLEditor.cpp
+++ b/src/mumble/ACLEditor.cpp
@@ -58,7 +58,7 @@ ACLEditor::ACLEditor(int channelparentid, QWidget *p) : QDialog(p) {
qleChannelPassword->hide();
qlChannelPassword->hide();
- if (Global::get().sh->uiVersion >= 0x010300) {
+ if (Global::get().sh->uiVersion >= Version::fromComponents(1, 3, 0)) {
qsbChannelMaxUsers->setRange(0, INT_MAX);
qsbChannelMaxUsers->setValue(0);
qsbChannelMaxUsers->setSpecialValueText(tr("Default server value"));
@@ -124,7 +124,7 @@ ACLEditor::ACLEditor(int channelid, const MumbleProto::ACL &mea, QWidget *p) : Q
qsbChannelPosition->setRange(INT_MIN, INT_MAX);
qsbChannelPosition->setValue(pChannel->iPosition);
- if (Global::get().sh->uiVersion >= 0x010300) {
+ if (Global::get().sh->uiVersion >= Version::fromComponents(1, 3, 0)) {
qsbChannelMaxUsers->setRange(0, INT_MAX);
qsbChannelMaxUsers->setValue(pChannel->uiMaxUsers);
qsbChannelMaxUsers->setSpecialValueText(tr("Default server value"));
@@ -148,7 +148,7 @@ ACLEditor::ACLEditor(int channelid, const MumbleProto::ACL &mea, QWidget *p) : Q
if (!name.isEmpty()) {
// If the server's version is less than 1.4.0 then it won't support the new permissions.
// Skipping this iteration of the loop prevents checkboxes for it being added to the UI.
- if (Global::get().sh->uiVersion < Version::toRaw(1, 4, 0)
+ if (Global::get().sh->uiVersion < Version::fromComponents(1, 4, 0)
&& (perm == ChanACL::ResetUserContent || perm == ChanACL::Listen)) {
continue;
}
diff --git a/src/mumble/API_v_1_0_x.cpp b/src/mumble/API_v_1_0_x.cpp
index dc8477b5b..a796fbc64 100644
--- a/src/mumble/API_v_1_0_x.cpp
+++ b/src/mumble/API_v_1_0_x.cpp
@@ -1561,7 +1561,7 @@ void MumbleAPI::sendData_v_1_0_x(mumble_plugin_id_t callerID, mumble_connection_
mpdt.set_dataid(dataID);
if (Global::get().sh) {
- if (Global::get().sh->uiVersion < Version::toRaw(1, 4, 0)) {
+ if (Global::get().sh->uiVersion < 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.
diff --git a/src/mumble/About.cpp b/src/mumble/About.cpp
index 2abac5852..47087141a 100644
--- a/src/mumble/About.cpp
+++ b/src/mumble/About.cpp
@@ -68,7 +68,7 @@ AboutDialog::AboutDialog(QWidget *p) : QDialog(p) {
"<p>%3</p>"
"<p><b>An Open Source, low-latency, high quality voice-chat utility</b></p>"
"<p><tt><a href=\"%2\">%2</a></tt></p>")
- .arg(QLatin1String(MUMBLE_RELEASE))
+ .arg(Version::getRelease())
.arg(QLatin1String("https://www.mumble.info/"))
.arg(copyrightText));
QHBoxLayout *qhbl = new QHBoxLayout(about);
diff --git a/src/mumble/ConnectDialog.cpp b/src/mumble/ConnectDialog.cpp
index 552887aea..35e00eafe 100644
--- a/src/mumble/ConnectDialog.cpp
+++ b/src/mumble/ConnectDialog.cpp
@@ -1358,7 +1358,7 @@ void ConnectDialog::initList() {
url.setPath(QLatin1String("/v1/list"));
QUrlQuery query;
- query.addQueryItem(QLatin1String("version"), QLatin1String(MUMTEXT(MUMBLE_VERSION)));
+ query.addQueryItem(QLatin1String("version"), Version::getRelease());
url.setQuery(query);
WebFetch::fetch(QLatin1String("publist"), url, this, SLOT(fetched(QByteArray, QUrl, QMap< QString, QString >)));
@@ -1778,7 +1778,7 @@ void ConnectDialog::udpReply() {
quint64 elapsed = tPing.elapsed() - (*ts ^ qhPingRand.value(address));
foreach (ServerItem *si, qhPings.value(address)) {
- si->uiVersion = qFromBigEndian(ping[0]);
+ si->uiVersion = Version::fromLegacyVersion(qFromBigEndian(ping[0]));
quint32 users = qFromBigEndian(ping[3]);
quint32 maxusers = qFromBigEndian(ping[4]);
si->uiBandwidth = qFromBigEndian(ping[5]);
diff --git a/src/mumble/ConnectDialog.h b/src/mumble/ConnectDialog.h
index 278d4ccca..1758a9a0a 100644
--- a/src/mumble/ConnectDialog.h
+++ b/src/mumble/ConnectDialog.h
@@ -30,6 +30,7 @@
#include "ServerAddress.h"
#include "Timer.h"
#include "UnresolvedServerAddress.h"
+#include "Version.h"
struct FavoriteServer;
class QUdpSocket;
@@ -52,7 +53,7 @@ protected:
void init();
public:
- quint32 uiVersion;
+ Version::full_t uiVersion;
quint32 uiPing;
quint32 uiPingSort;
quint32 uiUsers;
diff --git a/src/mumble/CrashReporter.cpp b/src/mumble/CrashReporter.cpp
index c12cbf28e..ace38c622 100644
--- a/src/mumble/CrashReporter.cpp
+++ b/src/mumble/CrashReporter.cpp
@@ -210,8 +210,8 @@ void CrashReporter::run() {
"name=\"os\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n%2 %3\r\n")
.arg(boundary, OSInfo::getOS(), OSInfo::getOSVersion());
QString ver = QString::fromLatin1("--%1\r\nContent-Disposition: form-data; "
- "name=\"ver\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n%2 %3\r\n")
- .arg(boundary, QLatin1String(MUMTEXT(MUMBLE_VERSION)), QLatin1String(MUMBLE_RELEASE));
+ "name=\"ver\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n%2\r\n")
+ .arg(boundary, Version::getRelease());
QString email = QString::fromLatin1("--%1\r\nContent-Disposition: form-data; "
"name=\"email\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n%2\r\n")
.arg(boundary, qleEmail->text());
diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp
index 21022ff64..8ffbb958d 100644
--- a/src/mumble/MainWindow.cpp
+++ b/src/mumble/MainWindow.cpp
@@ -249,7 +249,7 @@ void MainWindow::createActions() {
gsVolumeDown->setObjectName(QLatin1String("VolumeDown"));
qstiIcon = new QSystemTrayIcon(qiIcon, this);
- qstiIcon->setToolTip(tr("Mumble -- %1").arg(QLatin1String(MUMBLE_RELEASE)));
+ qstiIcon->setToolTip(tr("Mumble -- %1").arg(Version::getRelease()));
qstiIcon->setObjectName(QLatin1String("Icon"));
gsWhisper = new GlobalShortcut(this, idx++, tr("Whisper/Shout"), QVariant::fromValue(ShortcutTarget()));
@@ -1052,19 +1052,14 @@ void MainWindow::openUrl(const QUrl &url) {
return;
}
- int major, minor, patch;
- int thismajor, thisminor, thispatch;
- Version::get(&thismajor, &thisminor, &thispatch);
-
- // With no version parameter given assume the link refers to our version
- major = thismajor;
- minor = thisminor;
- patch = thispatch;
+ Version::full_t thisVersion = Version::get();
+ Version::full_t targetVersion = Version::UNKNOWN;
QUrlQuery query(url);
QString version = query.queryItemValue(QLatin1String("version"));
if (version.size() > 0) {
- if (!Version::get(&major, &minor, &patch, version)) {
+ targetVersion = Version::fromString(version);
+ if (targetVersion == Version::UNKNOWN) {
// The version format is invalid
Global::get().l->log(Log::Warning,
QObject::tr("The provided URL uses an invalid version format: \"%1\"").arg(version));
@@ -1072,21 +1067,20 @@ void MainWindow::openUrl(const QUrl &url) {
}
}
+ // With no version parameter given assume the link refers to our version
+ if (targetVersion == Version::UNKNOWN) {
+ targetVersion = thisVersion;
+ }
+
// We can't handle URLs for versions < 1.2.0
- const int minMajor = 1;
- const int minMinor = 2;
- const int minPatch = 0;
- const bool isPre_120 = major < minMajor || (major == minMajor && minor < minMinor)
- || (major == minMajor && minor == minMinor && patch < minPatch);
+ const bool isPre_120 = targetVersion < Version::fromComponents(1, 2, 0);
// We also can't handle URLs for versions newer than the running Mumble instance
- const bool isFuture = major > thismajor || (major == thismajor && minor > thisminor)
- || (major == thismajor && minor == thisminor && patch > thispatch);
+ const bool isFuture = thisVersion < targetVersion;
if (isPre_120 || isFuture) {
- Global::get().l->log(Log::Warning, tr("This version of Mumble can't handle URLs for Mumble version %1.%2.%3")
- .arg(major)
- .arg(minor)
- .arg(patch));
+ Global::get().l->log(
+ Log::Warning,
+ tr("This version of Mumble can't handle URLs for Mumble version %1").arg(Version::toString(targetVersion)));
return;
}
@@ -1385,7 +1379,7 @@ void MainWindow::on_qmSelf_aboutToShow() {
qaSelfRegister->setEnabled(user && (user->iId < 0) && !user->qsHash.isEmpty()
&& (Global::get().pPermissions & (ChanACL::SelfRegister | ChanACL::Write)));
- if (Global::get().sh && Global::get().sh->uiVersion >= 0x010203) {
+ if (Global::get().sh && Global::get().sh->uiVersion >= Version::fromComponents(1, 2, 3)) {
qaSelfPrioritySpeaker->setEnabled(user && Global::get().pPermissions & (ChanACL::Write | ChanACL::MuteDeafen));
qaSelfPrioritySpeaker->setChecked(user && user->bPrioritySpeaker);
} else {
@@ -1581,7 +1575,7 @@ void MainWindow::qmUser_aboutToShow() {
qmUser->addAction(qaUserBan);
qmUser->addAction(qaUserMute);
qmUser->addAction(qaUserDeaf);
- if (Global::get().sh && Global::get().sh->uiVersion >= 0x010203)
+ if (Global::get().sh && Global::get().sh->uiVersion >= Version::fromComponents(1, 2, 3))
qmUser->addAction(qaUserPrioritySpeaker);
qmUser->addAction(qaUserLocalMute);
qmUser->addAction(qaUserLocalIgnore);
@@ -1599,7 +1593,7 @@ void MainWindow::qmUser_aboutToShow() {
}
qmUser->addAction(qaUserTextMessage);
- if (Global::get().sh && Global::get().sh->uiVersion >= 0x010202)
+ if (Global::get().sh && Global::get().sh->uiVersion >= Version::fromComponents(1, 2, 2))
qmUser->addAction(qaUserInformation);
if (p && (p->iId < 0) && !p->qsHash.isEmpty()
@@ -1664,7 +1658,7 @@ void MainWindow::qmUser_aboutToShow() {
qaUserLocalIgnoreTTS->setEnabled(!isSelf);
// If the server's version is less than 1.4.0 it won't support the new permission to reset a comment/avatar, so
// fall back to the old method
- if (Global::get().sh->uiVersion < 0x010400) {
+ if (Global::get().sh->uiVersion < Version::fromComponents(1, 4, 0)) {
qaUserCommentReset->setEnabled(!p->qbaCommentHash.isEmpty()
&& (Global::get().pPermissions & (ChanACL::Move | ChanACL::Write)));
qaUserTextureReset->setEnabled(!p->qbaTextureHash.isEmpty()
@@ -2132,7 +2126,7 @@ void MainWindow::qmChannel_aboutToShow() {
qmChannel->addSeparator();
}
- if (c && Global::get().sh && Global::get().sh->uiVersion >= 0x010400) {
+ if (c && Global::get().sh && Global::get().sh->uiVersion >= Version::fromComponents(1, 4, 0)) {
// If the server's version is less than 1.4, the listening feature is not supported yet
// and thus it doesn't make sense to show the action for it
qmChannel->addAction(qaChannelListen);
@@ -3385,7 +3379,7 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re
}
}
}
- qstiIcon->setToolTip(tr("Mumble -- %1").arg(QLatin1String(MUMBLE_RELEASE)));
+ qstiIcon->setToolTip(tr("Mumble -- %1").arg(Version::getRelease()));
AudioInput::setMaxBandwidth(-1);
}
diff --git a/src/mumble/Messages.cpp b/src/mumble/Messages.cpp
index c49a1739b..d39a6cc5f 100644
--- a/src/mumble/Messages.cpp
+++ b/src/mumble/Messages.cpp
@@ -25,6 +25,7 @@
#endif
#include "ChannelListenerManager.h"
#include "PluginManager.h"
+#include "ProtoUtils.h"
#include "ServerHandler.h"
#include "TalkingUI.h"
#include "User.h"
@@ -1153,8 +1154,8 @@ void MainWindow::removeContextAction(const MumbleProto::ContextActionModify &msg
///
/// @param msg The message object with the respective information
void MainWindow::msgVersion(const MumbleProto::Version &msg) {
- if (msg.has_version())
- Global::get().sh->uiVersion = msg.version();
+ Global::get().sh->uiVersion = MumbleProto::getVersion(msg);
+
if (msg.has_release())
Global::get().sh->qsRelease = u8(msg.release());
if (msg.has_os()) {
@@ -1232,7 +1233,8 @@ void MainWindow::msgCodecVersion(const MumbleProto::CodecVersion &msg) {
#endif
// Workaround for broken 1.2.2 servers
- if (Global::get().sh && Global::get().sh->uiVersion == 0x010202 && alpha != -1 && alpha == beta) {
+ if (Global::get().sh && Global::get().sh->uiVersion == Version::fromComponents(1, 2, 2) && alpha != -1
+ && alpha == beta) {
if (pref)
beta = Global::get().iCodecBeta;
else
@@ -1299,9 +1301,13 @@ void MainWindow::msgRequestBlob(const MumbleProto::RequestBlob &) {
///
/// @param msg The message object containing the suggestions
void MainWindow::msgSuggestConfig(const MumbleProto::SuggestConfig &msg) {
- if (msg.has_version() && (msg.version() > Version::getRaw())) {
- Global::get().l->log(Log::Warning,
- tr("The server requests minimum client version %1").arg(Version::toString(msg.version())));
+ Version::full_t requestedVersion = MumbleProto::getSuggestedVersion(msg);
+ if (requestedVersion <= Version::get()) {
+ requestedVersion = Version::UNKNOWN;
+ }
+ if (requestedVersion != Version::UNKNOWN) {
+ Global::get().l->log(
+ Log::Warning, tr("The server requests minimum client version %1").arg(Version::toString(requestedVersion)));
}
if (msg.has_positional() && (msg.positional() != Global::get().s.doPositionalAudio())) {
if (msg.positional())
diff --git a/src/mumble/NetworkConfig.cpp b/src/mumble/NetworkConfig.cpp
index 674caedb1..e3dfe4353 100644
--- a/src/mumble/NetworkConfig.cpp
+++ b/src/mumble/NetworkConfig.cpp
@@ -190,14 +190,11 @@ void Network::prepareRequest(QNetworkRequest &req) {
// Do not send OS information if the corresponding privacy setting is enabled
if (Global::get().s.bHideOS) {
req.setRawHeader(QString::fromLatin1("User-Agent").toUtf8(),
- QString::fromLatin1("Mozilla/5.0 Mumble/%1 %2")
- .arg(QLatin1String(MUMTEXT(MUMBLE_VERSION)), QLatin1String(MUMBLE_RELEASE))
- .toUtf8());
+ QString::fromLatin1("Mozilla/5.0 Mumble/%1").arg(Version::getRelease()).toUtf8());
} else {
req.setRawHeader(QString::fromLatin1("User-Agent").toUtf8(),
- QString::fromLatin1("Mozilla/5.0 (%1; %2) Mumble/%3 %4")
- .arg(OSInfo::getOS(), OSInfo::getOSVersion(), QLatin1String(MUMTEXT(MUMBLE_VERSION)),
- QLatin1String(MUMBLE_RELEASE))
+ QString::fromLatin1("Mozilla/5.0 (%1; %2) Mumble/%3")
+ .arg(OSInfo::getOS(), OSInfo::getOSVersion(), Version::getRelease())
.toUtf8());
}
}
diff --git a/src/mumble/Plugin.cpp b/src/mumble/Plugin.cpp
index 5c5b1cab1..cd8b2b396 100644
--- a/src/mumble/Plugin.cpp
+++ b/src/mumble/Plugin.cpp
@@ -312,8 +312,8 @@ mumble_error_t Plugin::init() {
// Step 1: Introduce ourselves (inform the plugin about Mumble's (API) version
// Get Mumble version
- int mumbleMajor, mumbleMinor, mumblePatch;
- Version::get(&mumbleMajor, &mumbleMinor, &mumblePatch);
+ Version::component_t mumbleMajor, mumbleMinor, mumblePatch;
+ Version::getComponents(mumbleMajor, mumbleMinor, mumblePatch);
// Require API version 1.0.0 as the minimal supported one
setMumbleInfo({ mumbleMajor, mumbleMinor, mumblePatch }, MUMBLE_PLUGIN_API_VERSION, { 1, 0, 0 });
diff --git a/src/mumble/ServerHandler.cpp b/src/mumble/ServerHandler.cpp
index 8fd5486c4..a77f2abfa 100644
--- a/src/mumble/ServerHandler.cpp
+++ b/src/mumble/ServerHandler.cpp
@@ -24,6 +24,7 @@
#include "NetworkConfig.h"
#include "OSInfo.h"
#include "PacketDataStream.h"
+#include "ProtoUtils.h"
#include "RichTextEditor.h"
#include "SSL.h"
#include "ServerResolver.h"
@@ -112,7 +113,7 @@ ServerHandler::ServerHandler() : database(new Database(QLatin1String("ServerHand
usPort = 0;
bUdp = true;
tConnectionTimeoutTimer = nullptr;
- uiVersion = 0;
+ uiVersion = Version::UNKNOWN;
iInFlightTCPPings = 0;
// assign connection ID
@@ -452,7 +453,7 @@ void ServerHandler::run() {
accUDP = accTCP = accClean;
- uiVersion = 0;
+ uiVersion = Version::UNKNOWN;
qsRelease = QString();
qsOS = QString();
qsOSVersion = QString();
@@ -771,12 +772,8 @@ void ServerHandler::serverConnectionConnected() {
}
MumbleProto::Version mpv;
- mpv.set_release(u8(QLatin1String(MUMBLE_RELEASE)));
-
- unsigned int version = Version::getRaw();
- if (version) {
- mpv.set_version(version);
- }
+ mpv.set_release(u8(Version::getRelease()));
+ MumbleProto::setVersion(mpv, Version::get());
if (!Global::get().s.bHideOS) {
mpv.set_os(u8(OSInfo::getOS()));
@@ -1032,7 +1029,7 @@ void ServerHandler::setUserComment(unsigned int uiSession, const QString &commen
void ServerHandler::setUserTexture(unsigned int uiSession, const QByteArray &qba) {
QByteArray texture;
- if ((uiVersion >= 0x010202) || qba.isEmpty()) {
+ if ((uiVersion >= Version::fromComponents(1, 2, 2)) || qba.isEmpty()) {
texture = qba;
} else {
QByteArray raw = qba;
diff --git a/src/mumble/ServerHandler.h b/src/mumble/ServerHandler.h
index 6790c09b3..869033624 100644
--- a/src/mumble/ServerHandler.h
+++ b/src/mumble/ServerHandler.h
@@ -36,6 +36,7 @@
#include "Mumble.pb.h"
#include "ServerAddress.h"
#include "Timer.h"
+#include "Version.h"
class Connection;
class Database;
@@ -106,7 +107,7 @@ public:
QHash< ServerAddress, QString > qhHostnames;
ServerAddress saTargetServer;
- unsigned int uiVersion;
+ Version::full_t uiVersion;
QString qsRelease;
QString qsOS;
QString qsOSVersion;
diff --git a/src/mumble/UserInformation.cpp b/src/mumble/UserInformation.cpp
index a8395e798..5eb9aa182 100644
--- a/src/mumble/UserInformation.cpp
+++ b/src/mumble/UserInformation.cpp
@@ -8,6 +8,7 @@
#include "Audio.h"
#include "CELTCodec.h"
#include "HostAddress.h"
+#include "ProtoUtils.h"
#include "QtUtils.h"
#include "ServerHandler.h"
#include "ViewCert.h"
@@ -128,9 +129,16 @@ void UserInformation::update(const MumbleProto::UserStats &msg) {
showcon = true;
const MumbleProto::Version &mpv = msg.version();
-
- qlVersion->setText(tr("%1 (%2)").arg(Version::toString(mpv.version())).arg(u8(mpv.release())));
+ Version::full_t version = MumbleProto::getVersion(mpv);
+ qlVersion->setText(tr("%1 (%2)").arg(Version::toString(version)).arg(u8(mpv.release())));
qlOS->setText(tr("%1 (%2)").arg(u8(mpv.os())).arg(u8(mpv.os_version())));
+
+ if (Version::getPatch(version) == 255) {
+ // The patch level 255 might indicate that the server is incapable of parsing
+ // the new version format (or the patch level is actually exactly 255).
+ // Show a warning to the user just in case.
+ qlVersionNote->show();
+ }
}
if (msg.celt_versions_size() > 0) {
QStringList qsl;
diff --git a/src/mumble/UserInformation.ui b/src/mumble/UserInformation.ui
index d08f4b8f7..dbb0d53b9 100644
--- a/src/mumble/UserInformation.ui
+++ b/src/mumble/UserInformation.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>379</width>
- <height>401</height>
+ <width>488</width>
+ <height>658</height>
</rect>
</property>
<property name="windowTitle">
@@ -20,17 +20,10 @@
<string>Connection Information</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="0" column="0">
- <widget class="QLabel" name="qliVersion">
- <property name="text">
- <string>Version</string>
- </property>
- </widget>
- </item>
- <item row="0" column="1" colspan="2">
- <widget class="QLabel" name="qlVersion">
+ <item row="4" column="1">
+ <widget class="QLabel" name="qlCertificate">
<property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -46,14 +39,14 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="qliOS">
<property name="text">
<string>OS</string>
</property>
</widget>
</item>
- <item row="1" column="1" colspan="2">
+ <item row="2" column="1" colspan="2">
<widget class="QLabel" name="qlOS">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -72,17 +65,24 @@
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="qliCertificate">
<property name="text">
<string>Certificate</string>
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QLabel" name="qlCertificate">
+ <item row="0" column="0">
+ <widget class="QLabel" name="qliVersion">
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1" colspan="2">
+ <widget class="QLabel" name="qlCELT">
<property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -90,46 +90,34 @@
<property name="text">
<string/>
</property>
- <property name="textFormat">
- <enum>Qt::PlainText</enum>
- </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QLabel" name="qliAddress">
+ <item row="7" column="0">
+ <widget class="QLabel" name="qliOpus">
<property name="text">
- <string>IP Address</string>
+ <string notr="true">Opus</string>
</property>
</widget>
</item>
- <item row="4" column="1" colspan="2">
- <widget class="QLabel" name="qlAddress">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
- <horstretch>1</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
+ <item row="6" column="0">
+ <widget class="QLabel" name="qliCELT">
<property name="text">
- <string/>
- </property>
- <property name="textInteractionFlags">
- <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ <string>CELT Versions</string>
</property>
</widget>
</item>
- <item row="5" column="0">
- <widget class="QLabel" name="qliCELT">
+ <item row="7" column="1" colspan="2">
+ <widget class="QLabel" name="qlOpus">
<property name="text">
- <string>CELT Versions</string>
+ <string/>
</property>
</widget>
</item>
- <item row="5" column="1" colspan="2">
- <widget class="QLabel" name="qlCELT">
+ <item row="0" column="1" colspan="2">
+ <widget class="QLabel" name="qlVersion">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
@@ -139,12 +127,22 @@
<property name="text">
<string/>
</property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
- <item row="3" column="2">
+ <item row="5" column="0">
+ <widget class="QLabel" name="qliAddress">
+ <property name="text">
+ <string>IP Address</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="2">
<widget class="QPushButton" name="qpbCertificate">
<property name="enabled">
<bool>false</bool>
@@ -166,17 +164,41 @@
</property>
</widget>
</item>
- <item row="6" column="0">
- <widget class="QLabel" name="qliOpus">
+ <item row="5" column="1" colspan="2">
+ <widget class="QLabel" name="qlAddress">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="text">
- <string notr="true">Opus</string>
+ <string/>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
- <item row="6" column="1" colspan="2">
- <widget class="QLabel" name="qlOpus">
+ <item row="1" column="0" colspan="3">
+ <widget class="QLabel" name="qlVersionNote">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="visible">
+ <bool>false</bool>
+ </property>
<property name="text">
- <string/>
+ <string>Warning: The server seems to report a truncated protocol version for this client. (See: &lt;a href=&quot;https://github.com/mumble-voip/mumble/issues/5827/&quot;&gt;Issue #5827&lt;/a&gt;)</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
</property>
</widget>
</item>
diff --git a/src/mumble/VersionCheck.cpp b/src/mumble/VersionCheck.cpp
index 123665e57..aca7333c1 100644
--- a/src/mumble/VersionCheck.cpp
+++ b/src/mumble/VersionCheck.cpp
@@ -33,7 +33,7 @@ VersionCheck::VersionCheck(bool autocheck, QObject *p, bool focus) : QObject(p),
QList< QPair< QString, QString > > queryItems;
queryItems << qMakePair(QString::fromLatin1("ver"),
- QString::fromLatin1(QUrl::toPercentEncoding(QLatin1String(MUMBLE_RELEASE))));
+ QString::fromLatin1(QUrl::toPercentEncoding(Version::getRelease())));
#if defined(Q_OS_WIN)
# if defined(Q_OS_WIN64)
queryItems << qMakePair(QString::fromLatin1("os"), QString::fromLatin1("WinX64"));
diff --git a/src/mumble/VoiceRecorder.cpp b/src/mumble/VoiceRecorder.cpp
index bba6bf34b..ffd686a20 100644
--- a/src/mumble/VoiceRecorder.cpp
+++ b/src/mumble/VoiceRecorder.cpp
@@ -280,7 +280,7 @@ bool VoiceRecorder::ensureFileIsOpenedFor(SF_INFO &soundFileInfo, boost::shared_
void VoiceRecorder::run() {
Q_ASSERT(!m_recording);
- if (Global::get().sh && Global::get().sh->uiVersion < 0x010203)
+ if (Global::get().sh && Global::get().sh->uiVersion < Version::fromComponents(1, 2, 3))
return;
SF_INFO soundFileInfo = createSoundFileInfo();
@@ -293,7 +293,8 @@ void VoiceRecorder::run() {
m_sleepLock.lock();
m_sleepCondition.wait(&m_sleepLock);
- if (!m_recording || m_abort || (Global::get().sh && Global::get().sh->uiVersion < 0x010203)) {
+ if (!m_recording || m_abort
+ || (Global::get().sh && Global::get().sh->uiVersion < Version::fromComponents(1, 2, 3))) {
m_sleepLock.unlock();
break;
}
diff --git a/src/mumble/VoiceRecorderDialog.cpp b/src/mumble/VoiceRecorderDialog.cpp
index bca3d5ee5..77039f68a 100644
--- a/src/mumble/VoiceRecorderDialog.cpp
+++ b/src/mumble/VoiceRecorderDialog.cpp
@@ -113,7 +113,7 @@ void VoiceRecorderDialog::on_qpbStart_clicked() {
return;
}
- if (Global::get().sh->uiVersion < 0x010203) {
+ if (Global::get().sh->uiVersion < Version::fromComponents(1, 2, 3)) {
QMessageBox::critical(this, tr("Recorder"),
tr("The server you are currently connected to is version 1.2.2 or older. "
"For privacy reasons, recording on servers of versions older than 1.2.3 "
diff --git a/src/mumble/os_win.cpp b/src/mumble/os_win.cpp
index 0e5ac74de..6911eacd7 100644
--- a/src/mumble/os_win.cpp
+++ b/src/mumble/os_win.cpp
@@ -278,8 +278,7 @@ void os_init() {
}
}
- QString comment = QString::fromLatin1("%1\n%2\n%3")
- .arg(QString::fromLatin1(MUMBLE_RELEASE), QString::fromLatin1(MUMTEXT(MUMBLE_VERSION)), hash);
+ QString comment = QString::fromLatin1("%1\n%2").arg(Version::getRelease(), hash);
wcscpy_s(wcComment, DUMP_BUFFER_SIZE, comment.toStdWString().c_str());
musComment.Type = CommentStreamW;
diff --git a/src/murmur/About.cpp b/src/murmur/About.cpp
index 8e0a07b63..88f17d622 100644
--- a/src/murmur/About.cpp
+++ b/src/murmur/About.cpp
@@ -56,7 +56,7 @@ AboutDialog::AboutDialog(QWidget *p, AboutDialogOptions options) : QDialog(p) {
text->setText(tr("<h3>Murmur (%1)</h3>"
"<p>%3</p>"
"<p><tt><a href=\"%2\">%2</a></tt></p>")
- .arg(QLatin1String(MUMBLE_RELEASE))
+ .arg(Version::getRelease())
.arg(QLatin1String("http://www.mumble.info/"))
.arg(QLatin1String("Copyright 2005-2020 The Mumble Developers")));
QHBoxLayout *qhbl = new QHBoxLayout(about);
diff --git a/src/murmur/DBus.cpp b/src/murmur/DBus.cpp
index 7b70de3e0..56dec1bbe 100644
--- a/src/murmur/DBus.cpp
+++ b/src/murmur/DBus.cpp
@@ -938,7 +938,8 @@ void MetaDBus::quit() {
QCoreApplication::instance()->quit();
}
-void MetaDBus::getVersion(int &major, int &minor, int &patch, QString &text) {
+void MetaDBus::getVersion(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ QString &text) {
Meta::getVersion(major, minor, patch, text);
}
diff --git a/src/murmur/DBus.h b/src/murmur/DBus.h
index aa6147fc5..03c43ce0f 100644
--- a/src/murmur/DBus.h
+++ b/src/murmur/DBus.h
@@ -231,7 +231,8 @@ public slots:
void setConf(int server_id, const QString &key, const QString &value, const QDBusMessage &);
void setSuperUserPassword(int server_id, const QString &pw, const QDBusMessage &);
void getLog(int server_id, int min_offset, int max_offset, const QDBusMessage &, QList< LogEntry > &entries);
- void getVersion(int &major, int &minor, int &patch, QString &string);
+ void getVersion(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ QString &string);
void quit();
signals:
void started(int server_id);
diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp
index ca47f52a2..1fb33db3f 100644
--- a/src/murmur/Messages.cpp
+++ b/src/murmur/Messages.cpp
@@ -10,6 +10,7 @@
#include "Message.h"
#include "Meta.h"
#include "MumbleConstants.h"
+#include "ProtoUtils.h"
#include "Server.h"
#include "ServerDB.h"
#include "ServerUser.h"
@@ -354,7 +355,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
mpcs.set_position(c->iPosition);
- if ((uSource->uiVersion >= 0x010202) && !c->qbaDescHash.isEmpty())
+ if ((uSource->uiVersion >= Version::fromComponents(1, 2, 2)) && !c->qbaDescHash.isEmpty())
mpcs.set_description_hash(blob(c->qbaDescHash));
else if (!c->qsDesc.isEmpty())
mpcs.set_description(u8(c->qsDesc));
@@ -419,7 +420,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
if (uSource->cChannel->iId != 0)
mpus.set_channel_id(uSource->cChannel->iId);
- sendAll(mpus, 0x010202);
+ sendAll(mpus, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
if ((uSource->qbaTexture.length() >= 4)
&& (qFromBigEndian< unsigned int >(reinterpret_cast< const unsigned char * >(uSource->qbaTexture.constData()))
@@ -427,7 +428,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
mpus.set_texture(blob(uSource->qbaTexture));
if (!uSource->qsComment.isEmpty())
mpus.set_comment(u8(uSource->qsComment));
- sendAll(mpus, ~0x010202);
+ sendAll(mpus, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
// Transmit other users profiles
foreach (ServerUser *u, qhUsers) {
@@ -442,7 +443,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
mpus.set_name(u8(u->qsName));
if (u->iId >= 0)
mpus.set_user_id(u->iId);
- if (uSource->uiVersion >= 0x010202) {
+ if (uSource->uiVersion >= Version::fromComponents(1, 2, 2)) {
if (!u->qbaTextureHash.isEmpty())
mpus.set_texture_hash(blob(u->qbaTextureHash));
else if (!u->qbaTexture.isEmpty())
@@ -469,7 +470,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
mpus.set_self_deaf(true);
else if (u->bSelfMute)
mpus.set_self_mute(true);
- if ((uSource->uiVersion >= 0x010202) && !u->qbaCommentHash.isEmpty())
+ if ((uSource->uiVersion >= Version::fromComponents(1, 2, 2)) && !u->qbaCommentHash.isEmpty())
mpus.set_comment_hash(blob(u->qbaCommentHash));
else if (!u->qsComment.isEmpty())
mpus.set_comment(u8(u->qsComment));
@@ -508,8 +509,9 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
sendMessage(uSource, mpsc);
MumbleProto::SuggestConfig mpsug;
- if (!qvSuggestVersion.isNull())
- mpsug.set_version(qvSuggestVersion.toUInt());
+ if (m_suggestVersion != Version::UNKNOWN) {
+ MumbleProto::setSuggestedVersion(mpsug, m_suggestVersion);
+ }
if (!qvSuggestPositional.isNull())
mpsug.set_positional(qvSuggestPositional.toBool());
if (!qvSuggestPushToTalk.isNull())
@@ -523,7 +525,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
sendMessage(uSource, mpsug);
}
- if (uSource->uiVersion < 0x010400 && Meta::mp.iMaxListenersPerChannel != 0
+ if (uSource->uiVersion < Version::fromComponents(1, 4, 0) && Meta::mp.iMaxListenersPerChannel != 0
&& Meta::mp.iMaxListenerProxiesPerUser != 0) {
// The server has the ChannelListener feature enabled but the client that connects doesn't have version 1.4.0 or
// newer meaning that this client doesn't know what ChannelListeners are. Thus we'll send that user a
@@ -686,7 +688,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
return;
}
if (isChannelFull(c, uSource)) {
- PERM_DENIED_FALLBACK(ChannelFull, 0x010201, QLatin1String("Channel is full"));
+ PERM_DENIED_FALLBACK(ChannelFull, Version::fromComponents(1, 2, 1), QLatin1String("Channel is full"));
return;
}
}
@@ -709,7 +711,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
if (Meta::mp.iMaxListenersPerChannel >= 0
&& Meta::mp.iMaxListenersPerChannel - m_channelListenerManager.getListenerCountForChannel(c->iId) - 1 < 0) {
// A limit for the amount of listener proxies per channel is set and it has been reached already
- PERM_DENIED_FALLBACK(ChannelListenerLimit, 0x010400,
+ PERM_DENIED_FALLBACK(ChannelListenerLimit, Version::fromComponents(1, 4, 0),
QLatin1String("No more listeners allowed in this channel"));
continue;
}
@@ -720,7 +722,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
- passedChannelListener - 1
< 0) {
// A limit for the amount of listener proxies per user is set and it has been reached already
- PERM_DENIED_FALLBACK(UserListenerLimit, 0x010400,
+ PERM_DENIED_FALLBACK(UserListenerLimit, Version::fromComponents(1, 4, 0),
QLatin1String("No more listeners allowed in this channel"));
continue;
}
@@ -919,7 +921,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
else
mptm.set_message(u8(QString(QLatin1String("User '%1' stopped recording")).arg(pDstServerUser->qsName)));
- sendAll(mptm, ~0x010203);
+ sendAll(mptm, Version::fromComponents(1, 2, 3), Version::CompareMode::LessThan);
bBroadcast = true;
}
@@ -985,12 +987,12 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
!= 600 * 60 * 4)) {
// This is a new style texture, don't send it because the client doesn't handle it correctly / crashes.
msg.clear_texture();
- sendAll(msg, ~0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
msg.set_texture(blob(pDstServerUser->qbaTexture));
} else {
// This is an old style texture, empty texture or there was no texture in this packet,
// send the message unchanged.
- sendAll(msg, ~0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
}
// Texture / comment handling for clients >= 1.2.2.
@@ -1004,7 +1006,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
msg.set_comment_hash(blob(pDstServerUser->qbaCommentHash));
}
- sendAll(msg, 0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
if (bDstAclChanged) {
clearACLCache(pDstServerUser);
@@ -1123,7 +1125,8 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
// a channel in or move a channel into this parent.
if (!canNest(p, c)) {
- PERM_DENIED_FALLBACK(NestingLimit, 0x010204, QLatin1String("Channel nesting limit reached"));
+ PERM_DENIED_FALLBACK(NestingLimit, Version::fromComponents(1, 2, 4),
+ QLatin1String("Channel nesting limit reached"));
return;
}
}
@@ -1135,7 +1138,8 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
return;
if (iChannelCountLimit != 0 && qhChannels.count() >= iChannelCountLimit) {
- PERM_DENIED_FALLBACK(ChannelCountLimit, 0x010300, QLatin1String("Channel count limit reached"));
+ PERM_DENIED_FALLBACK(ChannelCountLimit, Version::fromComponents(1, 3, 0),
+ QLatin1String("Channel count limit reached"));
return;
}
@@ -1182,12 +1186,12 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
log(uSource, QString("Added channel %1 under %2").arg(QString(*c), QString(*p)));
emit channelCreated(c);
- sendAll(msg, ~0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
if (!c->qbaDescHash.isEmpty()) {
msg.clear_description();
msg.set_description_hash(blob(c->qbaDescHash));
}
- sendAll(msg, 0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
if (c->bTemporary) {
// If a temporary channel has been created move the creator right in there
@@ -1326,12 +1330,12 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
updateChannel(c);
emit channelStateChanged(c);
- sendAll(msg, ~0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
if (msg.has_description() && !c->qbaDescHash.isEmpty()) {
msg.clear_description();
msg.set_description_hash(blob(c->qbaDescHash));
}
- sendAll(msg, 0x010202);
+ sendAll(msg, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
}
}
@@ -1879,9 +1883,7 @@ QString convertWithSizeRestriction(const std::string &str, size_t maxSize) {
void Server::msgVersion(ServerUser *uSource, MumbleProto::Version &msg) {
RATELIMIT(uSource);
- if (msg.has_version()) {
- uSource->uiVersion = msg.version();
- }
+ uSource->uiVersion = MumbleProto::getVersion(msg);
if (msg.has_release()) {
uSource->qsRelease = convertWithSizeRestriction(msg.release(), 100);
}
@@ -1964,7 +1966,7 @@ void Server::msgUserList(ServerUser *uSource, MumbleProto::UserList &msg) {
} else {
MumbleProto::PermissionDenied mppd;
mppd.set_type(MumbleProto::PermissionDenied_DenyType_UserName);
- if (uSource->uiVersion < 0x010201)
+ if (uSource->uiVersion < Version::fromComponents(1, 2, 1))
mppd.set_reason(u8(QString::fromLatin1("%1 is not a valid username").arg(name)));
else
mppd.set_name(u8(name));
@@ -2090,10 +2092,12 @@ void Server::msgUserStats(ServerUser *uSource, MumbleProto::UserStats &msg) {
MumbleProto::Version *mpv;
mpv = msg.mutable_version();
- if (pDstServerUser->uiVersion)
- mpv->set_version(pDstServerUser->uiVersion);
- if (!pDstServerUser->qsRelease.isEmpty())
+ if (pDstServerUser->uiVersion != Version::UNKNOWN) {
+ MumbleProto::setVersion(*mpv, pDstServerUser->uiVersion);
+ }
+ if (!pDstServerUser->qsRelease.isEmpty()) {
mpv->set_release(u8(pDstServerUser->qsRelease));
+ }
if (!pDstServerUser->qsOS.isEmpty()) {
mpv->set_os(u8(pDstServerUser->qsOS));
if (!pDstServerUser->qsOSVersion.isEmpty())
diff --git a/src/murmur/Meta.cpp b/src/murmur/Meta.cpp
index 6ed11cdb1..d24318eaf 100644
--- a/src/murmur/Meta.cpp
+++ b/src/murmur/Meta.cpp
@@ -305,9 +305,7 @@ void MetaParams::read(QString fname) {
iBanTime = typeCheckedFromSettings("autobanTime", iBanTime);
bBanSuccessful = typeCheckedFromSettings("autobanSuccessfulConnections", bBanSuccessful);
- qvSuggestVersion = Version::getRaw(qsSettings->value("suggestVersion").toString());
- if (qvSuggestVersion.toUInt() == 0)
- qvSuggestVersion = QVariant();
+ m_suggestVersion = Version::fromConfig(qsSettings->value("suggestVersion"));
qvSuggestPositional = qsSettings->value("suggestPositional");
if (qvSuggestPositional.toString().trimmed().isEmpty())
@@ -405,8 +403,7 @@ void MetaParams::read(QString fname) {
qmConfig.insert(QLatin1String("certrequired"), bCertRequired ? QLatin1String("true") : QLatin1String("false"));
qmConfig.insert(QLatin1String("forceExternalAuth"),
bForceExternalAuth ? QLatin1String("true") : QLatin1String("false"));
- qmConfig.insert(QLatin1String("suggestversion"),
- qvSuggestVersion.isNull() ? QString() : qvSuggestVersion.toString());
+ qmConfig.insert(QLatin1String("suggestversion"), Version::toConfigString(m_suggestVersion));
qmConfig.insert(QLatin1String("suggestpositional"),
qvSuggestPositional.isNull() ? QString() : qvSuggestPositional.toString());
qmConfig.insert(QLatin1String("suggestpushtotalk"),
diff --git a/src/murmur/Meta.h b/src/murmur/Meta.h
index 91b48f535..9c793bc7f 100644
--- a/src/murmur/Meta.h
+++ b/src/murmur/Meta.h
@@ -8,6 +8,8 @@
#include "Timer.h"
+#include "Version.h"
+
#ifdef Q_OS_WIN
# include "win.h"
#endif
@@ -141,7 +143,7 @@ public:
QString qsName;
#endif
- QVariant qvSuggestVersion;
+ Version::full_t m_suggestVersion;
QVariant qvSuggestPositional;
QVariant qvSuggestPushToTalk;
@@ -207,7 +209,8 @@ public:
void killAll();
void getOSInfo();
void connectListener(QObject *);
- static void getVersion(int &major, int &minor, int &patch, QString &string);
+ static void getVersion(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ QString &string);
signals:
void started(Server *);
void stopped(Server *);
diff --git a/src/murmur/Murmur.ice b/src/murmur/Murmur.ice
index 1dff7fca3..d72d63b33 100644
--- a/src/murmur/Murmur.ice
+++ b/src/murmur/Murmur.ice
@@ -49,8 +49,10 @@ module Murmur
int onlinesecs;
/** Average transmission rate in bytes per second over the last few seconds. */
int bytespersec;
- /** Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203. */
+ /** Legacy client version. */
int version;
+ /** New client version. (See https://github.com/mumble-voip/mumble/issues/5827) */
+ long version2;
/** Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else. */
string release;
/** Client OS. */
diff --git a/src/murmur/MurmurGRPCImpl.cpp b/src/murmur/MurmurGRPCImpl.cpp
index 37ea5c550..16d06833f 100644
--- a/src/murmur/MurmurGRPCImpl.cpp
+++ b/src/murmur/MurmurGRPCImpl.cpp
@@ -17,6 +17,7 @@
#include "ServerDB.h"
#include "ServerUser.h"
#include "Utils.h"
+#include "Version.h"
#include <chrono>
@@ -274,7 +275,7 @@ void ToRPC(const ::Server *srv, const ::User *u, ::MurmurRPC::User *ru) {
const auto su = static_cast< const ServerUser * >(u);
ru->set_online_secs(su->bwr.onlineSeconds());
ru->set_bytes_per_sec(su->bwr.bandwidth());
- ru->mutable_version()->set_version(su->uiVersion);
+ ru->mutable_version()->set_version(::Version::toLegacyVersion(su->uiVersion));
ru->mutable_version()->set_release(u8(su->qsRelease));
ru->mutable_version()->set_os(u8(su->qsOS));
ru->mutable_version()->set_os_version(u8(su->qsOSVersion));
@@ -1316,10 +1317,10 @@ namespace Wrapper {
void V1_GetVersion::impl(bool) {
::MurmurRPC::Version version;
- int major, minor, patch;
+ ::Version::component_t major, minor, patch;
QString release;
Meta::getVersion(major, minor, patch, release);
- version.set_version(major << 16 | minor << 8 | patch);
+ version.set_version(::Version::toLegacyVersion(::Version::fromComponents(major, minor, patch)));
version.set_release(u8(release));
end(version);
}
diff --git a/src/murmur/MurmurIce.cpp b/src/murmur/MurmurIce.cpp
index b19116e06..a75c77117 100644
--- a/src/murmur/MurmurIce.cpp
+++ b/src/murmur/MurmurIce.cpp
@@ -111,7 +111,8 @@ static void userToUser(const ::User *p, Murmur::User &mp) {
const ServerUser *u = static_cast< const ServerUser * >(p);
mp.onlinesecs = u->bwr.onlineSeconds();
mp.bytespersec = u->bwr.bandwidth();
- mp.version = u->uiVersion;
+ mp.version2 = u->uiVersion;
+ mp.version = Version::toLegacyVersion(u->uiVersion);
mp.release = iceString(u->qsRelease);
mp.os = iceString(u->qsOS);
mp.osversion = iceString(u->qsOSVersion);
@@ -1663,12 +1664,12 @@ static void impl_Server_setTexture(const ::Murmur::AMD_Server_setTexturePtr cb,
mpus.set_session(user->uiSession);
mpus.set_texture(blob(user->qbaTexture));
- server->sendAll(mpus, ~0x010202);
+ server->sendAll(mpus, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
if (!user->qbaTextureHash.isEmpty()) {
mpus.clear_texture();
mpus.set_texture_hash(blob(user->qbaTextureHash));
}
- server->sendAll(mpus, 0x010202);
+ server->sendAll(mpus, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
}
cb->ice_response();
@@ -1927,7 +1928,7 @@ static void impl_Meta_getBootedServers(const ::Murmur::AMD_Meta_getBootedServers
#define ACCESS_Meta_getVersion_ALL
static void impl_Meta_getVersion(const ::Murmur::AMD_Meta_getVersionPtr cb, const Ice::ObjectAdapterPtr) {
- int major, minor, patch;
+ Version::component_t major, minor, patch;
QString txt;
::Meta::getVersion(major, minor, patch, txt);
cb->ice_response(major, minor, patch, iceString(txt));
diff --git a/src/murmur/MurmurIceWrapper.cpp b/src/murmur/MurmurIceWrapper.cpp
index a0ffd3ce9..4dd6ce950 100644
--- a/src/murmur/MurmurIceWrapper.cpp
+++ b/src/murmur/MurmurIceWrapper.cpp
@@ -2234,7 +2234,8 @@ void ::Murmur::MetaI::getSlice_async(const ::Murmur::AMD_Meta_getSlicePtr &cb, c
"\n\n\n\n#include <Ice/SliceChecksumDict.ice>\nmodule Murmur\n{\n\n[\"python:seq:tuple\"] sequence<byte> "
"NetAddress;\n\nstruct User {\nint session;\nint userid;\nbool mute;\nbool deaf;\nbool suppress;\nbool "
"prioritySpeaker;\nbool selfMute;\nbool selfDeaf;\nbool recording;\nint channel;\nstring name;\nint "
- "onlinesecs;\nint bytespersec;\nint version;\nstring release;\nstring os;\nstring osversion;\nstring "
+ "onlinesecs;\nint bytespersec;\nint version;\nlong version2;\nstring release;\nstring os;\nstring "
+ "osversion;\nstring "
"identity;\nstring context;\nstring comment;\nNetAddress address;\nbool tcponly;\nint idlesecs;\nfloat "
"udpPing;\nfloat tcpPing;\n};\nsequence<int> IntList;\n\nstruct TextMessage {\nIntList sessions;\nIntList "
"channels;\nIntList trees;\nstring text;\n};\n\nstruct Channel {\nint id;\nstring name;\nint parent;\nIntList "
diff --git a/src/murmur/RPC.cpp b/src/murmur/RPC.cpp
index f887e6c85..b06e7fb7d 100644
--- a/src/murmur/RPC.cpp
+++ b/src/murmur/RPC.cpp
@@ -80,12 +80,12 @@ void Server::setUserState(User *pUser, Channel *cChannel, bool mute, bool deaf,
}
if (changed) {
- sendAll(mpus, ~0x010202);
+ sendAll(mpus, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
if (mpus.has_comment() && !pUser->qbaCommentHash.isEmpty()) {
mpus.clear_comment();
mpus.set_comment_hash(blob(pUser->qbaCommentHash));
}
- sendAll(mpus, 0x010202);
+ sendAll(mpus, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
emit userStateChanged(pUser);
}
@@ -299,12 +299,12 @@ bool Server::setChannelState(Channel *cChannel, Channel *cParent, const QString
if (updated)
updateChannel(cChannel);
if (changed) {
- sendAll(mpcs, ~0x010202);
+ sendAll(mpcs, Version::fromComponents(1, 2, 2), Version::CompareMode::LessThan);
if (mpcs.has_description() && !cChannel->qbaDescHash.isEmpty()) {
mpcs.clear_description();
mpcs.set_description_hash(blob(cChannel->qbaDescHash));
}
- sendAll(mpcs, 0x010202);
+ sendAll(mpcs, Version::fromComponents(1, 2, 2), Version::CompareMode::AtLeast);
emit channelStateChanged(cChannel);
}
@@ -581,8 +581,9 @@ void Meta::connectListener(QObject *obj) {
connect(this, SIGNAL(stopped(Server *)), obj, SLOT(stopped(Server *)));
}
-void Meta::getVersion(int &major, int &minor, int &patch, QString &string) {
- string = QLatin1String(MUMBLE_RELEASE);
+void Meta::getVersion(Version::component_t &major, Version::component_t &minor, Version::component_t &patch,
+ QString &string) {
+ string = Version::getRelease();
major = minor = patch = 0;
- Version::get(&major, &minor, &patch);
+ Version::getComponents(major, minor, patch);
}
diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp
index b2d63f67a..3b5b6077e 100644
--- a/src/murmur/Server.cpp
+++ b/src/murmur/Server.cpp
@@ -15,6 +15,7 @@
#include "Message.h"
#include "Meta.h"
#include "PacketDataStream.h"
+#include "ProtoUtils.h"
#include "ServerDB.h"
#include "ServerUser.h"
#include "SpeechFlags.h"
@@ -226,12 +227,6 @@ Server::Server(int snum, QObject *p) : QThread(p) {
readLinks();
initializeCert();
- int major, minor, patch;
- QString release;
- Meta::getVersion(major, minor, patch, release);
-
- uiVersionBlob = qToBigEndian(static_cast< quint32 >((major << 16) | (minor << 8) | patch));
-
if (bValid) {
#ifdef USE_ZEROCONF
if (bBonjour)
@@ -315,41 +310,6 @@ Server::~Server() {
log("Stopped");
}
-/// normalizeSuggestVersion normalizes a 'suggestversion' config value.
-/// The config value may be a version string, or a bitmasked
-/// integer representing the version.
-/// This function converts the 'suggestversion' config value to
-/// always be a bitmasked integer representation.
-///
-/// On error, the function returns an empty QVariant.
-static QVariant normalizeSuggestVersion(QVariant suggestVersion) {
- uint integerValue = suggestVersion.toUInt();
-
- // If the integer value is 0, it can mean two things:
- //
- // Either the suggestversion is set to 0.
- // Or, the suggestversion is a version string such as "1.3.0",
- // and cannot be converted to an integer value.
- //
- // We handle both cases the same: by pretending the
- // suggestversion is a version string in both cases.
- //
- // If it is a version string, the call to Version::getRaw()
- // will return the bitmasked representation.
- //
- // If it is not a version string, the call to Version::getRaw()
- // will return 0, so it is effectively a no-op.
- if (integerValue == 0) {
- integerValue = Version::getRaw(suggestVersion.toString());
- }
-
- if (integerValue != 0) {
- return integerValue;
- }
-
- return QVariant();
-}
-
void Server::readParams() {
qsPassword = Meta::mp.qsPassword;
usPort = static_cast< unsigned short >(Meta::mp.usPort + iServerNum - 1);
@@ -381,7 +341,7 @@ void Server::readParams() {
iMessageBurst = Meta::mp.iMessageBurst;
iPluginMessageLimit = Meta::mp.iPluginMessageLimit;
iPluginMessageBurst = Meta::mp.iPluginMessageBurst;
- qvSuggestVersion = Meta::mp.qvSuggestVersion;
+ m_suggestVersion = Meta::mp.m_suggestVersion;
qvSuggestPositional = Meta::mp.qvSuggestPositional;
qvSuggestPushToTalk = Meta::mp.qvSuggestPushToTalk;
iOpusThreshold = Meta::mp.iOpusThreshold;
@@ -461,9 +421,8 @@ void Server::readParams() {
bCertRequired = getConf("certrequired", bCertRequired).toBool();
bForceExternalAuth = getConf("forceExternalAuth", bForceExternalAuth).toBool();
- qvSuggestVersion = normalizeSuggestVersion(getConf("suggestversion", qvSuggestVersion));
- if (qvSuggestVersion.toUInt() == 0)
- qvSuggestVersion = QVariant();
+ m_suggestVersion =
+ Version::fromString(getConf("suggestversion", Version::toConfigString(m_suggestVersion)).toString());
qvSuggestPositional = getConf("suggestpositional", qvSuggestPositional);
if (qvSuggestPositional.toString().trimmed().isEmpty())
@@ -608,8 +567,7 @@ void Server::setLiveConf(const QString &key, const QString &value) {
else if (key == "channelname")
qrChannelName = !v.isNull() ? QRegExp(v) : Meta::mp.qrChannelName;
else if (key == "suggestversion")
- qvSuggestVersion =
- !v.isNull() ? (v.isEmpty() ? QVariant() : normalizeSuggestVersion(v)) : Meta::mp.qvSuggestVersion;
+ m_suggestVersion = !v.isNull() ? Version::fromConfig(v) : Meta::mp.m_suggestVersion;
else if (key == "suggestpositional")
qvSuggestPositional = !v.isNull() ? (v.isEmpty() ? QVariant() : v) : Meta::mp.qvSuggestPositional;
else if (key == "suggestpushtotalk")
@@ -704,7 +662,7 @@ void Server::udpActivated(int socket) {
// Cloned from ::run(), as it's the only UDP data we care about until the thread is started.
quint32 *ping = reinterpret_cast< quint32 * >(encrypt);
if ((len == 12) && (*ping == 0) && bAllowPing) {
- ping[0] = uiVersionBlob;
+ ping[0] = qToBigEndian(Version::toLegacyVersion(Version::get()));
ping[3] = qToBigEndian(static_cast< quint32 >(qhUsers.count()));
ping[4] = qToBigEndian(static_cast< quint32 >(iMaxUsers));
ping[5] = qToBigEndian(static_cast< quint32 >(iMaxBandwidth));
@@ -848,7 +806,7 @@ void Server::run() {
quint32 *ping = reinterpret_cast< quint32 * >(encrypt);
if ((len == 12) && (*ping == 0) && bAllowPing) {
- ping[0] = uiVersionBlob;
+ ping[0] = qToBigEndian(Version::toLegacyVersion(Version::get()));
// 1 and 2 will be the timestamp, which we return unmodified.
ping[3] = qToBigEndian(static_cast< quint32 >(qhUsers.count()));
ping[4] = qToBigEndian(static_cast< quint32 >(iMaxUsers));
@@ -1457,15 +1415,11 @@ void Server::newClient() {
void Server::encrypted() {
ServerUser *uSource = qobject_cast< ServerUser * >(sender());
- int major, minor, patch;
- QString release;
-
- Meta::getVersion(major, minor, patch, release);
MumbleProto::Version mpv;
- mpv.set_version((major << 16) | (minor << 8) | patch);
+ MumbleProto::setVersion(mpv, Version::get());
if (Meta::mp.bSendVersion) {
- mpv.set_release(u8(release));
+ mpv.set_release(u8(Version::getRelease()));
mpv.set_os(u8(meta->qsOS));
mpv.set_os_version(u8(meta->qsOSVersion));
}
@@ -1779,18 +1733,25 @@ void Server::sendProtoMessage(ServerUser *u, const ::google::protobuf::Message &
u->sendMessage(msg, msgType, cache);
}
-void Server::sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int version) {
- sendProtoExcept(nullptr, msg, msgType, version);
+void Server::sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, Version::full_t version,
+ Version::CompareMode mode) {
+ sendProtoExcept(nullptr, msg, msgType, version, mode);
}
void Server::sendProtoExcept(ServerUser *u, const ::google::protobuf::Message &msg, unsigned int msgType,
- unsigned int version) {
+ Version::full_t version, Version::CompareMode mode) {
QByteArray cache;
foreach (ServerUser *usr, qhUsers)
- if ((usr != u) && (usr->sState == ServerUser::Authenticated))
- if ((version == 0) || (usr->uiVersion >= version)
- || ((version & 0x80000000) && (usr->uiVersion < (~version))))
+ if ((usr != u) && (usr->sState == ServerUser::Authenticated)) {
+ assert(mode == Version::CompareMode::AtLeast || mode == Version::CompareMode::LessThan);
+
+ const bool isUnknown = version == Version::UNKNOWN;
+ const bool fulfillsVersionRequirement =
+ mode == Version::CompareMode::AtLeast ? usr->uiVersion >= version : usr->uiVersion < version;
+ if (isUnknown || fulfillsVersionRequirement) {
usr->sendMessage(msg, msgType, cache);
+ }
+ }
}
void Server::removeChannel(int id) {
diff --git a/src/murmur/Server.h b/src/murmur/Server.h
index ee927adc4..51223c740 100644
--- a/src/murmur/Server.h
+++ b/src/murmur/Server.h
@@ -20,6 +20,7 @@
#include "Mumble.pb.h"
#include "Timer.h"
#include "User.h"
+#include "Version.h"
#ifndef Q_MOC_RUN
# include <boost/function.hpp>
@@ -141,7 +142,7 @@ public:
unsigned int iPluginMessageLimit;
unsigned int iPluginMessageBurst;
- QVariant qvSuggestVersion;
+ Version::full_t m_suggestVersion;
QVariant qvSuggestPositional;
QVariant qvSuggestPushToTalk;
@@ -231,7 +232,6 @@ public:
HANDLE hNotify;
QList< SOCKET > qlUdpSocket;
#endif
- quint32 uiVersionBlob;
QList< QSocketNotifier * > qlUdpNotifier;
/// This lock provides synchronization between the
@@ -309,18 +309,23 @@ public:
void clearACLCache(User *p = nullptr);
void clearWhisperTargetCache();
- void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion);
+ void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, Version::full_t version,
+ Version::CompareMode mode);
void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType,
- unsigned int minversion);
+ Version::full_t version, Version::CompareMode mode);
void sendProtoMessage(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType);
// sendAll sends a protobuf message to all users on the server whose version is either bigger than v or
// lower than ~v. If v == 0 the message is sent to everyone.
-#define MUMBLE_MH_MSG(x) \
- void sendAll(const MumbleProto::x &msg, unsigned int v = 0) { sendProtoAll(msg, MessageHandler::x, v); } \
- void sendExcept(ServerUser *u, const MumbleProto::x &msg, unsigned int v = 0) { \
- sendProtoExcept(u, msg, MessageHandler::x, v); \
- } \
+#define MUMBLE_MH_MSG(x) \
+ void sendAll(const MumbleProto::x &msg, Version::full_t v = Version::UNKNOWN, \
+ Version::CompareMode mode = Version::CompareMode::AtLeast) { \
+ sendProtoAll(msg, MessageHandler::x, v, mode); \
+ } \
+ void sendExcept(ServerUser *u, const MumbleProto::x &msg, Version::full_t v = Version::UNKNOWN, \
+ Version::CompareMode mode = Version::CompareMode::AtLeast) { \
+ sendProtoExcept(u, msg, MessageHandler::x, v, mode); \
+ } \
void sendMessage(ServerUser *u, const MumbleProto::x &msg) { sendProtoMessage(u, msg, MessageHandler::x); }
MUMBLE_MH_ALL
diff --git a/src/murmur/ServerUser.cpp b/src/murmur/ServerUser.cpp
index 7e0a61ccc..42eb90851 100644
--- a/src/murmur/ServerUser.cpp
+++ b/src/murmur/ServerUser.cpp
@@ -26,7 +26,7 @@ ServerUser::ServerUser(Server *p, QSslSocket *socket)
uiUDPPackets = uiTCPPackets = 0;
aiUdpFlag = 1;
- uiVersion = 0;
+ uiVersion = Version::UNKNOWN;
bVerified = true;
iLastPermissionCheck = -1;
diff --git a/src/murmur/ServerUser.h b/src/murmur/ServerUser.h
index c34ebeaf7..fe52119db 100644
--- a/src/murmur/ServerUser.h
+++ b/src/murmur/ServerUser.h
@@ -16,6 +16,7 @@
#include "HostAddress.h"
#include "Timer.h"
#include "User.h"
+#include "Version.h"
#include <QtCore/QElapsedTimer>
#include <QtCore/QStringList>
@@ -114,7 +115,7 @@ public:
float dTCPPingAvg, dTCPPingVar;
quint32 uiUDPPackets, uiTCPPackets;
- unsigned int uiVersion;
+ Version::full_t uiVersion;
QString qsRelease;
QString qsOS;
QString qsOSVersion;
diff --git a/src/murmur/Tray.cpp b/src/murmur/Tray.cpp
index 977c420bf..b1986fb18 100644
--- a/src/murmur/Tray.cpp
+++ b/src/murmur/Tray.cpp
@@ -78,7 +78,7 @@ void Tray::on_ShowLog_triggered() {
QTextBrowser *tb = new QTextBrowser();
mw->resize(675, 300);
mw->setCentralWidget(tb);
- mw->setWindowTitle(QString::fromLatin1("Murmur -- %1").arg(MUMBLE_RELEASE));
+ mw->setWindowTitle(QString::fromLatin1("Murmur -- %1").arg(Version::getRelease()));
connect(le, SIGNAL(newLogEntry(const QString &)), tb, SLOT(append(const QString &)));
diff --git a/src/murmur/main.cpp b/src/murmur/main.cpp
index 4a5826dea..cef62805f 100644
--- a/src/murmur/main.cpp
+++ b/src/murmur/main.cpp
@@ -352,7 +352,7 @@ int main(int argc, char **argv) {
bVerbose = true;
} else if ((arg == "-version") || (arg == "--version")) {
detach = false;
- qInfo("%s -- %s", qPrintable(args.at(0)), MUMBLE_RELEASE);
+ qInfo("%s -- %s", qPrintable(args.at(0)), Version::getRelease().toStdString().c_str());
return 0;
} else if (args.at(i) == QLatin1String("-license") || args.at(i) == QLatin1String("--license")) {
#ifdef Q_OS_WIN
@@ -663,11 +663,7 @@ int main(int argc, char **argv) {
meta->getOSInfo();
- int major, minor, patch;
- QString strver;
- meta->getVersion(major, minor, patch, strver);
-
- qWarning("Murmur %d.%d.%d (%s) running on %s: %s: Booting servers", major, minor, patch, qPrintable(strver),
+ qWarning("Murmur %s running on %s: %s: Booting servers", qPrintable(Version::toString(Version::get())),
qPrintable(meta->qsOS), qPrintable(meta->qsOSVersion));
meta->bootAll();
diff --git a/src/tests/Benchmark.cpp b/src/tests/Benchmark.cpp
index 251923ad4..aea34ea33 100644
--- a/src/tests/Benchmark.cpp
+++ b/src/tests/Benchmark.cpp
@@ -100,7 +100,7 @@ Client::Client(QObject *p, QHostAddress qha, unsigned short prt, bool send, bool
MumbleProto::Version mpv;
mpv.set_release(u8(QLatin1String("1.2.1 Benchmark")));
- mpv.set_version(0x010203);
+ mpv.set_version_v1(Version::toLegacyVersion(Version::fromComponents(1, 2, 3)));
sendMessage(mpv, MessageHandler::Version);