summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp21
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h3
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp73
-rw-r--r--Swift/Controllers/UIInterfaces/ChatListWindow.h36
-rw-r--r--Swift/QtUI/ChatList/ChatListRecentItem.cpp2
-rw-r--r--Swiften/Base/Algorithm.h8
-rw-r--r--Swiften/Client/DummyStanzaChannel.h14
7 files changed, 140 insertions, 17 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index db3b3b7..9db343f 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -67,7 +67,7 @@
#include <Swift/Controllers/WhiteboardManager.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
-BOOST_CLASS_VERSION(Swift::ChatListWindow::Chat, 1)
+BOOST_CLASS_VERSION(Swift::ChatListWindow::Chat, 2)
namespace boost {
namespace serialization {
@@ -96,6 +96,9 @@ namespace serialization {
if (version > 0) {
ar & chat.password;
}
+ if (version > 1) {
+ ar & chat.inviteesNames;
+ }
}
}
}
@@ -402,6 +405,12 @@ ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const
ChatListWindow::Chat chat = ChatListWindow::Chat(jid, jid.toString(), activity, unreadCount, type, boost::filesystem::path(), true, privateMessage, nick, password);
std::map<std::string, JID> participants = controller->getParticipantJIDs();
chat.impromptuJIDs = participants;
+
+ std::map<JID, std::string> participantsNames;
+ for (auto& i : invitees_[jid]) {
+ participantsNames.emplace(i, roster_->getNameForJID(i));
+ }
+ chat.inviteesNames = participantsNames;
return chat;
}
}
@@ -488,7 +497,8 @@ void ChatsManager::cleanupPrivateMessageRecents() {
void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) {
boost::optional<ChatListWindow::Chat> oldChat = removeExistingChat(chat);
ChatListWindow::Chat mergedChat = chat;
- if (oldChat && !oldChat->impromptuJIDs.empty()) {
+ if (oldChat) {
+ mergedChat.inviteesNames.insert(oldChat->inviteesNames.begin(), oldChat->inviteesNames.end());
mergedChat.impromptuJIDs.insert(oldChat->impromptuJIDs.begin(), oldChat->impromptuJIDs.end());
}
recentChats_.push_front(mergedChat);
@@ -497,7 +507,8 @@ void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) {
void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) {
boost::optional<ChatListWindow::Chat> oldChat = removeExistingChat(chat);
ChatListWindow::Chat mergedChat = chat;
- if (oldChat && !oldChat->impromptuJIDs.empty()) {
+ if (oldChat) {
+ mergedChat.inviteesNames.insert(oldChat->inviteesNames.begin(), oldChat->inviteesNames.end());
mergedChat.impromptuJIDs.insert(oldChat->impromptuJIDs.begin(), oldChat->impromptuJIDs.end());
}
recentChats_.push_back(mergedChat);
@@ -590,6 +601,10 @@ void ChatsManager::handleUIEvent(std::shared_ptr<UIEvent> event) {
// The room JID is random for new impromptu rooms, or a predefined JID for impromptu rooms resumed from the 'Recent chats' list.
JID roomJID = createImpromptuMUCEvent->getRoomJID().toString().empty() ? JID(idGenerator_.generateID(), localMUCServiceJID_) : createImpromptuMUCEvent->getRoomJID();
+ std::vector<JID> missingJIDsToInvite = createImpromptuMUCEvent->getJIDs();
+ for (const JID& jid : missingJIDsToInvite) {
+ invitees_[roomJID].insert(jid);
+ }
// join muc
MUC::ref muc = handleJoinMUCRequest(roomJID, boost::optional<std::string>(), nickResolver_->jidToNick(jid_), false, true, true);
mucControllers_[roomJID]->onImpromptuConfigCompleted.connect(boost::bind(&ChatsManager::finalizeImpromptuJoin, this, muc, createImpromptuMUCEvent->getJIDs(), createImpromptuMUCEvent->getReason(), boost::optional<JID>()));
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 593624d..6004347 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -9,6 +9,7 @@
#include <map>
#include <memory>
#include <string>
+#include <set>
#include <Swiften/Base/IDGenerator.h>
#include <Swiften/Elements/DiscoInfo.h>
@@ -181,5 +182,7 @@ namespace Swift {
AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
IDGenerator idGenerator_;
VCardManager* vcardManager_;
+
+ std::map<JID, std::set<JID>> invitees_;
};
}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index bf645d0..52537a9 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -16,6 +16,8 @@
#include <Swiften/Avatars/AvatarMemoryStorage.h>
#include <Swiften/Avatars/NullAvatarManager.h>
#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/Log.h>
+#include <Swiften/Base/LogSerializers.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/DummyStanzaChannel.h>
@@ -52,6 +54,7 @@
#include <Swift/Controllers/ProfileSettingsProvider.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
@@ -67,6 +70,9 @@
#include <SwifTools/Notifier/Notifier.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swiften/MUC/UnitTest/MockMUC.h>
+
using namespace Swift;
class DummyNotifier : public Notifier {
@@ -137,7 +143,6 @@ class ChatsManagerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testCarbonsForwardedOutgoingMessageFromSecondResource);
CPPUNIT_TEST(testCarbonsForwardedIncomingDuplicates);
-
// Message correction tests
CPPUNIT_TEST(testChatControllerMessageCorrectionCorrectReplaceID);
CPPUNIT_TEST(testChatControllerMessageCorrectionIncorrectReplaceID);
@@ -145,6 +150,9 @@ class ChatsManagerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testChatControllerMessageCorrectionReplaceByOtherResource);
CPPUNIT_TEST(testMUCControllerMessageCorrectionNoIDMatchRequired);
+ //Imptomptu test
+ CPPUNIT_TEST(testImpromptuChatTitle);
+
CPPUNIT_TEST_SUITE_END();
public:
@@ -1503,6 +1511,69 @@ public:
CPPUNIT_ASSERT_EQUAL(std::string("Some correctly spelled message."), window->bodyFromMessage(window->lastReplacedMessage_));
}
+ void testImpromptuChatTitle() {
+ stanzaChannel_->uniqueIDs_ = true;
+ JID mucJID("795B7BBE-9099-4A0D-81BA-C816F78E275C@test.com");
+ manager_->setOnline(true);
+
+ // Open chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+ std::shared_ptr<IQ> infoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ CPPUNIT_ASSERT(infoRequest);
+
+ std::shared_ptr<IQ> infoResponse = IQ::createResult(infoRequest->getFrom(), infoRequest->getTo(), infoRequest->getID());
+
+ DiscoInfo info;
+ info.addIdentity(DiscoInfo::Identity("Shakespearean Chat Service", "conference", "text"));
+ info.addFeature("http://jabber.org/protocol/muc");
+ infoResponse->addPayload(std::make_shared<DiscoInfo>(info));
+ stanzaChannel_->onIQReceived(infoResponse);
+
+ std::vector<JID> jids;
+ jids.emplace_back("foo@test.com");
+ jids.emplace_back("bar@test.com");
+
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+ uiEventStream_->send(std::make_shared<CreateImpromptuMUCUIEvent>(jids, mucJID, ""));
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
+
+ auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[2]);
+ CPPUNIT_ASSERT(mucJoinPresence);
+
+ // MUC presence reply
+ auto mucResponse = Presence::create();
+ mucResponse->setTo(jid_);
+ mucResponse->setFrom(mucJoinPresence->getTo());
+ mucResponse->addPayload([]() {
+ auto mucUser = std::make_shared<MUCUserPayload>();
+ mucUser->addItem(MUCItem(MUCOccupant::Member, MUCOccupant::Participant));
+ mucUser->addStatusCode(MUCUserPayload::StatusCode(110));
+ mucUser->addStatusCode(MUCUserPayload::StatusCode(210));
+ return mucUser;
+ }());
+ stanzaChannel_->onPresenceReceived(mucResponse);
+
+ // Before people join the impromptu room, the title is based on names coming from Roster
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
+
+ auto mucParticipantJoined = [&](const JID& jid) {
+ auto participantJoinedPresence = Presence::create();
+ participantJoinedPresence->setTo(jid_);
+ participantJoinedPresence->setFrom(mucJID.withResource(jid.toString()));
+ auto mucUser = std::make_shared<MUCUserPayload>();
+ mucUser->addItem(MUCItem(MUCOccupant::Member, MUCOccupant::Participant));
+ participantJoinedPresence->addPayload(mucUser);
+ return participantJoinedPresence;
+ };
+
+ for (const auto& participantJID : jids) {
+ stanzaChannel_->onPresenceReceived(mucParticipantJoined(participantJID));
+ }
+
+ // After people joined, the title is the list of participant nicknames or names coming from Roster (if nicknames are unavailable)
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
+ }
+
private:
std::shared_ptr<Message> makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) {
diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h
index dde596e..29097e9 100644
--- a/Swift/Controllers/UIInterfaces/ChatListWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h
@@ -11,9 +11,12 @@
#include <memory>
#include <set>
+
+#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/signals2.hpp>
+#include <Swiften/Base/Algorithm.h>
#include <Swiften/Elements/StatusShow.h>
#include <Swiften/MUC/MUCBookmark.h>
@@ -31,6 +34,9 @@ namespace Swift {
return jid.toBare() == other.jid.toBare()
&& isMUC == other.isMUC;
}
+ if (chatName == other.chatName) {
+ return true;
+ }
else { /* compare the chat occupant lists */
for (const auto& jid : impromptuJIDs) {
bool found = false;
@@ -44,7 +50,7 @@ namespace Swift {
return false;
}
}
- return true;
+ return key_compare(inviteesNames, other.inviteesNames);
}
}
void setUnreadCount(int unread) {
@@ -57,15 +63,28 @@ namespace Swift {
avatarPath = path;
}
std::string getImpromptuTitle() const {
- std::string title;
- for (auto& pair : impromptuJIDs) {
- if (title.empty()) {
- title += pair.first;
- } else {
- title += ", " + pair.first;
+ std::set<std::string> participants;
+ std::map<JID, std::string> participantsMap;
+
+ for (auto& pair : inviteesNames) {
+ if (!pair.second.empty()) {
+ participantsMap[pair.first] = pair.second;
}
+ else {
+ participantsMap[pair.first] = pair.first.toString();
+ }
+ }
+ for (auto& pair : impromptuJIDs) {
+ participantsMap[pair.second] = pair.first;
}
- return title;
+ for (auto& participant : participantsMap) {
+ participants.insert(participant.second);
+ }
+ return boost::algorithm::join(participants, ", ");
+ }
+ std::string getTitle() const {
+ std::string title = getImpromptuTitle();
+ return title.empty() ? chatName : title;
}
JID jid;
std::string chatName;
@@ -77,6 +96,7 @@ namespace Swift {
int unreadCount;
boost::filesystem::path avatarPath;
std::map<std::string, JID> impromptuJIDs;
+ std::map<JID, std::string> inviteesNames;
bool isPrivateMessage;
};
virtual ~ChatListWindow();
diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp
index faac937..9e55e1b 100644
--- a/Swift/QtUI/ChatList/ChatListRecentItem.cpp
+++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp
@@ -22,7 +22,7 @@ const ChatListWindow::Chat& ChatListRecentItem::getChat() const {
QVariant ChatListRecentItem::data(int role) const {
switch (role) {
- case Qt::DisplayRole: return chat_.impromptuJIDs.empty() ? P2QSTRING(chat_.chatName) : P2QSTRING(chat_.getImpromptuTitle());
+ case Qt::DisplayRole: return P2QSTRING(chat_.getTitle());
case DetailTextRole: return P2QSTRING(chat_.activity);
case Qt::TextColorRole: return QColor(89,89,89);
/*case Qt::BackgroundColorRole: return backgroundColor_;
diff --git a/Swiften/Base/Algorithm.h b/Swiften/Base/Algorithm.h
index c481aa8..108dbe3 100644
--- a/Swiften/Base/Algorithm.h
+++ b/Swiften/Base/Algorithm.h
@@ -152,4 +152,12 @@ namespace Swift {
private:
V value;
};
+
+ template <typename Map>
+ bool key_compare(Map const& lhs, Map const& rhs) {
+
+ auto pred = [](decltype(*lhs.begin()) a, decltype(a) b) { return a.first == b.first; };
+
+ return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred);
+ }
}
diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h
index fc2f05b..4cc0f7e 100644
--- a/Swiften/Client/DummyStanzaChannel.h
+++ b/Swiften/Client/DummyStanzaChannel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2017 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -13,7 +13,7 @@
namespace Swift {
class DummyStanzaChannel : public StanzaChannel {
public:
- DummyStanzaChannel() : available_(true) {}
+ DummyStanzaChannel() {}
virtual void sendStanza(std::shared_ptr<Stanza> stanza) {
sentStanzas.push_back(stanza);
@@ -37,7 +37,11 @@ namespace Swift {
}
virtual std::string getNewIQID() {
- return "test-id";
+ std::string id = "test-id";
+ if (uniqueIDs_) {
+ id += "-" + std::to_string(idCounter_++);
+ }
+ return id;
}
virtual bool isAvailable() const {
@@ -94,6 +98,8 @@ namespace Swift {
}
std::vector<std::shared_ptr<Stanza> > sentStanzas;
- bool available_;
+ bool available_ = true;
+ bool uniqueIDs_ = false;
+ unsigned int idCounter_ = 0;
};
}