diff options
| author | Tobias Markmann <tm@ayena.de> | 2018-03-20 13:12:10 (GMT) | 
|---|---|---|
| committer | Tobias Markmann <tm@ayena.de> | 2018-03-20 14:48:04 (GMT) | 
| commit | f2c2c7d035029fb9615b42c18ccea83e8e705b10 (patch) | |
| tree | 2f56fb77de0f366528395f21732d418f016f63b5 /Swift/Controllers | |
| parent | 44581c5285d13c0ec715b35ddc79177e5ebeef39 (diff) | |
| parent | 5ba3f18ad8efa040d49f36d83ec2e7891a9add9f (diff) | |
| download | swift-f2c2c7d035029fb9615b42c18ccea83e8e705b10.zip swift-f2c2c7d035029fb9615b42c18ccea83e8e705b10.tar.bz2 | |
Merge branch 'swift-4.x'swift-5.0alpha2
* swift-4.x: (44 commits)
Test-Information:
Builds on macOS 10.13.3 with clang trunk.
Change-Id: If50381f103b0ad18d038b920d3d43537642141cb
Diffstat (limited to 'Swift/Controllers')
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 17 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 1 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 3 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h | 82 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 57 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp | 292 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp | 105 | ||||
| -rw-r--r-- | Swift/Controllers/Highlighting/HighlightAction.cpp | 2 | ||||
| -rw-r--r-- | Swift/Controllers/Highlighting/HighlightAction.h | 56 | ||||
| -rw-r--r-- | Swift/Controllers/SConscript | 1 | ||||
| -rw-r--r-- | Swift/Controllers/Storages/AvatarFileStorage.cpp | 31 | 
11 files changed, 577 insertions, 70 deletions
| diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 7fb9c59..5f5f41d 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -86,7 +86,7 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ      chatStateNotifier_->setContactIsOnline(theirPresence && theirPresence->getType() == Presence::Available);      startMessage += ".";      chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(startMessage), ChatWindow::DefaultDirection); -    chatWindow_->onContinuationsBroken.connect([this, startMessage]() { chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(startMessage), ChatWindow::DefaultDirection); }); +    continuationsBrokenConnection_ = chatWindow_->onContinuationsBroken.connect([this, startMessage]() { chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(startMessage), ChatWindow::DefaultDirection); });      chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_));      chatWindow_->onUserCancelsTyping.connect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_));      chatWindow_->onFileTransferStart.connect(boost::bind(&ChatController::handleFileTransferStart, this, _1, _2)); @@ -320,6 +320,7 @@ void ChatController::handleIncomingOwnMessage(std::shared_ptr<Message> message)      if (!message->getBody().get_value_or("").empty()) {          postSendMessage(message->getBody().get_value_or(""), message);          handleStanzaAcked(message); +        onActivity(message->getBody().get_value_or(""));      }  } @@ -585,8 +586,20 @@ JID ChatController::messageCorrectionJID(const JID& fromJID) {  }  ChatWindow* ChatController::detachChatWindow() { -    chatWindow_->onUserTyping.disconnect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_)); +    continuationsBrokenConnection_.disconnect(); +    chatWindow_->onClosed.disconnect(boost::bind(&ChatController::handleWindowClosed, this)); +    chatWindow_->onInviteToChat.disconnect(boost::bind(&ChatController::handleInviteToChat, this, _1)); +    chatWindow_->onUnblockUserRequest.disconnect(boost::bind(&ChatController::handleUnblockUserRequest, this)); +    chatWindow_->onBlockUserRequest.disconnect(boost::bind(&ChatController::handleBlockUserRequest, this)); +    chatWindow_->onWhiteboardWindowShow.disconnect(boost::bind(&ChatController::handleWhiteboardWindowShow, this)); +    chatWindow_->onWhiteboardSessionCancel.disconnect(boost::bind(&ChatController::handleWhiteboardSessionCancel, this)); +    chatWindow_->onWhiteboardSessionAccept.disconnect(boost::bind(&ChatController::handleWhiteboardSessionAccept, this)); +    chatWindow_->onSendFileRequest.disconnect(boost::bind(&ChatController::handleSendFileRequest, this, _1)); +    chatWindow_->onFileTransferCancel.disconnect(boost::bind(&ChatController::handleFileTransferCancel, this, _1)); +    chatWindow_->onFileTransferAccept.disconnect(boost::bind(&ChatController::handleFileTransferAccept, this, _1, _2)); +    chatWindow_->onFileTransferStart.disconnect(boost::bind(&ChatController::handleFileTransferStart, this, _1, _2));      chatWindow_->onUserCancelsTyping.disconnect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_)); +    chatWindow_->onUserTyping.disconnect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_));      return ChatControllerBase::detachChatWindow();  } diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index c65eb9c..72acc27 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -111,6 +111,7 @@ namespace Swift {              boost::signals2::scoped_connection blockingOnStateChangedConnection_;              boost::signals2::scoped_connection blockingOnItemAddedConnection_;              boost::signals2::scoped_connection blockingOnItemRemovedConnection_; +            boost::signals2::scoped_connection continuationsBrokenConnection_;              boost::optional<ChatWindow::AlertID> deliveryReceiptAlert_;              boost::optional<ChatWindow::AlertID> blockedContactAlert_; diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index f514346..b1854d8 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -58,6 +58,9 @@ void ChatControllerBase::handleContinuationsBroken() {  }  ChatWindow* ChatControllerBase::detachChatWindow() { +    chatWindow_->onContinuationsBroken.disconnect(boost::bind(&ChatControllerBase::handleContinuationsBroken, this)); +    chatWindow_->onSendMessageRequest.disconnect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2)); +    chatWindow_->onAllMessagesRead.disconnect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));      ChatWindow* chatWindow = chatWindow_;      chatWindow_ = nullptr;      return chatWindow; 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 dd74f6a..81892fc 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> @@ -43,6 +36,7 @@  #include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>  #include <Swift/Controllers/Chat/ChatController.h>  #include <Swift/Controllers/Chat/ChatControllerBase.h> +#include <Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h>  #include <Swift/Controllers/Chat/ChatMessageParser.h>  #include <Swift/Controllers/Chat/MUCController.h>  #include <Swift/Controllers/Chat/MUCSearchController.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; @@ -206,6 +164,7 @@ ChatsManager::~ChatsManager() {      roster_->onRosterCleared.disconnect(boost::bind(&ChatsManager::handleRosterCleared, this));      ftOverview_->onNewFileTransferController.disconnect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1));      delete joinMUCWindow_; +    SWIFT_LOG(debug) << "Destroying ChatsManager, containing " << chatControllers_.size() << " chats and " << mucControllers_.size() << " MUCs" << std::endl;      for (JIDChatControllerPair controllerPair : chatControllers_) {          delete controllerPair.second;      } @@ -341,7 +300,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); @@ -372,11 +331,13 @@ void ChatsManager::handleBookmarksReady() {  }  void ChatsManager::handleMUCBookmarkAdded(const MUCBookmark& bookmark) { -    std::map<JID, MUCController*>::iterator it = mucControllers_.find(bookmark.getRoom()); -    if (it == mucControllers_.end() && bookmark.getAutojoin()) { -        handleJoinMUCRequest(bookmark.getRoom(), bookmark.getPassword(), bookmark.getNick(), false, false, false  ); +    if (bookmark.getRoom().isBare() && !bookmark.getRoom().getNode().empty()) { +        std::map<JID, MUCController*>::iterator it = mucControllers_.find(bookmark.getRoom()); +        if (it == mucControllers_.end() && bookmark.getAutojoin()) { +            handleJoinMUCRequest(bookmark.getRoom(), bookmark.getPassword(), bookmark.getNick(), false, false, false  ); +        } +        chatListWindow_->addMUCBookmark(bookmark);      } -    chatListWindow_->addMUCBookmark(bookmark);  }  void ChatsManager::handleMUCBookmarkRemoved(const MUCBookmark& bookmark) { 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/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index e06a3c7..4a46b32 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -32,9 +32,12 @@  #include <Swiften/Elements/Forwarded.h>  #include <Swiften/Elements/MUCInvitationPayload.h>  #include <Swiften/Elements/MUCUserPayload.h> +#include <Swiften/Elements/PrivateStorage.h> +#include <Swiften/Elements/Storage.h>  #include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>  #include <Swiften/Jingle/JingleSessionManager.h>  #include <Swiften/MUC/MUCManager.h> +#include <Swiften/MUC/UnitTest/MockMUC.h>  #include <Swiften/Network/DummyTimerFactory.h>  #include <Swiften/Presence/DirectedPresenceSender.h>  #include <Swiften/Presence/PresenceOracle.h> @@ -71,7 +74,6 @@  #include <SwifTools/Notifier/Notifier.h>  #include <Swift/QtUI/QtSwiftUtil.h> -#include <Swiften/MUC/UnitTest/MockMUC.h>  using namespace Swift; @@ -155,6 +157,11 @@ class ChatsManagerTest : public CppUnit::TestFixture {      CPPUNIT_TEST(testImpromptuChatWindowTitle);      CPPUNIT_TEST(testStandardMUCChatWindowTitle); +    // Bookmark tests +    CPPUNIT_TEST(testReceivingBookmarksWithDomainJID); +    CPPUNIT_TEST(testReceivingBookmarksWithBareJID); +    CPPUNIT_TEST(testReceivingBookmarksWithFullJID); +      CPPUNIT_TEST_SUITE_END();  public: @@ -1228,6 +1235,11 @@ public:              CPPUNIT_ASSERT_EQUAL(forwardedBody, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));              CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_); + +            auto recentChats = manager_->getRecentChats(); +            CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1)); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, originalMessage->getFrom().toBare()); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some further text."));          }      } @@ -1264,6 +1276,11 @@ public:              CPPUNIT_ASSERT_EQUAL(true, window->lastAddedMessageSenderIsSelf_);              CPPUNIT_ASSERT_EQUAL(size_t(1), window->receiptChanges_.size());              CPPUNIT_ASSERT_EQUAL(ChatWindow::ReceiptRequested, window->receiptChanges_[0].second); + +            auto recentChats = manager_->getRecentChats(); +            CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1)); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, originalMessage->getTo().toBare()); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some text my other resource sent."));          }          // incoming carbons message for the received delivery receipt to the other resource @@ -1280,6 +1297,12 @@ public:              CPPUNIT_ASSERT_EQUAL(size_t(2), window->receiptChanges_.size());              CPPUNIT_ASSERT_EQUAL(ChatWindow::ReceiptReceived, window->receiptChanges_[1].second); + +            //Delivery receipt should not change the latest recent entry. Checking for the original message. +            auto recentChats = manager_->getRecentChats(); +            CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1)); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, messageJID.toBare()); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some text my other resource sent."));          }      } @@ -1319,6 +1342,11 @@ public:              manager_->handleIncomingMessage(messageWrapper);              CPPUNIT_ASSERT_EQUAL(std::string(), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));              CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_); + +            auto recentChats = manager_->getRecentChats(); +            CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1)); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, originalMessage->getFrom().toBare()); +            CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some further text."));          }      } @@ -1602,6 +1630,78 @@ public:          CPPUNIT_ASSERT_EQUAL(std::string("mucroom"), window->name_);      } +    static std::shared_ptr<Storage> createBookmarkStorageWithJID(const JID& jid) { +        auto storage = std::make_shared<Storage>(); +        auto room = Storage::Room(); +        room.jid = jid; +        room.autoJoin = true; +        storage->addRoom(room); +        return storage; +    } + +    void testReceivingBookmarksWithDomainJID() { +        auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]); +        CPPUNIT_ASSERT(bookmarkRequest); +        CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType()); + +        auto privateStorage = bookmarkRequest->getPayload<PrivateStorage>(); +        CPPUNIT_ASSERT(privateStorage); + +        auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload()); +        CPPUNIT_ASSERT(storage); + +        auto response = IQ::createResult( +            bookmarkRequest->getFrom(), +            bookmarkRequest->getTo(), +            bookmarkRequest->getID(), +            std::make_shared<PrivateStorage>(createBookmarkStorageWithJID("montague.lit")) +        ); +        stanzaChannel_->onIQReceived(response); +    } + +    void testReceivingBookmarksWithBareJID() { +        auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]); +        CPPUNIT_ASSERT(bookmarkRequest); +        CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType()); + +        auto privateStorage = bookmarkRequest->getPayload<PrivateStorage>(); +        CPPUNIT_ASSERT(privateStorage); + +        auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload()); +        CPPUNIT_ASSERT(storage); + +        MockChatWindow* window = new MockChatWindow(); +        mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("example@montague.lit"), uiEventStream_).Return(window); + +        auto response = IQ::createResult( +            bookmarkRequest->getFrom(), +            bookmarkRequest->getTo(), +            bookmarkRequest->getID(), +            std::make_shared<PrivateStorage>(createBookmarkStorageWithJID("example@montague.lit")) +        ); +        stanzaChannel_->onIQReceived(response); +    } + +    void testReceivingBookmarksWithFullJID() { +        auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]); +        CPPUNIT_ASSERT(bookmarkRequest); +        CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType()); + +        auto privateStorage = bookmarkRequest->getPayload<PrivateStorage>(); +        CPPUNIT_ASSERT(privateStorage); + +        auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload()); +        CPPUNIT_ASSERT(storage); + +        auto response = IQ::createResult( +            bookmarkRequest->getFrom(), +            bookmarkRequest->getTo(), +            bookmarkRequest->getID(), +            std::make_shared<PrivateStorage>(createBookmarkStorageWithJID("example@montague.lit/someresource")) +        ); +        stanzaChannel_->onIQReceived(response); +    } +  private:      std::shared_ptr<Message> makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) {          std::shared_ptr<Message> message = std::make_shared<Message>(); @@ -1668,4 +1768,3 @@ private:  };  CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest); - 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/Controllers/Storages/AvatarFileStorage.cpp b/Swift/Controllers/Storages/AvatarFileStorage.cpp index a103920..9d9b9ea 100644 --- a/Swift/Controllers/Storages/AvatarFileStorage.cpp +++ b/Swift/Controllers/Storages/AvatarFileStorage.cpp @@ -1,16 +1,15 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */  #include <Swift/Controllers/Storages/AvatarFileStorage.h> -#include <iostream> -  #include <boost/filesystem.hpp>  #include <boost/filesystem/fstream.hpp> +#include <Swiften/Base/Log.h>  #include <Swiften/Base/String.h>  #include <Swiften/Crypto/CryptoProvider.h>  #include <Swiften/StringCodecs/Hexify.h> @@ -31,13 +30,13 @@ AvatarFileStorage::AvatarFileStorage(const boost::filesystem::path& avatarsDir,                          jidAvatars.insert(std::make_pair(jid, r.first));                      }                      else if (!r.first.empty() || !r.second.empty()) { -                        std::cerr << "Invalid entry in avatars file: " << r.second << std::endl; +                        SWIFT_LOG(error) << "Invalid entry in avatars file: " << r.second << std::endl;                      }                  }              }          }          catch (...) { -            std::cerr << "Error reading avatars file" << std::endl; +            SWIFT_LOG(error) << "Error reading avatars file" << std::endl;          }      }  } @@ -55,12 +54,17 @@ void AvatarFileStorage::addAvatar(const std::string& hash, const ByteArray& avat              boost::filesystem::create_directories(avatarPath.parent_path());          }          catch (const boost::filesystem::filesystem_error& e) { -            std::cerr << "ERROR: " << e.what() << std::endl; +            SWIFT_LOG(error) << "filesystem error: " << e.what() << std::endl;          }      } -    boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); -    file.write(reinterpret_cast<const char*>(vecptr(avatar)), static_cast<std::streamsize>(avatar.size())); -    file.close(); + +    try { +        boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); +        file.write(reinterpret_cast<const char*>(vecptr(avatar)), static_cast<std::streamsize>(avatar.size())); +    } +    catch (const boost::filesystem::filesystem_error& e) { +        SWIFT_LOG(error) << "filesystem error: " << e.what() << std::endl; +    }  }  boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash) const { @@ -69,7 +73,12 @@ boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash  ByteArray AvatarFileStorage::getAvatar(const std::string& hash) const {      ByteArray data; -    readByteArrayFromFile(data, getAvatarPath(hash)); +    try { +        readByteArrayFromFile(data, getAvatarPath(hash)); +    } +    catch (const boost::filesystem::filesystem_error& e) { +        SWIFT_LOG(error) << "filesystem error: " << e.what() << std::endl; +    }      return data;  } @@ -98,7 +107,7 @@ void AvatarFileStorage::saveJIDAvatars() {          file.close();      }      catch (...) { -        std::cerr << "Error writing avatars file" << std::endl; +        SWIFT_LOG(error) << "Error writing avatars file" << std::endl;      }  } | 
 Swift
 Swift