summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--BuildTools/SCons/SConscript.boot1
-rw-r--r--BuildTools/SCons/SConstruct7
-rw-r--r--Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h82
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp46
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp292
-rw-r--r--Swift/Controllers/Highlighting/HighlightAction.cpp2
-rw-r--r--Swift/Controllers/Highlighting/HighlightAction.h56
-rw-r--r--Swift/Controllers/SConscript1
-rw-r--r--Swift/SConscript6
9 files changed, 441 insertions, 52 deletions
diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot
index f815bbc..6ac4981 100644
--- a/BuildTools/SCons/SConscript.boot
+++ b/BuildTools/SCons/SConscript.boot
@@ -53,6 +53,7 @@ vars.Add(PathVariable("boost_includedir", "Boost headers location", None, PathVa
vars.Add(PathVariable("boost_libdir", "Boost library location", None, PathVariable.PathAccept))
vars.Add(BoolVariable("boost_bundled_enable", "Allow use of bundled Boost as last resort", "true"))
vars.Add(BoolVariable("boost_force_bundled", "Force use of bundled Boost.", False))
+vars.Add(BoolVariable("allow_boost_1_64", "Allow use of Boost 1.64", False))
vars.Add(PathVariable("zlib_includedir", "Zlib headers location", None, PathVariable.PathAccept))
vars.Add(PathVariable("zlib_libdir", "Zlib library location", None, PathVariable.PathAccept))
vars.Add(PathVariable("zlib_libfile", "Zlib library file (full path to file)", None, PathVariable.PathAccept))
diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct
index 2c2d629..6d63d5b 100644
--- a/BuildTools/SCons/SConstruct
+++ b/BuildTools/SCons/SConstruct
@@ -242,6 +242,12 @@ elif not env.get("boost_bundled_enable", True) :
Exit(1)
else :
env["BOOST_BUNDLED"] = True
+boost_version = GetVersion(conf, "BOOST_VERSION", "boost/version.hpp")
+if boost_version == 106400 :
+ #Version 1.64 has some issues with the serialization of boost::optional, see https://svn.boost.org/trac10/ticket/13050
+ env["BOOST_1_64_DETECTED"] = True
+else:
+ env["BOOST_1_64_DETECTED"] = False
conf.Finish()
@@ -780,4 +786,3 @@ print
if not GetOption("help") and not env.get("HAVE_OPENSSL", 0) and not env.get("HAVE_SCHANNEL", 0) and not env.get("HAVE_SECURETRANSPORT", 0):
print "Error: A working TLS backend is required. Please check the documentation for more information."
Exit(1)
-
diff --git a/Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h b/Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h
new file mode 100644
index 0000000..1e053b2
--- /dev/null
+++ b/Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <boost/version.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/bind.hpp>
+#include <boost/serialization/map.hpp>
+#include <boost/serialization/optional.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
+
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
+
+BOOST_CLASS_VERSION(Swift::ChatListWindow::Chat, 3)
+namespace Swift {
+ const boost::archive::library_version_type BoostArchiveSkipVersion(15);
+}
+
+namespace boost {
+ namespace serialization {
+ template<class Archive> void save(Archive& ar, const Swift::JID& jid, const unsigned int /*version*/) {
+ std::string jidStr = jid.toString();
+ ar << jidStr;
+ }
+
+ template<class Archive> void load(Archive& ar, Swift::JID& jid, const unsigned int /*version*/) {
+ std::string stringJID;
+ ar >> stringJID;
+ jid = Swift::JID(stringJID);
+ }
+
+ template<class Archive> inline void serialize(Archive& ar, Swift::JID& t, const unsigned int file_version) {
+ split_free(ar, t, file_version);
+ }
+
+ template<class Archive> void serialize(Archive& ar, Swift::ChatListWindow::Chat& chat, const unsigned int version) {
+ auto archiveLibraryVersion = boost::archive::BOOST_ARCHIVE_VERSION();
+ int archiveVersion = 0;
+ archive::text_oarchive* outputStream = dynamic_cast<archive::text_oarchive*>(&ar);
+ if (outputStream) {
+ archiveVersion = outputStream->get_library_version();
+ }
+ archive::text_iarchive* inputStream = dynamic_cast<archive::text_iarchive*>(&ar);
+ if (inputStream) {
+ archiveVersion = inputStream->get_library_version();
+ //Due to https://svn.boost.org/trac10/ticket/13050 the password field may fail to load and crash the client. Therefore we skip loading the values from previous versions.
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion && archiveLibraryVersion > archiveVersion) {
+ return;
+ }
+ }
+ ar & chat.jid;
+ ar & chat.chatName;
+ ar & chat.activity;
+ ar & chat.isMUC;
+ ar & chat.nick;
+ ar & chat.impromptuJIDs;
+ if (version > 0) {
+ if (outputStream && archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ //The bug does not affect the case boost::optional doesn't have a value. Therefore we store always that value, to avoid problem on future launches of the client.
+ boost::optional<std::string> empty;
+ ar & empty;
+ }
+ else {
+ ar & chat.password;
+ }
+ }
+ if (version > 1) {
+ ar & chat.inviteesNames;
+ }
+ }
+ }
+}
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index b7087fd..95a9f64 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -9,14 +9,7 @@
#include <memory>
#include <boost/algorithm/string.hpp>
-#include <boost/archive/text_iarchive.hpp>
-#include <boost/archive/text_oarchive.hpp>
#include <boost/bind.hpp>
-#include <boost/serialization/map.hpp>
-#include <boost/serialization/optional.hpp>
-#include <boost/serialization/split_free.hpp>
-#include <boost/serialization/string.hpp>
-#include <boost/serialization/vector.hpp>
#include <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Base/Log.h>
@@ -40,6 +33,7 @@
#include <Swiften/StringCodecs/Base64.h>
#include <Swiften/VCards/VCardManager.h>
+#include <Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h>
#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatControllerBase.h>
@@ -67,42 +61,6 @@
#include <Swift/Controllers/WhiteboardManager.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
-BOOST_CLASS_VERSION(Swift::ChatListWindow::Chat, 2)
-
-namespace boost {
-namespace serialization {
- template<class Archive> void save(Archive& ar, const Swift::JID& jid, const unsigned int /*version*/) {
- std::string jidStr = jid.toString();
- ar << jidStr;
- }
-
- template<class Archive> void load(Archive& ar, Swift::JID& jid, const unsigned int /*version*/) {
- std::string stringJID;
- ar >> stringJID;
- jid = Swift::JID(stringJID);
- }
-
- template<class Archive> inline void serialize(Archive& ar, Swift::JID& t, const unsigned int file_version){
- split_free(ar, t, file_version);
- }
-
- template<class Archive> void serialize(Archive& ar, Swift::ChatListWindow::Chat& chat, const unsigned int version) {
- ar & chat.jid;
- ar & chat.chatName;
- ar & chat.activity;
- ar & chat.isMUC;
- ar & chat.nick;
- ar & chat.impromptuJIDs;
- if (version > 0) {
- ar & chat.password;
- }
- if (version > 1) {
- ar & chat.inviteesNames;
- }
- }
-}
-}
-
namespace Swift {
typedef std::pair<JID, ChatController*> JIDChatControllerPair;
@@ -341,7 +299,7 @@ void ChatsManager::loadRecents() {
SWIFT_LOG(debug) << "Failed to load recents: " << e.what() << std::endl;
return;
}
-
+ recentChats.erase(std::remove(recentChats.begin(), recentChats.end(), ChatListWindow::Chat()), recentChats.end());
for (auto chat : recentChats) {
chat.statusType = StatusShow::None;
chat = updateChatStatusAndAvatarHelper(chat);
diff --git a/Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp
new file mode 100644
index 0000000..9561e2b
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/version.hpp>
+
+#include <gtest/gtest.h>
+
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/StringCodecs/Base64.h>
+
+#include <Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
+
+using namespace Swift;
+
+class ChatListWindowChatTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ void testOptionalPasswordValue(const boost::optional<std::string>& value1, const std::string& value2) {
+ auto archiveLibraryVersion = boost::archive::BOOST_ARCHIVE_VERSION();
+ if (archiveLibraryVersion != Swift::BoostArchiveSkipVersion) {
+ EXPECT_EQ(value1.get_value_or(""), value2);
+ }
+ else {
+ EXPECT_EQ(value1.get_value_or(""), "");
+ }
+ }
+
+ std::string chatsSerialise(const std::vector<ChatListWindow::Chat>& chats) {
+ std::stringstream serializeStream;
+ boost::archive::text_oarchive oa(serializeStream);
+ oa & chats;
+ std::string serializedStr = Base64::encode(createByteArray(serializeStream.str()));
+ return serializedStr;
+ }
+
+ std::vector<ChatListWindow::Chat> chatsDeserialise(const std::string& b64chats) {
+ ByteArray debase64 = Base64::decode(b64chats);
+ std::vector<ChatListWindow::Chat> recentChats;
+ std::stringstream deserializeStream(std::string(reinterpret_cast<const char*>(vecptr(debase64)), debase64.size()));
+ try {
+ boost::archive::text_iarchive ia(deserializeStream);
+ ia >> recentChats;
+ }
+ catch (const boost::archive::archive_exception& e) {
+ EXPECT_TRUE(false) << "Archive Version:" << boost::archive::BOOST_ARCHIVE_VERSION() << " " << e.what() << std::endl;
+ recentChats.clear();
+ return recentChats;
+ }
+ recentChats.erase(std::remove(recentChats.begin(), recentChats.end(), ChatListWindow::Chat()), recentChats.end());
+ return recentChats;
+ }
+};
+
+TEST_F(ChatListWindowChatTest, testNormalSerialization) {
+ ChatListWindow::Chat chat1("swift@rooms.swift.im", "swift@rooms.swift.im", "Some text 0", 0, StatusShow::None, "", false, false, "Nick Name");
+ ChatListWindow::Chat chat2("testuser1@domain.com", "swift@rooms2.swift.im", "Some text 1", 0, StatusShow::None, "", false, false, "Nick Name", std::string("pass"));
+ ChatListWindow::Chat chat3("testuser2@domain.com", "room 2", "Some text 2", 0, StatusShow::None, "", true, false, "Nick Name");
+ ChatListWindow::Chat chat4("testuser3@domain.com", "room 3", "Some text 2", 0, StatusShow::None, "", true, false, "Nick Name", std::string("pass"));
+
+ std::map<std::string, JID> impromptuJIDs;
+ impromptuJIDs["testuser1@domain.com"] = "testuser1@domain.com";
+ impromptuJIDs["testuser2@domain.com"] = "testuser2@domain.com";
+ std::map<JID, std::string> inviteesNames;
+ inviteesNames["user1@domain.com"] = "user1@domain.com";
+
+ chat3.impromptuJIDs = impromptuJIDs;
+ chat3.inviteesNames = inviteesNames;
+ chat4.impromptuJIDs = impromptuJIDs;
+ chat4.inviteesNames = inviteesNames;
+
+ std::vector<ChatListWindow::Chat> chats;
+ chats.push_back(chat1);
+ chats.push_back(chat2);
+ chats.push_back(chat3);
+ chats.push_back(chat4);
+
+ auto base64 = chatsSerialise(chats);
+ ASSERT_TRUE(base64.size() > 0);
+ auto restoredChats = chatsDeserialise(base64);
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+ testOptionalPasswordValue(restoredChats[0].password, "");
+ EXPECT_EQ(restoredChats[0].inviteesNames.size(), 0);
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+ testOptionalPasswordValue(restoredChats[1].password, "pass");
+ EXPECT_EQ(restoredChats[1].inviteesNames.size(), 0);
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ testOptionalPasswordValue(restoredChats[2].password, "");
+ ASSERT_EQ(restoredChats[2].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[2].inviteesNames["user1@domain.com"], "user1@domain.com");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ testOptionalPasswordValue(restoredChats[3].password, "pass");
+ ASSERT_EQ(restoredChats[3].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[3].inviteesNames["user1@domain.com"], "user1@domain.com");
+}
+
+TEST_F(ChatListWindowChatTest, testVersionsSerialization) {
+ auto archiveLibraryVersion = boost::archive::BOOST_ARCHIVE_VERSION();
+ /*
+ The following strings are base64 serialised vectors with these Swift::ChatListWindow::Chat elements:
+
+ Chat1: Jid = "swift@rooms.swift.im", ChatName = "swift@rooms.swift.im", Activity = "Some text 0", isMUC = false, nick="Nick Name"
+ Chat2: Jid = "testuser1@domain.com", ChatName = "swift@rooms2.swift.im", Activity = "Some text 1", isMUC = false, nick="Nick Name", password = "pass"
+ Chat3: Jid = "testuser2@domain.com", ChatName = "room2", Activity = "Some text 2", isMUC = true, nick="Nick Name", impromptuJIDs, inviteesNames
+ Chat4: Jid = "testuser3@domain.com", ChatName = "room3", Activity = "Some text 2", isMUC = true, nick="Nick Name", impromptuJIDs, password = "pass", inviteesNames
+
+ impromptuJIDs = {("testuser1@domain.com","testuser1@domain.com"), ("testuser2@domain.com", "testuser2@domain.com")}
+ inviteesNames = {("user1@domain.com","user1@domain.com")}
+ */
+ std::string serializedChats_BoostArchiveV10_ClassVersion_0 = "MjIgc2VyaWFsaXphdGlvbjo6YXJjaGl2ZSAxMCAwIDAgNCAwIDAgMCAwIDAgMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMTEgU29tZSB0ZXh0IDAgMCA5IE5pY2sgTmFtZSAwIDAgMCAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIxIHN3aWZ0QHJvb21zMi5zd2lmdC5pbSAxMSBTb21lIHRleHQgMSAwIDkgTmljayBOYW1lIDAgMCAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSA2IHJvb20gMiAxMSBTb21lIHRleHQgMiAxIDkgTmljayBOYW1lIDIgMCAwIDAgMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIzQGRvbWFpbi5jb20gNiByb29tIDMgMTEgU29tZSB0ZXh0IDIgMSA5IE5pY2sgTmFtZSAyIDAgMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20=";
+ {
+ auto restoredChats = chatsDeserialise(serializedChats_BoostArchiveV10_ClassVersion_0);
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ ASSERT_EQ(restoredChats.size(), 0);
+ }
+ else {
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ }
+ }
+
+ std::string serializedChats_BoostArchiveV10_ClassVersion_1 = "MjIgc2VyaWFsaXphdGlvbjo6YXJjaGl2ZSAxMCAwIDAgNCAxIDAgMSAwIDAgMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMTEgU29tZSB0ZXh0IDAgMCA5IE5pY2sgTmFtZSAwIDAgMCAwIDAgMCAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIxIHN3aWZ0QHJvb21zMi5zd2lmdC5pbSAxMSBTb21lIHRleHQgMSAwIDkgTmljayBOYW1lIDAgMCAxIDAgNCBwYXNzIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDYgcm9vbSAyIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDAgMCAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAwIDIwIHRlc3R1c2VyM0Bkb21haW4uY29tIDYgcm9vbSAzIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDEgMCA0IHBhc3M=";
+ {
+ auto restoredChats = chatsDeserialise(serializedChats_BoostArchiveV10_ClassVersion_1);
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ ASSERT_EQ(restoredChats.size(), 0);
+ }
+ else {
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[0].password.get_value_or(""), "");
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[1].password.get_value_or(""), "pass");
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].password.get_value_or(""), "");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[3].password.get_value_or(""), "pass");
+ }
+ }
+
+ std::string serializedChats_BoostArchiveV10_ClassVersion_2 = "MjIgc2VyaWFsaXphdGlvbjo6YXJjaGl2ZSAxMCAwIDAgNCAyIDAgMiAwIDAgMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMTEgU29tZSB0ZXh0IDAgMCA5IE5pY2sgTmFtZSAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjEgc3dpZnRAcm9vbXMyLnN3aWZ0LmltIDExIFNvbWUgdGV4dCAxIDAgOSBOaWNrIE5hbWUgMCAwIDEgMCA0IHBhc3MgMCAwIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDYgcm9vbSAyIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDAgMCAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAwIDEgMCAwIDAgMTYgdXNlcjFAZG9tYWluLmNvbSAxNiB1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyM0Bkb21haW4uY29tIDYgcm9vbSAzIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDEgMCA0IHBhc3MgMSAwIDE2IHVzZXIxQGRvbWFpbi5jb20gMTYgdXNlcjFAZG9tYWluLmNvbQ==";
+ {
+ auto restoredChats = chatsDeserialise(serializedChats_BoostArchiveV10_ClassVersion_2);
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ ASSERT_EQ(restoredChats.size(), 0);
+ }
+ else {
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[0].password.get_value_or(""), "");
+ EXPECT_EQ(restoredChats[0].inviteesNames.size(), 0);
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[1].password.get_value_or(""), "pass");
+ EXPECT_EQ(restoredChats[1].inviteesNames.size(), 0);
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].password.get_value_or(""), "");
+ ASSERT_EQ(restoredChats[2].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[2].inviteesNames["user1@domain.com"], "user1@domain.com");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[3].password.get_value_or(""), "pass");
+ ASSERT_EQ(restoredChats[3].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[3].inviteesNames["user1@domain.com"], "user1@domain.com");
+ }
+ }
+}
+
diff --git a/Swift/Controllers/Highlighting/HighlightAction.cpp b/Swift/Controllers/Highlighting/HighlightAction.cpp
index e9f14df..60ace42 100644
--- a/Swift/Controllers/Highlighting/HighlightAction.cpp
+++ b/Swift/Controllers/Highlighting/HighlightAction.cpp
@@ -12,6 +12,8 @@
#include <Swift/Controllers/Highlighting/HighlightAction.h>
+BOOST_CLASS_VERSION(Swift::HighlightAction, 1)
+
namespace Swift {
diff --git a/Swift/Controllers/Highlighting/HighlightAction.h b/Swift/Controllers/Highlighting/HighlightAction.h
index da92901..d11f3ec 100644
--- a/Swift/Controllers/Highlighting/HighlightAction.h
+++ b/Swift/Controllers/Highlighting/HighlightAction.h
@@ -12,11 +12,14 @@
#pragma once
+#include <map>
+#include <memory>
#include <string>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/optional.hpp>
+#include <boost/serialization/map.hpp>
#include <boost/serialization/optional.hpp>
namespace Swift {
@@ -57,12 +60,53 @@ namespace Swift {
bool operator ==(const HighlightAction& a, const HighlightAction& b);
bool operator !=(const HighlightAction& a, const HighlightAction& b);
+
template<class Archive>
- void HighlightAction::serialize(Archive& ar, const unsigned int /*version*/) {
- ar & frontColor_;
- ar & backColor_;
- ar & soundFilePath_;
- ar & systemNotificaitonEnabled_;
+ void HighlightAction::serialize(Archive& ar, const unsigned int version) {
+ auto inputStream = dynamic_cast<boost::archive::text_iarchive*>(&ar);
+ auto outputStream = dynamic_cast<boost::archive::text_oarchive*>(&ar);
+
+ if (version == 0) {
+ if (inputStream) {
+ const boost::archive::library_version_type BoostArchiveSkipVersion(15);
+ auto archiveLibraryVersion = boost::archive::BOOST_ARCHIVE_VERSION();
+ //Due to https://svn.boost.org/trac10/ticket/13050 the boost::optional fields may fail to load and crash the client. Therefore we skip loading the values from previous versions.
+ if (archiveLibraryVersion == BoostArchiveSkipVersion && archiveLibraryVersion > inputStream->get_library_version()) {
+ return;
+ }
+ }
+ ar & frontColor_;
+ ar & backColor_;
+ ar & soundFilePath_;
+ ar & systemNotificaitonEnabled_;
+ }
+ else if (version == 1) {
+ //Using a map instead of optional values that may cause a problems when serialised with boost::archive 15 version
+ std::map<std::string, std::string> properties;
+ if (outputStream) {
+ if (frontColor_.is_initialized()) {
+ properties["frontColor"] = frontColor_.get();
+ }
+ if (backColor_.is_initialized()) {
+ properties["backColor"] = backColor_.get();
+ }
+ if (soundFilePath_.is_initialized()) {
+ properties["soundFilePath"] = soundFilePath_.get();
+ }
+ }
+ ar & properties;
+ ar & systemNotificaitonEnabled_;
+ if (inputStream) {
+ if (properties.find("frontColor") != properties.end()) {
+ frontColor_ = properties["frontColor"];
+ }
+ if (properties.find("backColor") != properties.end()) {
+ backColor_ = properties["backColor"];
+ }
+ if (properties.find("soundFilePath") != properties.end()) {
+ soundFilePath_ = properties["soundFilePath"];
+ }
+ }
+ }
}
-
}
diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript
index 0c3127c..bc5c2c0 100644
--- a/Swift/Controllers/SConscript
+++ b/Swift/Controllers/SConscript
@@ -93,6 +93,7 @@ if env["SCONS_STAGE"] == "build" :
])
env.Append(UNITTEST_SOURCES = [
+ File("Chat/UnitTest/ChatListWindowChatTest.cpp"),
File("Chat/UnitTest/ChatMessageParserTest.cpp"),
File("Chat/UnitTest/ChatsManagerTest.cpp"),
File("Chat/UnitTest/MUCControllerTest.cpp"),
diff --git a/Swift/SConscript b/Swift/SConscript
index daff755..863597a 100644
--- a/Swift/SConscript
+++ b/Swift/SConscript
@@ -13,5 +13,9 @@ if env["SCONS_STAGE"] == "build" :
try :
SConscript("QtUI/SConscript")
except Exception as e:
- print "Warning: %s" % str(e)
+ print "Warning: %s" % str(e)
env["PROJECTS"].remove("Swift")
+if "Swift" in env["PROJECTS"] and env["BOOST_1_64_DETECTED"] and not env.get("allow_boost_1_64") and not env.GetOption("clean") :
+ #Version 1.64 has some issues with the serialization of boost::optional, see https://svn.boost.org/trac10/ticket/13050
+ print "Boost 1.64 has been detected. It is not recommended to use this version due to a regression within the library. Swift has been removed from the current build. You can still use this version by setting allow_boost_1_64 to true, but recent chats and highlighting rules will reset."
+ env["PROJECTS"].remove("Swift")