From 40dc0541e60549cc2db83005f45b51f93d42cc00 Mon Sep 17 00:00:00 2001
From: Catalin Badea <catalin.badea392@gmail.com>
Date: Tue, 3 Jul 2012 16:17:51 +0300
Subject: Added message type logging. Fixed handling new messages.


diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 632d760..f40f704 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -37,8 +37,8 @@ namespace Swift {
 /**
  * The controller does not gain ownership of the stanzaChannel, nor the factory.
  */
-ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController)
-	: ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) {
+ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry)
+	: ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) {
 	isInMUC_ = isInMUC;
 	lastWasPresence_ = false;
 	chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
@@ -354,8 +354,16 @@ boost::optional<boost::posix_time::ptime> ChatController::getMessageTimestamp(bo
 }
 
 void ChatController::logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool /* isIncoming */) {
+	HistoryMessage::Type type;
+	if (mucRegistry_->isMUC(fromJID.toBare()) || mucRegistry_->isMUC(toJID.toBare())) {
+		type = HistoryMessage::PrivateMessage;
+	}
+	else {
+		type = HistoryMessage::Chat;
+	}
+
 	if (historyController_) {
-		historyController_->addMessage(message, fromJID, toJID, false, timeStamp);
+		historyController_->addMessage(message, fromJID, toJID, type, timeStamp);
 	}
 }
 
diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h
index daf687d..a873ae9 100644
--- a/Swift/Controllers/Chat/ChatController.h
+++ b/Swift/Controllers/Chat/ChatController.h
@@ -25,7 +25,7 @@ namespace Swift {
 
 	class ChatController : public ChatControllerBase {
 		public:
-			ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController);
+			ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry);
 			virtual ~ChatController();
 			virtual void setToJID(const JID& jid);
 			virtual void setOnline(bool online);
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp
index 115c258..ad6aabe 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.cpp
+++ b/Swift/Controllers/Chat/ChatControllerBase.cpp
@@ -33,7 +33,7 @@
 
 namespace Swift {
 
-ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController) {
+ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry) {
 	chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);
 	chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));
 	chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2));
diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h
index 762a1a3..b618d3c 100644
--- a/Swift/Controllers/Chat/ChatControllerBase.h
+++ b/Swift/Controllers/Chat/ChatControllerBase.h
@@ -28,6 +28,7 @@
 #include "Swiften/Queries/IQRouter.h"
 #include "Swiften/Base/IDGenerator.h"
 #include <Swift/Controllers/HistoryController.h>
