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
committerHartmnt <hartmunt@protonmail.com>2022-09-08 11:45:47 +0300
commit79762ce55e3bebf903a54f57adbefb517de537a0 (patch)
treeac79f144f40dad4fc8c71697f1ac6ced81a00132
parent7e959985ad713b919c4dbca0ab9bae5aa6dcc1ed (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/MumbleProtocol.cpp29
-rw-r--r--src/MumbleProtocol.h20
-rw-r--r--src/MumbleUDP.proto9
-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.h99
-rw-r--r--src/benchmarks/AudioReceiverBuffer/AudioReceiverBuffer_benchmark.cpp3
-rw-r--r--src/benchmarks/AudioReceiverBuffer/ServerUser.h4
-rw-r--r--src/benchmarks/protocol/protocol_benchmark.cpp6
-rw-r--r--src/mumble/ACLEditor.cpp6
-rw-r--r--src/mumble/API_v_1_x_x.cpp2
-rw-r--r--src/mumble/About.cpp2
-rw-r--r--src/mumble/ConnectDialog.cpp8
-rw-r--r--src/mumble/ConnectDialog.h6
-rw-r--r--src/mumble/CrashReporter.cpp4
-rw-r--r--src/mumble/MainWindow.cpp48
-rw-r--r--src/mumble/Messages.cpp19
-rw-r--r--src/mumble/NetworkConfig.cpp9
-rw-r--r--src/mumble/Plugin.cpp4
-rw-r--r--src/mumble/ServerHandler.cpp13
-rw-r--r--src/mumble/ServerHandler.h4
-rw-r--r--src/mumble/Usage.cpp4
-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/main.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/MurmurIce.cpp9
-rw-r--r--src/murmur/MurmurIceWrapper.cpp3
-rw-r--r--src/murmur/RPC.cpp15
-rw-r--r--src/murmur/Server.cpp82
-rw-r--r--src/murmur/Server.h27
-rw-r--r--src/murmur/ServerUser.cpp2
-rw-r--r--src/murmur/ServerUser.h2
-rw-r--r--src/murmur/Tray.cpp2
-rw-r--r--src/murmur/main.cpp8
-rw-r--r--src/tests/Benchmark.cpp2
-rw-r--r--src/tests/TestAudioReceiverBuffer/ServerUser.h4
-rw-r--r--src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp25
-rw-r--r--src/tests/TestMumbleProtocol/TestMumbleProtocol.cpp16
53 files changed, 531 insertions, 357 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0cd019904..36a042a25 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -74,6 +74,7 @@ set(SHARED_SOURCES
"PlatformCheck.cpp"
"QtUtils.cpp"
"ProcessResolver.cpp"
+ "ProtoUtils.cpp"
"SelfSignedCertificate.cpp"
"ServerAddress.cpp"
"ServerResolver.cpp"
@@ -109,6 +110,7 @@ set(SHARED_HEADERS
"PasswordGenerator.h"
"PlatformCheck.h"
"ProcessResolver.h"
+ "ProtoUtils.h"
"SelfSignedCertificate.h"
"ServerAddress.h"
"ServerResolver.h"
@@ -136,7 +138,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 918f82b84..8f8b7c9a4 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.
@@ -581,8 +585,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/MumbleProtocol.cpp b/src/MumbleProtocol.cpp
index 8e6b75188..cc76c0b9e 100644
--- a/src/MumbleProtocol.cpp
+++ b/src/MumbleProtocol.cpp
@@ -17,7 +17,7 @@
namespace Mumble {
namespace Protocol {
- bool protocolVersionsAreCompatible(Version::mumble_raw_version_t lhs, Version::mumble_raw_version_t rhs) {
+ bool protocolVersionsAreCompatible(Version::full_t lhs, Version::full_t rhs) {
// At this point the protocol version only makes a difference between pre-protobuf and post-protobuf
return (lhs < PROTOBUF_INTRODUCTION_VERSION) == (rhs < PROTOBUF_INTRODUCTION_VERSION);
}
@@ -60,21 +60,19 @@ namespace Protocol {
}
template< Role role >
- ProtocolHandler< role >::ProtocolHandler(Version::mumble_raw_version_t protocolVersion)
- : m_protocolVersion(protocolVersion) {}
+ ProtocolHandler< role >::ProtocolHandler(Version::full_t protocolVersion) : m_protocolVersion(protocolVersion) {}
- template< Role role > Version::mumble_raw_version_t ProtocolHandler< role >::getProtocolVersion() const {
+ template< Role role > Version::full_t ProtocolHandler< role >::getProtocolVersion() const {
return m_protocolVersion;
}
- template< Role role >
- void ProtocolHandler< role >::setProtocolVersion(Version::mumble_raw_version_t protocolVersion) {
+ template< Role role > void ProtocolHandler< role >::setProtocolVersion(Version::full_t protocolVersion) {
m_protocolVersion = protocolVersion;
}
template< Role role >
- UDPAudioEncoder< role >::UDPAudioEncoder(Version::mumble_raw_version_t protocolVersion)
+ UDPAudioEncoder< role >::UDPAudioEncoder(Version::full_t protocolVersion)
: ProtocolHandler< role >(protocolVersion) {
m_byteBuffer.resize(MAX_UDP_PACKET_SIZE);
@@ -402,8 +400,7 @@ namespace Protocol {
template< Role role >
- UDPPingEncoder< role >::UDPPingEncoder(Version::mumble_raw_version_t protocolVersion)
- : ProtocolHandler< role >(protocolVersion) {
+ UDPPingEncoder< role >::UDPPingEncoder(Version::full_t protocolVersion) : ProtocolHandler< role >(protocolVersion) {
// Use the assumption that a general ping package will be < 32bytes long (the legacy ping packet is at most
// 12bytes long)
m_byteBuffer.reserve(32);
@@ -448,7 +445,8 @@ namespace Protocol {
if (writeAdditionalInformation) {
std::uint32_t *dataArray = reinterpret_cast< std::uint32_t * >(m_byteBuffer.data());
- dataArray[0] = qToBigEndian(data.serverVersion);
+ // Legacy pings expect the version to be encoded using the old (legacy) format
+ dataArray[0] = qToBigEndian(Version::toLegacyVersion(data.serverVersion));
// dataArray[1] and dataArray[2] together hold the timestamp (written below)
dataArray[3] = qToBigEndian(data.userCount);
dataArray[4] = qToBigEndian(data.maxUserCount);
@@ -487,7 +485,7 @@ namespace Protocol {
if (data.requestAdditionalInformation) {
m_pingMessage.set_request_extended_information(true);
} else if (data.containsAdditionalInformation) {
- m_pingMessage.set_server_version(data.serverVersion);
+ m_pingMessage.set_server_version_v2(data.serverVersion);
m_pingMessage.set_user_count(data.userCount);
m_pingMessage.set_max_user_count(data.maxUserCount);
m_pingMessage.set_max_bandwidth_per_user(data.maxBandwidthPerUser);
@@ -502,8 +500,7 @@ namespace Protocol {
template< Role role >
- UDPDecoder< role >::UDPDecoder(Version::mumble_raw_version_t protocolVersion)
- : ProtocolHandler< role >(protocolVersion) {
+ UDPDecoder< role >::UDPDecoder(Version::full_t protocolVersion) : ProtocolHandler< role >(protocolVersion) {
m_byteBuffer.resize(MAX_UDP_PACKET_SIZE);
}
@@ -629,7 +626,9 @@ namespace Protocol {
// Extended ping containing meta-information
const std::uint32_t *dataArray = reinterpret_cast< const std::uint32_t * >(data.data());
- m_pingData.serverVersion = qFromBigEndian(dataArray[0]);
+ // Legacy pings only support the version to be encoded using the old (legacy) format
+ m_pingData.serverVersion = Version::fromLegacyVersion(qFromBigEndian(dataArray[0]));
+
// Virtual array entries 1 and 2 are actually a single uint64. Note that the timestamp is
// whatever the client sent to the server and thus it does not require an endian-transformation
m_pingData.timestamp = *reinterpret_cast< const std::uint64_t * >(&dataArray[1]);
@@ -685,7 +684,7 @@ namespace Protocol {
// m_pingMessage now contains the parsed data
m_pingData.timestamp = m_pingMessage.timestamp();
- m_pingData.serverVersion = m_pingMessage.server_version();
+ m_pingData.serverVersion = m_pingMessage.server_version_v2();
// 0 is not a valid version specifier, so if this field is zero, it means Protobuf has used a default
// value and thus the field was not set. Thus we assume that none of the extra fields are set.
diff --git a/src/MumbleProtocol.h b/src/MumbleProtocol.h
index d15e6857e..22c424b5f 100644
--- a/src/MumbleProtocol.h
+++ b/src/MumbleProtocol.h
@@ -107,23 +107,23 @@ namespace Protocol {
enum class Role { Server, Client };
- constexpr Version::mumble_raw_version_t PROTOBUF_INTRODUCTION_VERSION = Version::toRaw(1, 5, 0);
+ constexpr Version::full_t PROTOBUF_INTRODUCTION_VERSION = Version::fromComponents(1, 5, 0);
- bool protocolVersionsAreCompatible(Version::mumble_raw_version_t lhs, Version::mumble_raw_version_t rhs);
+ bool protocolVersionsAreCompatible(Version::full_t lhs, Version::full_t rhs);
template< Role role > class ProtocolHandler {
public:
- ProtocolHandler(Version::mumble_raw_version_t protocolVersion = Version::UNKNOWN);
+ ProtocolHandler(Version::full_t protocolVersion = Version::UNKNOWN);
- Version::mumble_raw_version_t getProtocolVersion() const;
- void setProtocolVersion(Version::mumble_raw_version_t protocolVersion);
+ Version::full_t getProtocolVersion() const;
+ void setProtocolVersion(Version::full_t protocolVersion);
constexpr Role getRole() const { return role; };
protected:
- Version::mumble_raw_version_t m_protocolVersion;
+ Version::full_t m_protocolVersion;
};
struct AudioData {
@@ -145,7 +145,7 @@ namespace Protocol {
std::uint64_t timestamp = 0;
bool requestAdditionalInformation = false;
bool containsAdditionalInformation = false;
- std::uint32_t serverVersion = Version::UNKNOWN;
+ Version::full_t serverVersion = Version::UNKNOWN;
std::uint32_t userCount = 0;
std::uint32_t maxUserCount = 0;
std::uint32_t maxBandwidthPerUser = 0;
@@ -156,7 +156,7 @@ namespace Protocol {
template< Role role > class UDPAudioEncoder : public ProtocolHandler< role > {
public:
- UDPAudioEncoder(Version::mumble_raw_version_t protocolVersion = Version::UNKNOWN);
+ UDPAudioEncoder(Version::full_t protocolVersion = Version::UNKNOWN);
/**
* Encodes an audio packet based on the provided data.
@@ -234,7 +234,7 @@ namespace Protocol {
template< Role role > class UDPPingEncoder : public ProtocolHandler< role > {
public:
- UDPPingEncoder(Version::mumble_raw_version_t protocolVersion = Version::UNKNOWN);
+ UDPPingEncoder(Version::full_t protocolVersion = Version::UNKNOWN);
gsl::span< const byte > encodePingPacket(const PingData &data);
@@ -248,7 +248,7 @@ namespace Protocol {
template< Role role > class UDPDecoder : public ProtocolHandler< role > {
public:
- UDPDecoder(Version::mumble_raw_version_t protocolVersion = Version::UNKNOWN);
+ UDPDecoder(Version::full_t protocolVersion = Version::UNKNOWN);
gsl::span< byte > getBuffer();
bool decode(const gsl::span< const byte > data, bool restrictToPing = false);
diff --git a/src/MumbleUDP.proto b/src/MumbleUDP.proto
index aabc463ca..86fe2e477 100644
--- a/src/MumbleUDP.proto
+++ b/src/MumbleUDP.proto
@@ -68,10 +68,11 @@ message Ping {
// Below are the fields for the "additional information" that are filled out by the server on request.
-
- // The version of the server encoded into a single integer. The 32 bits are partitioned in regions of (left to right)
- // 16, 8 and 8 bits representing the major, minor and patch version number respectively.
- uint32 server_version = 3;
+ // The version of the server in the new version format.
+ // The new protobuf Ping packet introduced with 1.5 drops support for the legacy version format
+ // since both server and client have to support this new format.
+ // (See https://github.com/mumble-voip/mumble/issues/5827)
+ uint64 server_version_v2 = 3;
// The amount of users currently connected to the server
uint32 user_count = 4;
diff --git a/src/OSInfo.cpp b/src/OSInfo.cpp
index 03d82e1af..09c6ff412 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 49b1f0a2a..97447302d 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 7e6d07e7b..3dab5893e 100644
--- a/src/Version.h
+++ b/src/Version.h
@@ -7,8 +7,10 @@
#define MUMBLE_VERSION_H_
#include <cstdint>
+#include <limits>
-#include <QtCore/QString>
+#include <QString>
+#include <QVariant>
#define MUMXTEXT(X) #X
#define MUMTEXT(X) MUMXTEXT(X)
@@ -17,26 +19,93 @@
namespace Version {
-using exact_width_mumble_raw_version_t = std::uint32_t;
-using mumble_raw_version_t = unsigned int;
+enum class CompareMode { AtLeast, LessThan };
-static_assert(sizeof(exact_width_mumble_raw_version_t) <= sizeof(mumble_raw_version_t),
- "Invalid scalar type used to represent Mumble versions");
+//
+// The mumble version format (v2) is a uint64:
+// major minor patch reserved/unused
+// 0xFFFF 0xFFFF 0xFFFF 0xFFFF
+// (big-endian)
+//
-constexpr mumble_raw_version_t UNKNOWN = 0;
+using full_t = std::uint64_t;
+using component_t = std::uint16_t;
-unsigned int getRaw(const QString &version = QLatin1String(MUMTEXT(MUMBLE_VERSION)));
-QString toString(mumble_raw_version_t version);
-bool get(int *major, int *minor, int *patch, const QString &version = QLatin1String(MUMTEXT(MUMBLE_VERSION)));
+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 Version::mumble_raw_version_t toRaw(int major, int minor, int patch) {
- return (major << 16) | (minor << 8) | patch;
+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);
}
-constexpr void fromRaw(unsigned int version, int *major, int *minor, int *patch) {
- *major = (version & 0xFFFF0000) >> 16;
- *minor = (version & 0xFF00) >> 8;
- *patch = (version & 0xFF);
+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/benchmarks/AudioReceiverBuffer/AudioReceiverBuffer_benchmark.cpp b/src/benchmarks/AudioReceiverBuffer/AudioReceiverBuffer_benchmark.cpp
index 3d3cdb0ba..7e31987c2 100644
--- a/src/benchmarks/AudioReceiverBuffer/AudioReceiverBuffer_benchmark.cpp
+++ b/src/benchmarks/AudioReceiverBuffer/AudioReceiverBuffer_benchmark.cpp
@@ -12,7 +12,8 @@ std::mt19937 rng(rd());
std::uniform_int_distribution< unsigned int > random_context(Mumble::Protocol::AudioContext::begin,
Mumble::Protocol::AudioContext::end);
std::uniform_int_distribution< int > random_volume_adjustment(-60, 30 + 1);
-std::uniform_int_distribution< unsigned int > random_version(Version::toRaw(1, 2, 0), Version::toRaw(1, 6, 0));
+std::uniform_int_distribution< Version::full_t > random_version(Version::fromComponents(1, 2, 0),
+ Version::fromComponents(1, 6, 0));
std::vector< Mumble::Protocol::audio_context_t > contexts;
std::vector< VolumeAdjustment > volumeAdjustments;
diff --git a/src/benchmarks/AudioReceiverBuffer/ServerUser.h b/src/benchmarks/AudioReceiverBuffer/ServerUser.h
index d07985227..202895ba3 100644
--- a/src/benchmarks/AudioReceiverBuffer/ServerUser.h
+++ b/src/benchmarks/AudioReceiverBuffer/ServerUser.h
@@ -11,12 +11,12 @@
#include <string>
struct ServerUser {
- ServerUser(unsigned int uiSession, Version::mumble_raw_version_t version, bool deaf = false, bool selfDeaf = false,
+ ServerUser(unsigned int uiSession, Version::full_t version, bool deaf = false, bool selfDeaf = false,
const std::string context = "")
: uiSession(uiSession), uiVersion(version), bDeaf(deaf), bSelfDeaf(selfDeaf), ssContext(context) {}
unsigned int uiSession;
- Version::mumble_raw_version_t uiVersion;
+ Version::full_t uiVersion;
bool bDeaf;
bool bSelfDeaf;
std::string ssContext;
diff --git a/src/benchmarks/protocol/protocol_benchmark.cpp b/src/benchmarks/protocol/protocol_benchmark.cpp
index bb3e6ebb3..60178bf6b 100644
--- a/src/benchmarks/protocol/protocol_benchmark.cpp
+++ b/src/benchmarks/protocol/protocol_benchmark.cpp
@@ -41,7 +41,7 @@ public:
audioData.position = { 1.25f, 1260.539f, -3.0765f };
audioData.containsPositionalData = true;
- encoder.setProtocolVersion(Version::toRaw(1, 3, 0));
+ encoder.setProtocolVersion(Version::fromComponents(1, 3, 0));
encoder.encodeAudioPacket(audioData);
encoder.setProtocolVersion(Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION);
encoder.encodeAudioPacket(audioData);
@@ -71,7 +71,7 @@ BENCHMARK_REGISTER_F(Fixture, BM_encodeLegacyDirect)
->Range(FROM_PAYLOAD_SIZE, TO_PAYLOAD_SIZE);
BENCHMARK_DEFINE_F(Fixture, BM_encodeLegacy)(::benchmark::State &state) {
- encoder.setProtocolVersion(Version::toRaw(1, 3, 0));
+ encoder.setProtocolVersion(Version::fromComponents(1, 3, 0));
for (auto _ : state) {
encoder.encodeAudioPacket(audioData);
@@ -83,7 +83,7 @@ BENCHMARK_REGISTER_F(Fixture, BM_encodeLegacy)
->Range(FROM_PAYLOAD_SIZE, TO_PAYLOAD_SIZE);
BENCHMARK_DEFINE_F(Fixture, BM_encodeLegacy_UpdateOnly)(::benchmark::State &state) {
- encoder.setProtocolVersion(Version::toRaw(1, 3, 0));
+ encoder.setProtocolVersion(Version::fromComponents(1, 3, 0));
encoder.prepareAudioPacket(audioData);
diff --git a/src/mumble/ACLEditor.cpp b/src/mumble/ACLEditor.cpp
index b17820011..b948929cf 100644
--- a/src/mumble/ACLEditor.cpp
+++ b/src/mumble/ACLEditor.cpp
@@ -59,7 +59,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"));
@@ -125,7 +125,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"));
@@ -149,7 +149,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_x_x.cpp b/src/mumble/API_v_1_x_x.cpp
index b3ce9c9fb..3bc6b287f 100644
--- a/src/mumble/API_v_1_x_x.cpp
+++ b/src/mumble/API_v_1_x_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 8e9584d05..e5dc07143 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 f53e6ea85..dea625e87 100644
--- a/src/mumble/ConnectDialog.cpp
+++ b/src/mumble/ConnectDialog.cpp
@@ -1380,7 +1380,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 >)));
@@ -1747,8 +1747,7 @@ void ConnectDialog::lookedUp() {
}
}
-void ConnectDialog::sendPing(const QHostAddress &host, unsigned short port,
- Version::mumble_raw_version_t protocolVersion) {
+void ConnectDialog::sendPing(const QHostAddress &host, unsigned short port, Version::full_t protocolVersion) {
ServerAddress addr(HostAddress(host), port);
quint64 uiRand;
@@ -1784,8 +1783,7 @@ void ConnectDialog::sendPing(const QHostAddress &host, unsigned short port,
++si->uiSent;
}
-bool ConnectDialog::writePing(const QHostAddress &host, unsigned short port,
- Version::mumble_raw_version_t protocolVersion,
+bool ConnectDialog::writePing(const QHostAddress &host, unsigned short port, Version::full_t protocolVersion,
const Mumble::Protocol::PingData &pingData) {
m_udpPingEncoder.setProtocolVersion(protocolVersion);
diff --git a/src/mumble/ConnectDialog.h b/src/mumble/ConnectDialog.h
index b0017c27c..dd4165363 100644
--- a/src/mumble/ConnectDialog.h
+++ b/src/mumble/ConnectDialog.h
@@ -54,7 +54,7 @@ protected:
void init();
public:
- quint32 uiVersion;
+ Version::full_t uiVersion;
quint32 uiPing;
quint32 uiPingSort;
quint32 uiUsers;
@@ -293,8 +293,8 @@ protected:
bool bAllowFilters;
- void sendPing(const QHostAddress &, unsigned short port, Version::mumble_raw_version_t protocolVersion);
- bool writePing(const QHostAddress &host, unsigned short port, Version::mumble_raw_version_t protocolVersion,
+ void sendPing(const QHostAddress &, unsigned short port, Version::full_t protocolVersion);
+ bool writePing(const QHostAddress &host, unsigned short port, Version::full_t protocolVersion,
const Mumble::Protocol::PingData &pingData);
void initList();
diff --git a/src/mumble/CrashReporter.cpp b/src/mumble/CrashReporter.cpp
index 036e74272..248e3f246 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 c6abc59c9..f949104a5 100644
--- a/src/mumble/MainWindow.cpp
+++ b/src/mumble/MainWindow.cpp
@@ -257,7 +257,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()));
@@ -1088,19 +1088,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));
@@ -1108,21 +1103,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;
}
@@ -1428,7 +1422,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 {
@@ -1624,7 +1618,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);
@@ -1650,7 +1644,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()
@@ -1713,7 +1707,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()
@@ -2187,7 +2181,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);
@@ -3453,7 +3447,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);
if (Global::get().s.bMinimalView) {
diff --git a/src/mumble/Messages.cpp b/src/mumble/Messages.cpp
index 3a622bf65..2d5e4d4b8 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"
@@ -1156,9 +1157,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->setProtocolVersion(msg.version());
- }
+ Global::get().sh->setProtocolVersion(MumbleProto::getVersion(msg));
+
if (msg.has_release())
Global::get().sh->qsRelease = u8(msg.release());
if (msg.has_os()) {
@@ -1234,7 +1234,8 @@ void MainWindow::msgCodecVersion(const MumbleProto::CodecVersion &msg) {
}
// 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
@@ -1301,9 +1302,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 874a13dae..8b60edbfc 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 b097ce02a..56decaaee 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 94e81bd29..8242ea017 100644
--- a/src/mumble/ServerHandler.cpp
+++ b/src/mumble/ServerHandler.cpp
@@ -23,6 +23,7 @@
#include "NetworkConfig.h"
#include "OSInfo.h"
#include "PacketDataStream.h"
+#include "ProtoUtils.h"
#include "RichTextEditor.h"
#include "SSL.h"
#include "ServerResolver.h"
@@ -196,7 +197,7 @@ int ServerHandler::getConnectionID() const {
return connectionID;
}
-void ServerHandler::setProtocolVersion(Version::mumble_raw_version_t version) {
+void ServerHandler::setProtocolVersion(Version::full_t version) {
uiVersion = version;
m_udpPingEncoder.setProtocolVersion(version);
@@ -772,12 +773,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()));
@@ -1029,7 +1026,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 3fed29bde..74608be64 100644
--- a/src/mumble/ServerHandler.h
+++ b/src/mumble/ServerHandler.h
@@ -108,7 +108,7 @@ public:
QHash< ServerAddress, QString > qhHostnames;
ServerAddress saTargetServer;
- unsigned int uiVersion;
+ Version::full_t uiVersion;
QString qsRelease;
QString qsOS;
QString qsOSVersion;
@@ -132,7 +132,7 @@ public:
void customEvent(QEvent *evt) Q_DECL_OVERRIDE;
int getConnectionID() const;
- void setProtocolVersion(Version::mumble_raw_version_t version);
+ void setProtocolVersion(Version::full_t version);
void sendProtoMessage(const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type);
void sendMessage(const unsigned char *data, int len, bool force = false);
diff --git a/src/mumble/Usage.cpp b/src/mumble/Usage.cpp
index 7e25b11c6..de4dd3585 100644
--- a/src/mumble/Usage.cpp
+++ b/src/mumble/Usage.cpp
@@ -30,8 +30,8 @@ Usage::Usage(QObject *p) : QObject(p) {
void Usage::registerUsage() {
if (!Global::get().s.bUsage
- || Version::getRaw() < Version::getRaw(
- "1.2.3")) // Only register usage if allowed by the user and first wizard run has finished
+ || Version::get() < Version::fromComponents(
+ 1, 2, 3)) // Only register usage if allowed by the user and first wizard run has finished
return;
QDomDocument doc;
diff --git a/src/mumble/UserInformation.cpp b/src/mumble/UserInformation.cpp
index 50d7bde7f..c9668bfdd 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 e6745c80b..ae512d19a 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 324292090..e2d25e7f0 100644
--- a/src/mumble/VoiceRecorder.cpp
+++ b/src/mumble/VoiceRecorder.cpp
@@ -292,7 +292,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();
@@ -305,7 +305,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 553ad2a96..856318aad 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/main.cpp b/src/mumble/main.cpp
index da6428778..369cc9a72 100644
--- a/src/mumble/main.cpp
+++ b/src/mumble/main.cpp
@@ -419,7 +419,7 @@ int main(int argc, char **argv) {
} else if (args.at(i) == "--version" || args.at(i) == "-V") {
// Print version and exit (print to regular std::cout to avoid adding any useless meta-information from
// using e.g. qWarning
- std::cout << "Mumble version " << Version::toString(Version::getRaw()).toStdString() << std::endl;
+ std::cout << "Mumble version " << Version::getRelease().toStdString() << std::endl;
return 0;
} else {
if (PluginInstaller::canBePluginFile(args.at(i))) {
diff --git a/src/mumble/os_win.cpp b/src/mumble/os_win.cpp
index 40ee6f0f7..1452ad467 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 ea6456698..f8f23097e 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 cd370d2a7..b0ad32c43 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 74e08a6f0..769028970 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 feff38a76..7914a5927 100644
--- a/src/murmur/Messages.cpp
+++ b/src/murmur/Messages.cpp
@@ -9,6 +9,7 @@
#include "Group.h"
#include "Meta.h"
#include "MumbleConstants.h"
+#include "ProtoUtils.h"
#include "QtUtils.h"
#include "Server.h"
#include "ServerDB.h"
@@ -360,7 +361,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));
@@ -425,7 +426,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
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()))
@@ -433,7 +434,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) {
@@ -448,7 +449,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())
@@ -475,7 +476,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));
@@ -515,8 +516,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())
@@ -530,7 +532,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
@@ -692,7 +694,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;
}
}
@@ -715,7 +717,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;
}
@@ -726,7 +728,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;
}
@@ -942,7 +944,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
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;
}
@@ -1012,12 +1014,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.
@@ -1031,7 +1033,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);
@@ -1154,7 +1156,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;
}
}
@@ -1166,7 +1169,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;
}
@@ -1213,12 +1217,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
@@ -1357,12 +1361,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);
}
}
@@ -1926,9 +1930,7 @@ 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);
}
@@ -2013,7 +2015,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));
@@ -2145,10 +2147,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 c9e7f45ed..c8a6455b6 100644
--- a/src/murmur/Meta.cpp
+++ b/src/murmur/Meta.cpp
@@ -314,9 +314,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())
@@ -416,8 +414,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 63cb32696..655c841a5 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
@@ -136,7 +138,7 @@ public:
QString qsName;
#endif
- QVariant qvSuggestVersion;
+ Version::full_t m_suggestVersion;
QVariant qvSuggestPositional;
QVariant qvSuggestPushToTalk;
@@ -205,7 +207,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 472943468..60d388458 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/MurmurIce.cpp b/src/murmur/MurmurIce.cpp
index 7f806556b..900694b9e 100644
--- a/src/murmur/MurmurIce.cpp
+++ b/src/murmur/MurmurIce.cpp
@@ -112,7 +112,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);
@@ -1664,12 +1665,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();
@@ -1928,7 +1929,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 8f47ad8aa..d98a489df 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 1e4b7f7f5..d04e29c04 100644
--- a/src/murmur/RPC.cpp
+++ b/src/murmur/RPC.cpp
@@ -81,12 +81,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);
}
@@ -170,12 +170,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);
}
@@ -395,8 +395,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 40d33fdb5..cca8a9940 100644
--- a/src/murmur/Server.cpp
+++ b/src/murmur/Server.cpp
@@ -14,6 +14,7 @@
#include "HostAddress.h"
#include "Meta.h"
#include "MumbleProtocol.h"
+#include "ProtoUtils.h"
#include "QtUtils.h"
#include "ServerDB.h"
#include "ServerUser.h"
@@ -40,6 +41,7 @@
#include <TracyC.h>
#include <algorithm>
+#include <cassert>
#include <vector>
#ifdef Q_OS_WIN
@@ -229,12 +231,6 @@ Server::Server(int snum, QObject *p) : QThread(p) {
readLinks();
initializeCert();
- int major, minor, patch;
- QString release;
- Meta::getVersion(major, minor, patch, release);
-
- m_versionBlob = Version::toRaw(major, minor, patch);
-
if (bValid) {
#ifdef USE_ZEROCONF
if (bBonjour)
@@ -318,41 +314,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);
@@ -385,7 +346,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;
@@ -465,9 +426,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())
@@ -614,8 +574,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")
@@ -675,7 +634,7 @@ gsl::span< const Mumble::Protocol::byte >
if (pingData.requestAdditionalInformation) {
pingData.requestAdditionalInformation = false;
- pingData.serverVersion = m_versionBlob;
+ pingData.serverVersion = Version::get();
pingData.userCount = qhUsers.size();
pingData.maxUserCount = iMaxUsers;
pingData.maxBandwidthPerUser = iMaxBandwidth;
@@ -1530,15 +1489,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));
}
@@ -1861,18 +1816,25 @@ void Server::sendProtoMessage(ServerUser *u, const ::google::protobuf::Message &
}
void Server::sendProtoAll(const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType msgType,
- unsigned int version) {
- sendProtoExcept(nullptr, msg, msgType, version);
+ Version::full_t version, Version::CompareMode mode) {
+ sendProtoExcept(nullptr, msg, msgType, version, mode);
}
void Server::sendProtoExcept(ServerUser *u, const ::google::protobuf::Message &msg,
- Mumble::Protocol::TCPMessageType msgType, unsigned int version) {
+ Mumble::Protocol::TCPMessageType msgType, 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 7f02cf32d..31a0de69d 100644
--- a/src/murmur/Server.h
+++ b/src/murmur/Server.h
@@ -144,7 +144,7 @@ public:
unsigned int iPluginMessageLimit;
unsigned int iPluginMessageBurst;
- QVariant qvSuggestVersion;
+ Version::full_t m_suggestVersion;
QVariant qvSuggestPositional;
QVariant qvSuggestPushToTalk;
@@ -248,7 +248,6 @@ public:
HANDLE hNotify;
QList< SOCKET > qlUdpSocket;
#endif
- Version::mumble_raw_version_t m_versionBlob;
QList< QSocketNotifier * > qlUdpNotifier;
/// This lock provides synchronization between the
@@ -328,22 +327,24 @@ public:
void clearWhisperTargetCache();
void sendProtoAll(const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type,
- unsigned int minversion);
+ Version::full_t version, Version::CompareMode mode);
void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type,
- unsigned int minversion);
+ Version::full_t version, Version::CompareMode mode);
void sendProtoMessage(ServerUser *, const ::google::protobuf::Message &msg, Mumble::Protocol::TCPMessageType type);
// 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 PROCESS_MUMBLE_TCP_MESSAGE(name, value) \
- void sendAll(const MumbleProto::name &msg, unsigned int v = 0) { \
- sendProtoAll(msg, Mumble::Protocol::TCPMessageType::name, v); \
- } \
- void sendExcept(ServerUser *u, const MumbleProto::name &msg, unsigned int v = 0) { \
- sendProtoExcept(u, msg, Mumble::Protocol::TCPMessageType::name, v); \
- } \
- void sendMessage(ServerUser *u, const MumbleProto::name &msg) { \
- sendProtoMessage(u, msg, Mumble::Protocol::TCPMessageType::name); \
+#define PROCESS_MUMBLE_TCP_MESSAGE(name, value) \
+ void sendAll(const MumbleProto::name &msg, Version::full_t v = Version::UNKNOWN, \
+ Version::CompareMode mode = Version::CompareMode::AtLeast) { \
+ sendProtoAll(msg, Mumble::Protocol::TCPMessageType::name, v, mode); \
+ } \
+ void sendExcept(ServerUser *u, const MumbleProto::name &msg, Version::full_t v = Version::UNKNOWN, \
+ Version::CompareMode mode = Version::CompareMode::AtLeast) { \
+ sendProtoExcept(u, msg, Mumble::Protocol::TCPMessageType::name, v, mode); \
+ } \
+ void sendMessage(ServerUser *u, const MumbleProto::name &msg) { \
+ sendProtoMessage(u, msg, Mumble::Protocol::TCPMessageType::name); \
}
MUMBLE_ALL_TCP_MESSAGES
diff --git a/src/murmur/ServerUser.cpp b/src/murmur/ServerUser.cpp
index e9fb27b42..5c508574d 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 db469efd0..125f08e8d 100644
--- a/src/murmur/ServerUser.h
+++ b/src/murmur/ServerUser.h
@@ -114,7 +114,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 7f90cb5a0..d2d4856c0 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 dc7ffb36d..c60993555 100644
--- a/src/murmur/main.cpp
+++ b/src/murmur/main.cpp
@@ -345,7 +345,7 @@ int main(int argc, char **argv) {
} else if ((arg == "-version") || (arg == "--version") || (arg == "-V")) {
// Print version and exit (print to regular std::cout to avoid adding any useless meta-information from
// using e.g. qWarning
- std::cout << "Mumble server version " << Version::toString(Version::getRaw()).toStdString() << std::endl;
+ std::cout << "Mumble server version " << Version::getRelease().toStdString() << std::endl;
return 0;
} else if (args.at(i) == QLatin1String("-license") || args.at(i) == QLatin1String("--license")) {
#ifdef Q_OS_WIN
@@ -648,11 +648,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 0fc53c45a..0ff6668e3 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);
diff --git a/src/tests/TestAudioReceiverBuffer/ServerUser.h b/src/tests/TestAudioReceiverBuffer/ServerUser.h
index d07985227..202895ba3 100644
--- a/src/tests/TestAudioReceiverBuffer/ServerUser.h
+++ b/src/tests/TestAudioReceiverBuffer/ServerUser.h
@@ -11,12 +11,12 @@
#include <string>
struct ServerUser {
- ServerUser(unsigned int uiSession, Version::mumble_raw_version_t version, bool deaf = false, bool selfDeaf = false,
+ ServerUser(unsigned int uiSession, Version::full_t version, bool deaf = false, bool selfDeaf = false,
const std::string context = "")
: uiSession(uiSession), uiVersion(version), bDeaf(deaf), bSelfDeaf(selfDeaf), ssContext(context) {}
unsigned int uiSession;
- Version::mumble_raw_version_t uiVersion;
+ Version::full_t uiVersion;
bool bDeaf;
bool bSelfDeaf;
std::string ssContext;
diff --git a/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp b/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp
index c04188a34..857216b72 100644
--- a/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp
+++ b/src/tests/TestAudioReceiverBuffer/TestAudioReceiverBuffer.cpp
@@ -16,10 +16,9 @@
#include <QDebug>
QDebug &operator<<(QDebug &stream, const ServerUser &user) {
- int major, minor, patch;
- Version::fromRaw(user.uiVersion, &major, &minor, &patch);
- return stream.nospace() << "ServerUser{ session: " << user.uiSession << ", version: " << major << "." << minor
- << "." << patch << ", deaf: " << user.bDeaf << ", selfDeaf: " << user.bSelfDeaf
+ return stream.nospace() << "ServerUser{ session: " << user.uiSession
+ << ", version: " << Version::toString(user.uiVersion) << ", deaf: " << user.bDeaf
+ << ", selfDeaf: " << user.bSelfDeaf
<< ", ssContext: " << QString::fromStdString(user.ssContext) << " }";
}
@@ -35,10 +34,10 @@ bool operator<(const AudioReceiver &lhs, const AudioReceiver &rhs) {
}
-Version::mumble_raw_version_t vOld1 = Version::toRaw(1, 2, 5);
-Version::mumble_raw_version_t vOld2 = Version::toRaw(1, 3, 1);
-Version::mumble_raw_version_t vOld3 = Version::toRaw(1, 4, 0);
-Version::mumble_raw_version_t vNew = Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION;
+Version::full_t vOld1 = Version::fromComponents(1, 2, 5);
+Version::full_t vOld2 = Version::fromComponents(1, 3, 1);
+Version::full_t vOld3 = Version::fromComponents(1, 4, 0);
+Version::full_t vNew = Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION;
std::array< ServerUser, 5 > users = { ServerUser(0, vOld1), ServerUser(1, vOld2), ServerUser(2, vOld3),
ServerUser(3, vNew), ServerUser(4, vNew) };
@@ -61,7 +60,7 @@ class PseudoEncoder {
public:
PseudoEncoder() = default;
- bool checkRequiresEncoding(Version::mumble_raw_version_t protocolVersion, Mumble::Protocol::audio_context_t context,
+ bool checkRequiresEncoding(Version::full_t protocolVersion, Mumble::Protocol::audio_context_t context,
float volumeAdjustment) {
bool requiresEncoding = m_encodings == 0
|| !Mumble::Protocol::protocolVersionsAreCompatible(m_protocolVersion, protocolVersion)
@@ -83,10 +82,10 @@ public:
void reset() { m_encodings = 0; }
protected:
- std::size_t m_encodings = 0;
- Version::mumble_raw_version_t m_protocolVersion = Version::UNKNOWN;
- Mumble::Protocol::audio_context_t m_context = Mumble::Protocol::AudioContext::INVALID;
- float m_volumeAdjustment = 0.0f;
+ std::size_t m_encodings = 0;
+ Version::full_t m_protocolVersion = Version::UNKNOWN;
+ Mumble::Protocol::audio_context_t m_context = Mumble::Protocol::AudioContext::INVALID;
+ float m_volumeAdjustment = 0.0f;
};
class TestAudioReceiverBuffer : public QObject {
diff --git a/src/tests/TestMumbleProtocol/TestMumbleProtocol.cpp b/src/tests/TestMumbleProtocol/TestMumbleProtocol.cpp
index d284655c1..2605e6566 100644
--- a/src/tests/TestMumbleProtocol/TestMumbleProtocol.cpp
+++ b/src/tests/TestMumbleProtocol/TestMumbleProtocol.cpp
@@ -84,11 +84,9 @@ template< Mumble::Protocol::Role encoderRole, Mumble::Protocol::Role decoderRole
Mumble::Protocol::UDPPingEncoder< encoderRole > encoder;
Mumble::Protocol::UDPDecoder< decoderRole > decoder;
- for (Version::mumble_raw_version_t version :
- { Version::toRaw(1, 3, 0), Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION }) {
- int major, minor, patch;
- Version::fromRaw(version, &major, &minor, &patch);
- qWarning("Using protocol version %d.%d.%d", major, minor, patch);
+ for (Version::full_t version :
+ { Version::fromComponents(1, 3, 0), Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION }) {
+ qWarning("Using protocol version %s", Version::toString(Version::get()).toStdString().c_str());
// Note: When the decoder is set to a version < PROTOBUF_INTRODUCTION_VERSION, it can decode pings in
// either format
@@ -147,10 +145,10 @@ template< Mumble::Protocol::Role encoderRole, Mumble::Protocol::Role decoderRole
std::string payloadData = "I am the payload";
- for (Version::mumble_raw_version_t version :
- { Version::toRaw(1, 3, 0), Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION }) {
- int major, minor, patch;
- Version::fromRaw(version, &major, &minor, &patch);
+ for (Version::full_t version :
+ { Version::fromComponents(1, 3, 0), Mumble::Protocol::PROTOBUF_INTRODUCTION_VERSION }) {
+ Version::component_t major, minor, patch;
+ Version::getComponents(major, minor, patch, version);
qWarning("Using protocol version %d.%d.%d", major, minor, patch);
encoder.setProtocolVersion(version);