+#include <Swiften/MUC/MUCRegistry.h>
 
 namespace Swift {
 	class IQRouter;
@@ -59,7 +60,7 @@ namespace Swift {
 			void handleCapsChanged(const JID& jid);
 
 		protected:
-			ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController);
+			ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry);
 
 			/**
 			 * Pass the Message appended, and the stanza used to send it.
@@ -113,5 +114,6 @@ namespace Swift {
 			TimerFactory* timerFactory_;
 			EntityCapsProvider* entityCapsProvider_;
 			HistoryController* historyController_;
+			MUCRegistry* mucRegistry_;
 	};
 }
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 3817a41..6b51df6 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -514,7 +514,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)
 
 ChatController* ChatsManager::createNewChatController(const JID& contact) {
 	assert(chatControllers_.find(contact) == chatControllers_.end());
-	ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_);
+	ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_);
 	chatControllers_[contact] = controller;
 	controller->setAvailableServerFeatures(serverDiscoInfo_);
 	controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
@@ -587,7 +587,7 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional
 		if (createAsReservedIfNew) {
 			muc->setCreateAsReservedIfNew();
 		}
-		MUCController* controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_);
+		MUCController* controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_);
 		mucControllers_[mucJID] = controller;
 		controller->setAvailableServerFeatures(serverDiscoInfo_);
 		controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller));
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp
index f86c726..bdc9b20 100644
--- a/Swift/Controllers/Chat/MUCController.cpp
+++ b/Swift/Controllers/Chat/MUCController.cpp
@@ -60,8 +60,9 @@ MUCController::MUCController (
 		EventController* eventController,
 		EntityCapsProvider* entityCapsProvider,
 		XMPPRoster* roster,
-		HistoryController* historyController) :
-			ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController), muc_(muc), nick_(nick), desiredNick_(nick), password_(password) {
+		HistoryController* historyController,
+		MUCRegistry* mucRegistry) :
+			ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry), muc_(muc), nick_(nick), desiredNick_(nick), password_(password) {
 	parting_ = true;
 	joined_ = false;
 	lastWasPresence_ = false;
@@ -783,7 +784,7 @@ void MUCController::handleAffiliationListReceived(MUCOccupant::Affiliation affil
 void MUCController::logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) {
 	// log only incoming messages
 	if (isIncoming && historyController_) {
-		historyController_->addMessage(message, fromJID, toJID, true, timeStamp);
+		historyController_->addMessage(message, fromJID, toJID, HistoryMessage::Groupchat, timeStamp);
 	}
 }
 
diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h
index 41393cd..0c6cfa4 100644
--- a/Swift/Controllers/Chat/MUCController.h
+++ b/Swift/Controllers/Chat/MUCController.h
@@ -44,7 +44,7 @@ namespace Swift {
 
 	class MUCController : public ChatControllerBase {
 		public:
-			MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController);
+			MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry);
 			~MUCController();
 			boost::signal<void ()> onUserLeft;
 			boost::signal<void ()> onUserJoined;
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 090899b..3615bed 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -63,7 +63,7 @@ public:
 		entityCapsProvider_ = new DummyEntityCapsProvider();
 		muc_ = boost::make_shared<MUC>(stanzaChannel_, iqRouter_, directedPresenceSender_, mucJID_, mucRegistry_);
 		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
-		controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL);
+		controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_);
 	};
 
 	void tearDown() {
diff --git a/Swift/Controllers/HistoryController.cpp b/Swift/Controllers/HistoryController.cpp
index 5bd4ffa..fe54e79 100644
--- a/Swift/Controllers/HistoryController.cpp
+++ b/Swift/Controllers/HistoryController.cpp
@@ -19,18 +19,18 @@ HistoryController::~HistoryController() {
 	delete localHistory_;
 }
 
-void HistoryController::addMessage(const std::string& message, const JID& fromJID, const JID& toJID, bool isGroupChat, const boost::posix_time::ptime& timeStamp) {
-	HistoryMessage historyMessage(message, fromJID, toJID, isGroupChat, timeStamp);
+void HistoryController::addMessage(const std::string& message, const JID& fromJID, const JID& toJID, HistoryMessage::Type type, const boost::posix_time::ptime& timeStamp) {
+	HistoryMessage historyMessage(message, fromJID, toJID, type, timeStamp);
 	localHistory_->addMessage(historyMessage);
 	onNewMessage(historyMessage);
 }
 
-std::vector<HistoryMessage> HistoryController::getMessages(const JID& selfJID, const JID& contactJID, bool isGroupChat) const {
-	return localHistory_->getMessages(selfJID, contactJID, isGroupChat);
+std::vector<HistoryMessage> HistoryController::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const {
+	return localHistory_->getMessages(selfJID, contactJID, type);
 }
 
-void HistoryController::getAllContacts(const JID& selfJID, std::set<JID>& mucs, std::set<JID>& contacts) const {
-	return localHistory_->getAllContacts(selfJID, mucs, contacts);
+std::set<JID> HistoryController::getContacts(const JID& selfJID, HistoryMessage::Type type) const {
+	return localHistory_->getContacts(selfJID, type);
 }
 
 }
diff --git a/Swift/Controllers/HistoryController.h b/Swift/Controllers/HistoryController.h
index babda8a..c08e112 100644
--- a/Swift/Controllers/HistoryController.h
+++ b/Swift/Controllers/HistoryController.h
@@ -11,10 +11,10 @@
 #include <vector>
 #include <set>
 #include <Swiften/Base/boost_bsignals.h>
+#include <Swiften/History/HistoryMessage.h>
 
 namespace Swift {
 	class HistoryManager;
-	class HistoryMessage;
 	class JID;
 
 	class HistoryController {
@@ -22,9 +22,9 @@ namespace Swift {
 			HistoryController();
 			~HistoryController();
 
-			void addMessage(const std::string& message, const JID& fromJID, const JID& toJID, bool isGroupChat, const boost::posix_time::ptime& timeStamp);
-			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, bool isGroupChat) const;
-			void getAllContacts(const JID& selfJID, std::set<JID>& mucs, std::set<JID>& contacts) const;
+			void addMessage(const std::string& message, const JID& fromJID, const JID& toJID, HistoryMessage::Type type, const boost::posix_time::ptime& timeStamp);
+			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const;
+			std::set<JID> getContacts(const JID& selfJID, HistoryMessage::Type type) const;
 
 			boost::signal<void (const HistoryMessage&)> onNewMessage;
 
diff --git a/Swift/Controllers/HistoryViewController.cpp b/Swift/Controllers/HistoryViewController.cpp
index a67f6cd..18e27bd 100644
--- a/Swift/Controllers/HistoryViewController.cpp
+++ b/Swift/Controllers/HistoryViewController.cpp
@@ -48,6 +48,7 @@ HistoryViewController::~HistoryViewController() {
 }
 
 void HistoryViewController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
+	// TODO: add new nick manager
 	boost::shared_ptr<RequestHistoryUIEvent> event = boost::dynamic_pointer_cast<RequestHistoryUIEvent>(rawEvent);
 	if (event != NULL) {
 		if (historyWindow_ == NULL) {
@@ -56,13 +57,31 @@ void HistoryViewController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
 
 			historyWindow_->setRosterModel(roster_);
 
-			historyController_->getAllContacts(selfJID_, rooms_, contacts_);
+			// MUCs
+			std::set<JID> rooms = historyController_->getContacts(selfJID_, HistoryMessage::Groupchat);
+			foreach (const JID& room, rooms) {
+				if ( !rooms_.count(room)) {
+					roster_->addContact(room, room, nickResolver_->jidToNick(room), "MUC", avatarManager_->getAvatarPath(room).string());
+					rooms_.insert(room);
+				}
+			}
 
-			foreach (const JID& muc, rooms_) {
-				roster_->addContact(muc, muc, nickResolver_->jidToNick(muc), "MUC", byteArrayToString(avatarManager_->getAvatar(muc)));
+			// Contacts
+			std::set<JID> contacts = historyController_->getContacts(selfJID_, HistoryMessage::Chat);
+			foreach (const JID& contact, contacts) {
+				if (!contacts_.count(contact)) {
+					roster_->addContact(contact, contact, nickResolver_->jidToNick(contact), "Contacts", avatarManager_->getAvatarPath(contact).string());
+					contacts_.insert(contact);
+				}
 			}
-			foreach (const JID& contact, contacts_) {
-				roster_->addContact(contact, contact, nickResolver_->jidToNick(contact), "Contacts", byteArrayToString(avatarManager_->getAvatar(contact)));
+
+			// MUC contacts
+			std::set<JID> roomPrivateContacts = historyController_->getContacts(selfJID_, HistoryMessage::PrivateMessage);
+			foreach (const JID& contact, roomPrivateContacts) {
+				if ( !roomPrivateContacts_.count(contact)) {
+					roster_->addContact(contact, contact, nickResolver_->jidToNick(contact), "Contacts", avatarManager_->getAvatarPath(contact).string());
+					roomPrivateContacts_.insert(contact);
+				}
 			}
 		}
 
@@ -72,38 +91,68 @@ void HistoryViewController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) {
 
 void HistoryViewController::handleSelectedContactChanged(RosterItem* newContact) {
 	// FIXME: signal is triggerd twice.
-	selectedItem_ = dynamic_cast<ContactRosterItem*>(newContact);
+	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(newContact);
 
-	if (newContact == NULL) {
+	if (contact && selectedItem_ != contact) {
+		selectedItem_ = contact;
+		historyWindow_->resetConversationView();
+	}
+	else {
 		return;
 	}
 
-	ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(newContact);
 	JID contactJID = contact->getJID();
-	bool isRoom = rooms_.count(contactJID);
 
-	std::vector<HistoryMessage> messages = historyController_->getMessages(selfJID_, contactJID, isRoom);
+	std::vector<HistoryMessage> messages;
+	if (roomPrivateContacts_.count(contactJID)) {
+		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::PrivateMessage);
+	}
+	else if (contacts_.count(contactJID)) {
+		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Chat);
+	}
+	else {
+		messages = historyController_->getMessages(selfJID_, contactJID, HistoryMessage::Groupchat);
+	}
+
 	foreach (const HistoryMessage& message, messages) {
-		bool senderIsSelf = message.getFromJID() == selfJID_;
-		std::string avatarPath = byteArrayToString(avatarManager_->getAvatar(message.getFromJID()));
-		historyWindow_->addMessage(message.getMessage(), nickResolver_->jidToNick(message.getFromJID()), senderIsSelf, avatarPath, message.getTime());
+		addNewMessage(message);
 	}
 }
 
 void HistoryViewController::handleNewMessage(const HistoryMessage& message) {
 	JID contactJID = message.getFromJID().toBare() == selfJID_ ? message.getToJID() : message.getFromJID();
 
-	if (selectedItem_ && selectedItem_->getJID().toBare() == contactJID) {
-		bool senderIsSelf = message.getFromJID().toBare() == selfJID_;
-		std::string avatarPath = byteArrayToString(avatarManager_->getAvatar(message.getFromJID()));
-		historyWindow_->addMessage(message.getMessage(), nickResolver_->jidToNick(message.getFromJID()), senderIsSelf, avatarPath, message.getTime());
+	JID displayJID;
+	if (message.getType() == HistoryMessage::PrivateMessage) {
+		displayJID = contactJID;
+	}
+	else {
+		displayJID = contactJID.toBare();
+	}
+
+	// check current conversation
+	if (selectedItem_ && selectedItem_->getJID() == displayJID) {
+		addNewMessage(message);
 	}
-	else if (!rooms_.count(contactJID.toBare()) && message.isGroupChat()) {
-		roster_->addContact(contactJID.toBare(), contactJID.toBare(), nickResolver_->jidToNick(contactJID.toBare()), "MUC", byteArrayToString(avatarManager_->getAvatar(contactJID.toBare())));
+	// add new contact
+	else if (message.getType() == HistoryMessage::Groupchat && !rooms_.count(displayJID)) {
+		roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), "MUC", avatarManager_->getAvatarPath(displayJID).string());
+		rooms_.insert(displayJID);
 	}
-	else if (!contacts_.count(contactJID) && !message.isGroupChat()) {
-		roster_->addContact(contactJID, contactJID, nickResolver_->jidToNick(contactJID), "Contacts", byteArrayToString(avatarManager_->getAvatar(contactJID)));
+	else if (message.getType() == HistoryMessage::Chat && !contacts_.count(displayJID)) {
+		roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), "Contacts", avatarManager_->getAvatarPath(displayJID).string());
+		contacts_.insert(displayJID);
 	}
+	else if (message.getType() == HistoryMessage::PrivateMessage && !roomPrivateContacts_.count(displayJID)) {
+		roster_->addContact(displayJID, displayJID, nickResolver_->jidToNick(displayJID), "Contacts", avatarManager_->getAvatarPath(displayJID).string());
+		roomPrivateContacts_.insert(displayJID);
+	}
+}
+
+void HistoryViewController::addNewMessage(const HistoryMessage& message) {
+	bool senderIsSelf = message.getFromJID().toBare() == selfJID_;
+	std::string avatarPath = avatarManager_->getAvatarPath(message.getFromJID()).string();
+	historyWindow_->addMessage(message.getMessage(), nickResolver_->jidToNick(message.getFromJID()), senderIsSelf, avatarPath, message.getTime());
 }
 
 }
diff --git a/Swift/Controllers/HistoryViewController.h b/Swift/Controllers/HistoryViewController.h
index 4f43f47..4957e37 100644
--- a/Swift/Controllers/HistoryViewController.h
+++ b/Swift/Controllers/HistoryViewController.h
@@ -34,6 +34,7 @@ namespace Swift {
 			void handleUIEvent(boost::shared_ptr<UIEvent> event);
 			void handleSelectedContactChanged(RosterItem* item);
 			void handleNewMessage(const HistoryMessage& message);
+			void addNewMessage(const HistoryMessage& message);
 
 		private:
 			JID selfJID_;
@@ -45,8 +46,9 @@ namespace Swift {
 			HistoryWindow* historyWindow_;
 			Roster* roster_;
 
-			std::set<JID> rooms_;
 			std::set<JID> contacts_;
+			std::set<JID> rooms_;
+			std::set<JID> roomPrivateContacts_;
 			ContactRosterItem* selectedItem_;
 	};
 }
diff --git a/Swift/Controllers/UIInterfaces/HistoryWindow.h b/Swift/Controllers/UIInterfaces/HistoryWindow.h
index d51b65d..cd232f1 100644
--- a/Swift/Controllers/UIInterfaces/HistoryWindow.h
+++ b/Swift/Controllers/UIInterfaces/HistoryWindow.h
@@ -16,6 +16,7 @@ namespace Swift {
 			virtual void activate() = 0;
 			virtual void setRosterModel(Roster*) = 0;
 			virtual void addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time) = 0;
+			virtual void resetConversationView() = 0;
 
 			boost::signal<void (RosterItem*)> onSelectedContactChanged;
 	};
diff --git a/Swift/QtUI/QtHistoryWindow.cpp b/Swift/QtUI/QtHistoryWindow.cpp
index 122655a..50fd66e 100644
--- a/Swift/QtUI/QtHistoryWindow.cpp
+++ b/Swift/QtUI/QtHistoryWindow.cpp
@@ -89,8 +89,11 @@ void QtHistoryWindow::addMessage(const std::string &message, const std::string &
 
 
 void QtHistoryWindow::handleSomethingSelectedChanged(RosterItem* item) {
-	conversation_->resetView();
 	onSelectedContactChanged(item);
 }
 
+void QtHistoryWindow::resetConversationView() {
+	conversation_->resetView();
+}
+
 }
diff --git a/Swift/QtUI/QtHistoryWindow.h b/Swift/QtUI/QtHistoryWindow.h
index 965abf7..279657d 100644
--- a/Swift/QtUI/QtHistoryWindow.h
+++ b/Swift/QtUI/QtHistoryWindow.h
@@ -22,6 +22,7 @@ namespace Swift {
 			void activate();
 			void setRosterModel(Roster*);
 			void addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, const std::string& avatarPath, const boost::posix_time::ptime& time);
+			void resetConversationView();
 
 		private:
 			virtual void closeEvent(QCloseEvent* event);
diff --git a/Swiften/History/HistoryManager.h b/Swiften/History/HistoryManager.h
index a10bb41..bc1680b 100644
--- a/Swiften/History/HistoryManager.h
+++ b/Swiften/History/HistoryManager.h
@@ -18,7 +18,7 @@ namespace Swift {
 
 			virtual void addMessage(const HistoryMessage& message) = 0;
 
-			virtual std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, bool isGroupChat) const = 0;
-			virtual void getAllContacts(const JID& selfJID, std::set<JID>& mucs, std::set<JID>& contacts) const = 0;
+			virtual std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const = 0;
+			virtual std::set<JID> getContacts(const JID& selfJID, HistoryMessage::Type type) const = 0;
 	};
 }
diff --git a/Swiften/History/HistoryMessage.h b/Swiften/History/HistoryMessage.h
index 021d6b9..d35474f 100644
--- a/Swiften/History/HistoryMessage.h
+++ b/Swiften/History/HistoryMessage.h
@@ -12,16 +12,22 @@
 namespace Swift {
 	class HistoryMessage {
 		public:
+			enum Type {
+				Chat = 0,
+				Groupchat = 1,
+				PrivateMessage = 2
+			};
+
 			HistoryMessage(
 				const std::string& message,
 				const JID& fromJID,
 				const JID& toJID,
-				bool isGroupChat,
+				Type type,
 				const boost::posix_time::ptime& time) :
 					message_(message),
 					fromJID_(fromJID),
 					toJID_(toJID),
-					isGroupChat_(isGroupChat),
+					type_(type),
 					time_(time) {
 			}
 
@@ -37,8 +43,8 @@ namespace Swift {
 				return toJID_;
 			}
 
-			bool isGroupChat() const {
-				return isGroupChat_;
+			Type getType() const {
+				return type_;
 			}
 
 			boost::posix_time::ptime getTime() const {
@@ -46,14 +52,14 @@ namespace Swift {
 			}
 
 			bool operator==(const HistoryMessage& o) const {
-				return message_ == o.message_ && fromJID_ == o.fromJID_ && toJID_ == o.toJID_ && isGroupChat_ == o.isGroupChat_ && time_ == o.time_;
+				return message_ == o.message_ && fromJID_ == o.fromJID_ && toJID_ == o.toJID_ && type_ == o.type_ && time_ == o.time_;
 			}
 
 		private:
 			std::string message_;
 			JID fromJID_;
 			JID toJID_;
-			bool isGroupChat_; // TODO: <- maybe use Message::Type ?
+			Type type_;
 			boost::posix_time::ptime time_;
 	};
 }
diff --git a/Swiften/History/SQLiteHistoryManager.cpp b/Swiften/History/SQLiteHistoryManager.cpp
index af09b66..3304a07 100644
--- a/Swiften/History/SQLiteHistoryManager.cpp
+++ b/Swiften/History/SQLiteHistoryManager.cpp
@@ -30,7 +30,7 @@ SQLiteHistoryManager::SQLiteHistoryManager(const std::string& file) : db_(0) {
 	}
 
 	char* errorMessage;
-	int result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS messages('message' STRING, 'fromBare' INTEGER, 'fromResource' STRING, 'toBare' INTEGER, 'toResource' STRING, 'groupChat' INTEGER, 'time' INTEGER)", 0, 0, &errorMessage);
+	int result = sqlite3_exec(db_, "CREATE TABLE IF NOT EXISTS messages('message' STRING, 'fromBare' INTEGER, 'fromResource' STRING, 'toBare' INTEGER, 'toResource' STRING, 'type' INTEGER, 'time' INTEGER)", 0, 0, &errorMessage);
 	if (result != SQLITE_OK) {
 		std::cerr << "SQL Error: " << errorMessage << std::endl;
 		sqlite3_free(errorMessage);
@@ -50,13 +50,13 @@ SQLiteHistoryManager::~SQLiteHistoryManager() {
 void SQLiteHistoryManager::addMessage(const HistoryMessage& message) {
 	int secondsSinceEpoch = (message.getTime() - boost::posix_time::ptime(boost::gregorian::date(1970, 1, 1))).total_seconds();
 
-	std::string statement = std::string("INSERT INTO messages('message', 'fromBare', 'fromResource', 'toBare', 'toResource', 'groupChat', 'time') VALUES(") +
+	std::string statement = std::string("INSERT INTO messages('message', 'fromBare', 'fromResource', 'toBare', 'toResource', 'type', 'time') VALUES(") +
 					"'" + getEscapedString(message.getMessage()) + "', " +
 					boost::lexical_cast<std::string>(getIDForJID(message.getFromJID().toBare())) + ", '" +
 					getEscapedString(message.getFromJID().getResource()) + "', " +
 					boost::lexical_cast<std::string>(getIDForJID(message.getToJID().toBare())) + ", '" +
 					getEscapedString(message.getToJID().getResource()) + "', " +
-					boost::lexical_cast<std::string>(message.isGroupChat()) + ", " + 
+					boost::lexical_cast<std::string>(message.getType()) + ", " +
 					boost::lexical_cast<std::string>(secondsSinceEpoch) + ")";
 	char* errorMessage;
 	int result = sqlite3_exec(db_, statement.c_str(), 0, 0, &errorMessage);
@@ -66,7 +66,7 @@ void SQLiteHistoryManager::addMessage(const HistoryMessage& message) {
 	}
 }
 
-std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID, const JID& contactJID, bool isGroupChat) const {
+std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const {
 	sqlite3_stmt* selectStatement;
 
 	boost::optional<int> selfID = getIDFromJID(selfJID.toBare());
@@ -77,7 +77,7 @@ std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID
 		return std::vector<HistoryMessage>();
 	}
 
-	std::string selectQuery = "SELECT * FROM messages WHERE groupChat=" + boost::lexical_cast<std::string>(isGroupChat);
+	std::string selectQuery = "SELECT * FROM messages WHERE type=" + boost::lexical_cast<std::string>(type);
 	if (contactJID.isBare()) {
 		// match only bare jid
 		selectQuery += " AND ((fromBare=" + boost::lexical_cast<std::string>(*selfID) + " AND toBare=" +
@@ -120,13 +120,13 @@ std::vector<HistoryMessage> SQLiteHistoryManager::getMessages(const JID& selfJID
 		}
 
 		// message type
-		bool isGroupChat = sqlite3_column_int(selectStatement, 5);
+		HistoryMessage::Type type = static_cast<HistoryMessage::Type>(sqlite3_column_int(selectStatement, 5));
 
 		// timestamp
 		int secondsSinceEpoch(sqlite3_column_int(selectStatement, 6));
 		boost::posix_time::ptime time(boost::gregorian::date(1970, 1, 1), boost::posix_time::seconds(secondsSinceEpoch));
 
-		result.push_back(HistoryMessage(message, (fromJID ? *fromJID : JID()), (toJID ? *toJID : JID()), isGroupChat, time));
+		result.push_back(HistoryMessage(message, (fromJID ? *fromJID : JID()), (toJID ? *toJID : JID()), type, time));
 		r = sqlite3_step(selectStatement);
 	}
 	if (r != SQLITE_DONE) {
@@ -190,42 +190,22 @@ boost::optional<int> SQLiteHistoryManager::getIDFromJID(const JID& jid) const {
 	return result;
 }
 
-void SQLiteHistoryManager::getAllContacts(const JID& selfJID, std::set<JID>& mucs, std::set<JID>& contacts) const {
+std::set<JID> SQLiteHistoryManager::getContacts(const JID& selfJID, HistoryMessage::Type type) const {
+	std::set<JID> result;
+	sqlite3_stmt* selectStatement;
+
 	// get id
 	boost::optional<int> id = getIDFromJID(selfJID);
 	if (!id) {
-		return;
+		return result;
 	}
 
-	// get all MUCs
-	std::string query = "SELECT DISTINCT messages.'fromBare' FROM messages WHERE groupChat=1 AND toBare=" + boost::lexical_cast<std::string>(*id);
-	sqlite3_stmt* selectStatement;
-
-	int r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
-	if (r != SQLITE_OK) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-
-	r = sqlite3_step(selectStatement);
-	while (r == SQLITE_ROW) {
-		boost::optional<JID> contactJID(getJIDFromID(sqlite3_column_int(selectStatement, 0)));
-		if (contactJID) {
-			mucs.insert(*contactJID);
-		}
-
-		r = sqlite3_step(selectStatement);
-	}
-
-	if (r != SQLITE_DONE) {
-		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
-	}
-	sqlite3_finalize(selectStatement);
-
-	// get all contacts
-	query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource' FROM messages WHERE groupChat=0 AND (toBare="
+	// get contacts
+	std::string query = "SELECT DISTINCT messages.'fromBare', messages.'fromResource', messages.'toBare', messages.'toResource' FROM messages WHERE type="
+		+ boost::lexical_cast<std::string>(type) + " AND (toBare="
 		+ boost::lexical_cast<std::string>(*id) + " OR fromBare=" + boost::lexical_cast<std::string>(*id) + ")";
 
-	r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
+	int r = sqlite3_prepare(db_, query.c_str(), query.size(), &selectStatement, NULL);
 	if (r != SQLITE_OK) {
 		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
 	}
@@ -250,12 +230,12 @@ void SQLiteHistoryManager::getAllContacts(const JID& selfJID, std::set<JID>& muc
 		}
 
 		// check if it is a MUC contact (from a private conversation)
-		if (contactJID && mucs.count(*contactJID)) {
+		if (type == HistoryMessage::PrivateMessage) {
 			contactJID = boost::optional<JID>(JID(contactJID->getNode(), contactJID->getDomain(), resource));
 		}
 
 		if (contactJID) {
-			contacts.insert(*contactJID);
+			result.insert(*contactJID);
 		}
 
 		r = sqlite3_step(selectStatement);
@@ -265,6 +245,8 @@ void SQLiteHistoryManager::getAllContacts(const JID& selfJID, std::set<JID>& muc
 		std::cout << "Error: " << sqlite3_errmsg(db_) << std::endl;
 	}
 	sqlite3_finalize(selectStatement);
+
+	return result;
 }
 
 }
diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h
index 480d570..fce30f8 100644
--- a/Swiften/History/SQLiteHistoryManager.h
+++ b/Swiften/History/SQLiteHistoryManager.h
@@ -19,8 +19,8 @@ namespace Swift {
 			~SQLiteHistoryManager();
 
 			void addMessage(const HistoryMessage& message);
-			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, bool isGroupChat) const;
-			void getAllContacts(const JID& selfJID, std::set<JID>& mucs, std::set<JID>& contacts) const;
+			std::vector<HistoryMessage> getMessages(const JID& selfJID, const JID& contactJID, HistoryMessage::Type type) const;
+			std::set<JID> getContacts(const JID& selfJID, HistoryMessage::Type type) const;
 
 		private:
 			int getIDForJID(const JID&);
-- 
cgit v0.10.2-6-g49f6